From dfdc60b200ea4395b79c02964f6aa0f043c1f372 Mon Sep 17 00:00:00 2001 From: Jan Kriz Date: Sun, 27 Jul 2008 00:40:29 +0200 Subject: [PATCH] Each (future) canchip associated to different usb endpoint, instead of whole device to just one endpoint. --- lincan/include/main.h | 2 +- lincan/include/usbcan.h | 31 ++-- lincan/src/main.c | 6 +- lincan/src/usbcan.c | 382 ++++++++++++++++++++++++---------------- 4 files changed, 248 insertions(+), 173 deletions(-) diff --git a/lincan/include/main.h b/lincan/include/main.h index 296ee2d..f360dcf 100644 --- a/lincan/include/main.h +++ b/lincan/include/main.h @@ -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); diff --git a/lincan/include/usbcan.h b/lincan/include/usbcan.h index b01a627..5ddbb12 100644 --- a/lincan/include/usbcan.h +++ b/lincan/include/usbcan.h @@ -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*/ diff --git a/lincan/src/main.c b/lincan/src/main.c index dbedd0f..b8edf46 100644 --- a/lincan/src/main.c +++ b/lincan/src/main.c @@ -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; diff --git a/lincan/src/usbcan.c b/lincan/src/usbcan.c index b356373..f29e549 100644 --- a/lincan/src/usbcan.c +++ b/lincan/src/usbcan.c @@ -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;ictl_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;jbulk_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;kdevs[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;jcount;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;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); + + 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){ -- 2.39.2