]> rtime.felk.cvut.cz Git - lincan.git/commitdiff
Each (future) canchip associated to different usb endpoint, instead of whole device...
authorJan Kriz <krizj1@fel.cvut.cz>
Sat, 26 Jul 2008 22:40:29 +0000 (00:40 +0200)
committerppisa <pisa@cmp.felk.cvut.cz>
Sun, 23 Nov 2008 23:25:20 +0000 (00:25 +0100)
lincan/include/main.h
lincan/include/usbcan.h
lincan/src/main.c
lincan/src/usbcan.c

index 296ee2df3919a8a974af24206f03121f811e889d..f360dcf5b1539f69308a65e37ebde60f341a4808 100644 (file)
@@ -513,5 +513,5 @@ void can_filltimestamp(canmsg_tstamp_t *ptimestamp)
 extern int can_rtl_priority;
 #endif /*CAN_WITH_RTL*/
 
-extern struct candevice_t* register_usbdev(const char *hwname,void *anydev);
+extern struct candevice_t* register_usbdev(const char *hwname,void *devdata,void (*chipdataregfnc)(struct canchip_t *chip,void *data));
 extern void cleanup_usbdev(struct candevice_t *dev);
index b01a6275d0d6a953a9b3f7049462f55efa4d135b..5ddbb12c8d86f24451b32c1914eb8efb42c6c1d5 100644 (file)
@@ -119,7 +119,7 @@ struct usbcan_message {
        struct urb      *u;
        u8      msg[16];
        spinlock_t              acc;            /* access lock */
-       long    flags;
+       volatile long   flags;
 };
 
 #define USBCAN_MESSAGE_FREE (1)
@@ -136,19 +136,10 @@ struct usbcan_message {
 struct usbcan_usb {
        struct usb_device       *udev;                  /* the usb device for this device */
        struct usb_interface    *interface;             /* the interface for this device */
-       struct semaphore        limit_sem;              /* limiting the number of writes in progress */
-       struct usb_anchor       submitted;              /* in case we need to retract our submissions */
        unsigned char           *bulk_in_buffer;        /* the buffer to receive data */
-       unsigned char           *ctl_in_buffer; /* the buffer to receive data */
        size_t                  bulk_in_size;           /* the size of the receive buffer */
-       size_t                  ctl_in_size;            /* the size of the receive buffer */
-       u8                      ctl_in_endpointAddr;    /* the address of the bulk in endpoint */
-       u8                      ctl_out_endpointAddr;   /* the address of the bulk in endpoint */
        u8                      bulk_in_endpointAddr;   /* the address of the bulk in endpoint */
        u8                      bulk_out_endpointAddr;  /* the address of the bulk out endpoint */
-       int                     errors;                 /* the last request tanked */
-       int                     open_count;             /* count the number of openers */
-       spinlock_t              err_lock;               /* lock for errors */
        struct mutex            io_mutex;               /* synchronize I/O with disconnect */
        struct urb              *rx;
        struct urb              *tx;
@@ -157,15 +148,15 @@ struct usbcan_usb {
 
        struct task_struct *comthread;                      /* usb communication kernel thread  */
 
-
-       struct candevice_t *candev;
-       long flags;
+       struct canchip_t *chip;
+       volatile long flags;
 };
 
-#define USBCAN_DATA_READ               (1)
-#define USBCAN_TERMINATE               (2)
-#define USBCAN_ERROR                           (3)
-#define USBCAN_TX_PENDING              (4)
+#define USBCAN_DATA_READ                       (1)
+#define USBCAN_TERMINATE                       (2)
+#define USBCAN_ERROR                                   (3)
+#define USBCAN_TX_PENDING                      (4)
+#define USBCAN_THREAD_RUNNING  (5)
 
 #define USBCAN_VENDOR_BAUD_RATE_SET    (1)
 #define USBCAN_VENDOR_BAUD_RATE_STATUS (2)
@@ -176,5 +167,11 @@ struct usbcan_usb {
 #define USBCAN_VENDOR_EXT_MASK_SET     (7)
 #define USBCAN_VENDOR_EXT_MASK_STATUS  (8)
 
+struct usbcan_devs {
+       struct usbcan_usb **devs;
+       int     count;
+       struct candevice_t *candev;
+};
+
 
 #endif /*USBCAN_H*/
index dbedd0fcbacc2b2c69876a88e9dafe9aa6d50d83..b8edf46f5c37a3b7f59f1f91f36f5862bf1a645b 100644 (file)
@@ -417,7 +417,7 @@ int init_module(void)
 
 
 
-struct candevice_t* register_usbdev(const char *hwname,void *anydev){
+struct candevice_t* register_usbdev(const char *hwname,void *devdata,void (*chipdataregfnc)(struct canchip_t *ch,void *data)){
        int i=0, j, board=0;
        struct candevice_t *candev;
        struct canchip_t *chip;
@@ -450,7 +450,7 @@ struct candevice_t* register_usbdev(const char *hwname,void *anydev){
        candev=hardware_p->candevice[board];
 
        /* Adding link to usb device structure into can device */
-       candev->sysdevptr.anydev=anydev;
+       candev->sysdevptr.anydev=devdata;
 
        if (candev->hwspecops->request_io(candev))
                goto request_io_error;
@@ -463,6 +463,8 @@ struct candevice_t* register_usbdev(const char *hwname,void *anydev){
                if((chip=candev->chip[j])==NULL)
                        continue;
 
+               chipdataregfnc(chip,devdata);
+
                if(chip->chipspecops->attach_to_chip(chip)<0) {
                        CANMSG("Initial attach to the chip HW failed\n");
                        goto interrupt_error;
index b35637342d3226967ce2710f7d31a177bedcaa27..f29e549b496cc87dd28891a23f0a0e0aad0041d4 100644 (file)
@@ -15,6 +15,8 @@
 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) },
@@ -45,19 +47,14 @@ static struct usb_driver usbcan_driver = {
  */
 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;
 
-       if (!dev){
+       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;
        }
 
-       /* start kernel thread */
-       dev->comthread=can_kthread_run(usbcan_read_kthread, (void *)dev, "usbcan");
-
-       /* Adding link to can device into usbcan_usb struct */
-       ((struct usbcan_usb*)candev->sysdevptr.anydev)->candev=candev;
        return 0;
 }
 
@@ -75,13 +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);
-       if (!dev)
-               return 0;
-
-       /* terminate the kernel thread */
-       can_kthread_stop(dev->comthread);
-
        return 0;
 }
 
@@ -119,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;
@@ -144,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;
 }
@@ -271,7 +261,7 @@ 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];
 
@@ -282,7 +272,7 @@ int usbcan_extended_mask(struct canchip_t *chip, unsigned long code, unsigned  l
        *(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,
                cpu_to_le16(0), cpu_to_le16(chip->chip_idx),
@@ -292,7 +282,7 @@ int usbcan_extended_mask(struct canchip_t *chip, unsigned long code, unsigned  l
                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,
                cpu_to_le16(0), cpu_to_le16(chip->chip_idx),
@@ -327,7 +317,7 @@ 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];
 
@@ -340,7 +330,7 @@ int usbcan_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw,
        *(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,
                cpu_to_le16(0), cpu_to_le16(chip->chip_idx),
@@ -350,7 +340,7 @@ int usbcan_baud_rate(struct canchip_t *chip, int rate, int clock, int sjw,
                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,
                cpu_to_le16(0), cpu_to_le16(chip->chip_idx),
@@ -398,7 +388,7 @@ 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;
@@ -447,7 +437,7 @@ 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;
+       struct usbcan_usb *dev=(struct usbcan_usb*)chip->chip_data;
        int len,retval;
 
        if (!dev)
@@ -498,7 +488,7 @@ int usbcan_send_msg(struct canchip_t *chip, struct msgobj_t *obj,
  */
 int usbcan_check_tx_stat(struct canchip_t *chip)
 {
-       struct usbcan_usb *dev=(struct usbcan_usb*)chip->hostdevice->sysdevptr.anydev;
+       struct usbcan_usb *dev=(struct usbcan_usb*)chip->chip_data;
        if (!dev)
                return 0;
        if (test_bit(USBCAN_TX_PENDING,&dev->flags))
@@ -519,22 +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,
        cpu_to_le16(value), cpu_to_le16(chip->chip_idx),
-       dev->ctl_in_buffer, dev->ctl_in_size,
+       &buf, 16,
        10000);
 
        if (retval==1){
-               if(dev->ctl_in_buffer[0]==1)
+               if(buf[0]==1)
                        return 0;
        }
        return -ENODEV;
@@ -550,21 +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,
        cpu_to_le16(0), cpu_to_le16(chip->chip_idx),
-       dev->ctl_in_buffer, dev->ctl_in_size,
+       &buf, 16,
        10000);
 
        if (retval==1){
-               if(dev->ctl_in_buffer[0]==1)
+               if(buf[0]==1)
                        return 0;
        }
        return -ENODEV;
@@ -581,26 +573,25 @@ int usbcan_start_chip(struct canchip_t *chip)
  */
 int usbcan_chip_queue_status(struct canchip_t *chip)
 {
-       int retval,i;
-       struct usbcan_usb *dev=(struct usbcan_usb*)chip->hostdevice->sysdevptr.anydev;
+       int retval;
+       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,
        cpu_to_le16(0), cpu_to_le16(chip->chip_idx),
-       dev->ctl_in_buffer, dev->ctl_in_size,
+       &buf, 16,
        10000);
 
-       for (i=0;i<dev->ctl_in_size;i++)
-               CANMSG("Buffer content: %d\n",dev->ctl_in_buffer[i]);
        if (retval==1){
-               CANMSG("Chip_queue_status: %d\n",dev->ctl_in_buffer[0]);
-               if(dev->ctl_in_buffer[0]==1)
+               CANMSG("Chip_queue_status: %d\n",buf[0]);
+               if(buf[0]==1)
                        return 0;
-               if(dev->ctl_in_buffer[0]==0)
+               if(buf[0]==0)
                        return 1;
        }
        CANMSG("Chip_queue_status error: %d\n",retval);
@@ -617,26 +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,
        cpu_to_le16(0), cpu_to_le16(chip->chip_idx),
-       dev->ctl_in_buffer, dev->ctl_in_size,
+       &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
@@ -646,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;
 }
 
@@ -658,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;
 }
 
@@ -1035,12 +1060,16 @@ 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);
                CANMSG("Message received\n");
-               wake_up_process(dev->comthread);
+               if (test_bit(USBCAN_THREAD_RUNNING,&dev->flags))
+                       wake_up_process(dev->comthread);
                return;
        case -ECONNRESET:
        case -ENOENT:
@@ -1048,7 +1077,6 @@ 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_process(dev->comthread);
                return;
        default:
 //             CANMSG("%s - nonzero urb status received: %d\n", __FUNCTION__, urb->status);
@@ -1057,16 +1085,17 @@ static void usbcan_rcv(struct urb *urb)
 
        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_process(dev->comthread);
+               if (test_bit(USBCAN_THREAD_RUNNING,&dev->flags))
+                       wake_up_process(dev->comthread);
        }
 }
 
 int usbcan_read_kthread(void *data)
 {
-       int retval;
+       int retval=0;
        struct usbcan_usb *dev=(struct usbcan_usb *)data;
        struct msgobj_t *obj;
 
@@ -1084,23 +1113,24 @@ int usbcan_read_kthread(void *data)
                         &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(;;)
   {
-               if (!can_kthread_should_stop()){
-                   retval=usb_submit_urb(dev->rx, GFP_KERNEL);
-                   if (retval){
-                       CANMSG("URB error %d\n",retval);
-                       break;
-                   }
-
-
-                   /* fall asleep */
-                   usbcan_sleep_thread(dev);
+               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 */
+               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 (can_kthread_should_stop())
@@ -1109,23 +1139,18 @@ int usbcan_read_kthread(void *data)
                        break;
                }
 
-               if (test_bit(USBCAN_ERROR,&dev->flags)){
-                       CANMSG("URB error %d\n",retval);
-                       clear_bit(USBCAN_ERROR,&dev->flags);
-               }
-
                { /* Normal work to do */
                        if (test_bit(USBCAN_DATA_READ,&dev->flags)){
                                int i, len;
                                clear_bit(USBCAN_DATA_READ,&dev->flags);
                                CANMSG("Thread got received message\n");
 
-                               if ((dev->candev->chip[dev->rx_msg[0]])&&
-                                       (dev->candev->chip[dev->rx_msg[0]]->flags & CHIP_CONFIGURED)
+                               if ((dev->chip)&&
+                                       (dev->chip->flags & CHIP_CONFIGURED)
                                ){
                                        u8 *ptr;
 
-                                       obj=dev->candev->chip[dev->rx_msg[0]]->msgobj[0];
+                                       obj=dev->chip->msgobj[0];
 
                                        len=*(uint8_t *)(dev->rx_msg+1);
                                        if(len > CAN_MSG_LENGTH) len = CAN_MSG_LENGTH;
@@ -1147,138 +1172,189 @@ int usbcan_read_kthread(void *data)
                        }
     }
   }
+       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");
   return -ENOMEM;
-//   exit_kthread(kthread);
-
-  /* returning from the thread here calls the exit functions */
 }
 
 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(dev, 0, sizeof(struct usbcan_usb));
+       memset(usbdevs, 0, sizeof(struct usbcan_devs));
 
-       sema_init(&dev->limit_sem, WRITES_IN_FLIGHT);
-       mutex_init(&dev->io_mutex);
-       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->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
-               err("Could not find all bulk-in and bulk-out endpoints");
-               goto error;
-       }
-       dev->ctl_in_endpointAddr=0;
-       dev->ctl_in_size=16;
-       dev->ctl_in_buffer = can_checked_malloc(dev->ctl_in_size);
-       dev->ctl_out_endpointAddr=0;
+                       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->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
+                       err("Could not find all bulk-in and bulk-out endpoints for chip %d",j);
+                       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);
-       if (!dev)
+       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->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(usbdevs);
 
-       if (dev->bulk_in_buffer)
-               can_checked_free(dev->bulk_in_buffer);
-       if (dev->ctl_in_buffer)
-               can_checked_free(dev->ctl_in_buffer);
-
-       can_checked_free(dev);
-
-       info("USB Skeleton now disconnected");
+       DEBUGMSG("USBCAN now disconnected");
 }
 
 int usbcan_init(void){