]> rtime.felk.cvut.cz Git - lincan.git/blobdiff - lincan/src/usbcan.c
Each (future) canchip associated to different usb endpoint, instead of whole device...
[lincan.git] / lincan / src / usbcan.c
index cb1c9b0b2d285433fefec52715c629ca03ccdf5f..f29e549b496cc87dd28891a23f0a0e0aad0041d4 100644 (file)
@@ -5,7 +5,6 @@
  * Version lincan-0.3  17 Jul 2008
  */
 
-#include "../include/kthread.h"
 #include "../include/can.h"
 #include "../include/can_sysdep.h"
 #include "../include/main.h"
 #include "../include/setup.h"
 #include "../include/usbcan.h"
 
+static int usbcan_probe(struct usb_interface *interface, const struct usb_device_id *id);
+static void usbcan_disconnect(struct usb_interface *interface);
+
+volatile int usbcan_chip_count=0;
+
+/* table of devices that work with this driver */
+static struct usb_device_id usbcan_table [] = {
+       { USB_DEVICE(USBCAN_VENDOR_ID, USBCAN_PRODUCT_ID) },
+       { }                                     /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, usbcan_table);
+
+static struct usb_driver usbcan_driver = {
+       .name =         "usbcan",
+       .id_table = usbcan_table,
+       .probe =        usbcan_probe,
+       .disconnect =   usbcan_disconnect,
+};
+
 /**
  * usbcan_request_io: - reserve io or memory range for can board
  * @candev: pointer to candevice/board which asks for io. Field @io_addr
  */
 int usbcan_request_io(struct candevice_t *candev)
 {
-       struct usbcan_usb *dev = (struct usbcan_usb*)candev->sysdevptr.anydev;
+       struct usbcan_devs *usbdevs = (struct usbcan_devs *)candev->sysdevptr.anydev;
 
-       /* start kernel thread */
-       dev->rcvthread.arg = dev;
-       start_kthread(usbcan_read_kthread, &dev->rcvthread);
+       if (!usbdevs){
+               CANMSG("USBCAN_REQUEST_IO: Cannot register usbcan while usb device is not present.\n");
+               CANMSG("USBCAN_REQUEST_IO: Usbcan registers automatically on device insertion.\n");
+               return -ENODEV;
+       }
 
-       /* Adding link to can device into usbcan_usb struct */
-       ((struct usbcan_usb*)candev->sysdevptr.anydev)->candev=candev;
        return 0;
 }
 
@@ -54,14 +72,6 @@ int usbcan_request_io(struct candevice_t *candev)
  */
 int usbcan_release_io(struct candevice_t *candev)
 {
-       struct usbcan_usb *dev = ((struct usbcan_usb*)candev->sysdevptr.anydev);
-
-       /* terminate the kernel thread */
-       if (dev->rcv){
-               usb_kill_urb(dev->rcv);
-               usb_free_urb(dev->rcv);
-       }
-       stop_kthread(&dev->rcvthread);
        return 0;
 }
 
@@ -99,7 +109,7 @@ int usbcan_init_hw_data(struct candevice_t *candev)
        candev->res_addr=RESET_ADDR;
        candev->nr_82527_chips=0;
        candev->nr_sja1000_chips=0;
-       candev->nr_all_chips=1;
+       candev->nr_all_chips=usbcan_chip_count;
        candev->flags |= CANDEV_PROGRAMMABLE_IRQ*0;
 
        return 0;
@@ -124,7 +134,7 @@ int usbcan_init_hw_data(struct candevice_t *candev)
  */
 int usbcan_init_obj_data(struct canchip_t *chip, int objnr)
 {
-       chip->msgobj[objnr]->obj_base_addr=chip->chip_base_addr+(objnr+1)*0x10;
+       chip->msgobj[objnr]->obj_base_addr=0;
 
        return 0;
 }
@@ -161,7 +171,7 @@ int usbcan_register(struct hwspecops_t *hwspecops)
        return 0;
 }
 
-static int sja1000_report_error_limit_counter;
+// static int sja1000_report_error_limit_counter;
 
 static void sja1000_report_error(struct canchip_t *chip,
                                unsigned sr, unsigned ir, unsigned ecc)
@@ -251,33 +261,36 @@ int usbcan_chip_config(struct canchip_t *chip)
 int usbcan_extended_mask(struct canchip_t *chip, unsigned long code, unsigned  long mask)
 {
        int retval;
-       struct usbcan_usb *dev=(struct usbcan_usb*)chip->hostdevice->sysdevptr.anydev;
+       struct usbcan_usb *dev=(struct usbcan_usb*)chip->chip_data;
+
+       u8 usbbuf[16];
+
+       if (!dev)
+               return -ENODEV;
 
-       struct usbcan_mask_t mask={
-               .code=code;
-               .mask=mask;
-       };
+       *(uint32_t *)(usbbuf)=cpu_to_le32(mask);
+       *(uint32_t *)(usbbuf+4)=cpu_to_le32(code);
 
        retval=usb_control_msg(dev->udev,
-               usb_sndctrlpipe(dev->udev, dev->ctl_out_endpointAddr),
+               usb_sndctrlpipe(dev->udev, 0),
                USBCAN_VENDOR_EXT_MASK_SET,
                USB_TYPE_VENDOR,
-               0, chip->chip_idx,
-               &mask, sizeof(usbcan_mask_t),
+               cpu_to_le16(0), cpu_to_le16(chip->chip_idx),
+               &usbbuf, 16,
                10000);
        if (retval<0)
                return -ENODEV;
 
        retval = usb_control_msg(dev->udev,
-               usb_rcvctrlpipe(dev->udev, dev->ctl_in_endpointAddr),
+               usb_rcvctrlpipe(dev->udev, 0),
                USBCAN_VENDOR_EXT_MASK_STATUS,
                USB_TYPE_VENDOR,
-               0, chip->chip_idx,
-               dev->ctl_in_buffer, dev->ctl_in_size,
+               cpu_to_le16(0), cpu_to_le16(chip->chip_idx),
+               &usbbuf, 16,
                10000);
 
        if (retval==1){
-               if(dev->ctl_in_buffer[0]==1){
+               if(usbbuf[0]==1){
                        DEBUGMSG("Setting acceptance code to 0x%lx\n",(unsigned long)code);
                        DEBUGMSG("Setting acceptance mask to 0x%lx\n",(unsigned long)mask);
                        return 0;
@@ -304,37 +317,38 @@ int usbcan_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw,
                                                        int sampl_pt, int flags)
 {
        int retval;
-       struct usbcan_usb *dev=(struct usbcan_usb*)chip->hostdevice->sysdevptr.anydev;
+       struct usbcan_usb *dev=(struct usbcan_usb*)chip->chip_data;
+
+       u8 usbbuf[16];
 
-       // Data too big to use single receive control message
-       struct can_baudparams_t baud={
-               .flags=flags,
-               .baudrate=rate,
-               .sjw=sjw,
-               .sample_pt=sampl_pt,
-       };
+       if (!dev)
+               return -ENODEV;
 
+       *(int32_t *)(usbbuf)=cpu_to_le32(rate);
+       *(int32_t *)(usbbuf+4)=cpu_to_le32(sjw);
+       *(int32_t *)(usbbuf+8)=cpu_to_le32(sampl_pt);
+       *(int32_t *)(usbbuf+12)=cpu_to_le32(flags);
 
        retval=usb_control_msg(dev->udev,
-               usb_sndctrlpipe(dev->udev, dev->ctl_out_endpointAddr),
+               usb_sndctrlpipe(dev->udev, 0),
                USBCAN_VENDOR_BAUD_RATE_SET,
                USB_TYPE_VENDOR,
-               0, chip->chip_idx,
-               &baud, sizeof(can_baudparams_t),
+               cpu_to_le16(0), cpu_to_le16(chip->chip_idx),
+               &usbbuf, 16,
                10000);
        if (retval<0)
                return -ENODEV;
 
        retval = usb_control_msg(dev->udev,
-               usb_rcvctrlpipe(dev->udev, dev->ctl_in_endpointAddr),
+               usb_rcvctrlpipe(dev->udev, 0),
                USBCAN_VENDOR_BAUD_RATE_STATUS,
                USB_TYPE_VENDOR,
-               0, chip->chip_idx,
-               dev->ctl_in_buffer, dev->ctl_in_size,
+               cpu_to_le16(0), cpu_to_le16(chip->chip_idx),
+               usbbuf, 16,
                10000);
 
        if (retval==1){
-               if(dev->ctl_in_buffer[0]==1)
+               if(usbbuf[0]==1)
                        return 0;
        }
 
@@ -374,10 +388,13 @@ int usbcan_pre_read_config(struct canchip_t *chip, struct msgobj_t *obj)
 int usbcan_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj,
                                                        struct canmsg_t *msg)
 {
-       struct usbcan_usb *dev=(struct usbcan_usb*)chip->hostdevice->sysdevptr.anydev;
+       struct usbcan_usb *dev=(struct usbcan_usb*)chip->chip_data;
        int i=0;
        int len;
+       u8 *ptr;
 
+       if (!dev)
+               return -ENODEV;
        /* Wait until Transmit Buffer Status is released */
        while ( usbcan_chip_queue_status(chip) &&
                                                i++<MAX_TRANSMIT_WAIT_LOOPS) {
@@ -388,29 +405,20 @@ int usbcan_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj,
                return -EIO;
        }
 
-       dev->tx_msg.chip_id=(__u8)chip->chip_idx;
+       *(uint8_t *)(dev->tx_msg)=chip->chip_idx & 0xFF;
 
        len = msg->length;
        if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH;
-       dev->tx_msg.length=(__u8)len;
-       dev->tx_msg.flags=(__u16)msg->flags;
-
-       if(msg->flags&MSG_EXT) {
-               dev->tx_msg.id[0]=(msg->id) & 0xff;
-               dev->tx_msg.id[1]=(msg->id>>8) & 0xff;
-               dev->tx_msg.id[2]=(msg->id>>16) & 0xff;
-               dev->tx_msg.id[3]=(msg->id>>24) & 0xff;
-       } else {
-               dev->tx_msg.id[0]=(msg->id) & 0xff;
-               dev->tx_msg.id[1]=(msg->id>>8) & 0xff;
-               dev->tx_msg.id[2]=0;
-               dev->tx_msg.id[3]=0;
-       }
-       for(i=0; i < len; i++) {
-               dev->tx_msg.data[i]=(__u8) msg->data[i];
+
+       *(uint8_t *)(dev->tx_msg+1)=len & 0xFF;
+       *(uint16_t *)(dev->tx_msg+2)=cpu_to_le16(msg->flags);
+       *(uint32_t *)(dev->tx_msg+4)=cpu_to_le32(msg->id);
+
+       for(ptr=dev->tx_msg+8,i=0; i < len; ptr++,i++) {
+               *ptr=msg->data[i] & 0xFF;
        }
-       for(i; i < 8; i++) {
-               dev->tx_msg.data[i]=0;
+       for(; i < 8; ptr++,i++) {
+               *ptr=0;
        }
        return 0;
 }
@@ -429,24 +437,43 @@ int usbcan_pre_write_config(struct canchip_t *chip, struct msgobj_t *obj,
 int usbcan_send_msg(struct canchip_t *chip, struct msgobj_t *obj,
                                                        struct canmsg_t *msg)
 {
-       struct usbcan_usb *dev=(struct usbcan_usb*)chip->hostdevice->sysdevptr.anydev;
-       int len;
+       struct usbcan_usb *dev=(struct usbcan_usb*)chip->chip_data;
+       int len,retval;
+
+       if (!dev)
+               return -ENODEV;
 
        set_bit(USBCAN_TX_PENDING,&dev->flags);
        retval=usb_bulk_msg(dev->udev,
                        usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
-                       &dev->tx_msg, sizeof(usbcan_canmsg_t),
+                       &dev->tx_msg, 16,
                        &len,10000);
        clear_bit(USBCAN_TX_PENDING,&dev->flags);
        if (retval){
                CANMSG("URB error %d\n",retval);
                return -EIO;
        }
-       if (len!=sizeof(struct usbcan_canmsg_t)){
+       if (len!=16){
                CANMSG("CAN message not sent\n");
                return -EIO;
        }
+       CANMSG("Message sent\n");
+
+       if(obj->tx_slot){
+               // Do local transmitted message distribution if enabled
+               if (processlocal){
+                       // fill CAN message timestamp
+                       can_filltimestamp(&obj->tx_slot->msg.timestamp);
+
+                       obj->tx_slot->msg.flags |= MSG_LOCAL;
+                       canque_filter_msg2edges(obj->qends, &obj->tx_slot->msg);
+               }
+               // Free transmitted slot
+               canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
+               obj->tx_slot=NULL;
+       }
 
+       can_msgobj_clear_fl(obj,TX_PENDING);
        return 0;
 }
 
@@ -461,7 +488,10 @@ int usbcan_send_msg(struct canchip_t *chip, struct msgobj_t *obj,
  */
 int usbcan_check_tx_stat(struct canchip_t *chip)
 {
-       if (test_bit(USBCAN_TX_PENDING,&((struct usbcan_usb*)chip->hostdevice->sysdevptr.anydev)->flags))
+       struct usbcan_usb *dev=(struct usbcan_usb*)chip->chip_data;
+       if (!dev)
+               return 0;
+       if (test_bit(USBCAN_TX_PENDING,&dev->flags))
                return 1;
        return 0;
 }
@@ -479,18 +509,23 @@ int usbcan_set_btregs(struct canchip_t *chip, unsigned short btr0,
                                                        unsigned short btr1)
 {
        int retval;
-       struct usbcan_usb *dev=(struct usbcan_usb*)chip->hostdevice->sysdevptr.anydev;
+       u8      buf[16];
+       struct usbcan_usb *dev=(struct usbcan_usb*)chip->chip_data;
+       uint16_t value=(btr1&0xFF)<<8 | (btr0&0xFF);
+
+       if (!dev)
+               return -ENODEV;
 
        retval = usb_control_msg(dev->udev,
-       usb_rcvctrlpipe(dev->udev, dev->ctl_in_endpointAddr),
+       usb_rcvctrlpipe(dev->udev, 0),
        USBCAN_VENDOR_SET_BTREGS,
        USB_TYPE_VENDOR,
-       btr1<<8 | btr0, chip->chip_idx,
-       dev->ctl_in_buffer, dev->ctl_in_size,
+       cpu_to_le16(value), cpu_to_le16(chip->chip_idx),
+       &buf, 16,
        10000);
 
        if (retval==1){
-               if(dev->ctl_in_buffer[0]==1)
+               if(buf[0]==1)
                        return 0;
        }
        return -ENODEV;
@@ -506,18 +541,22 @@ int usbcan_set_btregs(struct canchip_t *chip, unsigned short btr0,
 int usbcan_start_chip(struct canchip_t *chip)
 {
        int retval;
-       struct usbcan_usb *dev=(struct usbcan_usb*)chip->hostdevice->sysdevptr.anydev;
+       u8      buf[16];
+       struct usbcan_usb *dev=(struct usbcan_usb*)chip->chip_data;
+
+       if (!dev)
+               return -ENODEV;
 
        retval = usb_control_msg(dev->udev,
-       usb_rcvctrlpipe(dev->udev, dev->ctl_in_endpointAddr),
+       usb_rcvctrlpipe(dev->udev, 0),
        USBCAN_VENDOR_START_CHIP,
        USB_TYPE_VENDOR,
-       0, chip->chip_idx,
-       dev->ctl_in_buffer, dev->ctl_in_size,
+       cpu_to_le16(0), cpu_to_le16(chip->chip_idx),
+       &buf, 16,
        10000);
 
        if (retval==1){
-               if(dev->ctl_in_buffer[0]==1)
+               if(buf[0]==1)
                        return 0;
        }
        return -ENODEV;
@@ -535,22 +574,27 @@ int usbcan_start_chip(struct canchip_t *chip)
 int usbcan_chip_queue_status(struct canchip_t *chip)
 {
        int retval;
-       struct usbcan_usb *dev=(struct usbcan_usb*)chip->hostdevice->sysdevptr.anydev;
+       u8      buf[16];
+       struct usbcan_usb *dev=(struct usbcan_usb*)chip->chip_data;
 
+       if (!dev)
+               return -ENODEV;
        retval = usb_control_msg(dev->udev,
-       usb_rcvctrlpipe(dev->udev, dev->ctl_in_endpointAddr),
+       usb_rcvctrlpipe(dev->udev, 0),
        USBCAN_VENDOR_CHECK_TX_STAT,
        USB_TYPE_VENDOR,
-       0, chip->chip_idx,
-       dev->ctl_in_buffer, dev->ctl_in_size,
+       cpu_to_le16(0), cpu_to_le16(chip->chip_idx),
+       &buf, 16,
        10000);
 
        if (retval==1){
-               if(dev->ctl_in_buffer[0]==1)
-                       return 1;
-               if(dev->ctl_in_buffer[0]==0)
+               CANMSG("Chip_queue_status: %d\n",buf[0]);
+               if(buf[0]==1)
                        return 0;
+               if(buf[0]==0)
+                       return 1;
        }
+       CANMSG("Chip_queue_status error: %d\n",retval);
        return -ENODEV;
 }
 
@@ -564,23 +608,49 @@ int usbcan_chip_queue_status(struct canchip_t *chip)
 int usbcan_stop_chip(struct canchip_t *chip)
 {
        int retval;
-       struct usbcan_usb *dev=(struct usbcan_usb*)chip->hostdevice->sysdevptr.anydev;
+       u8      buf[16];
+       struct usbcan_usb *dev=(struct usbcan_usb*)chip->chip_data;
+
+       if (!dev)
+               return -ENODEV;
 
        retval = usb_control_msg(dev->udev,
-       usb_rcvctrlpipe(dev->udev, dev->ctl_in_endpointAddr),
+       usb_rcvctrlpipe(dev->udev, 0),
        USBCAN_VENDOR_STOP_CHIP,
        USB_TYPE_VENDOR,
-       0, chip->chip_idx,
-       dev->ctl_in_buffer, dev->ctl_in_size,
+       cpu_to_le16(0), cpu_to_le16(chip->chip_idx),
+       &buf, 16,
        10000);
 
        if (retval==1){
-               if(dev->ctl_in_buffer[0]==1)
+               if(buf[0]==1)
                        return 0;
        }
        return -ENODEV;
 }
 
+/**
+ * usbcan_register_devs: - attaches usb device data to the chip structure
+ * @chip: pointer to chip state structure
+ * @data: usb device data
+ *
+ * File: src/usbcan.c
+ */
+void 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;
+       }
+       if (chip->chip_idx>=usbdevs->count) {
+           CANMSG("Requested chip number is bigger than chip count\n");
+           return;
+       }
+
+       usbdevs->devs[chip->chip_idx]->chip=chip;
+       chip->chip_data=(void *)usbdevs->devs[chip->chip_idx];
+}
+
 /**
  * usbcan_attach_to_chip: - attaches to the chip, setups registers and state
  * @chip: pointer to chip state structure
@@ -590,6 +660,11 @@ int usbcan_stop_chip(struct canchip_t *chip)
  */
 int usbcan_attach_to_chip(struct canchip_t *chip)
 {
+       struct usbcan_usb *dev = (struct usbcan_usb *)chip->chip_data;
+
+       /* start kernel thread */
+       dev->comthread=can_kthread_run(usbcan_read_kthread, (void *)dev, "usbcan_%d",chip->chip_idx);
+
        return 0;
 }
 
@@ -602,7 +677,13 @@ int usbcan_attach_to_chip(struct canchip_t *chip)
  */
 int usbcan_release_chip(struct canchip_t *chip)
 {
+       struct usbcan_usb *dev = (struct usbcan_usb *)chip->chip_data;
+
        usbcan_stop_chip(chip);
+
+       /* terminate the kernel thread */
+       can_kthread_stop(dev->comthread);
+
        return 0;
 }
 
@@ -835,7 +916,7 @@ int usbcan_irq_handler(int irq, struct canchip_t *chip)
  */
 int usbcan_wakeup_tx(struct canchip_t *chip, struct msgobj_t *obj)
 {
-
+       CANMSG("Trying to send message\n");
        can_preempt_disable();
 
        can_msgobj_set_fl(obj,TX_PENDING);
@@ -949,17 +1030,46 @@ int usbcan_init_chip_data(struct candevice_t *candev, int chipnr)
 
 
 /* --------------------------------------------------------------------------------------------------- */
+static int usbcan_sleep_thread(struct usbcan_usb *dev)
+{
+       int     rc = 0;
+
+       /* Wait until a signal arrives or we are woken up */
+       for (;;) {
+               try_to_freeze();
+               set_current_state(TASK_INTERRUPTIBLE);
+               if (signal_pending(current)) {
+                       rc = -EINTR;
+                       break;
+               }
+               if (
+                       can_kthread_should_stop() ||
+                       test_bit(USBCAN_DATA_READ,&dev->flags) ||
+                       test_bit(USBCAN_TERMINATE,&dev->flags) ||
+                       test_bit(USBCAN_ERROR,&dev->flags)
+               )
+                       break;
+               schedule();
+       }
+       __set_current_state(TASK_RUNNING);
+       return rc;
+}
 
 static void usbcan_rcv(struct urb *urb)
 {
        struct usbcan_usb *dev = urb->context;
        int retval;
 
+       if (!test_bit(USBCAN_THREAD_RUNNING,&dev->flags))
+               return;
+
        switch (urb->status) {
        case 0:
                /* success */
                set_bit(USBCAN_DATA_READ,&dev->flags);
-               wake_up(&dev->rcvthread.queue);
+               CANMSG("Message received\n");
+               if (test_bit(USBCAN_THREAD_RUNNING,&dev->flags))
+                       wake_up_process(dev->comthread);
                return;
        case -ECONNRESET:
        case -ENOENT:
@@ -967,246 +1077,284 @@ static void usbcan_rcv(struct urb *urb)
                /* this urb is terminated, clean up */
                CANMSG("%s - urb shutting down with status: %d\n", __FUNCTION__, urb->status);
                set_bit(USBCAN_TERMINATE,&dev->flags);
-               wake_up(&dev->rcvthread.queue);
                return;
        default:
-               CANMSG("%s - nonzero urb status received: %d\n", __FUNCTION__, urb->status);
+//             CANMSG("%s - nonzero urb status received: %d\n", __FUNCTION__, urb->status);
                break;
        }
 
        retval = usb_submit_urb (urb, GFP_ATOMIC);
        if (retval<0){
-               CANMSG("%s - usb_submit_urb failed with result %d\n",
+               CANMSG("%s - usb_submit_urb failed with result %d ... retrying\n",
                     __FUNCTION__, retval);
                set_bit(USBCAN_ERROR,&dev->flags);
-               wake_up(&dev->rcvthread.queue);
+               if (test_bit(USBCAN_THREAD_RUNNING,&dev->flags))
+                       wake_up_process(dev->comthread);
        }
 }
 
-void usbcan_read_kthread(kthread_t *kthread)
+int usbcan_read_kthread(void *data)
 {
-       int retval;
-       struct usbcan_usb *dev=(struct usbcan_usb *)kthread->arg;
+       int retval=0;
+       struct usbcan_usb *dev=(struct usbcan_usb *)data;
        struct msgobj_t *obj;
 
-  /* setup the thread environment */
-  init_kthread(kthread, "usbcan");
-
   /* this is normal work to do */
   CANMSG ("usbcan thread started!\n");
 
-       dev->rcv = usb_alloc_urb(0, GFP_KERNEL);
-       if (!dev->rcv){
+       dev->rx = usb_alloc_urb(0, GFP_KERNEL);
+       if (!dev->rx){
                CANMSG("Error allocating usb urb\n");
                goto error;
        }
-       dev->rcv->dev = dev->udev;
-       usb_fill_bulk_urb(dev->rcv, dev->udev,
+       dev->rx->dev = dev->udev;
+       usb_fill_bulk_urb(dev->rx, dev->udev,
                         usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
-                        &dev->rcv_msg, sizeof(usbcan_canmsg_t),
+                        &dev->rx_msg, 16,
                         usbcan_rcv, dev);
 
+       set_bit(USBCAN_THREAD_RUNNING,&dev->flags);
   /* an endless loop in which we are doing our work */
   for(;;)
   {
-               retval=usb_submit_urb(dev->rcv, GFP_KERNEL);
+               retval=usb_submit_urb(dev->rx, GFP_ATOMIC);
                if (retval){
                        CANMSG("URB error %d\n",retval);
+                       set_bit(USBCAN_ERROR,&dev->flags);
                        break;
                }
+               /* We need to do a memory barrier here to be sure that
+               the flags are visible on all CPUs. */
+               mb();
                /* fall asleep */
-               wait_event_interruptible(kthread->queue,
-                       test_bit(USBCAN_CHIP_DATA_READ,&chip_data->flags)
-                       || test_bit(USBCAN_CHIP_TERMINATE,&chip_data->flags)
-                       || test_bit(USBCAN_CHIP_ERROR,&chip_data->flags)
-               );
-
+               usbcan_sleep_thread(dev);
                /* 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 (kthread->terminate)
+               if (can_kthread_should_stop())
                {
                        /* we received a request to terminate ourself */
                        break;
                }
 
-               if (test_bit(USBCAN_CHIP_ERROR,&chip_data->flags)){
-                       CANMSG("URB error %d\n",retval);
-                       break;
-               }
-
                { /* Normal work to do */
-                       if (test_bit(USBCAN_CHIP_DATA_READ,&chip_data->flags)){
+                       if (test_bit(USBCAN_DATA_READ,&dev->flags)){
                                int i, len;
-                               clear_bit(USBCAN_CHIP_DATA_READ,&chip_data->flags);
-
-                               if ((dev->candev->chip[dev->rcv_msg.chip_id])&&
-                                       (dev->candev->chip[dev->rcv_msg.chip_id].flags & CHIP_CONFIGURED)){
-
-                                       obj=dev->candev->chip[dev->rcv_msg.chip_id]->msgobj[0];
-                                       if (dev->rcv_msg.flags & MSG_EXT) {
-                                               obj->rx_msg.id =
-                                                       (dev->rcv_msg.id[0]) +
-                                                       (dev->rcv_msg.id[1]<<8) +
-                                                       (dev->rcv_msg.id[2]<<16) +
-                                                       (dev->rcv_msg.id[3]<<24);
-                                       } else {
-                                               obj->rx_msg.id =
-                                                       (dev->rcv_msg.id[0]) +
-                                                       (dev->rcv_msg.id[1]<<8);
-                                       }
-                                       obj->rx_msg.flags = dev->rcv_msg.flags;
-                                       len=dev->rcv_msg.length;
+                               clear_bit(USBCAN_DATA_READ,&dev->flags);
+                               CANMSG("Thread got received message\n");
+
+                               if ((dev->chip)&&
+                                       (dev->chip->flags & CHIP_CONFIGURED)
+                               ){
+                                       u8 *ptr;
+
+                                       obj=dev->chip->msgobj[0];
+
+                                       len=*(uint8_t *)(dev->rx_msg+1);
                                        if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH;
                                        obj->rx_msg.length = len;
-                                       for(i=0; i< len; i++) {
-                                               obj->rx_msg.data[i]=obj->rx_msg.data[i];
+
+                                       obj->rx_msg.flags=le16_to_cpu(*(uint16_t *)(dev->rx_msg+2));
+                                       obj->rx_msg.id=le32_to_cpu((*(uint32_t *)(dev->rx_msg+4)));
+
+                                       for(ptr=dev->rx_msg+8,i=0; i < len; ptr++,i++) {
+                                               obj->rx_msg.data[i]=*ptr;
                                        }
 
                                        // fill CAN message timestamp
                                        can_filltimestamp(&obj->rx_msg.timestamp);
                                        canque_filter_msg2edges(obj->qends, &obj->rx_msg);
                                }
+                               else
+                                       CANMSG("Destination chip not found\n");
                        }
     }
   }
+       clear_bit(USBCAN_THREAD_RUNNING,&dev->flags);
+
   /* here we go only in case of termination of the thread */
+       if (dev->rx){
+               usb_kill_urb(dev->rx);
+               usb_free_urb(dev->rx);
+       }
+
+  CANMSG ("usbcan thread finished!\n");
+  return 0;
 error:
   /* cleanup the thread, leave */
   CANMSG ("kernel thread terminated!\n");
-  exit_kthread(kthread);
-
-  /* returning from the thread here calls the exit functions */
+  return -ENOMEM;
 }
 
 static int usbcan_probe(struct usb_interface *interface, const struct usb_device_id *id)
 {
-       struct usbcan_usb *dev;
+       struct usbcan_devs *usbdevs=NULL;
        struct usb_host_interface *iface_desc;
        struct usb_endpoint_descriptor *endpoint;
        size_t buffer_size;
-       int i;
+       int i,j,k;
        int retval = -ENOMEM;
 
-       /* allocate memory for our device state and initialize it */
-       dev = (struct usbcan_usb *) can_checked_malloc(sizeof(struct usbcan_usb));
-       if (!dev) {
+       iface_desc = interface->cur_altsetting;
+       if (iface_desc->desc.bNumEndpoints % 2){
+               err("Endpoint count must be even");
+               goto noalloc;
+       }
+
+       usbcan_chip_count = iface_desc->desc.bNumEndpoints / 2;
+
+       usbdevs = (struct usbcan_devs *) can_checked_malloc(sizeof(struct usbcan_devs));
+       if (!usbdevs) {
                err("Out of memory");
                goto error;
        }
+       memset(usbdevs, 0, sizeof(struct usbcan_devs));
 
-       sema_init(&dev->limit_sem, WRITES_IN_FLIGHT);
-       spin_lock_init(&dev->err_lock);
-       init_usb_anchor(&dev->submitted);
+       usbdevs->count=usbcan_chip_count;
 
-//     dev->udev = usb_get_dev(interface_to_usbdev(interface));
-       dev->udev = interface_to_usbdev(interface);
-       dev->interface = interface;
+       usbdevs->devs = (struct usbcan_usb **) can_checked_malloc(usbcan_chip_count * sizeof(struct usbcan_usb *));
+       if (!usbdevs->devs) {
+               err("Out of memory");
+               goto error;
+       }
+       memset(usbdevs->devs, 0, usbcan_chip_count * sizeof(struct usbcan_usb *));
 
-       /* set up the endpoint information */
-       /* use only the first bulk-in and bulk-out endpoints */
-       iface_desc = interface->cur_altsetting;
-       for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
-               endpoint = &iface_desc->endpoint[i].desc;
-
-               if (!dev->bulk_in_endpointAddr &&
-                   usb_endpoint_is_bulk_in(endpoint)) {
-                       /* we found a bulk in endpoint */
-                       buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
-                       dev->bulk_in_size = buffer_size;
-                       dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
-                       dev->bulk_in_buffer = can_checked_malloc(buffer_size);
-                       if (!dev->bulk_in_buffer) {
-                               err("Could not allocate bulk_in_buffer");
-                               goto error;
-                       }
-               }
+       for (j=0;j<usbcan_chip_count;j++){
+               struct usbcan_usb *dev;
+               int epnum=-1,was;
 
-               if (!dev->bulk_out_endpointAddr &&
-                   usb_endpoint_is_bulk_out(endpoint)) {
-                       /* we found a bulk out endpoint */
-                               dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
+               /* 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]) {
+                       err("Out of memory");
+                       goto error;
                }
+               memset(usbdevs->devs[j], 0, sizeof(struct usbcan_usb));
+               dev=usbdevs->devs[j];
+
+               mutex_init(&dev->io_mutex);
+               dev->udev = interface_to_usbdev(interface);
+               dev->interface = interface;
+
+               /* set up the endpoint information */
+               for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+                       endpoint = &iface_desc->endpoint[i].desc;
+
+                       if (epnum==-1){
+                               was=0;
+                               for (k=0;k<j;k++){
+                                       if ((usbdevs->devs[k]->bulk_in_endpointAddr & USB_ENDPOINT_NUMBER_MASK) == (endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK))
+                                               was=1;
+                               }
+                               if (was) continue;
+                               epnum=endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+                       }
 
-               if (!dev->ctl_in_endpointAddr &&
-                   usb_endpoint_xfer_control(endpoint) &&
-                   usb_endpoint_dir_in(endpoint)) {
-                       /* we found a bulk in endpoint */
-                       buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
-                       dev->ctl_in_size = buffer_size;
-                       dev->ctl_in_endpointAddr = endpoint->bEndpointAddress;
-                       dev->ctl_in_buffer = can_checked_malloc(buffer_size);
-                       if (!dev->ctl_in_buffer) {
-                               err("Could not allocate bulk_in_buffer");
-                               goto error;
+                       if (!dev->bulk_in_endpointAddr &&
+                                       usb_endpoint_is_bulk_in(endpoint)) {
+                               if (epnum == (endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)){
+                                       /* we found a bulk in endpoint */
+                                       buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+                                       dev->bulk_in_size = buffer_size;
+                                       dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
+                                       dev->bulk_in_buffer = can_checked_malloc(buffer_size);
+                                       if (!dev->bulk_in_buffer) {
+                                               err("Could not allocate bulk_in_buffer");
+                                               goto error;
+                                       }
+                               }
+                       }
+
+                       if (!dev->bulk_out_endpointAddr &&
+                                       usb_endpoint_is_bulk_out(endpoint)) {
+                               if (epnum == (endpoint->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)){
+                               /* we found a bulk out endpoint */
+                                       dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
+                               }
                        }
-               }
 
-               if (!dev->ctl_out_endpointAddr &&
-                   usb_endpoint_xfer_control(endpoint) &&
-                   usb_endpoint_dir_out(endpoint)) {
-                       /* we found a bulk out endpoint */
-                               dev->ctl_out_endpointAddr = endpoint->bEndpointAddress;
+               }
+               if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
+                       err("Could not find all bulk-in and bulk-out endpoints for chip %d",j);
+                       goto error;
                }
        }
-       if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
-               err("Could not find all bulk-in and bulk-out endpoints");
-               goto error;
-       }
-
        /* save our data pointer in this interface device */
-       usb_set_intfdata(interface, dev);
+       usb_set_intfdata(interface, usbdevs);
 
-       register_usbdev("usbcan",(void *) dev);
+       if (!(usbdevs->candev=register_usbdev("usbcan",(void *) usbdevs, usbcan_register_devs)))
+               goto register_error;
 
        /* let the user know what node this device is now attached to */
-       info("USB Skeleton device now attached");
+       DEBUGMSG("USBCAN device now attached");
        return 0;
 
+register_error:
+       cleanup_usbdev(usbdevs->candev);
 error:
-       usb_put_dev(dev->udev);
-       if (dev->bulk_in_buffer)
-               can_checked_free(dev->bulk_in_buffer);
-       if (dev->ctl_in_buffer)
-               can_checked_free(dev->ctl_in_buffer);
-       if (dev->candev){
-               dev->candev->sysdevptr.anydev=NULL;
-               cleanup_usbdev(dev->candev);
+       if (usbdevs){
+               if (usbdevs->devs){
+                       if (usbdevs->devs[0]){
+                               usb_put_dev(usbdevs->devs[0]->udev);
+                       }
+                       for (j=0;j<usbdevs->count;j++){
+                               if (!usbdevs->devs[j])  continue;
+
+                               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]);
+                       }
+                       can_checked_free(usbdevs->devs);
+               }
+               can_checked_free(usbdevs);
        }
-       can_checked_free(dev);
+noalloc:
        return retval;
 }
 
 // Physically disconnected device
 static void usbcan_disconnect(struct usb_interface *interface)
 {
-       struct usbcan_usb *dev;
-       int minor = interface->minor;
-
-       dev = usb_get_intfdata(interface);
+       struct usbcan_devs *usbdevs;
+       int j;
+       usbdevs = usb_get_intfdata(interface);
+       if (usbdevs==NULL){
+               CANMSG("USBCAN device seems to be removed\n");
+               return;
+       }
        usb_set_intfdata(interface, NULL);
 
-       /* prevent more I/O from starting */
-       mutex_lock(&dev->io_mutex);
-       dev->interface = NULL;
-       mutex_unlock(&dev->io_mutex);
-
-       //usb_kill_anchored_urbs(&dev->submitted);
-
-       usb_put_dev(dev->udev);
-       if (dev->bulk_in_buffer)
-               can_checked_free(dev->bulk_in_buffer);
-       if (dev->ctl_in_buffer)
-               can_checked_free(dev->ctl_in_buffer);
-       if (dev->candev){
-               dev->candev->sysdevptr.anydev=NULL;
-               cleanup_usbdev(dev->candev);
+       if (usbdevs->devs){
+               usb_put_dev((*usbdevs->devs)->udev);
+       }
+       cleanup_usbdev(usbdevs->candev);
+       if (usbdevs->devs){
+               for (j=0;j<usbdevs->count;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);
+
+                       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;
+               }
+               can_checked_free(usbdevs->devs);
        }
-       can_checked_free(dev);
+       can_checked_free(usbdevs);
 
-       info("USB Skeleton now disconnected");
+       DEBUGMSG("USBCAN now disconnected");
 }
 
 int usbcan_init(void){