diff options
-rw-r--r-- | drivers/usb/atm/usbatm.c | 66 | ||||
-rw-r--r-- | drivers/usb/atm/usbatm.h | 1 |
2 files changed, 48 insertions, 19 deletions
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index 3ed5f02c36d3..e660a1ebf12b 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c | |||
@@ -602,8 +602,12 @@ static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) | |||
602 | 602 | ||
603 | vdbg("%s called (skb 0x%p, len %u)", __func__, skb, skb->len); | 603 | vdbg("%s called (skb 0x%p, len %u)", __func__, skb, skb->len); |
604 | 604 | ||
605 | if (!instance) { | 605 | /* racy disconnection check - fine */ |
606 | dbg("%s: NULL data!", __func__); | 606 | if (!instance || instance->disconnected) { |
607 | #ifdef DEBUG | ||
608 | if (printk_ratelimit()) | ||
609 | printk(KERN_DEBUG "%s: %s!\n", __func__, instance ? "disconnected" : "NULL instance"); | ||
610 | #endif | ||
607 | err = -ENODEV; | 611 | err = -ENODEV; |
608 | goto fail; | 612 | goto fail; |
609 | } | 613 | } |
@@ -715,15 +719,19 @@ static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *pag | |||
715 | atomic_read(&atm_dev->stats.aal5.rx_err), | 719 | atomic_read(&atm_dev->stats.aal5.rx_err), |
716 | atomic_read(&atm_dev->stats.aal5.rx_drop)); | 720 | atomic_read(&atm_dev->stats.aal5.rx_drop)); |
717 | 721 | ||
718 | if (!left--) | 722 | if (!left--) { |
719 | switch (atm_dev->signal) { | 723 | if (instance->disconnected) |
720 | case ATM_PHY_SIG_FOUND: | 724 | return sprintf(page, "Disconnected\n"); |
721 | return sprintf(page, "Line up\n"); | 725 | else |
722 | case ATM_PHY_SIG_LOST: | 726 | switch (atm_dev->signal) { |
723 | return sprintf(page, "Line down\n"); | 727 | case ATM_PHY_SIG_FOUND: |
724 | default: | 728 | return sprintf(page, "Line up\n"); |
725 | return sprintf(page, "Line state unknown\n"); | 729 | case ATM_PHY_SIG_LOST: |
726 | } | 730 | return sprintf(page, "Line down\n"); |
731 | default: | ||
732 | return sprintf(page, "Line state unknown\n"); | ||
733 | } | ||
734 | } | ||
727 | 735 | ||
728 | return 0; | 736 | return 0; |
729 | } | 737 | } |
@@ -757,6 +765,12 @@ static int usbatm_atm_open(struct atm_vcc *vcc) | |||
757 | 765 | ||
758 | down(&instance->serialize); /* vs self, usbatm_atm_close, usbatm_usb_disconnect */ | 766 | down(&instance->serialize); /* vs self, usbatm_atm_close, usbatm_usb_disconnect */ |
759 | 767 | ||
768 | if (instance->disconnected) { | ||
769 | atm_dbg(instance, "%s: disconnected!\n", __func__); | ||
770 | ret = -ENODEV; | ||
771 | goto fail; | ||
772 | } | ||
773 | |||
760 | if (usbatm_find_vcc(instance, vpi, vci)) { | 774 | if (usbatm_find_vcc(instance, vpi, vci)) { |
761 | atm_dbg(instance, "%s: %hd/%d already in use!\n", __func__, vpi, vci); | 775 | atm_dbg(instance, "%s: %hd/%d already in use!\n", __func__, vpi, vci); |
762 | ret = -EADDRINUSE; | 776 | ret = -EADDRINUSE; |
@@ -845,6 +859,13 @@ static void usbatm_atm_close(struct atm_vcc *vcc) | |||
845 | static int usbatm_atm_ioctl(struct atm_dev *atm_dev, unsigned int cmd, | 859 | static int usbatm_atm_ioctl(struct atm_dev *atm_dev, unsigned int cmd, |
846 | void __user * arg) | 860 | void __user * arg) |
847 | { | 861 | { |
862 | struct usbatm_data *instance = atm_dev->dev_data; | ||
863 | |||
864 | if (!instance || instance->disconnected) { | ||
865 | dbg("%s: %s!", __func__, instance ? "disconnected" : "NULL instance"); | ||
866 | return -ENODEV; | ||
867 | } | ||
868 | |||
848 | switch (cmd) { | 869 | switch (cmd) { |
849 | case ATM_QUERYLOOP: | 870 | case ATM_QUERYLOOP: |
850 | return put_user(ATM_LM_NONE, (int __user *)arg) ? -EFAULT : 0; | 871 | return put_user(ATM_LM_NONE, (int __user *)arg) ? -EFAULT : 0; |
@@ -1129,6 +1150,7 @@ void usbatm_usb_disconnect(struct usb_interface *intf) | |||
1129 | { | 1150 | { |
1130 | struct device *dev = &intf->dev; | 1151 | struct device *dev = &intf->dev; |
1131 | struct usbatm_data *instance = usb_get_intfdata(intf); | 1152 | struct usbatm_data *instance = usb_get_intfdata(intf); |
1153 | struct usbatm_vcc_data *vcc_data; | ||
1132 | int i; | 1154 | int i; |
1133 | 1155 | ||
1134 | dev_dbg(dev, "%s entered\n", __func__); | 1156 | dev_dbg(dev, "%s entered\n", __func__); |
@@ -1141,12 +1163,18 @@ void usbatm_usb_disconnect(struct usb_interface *intf) | |||
1141 | usb_set_intfdata(intf, NULL); | 1163 | usb_set_intfdata(intf, NULL); |
1142 | 1164 | ||
1143 | down(&instance->serialize); | 1165 | down(&instance->serialize); |
1166 | instance->disconnected = 1; | ||
1144 | if (instance->thread_pid >= 0) | 1167 | if (instance->thread_pid >= 0) |
1145 | kill_proc(instance->thread_pid, SIGTERM, 1); | 1168 | kill_proc(instance->thread_pid, SIGTERM, 1); |
1146 | up(&instance->serialize); | 1169 | up(&instance->serialize); |
1147 | 1170 | ||
1148 | wait_for_completion(&instance->thread_exited); | 1171 | wait_for_completion(&instance->thread_exited); |
1149 | 1172 | ||
1173 | down(&instance->serialize); | ||
1174 | list_for_each_entry(vcc_data, &instance->vcc_list, list) | ||
1175 | vcc_release_async(vcc_data->vcc, -EPIPE); | ||
1176 | up(&instance->serialize); | ||
1177 | |||
1150 | tasklet_disable(&instance->rx_channel.tasklet); | 1178 | tasklet_disable(&instance->rx_channel.tasklet); |
1151 | tasklet_disable(&instance->tx_channel.tasklet); | 1179 | tasklet_disable(&instance->tx_channel.tasklet); |
1152 | 1180 | ||
@@ -1156,6 +1184,14 @@ void usbatm_usb_disconnect(struct usb_interface *intf) | |||
1156 | del_timer_sync(&instance->rx_channel.delay); | 1184 | del_timer_sync(&instance->rx_channel.delay); |
1157 | del_timer_sync(&instance->tx_channel.delay); | 1185 | del_timer_sync(&instance->tx_channel.delay); |
1158 | 1186 | ||
1187 | /* turn usbatm_[rt]x_process into something close to a no-op */ | ||
1188 | /* no need to take the spinlock */ | ||
1189 | INIT_LIST_HEAD(&instance->rx_channel.list); | ||
1190 | INIT_LIST_HEAD(&instance->tx_channel.list); | ||
1191 | |||
1192 | tasklet_enable(&instance->rx_channel.tasklet); | ||
1193 | tasklet_enable(&instance->tx_channel.tasklet); | ||
1194 | |||
1159 | if (instance->atm_dev && instance->driver->atm_stop) | 1195 | if (instance->atm_dev && instance->driver->atm_stop) |
1160 | instance->driver->atm_stop(instance, instance->atm_dev); | 1196 | instance->driver->atm_stop(instance, instance->atm_dev); |
1161 | 1197 | ||
@@ -1164,14 +1200,6 @@ void usbatm_usb_disconnect(struct usb_interface *intf) | |||
1164 | 1200 | ||
1165 | instance->driver_data = NULL; | 1201 | instance->driver_data = NULL; |
1166 | 1202 | ||
1167 | /* turn usbatm_[rt]x_process into noop */ | ||
1168 | /* no need to take the spinlock */ | ||
1169 | INIT_LIST_HEAD(&instance->rx_channel.list); | ||
1170 | INIT_LIST_HEAD(&instance->tx_channel.list); | ||
1171 | |||
1172 | tasklet_enable(&instance->rx_channel.tasklet); | ||
1173 | tasklet_enable(&instance->tx_channel.tasklet); | ||
1174 | |||
1175 | for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) { | 1203 | for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) { |
1176 | kfree(instance->urbs[i]->transfer_buffer); | 1204 | kfree(instance->urbs[i]->transfer_buffer); |
1177 | usb_free_urb(instance->urbs[i]); | 1205 | usb_free_urb(instance->urbs[i]); |
diff --git a/drivers/usb/atm/usbatm.h b/drivers/usb/atm/usbatm.h index 4b923a83555e..1a31cf87bb1f 100644 --- a/drivers/usb/atm/usbatm.h +++ b/drivers/usb/atm/usbatm.h | |||
@@ -168,6 +168,7 @@ struct usbatm_data { | |||
168 | 168 | ||
169 | struct kref refcount; | 169 | struct kref refcount; |
170 | struct semaphore serialize; | 170 | struct semaphore serialize; |
171 | int disconnected; | ||
171 | 172 | ||
172 | /* heavy init */ | 173 | /* heavy init */ |
173 | int thread_pid; | 174 | int thread_pid; |