Skip to content

Commit d8e9a40

Browse files
Magnus Dammgregkh
authored andcommitted
serdev: BREAK/FRAME/PARITY/OVERRUN notification prototype V2
Allow serdev device drivers get notified by hardware errors such as BREAK, FRAME, PARITY and OVERRUN. With this patch, in the event of an error detected in the UART device driver the serdev_device_driver will get the newly introduced ->error() callback invoked if serdev_device_set_error_mask() has previously been used to enable the type of error. The errors are taken straight from the TTY layer and fed into the serdev_device_driver after filtering out only enabled errors. Without this patch the hardware errors never reach the serdev_device_driver. Signed-off-by: Magnus Damm <[email protected]> Link: https://lore.kernel.org/r/163931528842.27756.3665040315954968747.sendpatchset@octo Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent ad234e2 commit d8e9a40

File tree

3 files changed

+82
-0
lines changed

3 files changed

+82
-0
lines changed

drivers/tty/serdev/core.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,17 @@ unsigned int serdev_device_set_baudrate(struct serdev_device *serdev, unsigned i
349349
}
350350
EXPORT_SYMBOL_GPL(serdev_device_set_baudrate);
351351

352+
void serdev_device_set_error_mask(struct serdev_device *serdev, unsigned long mask)
353+
{
354+
struct serdev_controller *ctrl = serdev->ctrl;
355+
356+
if (!ctrl || !ctrl->ops->set_error_mask)
357+
return;
358+
359+
ctrl->ops->set_error_mask(ctrl, mask);
360+
}
361+
EXPORT_SYMBOL_GPL(serdev_device_set_error_mask);
362+
352363
void serdev_device_set_flow_control(struct serdev_device *serdev, bool enable)
353364
{
354365
struct serdev_controller *ctrl = serdev->ctrl;

drivers/tty/serdev/serdev-ttyport.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@
22
/*
33
* Copyright (C) 2016-2017 Linaro Ltd., Rob Herring <[email protected]>
44
*/
5+
#include <linux/bits.h>
56
#include <linux/kernel.h>
67
#include <linux/serdev.h>
78
#include <linux/tty.h>
89
#include <linux/tty_driver.h>
910
#include <linux/poll.h>
1011

1112
#define SERPORT_ACTIVE 1
13+
#define SERPORT_NOTIFY_BREAK 2
14+
#define SERPORT_NOTIFY_FRAME 3
15+
#define SERPORT_NOTIFY_PARITY 4
16+
#define SERPORT_NOTIFY_OVERRUN 5
1217

1318
struct serport {
1419
struct tty_port *port;
@@ -27,11 +32,39 @@ static int ttyport_receive_buf(struct tty_port *port, const unsigned char *cp,
2732
{
2833
struct serdev_controller *ctrl = port->client_data;
2934
struct serport *serport = serdev_controller_get_drvdata(ctrl);
35+
unsigned long errors = 0;
36+
unsigned int i;
3037
int ret;
3138

3239
if (!test_bit(SERPORT_ACTIVE, &serport->flags))
3340
return 0;
3441

42+
for (i = 0; fp && i < count; i++) {
43+
switch (fp[i]) {
44+
case TTY_BREAK:
45+
if (test_bit(SERPORT_NOTIFY_BREAK, &serport->flags))
46+
__set_bit(SERDEV_ERROR_BREAK, &errors);
47+
break;
48+
49+
case TTY_FRAME:
50+
if (test_bit(SERPORT_NOTIFY_FRAME, &serport->flags))
51+
__set_bit(SERDEV_ERROR_FRAME, &errors);
52+
break;
53+
54+
case TTY_PARITY:
55+
if (test_bit(SERPORT_NOTIFY_PARITY, &serport->flags))
56+
__set_bit(SERDEV_ERROR_PARITY, &errors);
57+
break;
58+
59+
case TTY_OVERRUN:
60+
if (test_bit(SERPORT_NOTIFY_OVERRUN, &serport->flags))
61+
__set_bit(SERDEV_ERROR_OVERRUN, &errors);
62+
break;
63+
}
64+
}
65+
if (errors)
66+
serdev_controller_error(ctrl, errors);
67+
3568
ret = serdev_controller_receive_buf(ctrl, cp, count);
3669

3770
dev_WARN_ONCE(&ctrl->dev, ret < 0 || ret > count,
@@ -180,6 +213,21 @@ static unsigned int ttyport_set_baudrate(struct serdev_controller *ctrl, unsigne
180213
return ktermios.c_ospeed;
181214
}
182215

216+
static void ttyport_set_error_mask(struct serdev_controller *ctrl,
217+
unsigned long m)
218+
{
219+
struct serport *sp = serdev_controller_get_drvdata(ctrl);
220+
221+
assign_bit(SERPORT_NOTIFY_BREAK, &sp->flags,
222+
m & BIT(SERDEV_ERROR_BREAK));
223+
assign_bit(SERPORT_NOTIFY_FRAME, &sp->flags,
224+
m & BIT(SERDEV_ERROR_FRAME));
225+
assign_bit(SERPORT_NOTIFY_PARITY, &sp->flags,
226+
m & BIT(SERDEV_ERROR_PARITY));
227+
assign_bit(SERPORT_NOTIFY_OVERRUN, &sp->flags,
228+
m & BIT(SERDEV_ERROR_OVERRUN));
229+
}
230+
183231
static void ttyport_set_flow_control(struct serdev_controller *ctrl, bool enable)
184232
{
185233
struct serport *serport = serdev_controller_get_drvdata(ctrl);
@@ -253,6 +301,7 @@ static const struct serdev_controller_ops ctrl_ops = {
253301
.write_room = ttyport_write_room,
254302
.open = ttyport_open,
255303
.close = ttyport_close,
304+
.set_error_mask = ttyport_set_error_mask,
256305
.set_flow_control = ttyport_set_flow_control,
257306
.set_parity = ttyport_set_parity,
258307
.set_baudrate = ttyport_set_baudrate,

include/linux/serdev.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,15 @@ struct serdev_device;
1919

2020
/**
2121
* struct serdev_device_ops - Callback operations for a serdev device
22+
* @error: Function called with errors received from device;
23+
* may sleep.
2224
* @receive_buf: Function called with data received from device;
2325
* returns number of bytes accepted; may sleep.
2426
* @write_wakeup: Function called when ready to transmit more data; must
2527
* not sleep.
2628
*/
2729
struct serdev_device_ops {
30+
void (*error)(struct serdev_device *, unsigned long);
2831
int (*receive_buf)(struct serdev_device *, const unsigned char *, size_t);
2932
void (*write_wakeup)(struct serdev_device *);
3033
};
@@ -76,6 +79,11 @@ enum serdev_parity {
7679
SERDEV_PARITY_ODD,
7780
};
7881

82+
#define SERDEV_ERROR_BREAK 0
83+
#define SERDEV_ERROR_FRAME 1
84+
#define SERDEV_ERROR_PARITY 2
85+
#define SERDEV_ERROR_OVERRUN 3
86+
7987
/*
8088
* serdev controller structures
8189
*/
@@ -85,6 +93,7 @@ struct serdev_controller_ops {
8593
int (*write_room)(struct serdev_controller *);
8694
int (*open)(struct serdev_controller *);
8795
void (*close)(struct serdev_controller *);
96+
void (*set_error_mask)(struct serdev_controller *, unsigned long);
8897
void (*set_flow_control)(struct serdev_controller *, bool);
8998
int (*set_parity)(struct serdev_controller *, enum serdev_parity);
9099
unsigned int (*set_baudrate)(struct serdev_controller *, unsigned int);
@@ -190,12 +199,24 @@ static inline int serdev_controller_receive_buf(struct serdev_controller *ctrl,
190199
return serdev->ops->receive_buf(serdev, data, count);
191200
}
192201

202+
static inline void serdev_controller_error(struct serdev_controller *ctrl,
203+
unsigned long errors)
204+
{
205+
struct serdev_device *serdev = ctrl->serdev;
206+
207+
if (!serdev || !serdev->ops->error)
208+
return;
209+
210+
serdev->ops->error(serdev, errors);
211+
}
212+
193213
#if IS_ENABLED(CONFIG_SERIAL_DEV_BUS)
194214

195215
int serdev_device_open(struct serdev_device *);
196216
void serdev_device_close(struct serdev_device *);
197217
int devm_serdev_device_open(struct device *, struct serdev_device *);
198218
unsigned int serdev_device_set_baudrate(struct serdev_device *, unsigned int);
219+
void serdev_device_set_error_mask(struct serdev_device *, unsigned long);
199220
void serdev_device_set_flow_control(struct serdev_device *, bool);
200221
int serdev_device_write_buf(struct serdev_device *, const unsigned char *, size_t);
201222
void serdev_device_wait_until_sent(struct serdev_device *, long);
@@ -238,6 +259,7 @@ static inline unsigned int serdev_device_set_baudrate(struct serdev_device *sdev
238259
{
239260
return 0;
240261
}
262+
static inline void serdev_device_set_error_mask(struct serdev_device *sdev, unsigned long mask) {}
241263
static inline void serdev_device_set_flow_control(struct serdev_device *sdev, bool enable) {}
242264
static inline int serdev_device_write_buf(struct serdev_device *serdev,
243265
const unsigned char *buf,

0 commit comments

Comments
 (0)