ARM64: dts: rk3399: support more frequency for evb2
[firefly-linux-kernel-4.4.55.git] / drivers / tty / n_gsm.c
index 642239015b46bbe9e18844f186a31296a343d5f9..c3fe026d3168dda14e7388472db49abf27544e4f 100644 (file)
@@ -161,7 +161,7 @@ struct gsm_dlci {
        struct net_device *net; /* network interface, if created */
 };
 
-/* DLCI 0, 62/63 are special or reseved see gsmtty_open */
+/* DLCI 0, 62/63 are special or reserved see gsmtty_open */
 
 #define NUM_DLCI               64
 
@@ -194,6 +194,7 @@ struct gsm_control {
 struct gsm_mux {
        struct tty_struct *tty;         /* The tty our ldisc is bound to */
        spinlock_t lock;
+       struct mutex mutex;
        unsigned int num;
        struct kref ref;
 
@@ -807,7 +808,7 @@ static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci)
        int h = dlci->adaption - 1;
 
        total_size = 0;
-       while(1) {
+       while (1) {
                len = kfifo_len(dlci->fifo);
                if (len == 0)
                        return total_size;
@@ -827,8 +828,8 @@ static int gsm_dlci_data_output(struct gsm_mux *gsm, struct gsm_dlci *dlci)
                switch (dlci->adaption) {
                case 1: /* Unstructured */
                        break;
-               case 2: /* Unstructed with modem bits. Always one byte as we never
-                          send inline break data */
+               case 2: /* Unstructed with modem bits.
+               Always one byte as we never send inline break data */
                        *dp++ = gsm_encode_modem(dlci);
                        break;
                }
@@ -968,7 +969,7 @@ static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
        unsigned long flags;
        int sweep;
 
-       if (dlci->constipated) 
+       if (dlci->constipated)
                return;
 
        spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
@@ -981,7 +982,7 @@ static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
                        gsm_dlci_data_output(dlci->gsm, dlci);
        }
        if (sweep)
-               gsm_dlci_data_sweep(dlci->gsm);
+               gsm_dlci_data_sweep(dlci->gsm);
        spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
 }
 
@@ -1089,6 +1090,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, 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;
@@ -1115,6 +1117,16 @@ static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen)
                if (len == 0)
                        return;
        }
+       len--;
+       if (len > 0) {
+               while (gsm_read_ea(&brk, *dp++) == 0) {
+                       len--;
+                       if (len == 0)
+                               return;
+               }
+               modem <<= 7;
+               modem |= (brk & 0x7f);
+       }
        tty = tty_port_tty_get(&dlci->port);
        gsm_process_modem(tty, dlci, modem, clen);
        if (tty) {
@@ -1138,7 +1150,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen)
 static void gsm_control_rls(struct gsm_mux *gsm, u8 *data, int clen)
 {
        struct tty_port *port;
-       unsigned int addr = 0 ;
+       unsigned int addr = 0;
        u8 bits;
        int len = clen;
        u8 *dp = data;
@@ -1704,11 +1716,8 @@ static void gsm_dlci_release(struct gsm_dlci *dlci)
                gsm_destroy_network(dlci);
                mutex_unlock(&dlci->mutex);
 
-               /* tty_vhangup needs the tty_lock, so unlock and
-                  relock after doing the hangup. */
-               tty_unlock(tty);
                tty_vhangup(tty);
-               tty_lock(tty);
+
                tty_port_tty_set(&dlci->port, NULL);
                tty_kref_put(tty);
        }
@@ -1740,10 +1749,11 @@ 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);
-       if (gsm->encoding == 0){
-               /* WARNING: gsm->received_fcs is used for gsm->encoding = 0 only.
-                           In this case it contain the last piece of data
-                           required to generate final CRC */
+       if (gsm->encoding == 0) {
+               /* WARNING: gsm->received_fcs is used for
+               gsm->encoding = 0 only.
+               In this case it contain the last piece of data
+               required to generate final CRC */
                gsm->fcs = gsm_fcs_add(gsm->fcs, gsm->received_fcs);
        }
        if (gsm->fcs != GOOD_FCS) {
@@ -2018,7 +2028,7 @@ static void gsm_error(struct gsm_mux *gsm,
  *     and then shut down each device hanging up the channels as we go.
  */
 
-void gsm_cleanup_mux(struct gsm_mux *gsm)
+static void gsm_cleanup_mux(struct gsm_mux *gsm)
 {
        int i;
        struct gsm_dlci *dlci = gsm->dlci[0];
@@ -2053,15 +2063,16 @@ void gsm_cleanup_mux(struct gsm_mux *gsm)
                                        dlci->state == DLCI_CLOSED);
        }
        /* Free up any link layer users */
+       mutex_lock(&gsm->mutex);
        for (i = 0; i < NUM_DLCI; i++)
                if (gsm->dlci[i])
                        gsm_dlci_release(gsm->dlci[i]);
+       mutex_unlock(&gsm->mutex);
        /* Now wipe the queues */
        list_for_each_entry_safe(txq, ntxq, &gsm->tx_list, list)
                kfree(txq);
        INIT_LIST_HEAD(&gsm->tx_list);
 }
-EXPORT_SYMBOL_GPL(gsm_cleanup_mux);
 
 /**
  *     gsm_activate_mux        -       generic GSM setup
@@ -2072,14 +2083,12 @@ EXPORT_SYMBOL_GPL(gsm_cleanup_mux);
  *     finally kick off connecting to DLCI 0 on the modem.
  */
 
-int gsm_activate_mux(struct gsm_mux *gsm)
+static int gsm_activate_mux(struct gsm_mux *gsm)
 {
        struct gsm_dlci *dlci;
        int i = 0;
 
-       init_timer(&gsm->t2_timer);
-       gsm->t2_timer.function = gsm_control_retransmit;
-       gsm->t2_timer.data = (unsigned long)gsm;
+       setup_timer(&gsm->t2_timer, gsm_control_retransmit, (unsigned long)gsm);
        init_waitqueue_head(&gsm->event);
        spin_lock_init(&gsm->control_lock);
        spin_lock_init(&gsm->tx_lock);
@@ -2108,7 +2117,6 @@ int gsm_activate_mux(struct gsm_mux *gsm)
        gsm->dead = 0;          /* Tty opens are now permissible */
        return 0;
 }
-EXPORT_SYMBOL_GPL(gsm_activate_mux);
 
 /**
  *     gsm_free_mux            -       free up a mux
@@ -2116,13 +2124,12 @@ EXPORT_SYMBOL_GPL(gsm_activate_mux);
  *
  *     Dispose of allocated resources for a dead mux
  */
-void gsm_free_mux(struct gsm_mux *gsm)
+static void gsm_free_mux(struct gsm_mux *gsm)
 {
        kfree(gsm->txframe);
        kfree(gsm->buf);
        kfree(gsm);
 }
-EXPORT_SYMBOL_GPL(gsm_free_mux);
 
 /**
  *     gsm_free_muxr           -       free up a mux
@@ -2152,7 +2159,7 @@ static inline void mux_put(struct gsm_mux *gsm)
  *     Creates a new mux ready for activation.
  */
 
-struct gsm_mux *gsm_alloc_mux(void)
+static struct gsm_mux *gsm_alloc_mux(void)
 {
        struct gsm_mux *gsm = kzalloc(sizeof(struct gsm_mux), GFP_KERNEL);
        if (gsm == NULL)
@@ -2169,6 +2176,7 @@ struct gsm_mux *gsm_alloc_mux(void)
                return NULL;
        }
        spin_lock_init(&gsm->lock);
+       mutex_init(&gsm->mutex);
        kref_init(&gsm->ref);
        INIT_LIST_HEAD(&gsm->tx_list);
 
@@ -2184,7 +2192,6 @@ struct gsm_mux *gsm_alloc_mux(void)
 
        return gsm;
 }
-EXPORT_SYMBOL_GPL(gsm_alloc_mux);
 
 /**
  *     gsmld_output            -       write to link
@@ -2221,8 +2228,7 @@ static int gsmld_output(struct gsm_mux *gsm, u8 *data, int len)
 
 static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
 {
-       int ret, i;
-       int base = gsm->num << 6; /* Base for this MUX */
+       int ret, i, base;
 
        gsm->tty = tty_kref_get(tty);
        gsm->output = gsmld_output;
@@ -2232,6 +2238,7 @@ static int gsmld_attach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
        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);
        }
@@ -2267,15 +2274,15 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
        const unsigned char *dp;
        char *f;
        int i;
-       char buf[64];
-       char flags;
+       char flags = TTY_NORMAL;
 
        if (debug & 4)
                print_hex_dump_bytes("gsmld_receive: ", DUMP_PREFIX_OFFSET,
                                     cp, count);
 
        for (i = count, dp = cp, f = fp; i; i--, dp++) {
-               flags = *f++;
+               if (f)
+                       flags = *f++;
                switch (flags) {
                case TTY_NORMAL:
                        gsm->receive(gsm, *dp);
@@ -2288,7 +2295,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
                        break;
                default:
                        WARN_ONCE(1, "%s: unknown flag %d\n",
-                              tty_name(tty, buf), flags);
+                              tty_name(tty), flags);
                        break;
                }
        }
@@ -2358,6 +2365,7 @@ static void gsmld_close(struct tty_struct *tty)
 static int gsmld_open(struct tty_struct *tty)
 {
        struct gsm_mux *gsm;
+       int ret;
 
        if (tty->ops->write == NULL)
                return -EINVAL;
@@ -2372,7 +2380,13 @@ static int gsmld_open(struct tty_struct *tty)
 
        /* Attach the initial passive connection */
        gsm->encoding = 1;
-       return gsmld_attach_gsm(tty, gsm);
+
+       ret = gsmld_attach_gsm(tty, gsm);
+       if (ret != 0) {
+               gsm_cleanup_mux(gsm);
+               mux_put(gsm);
+       }
+       return ret;
 }
 
 /**
@@ -2654,7 +2668,7 @@ static inline void muxnet_put(struct gsm_mux_net *mux_net)
 static int gsm_mux_net_start_xmit(struct sk_buff *skb,
                                      struct net_device *net)
 {
-       struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net);
+       struct gsm_mux_net *mux_net = netdev_priv(net);
        struct gsm_dlci *dlci = mux_net->dlci;
        muxnet_get(mux_net);
 
@@ -2683,7 +2697,7 @@ static void gsm_mux_rx_netchar(struct gsm_dlci *dlci,
 {
        struct net_device *net = dlci->net;
        struct sk_buff *skb;
-       struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net);
+       struct gsm_mux_net *mux_net = netdev_priv(net);
        muxnet_get(mux_net);
 
        /* Allocate an sk_buff */
@@ -2698,7 +2712,7 @@ static void gsm_mux_rx_netchar(struct gsm_dlci *dlci,
        memcpy(skb_put(skb, size), in_buf, size);
 
        skb->dev = net;
-       skb->protocol = __constant_htons(ETH_P_IP);
+       skb->protocol = htons(ETH_P_IP);
 
        /* Ship it off to the kernel */
        netif_rx(skb);
@@ -2710,9 +2724,9 @@ static void gsm_mux_rx_netchar(struct gsm_dlci *dlci,
        return;
 }
 
-int gsm_change_mtu(struct net_device *net, int new_mtu)
+static int gsm_change_mtu(struct net_device *net, int new_mtu)
 {
-       struct gsm_mux_net *mux_net = (struct gsm_mux_net *)netdev_priv(net);
+       struct gsm_mux_net *mux_net = netdev_priv(net);
        if ((new_mtu < 8) || (new_mtu > mux_net->dlci->gsm->mtu))
                return -EINVAL;
        net->mtu = new_mtu;
@@ -2748,7 +2762,7 @@ static void gsm_destroy_network(struct gsm_dlci *dlci)
        pr_debug("destroy network interface");
        if (!dlci->net)
                return;
-       mux_net = (struct gsm_mux_net *)netdev_priv(dlci->net);
+       mux_net = netdev_priv(dlci->net);
        muxnet_put(mux_net);
 }
 
@@ -2779,15 +2793,14 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc)
        netname = "gsm%d";
        if (nc->if_name[0] != '\0')
                netname = nc->if_name;
-       net = alloc_netdev(sizeof(struct gsm_mux_net),
-                       netname,
-                       gsm_mux_net_init);
+       net = alloc_netdev(sizeof(struct gsm_mux_net), netname,
+                          NET_NAME_UNKNOWN, gsm_mux_net_init);
        if (!net) {
                pr_err("alloc_netdev failed");
                return -ENOMEM;
        }
        net->mtu = dlci->gsm->mtu;
-       mux_net = (struct gsm_mux_net *)netdev_priv(net);
+       mux_net = netdev_priv(net);
        mux_net->dlci = dlci;
        kref_init(&mux_net->ref);
        strncpy(nc->if_name, net->name, IFNAMSIZ); /* return net name */
@@ -2810,7 +2823,7 @@ static int gsm_create_network(struct gsm_dlci *dlci, struct gsm_netconfig *nc)
 }
 
 /* Line discipline for real tty */
-struct tty_ldisc_ops tty_ldisc_packet = {
+static struct tty_ldisc_ops tty_ldisc_packet = {
        .owner           = THIS_MODULE,
        .magic           = TTY_LDISC_MAGIC,
        .name            = "n_gsm",
@@ -2904,25 +2917,37 @@ static int gsmtty_install(struct tty_driver *driver, struct tty_struct *tty)
        gsm = gsm_mux[mux];
        if (gsm->dead)
                return -EL2HLT;
-       /* If DLCI 0 is not yet fully open return an error. This is ok from a locking
-          perspective as we don't have to worry about this if DLCI0 is lost */
-       if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN) 
+       /* If DLCI 0 is not yet fully open return an error.
+       This is ok from a locking
+       perspective as we don't have to worry about this
+       if DLCI0 is lost */
+       mutex_lock(&gsm->mutex);
+       if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN) {
+               mutex_unlock(&gsm->mutex);
                return -EL2NSYNC;
+       }
        dlci = gsm->dlci[line];
        if (dlci == NULL) {
                alloc = true;
                dlci = gsm_dlci_alloc(gsm, line);
        }
-       if (dlci == NULL)
+       if (dlci == NULL) {
+               mutex_unlock(&gsm->mutex);
                return -ENOMEM;
+       }
        ret = tty_port_install(&dlci->port, driver, tty);
        if (ret) {
                if (alloc)
                        dlci_put(dlci);
+               mutex_unlock(&gsm->mutex);
                return ret;
        }
 
+       dlci_get(dlci);
+       dlci_get(gsm->dlci[0]);
+       mux_get(gsm);
        tty->driver_data = dlci;
+       mutex_unlock(&gsm->mutex);
 
        return 0;
 }
@@ -2933,9 +2958,6 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp)
        struct tty_port *port = &dlci->port;
 
        port->count++;
-       dlci_get(dlci);
-       dlci_get(dlci->gsm->dlci[0]);
-       mux_get(dlci->gsm);
        tty_port_tty_set(port, tty);
 
        dlci->modem_rx = 0;
@@ -2962,7 +2984,7 @@ static void gsmtty_close(struct tty_struct *tty, struct file *filp)
        mutex_unlock(&dlci->mutex);
        gsm = dlci->gsm;
        if (tty_port_close_start(&dlci->port, tty, filp) == 0)
-               goto out;
+               return;
        gsm_dlci_begin_close(dlci);
        if (test_bit(ASYNCB_INITIALIZED, &dlci->port.flags)) {
                if (C_HUPCL(tty))
@@ -2970,10 +2992,7 @@ static void gsmtty_close(struct tty_struct *tty, struct file *filp)
        }
        tty_port_close_end(&dlci->port, tty);
        tty_port_tty_set(&dlci->port, NULL);
-out:
-       dlci_put(dlci);
-       dlci_put(gsm->dlci[0]);
-       mux_put(gsm);
+       return;
 }
 
 static void gsmtty_hangup(struct tty_struct *tty)
@@ -3150,6 +3169,15 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state)
        return gsmtty_modem_update(dlci, encode);
 }
 
+static void gsmtty_cleanup(struct tty_struct *tty)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       struct gsm_mux *gsm = dlci->gsm;
+
+       dlci_put(dlci);
+       dlci_put(gsm->dlci[0]);
+       mux_put(gsm);
+}
 
 /* Virtual ttys for the demux */
 static const struct tty_operations gsmtty_ops = {
@@ -3169,6 +3197,7 @@ static const struct tty_operations gsmtty_ops = {
        .tiocmget               = gsmtty_tiocmget,
        .tiocmset               = gsmtty_tiocmset,
        .break_ctl              = gsmtty_break_ctl,
+       .cleanup                = gsmtty_cleanup,
 };