Merge branch 'tty-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6
[pandora-kernel.git] / drivers / tty / n_gsm.c
index c5f8e5b..44b8412 100644 (file)
@@ -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);