aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/tty/n_gsm.c39
1 files changed, 29 insertions, 10 deletions
diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
index c09db11b8831..679294b37653 100644
--- a/drivers/tty/n_gsm.c
+++ b/drivers/tty/n_gsm.c
@@ -194,6 +194,7 @@ struct gsm_control {
194struct gsm_mux { 194struct gsm_mux {
195 struct tty_struct *tty; /* The tty our ldisc is bound to */ 195 struct tty_struct *tty; /* The tty our ldisc is bound to */
196 spinlock_t lock; 196 spinlock_t lock;
197 struct mutex mutex;
197 unsigned int num; 198 unsigned int num;
198 struct kref ref; 199 struct kref ref;
199 200
@@ -2054,9 +2055,11 @@ void gsm_cleanup_mux(struct gsm_mux *gsm)
2054 dlci->state == DLCI_CLOSED); 2055 dlci->state == DLCI_CLOSED);
2055 } 2056 }
2056 /* Free up any link layer users */ 2057 /* Free up any link layer users */
2058 mutex_lock(&gsm->mutex);
2057 for (i = 0; i < NUM_DLCI; i++) 2059 for (i = 0; i < NUM_DLCI; i++)
2058 if (gsm->dlci[i]) 2060 if (gsm->dlci[i])
2059 gsm_dlci_release(gsm->dlci[i]); 2061 gsm_dlci_release(gsm->dlci[i]);
2062 mutex_unlock(&gsm->mutex);
2060 /* Now wipe the queues */ 2063 /* Now wipe the queues */
2061 list_for_each_entry_safe(txq, ntxq, &gsm->tx_list, list) 2064 list_for_each_entry_safe(txq, ntxq, &gsm->tx_list, list)
2062 kfree(txq); 2065 kfree(txq);
@@ -2170,6 +2173,7 @@ struct gsm_mux *gsm_alloc_mux(void)
2170 return NULL; 2173 return NULL;
2171 } 2174 }
2172 spin_lock_init(&gsm->lock); 2175 spin_lock_init(&gsm->lock);
2176 mutex_init(&gsm->mutex);
2173 kref_init(&gsm->ref); 2177 kref_init(&gsm->ref);
2174 INIT_LIST_HEAD(&gsm->tx_list); 2178 INIT_LIST_HEAD(&gsm->tx_list);
2175 2179
@@ -2910,23 +2914,33 @@ static int gsmtty_install(struct tty_driver *driver, struct tty_struct *tty)
2910 This is ok from a locking 2914 This is ok from a locking
2911 perspective as we don't have to worry about this 2915 perspective as we don't have to worry about this
2912 if DLCI0 is lost */ 2916 if DLCI0 is lost */
2913 if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN) 2917 mutex_lock(&gsm->mutex);
2918 if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN) {
2919 mutex_unlock(&gsm->mutex);
2914 return -EL2NSYNC; 2920 return -EL2NSYNC;
2921 }
2915 dlci = gsm->dlci[line]; 2922 dlci = gsm->dlci[line];
2916 if (dlci == NULL) { 2923 if (dlci == NULL) {
2917 alloc = true; 2924 alloc = true;
2918 dlci = gsm_dlci_alloc(gsm, line); 2925 dlci = gsm_dlci_alloc(gsm, line);
2919 } 2926 }
2920 if (dlci == NULL) 2927 if (dlci == NULL) {
2928 mutex_unlock(&gsm->mutex);
2921 return -ENOMEM; 2929 return -ENOMEM;
2930 }
2922 ret = tty_port_install(&dlci->port, driver, tty); 2931 ret = tty_port_install(&dlci->port, driver, tty);
2923 if (ret) { 2932 if (ret) {
2924 if (alloc) 2933 if (alloc)
2925 dlci_put(dlci); 2934 dlci_put(dlci);
2935 mutex_unlock(&gsm->mutex);
2926 return ret; 2936 return ret;
2927 } 2937 }
2928 2938
2939 dlci_get(dlci);
2940 dlci_get(gsm->dlci[0]);
2941 mux_get(gsm);
2929 tty->driver_data = dlci; 2942 tty->driver_data = dlci;
2943 mutex_unlock(&gsm->mutex);
2930 2944
2931 return 0; 2945 return 0;
2932} 2946}
@@ -2937,9 +2951,6 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp)
2937 struct tty_port *port = &dlci->port; 2951 struct tty_port *port = &dlci->port;
2938 2952
2939 port->count++; 2953 port->count++;
2940 dlci_get(dlci);
2941 dlci_get(dlci->gsm->dlci[0]);
2942 mux_get(dlci->gsm);
2943 tty_port_tty_set(port, tty); 2954 tty_port_tty_set(port, tty);
2944 2955
2945 dlci->modem_rx = 0; 2956 dlci->modem_rx = 0;
@@ -2966,7 +2977,7 @@ static void gsmtty_close(struct tty_struct *tty, struct file *filp)
2966 mutex_unlock(&dlci->mutex); 2977 mutex_unlock(&dlci->mutex);
2967 gsm = dlci->gsm; 2978 gsm = dlci->gsm;
2968 if (tty_port_close_start(&dlci->port, tty, filp) == 0) 2979 if (tty_port_close_start(&dlci->port, tty, filp) == 0)
2969 goto out; 2980 return;
2970 gsm_dlci_begin_close(dlci); 2981 gsm_dlci_begin_close(dlci);
2971 if (test_bit(ASYNCB_INITIALIZED, &dlci->port.flags)) { 2982 if (test_bit(ASYNCB_INITIALIZED, &dlci->port.flags)) {
2972 if (C_HUPCL(tty)) 2983 if (C_HUPCL(tty))
@@ -2974,10 +2985,7 @@ static void gsmtty_close(struct tty_struct *tty, struct file *filp)
2974 } 2985 }
2975 tty_port_close_end(&dlci->port, tty); 2986 tty_port_close_end(&dlci->port, tty);
2976 tty_port_tty_set(&dlci->port, NULL); 2987 tty_port_tty_set(&dlci->port, NULL);
2977out: 2988 return;
2978 dlci_put(dlci);
2979 dlci_put(gsm->dlci[0]);
2980 mux_put(gsm);
2981} 2989}
2982 2990
2983static void gsmtty_hangup(struct tty_struct *tty) 2991static void gsmtty_hangup(struct tty_struct *tty)
@@ -3154,6 +3162,16 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state)
3154 return gsmtty_modem_update(dlci, encode); 3162 return gsmtty_modem_update(dlci, encode);
3155} 3163}
3156 3164
3165static void gsmtty_remove(struct tty_driver *driver, struct tty_struct *tty)
3166{
3167 struct gsm_dlci *dlci = tty->driver_data;
3168 struct gsm_mux *gsm = dlci->gsm;
3169
3170 dlci_put(dlci);
3171 dlci_put(gsm->dlci[0]);
3172 mux_put(gsm);
3173 driver->ttys[tty->index] = NULL;
3174}
3157 3175
3158/* Virtual ttys for the demux */ 3176/* Virtual ttys for the demux */
3159static const struct tty_operations gsmtty_ops = { 3177static const struct tty_operations gsmtty_ops = {
@@ -3173,6 +3191,7 @@ static const struct tty_operations gsmtty_ops = {
3173 .tiocmget = gsmtty_tiocmget, 3191 .tiocmget = gsmtty_tiocmget,
3174 .tiocmset = gsmtty_tiocmset, 3192 .tiocmset = gsmtty_tiocmset,
3175 .break_ctl = gsmtty_break_ctl, 3193 .break_ctl = gsmtty_break_ctl,
3194 .remove = gsmtty_remove,
3176}; 3195};
3177 3196
3178 3197