aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/atm/usbatm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/atm/usbatm.c')
-rw-r--r--drivers/usb/atm/usbatm.c66
1 files changed, 47 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)
845static int usbatm_atm_ioctl(struct atm_dev *atm_dev, unsigned int cmd, 859static 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]);