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