summaryrefslogtreecommitdiffstats
path: root/drivers/tty/n_gsm.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-01-07 14:39:20 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2011-01-07 14:39:20 -0800
commit56b85f32d530d09d6805488ad00775d4e0e3baab (patch)
treee7fbe69e338ef775d3b2dd822aa915d259b4bc94 /drivers/tty/n_gsm.c
parent3e5b08cbbf78bedd316904ab0cf3b27119433ee5 (diff)
parent568389c257fa7d74ce36c2f78bad31965fded4cf (diff)
Merge branch 'tty-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6
* 'tty-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6: (36 commits) serial: apbuart: Fixup apbuart_console_init() TTY: Add tty ioctl to figure device node of the system console. tty: add 'active' sysfs attribute to tty0 and console device drivers: serial: apbuart: Handle OF failures gracefully Serial: Avoid unbalanced IRQ wake disable during resume tty: fix typos/errors in tty_driver.h comments pch_uart : fix warnings for 64bit compile 8250: fix uninitialized FIFOs ip2: fix compiler warning on ip2main_pci_tbl specialix: fix compiler warning on specialix_pci_tbl rocket: fix compiler warning on rocket_pci_ids 8250: add a UPIO_DWAPB32 for 32 bit accesses 8250: use container_of() instead of casting serial: omap-serial: Add support for kernel debugger serial: fix pch_uart kconfig & build drivers: char: hvc: add arm JTAG DCC console support RS485 documentation: add 16C950 UART description serial: ifx6x60: fix memory leak serial: ifx6x60: free IRQ on error Serial: EG20T: add PCH_UART driver ... Fixed up conflicts in drivers/serial/apbuart.c with evil merge that makes the code look fairly sane (unlike either side).
Diffstat (limited to 'drivers/tty/n_gsm.c')
-rw-r--r--drivers/tty/n_gsm.c213
1 files changed, 127 insertions, 86 deletions
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index c5f8e5bda2b..44b8412a04e 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -19,7 +19,7 @@
*
* TO DO:
* Mostly done: ioctls for setting modes/timing
- * Partly done: hooks so you can pull off frames to non tty devs
+ * Partly done: hooks so you can pull off frames to non tty devs
* Restart DLCI 0 when it closes ?
* Test basic encoding
* Improve the tx engine
@@ -73,8 +73,10 @@ module_param(debug, int, 0600);
#define T2 (2 * HZ)
#endif
-/* Semi-arbitary buffer size limits. 0710 is normally run with 32-64 byte
- limits so this is plenty */
+/*
+ * Semi-arbitary buffer size limits. 0710 is normally run with 32-64 byte
+ * limits so this is plenty
+ */
#define MAX_MRU 512
#define MAX_MTU 512
@@ -184,6 +186,9 @@ struct gsm_mux {
#define GSM_DATA 5
#define GSM_FCS 6
#define GSM_OVERRUN 7
+#define GSM_LEN0 8
+#define GSM_LEN1 9
+#define GSM_SSOF 10
unsigned int len;
unsigned int address;
unsigned int count;
@@ -191,6 +196,7 @@ struct gsm_mux {
int encoding;
u8 control;
u8 fcs;
+ u8 received_fcs;
u8 *txframe; /* TX framing buffer */
/* Methods for the receiver side */
@@ -286,7 +292,7 @@ static spinlock_t gsm_mux_lock;
#define MDM_DV 0x40
#define GSM0_SOF 0xF9
-#define GSM1_SOF 0x7E
+#define GSM1_SOF 0x7E
#define GSM1_ESCAPE 0x7D
#define GSM1_ESCAPE_BITS 0x20
#define XON 0x11
@@ -429,61 +435,63 @@ static void gsm_print_packet(const char *hdr, int addr, int cr,
if (!(debug & 1))
return;
- printk(KERN_INFO "%s %d) %c: ", hdr, addr, "RC"[cr]);
+ pr_info("%s %d) %c: ", hdr, addr, "RC"[cr]);
switch (control & ~PF) {
case SABM:
- printk(KERN_CONT "SABM");
+ pr_cont("SABM");
break;
case UA:
- printk(KERN_CONT "UA");
+ pr_cont("UA");
break;
case DISC:
- printk(KERN_CONT "DISC");
+ pr_cont("DISC");
break;
case DM:
- printk(KERN_CONT "DM");
+ pr_cont("DM");
break;
case UI:
- printk(KERN_CONT "UI");
+ pr_cont("UI");
break;
case UIH:
- printk(KERN_CONT "UIH");
+ pr_cont("UIH");
break;
default:
if (!(control & 0x01)) {
- printk(KERN_CONT "I N(S)%d N(R)%d",
- (control & 0x0E) >> 1, (control & 0xE)>> 5);
+ pr_cont("I N(S)%d N(R)%d",
+ (control & 0x0E) >> 1, (control & 0xE) >> 5);
} else switch (control & 0x0F) {
- case RR:
- printk("RR(%d)", (control & 0xE0) >> 5);
- break;
- case RNR:
- printk("RNR(%d)", (control & 0xE0) >> 5);
- break;
- case REJ:
- printk("REJ(%d)", (control & 0xE0) >> 5);
- break;
- default:
- printk(KERN_CONT "[%02X]", control);
+ case RR:
+ pr_cont("RR(%d)", (control & 0xE0) >> 5);
+ break;
+ case RNR:
+ pr_cont("RNR(%d)", (control & 0xE0) >> 5);
+ break;
+ case REJ:
+ pr_cont("REJ(%d)", (control & 0xE0) >> 5);
+ break;
+ default:
+ pr_cont("[%02X]", control);
}
}
if (control & PF)
- printk(KERN_CONT "(P)");
+ pr_cont("(P)");
else
- printk(KERN_CONT "(F)");
+ pr_cont("(F)");
if (dlen) {
int ct = 0;
while (dlen--) {
- if (ct % 8 == 0)
- printk(KERN_CONT "\n ");
- printk(KERN_CONT "%02X ", *data++);
+ if (ct % 8 == 0) {
+ pr_cont("\n");
+ pr_debug(" ");
+ }
+ pr_cont("%02X ", *data++);
ct++;
}
}
- printk(KERN_CONT "\n");
+ pr_cont("\n");
}
@@ -522,11 +530,13 @@ static void hex_packet(const unsigned char *p, int len)
{
int i;
for (i = 0; i < len; i++) {
- if (i && (i % 16) == 0)
- printk("\n");
- printk("%02X ", *p++);
+ if (i && (i % 16) == 0) {
+ pr_cont("\n");
+ pr_debug("");
+ }
+ pr_cont("%02X ", *p++);
}
- printk("\n");
+ pr_cont("\n");
}
/**
@@ -676,7 +686,7 @@ static void gsm_data_kick(struct gsm_mux *gsm)
}
if (debug & 4) {
- printk("gsm_data_kick: \n");
+ pr_debug("gsm_data_kick:\n");
hex_packet(gsm->txframe, len);
}
@@ -1231,7 +1241,7 @@ static void gsm_control_response(struct gsm_mux *gsm, unsigned int command,
}
/**
- * gsm_control_transmit - send control packet
+ * gsm_control_transmit - send control packet
* @gsm: gsm mux
* @ctrl: frame to send
*
@@ -1361,7 +1371,7 @@ static void gsm_dlci_close(struct gsm_dlci *dlci)
{
del_timer(&dlci->t1);
if (debug & 8)
- printk("DLCI %d goes closed.\n", dlci->addr);
+ pr_debug("DLCI %d goes closed.\n", dlci->addr);
dlci->state = DLCI_CLOSED;
if (dlci->addr != 0) {
struct tty_struct *tty = tty_port_tty_get(&dlci->port);
@@ -1392,7 +1402,7 @@ static void gsm_dlci_open(struct gsm_dlci *dlci)
/* This will let a tty open continue */
dlci->state = DLCI_OPEN;
if (debug & 8)
- printk("DLCI %d goes open.\n", dlci->addr);
+ pr_debug("DLCI %d goes open.\n", dlci->addr);
wake_up(&dlci->gsm->event);
}
@@ -1494,29 +1504,29 @@ static void gsm_dlci_data(struct gsm_dlci *dlci, u8 *data, int len)
unsigned int modem = 0;
if (debug & 16)
- printk("%d bytes for tty %p\n", len, tty);
+ pr_debug("%d bytes for tty %p\n", len, tty);
if (tty) {
switch (dlci->adaption) {
- /* Unsupported types */
- /* Packetised interruptible data */
- case 4:
- break;
- /* Packetised uininterruptible voice/data */
- case 3:
- break;
- /* Asynchronous serial with line state in each frame */
- case 2:
- while (gsm_read_ea(&modem, *data++) == 0) {
- len--;
- if (len == 0)
- return;
- }
- gsm_process_modem(tty, dlci, modem);
- /* Line state will go via DLCI 0 controls only */
- case 1:
- default:
- tty_insert_flip_string(tty, data, len);
- tty_flip_buffer_push(tty);
+ /* Unsupported types */
+ /* Packetised interruptible data */
+ case 4:
+ break;
+ /* Packetised uininterruptible voice/data */
+ case 3:
+ break;
+ /* Asynchronous serial with line state in each frame */
+ case 2:
+ while (gsm_read_ea(&modem, *data++) == 0) {
+ len--;
+ if (len == 0)
+ return;
+ }
+ gsm_process_modem(tty, dlci, modem);
+ /* Line state will go via DLCI 0 controls only */
+ case 1:
+ default:
+ tty_insert_flip_string(tty, data, len);
+ tty_flip_buffer_push(tty);
}
tty_kref_put(tty);
}
@@ -1625,7 +1635,6 @@ static void gsm_dlci_free(struct gsm_dlci *dlci)
kfree(dlci);
}
-
/*
* LAPBish link layer logic
*/
@@ -1650,10 +1659,12 @@ static void gsm_queue(struct gsm_mux *gsm)
if ((gsm->control & ~PF) == UI)
gsm->fcs = gsm_fcs_add_block(gsm->fcs, gsm->buf, gsm->len);
+ /* generate final CRC with received FCS */
+ gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->received_fcs);
if (gsm->fcs != GOOD_FCS) {
gsm->bad_fcs++;
if (debug & 4)
- printk("BAD FCS %02x\n", gsm->fcs);
+ pr_debug("BAD FCS %02x\n", gsm->fcs);
return;
}
address = gsm->address >> 1;
@@ -1748,6 +1759,8 @@ invalid:
static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
{
+ unsigned int len;
+
switch (gsm->state) {
case GSM_SEARCH: /* SOF marker */
if (c == GSM0_SOF) {
@@ -1756,8 +1769,8 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
gsm->len = 0;
gsm->fcs = INIT_FCS;
}
- break; /* Address EA */
- case GSM_ADDRESS:
+ break;
+ case GSM_ADDRESS: /* Address EA */
gsm->fcs = gsm_fcs_add(gsm->fcs, c);
if (gsm_read_ea(&gsm->address, c))
gsm->state = GSM_CONTROL;
@@ -1765,9 +1778,9 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
case GSM_CONTROL: /* Control Byte */
gsm->fcs = gsm_fcs_add(gsm->fcs, c);
gsm->control = c;
- gsm->state = GSM_LEN;
+ gsm->state = GSM_LEN0;
break;
- case GSM_LEN: /* Length EA */
+ case GSM_LEN0: /* Length EA */
gsm->fcs = gsm_fcs_add(gsm->fcs, c);
if (gsm_read_ea(&gsm->len, c)) {
if (gsm->len > gsm->mru) {
@@ -1776,8 +1789,28 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
break;
}
gsm->count = 0;
- gsm->state = GSM_DATA;
+ if (!gsm->len)
+ gsm->state = GSM_FCS;
+ else
+ gsm->state = GSM_DATA;
+ break;
+ }
+ gsm->state = GSM_LEN1;
+ break;
+ case GSM_LEN1:
+ gsm->fcs = gsm_fcs_add(gsm->fcs, c);
+ len = c;
+ gsm->len |= len << 7;
+ if (gsm->len > gsm->mru) {
+ gsm->bad_size++;
+ gsm->state = GSM_SEARCH;
+ break;
}
+ gsm->count = 0;
+ if (!gsm->len)
+ gsm->state = GSM_FCS;
+ else
+ gsm->state = GSM_DATA;
break;
case GSM_DATA: /* Data */
gsm->buf[gsm->count++] = c;
@@ -1785,16 +1818,25 @@ static void gsm0_receive(struct gsm_mux *gsm, unsigned char c)
gsm->state = GSM_FCS;
break;
case GSM_FCS: /* FCS follows the packet */
- gsm->fcs = c;
+ gsm->received_fcs = c;
+ if (c == GSM0_SOF) {
+ gsm->state = GSM_SEARCH;
+ break;
+ }
gsm_queue(gsm);
- /* And then back for the next frame */
- gsm->state = GSM_SEARCH;
+ gsm->state = GSM_SSOF;
+ break;
+ case GSM_SSOF:
+ if (c == GSM0_SOF) {
+ gsm->state = GSM_SEARCH;
+ break;
+ }
break;
}
}
/**
- * gsm0_receive - perform processing for non-transparency
+ * gsm1_receive - perform processing for non-transparency
* @gsm: gsm data for this ldisc instance
* @c: character
*
@@ -1856,7 +1898,7 @@ static void gsm1_receive(struct gsm_mux *gsm, unsigned char c)
gsm->state = GSM_DATA;
break;
case GSM_DATA: /* Data */
- if (gsm->count > gsm->mru ) { /* Allow one for the FCS */
+ if (gsm->count > gsm->mru) { /* Allow one for the FCS */
gsm->state = GSM_OVERRUN;
gsm->bad_size++;
} else
@@ -2034,9 +2076,6 @@ struct gsm_mux *gsm_alloc_mux(void)
}
EXPORT_SYMBOL_GPL(gsm_alloc_mux);
-
-
-
/**
* gsmld_output - write to link
* @gsm: our mux
@@ -2054,7 +2093,7 @@ static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len)
return -ENOSPC;
}
if (debug & 4) {
- printk("-->%d bytes out\n", len);
+ pr_debug("-->%d bytes out\n", len);
hex_packet(data, len);
}
gsm->tty->ops->write(gsm->tty, data, len);
@@ -2111,7 +2150,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
char flags;
if (debug & 4) {
- printk("Inbytes %dd\n", count);
+ pr_debug("Inbytes %dd\n", count);
hex_packet(cp, count);
}
@@ -2128,7 +2167,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
gsm->error(gsm, *dp, flags);
break;
default:
- printk(KERN_ERR "%s: unknown flag %d\n",
+ WARN_ONCE("%s: unknown flag %d\n",
tty_name(tty, buf), flags);
break;
}
@@ -2323,7 +2362,7 @@ static int gsmld_config(struct tty_struct *tty, struct gsm_mux *gsm,
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)
+ 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)
@@ -2418,7 +2457,7 @@ static int gsmld_ioctl(struct tty_struct *tty, struct file *file,
c.i = 1;
else
c.i = 2;
- printk("Ftype %d i %d\n", gsm->ftype, c.i);
+ pr_debug("Ftype %d i %d\n", gsm->ftype, c.i);
c.mru = gsm->mru;
c.mtu = gsm->mtu;
c.k = 0;
@@ -2712,14 +2751,15 @@ static int __init gsm_init(void)
/* Fill in our line protocol discipline, and register it */
int status = tty_register_ldisc(N_GSM0710, &tty_ldisc_packet);
if (status != 0) {
- printk(KERN_ERR "n_gsm: can't register line discipline (err = %d)\n", status);
+ pr_err("n_gsm: can't register line discipline (err = %d)\n",
+ status);
return status;
}
gsm_tty_driver = alloc_tty_driver(256);
if (!gsm_tty_driver) {
tty_unregister_ldisc(N_GSM0710);
- printk(KERN_ERR "gsm_init: tty allocation failed.\n");
+ pr_err("gsm_init: tty allocation failed.\n");
return -EINVAL;
}
gsm_tty_driver->owner = THIS_MODULE;
@@ -2730,7 +2770,7 @@ static int __init gsm_init(void)
gsm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
gsm_tty_driver->subtype = SERIAL_TYPE_NORMAL;
gsm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV
- | TTY_DRIVER_HARDWARE_BREAK;
+ | TTY_DRIVER_HARDWARE_BREAK;
gsm_tty_driver->init_termios = tty_std_termios;
/* Fixme */
gsm_tty_driver->init_termios.c_lflag &= ~ECHO;
@@ -2741,10 +2781,11 @@ static int __init gsm_init(void)
if (tty_register_driver(gsm_tty_driver)) {
put_tty_driver(gsm_tty_driver);
tty_unregister_ldisc(N_GSM0710);
- printk(KERN_ERR "gsm_init: tty registration failed.\n");
+ pr_err("gsm_init: tty registration failed.\n");
return -EBUSY;
}
- printk(KERN_INFO "gsm_init: loaded as %d,%d.\n", gsm_tty_driver->major, gsm_tty_driver->minor_start);
+ pr_debug("gsm_init: loaded as %d,%d.\n",
+ gsm_tty_driver->major, gsm_tty_driver->minor_start);
return 0;
}
@@ -2752,10 +2793,10 @@ static void __exit gsm_exit(void)
{
int status = tty_unregister_ldisc(N_GSM0710);
if (status != 0)
- printk(KERN_ERR "n_gsm: can't unregister line discipline (err = %d)\n", status);
+ pr_err("n_gsm: can't unregister line discipline (err = %d)\n",
+ status);
tty_unregister_driver(gsm_tty_driver);
put_tty_driver(gsm_tty_driver);
- printk(KERN_INFO "gsm_init: unloaded.\n");
}
module_init(gsm_init);