1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) ST-Ericsson AB 2010
4*4882a593Smuzhiyun * Author: Sjur Brendeland
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <linux/hardirq.h>
8*4882a593Smuzhiyun #include <linux/init.h>
9*4882a593Smuzhiyun #include <linux/module.h>
10*4882a593Smuzhiyun #include <linux/device.h>
11*4882a593Smuzhiyun #include <linux/types.h>
12*4882a593Smuzhiyun #include <linux/skbuff.h>
13*4882a593Smuzhiyun #include <linux/netdevice.h>
14*4882a593Smuzhiyun #include <linux/rtnetlink.h>
15*4882a593Smuzhiyun #include <linux/tty.h>
16*4882a593Smuzhiyun #include <linux/file.h>
17*4882a593Smuzhiyun #include <linux/if_arp.h>
18*4882a593Smuzhiyun #include <net/caif/caif_device.h>
19*4882a593Smuzhiyun #include <net/caif/cfcnfg.h>
20*4882a593Smuzhiyun #include <linux/err.h>
21*4882a593Smuzhiyun #include <linux/debugfs.h>
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun MODULE_LICENSE("GPL");
24*4882a593Smuzhiyun MODULE_AUTHOR("Sjur Brendeland");
25*4882a593Smuzhiyun MODULE_DESCRIPTION("CAIF serial device TTY line discipline");
26*4882a593Smuzhiyun MODULE_LICENSE("GPL");
27*4882a593Smuzhiyun MODULE_ALIAS_LDISC(N_CAIF);
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #define SEND_QUEUE_LOW 10
30*4882a593Smuzhiyun #define SEND_QUEUE_HIGH 100
31*4882a593Smuzhiyun #define CAIF_SENDING 1 /* Bit 1 = 0x02*/
32*4882a593Smuzhiyun #define CAIF_FLOW_OFF_SENT 4 /* Bit 4 = 0x10 */
33*4882a593Smuzhiyun #define MAX_WRITE_CHUNK 4096
34*4882a593Smuzhiyun #define ON 1
35*4882a593Smuzhiyun #define OFF 0
36*4882a593Smuzhiyun #define CAIF_MAX_MTU 4096
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun static DEFINE_SPINLOCK(ser_lock);
39*4882a593Smuzhiyun static LIST_HEAD(ser_list);
40*4882a593Smuzhiyun static LIST_HEAD(ser_release_list);
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun static bool ser_loop;
43*4882a593Smuzhiyun module_param(ser_loop, bool, 0444);
44*4882a593Smuzhiyun MODULE_PARM_DESC(ser_loop, "Run in simulated loopback mode.");
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun static bool ser_use_stx = true;
47*4882a593Smuzhiyun module_param(ser_use_stx, bool, 0444);
48*4882a593Smuzhiyun MODULE_PARM_DESC(ser_use_stx, "STX enabled or not.");
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun static bool ser_use_fcs = true;
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun module_param(ser_use_fcs, bool, 0444);
53*4882a593Smuzhiyun MODULE_PARM_DESC(ser_use_fcs, "FCS enabled or not.");
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun static int ser_write_chunk = MAX_WRITE_CHUNK;
56*4882a593Smuzhiyun module_param(ser_write_chunk, int, 0444);
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun MODULE_PARM_DESC(ser_write_chunk, "Maximum size of data written to UART.");
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun static struct dentry *debugfsdir;
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun static int caif_net_open(struct net_device *dev);
63*4882a593Smuzhiyun static int caif_net_close(struct net_device *dev);
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun struct ser_device {
66*4882a593Smuzhiyun struct caif_dev_common common;
67*4882a593Smuzhiyun struct list_head node;
68*4882a593Smuzhiyun struct net_device *dev;
69*4882a593Smuzhiyun struct sk_buff_head head;
70*4882a593Smuzhiyun struct tty_struct *tty;
71*4882a593Smuzhiyun bool tx_started;
72*4882a593Smuzhiyun unsigned long state;
73*4882a593Smuzhiyun #ifdef CONFIG_DEBUG_FS
74*4882a593Smuzhiyun struct dentry *debugfs_tty_dir;
75*4882a593Smuzhiyun struct debugfs_blob_wrapper tx_blob;
76*4882a593Smuzhiyun struct debugfs_blob_wrapper rx_blob;
77*4882a593Smuzhiyun u8 rx_data[128];
78*4882a593Smuzhiyun u8 tx_data[128];
79*4882a593Smuzhiyun u8 tty_status;
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun #endif
82*4882a593Smuzhiyun };
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun static void caifdev_setup(struct net_device *dev);
85*4882a593Smuzhiyun static void ldisc_tx_wakeup(struct tty_struct *tty);
86*4882a593Smuzhiyun #ifdef CONFIG_DEBUG_FS
update_tty_status(struct ser_device * ser)87*4882a593Smuzhiyun static inline void update_tty_status(struct ser_device *ser)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun ser->tty_status =
90*4882a593Smuzhiyun ser->tty->stopped << 5 |
91*4882a593Smuzhiyun ser->tty->flow_stopped << 3 |
92*4882a593Smuzhiyun ser->tty->packet << 2 |
93*4882a593Smuzhiyun ser->tty->port->low_latency << 1;
94*4882a593Smuzhiyun }
debugfs_init(struct ser_device * ser,struct tty_struct * tty)95*4882a593Smuzhiyun static inline void debugfs_init(struct ser_device *ser, struct tty_struct *tty)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun ser->debugfs_tty_dir = debugfs_create_dir(tty->name, debugfsdir);
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun debugfs_create_blob("last_tx_msg", 0400, ser->debugfs_tty_dir,
100*4882a593Smuzhiyun &ser->tx_blob);
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun debugfs_create_blob("last_rx_msg", 0400, ser->debugfs_tty_dir,
103*4882a593Smuzhiyun &ser->rx_blob);
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun debugfs_create_xul("ser_state", 0400, ser->debugfs_tty_dir,
106*4882a593Smuzhiyun &ser->state);
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun debugfs_create_x8("tty_status", 0400, ser->debugfs_tty_dir,
109*4882a593Smuzhiyun &ser->tty_status);
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun ser->tx_blob.data = ser->tx_data;
112*4882a593Smuzhiyun ser->tx_blob.size = 0;
113*4882a593Smuzhiyun ser->rx_blob.data = ser->rx_data;
114*4882a593Smuzhiyun ser->rx_blob.size = 0;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
debugfs_deinit(struct ser_device * ser)117*4882a593Smuzhiyun static inline void debugfs_deinit(struct ser_device *ser)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun debugfs_remove_recursive(ser->debugfs_tty_dir);
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
debugfs_rx(struct ser_device * ser,const u8 * data,int size)122*4882a593Smuzhiyun static inline void debugfs_rx(struct ser_device *ser, const u8 *data, int size)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun if (size > sizeof(ser->rx_data))
125*4882a593Smuzhiyun size = sizeof(ser->rx_data);
126*4882a593Smuzhiyun memcpy(ser->rx_data, data, size);
127*4882a593Smuzhiyun ser->rx_blob.data = ser->rx_data;
128*4882a593Smuzhiyun ser->rx_blob.size = size;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
debugfs_tx(struct ser_device * ser,const u8 * data,int size)131*4882a593Smuzhiyun static inline void debugfs_tx(struct ser_device *ser, const u8 *data, int size)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun if (size > sizeof(ser->tx_data))
134*4882a593Smuzhiyun size = sizeof(ser->tx_data);
135*4882a593Smuzhiyun memcpy(ser->tx_data, data, size);
136*4882a593Smuzhiyun ser->tx_blob.data = ser->tx_data;
137*4882a593Smuzhiyun ser->tx_blob.size = size;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun #else
debugfs_init(struct ser_device * ser,struct tty_struct * tty)140*4882a593Smuzhiyun static inline void debugfs_init(struct ser_device *ser, struct tty_struct *tty)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
debugfs_deinit(struct ser_device * ser)144*4882a593Smuzhiyun static inline void debugfs_deinit(struct ser_device *ser)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
update_tty_status(struct ser_device * ser)148*4882a593Smuzhiyun static inline void update_tty_status(struct ser_device *ser)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun
debugfs_rx(struct ser_device * ser,const u8 * data,int size)152*4882a593Smuzhiyun static inline void debugfs_rx(struct ser_device *ser, const u8 *data, int size)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun
debugfs_tx(struct ser_device * ser,const u8 * data,int size)156*4882a593Smuzhiyun static inline void debugfs_tx(struct ser_device *ser, const u8 *data, int size)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun #endif
161*4882a593Smuzhiyun
ldisc_receive(struct tty_struct * tty,const u8 * data,char * flags,int count)162*4882a593Smuzhiyun static void ldisc_receive(struct tty_struct *tty, const u8 *data,
163*4882a593Smuzhiyun char *flags, int count)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun struct sk_buff *skb = NULL;
166*4882a593Smuzhiyun struct ser_device *ser;
167*4882a593Smuzhiyun int ret;
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun ser = tty->disc_data;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun /*
172*4882a593Smuzhiyun * NOTE: flags may contain information about break or overrun.
173*4882a593Smuzhiyun * This is not yet handled.
174*4882a593Smuzhiyun */
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun /*
178*4882a593Smuzhiyun * Workaround for garbage at start of transmission,
179*4882a593Smuzhiyun * only enable if STX handling is not enabled.
180*4882a593Smuzhiyun */
181*4882a593Smuzhiyun if (!ser->common.use_stx && !ser->tx_started) {
182*4882a593Smuzhiyun dev_info(&ser->dev->dev,
183*4882a593Smuzhiyun "Bytes received before initial transmission -"
184*4882a593Smuzhiyun "bytes discarded.\n");
185*4882a593Smuzhiyun return;
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun BUG_ON(ser->dev == NULL);
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun /* Get a suitable caif packet and copy in data. */
191*4882a593Smuzhiyun skb = netdev_alloc_skb(ser->dev, count+1);
192*4882a593Smuzhiyun if (skb == NULL)
193*4882a593Smuzhiyun return;
194*4882a593Smuzhiyun skb_put_data(skb, data, count);
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun skb->protocol = htons(ETH_P_CAIF);
197*4882a593Smuzhiyun skb_reset_mac_header(skb);
198*4882a593Smuzhiyun debugfs_rx(ser, data, count);
199*4882a593Smuzhiyun /* Push received packet up the stack. */
200*4882a593Smuzhiyun ret = netif_rx_ni(skb);
201*4882a593Smuzhiyun if (!ret) {
202*4882a593Smuzhiyun ser->dev->stats.rx_packets++;
203*4882a593Smuzhiyun ser->dev->stats.rx_bytes += count;
204*4882a593Smuzhiyun } else
205*4882a593Smuzhiyun ++ser->dev->stats.rx_dropped;
206*4882a593Smuzhiyun update_tty_status(ser);
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun
handle_tx(struct ser_device * ser)209*4882a593Smuzhiyun static int handle_tx(struct ser_device *ser)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun struct tty_struct *tty;
212*4882a593Smuzhiyun struct sk_buff *skb;
213*4882a593Smuzhiyun int tty_wr, len, room;
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun tty = ser->tty;
216*4882a593Smuzhiyun ser->tx_started = true;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun /* Enter critical section */
219*4882a593Smuzhiyun if (test_and_set_bit(CAIF_SENDING, &ser->state))
220*4882a593Smuzhiyun return 0;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun /* skb_peek is safe because handle_tx is called after skb_queue_tail */
223*4882a593Smuzhiyun while ((skb = skb_peek(&ser->head)) != NULL) {
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun /* Make sure you don't write too much */
226*4882a593Smuzhiyun len = skb->len;
227*4882a593Smuzhiyun room = tty_write_room(tty);
228*4882a593Smuzhiyun if (!room)
229*4882a593Smuzhiyun break;
230*4882a593Smuzhiyun if (room > ser_write_chunk)
231*4882a593Smuzhiyun room = ser_write_chunk;
232*4882a593Smuzhiyun if (len > room)
233*4882a593Smuzhiyun len = room;
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun /* Write to tty or loopback */
236*4882a593Smuzhiyun if (!ser_loop) {
237*4882a593Smuzhiyun tty_wr = tty->ops->write(tty, skb->data, len);
238*4882a593Smuzhiyun update_tty_status(ser);
239*4882a593Smuzhiyun } else {
240*4882a593Smuzhiyun tty_wr = len;
241*4882a593Smuzhiyun ldisc_receive(tty, skb->data, NULL, len);
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun ser->dev->stats.tx_packets++;
244*4882a593Smuzhiyun ser->dev->stats.tx_bytes += tty_wr;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun /* Error on TTY ?! */
247*4882a593Smuzhiyun if (tty_wr < 0)
248*4882a593Smuzhiyun goto error;
249*4882a593Smuzhiyun /* Reduce buffer written, and discard if empty */
250*4882a593Smuzhiyun skb_pull(skb, tty_wr);
251*4882a593Smuzhiyun if (skb->len == 0) {
252*4882a593Smuzhiyun struct sk_buff *tmp = skb_dequeue(&ser->head);
253*4882a593Smuzhiyun WARN_ON(tmp != skb);
254*4882a593Smuzhiyun dev_consume_skb_any(skb);
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun /* Send flow off if queue is empty */
258*4882a593Smuzhiyun if (ser->head.qlen <= SEND_QUEUE_LOW &&
259*4882a593Smuzhiyun test_and_clear_bit(CAIF_FLOW_OFF_SENT, &ser->state) &&
260*4882a593Smuzhiyun ser->common.flowctrl != NULL)
261*4882a593Smuzhiyun ser->common.flowctrl(ser->dev, ON);
262*4882a593Smuzhiyun clear_bit(CAIF_SENDING, &ser->state);
263*4882a593Smuzhiyun return 0;
264*4882a593Smuzhiyun error:
265*4882a593Smuzhiyun clear_bit(CAIF_SENDING, &ser->state);
266*4882a593Smuzhiyun return tty_wr;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
caif_xmit(struct sk_buff * skb,struct net_device * dev)269*4882a593Smuzhiyun static netdev_tx_t caif_xmit(struct sk_buff *skb, struct net_device *dev)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun struct ser_device *ser;
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun ser = netdev_priv(dev);
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun /* Send flow off once, on high water mark */
276*4882a593Smuzhiyun if (ser->head.qlen > SEND_QUEUE_HIGH &&
277*4882a593Smuzhiyun !test_and_set_bit(CAIF_FLOW_OFF_SENT, &ser->state) &&
278*4882a593Smuzhiyun ser->common.flowctrl != NULL)
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun ser->common.flowctrl(ser->dev, OFF);
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun skb_queue_tail(&ser->head, skb);
283*4882a593Smuzhiyun return handle_tx(ser);
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun
ldisc_tx_wakeup(struct tty_struct * tty)287*4882a593Smuzhiyun static void ldisc_tx_wakeup(struct tty_struct *tty)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun struct ser_device *ser;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun ser = tty->disc_data;
292*4882a593Smuzhiyun BUG_ON(ser == NULL);
293*4882a593Smuzhiyun WARN_ON(ser->tty != tty);
294*4882a593Smuzhiyun handle_tx(ser);
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun
ser_release(struct work_struct * work)298*4882a593Smuzhiyun static void ser_release(struct work_struct *work)
299*4882a593Smuzhiyun {
300*4882a593Smuzhiyun struct list_head list;
301*4882a593Smuzhiyun struct ser_device *ser, *tmp;
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun spin_lock(&ser_lock);
304*4882a593Smuzhiyun list_replace_init(&ser_release_list, &list);
305*4882a593Smuzhiyun spin_unlock(&ser_lock);
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun if (!list_empty(&list)) {
308*4882a593Smuzhiyun rtnl_lock();
309*4882a593Smuzhiyun list_for_each_entry_safe(ser, tmp, &list, node) {
310*4882a593Smuzhiyun dev_close(ser->dev);
311*4882a593Smuzhiyun unregister_netdevice(ser->dev);
312*4882a593Smuzhiyun debugfs_deinit(ser);
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun rtnl_unlock();
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun static DECLARE_WORK(ser_release_work, ser_release);
319*4882a593Smuzhiyun
ldisc_open(struct tty_struct * tty)320*4882a593Smuzhiyun static int ldisc_open(struct tty_struct *tty)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun struct ser_device *ser;
323*4882a593Smuzhiyun struct net_device *dev;
324*4882a593Smuzhiyun char name[64];
325*4882a593Smuzhiyun int result;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun /* No write no play */
328*4882a593Smuzhiyun if (tty->ops->write == NULL)
329*4882a593Smuzhiyun return -EOPNOTSUPP;
330*4882a593Smuzhiyun if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_TTY_CONFIG))
331*4882a593Smuzhiyun return -EPERM;
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun /* release devices to avoid name collision */
334*4882a593Smuzhiyun ser_release(NULL);
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun result = snprintf(name, sizeof(name), "cf%s", tty->name);
337*4882a593Smuzhiyun if (result >= IFNAMSIZ)
338*4882a593Smuzhiyun return -EINVAL;
339*4882a593Smuzhiyun dev = alloc_netdev(sizeof(*ser), name, NET_NAME_UNKNOWN,
340*4882a593Smuzhiyun caifdev_setup);
341*4882a593Smuzhiyun if (!dev)
342*4882a593Smuzhiyun return -ENOMEM;
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun ser = netdev_priv(dev);
345*4882a593Smuzhiyun ser->tty = tty_kref_get(tty);
346*4882a593Smuzhiyun ser->dev = dev;
347*4882a593Smuzhiyun debugfs_init(ser, tty);
348*4882a593Smuzhiyun tty->receive_room = N_TTY_BUF_SIZE;
349*4882a593Smuzhiyun tty->disc_data = ser;
350*4882a593Smuzhiyun set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
351*4882a593Smuzhiyun rtnl_lock();
352*4882a593Smuzhiyun result = register_netdevice(dev);
353*4882a593Smuzhiyun if (result) {
354*4882a593Smuzhiyun tty_kref_put(tty);
355*4882a593Smuzhiyun rtnl_unlock();
356*4882a593Smuzhiyun free_netdev(dev);
357*4882a593Smuzhiyun return -ENODEV;
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun spin_lock(&ser_lock);
361*4882a593Smuzhiyun list_add(&ser->node, &ser_list);
362*4882a593Smuzhiyun spin_unlock(&ser_lock);
363*4882a593Smuzhiyun rtnl_unlock();
364*4882a593Smuzhiyun netif_stop_queue(dev);
365*4882a593Smuzhiyun update_tty_status(ser);
366*4882a593Smuzhiyun return 0;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun
ldisc_close(struct tty_struct * tty)369*4882a593Smuzhiyun static void ldisc_close(struct tty_struct *tty)
370*4882a593Smuzhiyun {
371*4882a593Smuzhiyun struct ser_device *ser = tty->disc_data;
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun tty_kref_put(ser->tty);
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun spin_lock(&ser_lock);
376*4882a593Smuzhiyun list_move(&ser->node, &ser_release_list);
377*4882a593Smuzhiyun spin_unlock(&ser_lock);
378*4882a593Smuzhiyun schedule_work(&ser_release_work);
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun /* The line discipline structure. */
382*4882a593Smuzhiyun static struct tty_ldisc_ops caif_ldisc = {
383*4882a593Smuzhiyun .owner = THIS_MODULE,
384*4882a593Smuzhiyun .magic = TTY_LDISC_MAGIC,
385*4882a593Smuzhiyun .name = "n_caif",
386*4882a593Smuzhiyun .open = ldisc_open,
387*4882a593Smuzhiyun .close = ldisc_close,
388*4882a593Smuzhiyun .receive_buf = ldisc_receive,
389*4882a593Smuzhiyun .write_wakeup = ldisc_tx_wakeup
390*4882a593Smuzhiyun };
391*4882a593Smuzhiyun
register_ldisc(void)392*4882a593Smuzhiyun static int register_ldisc(void)
393*4882a593Smuzhiyun {
394*4882a593Smuzhiyun int result;
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun result = tty_register_ldisc(N_CAIF, &caif_ldisc);
397*4882a593Smuzhiyun if (result < 0) {
398*4882a593Smuzhiyun pr_err("cannot register CAIF ldisc=%d err=%d\n", N_CAIF,
399*4882a593Smuzhiyun result);
400*4882a593Smuzhiyun return result;
401*4882a593Smuzhiyun }
402*4882a593Smuzhiyun return result;
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun static const struct net_device_ops netdev_ops = {
405*4882a593Smuzhiyun .ndo_open = caif_net_open,
406*4882a593Smuzhiyun .ndo_stop = caif_net_close,
407*4882a593Smuzhiyun .ndo_start_xmit = caif_xmit
408*4882a593Smuzhiyun };
409*4882a593Smuzhiyun
caifdev_setup(struct net_device * dev)410*4882a593Smuzhiyun static void caifdev_setup(struct net_device *dev)
411*4882a593Smuzhiyun {
412*4882a593Smuzhiyun struct ser_device *serdev = netdev_priv(dev);
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun dev->features = 0;
415*4882a593Smuzhiyun dev->netdev_ops = &netdev_ops;
416*4882a593Smuzhiyun dev->type = ARPHRD_CAIF;
417*4882a593Smuzhiyun dev->flags = IFF_POINTOPOINT | IFF_NOARP;
418*4882a593Smuzhiyun dev->mtu = CAIF_MAX_MTU;
419*4882a593Smuzhiyun dev->priv_flags |= IFF_NO_QUEUE;
420*4882a593Smuzhiyun dev->needs_free_netdev = true;
421*4882a593Smuzhiyun skb_queue_head_init(&serdev->head);
422*4882a593Smuzhiyun serdev->common.link_select = CAIF_LINK_LOW_LATENCY;
423*4882a593Smuzhiyun serdev->common.use_frag = true;
424*4882a593Smuzhiyun serdev->common.use_stx = ser_use_stx;
425*4882a593Smuzhiyun serdev->common.use_fcs = ser_use_fcs;
426*4882a593Smuzhiyun serdev->dev = dev;
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun
caif_net_open(struct net_device * dev)430*4882a593Smuzhiyun static int caif_net_open(struct net_device *dev)
431*4882a593Smuzhiyun {
432*4882a593Smuzhiyun netif_wake_queue(dev);
433*4882a593Smuzhiyun return 0;
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun
caif_net_close(struct net_device * dev)436*4882a593Smuzhiyun static int caif_net_close(struct net_device *dev)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun netif_stop_queue(dev);
439*4882a593Smuzhiyun return 0;
440*4882a593Smuzhiyun }
441*4882a593Smuzhiyun
caif_ser_init(void)442*4882a593Smuzhiyun static int __init caif_ser_init(void)
443*4882a593Smuzhiyun {
444*4882a593Smuzhiyun int ret;
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun ret = register_ldisc();
447*4882a593Smuzhiyun debugfsdir = debugfs_create_dir("caif_serial", NULL);
448*4882a593Smuzhiyun return ret;
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun
caif_ser_exit(void)451*4882a593Smuzhiyun static void __exit caif_ser_exit(void)
452*4882a593Smuzhiyun {
453*4882a593Smuzhiyun spin_lock(&ser_lock);
454*4882a593Smuzhiyun list_splice(&ser_list, &ser_release_list);
455*4882a593Smuzhiyun spin_unlock(&ser_lock);
456*4882a593Smuzhiyun ser_release(NULL);
457*4882a593Smuzhiyun cancel_work_sync(&ser_release_work);
458*4882a593Smuzhiyun tty_unregister_ldisc(N_CAIF);
459*4882a593Smuzhiyun debugfs_remove_recursive(debugfsdir);
460*4882a593Smuzhiyun }
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun module_init(caif_ser_init);
463*4882a593Smuzhiyun module_exit(caif_ser_exit);
464