From f70575805708cabdedea7498aaa3f710fde4d920 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Wed, 31 Jan 2024 03:29:01 +0000 Subject: [PATCH] add lvds1024*800 --- kernel/drivers/tty/n_gsm.c | 892 +++++++++++++++++++++++++++++++++++------------------------ 1 files changed, 527 insertions(+), 365 deletions(-) diff --git a/kernel/drivers/tty/n_gsm.c b/kernel/drivers/tty/n_gsm.c index 4d58114..94c9634 100644 --- a/kernel/drivers/tty/n_gsm.c +++ b/kernel/drivers/tty/n_gsm.c @@ -50,6 +50,7 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/gsmmux.h> +#include "tty.h" static int debug; module_param(debug, int, 0600); @@ -72,14 +73,15 @@ */ #define MAX_MRU 1500 #define MAX_MTU 1500 +/* SOF, ADDR, CTRL, LEN1, LEN2, ..., FCS, EOF */ +#define PROT_OVERHEAD 7 #define GSM_NET_TX_TIMEOUT (HZ*10) /** * struct gsm_mux_net - network interface - * @struct gsm_dlci* dlci * * Created when net interface is initialized. - **/ + */ struct gsm_mux_net { struct kref ref; struct gsm_dlci *dlci; @@ -97,7 +99,19 @@ u8 ctrl; /* Control byte + flags */ unsigned int len; /* Length of data block (can be zero) */ unsigned char *data; /* Points into buffer but not at the start */ - unsigned char buffer[0]; + unsigned char buffer[]; +}; + +enum gsm_dlci_state { + DLCI_CLOSED, + DLCI_OPENING, /* Sending SABM not seen UA */ + DLCI_OPEN, /* SABM/UA complete */ + DLCI_CLOSING, /* Sending DISC not seen UA/DM */ +}; + +enum gsm_dlci_mode { + DLCI_MODE_ABM, /* Normal Asynchronous Balanced Mode */ + DLCI_MODE_ADM, /* Asynchronous Disconnected Mode */ }; /* @@ -113,38 +127,31 @@ struct gsm_dlci { struct gsm_mux *gsm; int addr; - int state; -#define DLCI_CLOSED 0 -#define DLCI_OPENING 1 /* Sending SABM not seen UA */ -#define DLCI_OPEN 2 /* SABM/UA complete */ -#define DLCI_CLOSING 3 /* Sending DISC not seen UA/DM */ + enum gsm_dlci_state state; struct mutex mutex; /* Link layer */ - int mode; -#define DLCI_MODE_ABM 0 /* Normal Asynchronous Balanced Mode */ -#define DLCI_MODE_ADM 1 /* Asynchronous Disconnected Mode */ + enum gsm_dlci_mode mode; spinlock_t lock; /* Protects the internal state */ struct timer_list t1; /* Retransmit timer for SABM and UA */ int retries; /* Uplink tty if active */ struct tty_port port; /* The tty bound to this DLCI if there is one */ - struct kfifo *fifo; /* Queue fifo for the DLCI */ - struct kfifo _fifo; /* For new fifo API porting only */ + struct kfifo fifo; /* Queue fifo for the DLCI */ int adaption; /* Adaption layer in use */ int prev_adaption; u32 modem_rx; /* Our incoming virtual modem lines */ u32 modem_tx; /* Our outgoing modem lines */ - int dead; /* Refuse re-open */ + bool dead; /* Refuse re-open */ /* Flow control */ - int throttled; /* Private copy of throttle state */ - int constipated; /* Throttle status for outgoing */ + bool throttled; /* Private copy of throttle state */ + bool constipated; /* Throttle status for outgoing */ /* Packetised I/O */ struct sk_buff *skb; /* Frame being sent */ struct sk_buff_head skb_list; /* Queued frames */ /* Data handling callback */ - void (*data)(struct gsm_dlci *dlci, u8 *data, int len); - void (*prev_data)(struct gsm_dlci *dlci, u8 *data, int len); + void (*data)(struct gsm_dlci *dlci, const u8 *data, int len); + void (*prev_data)(struct gsm_dlci *dlci, const u8 *data, int len); struct net_device *net; /* network interface, if created */ }; @@ -166,6 +173,20 @@ int len; /* Length of block for retransmission */ int done; /* Done flag */ int error; /* Error if any */ +}; + +enum gsm_mux_state { + GSM_SEARCH, + GSM_START, + GSM_ADDRESS, + GSM_CONTROL, + GSM_LEN, + GSM_DATA, + GSM_FCS, + GSM_OVERRUN, + GSM_LEN0, + GSM_LEN1, + GSM_SSOF, }; /* @@ -192,41 +213,28 @@ /* Framing Layer */ unsigned char *buf; - int state; -#define GSM_SEARCH 0 -#define GSM_START 1 -#define GSM_ADDRESS 2 -#define GSM_CONTROL 3 -#define GSM_LEN 4 -#define GSM_DATA 5 -#define GSM_FCS 6 -#define GSM_OVERRUN 7 -#define GSM_LEN0 8 -#define GSM_LEN1 9 -#define GSM_SSOF 10 + enum gsm_mux_state state; unsigned int len; unsigned int address; unsigned int count; - int escape; + bool escape; int encoding; u8 control; u8 fcs; u8 received_fcs; u8 *txframe; /* TX framing buffer */ - /* Methods for the receiver side */ + /* Method for the receiver side */ void (*receive)(struct gsm_mux *gsm, u8 ch); - void (*error)(struct gsm_mux *gsm, u8 ch, u8 flag); - /* And transmit side */ - int (*output)(struct gsm_mux *mux, u8 *data, int len); /* Link Layer */ unsigned int mru; unsigned int mtu; int initiator; /* Did we initiate connection */ - int dead; /* Has the mux been shut down */ + bool dead; /* Has the mux been shut down */ struct gsm_dlci *dlci[NUM_DLCI]; - int constipated; /* Asked by remote to shut up */ + int old_c_iflag; /* termios c_iflag value before attach */ + bool constipated; /* Asked by remote to shut up */ spinlock_t tx_lock; unsigned int tx_bytes; /* TX data outstanding */ @@ -359,6 +367,8 @@ #define INIT_FCS 0xFF #define GOOD_FCS 0xCF +static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len); + /** * gsm_fcs_add - update FCS * @fcs: Current FCS @@ -393,7 +403,7 @@ /** * gsm_read_ea - read a byte into an EA * @val: variable holding value - * c: byte going into the EA + * @c: byte going into the EA * * Processes one byte of an EA. Updates the passed variable * and returns 1 if the EA is now completely read @@ -406,6 +416,27 @@ *val |= c >> 1; /* Was this the last byte of the EA 1 = yes*/ return c & EA; +} + +/** + * gsm_read_ea_val - read a value until EA + * @val: variable holding value + * @data: buffer of data + * @dlen: length of data + * + * Processes an EA value. Updates the passed variable and + * returns the processed data length. + */ +static unsigned int gsm_read_ea_val(unsigned int *val, const u8 *data, int dlen) +{ + unsigned int len = 0; + + for (; dlen > 0; dlen--) { + len++; + if (gsm_read_ea(val, *data++)) + break; + } + return len; } /** @@ -497,18 +528,7 @@ else pr_cont("(F)"); - if (dlen) { - int ct = 0; - while (dlen--) { - if (ct % 8 == 0) { - pr_cont("\n"); - pr_debug(" "); - } - pr_cont("%02X ", *data++); - ct++; - } - } - pr_cont("\n"); + print_hex_dump_bytes("", DUMP_PREFIX_NONE, data, dlen); } @@ -518,8 +538,8 @@ /** * gsm_stuff_packet - bytestuff a packet - * @ibuf: input - * @obuf: output + * @input: input buffer + * @output: output buffer * @len: length of input * * Expand a buffer by bytestuffing it. The worst case size change @@ -592,7 +612,7 @@ WARN_ON(1); return; } - gsm->output(gsm, cbuf, len); + gsmld_output(gsm, cbuf, len); gsm_print_packet("-->", addr, cr, control, NULL, 0); } @@ -656,6 +676,37 @@ } /** + * gsm_is_flow_ctrl_msg - checks if flow control message + * @msg: message to check + * + * Returns true if the given message is a flow control command of the + * control channel. False is returned in any other case. + */ +static bool gsm_is_flow_ctrl_msg(struct gsm_msg *msg) +{ + unsigned int cmd; + + if (msg->addr > 0) + return false; + + switch (msg->ctrl & ~PF) { + case UI: + case UIH: + cmd = 0; + if (gsm_read_ea_val(&cmd, msg->data + 2, msg->len - 2) < 1) + break; + switch (cmd & ~PF) { + case CMD_FCOFF: + case CMD_FCON: + return true; + } + break; + } + + return false; +} + +/** * gsm_data_kick - poke the queue * @gsm: GSM Mux * @@ -673,7 +724,7 @@ int len; list_for_each_entry_safe(msg, nmsg, &gsm->tx_list, list) { - if (gsm->constipated && msg->addr) + if (gsm->constipated && !gsm_is_flow_ctrl_msg(msg)) continue; if (gsm->encoding != 0) { gsm->txframe[0] = GSM1_SOF; @@ -692,7 +743,7 @@ print_hex_dump_bytes("gsm_data_kick: ", DUMP_PREFIX_OFFSET, gsm->txframe, len); - if (gsm->output(gsm, gsm->txframe, len) < 0) + if (gsmld_output(gsm, gsm->txframe, len) < 0) break; /* FIXME: Can eliminate one SOF in many more cases */ gsm->tx_bytes -= msg->len; @@ -797,41 +848,51 @@ { struct gsm_msg *msg; u8 *dp; - int len, total_size, size; - int h = dlci->adaption - 1; + int h, len, size; - total_size = 0; - while (1) { - len = kfifo_len(dlci->fifo); - if (len == 0) - return total_size; + /* for modem bits without break data */ + h = ((dlci->adaption == 1) ? 0 : 1); - /* MTU/MRU count only the data bits */ - if (len > gsm->mtu) - len = gsm->mtu; + len = kfifo_len(&dlci->fifo); + if (len == 0) + return 0; - size = len + h; + /* MTU/MRU count only the data bits but watch adaption mode */ + if ((len + h) > gsm->mtu) + len = gsm->mtu - h; - msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype); - /* FIXME: need a timer or something to kick this so it can't - get stuck with no work outstanding and no buffer free */ - if (msg == NULL) - return -ENOMEM; - dp = msg->data; - switch (dlci->adaption) { - case 1: /* Unstructured */ - break; - case 2: /* Unstructed with modem bits. - Always one byte as we never send inline break data */ - *dp++ = gsm_encode_modem(dlci); - break; - } - WARN_ON(kfifo_out_locked(dlci->fifo, dp , len, &dlci->lock) != len); - __gsm_data_queue(dlci, msg); - total_size += size; + size = len + h; + + msg = gsm_data_alloc(gsm, dlci->addr, size, gsm->ftype); + /* FIXME: need a timer or something to kick this so it can't + * get stuck with no work outstanding and no buffer free + */ + if (!msg) + return -ENOMEM; + dp = msg->data; + switch (dlci->adaption) { + case 1: /* Unstructured */ + break; + case 2: /* Unstructured with modem bits. + * Always one byte as we never send inline break data + */ + *dp++ = (gsm_encode_modem(dlci) << 1) | EA; + break; + default: + pr_err("%s: unsupported adaption %d\n", __func__, + dlci->adaption); + break; } + + WARN_ON(len != kfifo_out_locked(&dlci->fifo, dp, len, + &dlci->lock)); + + /* Notify upper layer about available send space. */ + tty_port_tty_wakeup(&dlci->port); + + __gsm_data_queue(dlci, msg); /* Bytes of data we used up */ - return total_size; + return size; } /** @@ -994,7 +1055,7 @@ * Encode up and queue a UI/UIH frame containing our response. */ -static void gsm_control_reply(struct gsm_mux *gsm, int cmd, u8 *data, +static void gsm_control_reply(struct gsm_mux *gsm, int cmd, const u8 *data, int dlen) { struct gsm_msg *msg; @@ -1040,9 +1101,9 @@ fc = (modem & MDM_FC) || !(modem & MDM_RTR); if (fc && !dlci->constipated) { /* Need to throttle our output on this device */ - dlci->constipated = 1; + dlci->constipated = true; } else if (!fc && dlci->constipated) { - dlci->constipated = 0; + dlci->constipated = false; gsm_dlci_data_kick(dlci); } @@ -1079,14 +1140,14 @@ * and if need be stuff a break message down the tty. */ -static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen) +static void gsm_control_modem(struct gsm_mux *gsm, const u8 *data, int clen) { unsigned int addr = 0; unsigned int modem = 0; unsigned int brk = 0; struct gsm_dlci *dlci; int len = clen; - u8 *dp = data; + const u8 *dp = data; struct tty_struct *tty; while (gsm_read_ea(&addr, *dp++) == 0) { @@ -1140,13 +1201,13 @@ * this into the uplink tty if present */ -static void gsm_control_rls(struct gsm_mux *gsm, u8 *data, int clen) +static void gsm_control_rls(struct gsm_mux *gsm, const u8 *data, int clen) { struct tty_port *port; unsigned int addr = 0; u8 bits; int len = clen; - u8 *dp = data; + const u8 *dp = data; while (gsm_read_ea(&addr, *dp++) == 0) { len--; @@ -1195,7 +1256,7 @@ */ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command, - u8 *data, int clen) + const u8 *data, int clen) { u8 buf[1]; unsigned long flags; @@ -1205,8 +1266,8 @@ struct gsm_dlci *dlci = gsm->dlci[0]; /* Modem wishes to close down */ if (dlci) { - dlci->dead = 1; - gsm->dead = 1; + dlci->dead = true; + gsm->dead = true; gsm_dlci_begin_close(dlci); } } @@ -1217,7 +1278,7 @@ break; case CMD_FCON: /* Modem can accept data again */ - gsm->constipated = 0; + gsm->constipated = false; gsm_control_reply(gsm, CMD_FCON, NULL, 0); /* Kick the link in case it is idling */ spin_lock_irqsave(&gsm->tx_lock, flags); @@ -1226,7 +1287,7 @@ break; case CMD_FCOFF: /* Modem wants us to STFU */ - gsm->constipated = 1; + gsm->constipated = true; gsm_control_reply(gsm, CMD_FCOFF, NULL, 0); break; case CMD_MSC: @@ -1267,7 +1328,7 @@ */ static void gsm_control_response(struct gsm_mux *gsm, unsigned int command, - u8 *data, int clen) + const u8 *data, int clen) { struct gsm_control *ctrl; unsigned long flags; @@ -1300,17 +1361,18 @@ static void gsm_control_transmit(struct gsm_mux *gsm, struct gsm_control *ctrl) { - struct gsm_msg *msg = gsm_data_alloc(gsm, 0, ctrl->len + 1, gsm->ftype); + struct gsm_msg *msg = gsm_data_alloc(gsm, 0, ctrl->len + 2, gsm->ftype); if (msg == NULL) return; - msg->data[0] = (ctrl->cmd << 1) | 2 | EA; /* command */ - memcpy(msg->data + 1, ctrl->data, ctrl->len); + msg->data[0] = (ctrl->cmd << 1) | CR | EA; /* command */ + msg->data[1] = (ctrl->len << 1) | EA; + memcpy(msg->data + 2, ctrl->data, ctrl->len); gsm_data_queue(gsm->dlci[0], msg); } /** * gsm_control_retransmit - retransmit a control frame - * @data: pointer to our gsm object + * @t: timer contained in our gsm object * * Called off the T2 timer expiry in order to retransmit control frames * that have been lost in the system somewhere. The control_lock protects @@ -1327,8 +1389,7 @@ spin_lock_irqsave(&gsm->control_lock, flags); ctrl = gsm->pending_cmd; if (ctrl) { - gsm->cretries--; - if (gsm->cretries == 0) { + if (gsm->cretries == 0 || !gsm->dlci[0] || gsm->dlci[0]->dead) { gsm->pending_cmd = NULL; ctrl->error = -ETIMEDOUT; ctrl->done = 1; @@ -1336,6 +1397,7 @@ wake_up(&gsm->event); return; } + gsm->cretries--; gsm_control_transmit(gsm, ctrl); mod_timer(&gsm->t2_timer, jiffies + gsm->t2 * HZ / 100); } @@ -1347,7 +1409,7 @@ * @gsm: the GSM channel * @command: command to send including CR bit * @data: bytes of data (must be kmalloced) - * @len: length of the block to send + * @clen: length of the block to send * * Queue and dispatch a control command. Only one command can be * active at a time. In theory more can be outstanding but the matching @@ -1358,7 +1420,7 @@ unsigned int command, u8 *data, int clen) { struct gsm_control *ctrl = kzalloc(sizeof(struct gsm_control), - GFP_KERNEL); + GFP_ATOMIC); unsigned long flags; if (ctrl == NULL) return NULL; @@ -1376,7 +1438,7 @@ /* If DLCI0 is in ADM mode skip retries, it won't respond */ if (gsm->dlci[0]->mode == DLCI_MODE_ADM) - gsm->cretries = 1; + gsm->cretries = 0; else gsm->cretries = gsm->n2; @@ -1424,15 +1486,24 @@ static void gsm_dlci_close(struct gsm_dlci *dlci) { + unsigned long flags; + del_timer(&dlci->t1); if (debug & 8) pr_debug("DLCI %d goes closed.\n", dlci->addr); dlci->state = DLCI_CLOSED; + /* Prevent us from sending data before the link is up again */ + dlci->constipated = true; if (dlci->addr != 0) { tty_port_tty_hangup(&dlci->port, false); - kfifo_reset(dlci->fifo); + spin_lock_irqsave(&dlci->lock, flags); + kfifo_reset(&dlci->fifo); + spin_unlock_irqrestore(&dlci->lock, flags); + /* Ensure that gsmtty_open() can return. */ + tty_port_set_initialized(&dlci->port, 0); + wake_up_interruptible(&dlci->port.open_wait); } else - dlci->gsm->dead = 1; + dlci->gsm->dead = true; wake_up(&dlci->gsm->event); /* A DLCI 0 close is a MUX termination so we need to kick that back to userspace somehow */ @@ -1452,6 +1523,7 @@ del_timer(&dlci->t1); /* This will let a tty open continue */ dlci->state = DLCI_OPEN; + dlci->constipated = false; if (debug & 8) pr_debug("DLCI %d goes open.\n", dlci->addr); wake_up(&dlci->gsm->event); @@ -1459,7 +1531,7 @@ /** * gsm_dlci_t1 - T1 timer expiry - * @dlci: DLCI that opened + * @t: timer contained in the DLCI that opened * * The T1 timer handles retransmits of control frames (essentially of * SABM and DISC). We resend the command until the retry count runs out @@ -1479,8 +1551,8 @@ switch (dlci->state) { case DLCI_OPENING: - dlci->retries--; if (dlci->retries) { + dlci->retries--; gsm_command(dlci->gsm, dlci->addr, SABM|PF); mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100); } else if (!dlci->addr && gsm->control == (DM | PF)) { @@ -1495,12 +1567,15 @@ break; case DLCI_CLOSING: - dlci->retries--; if (dlci->retries) { + dlci->retries--; gsm_command(dlci->gsm, dlci->addr, DISC|PF); mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100); } else gsm_dlci_close(dlci); + break; + default: + pr_debug("%s: unhandled state: %d\n", __func__, dlci->state); break; } } @@ -1524,6 +1599,25 @@ dlci->state = DLCI_OPENING; gsm_command(dlci->gsm, dlci->addr, SABM|PF); mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100); +} + +/** + * gsm_dlci_set_opening - change state to opening + * @dlci: DLCI to open + * + * Change internal state to wait for DLCI open from initiator side. + * We set off timers and responses upon reception of an SABM. + */ +static void gsm_dlci_set_opening(struct gsm_dlci *dlci) +{ + switch (dlci->state) { + case DLCI_CLOSED: + case DLCI_CLOSING: + dlci->state = DLCI_OPENING; + break; + default: + break; + } } /** @@ -1552,14 +1646,14 @@ * gsm_dlci_data - data arrived * @dlci: channel * @data: block of bytes received - * @len: length of received block + * @clen: length of received block * * A UI or UIH frame has arrived which contains data for a channel * other than the control channel. If the relevant virtual tty is * open we shovel the bits down it, if not we drop them. */ -static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int clen) +static void gsm_dlci_data(struct gsm_dlci *dlci, const u8 *data, int clen) { /* krefs .. */ struct tty_port *port = &dlci->port; @@ -1571,14 +1665,11 @@ pr_debug("%d bytes for tty\n", len); switch (dlci->adaption) { /* Unsupported types */ - /* Packetised interruptible data */ - case 4: + case 4: /* Packetised interruptible data */ break; - /* Packetised uininterruptible voice/data */ - case 3: + case 3: /* Packetised uininterruptible voice/data */ break; - /* Asynchronous serial with line state in each frame */ - case 2: + case 2: /* Asynchronous serial with line state in each frame */ while (gsm_read_ea(&modem, *data++) == 0) { len--; if (len == 0) @@ -1589,8 +1680,8 @@ gsm_process_modem(tty, dlci, modem, clen); tty_kref_put(tty); } - /* Line state will go via DLCI 0 controls only */ - case 1: + fallthrough; + case 1: /* Line state will go via DLCI 0 controls only */ default: tty_insert_flip_string(port, data, len); tty_flip_buffer_push(port); @@ -1609,7 +1700,7 @@ * and we divide up the work accordingly. */ -static void gsm_dlci_command(struct gsm_dlci *dlci, u8 *data, int len) +static void gsm_dlci_command(struct gsm_dlci *dlci, const u8 *data, int len) { /* See what command is involved */ unsigned int command = 0; @@ -1654,8 +1745,7 @@ return NULL; spin_lock_init(&dlci->lock); mutex_init(&dlci->mutex); - dlci->fifo = &dlci->_fifo; - if (kfifo_alloc(&dlci->_fifo, 4096, GFP_KERNEL) < 0) { + if (kfifo_alloc(&dlci->fifo, 4096, GFP_KERNEL) < 0) { kfree(dlci); return NULL; } @@ -1668,17 +1758,20 @@ dlci->addr = addr; dlci->adaption = gsm->adaption; dlci->state = DLCI_CLOSED; - if (addr) + if (addr) { dlci->data = gsm_dlci_data; - else + /* Prevent us from sending data before the link is up */ + dlci->constipated = true; + } else { dlci->data = gsm_dlci_command; + } gsm->dlci[addr] = dlci; return dlci; } /** * gsm_dlci_free - free DLCI - * @dlci: DLCI to free + * @port: tty port for DLCI to free * * Free up a DLCI. * @@ -1690,7 +1783,7 @@ del_timer_sync(&dlci->t1); dlci->gsm->dlci[dlci->addr] = NULL; - kfifo_free(dlci->fifo); + kfifo_free(&dlci->fifo); while ((dlci->skb = skb_dequeue(&dlci->skb_list))) dev_kfree_skb(dlci->skb); kfree(dlci); @@ -1725,6 +1818,11 @@ gsm_destroy_network(dlci); mutex_unlock(&dlci->mutex); + /* We cannot use tty_hangup() because in tty_kref_put() the tty + * driver assumes that the hangup queue is free and reuses it to + * queue release_one_tty() -> NULL pointer panic in + * process_one_work(). + */ tty_vhangup(tty); tty_port_tty_set(&dlci->port, NULL); @@ -1808,7 +1906,6 @@ gsm_response(gsm, address, UA); gsm_dlci_close(dlci); break; - case UA: case UA|PF: if (cr == 0 || dlci == NULL) break; @@ -1818,6 +1915,10 @@ break; case DLCI_OPENING: gsm_dlci_open(dlci); + break; + default: + pr_debug("%s: unhandled state: %d\n", __func__, + dlci->state); break; } break; @@ -1838,7 +1939,7 @@ goto invalid; #endif if (dlci == NULL || dlci->state != DLCI_OPEN) { - gsm_command(gsm, address, DM|PF); + gsm_response(gsm, address, DM|PF); return; } dlci->data(dlci, gsm->buf, gsm->len); @@ -1932,6 +2033,9 @@ break; } break; + default: + pr_debug("%s: unhandled state: %d\n", __func__, gsm->state); + break; } } @@ -1945,6 +2049,16 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c) { + /* handle XON/XOFF */ + if ((c & ISO_IEC_646_MASK) == XON) { + gsm->constipated = true; + return; + } else if ((c & ISO_IEC_646_MASK) == XOFF) { + gsm->constipated = false; + /* Kick the link in case it is idling */ + gsm_data_kick(gsm, NULL); + return; + } if (c == GSM1_SOF) { /* EOF is only valid in frame if we have got to the data state and received at least one byte (the FCS) */ @@ -1959,7 +2073,8 @@ } /* Any partial frame was a runt so go back to start */ if (gsm->state != GSM_START) { - gsm->malformed++; + if (gsm->state != GSM_SEARCH) + gsm->malformed++; gsm->state = GSM_START; } /* A SOF in GSM_START means we are still reading idling or @@ -1968,7 +2083,7 @@ } if (c == GSM1_ESCAPE) { - gsm->escape = 1; + gsm->escape = true; return; } @@ -1978,14 +2093,14 @@ if (gsm->escape) { c ^= GSM1_ESCAPE_BITS; - gsm->escape = 0; + gsm->escape = false; } switch (gsm->state) { case GSM_START: /* First byte after SOF */ gsm->address = 0; gsm->state = GSM_ADDRESS; gsm->fcs = INIT_FCS; - /* Drop through */ + fallthrough; case GSM_ADDRESS: /* Address continuation */ gsm->fcs = gsm_fcs_add(gsm->fcs, c); if (gsm_read_ea(&gsm->address, c)) @@ -2005,6 +2120,9 @@ gsm->buf[gsm->count++] = c; break; case GSM_OVERRUN: /* Over-long - eg a dropped SOF */ + break; + default: + pr_debug("%s: unhandled state: %d\n", __func__, gsm->state); break; } } @@ -2028,74 +2146,46 @@ gsm->io_error++; } -static int gsm_disconnect(struct gsm_mux *gsm) -{ - struct gsm_dlci *dlci = gsm->dlci[0]; - struct gsm_control *gc; - - if (!dlci) - return 0; - - /* In theory disconnecting DLCI 0 is sufficient but for some - modems this is apparently not the case. */ - gc = gsm_control_send(gsm, CMD_CLD, NULL, 0); - if (gc) - gsm_control_wait(gsm, gc); - - del_timer_sync(&gsm->t2_timer); - /* Now we are sure T2 has stopped */ - - gsm_dlci_begin_close(dlci); - wait_event_interruptible(gsm->event, - dlci->state == DLCI_CLOSED); - - if (signal_pending(current)) - return -EINTR; - - return 0; -} - /** * gsm_cleanup_mux - generic GSM protocol cleanup * @gsm: our mux + * @disc: disconnect link? * * Clean up the bits of the mux which are the same for all framing * protocols. Remove the mux from the mux table, stop all the timers * and then shut down each device hanging up the channels as we go. */ -static void gsm_cleanup_mux(struct gsm_mux *gsm) +static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc) { int i; - struct gsm_dlci *dlci = gsm->dlci[0]; + struct gsm_dlci *dlci; struct gsm_msg *txq, *ntxq; - gsm->dead = 1; - - spin_lock(&gsm_mux_lock); - for (i = 0; i < MAX_MUX; i++) { - if (gsm_mux[i] == gsm) { - gsm_mux[i] = NULL; - break; - } - } - spin_unlock(&gsm_mux_lock); - /* open failed before registering => nothing to do */ - if (i == MAX_MUX) - return; - - del_timer_sync(&gsm->t2_timer); - /* Now we are sure T2 has stopped */ - if (dlci) - dlci->dead = 1; - - /* Free up any link layer users */ + gsm->dead = true; mutex_lock(&gsm->mutex); - for (i = 0; i < NUM_DLCI; i++) - if (gsm->dlci[i]) + + dlci = gsm->dlci[0]; + if (dlci) { + if (disc && dlci->state != DLCI_CLOSED) { + gsm_dlci_begin_close(dlci); + wait_event(gsm->event, dlci->state == DLCI_CLOSED); + } + dlci->dead = true; + } + + /* Finish outstanding timers, making sure they are done */ + del_timer_sync(&gsm->t2_timer); + + /* Free up any link layer users and finally the control channel */ + for (i = NUM_DLCI - 1; i >= 0; i--) + if (gsm->dlci[i]) { gsm_dlci_release(gsm->dlci[i]); + gsm->dlci[i] = NULL; + } mutex_unlock(&gsm->mutex); /* Now wipe the queues */ + tty_ldisc_flush(gsm->tty); list_for_each_entry_safe(txq, ntxq, &gsm->tx_list, list) kfree(txq); INIT_LIST_HEAD(&gsm->tx_list); @@ -2113,46 +2203,36 @@ static int gsm_activate_mux(struct gsm_mux *gsm) { struct gsm_dlci *dlci; - int i = 0; - - timer_setup(&gsm->t2_timer, gsm_control_retransmit, 0); - init_waitqueue_head(&gsm->event); - spin_lock_init(&gsm->control_lock); - spin_lock_init(&gsm->tx_lock); if (gsm->encoding == 0) gsm->receive = gsm0_receive; else gsm->receive = gsm1_receive; - gsm->error = gsm_error; - - spin_lock(&gsm_mux_lock); - for (i = 0; i < MAX_MUX; i++) { - if (gsm_mux[i] == NULL) { - gsm->num = i; - gsm_mux[i] = gsm; - break; - } - } - spin_unlock(&gsm_mux_lock); - if (i == MAX_MUX) - return -EBUSY; dlci = gsm_dlci_alloc(gsm, 0); if (dlci == NULL) return -ENOMEM; - gsm->dead = 0; /* Tty opens are now permissible */ + gsm->dead = false; /* Tty opens are now permissible */ return 0; } /** * gsm_free_mux - free up a mux - * @mux: mux to free + * @gsm: mux to free * * Dispose of allocated resources for a dead mux */ static void gsm_free_mux(struct gsm_mux *gsm) { + int i; + + for (i = 0; i < MAX_MUX; i++) { + if (gsm == gsm_mux[i]) { + gsm_mux[i] = NULL; + break; + } + } + mutex_destroy(&gsm->mutex); kfree(gsm->txframe); kfree(gsm->buf); kfree(gsm); @@ -2160,7 +2240,7 @@ /** * gsm_free_muxr - free up a mux - * @mux: mux to free + * @ref: kreference to the mux to free * * Dispose of allocated resources for a dead mux */ @@ -2172,12 +2252,30 @@ static inline void mux_get(struct gsm_mux *gsm) { + unsigned long flags; + + spin_lock_irqsave(&gsm_mux_lock, flags); kref_get(&gsm->ref); + spin_unlock_irqrestore(&gsm_mux_lock, flags); } static inline void mux_put(struct gsm_mux *gsm) { + unsigned long flags; + + spin_lock_irqsave(&gsm_mux_lock, flags); kref_put(&gsm->ref, gsm_free_muxr); + spin_unlock_irqrestore(&gsm_mux_lock, flags); +} + +static inline unsigned int mux_num_to_base(struct gsm_mux *gsm) +{ + return gsm->num * NUM_DLCI; +} + +static inline unsigned int mux_line_to_num(unsigned int line) +{ + return line / NUM_DLCI; } /** @@ -2188,6 +2286,7 @@ static struct gsm_mux *gsm_alloc_mux(void) { + int i; struct gsm_mux *gsm = kzalloc(sizeof(struct gsm_mux), GFP_KERNEL); if (gsm == NULL) return NULL; @@ -2196,7 +2295,7 @@ kfree(gsm); return NULL; } - gsm->txframe = kmalloc(2 * MAX_MRU + 2, GFP_KERNEL); + gsm->txframe = kmalloc(2 * (MAX_MTU + PROT_OVERHEAD - 1), GFP_KERNEL); if (gsm->txframe == NULL) { kfree(gsm->buf); kfree(gsm); @@ -2206,6 +2305,10 @@ mutex_init(&gsm->mutex); kref_init(&gsm->ref); INIT_LIST_HEAD(&gsm->tx_list); + timer_setup(&gsm->t2_timer, gsm_control_retransmit, 0); + init_waitqueue_head(&gsm->event); + spin_lock_init(&gsm->control_lock); + spin_lock_init(&gsm->tx_lock); gsm->t1 = T1; gsm->t2 = T2; @@ -2215,9 +2318,130 @@ gsm->encoding = 1; gsm->mru = 64; /* Default to encoding 1 so these should be 64 */ gsm->mtu = 64; - gsm->dead = 1; /* Avoid early tty opens */ + gsm->dead = true; /* Avoid early tty opens */ + + /* Store the instance to the mux array or abort if no space is + * available. + */ + spin_lock(&gsm_mux_lock); + for (i = 0; i < MAX_MUX; i++) { + if (!gsm_mux[i]) { + gsm_mux[i] = gsm; + gsm->num = i; + break; + } + } + spin_unlock(&gsm_mux_lock); + if (i == MAX_MUX) { + mutex_destroy(&gsm->mutex); + kfree(gsm->txframe); + kfree(gsm->buf); + kfree(gsm); + return NULL; + } return gsm; +} + +static void gsm_copy_config_values(struct gsm_mux *gsm, + struct gsm_config *c) +{ + memset(c, 0, sizeof(*c)); + c->adaption = gsm->adaption; + c->encapsulation = gsm->encoding; + c->initiator = gsm->initiator; + c->t1 = gsm->t1; + c->t2 = gsm->t2; + c->t3 = 0; /* Not supported */ + c->n2 = gsm->n2; + if (gsm->ftype == UIH) + c->i = 1; + else + c->i = 2; + pr_debug("Ftype %d i %d\n", gsm->ftype, c->i); + c->mru = gsm->mru; + c->mtu = gsm->mtu; + c->k = 0; +} + +static int gsm_config(struct gsm_mux *gsm, struct gsm_config *c) +{ + int ret = 0; + int need_close = 0; + int need_restart = 0; + + /* Stuff we don't support yet - UI or I frame transport, windowing */ + if ((c->adaption != 1 && c->adaption != 2) || c->k) + return -EOPNOTSUPP; + /* Check the MRU/MTU range looks sane */ + if (c->mru > MAX_MRU || c->mtu > MAX_MTU || c->mru < 8 || c->mtu < 8) + return -EINVAL; + if (c->n2 > 255) + return -EINVAL; + if (c->encapsulation > 1) /* Basic, advanced, no I */ + return -EINVAL; + if (c->initiator > 1) + return -EINVAL; + if (c->i == 0 || c->i > 2) /* UIH and UI only */ + return -EINVAL; + /* + * See what is needed for reconfiguration + */ + + /* Timing fields */ + if (c->t1 != 0 && c->t1 != gsm->t1) + need_restart = 1; + if (c->t2 != 0 && c->t2 != gsm->t2) + need_restart = 1; + if (c->encapsulation != gsm->encoding) + need_restart = 1; + if (c->adaption != gsm->adaption) + need_restart = 1; + /* Requires care */ + if (c->initiator != gsm->initiator) + need_close = 1; + if (c->mru != gsm->mru) + need_restart = 1; + if (c->mtu != gsm->mtu) + need_restart = 1; + + /* + * Close down what is needed, restart and initiate the new + * configuration. On the first time there is no DLCI[0] + * and closing or cleaning up is not necessary. + */ + if (need_close || need_restart) + gsm_cleanup_mux(gsm, true); + + gsm->initiator = c->initiator; + gsm->mru = c->mru; + gsm->mtu = c->mtu; + gsm->encoding = c->encapsulation; + gsm->adaption = c->adaption; + gsm->n2 = c->n2; + + if (c->i == 1) + gsm->ftype = UIH; + else if (c->i == 2) + gsm->ftype = UI; + + if (c->t1) + gsm->t1 = c->t1; + if (c->t2) + gsm->t2 = c->t2; + + /* + * FIXME: We need to separate activation/deactivation from adding + * and removing from the mux array + */ + if (gsm->dead) { + ret = gsm_activate_mux(gsm); + if (ret) + return ret; + if (gsm->initiator) + gsm_dlci_begin_open(gsm->dlci[0]); + } + return 0; } /** @@ -2255,19 +2479,32 @@ static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm) { - int ret, i, base; + unsigned int base; + int ret, i; gsm->tty = tty_kref_get(tty); - gsm->output = gsmld_output; + /* Turn off tty XON/XOFF handling to handle it explicitly. */ + gsm->old_c_iflag = tty->termios.c_iflag; + tty->termios.c_iflag &= (IXON | IXOFF); ret = gsm_activate_mux(gsm); if (ret != 0) tty_kref_put(gsm->tty); else { /* Don't register device 0 - this is the control channel and not a usable tty interface */ - base = gsm->num << 6; /* Base for this MUX */ - for (i = 1; i < NUM_DLCI; i++) - tty_register_device(gsm_tty_driver, base + i, NULL); + base = mux_num_to_base(gsm); /* Base for this MUX */ + for (i = 1; i < NUM_DLCI; i++) { + struct device *dev; + + dev = tty_register_device(gsm_tty_driver, + base + i, NULL); + if (IS_ERR(dev)) { + for (i--; i >= 1; i--) + tty_unregister_device(gsm_tty_driver, + base + i); + return PTR_ERR(dev); + } + } } return ret; } @@ -2283,13 +2520,14 @@ static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm) { + unsigned int base = mux_num_to_base(gsm); /* Base for this MUX */ int i; - int base = gsm->num << 6; /* Base for this MUX */ WARN_ON(tty != gsm->tty); for (i = 1; i < NUM_DLCI; i++) tty_unregister_device(gsm_tty_driver, base + i); - gsm_cleanup_mux(gsm); + /* Restore tty XON/XOFF handling. */ + gsm->tty->termios.c_iflag = gsm->old_c_iflag; tty_kref_put(gsm->tty); gsm->tty = NULL; } @@ -2318,7 +2556,7 @@ case TTY_BREAK: case TTY_PARITY: case TTY_FRAME: - gsm->error(gsm, *dp, flags); + gsm_error(gsm, *dp, flags); break; default: WARN_ONCE(1, "%s: unknown flag %d\n", @@ -2356,6 +2594,12 @@ static void gsmld_close(struct tty_struct *tty) { struct gsm_mux *gsm = tty->disc_data; + + /* The ldisc locks and closes the port before calling our close. This + * means we have no way to do a proper disconnect. We will not bother + * to do one. + */ + gsm_cleanup_mux(gsm, false); gsmld_detach_gsm(tty, gsm); @@ -2395,7 +2639,7 @@ ret = gsmld_attach_gsm(tty, gsm); if (ret != 0) { - gsm_cleanup_mux(gsm); + gsm_cleanup_mux(gsm, false); mux_put(gsm); } return ret; @@ -2441,7 +2685,8 @@ */ static ssize_t gsmld_read(struct tty_struct *tty, struct file *file, - unsigned char __user *buf, size_t nr) + unsigned char *buf, size_t nr, + void **cookie, unsigned long offset) { return -EOPNOTSUPP; } @@ -2463,11 +2708,24 @@ static ssize_t gsmld_write(struct tty_struct *tty, struct file *file, const unsigned char *buf, size_t nr) { - int space = tty_write_room(tty); + struct gsm_mux *gsm = tty->disc_data; + unsigned long flags; + int space; + int ret; + + if (!gsm) + return -ENODEV; + + ret = -ENOBUFS; + spin_lock_irqsave(&gsm->tx_lock, flags); + space = tty_write_room(tty); if (space >= nr) - return tty->ops->write(tty, buf, nr); - set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - return -ENOBUFS; + ret = tty->ops->write(tty, buf, nr); + else + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + spin_unlock_irqrestore(&gsm->tx_lock, flags); + + return ret; } /** @@ -2492,96 +2750,16 @@ poll_wait(file, &tty->read_wait, wait); poll_wait(file, &tty->write_wait, wait); + + if (gsm->dead) + mask |= EPOLLHUP; if (tty_hung_up_p(file)) + mask |= EPOLLHUP; + if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) mask |= EPOLLHUP; if (!tty_is_writelocked(tty) && tty_write_room(tty) > 0) mask |= EPOLLOUT | EPOLLWRNORM; - if (gsm->dead) - mask |= EPOLLHUP; return mask; -} - -static int gsmld_config(struct tty_struct *tty, struct gsm_mux *gsm, - struct gsm_config *c) -{ - int need_close = 0; - int need_restart = 0; - - /* Stuff we don't support yet - UI or I frame transport, windowing */ - if ((c->adaption != 1 && c->adaption != 2) || c->k) - return -EOPNOTSUPP; - /* Check the MRU/MTU range looks sane */ - if (c->mru > MAX_MRU || c->mtu > MAX_MTU || c->mru < 8 || c->mtu < 8) - return -EINVAL; - if (c->n2 < 3) - return -EINVAL; - if (c->encapsulation > 1) /* Basic, advanced, no I */ - return -EINVAL; - if (c->initiator > 1) - return -EINVAL; - if (c->i == 0 || c->i > 2) /* UIH and UI only */ - return -EINVAL; - /* - * See what is needed for reconfiguration - */ - - /* Timing fields */ - if (c->t1 != 0 && c->t1 != gsm->t1) - need_restart = 1; - if (c->t2 != 0 && c->t2 != gsm->t2) - need_restart = 1; - if (c->encapsulation != gsm->encoding) - need_restart = 1; - if (c->adaption != gsm->adaption) - need_restart = 1; - /* Requires care */ - if (c->initiator != gsm->initiator) - need_close = 1; - if (c->mru != gsm->mru) - need_restart = 1; - if (c->mtu != gsm->mtu) - need_restart = 1; - - /* - * Close down what is needed, restart and initiate the new - * configuration - */ - - if (need_close || need_restart) { - int ret; - - ret = gsm_disconnect(gsm); - - if (ret) - return ret; - } - if (need_restart) - gsm_cleanup_mux(gsm); - - gsm->initiator = c->initiator; - gsm->mru = c->mru; - gsm->mtu = c->mtu; - gsm->encoding = c->encapsulation; - gsm->adaption = c->adaption; - gsm->n2 = c->n2; - - if (c->i == 1) - gsm->ftype = UIH; - else if (c->i == 2) - gsm->ftype = UI; - - if (c->t1) - gsm->t1 = c->t1; - if (c->t2) - gsm->t2 = c->t2; - - /* FIXME: We need to separate activation/deactivation from adding - and removing from the mux array */ - if (need_restart) - gsm_activate_mux(gsm); - if (gsm->initiator && need_close) - gsm_dlci_begin_open(gsm->dlci[0]); - return 0; } static int gsmld_ioctl(struct tty_struct *tty, struct file *file, @@ -2589,44 +2767,25 @@ { struct gsm_config c; struct gsm_mux *gsm = tty->disc_data; + unsigned int base; switch (cmd) { case GSMIOC_GETCONF: - memset(&c, 0, sizeof(c)); - c.adaption = gsm->adaption; - c.encapsulation = gsm->encoding; - c.initiator = gsm->initiator; - c.t1 = gsm->t1; - c.t2 = gsm->t2; - c.t3 = 0; /* Not supported */ - c.n2 = gsm->n2; - if (gsm->ftype == UIH) - c.i = 1; - else - c.i = 2; - pr_debug("Ftype %d i %d\n", gsm->ftype, c.i); - c.mru = gsm->mru; - c.mtu = gsm->mtu; - c.k = 0; - if (copy_to_user((void *)arg, &c, sizeof(c))) + gsm_copy_config_values(gsm, &c); + if (copy_to_user((void __user *)arg, &c, sizeof(c))) return -EFAULT; return 0; case GSMIOC_SETCONF: - if (copy_from_user(&c, (void *)arg, sizeof(c))) + if (copy_from_user(&c, (void __user *)arg, sizeof(c))) return -EFAULT; - return gsmld_config(tty, gsm, &c); + return gsm_config(gsm, &c); + case GSMIOC_GETFIRST: + base = mux_num_to_base(gsm); + return put_user(base + 1, (__u32 __user *)arg); default: return n_tty_ioctl_helper(tty, file, cmd, arg); } } - -#ifdef CONFIG_COMPAT -static long gsmld_compat_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return gsmld_ioctl(tty, file, cmd, arg); -} -#endif /* * Network interface @@ -2699,7 +2858,7 @@ } /* called when a packet did not ack after watchdogtimeout */ -static void gsm_mux_net_tx_timeout(struct net_device *net) +static void gsm_mux_net_tx_timeout(struct net_device *net, unsigned int txqueue) { /* Tell syslog we are hosed. */ dev_dbg(&net->dev, "Tx timed out.\n"); @@ -2709,7 +2868,7 @@ } static void gsm_mux_rx_netchar(struct gsm_dlci *dlci, - unsigned char *in_buf, int size) + const unsigned char *in_buf, int size) { struct net_device *net = dlci->net; struct sk_buff *skb; @@ -2764,7 +2923,7 @@ { struct gsm_mux_net *mux_net; - pr_debug("destroy network interface"); + pr_debug("destroy network interface\n"); if (!dlci->net) return; mux_net = netdev_priv(dlci->net); @@ -2793,7 +2952,7 @@ if (nc->adaption != 3 && nc->adaption != 4) return -EPROTONOSUPPORT; - pr_debug("create network interface"); + pr_debug("create network interface\n"); netname = "gsm%d"; if (nc->if_name[0] != '\0') @@ -2801,7 +2960,7 @@ net = alloc_netdev(sizeof(struct gsm_mux_net), netname, NET_NAME_UNKNOWN, gsm_mux_net_init); if (!net) { - pr_err("alloc_netdev failed"); + pr_err("alloc_netdev failed\n"); return -ENOMEM; } net->mtu = dlci->gsm->mtu; @@ -2819,7 +2978,7 @@ dlci->data = gsm_mux_rx_netchar; dlci->net = net; - pr_debug("register netdev"); + pr_debug("register netdev\n"); retval = register_netdev(net); if (retval) { pr_err("network register fail %d\n", retval); @@ -2839,9 +2998,6 @@ .flush_buffer = gsmld_flush_buffer, .read = gsmld_read, .write = gsmld_write, -#ifdef CONFIG_COMPAT - .compat_ioctl = gsmld_compat_ioctl, -#endif .ioctl = gsmld_ioctl, .poll = gsmld_poll, .receive_buf = gsmld_receive_buf, @@ -2856,19 +3012,17 @@ static int gsmtty_modem_update(struct gsm_dlci *dlci, u8 brk) { - u8 modembits[5]; + u8 modembits[3]; struct gsm_control *ctrl; int len = 2; - if (brk) + modembits[0] = (dlci->addr << 2) | 2 | EA; /* DLCI, Valid, EA */ + modembits[1] = (gsm_encode_modem(dlci) << 1) | EA; + if (brk) { + modembits[2] = (brk << 4) | 2 | EA; /* Length, Break, EA */ len++; - - modembits[0] = len << 1 | EA; /* Data bytes */ - modembits[1] = dlci->addr << 2 | 3; /* DLCI, EA, 1 */ - modembits[2] = gsm_encode_modem(dlci) << 1 | EA; - if (brk) - modembits[3] = brk << 4 | 2 | EA; /* Valid, EA */ - ctrl = gsm_control_send(dlci->gsm, CMD_MSC, modembits, len + 1); + } + ctrl = gsm_control_send(dlci->gsm, CMD_MSC, modembits, len); if (ctrl == NULL) return -ENOMEM; return gsm_control_wait(dlci->gsm, ctrl); @@ -2921,7 +3075,7 @@ struct gsm_mux *gsm; struct gsm_dlci *dlci; unsigned int line = tty->index; - unsigned int mux = line >> 6; + unsigned int mux = mux_line_to_num(line); bool alloc = false; int ret; @@ -2976,6 +3130,7 @@ { struct gsm_dlci *dlci = tty->driver_data; struct tty_port *port = &dlci->port; + struct gsm_mux *gsm = dlci->gsm; port->count++; tty_port_tty_set(port, tty); @@ -2985,7 +3140,10 @@ a DM straight back. This is ok as that will have caused a hangup */ tty_port_set_initialized(port, 1); /* Start sending off SABM messages */ - gsm_dlci_begin_open(dlci); + if (gsm->initiator) + gsm_dlci_begin_open(dlci); + else + gsm_dlci_set_opening(dlci); /* And wait for virtual carrier */ return tty_port_block_til_ready(port, tty, filp); } @@ -3028,7 +3186,7 @@ if (dlci->state == DLCI_CLOSED) return -EINVAL; /* Stuff the bytes into the fifo queue */ - sent = kfifo_in_locked(dlci->fifo, buf, len, &dlci->lock); + sent = kfifo_in_locked(&dlci->fifo, buf, len, &dlci->lock); /* Need to kick the channel */ gsm_dlci_data_kick(dlci); return sent; @@ -3039,7 +3197,7 @@ struct gsm_dlci *dlci = tty->driver_data; if (dlci->state == DLCI_CLOSED) return -EINVAL; - return TX_SIZE - kfifo_len(dlci->fifo); + return TX_SIZE - kfifo_len(&dlci->fifo); } static int gsmtty_chars_in_buffer(struct tty_struct *tty) @@ -3047,19 +3205,23 @@ struct gsm_dlci *dlci = tty->driver_data; if (dlci->state == DLCI_CLOSED) return -EINVAL; - return kfifo_len(dlci->fifo); + return kfifo_len(&dlci->fifo); } static void gsmtty_flush_buffer(struct tty_struct *tty) { struct gsm_dlci *dlci = tty->driver_data; + unsigned long flags; + if (dlci->state == DLCI_CLOSED) return; /* Caution needed: If we implement reliable transport classes then the data being transmitted can't simply be junked once it has first hit the stack. Until then we can just blow it away */ - kfifo_reset(dlci->fifo); + spin_lock_irqsave(&dlci->lock, flags); + kfifo_reset(&dlci->fifo); + spin_unlock_irqrestore(&dlci->lock, flags); /* Need to unhook this DLCI from the transmit queue logic */ } @@ -3149,9 +3311,9 @@ if (dlci->state == DLCI_CLOSED) return; if (C_CRTSCTS(tty)) - dlci->modem_tx &= ~TIOCM_DTR; - dlci->throttled = 1; - /* Send an MSC with DTR cleared */ + dlci->modem_tx &= ~TIOCM_RTS; + dlci->throttled = true; + /* Send an MSC with RTS cleared */ gsmtty_modem_update(dlci, 0); } @@ -3161,9 +3323,9 @@ if (dlci->state == DLCI_CLOSED) return; if (C_CRTSCTS(tty)) - dlci->modem_tx |= TIOCM_DTR; - dlci->throttled = 0; - /* Send an MSC with DTR set */ + dlci->modem_tx |= TIOCM_RTS; + dlci->throttled = false; + /* Send an MSC with RTS set */ gsmtty_modem_update(dlci, 0); } -- Gitblit v1.6.2