+
+ /* Prepare transmit urbs */
+ for (i=0;i<USBCAN_TOT_TX_URBS;i++){
+ dev->tx[i].u = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->tx[i].u){
+ CANMSG("Error allocating %d. usb transmit urb\n",i);
+ goto error;
+ }
+ dev->tx[i].u->dev = dev->udev;
+ dev->tx[i].dev = dev;
+ usb_fill_bulk_urb(dev->tx[i].u, dev->udev,
+ usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
+ dev->tx[i].msg, USBCAN_TRANSFER_SIZE,
+ usbcan_callback, &dev->tx[i]);
+ set_bit(USBCAN_MESSAGE_FREE,&dev->tx[i].flags);
+ set_bit(USBCAN_MESSAGE_TYPE_TX,&dev->tx[i].flags);
+ }
+
+ set_bit(USBCAN_THREAD_RUNNING,&dev->flags);
+ set_bit(USBCAN_FREE_TX_URB,&dev->flags);
+
+ for (i=0;i<USBCAN_TOT_RX_URBS;i++){
+ retval=usb_submit_urb(dev->rx[i].u, GFP_KERNEL);
+ if (retval){
+ CANMSG("%d. URB error %d\n",i,retval);
+ set_bit(USBCAN_ERROR,&dev->flags);
+ goto exit;
+ }
+ else
+ set_bit(USBCAN_MESSAGE_URB_PENDING,&dev->rx[i].flags);
+ }
+ /* an endless loop in which we are doing our work */
+ for(;;)
+ {
+ /* We need to do a memory barrier here to be sure that
+ 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 */
+ break;
+ }
+
+ /* 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 */
+ break;
+ }
+
+ { /* Normal work to do */
+ if (test_and_clear_bit(USBCAN_DATA_OK,&dev->flags)){
+ CANMSG("USBCAN Succesfull data transfer\n");
+
+ if (test_and_clear_bit(USBCAN_DATA_RX,&dev->flags)){
+ usbcan_kthread_read_handler(dev, obj);
+ }
+ if (test_and_clear_bit(USBCAN_DATA_TX,&dev->flags)){
+ usbcan_kthread_write_handler(dev, obj);
+ }
+ }
+ if (test_and_clear_bit(USBCAN_TX_PENDING,&dev->flags)){
+ usbcan_kthread_write_request_handler(dev, obj);
+ }
+ }
+ }
+ set_bit(USBCAN_TERMINATE,&dev->flags);
+exit:
+ /* here we go only in case of termination of the thread */
+ for (i=0;i<USBCAN_TOT_RX_URBS;i++){
+ if (dev->rx[i].u){
+ set_bit(USBCAN_MESSAGE_TERMINATE,&dev->rx[i].flags);
+ usb_kill_urb(dev->rx[i].u);
+ usb_free_urb(dev->rx[i].u);
+ }
+ }
+ for (i=0;i<USBCAN_TOT_TX_URBS;i++){
+ if (dev->tx[i].u){
+ set_bit(USBCAN_MESSAGE_TERMINATE,&dev->tx[i].flags);
+ usb_kill_urb(dev->tx[i].u);
+ usb_free_urb(dev->tx[i].u);
+ }
+ }
+ clear_bit(USBCAN_THREAD_RUNNING,&dev->flags);
+
+ CANMSG ("usbcan thread finished!\n");
+ return 0;
+error:
+ /* cleanup the thread, leave */
+ CANMSG ("kernel thread terminated!\n");
+ return -ENOMEM;