xref: /OK3568_Linux_fs/kernel/drivers/tty/n_hdlc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-1.0+
2*4882a593Smuzhiyun /* generic HDLC line discipline for Linux
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Written by Paul Fulghum paulkf@microgate.com
5*4882a593Smuzhiyun  * for Microgate Corporation
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Microgate and SyncLink are registered trademarks of Microgate Corporation
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * Adapted from ppp.c, written by Michael Callahan <callahan@maths.ox.ac.uk>,
10*4882a593Smuzhiyun  *	Al Longyear <longyear@netcom.com>,
11*4882a593Smuzhiyun  *	Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  * Original release 01/11/99
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  * This module implements the tty line discipline N_HDLC for use with
16*4882a593Smuzhiyun  * tty device drivers that support bit-synchronous HDLC communications.
17*4882a593Smuzhiyun  *
18*4882a593Smuzhiyun  * All HDLC data is frame oriented which means:
19*4882a593Smuzhiyun  *
20*4882a593Smuzhiyun  * 1. tty write calls represent one complete transmit frame of data
21*4882a593Smuzhiyun  *    The device driver should accept the complete frame or none of
22*4882a593Smuzhiyun  *    the frame (busy) in the write method. Each write call should have
23*4882a593Smuzhiyun  *    a byte count in the range of 2-65535 bytes (2 is min HDLC frame
24*4882a593Smuzhiyun  *    with 1 addr byte and 1 ctrl byte). The max byte count of 65535
25*4882a593Smuzhiyun  *    should include any crc bytes required. For example, when using
26*4882a593Smuzhiyun  *    CCITT CRC32, 4 crc bytes are required, so the maximum size frame
27*4882a593Smuzhiyun  *    the application may transmit is limited to 65531 bytes. For CCITT
28*4882a593Smuzhiyun  *    CRC16, the maximum application frame size would be 65533.
29*4882a593Smuzhiyun  *
30*4882a593Smuzhiyun  *
31*4882a593Smuzhiyun  * 2. receive callbacks from the device driver represents
32*4882a593Smuzhiyun  *    one received frame. The device driver should bypass
33*4882a593Smuzhiyun  *    the tty flip buffer and call the line discipline receive
34*4882a593Smuzhiyun  *    callback directly to avoid fragmenting or concatenating
35*4882a593Smuzhiyun  *    multiple frames into a single receive callback.
36*4882a593Smuzhiyun  *
37*4882a593Smuzhiyun  *    The HDLC line discipline queues the receive frames in separate
38*4882a593Smuzhiyun  *    buffers so complete receive frames can be returned by the
39*4882a593Smuzhiyun  *    tty read calls.
40*4882a593Smuzhiyun  *
41*4882a593Smuzhiyun  * 3. tty read calls returns an entire frame of data or nothing.
42*4882a593Smuzhiyun  *
43*4882a593Smuzhiyun  * 4. all send and receive data is considered raw. No processing
44*4882a593Smuzhiyun  *    or translation is performed by the line discipline, regardless
45*4882a593Smuzhiyun  *    of the tty flags
46*4882a593Smuzhiyun  *
47*4882a593Smuzhiyun  * 5. When line discipline is queried for the amount of receive
48*4882a593Smuzhiyun  *    data available (FIOC), 0 is returned if no data available,
49*4882a593Smuzhiyun  *    otherwise the count of the next available frame is returned.
50*4882a593Smuzhiyun  *    (instead of the sum of all received frame counts).
51*4882a593Smuzhiyun  *
52*4882a593Smuzhiyun  * These conventions allow the standard tty programming interface
53*4882a593Smuzhiyun  * to be used for synchronous HDLC applications when used with
54*4882a593Smuzhiyun  * this line discipline (or another line discipline that is frame
55*4882a593Smuzhiyun  * oriented such as N_PPP).
56*4882a593Smuzhiyun  *
57*4882a593Smuzhiyun  * The SyncLink driver (synclink.c) implements both asynchronous
58*4882a593Smuzhiyun  * (using standard line discipline N_TTY) and synchronous HDLC
59*4882a593Smuzhiyun  * (using N_HDLC) communications, with the latter using the above
60*4882a593Smuzhiyun  * conventions.
61*4882a593Smuzhiyun  *
62*4882a593Smuzhiyun  * This implementation is very basic and does not maintain
63*4882a593Smuzhiyun  * any statistics. The main point is to enforce the raw data
64*4882a593Smuzhiyun  * and frame orientation of HDLC communications.
65*4882a593Smuzhiyun  *
66*4882a593Smuzhiyun  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
67*4882a593Smuzhiyun  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
68*4882a593Smuzhiyun  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
69*4882a593Smuzhiyun  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
70*4882a593Smuzhiyun  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
71*4882a593Smuzhiyun  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
72*4882a593Smuzhiyun  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
73*4882a593Smuzhiyun  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
74*4882a593Smuzhiyun  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
75*4882a593Smuzhiyun  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
76*4882a593Smuzhiyun  * OF THE POSSIBILITY OF SUCH DAMAGE.
77*4882a593Smuzhiyun  */
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun #define HDLC_MAGIC 0x239e
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun #include <linux/module.h>
82*4882a593Smuzhiyun #include <linux/init.h>
83*4882a593Smuzhiyun #include <linux/kernel.h>
84*4882a593Smuzhiyun #include <linux/sched.h>
85*4882a593Smuzhiyun #include <linux/types.h>
86*4882a593Smuzhiyun #include <linux/fcntl.h>
87*4882a593Smuzhiyun #include <linux/interrupt.h>
88*4882a593Smuzhiyun #include <linux/ptrace.h>
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun #include <linux/poll.h>
91*4882a593Smuzhiyun #include <linux/in.h>
92*4882a593Smuzhiyun #include <linux/ioctl.h>
93*4882a593Smuzhiyun #include <linux/slab.h>
94*4882a593Smuzhiyun #include <linux/tty.h>
95*4882a593Smuzhiyun #include <linux/errno.h>
96*4882a593Smuzhiyun #include <linux/string.h>	/* used in new tty drivers */
97*4882a593Smuzhiyun #include <linux/signal.h>	/* used in new tty drivers */
98*4882a593Smuzhiyun #include <linux/if.h>
99*4882a593Smuzhiyun #include <linux/bitops.h>
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun #include <asm/termios.h>
102*4882a593Smuzhiyun #include <linux/uaccess.h>
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun /*
105*4882a593Smuzhiyun  * Buffers for individual HDLC frames
106*4882a593Smuzhiyun  */
107*4882a593Smuzhiyun #define MAX_HDLC_FRAME_SIZE 65535
108*4882a593Smuzhiyun #define DEFAULT_RX_BUF_COUNT 10
109*4882a593Smuzhiyun #define MAX_RX_BUF_COUNT 60
110*4882a593Smuzhiyun #define DEFAULT_TX_BUF_COUNT 3
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun struct n_hdlc_buf {
113*4882a593Smuzhiyun 	struct list_head  list_item;
114*4882a593Smuzhiyun 	int		  count;
115*4882a593Smuzhiyun 	char		  buf[];
116*4882a593Smuzhiyun };
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun struct n_hdlc_buf_list {
119*4882a593Smuzhiyun 	struct list_head  list;
120*4882a593Smuzhiyun 	int		  count;
121*4882a593Smuzhiyun 	spinlock_t	  spinlock;
122*4882a593Smuzhiyun };
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun /**
125*4882a593Smuzhiyun  * struct n_hdlc - per device instance data structure
126*4882a593Smuzhiyun  * @magic: magic value for structure
127*4882a593Smuzhiyun  * @tbusy: reentrancy flag for tx wakeup code
128*4882a593Smuzhiyun  * @woke_up: tx wakeup needs to be run again as it was called while @tbusy
129*4882a593Smuzhiyun  * @tx_buf_list: list of pending transmit frame buffers
130*4882a593Smuzhiyun  * @rx_buf_list: list of received frame buffers
131*4882a593Smuzhiyun  * @tx_free_buf_list: list unused transmit frame buffers
132*4882a593Smuzhiyun  * @rx_free_buf_list: list unused received frame buffers
133*4882a593Smuzhiyun  */
134*4882a593Smuzhiyun struct n_hdlc {
135*4882a593Smuzhiyun 	int			magic;
136*4882a593Smuzhiyun 	bool			tbusy;
137*4882a593Smuzhiyun 	bool			woke_up;
138*4882a593Smuzhiyun 	struct n_hdlc_buf_list	tx_buf_list;
139*4882a593Smuzhiyun 	struct n_hdlc_buf_list	rx_buf_list;
140*4882a593Smuzhiyun 	struct n_hdlc_buf_list	tx_free_buf_list;
141*4882a593Smuzhiyun 	struct n_hdlc_buf_list	rx_free_buf_list;
142*4882a593Smuzhiyun 	struct work_struct	write_work;
143*4882a593Smuzhiyun 	struct tty_struct	*tty_for_write_work;
144*4882a593Smuzhiyun };
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun /*
147*4882a593Smuzhiyun  * HDLC buffer list manipulation functions
148*4882a593Smuzhiyun  */
149*4882a593Smuzhiyun static void n_hdlc_buf_return(struct n_hdlc_buf_list *buf_list,
150*4882a593Smuzhiyun 						struct n_hdlc_buf *buf);
151*4882a593Smuzhiyun static void n_hdlc_buf_put(struct n_hdlc_buf_list *list,
152*4882a593Smuzhiyun 			   struct n_hdlc_buf *buf);
153*4882a593Smuzhiyun static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list);
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun /* Local functions */
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun static struct n_hdlc *n_hdlc_alloc(void);
158*4882a593Smuzhiyun static void n_hdlc_tty_write_work(struct work_struct *work);
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun /* max frame size for memory allocations */
161*4882a593Smuzhiyun static int maxframe = 4096;
162*4882a593Smuzhiyun 
flush_rx_queue(struct tty_struct * tty)163*4882a593Smuzhiyun static void flush_rx_queue(struct tty_struct *tty)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun 	struct n_hdlc *n_hdlc = tty->disc_data;
166*4882a593Smuzhiyun 	struct n_hdlc_buf *buf;
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	while ((buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list)))
169*4882a593Smuzhiyun 		n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, buf);
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun 
flush_tx_queue(struct tty_struct * tty)172*4882a593Smuzhiyun static void flush_tx_queue(struct tty_struct *tty)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun 	struct n_hdlc *n_hdlc = tty->disc_data;
175*4882a593Smuzhiyun 	struct n_hdlc_buf *buf;
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	while ((buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list)))
178*4882a593Smuzhiyun 		n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, buf);
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun 
n_hdlc_free_buf_list(struct n_hdlc_buf_list * list)181*4882a593Smuzhiyun static void n_hdlc_free_buf_list(struct n_hdlc_buf_list *list)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	struct n_hdlc_buf *buf;
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	do {
186*4882a593Smuzhiyun 		buf = n_hdlc_buf_get(list);
187*4882a593Smuzhiyun 		kfree(buf);
188*4882a593Smuzhiyun 	} while (buf);
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun /**
192*4882a593Smuzhiyun  * n_hdlc_tty_close - line discipline close
193*4882a593Smuzhiyun  * @tty: pointer to tty info structure
194*4882a593Smuzhiyun  *
195*4882a593Smuzhiyun  * Called when the line discipline is changed to something
196*4882a593Smuzhiyun  * else, the tty is closed, or the tty detects a hangup.
197*4882a593Smuzhiyun  */
n_hdlc_tty_close(struct tty_struct * tty)198*4882a593Smuzhiyun static void n_hdlc_tty_close(struct tty_struct *tty)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun 	struct n_hdlc *n_hdlc = tty->disc_data;
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	if (n_hdlc->magic != HDLC_MAGIC) {
203*4882a593Smuzhiyun 		pr_warn("n_hdlc: trying to close unopened tty!\n");
204*4882a593Smuzhiyun 		return;
205*4882a593Smuzhiyun 	}
206*4882a593Smuzhiyun #if defined(TTY_NO_WRITE_SPLIT)
207*4882a593Smuzhiyun 	clear_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
208*4882a593Smuzhiyun #endif
209*4882a593Smuzhiyun 	tty->disc_data = NULL;
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	/* Ensure that the n_hdlcd process is not hanging on select()/poll() */
212*4882a593Smuzhiyun 	wake_up_interruptible(&tty->read_wait);
213*4882a593Smuzhiyun 	wake_up_interruptible(&tty->write_wait);
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	cancel_work_sync(&n_hdlc->write_work);
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	n_hdlc_free_buf_list(&n_hdlc->rx_free_buf_list);
218*4882a593Smuzhiyun 	n_hdlc_free_buf_list(&n_hdlc->tx_free_buf_list);
219*4882a593Smuzhiyun 	n_hdlc_free_buf_list(&n_hdlc->rx_buf_list);
220*4882a593Smuzhiyun 	n_hdlc_free_buf_list(&n_hdlc->tx_buf_list);
221*4882a593Smuzhiyun 	kfree(n_hdlc);
222*4882a593Smuzhiyun }	/* end of n_hdlc_tty_close() */
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun /**
225*4882a593Smuzhiyun  * n_hdlc_tty_open - called when line discipline changed to n_hdlc
226*4882a593Smuzhiyun  * @tty: pointer to tty info structure
227*4882a593Smuzhiyun  *
228*4882a593Smuzhiyun  * Returns 0 if success, otherwise error code
229*4882a593Smuzhiyun  */
n_hdlc_tty_open(struct tty_struct * tty)230*4882a593Smuzhiyun static int n_hdlc_tty_open(struct tty_struct *tty)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun 	struct n_hdlc *n_hdlc = tty->disc_data;
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	pr_debug("%s() called (device=%s)\n", __func__, tty->name);
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	/* There should not be an existing table for this slot. */
237*4882a593Smuzhiyun 	if (n_hdlc) {
238*4882a593Smuzhiyun 		pr_err("%s: tty already associated!\n", __func__);
239*4882a593Smuzhiyun 		return -EEXIST;
240*4882a593Smuzhiyun 	}
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	n_hdlc = n_hdlc_alloc();
243*4882a593Smuzhiyun 	if (!n_hdlc) {
244*4882a593Smuzhiyun 		pr_err("%s: n_hdlc_alloc failed\n", __func__);
245*4882a593Smuzhiyun 		return -ENFILE;
246*4882a593Smuzhiyun 	}
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	INIT_WORK(&n_hdlc->write_work, n_hdlc_tty_write_work);
249*4882a593Smuzhiyun 	n_hdlc->tty_for_write_work = tty;
250*4882a593Smuzhiyun 	tty->disc_data = n_hdlc;
251*4882a593Smuzhiyun 	tty->receive_room = 65536;
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	/* change tty_io write() to not split large writes into 8K chunks */
254*4882a593Smuzhiyun 	set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	/* flush receive data from driver */
257*4882a593Smuzhiyun 	tty_driver_flush_buffer(tty);
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	return 0;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun }	/* end of n_tty_hdlc_open() */
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun /**
264*4882a593Smuzhiyun  * n_hdlc_send_frames - send frames on pending send buffer list
265*4882a593Smuzhiyun  * @n_hdlc: pointer to ldisc instance data
266*4882a593Smuzhiyun  * @tty: pointer to tty instance data
267*4882a593Smuzhiyun  *
268*4882a593Smuzhiyun  * Send frames on pending send buffer list until the driver does not accept a
269*4882a593Smuzhiyun  * frame (busy) this function is called after adding a frame to the send buffer
270*4882a593Smuzhiyun  * list and by the tty wakeup callback.
271*4882a593Smuzhiyun  */
n_hdlc_send_frames(struct n_hdlc * n_hdlc,struct tty_struct * tty)272*4882a593Smuzhiyun static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun 	register int actual;
275*4882a593Smuzhiyun 	unsigned long flags;
276*4882a593Smuzhiyun 	struct n_hdlc_buf *tbuf;
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun check_again:
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
281*4882a593Smuzhiyun 	if (n_hdlc->tbusy) {
282*4882a593Smuzhiyun 		n_hdlc->woke_up = true;
283*4882a593Smuzhiyun 		spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
284*4882a593Smuzhiyun 		return;
285*4882a593Smuzhiyun 	}
286*4882a593Smuzhiyun 	n_hdlc->tbusy = true;
287*4882a593Smuzhiyun 	n_hdlc->woke_up = false;
288*4882a593Smuzhiyun 	spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
291*4882a593Smuzhiyun 	while (tbuf) {
292*4882a593Smuzhiyun 		pr_debug("sending frame %p, count=%d\n", tbuf, tbuf->count);
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 		/* Send the next block of data to device */
295*4882a593Smuzhiyun 		set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
296*4882a593Smuzhiyun 		actual = tty->ops->write(tty, tbuf->buf, tbuf->count);
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 		/* rollback was possible and has been done */
299*4882a593Smuzhiyun 		if (actual == -ERESTARTSYS) {
300*4882a593Smuzhiyun 			n_hdlc_buf_return(&n_hdlc->tx_buf_list, tbuf);
301*4882a593Smuzhiyun 			break;
302*4882a593Smuzhiyun 		}
303*4882a593Smuzhiyun 		/* if transmit error, throw frame away by */
304*4882a593Smuzhiyun 		/* pretending it was accepted by driver */
305*4882a593Smuzhiyun 		if (actual < 0)
306*4882a593Smuzhiyun 			actual = tbuf->count;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 		if (actual == tbuf->count) {
309*4882a593Smuzhiyun 			pr_debug("frame %p completed\n", tbuf);
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 			/* free current transmit buffer */
312*4882a593Smuzhiyun 			n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, tbuf);
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 			/* wait up sleeping writers */
315*4882a593Smuzhiyun 			wake_up_interruptible(&tty->write_wait);
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 			/* get next pending transmit buffer */
318*4882a593Smuzhiyun 			tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
319*4882a593Smuzhiyun 		} else {
320*4882a593Smuzhiyun 			pr_debug("frame %p pending\n", tbuf);
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 			/*
323*4882a593Smuzhiyun 			 * the buffer was not accepted by driver,
324*4882a593Smuzhiyun 			 * return it back into tx queue
325*4882a593Smuzhiyun 			 */
326*4882a593Smuzhiyun 			n_hdlc_buf_return(&n_hdlc->tx_buf_list, tbuf);
327*4882a593Smuzhiyun 			break;
328*4882a593Smuzhiyun 		}
329*4882a593Smuzhiyun 	}
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	if (!tbuf)
332*4882a593Smuzhiyun 		clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	/* Clear the re-entry flag */
335*4882a593Smuzhiyun 	spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
336*4882a593Smuzhiyun 	n_hdlc->tbusy = false;
337*4882a593Smuzhiyun 	spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	if (n_hdlc->woke_up)
340*4882a593Smuzhiyun 		goto check_again;
341*4882a593Smuzhiyun }	/* end of n_hdlc_send_frames() */
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun /**
344*4882a593Smuzhiyun  * n_hdlc_tty_write_work - Asynchronous callback for transmit wakeup
345*4882a593Smuzhiyun  * @work: pointer to work_struct
346*4882a593Smuzhiyun  *
347*4882a593Smuzhiyun  * Called when low level device driver can accept more send data.
348*4882a593Smuzhiyun  */
n_hdlc_tty_write_work(struct work_struct * work)349*4882a593Smuzhiyun static void n_hdlc_tty_write_work(struct work_struct *work)
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun 	struct n_hdlc *n_hdlc = container_of(work, struct n_hdlc, write_work);
352*4882a593Smuzhiyun 	struct tty_struct *tty = n_hdlc->tty_for_write_work;
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	n_hdlc_send_frames(n_hdlc, tty);
355*4882a593Smuzhiyun }	/* end of n_hdlc_tty_write_work() */
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun /**
358*4882a593Smuzhiyun  * n_hdlc_tty_wakeup - Callback for transmit wakeup
359*4882a593Smuzhiyun  * @tty: pointer to associated tty instance data
360*4882a593Smuzhiyun  *
361*4882a593Smuzhiyun  * Called when low level device driver can accept more send data.
362*4882a593Smuzhiyun  */
n_hdlc_tty_wakeup(struct tty_struct * tty)363*4882a593Smuzhiyun static void n_hdlc_tty_wakeup(struct tty_struct *tty)
364*4882a593Smuzhiyun {
365*4882a593Smuzhiyun 	struct n_hdlc *n_hdlc = tty->disc_data;
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	schedule_work(&n_hdlc->write_work);
368*4882a593Smuzhiyun }	/* end of n_hdlc_tty_wakeup() */
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun /**
371*4882a593Smuzhiyun  * n_hdlc_tty_receive - Called by tty driver when receive data is available
372*4882a593Smuzhiyun  * @tty: pointer to tty instance data
373*4882a593Smuzhiyun  * @data: pointer to received data
374*4882a593Smuzhiyun  * @flags: pointer to flags for data
375*4882a593Smuzhiyun  * @count: count of received data in bytes
376*4882a593Smuzhiyun  *
377*4882a593Smuzhiyun  * Called by tty low level driver when receive data is available. Data is
378*4882a593Smuzhiyun  * interpreted as one HDLC frame.
379*4882a593Smuzhiyun  */
n_hdlc_tty_receive(struct tty_struct * tty,const __u8 * data,char * flags,int count)380*4882a593Smuzhiyun static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
381*4882a593Smuzhiyun 			       char *flags, int count)
382*4882a593Smuzhiyun {
383*4882a593Smuzhiyun 	register struct n_hdlc *n_hdlc = tty->disc_data;
384*4882a593Smuzhiyun 	register struct n_hdlc_buf *buf;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	pr_debug("%s() called count=%d\n", __func__, count);
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	/* verify line is using HDLC discipline */
389*4882a593Smuzhiyun 	if (n_hdlc->magic != HDLC_MAGIC) {
390*4882a593Smuzhiyun 		pr_err("line not using HDLC discipline\n");
391*4882a593Smuzhiyun 		return;
392*4882a593Smuzhiyun 	}
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	if (count > maxframe) {
395*4882a593Smuzhiyun 		pr_debug("rx count>maxframesize, data discarded\n");
396*4882a593Smuzhiyun 		return;
397*4882a593Smuzhiyun 	}
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	/* get a free HDLC buffer */
400*4882a593Smuzhiyun 	buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list);
401*4882a593Smuzhiyun 	if (!buf) {
402*4882a593Smuzhiyun 		/*
403*4882a593Smuzhiyun 		 * no buffers in free list, attempt to allocate another rx
404*4882a593Smuzhiyun 		 * buffer unless the maximum count has been reached
405*4882a593Smuzhiyun 		 */
406*4882a593Smuzhiyun 		if (n_hdlc->rx_buf_list.count < MAX_RX_BUF_COUNT)
407*4882a593Smuzhiyun 			buf = kmalloc(struct_size(buf, buf, maxframe),
408*4882a593Smuzhiyun 				      GFP_ATOMIC);
409*4882a593Smuzhiyun 	}
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	if (!buf) {
412*4882a593Smuzhiyun 		pr_debug("no more rx buffers, data discarded\n");
413*4882a593Smuzhiyun 		return;
414*4882a593Smuzhiyun 	}
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	/* copy received data to HDLC buffer */
417*4882a593Smuzhiyun 	memcpy(buf->buf, data, count);
418*4882a593Smuzhiyun 	buf->count = count;
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	/* add HDLC buffer to list of received frames */
421*4882a593Smuzhiyun 	n_hdlc_buf_put(&n_hdlc->rx_buf_list, buf);
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	/* wake up any blocked reads and perform async signalling */
424*4882a593Smuzhiyun 	wake_up_interruptible(&tty->read_wait);
425*4882a593Smuzhiyun 	if (tty->fasync != NULL)
426*4882a593Smuzhiyun 		kill_fasync(&tty->fasync, SIGIO, POLL_IN);
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun }	/* end of n_hdlc_tty_receive() */
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun /**
431*4882a593Smuzhiyun  * n_hdlc_tty_read - Called to retrieve one frame of data (if available)
432*4882a593Smuzhiyun  * @tty: pointer to tty instance data
433*4882a593Smuzhiyun  * @file: pointer to open file object
434*4882a593Smuzhiyun  * @buf: pointer to returned data buffer
435*4882a593Smuzhiyun  * @nr: size of returned data buffer
436*4882a593Smuzhiyun  *
437*4882a593Smuzhiyun  * Returns the number of bytes returned or error code.
438*4882a593Smuzhiyun  */
n_hdlc_tty_read(struct tty_struct * tty,struct file * file,__u8 * kbuf,size_t nr,void ** cookie,unsigned long offset)439*4882a593Smuzhiyun static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file,
440*4882a593Smuzhiyun 			   __u8 *kbuf, size_t nr,
441*4882a593Smuzhiyun 			   void **cookie, unsigned long offset)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun 	struct n_hdlc *n_hdlc = tty->disc_data;
444*4882a593Smuzhiyun 	int ret = 0;
445*4882a593Smuzhiyun 	struct n_hdlc_buf *rbuf;
446*4882a593Smuzhiyun 	DECLARE_WAITQUEUE(wait, current);
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	/* Is this a repeated call for an rbuf we already found earlier? */
449*4882a593Smuzhiyun 	rbuf = *cookie;
450*4882a593Smuzhiyun 	if (rbuf)
451*4882a593Smuzhiyun 		goto have_rbuf;
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 	add_wait_queue(&tty->read_wait, &wait);
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	for (;;) {
456*4882a593Smuzhiyun 		if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
457*4882a593Smuzhiyun 			ret = -EIO;
458*4882a593Smuzhiyun 			break;
459*4882a593Smuzhiyun 		}
460*4882a593Smuzhiyun 		if (tty_hung_up_p(file))
461*4882a593Smuzhiyun 			break;
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 		set_current_state(TASK_INTERRUPTIBLE);
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 		rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
466*4882a593Smuzhiyun 		if (rbuf)
467*4882a593Smuzhiyun 			break;
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 		/* no data */
470*4882a593Smuzhiyun 		if (tty_io_nonblock(tty, file)) {
471*4882a593Smuzhiyun 			ret = -EAGAIN;
472*4882a593Smuzhiyun 			break;
473*4882a593Smuzhiyun 		}
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 		schedule();
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 		if (signal_pending(current)) {
478*4882a593Smuzhiyun 			ret = -EINTR;
479*4882a593Smuzhiyun 			break;
480*4882a593Smuzhiyun 		}
481*4882a593Smuzhiyun 	}
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 	remove_wait_queue(&tty->read_wait, &wait);
484*4882a593Smuzhiyun 	__set_current_state(TASK_RUNNING);
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	if (!rbuf)
487*4882a593Smuzhiyun 		return ret;
488*4882a593Smuzhiyun 	*cookie = rbuf;
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun have_rbuf:
491*4882a593Smuzhiyun 	/* Have we used it up entirely? */
492*4882a593Smuzhiyun 	if (offset >= rbuf->count)
493*4882a593Smuzhiyun 		goto done_with_rbuf;
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	/* More data to go, but can't copy any more? EOVERFLOW */
496*4882a593Smuzhiyun 	ret = -EOVERFLOW;
497*4882a593Smuzhiyun 	if (!nr)
498*4882a593Smuzhiyun 		goto done_with_rbuf;
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	/* Copy as much data as possible */
501*4882a593Smuzhiyun 	ret = rbuf->count - offset;
502*4882a593Smuzhiyun 	if (ret > nr)
503*4882a593Smuzhiyun 		ret = nr;
504*4882a593Smuzhiyun 	memcpy(kbuf, rbuf->buf+offset, ret);
505*4882a593Smuzhiyun 	offset += ret;
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 	/* If we still have data left, we leave the rbuf in the cookie */
508*4882a593Smuzhiyun 	if (offset < rbuf->count)
509*4882a593Smuzhiyun 		return ret;
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun done_with_rbuf:
512*4882a593Smuzhiyun 	*cookie = NULL;
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	if (n_hdlc->rx_free_buf_list.count > DEFAULT_RX_BUF_COUNT)
515*4882a593Smuzhiyun 		kfree(rbuf);
516*4882a593Smuzhiyun 	else
517*4882a593Smuzhiyun 		n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, rbuf);
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 	return ret;
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun }	/* end of n_hdlc_tty_read() */
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun /**
524*4882a593Smuzhiyun  * n_hdlc_tty_write - write a single frame of data to device
525*4882a593Smuzhiyun  * @tty: pointer to associated tty device instance data
526*4882a593Smuzhiyun  * @file: pointer to file object data
527*4882a593Smuzhiyun  * @data: pointer to transmit data (one frame)
528*4882a593Smuzhiyun  * @count: size of transmit frame in bytes
529*4882a593Smuzhiyun  *
530*4882a593Smuzhiyun  * Returns the number of bytes written (or error code).
531*4882a593Smuzhiyun  */
n_hdlc_tty_write(struct tty_struct * tty,struct file * file,const unsigned char * data,size_t count)532*4882a593Smuzhiyun static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file,
533*4882a593Smuzhiyun 			    const unsigned char *data, size_t count)
534*4882a593Smuzhiyun {
535*4882a593Smuzhiyun 	struct n_hdlc *n_hdlc = tty->disc_data;
536*4882a593Smuzhiyun 	int error = 0;
537*4882a593Smuzhiyun 	DECLARE_WAITQUEUE(wait, current);
538*4882a593Smuzhiyun 	struct n_hdlc_buf *tbuf;
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	pr_debug("%s() called count=%zd\n", __func__, count);
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun 	if (n_hdlc->magic != HDLC_MAGIC)
543*4882a593Smuzhiyun 		return -EIO;
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	/* verify frame size */
546*4882a593Smuzhiyun 	if (count > maxframe) {
547*4882a593Smuzhiyun 		pr_debug("%s: truncating user packet from %zu to %d\n",
548*4882a593Smuzhiyun 				__func__, count, maxframe);
549*4882a593Smuzhiyun 		count = maxframe;
550*4882a593Smuzhiyun 	}
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 	add_wait_queue(&tty->write_wait, &wait);
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	for (;;) {
555*4882a593Smuzhiyun 		set_current_state(TASK_INTERRUPTIBLE);
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 		tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list);
558*4882a593Smuzhiyun 		if (tbuf)
559*4882a593Smuzhiyun 			break;
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun 		if (tty_io_nonblock(tty, file)) {
562*4882a593Smuzhiyun 			error = -EAGAIN;
563*4882a593Smuzhiyun 			break;
564*4882a593Smuzhiyun 		}
565*4882a593Smuzhiyun 		schedule();
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 		if (signal_pending(current)) {
568*4882a593Smuzhiyun 			error = -EINTR;
569*4882a593Smuzhiyun 			break;
570*4882a593Smuzhiyun 		}
571*4882a593Smuzhiyun 	}
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	__set_current_state(TASK_RUNNING);
574*4882a593Smuzhiyun 	remove_wait_queue(&tty->write_wait, &wait);
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 	if (!error) {
577*4882a593Smuzhiyun 		/* Retrieve the user's buffer */
578*4882a593Smuzhiyun 		memcpy(tbuf->buf, data, count);
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 		/* Send the data */
581*4882a593Smuzhiyun 		tbuf->count = error = count;
582*4882a593Smuzhiyun 		n_hdlc_buf_put(&n_hdlc->tx_buf_list, tbuf);
583*4882a593Smuzhiyun 		n_hdlc_send_frames(n_hdlc, tty);
584*4882a593Smuzhiyun 	}
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	return error;
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun }	/* end of n_hdlc_tty_write() */
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun /**
591*4882a593Smuzhiyun  * n_hdlc_tty_ioctl - process IOCTL system call for the tty device.
592*4882a593Smuzhiyun  * @tty: pointer to tty instance data
593*4882a593Smuzhiyun  * @file: pointer to open file object for device
594*4882a593Smuzhiyun  * @cmd: IOCTL command code
595*4882a593Smuzhiyun  * @arg: argument for IOCTL call (cmd dependent)
596*4882a593Smuzhiyun  *
597*4882a593Smuzhiyun  * Returns command dependent result.
598*4882a593Smuzhiyun  */
n_hdlc_tty_ioctl(struct tty_struct * tty,struct file * file,unsigned int cmd,unsigned long arg)599*4882a593Smuzhiyun static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
600*4882a593Smuzhiyun 			    unsigned int cmd, unsigned long arg)
601*4882a593Smuzhiyun {
602*4882a593Smuzhiyun 	struct n_hdlc *n_hdlc = tty->disc_data;
603*4882a593Smuzhiyun 	int error = 0;
604*4882a593Smuzhiyun 	int count;
605*4882a593Smuzhiyun 	unsigned long flags;
606*4882a593Smuzhiyun 	struct n_hdlc_buf *buf = NULL;
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun 	pr_debug("%s() called %d\n", __func__, cmd);
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 	/* Verify the status of the device */
611*4882a593Smuzhiyun 	if (n_hdlc->magic != HDLC_MAGIC)
612*4882a593Smuzhiyun 		return -EBADF;
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 	switch (cmd) {
615*4882a593Smuzhiyun 	case FIONREAD:
616*4882a593Smuzhiyun 		/* report count of read data available */
617*4882a593Smuzhiyun 		/* in next available frame (if any) */
618*4882a593Smuzhiyun 		spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock, flags);
619*4882a593Smuzhiyun 		buf = list_first_entry_or_null(&n_hdlc->rx_buf_list.list,
620*4882a593Smuzhiyun 						struct n_hdlc_buf, list_item);
621*4882a593Smuzhiyun 		if (buf)
622*4882a593Smuzhiyun 			count = buf->count;
623*4882a593Smuzhiyun 		else
624*4882a593Smuzhiyun 			count = 0;
625*4882a593Smuzhiyun 		spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock, flags);
626*4882a593Smuzhiyun 		error = put_user(count, (int __user *)arg);
627*4882a593Smuzhiyun 		break;
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 	case TIOCOUTQ:
630*4882a593Smuzhiyun 		/* get the pending tx byte count in the driver */
631*4882a593Smuzhiyun 		count = tty_chars_in_buffer(tty);
632*4882a593Smuzhiyun 		/* add size of next output frame in queue */
633*4882a593Smuzhiyun 		spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
634*4882a593Smuzhiyun 		buf = list_first_entry_or_null(&n_hdlc->tx_buf_list.list,
635*4882a593Smuzhiyun 						struct n_hdlc_buf, list_item);
636*4882a593Smuzhiyun 		if (buf)
637*4882a593Smuzhiyun 			count += buf->count;
638*4882a593Smuzhiyun 		spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
639*4882a593Smuzhiyun 		error = put_user(count, (int __user *)arg);
640*4882a593Smuzhiyun 		break;
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 	case TCFLSH:
643*4882a593Smuzhiyun 		switch (arg) {
644*4882a593Smuzhiyun 		case TCIOFLUSH:
645*4882a593Smuzhiyun 		case TCOFLUSH:
646*4882a593Smuzhiyun 			flush_tx_queue(tty);
647*4882a593Smuzhiyun 		}
648*4882a593Smuzhiyun 		fallthrough;	/* to default */
649*4882a593Smuzhiyun 
650*4882a593Smuzhiyun 	default:
651*4882a593Smuzhiyun 		error = n_tty_ioctl_helper(tty, file, cmd, arg);
652*4882a593Smuzhiyun 		break;
653*4882a593Smuzhiyun 	}
654*4882a593Smuzhiyun 	return error;
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun }	/* end of n_hdlc_tty_ioctl() */
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun /**
659*4882a593Smuzhiyun  * n_hdlc_tty_poll - TTY callback for poll system call
660*4882a593Smuzhiyun  * @tty: pointer to tty instance data
661*4882a593Smuzhiyun  * @filp: pointer to open file object for device
662*4882a593Smuzhiyun  * @wait: wait queue for operations
663*4882a593Smuzhiyun  *
664*4882a593Smuzhiyun  * Determine which operations (read/write) will not block and return info
665*4882a593Smuzhiyun  * to caller.
666*4882a593Smuzhiyun  * Returns a bit mask containing info on which ops will not block.
667*4882a593Smuzhiyun  */
n_hdlc_tty_poll(struct tty_struct * tty,struct file * filp,poll_table * wait)668*4882a593Smuzhiyun static __poll_t n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
669*4882a593Smuzhiyun 				    poll_table *wait)
670*4882a593Smuzhiyun {
671*4882a593Smuzhiyun 	struct n_hdlc *n_hdlc = tty->disc_data;
672*4882a593Smuzhiyun 	__poll_t mask = 0;
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	if (n_hdlc->magic != HDLC_MAGIC)
675*4882a593Smuzhiyun 		return 0;
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun 	/*
678*4882a593Smuzhiyun 	 * queue the current process into any wait queue that may awaken in the
679*4882a593Smuzhiyun 	 * future (read and write)
680*4882a593Smuzhiyun 	 */
681*4882a593Smuzhiyun 	poll_wait(filp, &tty->read_wait, wait);
682*4882a593Smuzhiyun 	poll_wait(filp, &tty->write_wait, wait);
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun 	/* set bits for operations that won't block */
685*4882a593Smuzhiyun 	if (!list_empty(&n_hdlc->rx_buf_list.list))
686*4882a593Smuzhiyun 		mask |= EPOLLIN | EPOLLRDNORM;	/* readable */
687*4882a593Smuzhiyun 	if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
688*4882a593Smuzhiyun 		mask |= EPOLLHUP;
689*4882a593Smuzhiyun 	if (tty_hung_up_p(filp))
690*4882a593Smuzhiyun 		mask |= EPOLLHUP;
691*4882a593Smuzhiyun 	if (!tty_is_writelocked(tty) &&
692*4882a593Smuzhiyun 			!list_empty(&n_hdlc->tx_free_buf_list.list))
693*4882a593Smuzhiyun 		mask |= EPOLLOUT | EPOLLWRNORM;	/* writable */
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	return mask;
696*4882a593Smuzhiyun }	/* end of n_hdlc_tty_poll() */
697*4882a593Smuzhiyun 
n_hdlc_alloc_buf(struct n_hdlc_buf_list * list,unsigned int count,const char * name)698*4882a593Smuzhiyun static void n_hdlc_alloc_buf(struct n_hdlc_buf_list *list, unsigned int count,
699*4882a593Smuzhiyun 		const char *name)
700*4882a593Smuzhiyun {
701*4882a593Smuzhiyun 	struct n_hdlc_buf *buf;
702*4882a593Smuzhiyun 	unsigned int i;
703*4882a593Smuzhiyun 
704*4882a593Smuzhiyun 	for (i = 0; i < count; i++) {
705*4882a593Smuzhiyun 		buf = kmalloc(struct_size(buf, buf, maxframe), GFP_KERNEL);
706*4882a593Smuzhiyun 		if (!buf) {
707*4882a593Smuzhiyun 			pr_debug("%s(), kmalloc() failed for %s buffer %u\n",
708*4882a593Smuzhiyun 					__func__, name, i);
709*4882a593Smuzhiyun 			return;
710*4882a593Smuzhiyun 		}
711*4882a593Smuzhiyun 		n_hdlc_buf_put(list, buf);
712*4882a593Smuzhiyun 	}
713*4882a593Smuzhiyun }
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun /**
716*4882a593Smuzhiyun  * n_hdlc_alloc - allocate an n_hdlc instance data structure
717*4882a593Smuzhiyun  *
718*4882a593Smuzhiyun  * Returns a pointer to newly created structure if success, otherwise %NULL
719*4882a593Smuzhiyun  */
n_hdlc_alloc(void)720*4882a593Smuzhiyun static struct n_hdlc *n_hdlc_alloc(void)
721*4882a593Smuzhiyun {
722*4882a593Smuzhiyun 	struct n_hdlc *n_hdlc = kzalloc(sizeof(*n_hdlc), GFP_KERNEL);
723*4882a593Smuzhiyun 
724*4882a593Smuzhiyun 	if (!n_hdlc)
725*4882a593Smuzhiyun 		return NULL;
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	spin_lock_init(&n_hdlc->rx_free_buf_list.spinlock);
728*4882a593Smuzhiyun 	spin_lock_init(&n_hdlc->tx_free_buf_list.spinlock);
729*4882a593Smuzhiyun 	spin_lock_init(&n_hdlc->rx_buf_list.spinlock);
730*4882a593Smuzhiyun 	spin_lock_init(&n_hdlc->tx_buf_list.spinlock);
731*4882a593Smuzhiyun 
732*4882a593Smuzhiyun 	INIT_LIST_HEAD(&n_hdlc->rx_free_buf_list.list);
733*4882a593Smuzhiyun 	INIT_LIST_HEAD(&n_hdlc->tx_free_buf_list.list);
734*4882a593Smuzhiyun 	INIT_LIST_HEAD(&n_hdlc->rx_buf_list.list);
735*4882a593Smuzhiyun 	INIT_LIST_HEAD(&n_hdlc->tx_buf_list.list);
736*4882a593Smuzhiyun 
737*4882a593Smuzhiyun 	n_hdlc_alloc_buf(&n_hdlc->rx_free_buf_list, DEFAULT_RX_BUF_COUNT, "rx");
738*4882a593Smuzhiyun 	n_hdlc_alloc_buf(&n_hdlc->tx_free_buf_list, DEFAULT_TX_BUF_COUNT, "tx");
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun 	/* Initialize the control block */
741*4882a593Smuzhiyun 	n_hdlc->magic  = HDLC_MAGIC;
742*4882a593Smuzhiyun 
743*4882a593Smuzhiyun 	return n_hdlc;
744*4882a593Smuzhiyun 
745*4882a593Smuzhiyun }	/* end of n_hdlc_alloc() */
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun /**
748*4882a593Smuzhiyun  * n_hdlc_buf_return - put the HDLC buffer after the head of the specified list
749*4882a593Smuzhiyun  * @buf_list: pointer to the buffer list
750*4882a593Smuzhiyun  * @buf: pointer to the buffer
751*4882a593Smuzhiyun  */
n_hdlc_buf_return(struct n_hdlc_buf_list * buf_list,struct n_hdlc_buf * buf)752*4882a593Smuzhiyun static void n_hdlc_buf_return(struct n_hdlc_buf_list *buf_list,
753*4882a593Smuzhiyun 						struct n_hdlc_buf *buf)
754*4882a593Smuzhiyun {
755*4882a593Smuzhiyun 	unsigned long flags;
756*4882a593Smuzhiyun 
757*4882a593Smuzhiyun 	spin_lock_irqsave(&buf_list->spinlock, flags);
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun 	list_add(&buf->list_item, &buf_list->list);
760*4882a593Smuzhiyun 	buf_list->count++;
761*4882a593Smuzhiyun 
762*4882a593Smuzhiyun 	spin_unlock_irqrestore(&buf_list->spinlock, flags);
763*4882a593Smuzhiyun }
764*4882a593Smuzhiyun 
765*4882a593Smuzhiyun /**
766*4882a593Smuzhiyun  * n_hdlc_buf_put - add specified HDLC buffer to tail of specified list
767*4882a593Smuzhiyun  * @buf_list: pointer to buffer list
768*4882a593Smuzhiyun  * @buf: pointer to buffer
769*4882a593Smuzhiyun  */
n_hdlc_buf_put(struct n_hdlc_buf_list * buf_list,struct n_hdlc_buf * buf)770*4882a593Smuzhiyun static void n_hdlc_buf_put(struct n_hdlc_buf_list *buf_list,
771*4882a593Smuzhiyun 			   struct n_hdlc_buf *buf)
772*4882a593Smuzhiyun {
773*4882a593Smuzhiyun 	unsigned long flags;
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 	spin_lock_irqsave(&buf_list->spinlock, flags);
776*4882a593Smuzhiyun 
777*4882a593Smuzhiyun 	list_add_tail(&buf->list_item, &buf_list->list);
778*4882a593Smuzhiyun 	buf_list->count++;
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun 	spin_unlock_irqrestore(&buf_list->spinlock, flags);
781*4882a593Smuzhiyun }	/* end of n_hdlc_buf_put() */
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun /**
784*4882a593Smuzhiyun  * n_hdlc_buf_get - remove and return an HDLC buffer from list
785*4882a593Smuzhiyun  * @buf_list: pointer to HDLC buffer list
786*4882a593Smuzhiyun  *
787*4882a593Smuzhiyun  * Remove and return an HDLC buffer from the head of the specified HDLC buffer
788*4882a593Smuzhiyun  * list.
789*4882a593Smuzhiyun  * Returns a pointer to HDLC buffer if available, otherwise %NULL.
790*4882a593Smuzhiyun  */
n_hdlc_buf_get(struct n_hdlc_buf_list * buf_list)791*4882a593Smuzhiyun static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *buf_list)
792*4882a593Smuzhiyun {
793*4882a593Smuzhiyun 	unsigned long flags;
794*4882a593Smuzhiyun 	struct n_hdlc_buf *buf;
795*4882a593Smuzhiyun 
796*4882a593Smuzhiyun 	spin_lock_irqsave(&buf_list->spinlock, flags);
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun 	buf = list_first_entry_or_null(&buf_list->list,
799*4882a593Smuzhiyun 						struct n_hdlc_buf, list_item);
800*4882a593Smuzhiyun 	if (buf) {
801*4882a593Smuzhiyun 		list_del(&buf->list_item);
802*4882a593Smuzhiyun 		buf_list->count--;
803*4882a593Smuzhiyun 	}
804*4882a593Smuzhiyun 
805*4882a593Smuzhiyun 	spin_unlock_irqrestore(&buf_list->spinlock, flags);
806*4882a593Smuzhiyun 	return buf;
807*4882a593Smuzhiyun }	/* end of n_hdlc_buf_get() */
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun static struct tty_ldisc_ops n_hdlc_ldisc = {
810*4882a593Smuzhiyun 	.owner		= THIS_MODULE,
811*4882a593Smuzhiyun 	.magic		= TTY_LDISC_MAGIC,
812*4882a593Smuzhiyun 	.name		= "hdlc",
813*4882a593Smuzhiyun 	.open		= n_hdlc_tty_open,
814*4882a593Smuzhiyun 	.close		= n_hdlc_tty_close,
815*4882a593Smuzhiyun 	.read		= n_hdlc_tty_read,
816*4882a593Smuzhiyun 	.write		= n_hdlc_tty_write,
817*4882a593Smuzhiyun 	.ioctl		= n_hdlc_tty_ioctl,
818*4882a593Smuzhiyun 	.poll		= n_hdlc_tty_poll,
819*4882a593Smuzhiyun 	.receive_buf	= n_hdlc_tty_receive,
820*4882a593Smuzhiyun 	.write_wakeup	= n_hdlc_tty_wakeup,
821*4882a593Smuzhiyun 	.flush_buffer   = flush_rx_queue,
822*4882a593Smuzhiyun };
823*4882a593Smuzhiyun 
n_hdlc_init(void)824*4882a593Smuzhiyun static int __init n_hdlc_init(void)
825*4882a593Smuzhiyun {
826*4882a593Smuzhiyun 	int status;
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun 	/* range check maxframe arg */
829*4882a593Smuzhiyun 	maxframe = clamp(maxframe, 4096, MAX_HDLC_FRAME_SIZE);
830*4882a593Smuzhiyun 
831*4882a593Smuzhiyun 	status = tty_register_ldisc(N_HDLC, &n_hdlc_ldisc);
832*4882a593Smuzhiyun 	if (!status)
833*4882a593Smuzhiyun 		pr_info("N_HDLC line discipline registered with maxframe=%d\n",
834*4882a593Smuzhiyun 				maxframe);
835*4882a593Smuzhiyun 	else
836*4882a593Smuzhiyun 		pr_err("N_HDLC: error registering line discipline: %d\n",
837*4882a593Smuzhiyun 				status);
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun 	return status;
840*4882a593Smuzhiyun 
841*4882a593Smuzhiyun }	/* end of init_module() */
842*4882a593Smuzhiyun 
n_hdlc_exit(void)843*4882a593Smuzhiyun static void __exit n_hdlc_exit(void)
844*4882a593Smuzhiyun {
845*4882a593Smuzhiyun 	/* Release tty registration of line discipline */
846*4882a593Smuzhiyun 	int status = tty_unregister_ldisc(N_HDLC);
847*4882a593Smuzhiyun 
848*4882a593Smuzhiyun 	if (status)
849*4882a593Smuzhiyun 		pr_err("N_HDLC: can't unregister line discipline (err = %d)\n",
850*4882a593Smuzhiyun 				status);
851*4882a593Smuzhiyun 	else
852*4882a593Smuzhiyun 		pr_info("N_HDLC: line discipline unregistered\n");
853*4882a593Smuzhiyun }
854*4882a593Smuzhiyun 
855*4882a593Smuzhiyun module_init(n_hdlc_init);
856*4882a593Smuzhiyun module_exit(n_hdlc_exit);
857*4882a593Smuzhiyun 
858*4882a593Smuzhiyun MODULE_LICENSE("GPL");
859*4882a593Smuzhiyun MODULE_AUTHOR("Paul Fulghum paulkf@microgate.com");
860*4882a593Smuzhiyun module_param(maxframe, int, 0);
861*4882a593Smuzhiyun MODULE_ALIAS_LDISC(N_HDLC);
862