X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lincan.git/blobdiff_plain/c3adf4f9af7ee68df8bb65fafa4dbcbdcc4895ba..fdf877c54ec2598864f6193e8e1fbaedb5c05efb:/lincan/src/usbcan.c diff --git a/lincan/src/usbcan.c b/lincan/src/usbcan.c index a5e938a..19b1dc6 100644 --- a/lincan/src/usbcan.c +++ b/lincan/src/usbcan.c @@ -11,13 +11,18 @@ #include "../include/devcommon.h" #include "../include/setup.h" #include "../include/usbcan.h" - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)) #include #endif +#include static int usbcan_probe(struct usb_interface *interface, const struct usb_device_id *id); static void usbcan_disconnect(struct usb_interface *interface); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)) +void release_device(struct kref *refcount); +#else +void release_device(struct candevice_t *candev); +#endif volatile int usbcan_chip_count=0; @@ -160,7 +165,6 @@ int usbcan_program_irq(struct candevice_t *candev) return 0; } -/* !!! Don't change this function !!! */ int usbcan_register(struct hwspecops_t *hwspecops) { hwspecops->request_io = usbcan_request_io; @@ -172,6 +176,9 @@ int usbcan_register(struct hwspecops_t *hwspecops) hwspecops->write_register = NULL; hwspecops->read_register = NULL; hwspecops->program_irq = usbcan_program_irq; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)) + hwspecops->release_device = release_device; +#endif return 0; } @@ -621,8 +628,8 @@ int usbcan_release_chip(struct canchip_t *chip) /* terminate the kernel thread */ set_bit(USBCAN_TERMINATE,&dev->flags); - wake_up_process(dev->comthread); -// can_kthread_stop(dev->comthread); +// wake_up_process(dev->comthread); + can_kthread_stop(dev->comthread); return 0; } @@ -1078,7 +1085,7 @@ static void usbcan_tx_callback(struct urb *urb) case -ESHUTDOWN: /* this urb is terminated, clean up */ CANMSG("%s > Urb shutting down with status: %d\n", __FUNCTION__, urb->status); - set_bit(USBCAN_TERMINATE,&m->dev->flags); +// set_bit(USBCAN_TERMINATE,&m->dev->flags); set_bit(USBCAN_MESSAGE_TERMINATE,&m->flags); clear_bit(USBCAN_MESSAGE_URB_PENDING,&m->flags); return; @@ -1129,7 +1136,7 @@ static void usbcan_rx_callback(struct urb *urb) case -ESHUTDOWN: /* this urb is terminated, clean up */ CANMSG("%s > Urb shutting down with status: %d\n", __FUNCTION__, urb->status); - set_bit(USBCAN_TERMINATE,&m->dev->flags); +// set_bit(USBCAN_TERMINATE,&m->dev->flags); set_bit(USBCAN_MESSAGE_TERMINATE,&m->flags); clear_bit(USBCAN_MESSAGE_URB_PENDING,&m->flags); return; @@ -1207,7 +1214,6 @@ int usbcan_kthread(void *data) goto error; obj=dev->chip->msgobj[0]; - INIT_LIST_HEAD(&dev->rx_pend_list); INIT_LIST_HEAD(&dev->rx_ready_list); INIT_LIST_HEAD(&dev->tx_idle_list); @@ -1295,30 +1301,13 @@ int usbcan_kthread(void *data) the flags are visible on all CPUs. */ mb(); /* fall asleep */ - if (!(can_kthread_should_stop() || test_bit(USBCAN_TERMINATE,&dev->flags))){ - if (usbcan_sleep_thread(dev)<0) - break; -/* wait_event_interruptible(dev->queue, - can_kthread_should_stop() || - test_bit(USBCAN_DATA_OK,&dev->flags) || - test_bit(USBCAN_TX_PENDING,&dev->flags) || - test_bit(USBCAN_TERMINATE,&dev->flags) || - test_bit(USBCAN_ERROR,&dev->flags) - );*/ - } - /* We need to do a memory barrier here to be sure that - the flags are visible on all CPUs. */ - mb(); - - /* here we are back from sleep because we caught a signal. */ - if (can_kthread_should_stop()){ - /* we received a request to terminate ourself */ + if (!can_kthread_should_stop() && !test_bit(USBCAN_TERMINATE,&dev->flags) && (usbcan_sleep_thread(dev)<0)){ break; } + /* We need to do a memory barrier here to be sure that the flags are visible on all CPUs. */ + mb(); - /* here we are back from sleep because we caught a signal. */ - if (test_bit(USBCAN_TERMINATE,&dev->flags)){ - /* we received a request to terminate ourself */ + if (can_kthread_should_stop() || test_bit(USBCAN_TERMINATE,&dev->flags)){ break; } @@ -1345,11 +1334,8 @@ int usbcan_kthread(void *data) set_bit(USBCAN_TERMINATE,&dev->flags); exit: - /* here we go only in case of termination of the thread */ usbcan_kthread_free_urbs(dev); - - clear_bit(USBCAN_THREAD_RUNNING,&dev->flags); CANMSG ("usbcan thread finished!\n"); @@ -1381,16 +1367,15 @@ static int usbcan_probe(struct usb_interface *interface, const struct usb_device usbdevs = (struct usbcan_devs *) can_checked_malloc(sizeof(struct usbcan_devs)); if (!usbdevs) { - CANMSG("Out of memory"); - goto error; + goto noalloc; } memset(usbdevs, 0, sizeof(struct usbcan_devs)); - usbdevs->count=usbcan_chip_count; + usbdevs->count = usbcan_chip_count; + usbdevs->udev = interface_to_usbdev(interface); usbdevs->devs = (struct usbcan_usb **) can_checked_malloc(usbcan_chip_count * sizeof(struct usbcan_usb *)); if (!usbdevs->devs) { - CANMSG("Out of memory"); goto error; } memset(usbdevs->devs, 0, usbcan_chip_count * sizeof(struct usbcan_usb *)); @@ -1402,16 +1387,15 @@ static int usbcan_probe(struct usb_interface *interface, const struct usb_device /* allocate memory for our device state and initialize it */ usbdevs->devs[j] = (struct usbcan_usb *) can_checked_malloc(sizeof(struct usbcan_usb)); if (!usbdevs->devs[j]) { - CANMSG("Out of memory"); goto error; } memset(usbdevs->devs[j], 0, sizeof(struct usbcan_usb)); dev=usbdevs->devs[j]; - spin_lock_init(&usbdevs->devs[j]->list_lock); + spin_lock_init(&dev->list_lock); mutex_init(&dev->io_mutex); init_waitqueue_head(&dev->queue); - dev->udev = interface_to_usbdev(interface); + dev->udev = usbdevs->udev; dev->interface = interface; /* set up the endpoint information */ @@ -1457,24 +1441,28 @@ static int usbcan_probe(struct usb_interface *interface, const struct usb_device goto error; } } + + usb_get_dev(usbdevs->udev); + /* save our data pointer in this interface device */ usb_set_intfdata(interface, usbdevs); - if (!(usbdevs->candev=register_hotplug_dev("usbcan", usbcan_register_devs,(void *) usbdevs))) + usbdevs->candev=register_hotplug_dev("usbcan", usbcan_register_devs,(void *) usbdevs); + if (!(usbdevs->candev)){ + CANMSG("register_hotplug_dev() failed\n"); goto register_error; + } /* let the user know what node this device is now attached to */ CANMSG("USBCAN device now attached\n"); return 0; register_error: - cleanup_hotplug_dev(usbdevs->candev); +// cleanup_hotplug_dev(usbdevs->candev); + usb_put_dev(usbdevs->udev); error: if (usbdevs){ if (usbdevs->devs){ - if (usbdevs->devs[0]){ - usb_put_dev(usbdevs->devs[0]->udev); - } for (j=0;jcount;j++){ if (!usbdevs->devs[j]) continue; @@ -1493,45 +1481,31 @@ noalloc: return retval; } -// Physically disconnected device -static void usbcan_disconnect(struct usb_interface *interface) -{ - struct usbcan_devs *usbdevs; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)) +void release_device(struct kref *refcount){ + struct candevice_t *candev = container_of(refcount,struct candevice_t,refcount); +#else +void release_device(struct candevice_t *candev){ +#endif + struct usbcan_devs *usbdevs = (struct usbcan_devs *)candev->sysdevptr.anydev; int j; - usbdevs = usb_get_intfdata(interface); - if (usbdevs==NULL){ - CANMSG("USBCAN device seems to be removed\n"); + + if (!usbdevs) return; - } - usb_set_intfdata(interface, NULL); - - if (usbdevs->devs){ - usb_put_dev((*usbdevs->devs)->udev); - } + cleanup_hotplug_dev(usbdevs->candev); + if (usbdevs->devs){ + /* Finally, release all structures in USB subsystem */ + if (!usbdevs->udev) + panic("udev is already null on device release"); + usb_put_dev(usbdevs->udev); + for (j=0;jcount;j++){ if (!usbdevs->devs[j]) continue; - /* prevent more I/O from starting */ - mutex_lock(&usbdevs->devs[j]->io_mutex); - usbdevs->devs[j]->interface = NULL; - mutex_unlock(&usbdevs->devs[j]->io_mutex); - - while (test_bit(USBCAN_THREAD_RUNNING,&usbdevs->devs[j]->flags)) - { - CANMSG("USBCAN thread has not stopped, trying to wake...\n"); - set_bit(USBCAN_TERMINATE,&usbdevs->devs[j]->flags); - wake_up_process(usbdevs->devs[j]->comthread); - schedule(); -// can_kthread_stop(dev->comthread); - } - if (usbdevs->devs[j]->bulk_in_buffer) can_checked_free(usbdevs->devs[j]->bulk_in_buffer); - // if (usbdevs->devs[j]->chip){ - // usbdevs->devs[j]->chip->chip_data=NULL; - // } can_checked_free(usbdevs->devs[j]); usbdevs->devs[j]=NULL; } @@ -1542,6 +1516,40 @@ static void usbcan_disconnect(struct usb_interface *interface) CANMSG("USBCAN now disconnected\n"); } +// Physically disconnected device +static void usbcan_disconnect(struct usb_interface *interface) +{ + struct usbcan_devs *usbdevs; + int j; + + /* prevent more I/O from starting */ + lock_kernel(); + + usbdevs = usb_get_intfdata(interface); + if (usbdevs==NULL){ + CANMSG("USBCAN device seems to be already removed\n"); + unlock_kernel(); + return; + } + usb_set_intfdata(interface, NULL); + deregister_hotplug_dev(usbdevs->candev); + + for (j=0;jcount;j++){ + if (!usbdevs->devs[j]) continue; + mutex_lock(&usbdevs->devs[j]->io_mutex); + usbdevs->devs[j]->interface = NULL; + mutex_unlock(&usbdevs->devs[j]->io_mutex); + } + + unlock_kernel(); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)) + kref_put(&usbdevs->candev->refcount,release_device); +#else + release_device(&usbdevs->candev); +#endif +} + int usbcan_init(void){ return usb_register(&usbcan_driver); }