X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lincan.git/blobdiff_plain/cfa9e7afb7fe4e51b86b22be595dfe4c0615fa54..142761e5d7465e36ffa2d980213ff066139f8963:/lincan/src/usbcan.c diff --git a/lincan/src/usbcan.c b/lincan/src/usbcan.c index 429167c..70e0a84 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; } @@ -573,19 +580,20 @@ int usbcan_stop_chip(struct canchip_t *chip) * * File: src/usbcan.c */ -void usbcan_register_devs(struct canchip_t *chip,void *data){ +int usbcan_register_devs(struct canchip_t *chip,void *data){ struct usbcan_devs *usbdevs=(struct usbcan_devs *)data; if (!usbdevs){ CANMSG("Bad structure given\n"); - return; + return -1; } if (chip->chip_idx>=usbdevs->count) { CANMSG("Requested chip number is bigger than chip count\n"); - return; + return -1; } usbdevs->devs[chip->chip_idx]->chip=chip; chip->chip_data=(void *)usbdevs->devs[chip->chip_idx]; + return 0; } /** @@ -620,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; } @@ -743,7 +751,6 @@ void usbcan_kthread_read_handler(struct usbcan_usb *dev, struct usbcan_message * canque_filter_msg2edges(obj->qends, &obj->rx_msg); skip_msg: - set_bit(USBCAN_MESSAGE_URB_PENDING,&m->flags); DEBUGMSG("Renewing RX urb\n"); usbcan_usb_message_move_list(dev, m, &dev->rx_pend_list); @@ -787,13 +794,12 @@ void usbcan_kthread_write_handler(struct usbcan_usb *dev, struct usbcan_message canque_free_outslot(obj->qends, m->qedge, m->slot); m->slot=NULL; } - + /*FIXME - why there*/ can_msgobj_clear_fl(obj,TX_PENDING); skip_msg: set_bit(USBCAN_FREE_TX_URB,&dev->flags); - set_bit(USBCAN_MESSAGE_FREE,&m->flags); set_bit(USBCAN_TX_PENDING,&dev->flags); @@ -820,7 +826,7 @@ void usbcan_kthread_write_request_handler(struct usbcan_usb *dev, struct msgobj_ clear_bit(USBCAN_FREE_TX_URB,&dev->flags); return; } - + m = list_first_entry(&dev->tx_idle_list, typeof(*m), list_node); cmd=canque_test_outslot(obj->qends, &m->qedge, &m->slot); @@ -829,7 +835,6 @@ void usbcan_kthread_write_request_handler(struct usbcan_usb *dev, struct msgobj_ can_msgobj_set_fl(obj,TX_PENDING); clear_bit(USBCAN_FREE_TX_URB,&dev->flags); - clear_bit(USBCAN_MESSAGE_FREE,&m->flags); *(u8 *)(m->msg)=0; len = m->slot->msg.length; @@ -846,16 +851,13 @@ void usbcan_kthread_write_request_handler(struct usbcan_usb *dev, struct msgobj_ *ptr=0; } - set_bit(USBCAN_MESSAGE_URB_PENDING,&m->flags); usbcan_usb_message_move_list(dev, m, &dev->tx_pend_list); retval = usb_submit_urb (m->u, GFP_KERNEL); if (retval){ CANMSG("%d. URB error %d\n",i,retval); - clear_bit(USBCAN_MESSAGE_URB_PENDING,&m->flags); set_bit(USBCAN_FREE_TX_URB,&dev->flags); - set_bit(USBCAN_MESSAGE_FREE,&m->flags); obj->ret = -1; canque_notify_inends(m->qedge, CANQUEUE_NOTIFY_ERRTX_SEND); canque_free_outslot(obj->qends, m->qedge, m->slot); @@ -1009,7 +1011,7 @@ int usbcan_init_chip_data(struct candevice_t *candev, int chipnr) usbcan_fill_chipspecops(chip); - candev->chip[chipnr]->flags|=CHIP_IRQ_CUSTOM; + candev->chip[chipnr]->flags|=CHIP_IRQ_CUSTOM|CHIP_KEEP_DATA; candev->chip[chipnr]->chip_base_addr=0; candev->chip[chipnr]->clock = 0; @@ -1065,7 +1067,6 @@ static void usbcan_tx_callback(struct urb *urb) set_bit(USBCAN_MESSAGE_DATA_OK,&m->flags); DEBUGMSG("%s > TX flag set\n", __FUNCTION__); set_bit(USBCAN_DATA_TX,&m->dev->flags); - clear_bit(USBCAN_MESSAGE_URB_PENDING,&m->flags); usbcan_usb_message_move_list(m->dev, m, &m->dev->tx_ready_list); if (test_bit(USBCAN_THREAD_RUNNING,&m->dev->flags)) wake_up_process(m->dev->comthread); @@ -1077,9 +1078,8 @@ 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; default: //CANMSG("%s > Nonzero status received: %d\n", __FUNCTION__, urb->status); @@ -1091,7 +1091,6 @@ static void usbcan_tx_callback(struct urb *urb) if (retval<0){ CANMSG("%s > Retrying urb failed with result %d\n", __FUNCTION__, retval); set_bit(USBCAN_ERROR,&m->dev->flags); - clear_bit(USBCAN_MESSAGE_URB_PENDING,&m->flags); usbcan_usb_message_move_list(m->dev, m, &m->dev->tx_ready_list); if (test_bit(USBCAN_THREAD_RUNNING,&m->dev->flags)) wake_up_process(m->dev->comthread); @@ -1103,7 +1102,7 @@ static void usbcan_rx_callback(struct urb *urb) struct usbcan_message *m = urb->context; int retval; - if (!test_bit(USBCAN_THREAD_RUNNING,&m->dev->flags)) + if (!test_bit(USBCAN_THREAD_RUNNING,&m->dev->flags)) return; if (test_bit(USBCAN_MESSAGE_TERMINATE,&m->flags)) return; @@ -1116,7 +1115,6 @@ static void usbcan_rx_callback(struct urb *urb) set_bit(USBCAN_MESSAGE_DATA_OK,&m->flags); DEBUGMSG("%s > RX flag set\n", __FUNCTION__); set_bit(USBCAN_DATA_RX,&m->dev->flags); - clear_bit(USBCAN_MESSAGE_URB_PENDING,&m->flags); usbcan_usb_message_move_list(m->dev, m, &m->dev->rx_ready_list); if (test_bit(USBCAN_THREAD_RUNNING,&m->dev->flags)) wake_up_process(m->dev->comthread); @@ -1128,9 +1126,8 @@ 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; default: //CANMSG("%s > Nonzero status received: %d\n", __FUNCTION__, urb->status); @@ -1142,7 +1139,6 @@ static void usbcan_rx_callback(struct urb *urb) if (retval<0){ CANMSG("%s > Retrying urb failed with result %d\n", __FUNCTION__, retval); set_bit(USBCAN_ERROR,&m->dev->flags); - clear_bit(USBCAN_MESSAGE_URB_PENDING,&m->flags); usbcan_usb_message_move_list(m->dev, m, &m->dev->rx_ready_list); if (test_bit(USBCAN_THREAD_RUNNING,&m->dev->flags)) wake_up_process(m->dev->comthread); @@ -1206,7 +1202,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); @@ -1227,7 +1222,7 @@ int usbcan_kthread(void *data) CANMSG("Error allocating %d. usb receive urb\n",i); goto error; } - m = kmalloc(sizeof(struct usbcan_message), GFP_KERNEL); + m = kzalloc(sizeof(struct usbcan_message), GFP_KERNEL); if(!m) { usb_free_urb(u); CANMSG("Error allocating %d. receive usbcan_message\n",i); @@ -1239,7 +1234,7 @@ int usbcan_kthread(void *data) usb_fill_bulk_urb(u, dev->udev, usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr), m->msg, USBCAN_TRANSFER_SIZE, usbcan_rx_callback, m); - set_bit(USBCAN_MESSAGE_TYPE_RX, &m->flags); + list_add_tail(&m->list_node, &dev->rx_ready_list); } @@ -1251,7 +1246,7 @@ int usbcan_kthread(void *data) CANMSG("Error allocating %d. usb transmit urb\n",i); goto error; } - m = kmalloc(sizeof(struct usbcan_message), GFP_KERNEL); + m = kzalloc(sizeof(struct usbcan_message), GFP_KERNEL); if(!m) { usb_free_urb(u); CANMSG("Error allocating %d. transmit usbcan_message\n",i); @@ -1263,9 +1258,7 @@ int usbcan_kthread(void *data) usb_fill_bulk_urb(u, dev->udev, usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), m->msg, USBCAN_TRANSFER_SIZE, usbcan_tx_callback, m); - - set_bit(USBCAN_MESSAGE_FREE,&m->flags); - set_bit(USBCAN_MESSAGE_TYPE_TX,&m->flags); + list_add_tail(&m->list_node, &dev->tx_idle_list); } @@ -1276,7 +1269,6 @@ int usbcan_kthread(void *data) for (i=0;irx_ready_list, typeof(*m), list_node); - set_bit(USBCAN_MESSAGE_URB_PENDING,&m->flags); usbcan_usb_message_move_list(dev, m, &dev->rx_pend_list); retval=usb_submit_urb(m->u, GFP_KERNEL); @@ -1294,30 +1286,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; } @@ -1344,11 +1319,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"); @@ -1380,16 +1352,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 *)); @@ -1401,16 +1372,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 */ @@ -1456,24 +1426,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_usbdev("usbcan",(void *) usbdevs, usbcan_register_devs))) + 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_usbdev(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; @@ -1492,45 +1466,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); + + cleanup_hotplug_dev(usbdevs->candev); if (usbdevs->devs){ - usb_put_dev((*usbdevs->devs)->udev); - } - cleanup_usbdev(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; } @@ -1541,6 +1501,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); }