diff options
-rw-r--r-- | drivers/tty/n_gsm.c | 39 |
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 { | |||
194 | struct gsm_mux { | 194 | struct 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); |
2977 | out: | 2988 | return; |
2978 | dlci_put(dlci); | ||
2979 | dlci_put(gsm->dlci[0]); | ||
2980 | mux_put(gsm); | ||
2981 | } | 2989 | } |
2982 | 2990 | ||
2983 | static void gsmtty_hangup(struct tty_struct *tty) | 2991 | static 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 | ||
3165 | static 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 */ |
3159 | static const struct tty_operations gsmtty_ops = { | 3177 | static 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 | ||