]> rtime.felk.cvut.cz Git - lincan.git/commitdiff
Unoptimized usb extension, adds proc and devfs entry removing function, changed proc...
authorJan Kriz <krizj1@fel.cvut.cz>
Tue, 15 Jul 2008 12:24:20 +0000 (14:24 +0200)
committerppisa <pisa@cmp.felk.cvut.cz>
Sun, 23 Nov 2008 23:12:54 +0000 (00:12 +0100)
lincan/include/proc.h
lincan/include/setup.h
lincan/include/usbcan.h
lincan/src/main.c
lincan/src/proc.c
lincan/src/setup.c
lincan/src/usbcan.c

index a89f45a6fb628807f68c9b848cd0bbaa61b418e2..504b58a1775e38902bd2fc80f5335eab8ad86d5f 100644 (file)
@@ -11,7 +11,9 @@
 #include "./constants.h"
 
 int can_init_procdir(void);
+int can_init_procentry(int board);
 int can_delete_procdir(void);
+int can_delete_procentry(struct candevice_t *candev);
 
 struct canproc_t {
        struct proc_dir_entry *can_proc_entry;
index d35a8b1e51192a7d0fd270749478a7479a79cfb8..d07e3fda26637b14fd6f43c5390b688e7a389559 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 int init_hw_struct(void);
+int init_new_hw_struct(int devnr);
 int list_hw(void);
 void *can_checked_malloc(size_t size);
 int can_checked_free(void *address_p);
index 35ee4f1055218b5deaa54b9885c64eb7291a00ee..94fa0fc42c58e9cb5ee59a70aa408819a6337eea 100644 (file)
@@ -5,6 +5,16 @@
  * Version lincan-0.3  17 Jul 2008
  */
 
+#ifndef USBCAN_H
+#define USBCAN_H
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/kref.h>
+#include <asm/uaccess.h>
+#include <linux/usb.h>
+
 int usbcan_request_io(struct candevice_t *candev);
 int usbcan_release_io(struct candevice_t *candev);
 int usbcan_reset(struct candevice_t *candev);
@@ -27,4 +37,7 @@ int usbcan_send_msg(struct canchip_t *chip, struct msgobj_t *obj,
 int usbcan_fill_chipspecops(struct canchip_t *chip);
 int usbcan_irq_handler(int irq, struct canchip_t *chip);
 
+int usbcan_init(void);
+void usbcan_exit(void);
 
+#endif /*USBCAN_H*/
\ No newline at end of file
index c0c6d0085d2a9a69af16352fdc86225a024606b5..dd2319a876618a68471a83e5a9541bbc5d908676 100644 (file)
 #include "../include/can_iortl.h"
 #endif /*CAN_WITH_RTL*/
 
+#if defined(CONFIG_OC_LINCAN_CARD_usbcan)
+       #include "../include/usbcan.h"
+#endif
+
 can_spinlock_t canuser_manipulation_lock;
 
 int major=CAN_MAJOR;
@@ -362,6 +366,15 @@ int init_module(void)
                }
         }
 #endif
+
+#if defined(CONFIG_OC_LINCAN_CARD_usbcan)
+       res = usbcan_init();
+       if (res){
+               CANMSG("usb_register for usbcan failed. Error number %d.\n", res);
+               return -ENODEV;
+       }
+#endif
+
        return 0;
 
 #ifdef CONFIG_PROC_FS
@@ -400,12 +413,233 @@ int init_module(void)
                return -ENODEV;
 }
 
+
+
+
+
+struct candevice_t* register_usbdev(const char *hwname,void *anydev){
+       int i=0, j, board;
+       struct candevice_t *candev;
+       struct canchip_t *chip;
+       struct boardtype_t *brp;
+
+       while ( (hw[board] != NULL) && (board < MAX_HW_CARDS) )
+               board++;
+       brp = boardtype_find(hwname);
+       if(!brp) {
+               CANMSG("Sorry, hardware \"%s\" is currently not supported.\n",hw[board]);
+               return NULL;
+       }
+       if (board==MAX_HW_CARDS){
+                       CANMSG("Device \"%s\" could not be registered due to internal limits.\n",hw[board]);
+                       return NULL;
+       }
+       hw[board]=brp->boardtype;
+
+       if (init_new_hw_struct(board))
+               return NULL;
+
+       #ifdef CAN_DEBUG
+               list_hw();
+       #endif
+
+       candev=hardware_p->candevice[board];
+
+       /* Adding link to usb device structure into can device */
+       candev->sysdevptr.anydev=anydev;
+
+       if (candev->hwspecops->request_io(candev))
+               goto request_io_error;
+       candev->flags|=CANDEV_IO_RESERVED;
+
+       if (candev->hwspecops->reset(candev))
+               goto reset_error;
+
+       for(j=0; j<candev->nr_all_chips; j++) {
+               if((chip=candev->chip[j])==NULL)
+                       continue;
+
+               if(chip->chipspecops->attach_to_chip(chip)<0) {
+                       CANMSG("Initial attach to the chip HW failed\n");
+                       goto interrupt_error;
+               }
+
+               chip->flags |= CHIP_ATTACHED;
+
+               if(can_chip_setup_irq(chip)<0) {
+                       CANMSG("Error to setup chip IRQ\n");
+                       goto interrupt_error;
+               }
+       }
+
+       if (candev->flags & CANDEV_PROGRAMMABLE_IRQ)
+               if (candev->hwspecops->program_irq(candev)){
+                       CANMSG("Error to program board interrupt\n");
+                       goto interrupt_error;
+               }
+
+#ifdef CONFIG_PROC_FS
+       if (can_init_procentry(board))
+               goto proc_error;
+#endif
+
+#if defined(CONFIG_DEVFS_FS) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
+       {
+               #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,0))
+               char dev_name[32];
+               #else
+               struct class_device *this_dev;
+               #endif
+               int dev_minor;
+               for(i=0;i<MAX_TOT_MSGOBJS;i++) {
+                       if(!objects_p[i]) continue;
+                       if(objects_p[i]->hostchip->hostdevice != candev) continue;
+
+                       dev_minor=objects_p[i]->minor;
+                       #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,0))
+                       sprintf (dev_name, "can%d", dev_minor);
+                       devfs_handles[i]=devfs_register(NULL, dev_name,
+                       DEVFS_FL_DEFAULT, major, dev_minor,
+                       S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
+                       &can_fops, (void*)objects_p[i]);
+                       #else
+                       #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,14))
+                       this_dev=class_device_create(can_class, MKDEV(major, dev_minor), NULL,  "can%d", dev_minor);
+                       #elif  LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25) /* >= 2.6.15 */
+                       this_dev=class_device_create(can_class, NULL, MKDEV(major, dev_minor), NULL,  "can%d", dev_minor);
+                       #else /* >= 2.6.26 */
+                       this_dev=device_create_drvdata(can_class, NULL, MKDEV(major, dev_minor), objects_p[i],  "can%d", dev_minor);
+                       #endif /* >= 2.6.26 */
+                       if(IS_ERR(this_dev)){
+                               CANMSG("problem to create device \"can%d\" in the class \"can\"\n", dev_minor);
+                     #if  LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25)
+                       }else{
+                               /*this_dev->class_data=objects_p[i];*/
+                               class_set_devdata(this_dev,objects_p[i]);
+                     #endif /* <= 2.6.25 */
+                       }
+                       #ifdef CONFIG_DEVFS_FS
+                       devfs_mk_cdev(MKDEV(major, dev_minor), S_IFCHR | S_IRUGO | S_IWUGO, "can%d", dev_minor);
+                       #endif
+                       #endif
+               }
+       }
+#endif
+       return candev;
+
+#ifdef CONFIG_PROC_FS
+       proc_error: ;
+               CANMSG("Error registering /proc entry.\n");
+               goto memory_error;
+#endif
+
+       interrupt_error: ;
+               goto memory_error;
+
+       reset_error: ;
+               CANMSG("Error resetting device.\n");
+               goto memory_error;
+
+       request_io_error: ;
+               CANMSG("Error to request IO resources for device.\n");
+               goto memory_error;
+
+       memory_error: ;
+
+               #ifdef CAN_WITH_RTL
+       rtldev_error:
+               #endif /*CAN_WITH_RTL*/
+
+//     register_error:
+               if ( can_del_mem_list() )
+                       CANMSG("Error deallocating memory\n");
+
+               return NULL;
+}
+
+
+
+
+
+
+
+void cleanup_usbdev(struct candevice_t *dev)
+{
+       int i=0;
+       int dev_minor;
+
+       if (!dev)
+               return;
+
+#ifdef CONFIG_PROC_FS
+       if (can_delete_procentry(dev))
+               CANMSG("Error unregistering /proc/can entry.\n");
+#endif
+
+#if defined(CONFIG_DEVFS_FS) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
+       for(i=0;i<MAX_TOT_MSGOBJS;i++) {
+               if(!objects_p[i]) continue;
+               if(objects_p[i]->hostchip->hostdevice != dev) continue;
+               #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,0))
+               if(devfs_handles[i])
+                       devfs_unregister(devfs_handles[i]);
+               #else
+               dev_minor=objects_p[i]->minor;
+               if(dev_minor>=0){
+                       #ifdef CONFIG_DEVFS_FS
+                       devfs_remove("can%d", dev_minor);
+                       #endif
+                       #if  LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,25)
+                       class_device_destroy(can_class, MKDEV(major, dev_minor));
+                       #else /* >= 2.6.26 */
+                       device_destroy(can_class, MKDEV(major, dev_minor));
+                       #endif /* >= 2.6.26 */
+               }
+               #endif
+       }
+#endif
+
+       for(i=0;i<MAX_TOT_MSGOBJS;i++) {
+               if(!objects_p[i]) continue;
+               if(objects_p[i]->hostchip->hostdevice != dev) continue;
+               //canqueue_ends_done_chip(objects_p[i]->qends);
+               //can_checked_free(objects_p[i]->qends);
+               //can_checked_free(objects_p[i]);
+               objects_p[i]=NULL;
+       }
+
+       for(i=0;i<MAX_TOT_CHIPS;i++){
+               if(!chips_p[i]) continue;
+               if(chips_p[i]->hostdevice != dev) continue;
+               //can_checked_free(chips_p[i]->chipspecops);
+               //can_checked_free(chips_p[i]);
+               chips_p[i]=NULL;
+       }
+
+       hardware_p->candevice[dev->candev_idx]=NULL;
+       hardware_p->nr_boards--;
+       //kfree(hw[dev->candev_idx]);
+       hw[dev->candev_idx]=NULL;
+       //can_checked_free(dev->hwspecops);
+       //can_checked_free(dev);
+
+       candevice_done(dev);
+       can_checked_free(dev);
+}
+
+
+
+
 void cleanup_module(void)
 {
 #if defined(CONFIG_DEVFS_FS) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
        int i=0;
 #endif
 
+#if defined(CONFIG_OC_LINCAN_CARD_usbcan)
+       usbcan_exit();
+#endif
+
 #ifdef CONFIG_PROC_FS
        if (can_delete_procdir())
                CANMSG("Error unregistering /proc/can entry.\n");
index 4fb2343bf18fa43f7af4da87a58c2e749179e07a..e423b92725abca0012a166c2b1315554b03246fd 100644 (file)
 
 #define __NO_VERSION__
 #include <linux/module.h>
+#include <linux/mutex.h>
 
 int add_channel_to_procdir(struct candevice_t *candev);
-int remove_channel_from_procdir(void);
+int remove_channels_from_procdir(void);
+int remove_channel_from_procdir(struct candevice_t *candev);
 int add_object_to_procdir(int chip_nr);
 int remove_object_from_procdir(int chip_nr);
 
@@ -35,6 +37,7 @@ static int cc=0; /* static counter for each CAN chip */
 
 static struct canproc_t can_proc_base;
 static struct canproc_t *base=&can_proc_base;
+DEFINE_MUTEX(proc_mutex);              /* synchronize access to canproc_t array */
 
 /* The following functions are needed only for kernel version 2.2. Kernel
  * version 2.4 already defines them for us.
@@ -155,6 +158,9 @@ int can_init_procdir(void)
 {
        int board;
        struct candevice_t *candev;
+
+       mutex_init(&proc_mutex);
+
        base->can_proc_entry = can_create_proc_entry("can", S_IFDIR | S_IRUGO |
                                        S_IXUGO, CAN_PROC_ROOT);
        if (base->can_proc_entry == NULL)
@@ -168,13 +174,34 @@ int can_init_procdir(void)
        return 0;
 }
 
+/* can_init_procentry registers entry of a new board in CAN directory tree at
+ * the proc system.
+ */
+int can_init_procentry(int board)
+{
+       struct candevice_t *candev;
+       candev=hardware_p->candevice[board];
+       if(candev)
+               return add_channel_to_procdir(candev);
+       return -ENODEV;
+}
+
 /* can_delete_procdir removes the entire CAN tree from the proc system */
 int can_delete_procdir(void)
 {
-       if (remove_channel_from_procdir()) 
+       if (remove_channels_from_procdir())
                return -ENODEV;
        /* name: "can" */
-       if (can_remove_proc_entry(base->can_proc_entry, CAN_PROC_ROOT)) 
+       if (can_remove_proc_entry(base->can_proc_entry, CAN_PROC_ROOT))
+               return -ENODEV;
+
+       return 0;
+}
+
+/* can_delete_procentry removes device entries from CAN tree in the proc system */
+int can_delete_procentry(struct candevice_t *candev)
+{
+       if (remove_channel_from_procdir(candev))
                return -ENODEV;
 
        return 0;
@@ -214,58 +241,108 @@ int add_channel_to_procdir(struct candevice_t *candev)
 {
        int i=0;
 
-       for (i=0; i < candev->nr_all_chips; i++) {
+       mutex_lock(&proc_mutex);
+       for (i=0; i < MAX_TOT_CHIPS; i++){
+               if (!chips_p[i]) continue;
+               if (chips_p[i]->hostdevice != candev) continue;
 
-               base->channel[cc] = (struct channelproc_t *)
+               base->channel[i] = (struct channelproc_t *)
                        can_checked_malloc(sizeof(struct channelproc_t));
-               if (base->channel[cc] == NULL)
+               if (base->channel[i] == NULL){
+                       mutex_unlock(&proc_mutex);
                        return -ENOMEM;
+               }
 
-               sprintf(base->channel[cc]->ch_name, "channel%d",cc);
+               sprintf(base->channel[i]->ch_name, "channel%d",i);
 
-               base->channel[cc]->ch_entry = can_create_proc_entry(
-                                               base->channel[cc]->ch_name,
+               base->channel[i]->ch_entry = can_create_proc_entry(
+                                               base->channel[i]->ch_name,
                                                S_IFDIR | S_IRUGO |S_IXUGO,
                                                base->can_proc_entry);
 
-               if (base->channel[cc]->ch_entry == NULL)
+               if (base->channel[i]->ch_entry == NULL){
+                       mutex_unlock(&proc_mutex);
                        return -ENODEV;
+               }
 
-               add_object_to_procdir(cc);
+               add_object_to_procdir(i);
 
                create_proc_read_entry("chip_info",        /* proc entry name */
                                       0,                  /* protection mask, 0->default */
-                                      base->channel[cc]->ch_entry,  /* parent dir, NULL->/proc */
+                                      base->channel[i]->ch_entry,  /* parent dir, NULL->/proc */
                                       can_chip_procinfo,
-                                      candev->chip[i]);
-
+                                      chips_p[i]);
                cc++;
        }
+       mutex_unlock(&proc_mutex);
 
        return 0;
 }
 
-int remove_channel_from_procdir(void)
+int remove_channels_from_procdir(void)
 {
+       int i=0;
+
+       mutex_lock(&proc_mutex);
+       for (i=0; i < MAX_TOT_CHIPS; i++){
+               if (!chips_p[i]) continue;
 
-       while (cc != 0) {
                cc--;
 
-               if(!base->channel[cc]) continue;
+               if(!base->channel[i]) continue;
 
-               remove_proc_entry("chip_info", base->channel[cc]->ch_entry);
+               remove_proc_entry("chip_info", base->channel[i]->ch_entry);
 
-               if (remove_object_from_procdir(cc))
+               if (remove_object_from_procdir(i)){
+                       mutex_unlock(&proc_mutex);
                        return -ENODEV;
+               }
 
                /* name: base->channel[cc]->ch_name */
-               if (can_remove_proc_entry(base->channel[cc]->ch_entry,
-                                                       base->can_proc_entry))
+               if (can_remove_proc_entry(base->channel[i]->ch_entry,
+                                                       base->can_proc_entry)){
+                       mutex_unlock(&proc_mutex);
                        return -ENODEV;
+               }
 
-               can_checked_free(base->channel[cc]);
-               base->channel[cc] = NULL;
+               can_checked_free(base->channel[i]);
+               base->channel[i] = NULL;
+       }
+       mutex_unlock(&proc_mutex);
+
+       return 0;
+}
+
+int remove_channel_from_procdir(struct candevice_t *candev)
+{
+       int i=0,j=0;
+
+       mutex_lock(&proc_mutex);
+       for (i=0; i < MAX_TOT_CHIPS; i++){
+               if (!chips_p[i]) continue;
+               if (chips_p[i]->hostdevice != candev) continue;
+               if (!base->channel[i]) continue;
+
+               remove_proc_entry("chip_info", base->channel[i]->ch_entry);
+
+               if (remove_object_from_procdir(i)){
+                       mutex_unlock(&proc_mutex);
+                       return -ENODEV;
+               }
+
+               /* name: base->channel[cc]->ch_name */
+               if (can_remove_proc_entry(base->channel[i]->ch_entry,
+                                                       base->can_proc_entry)){
+                       mutex_unlock(&proc_mutex);
+                       return -ENODEV;
+               }
+
+               can_checked_free(base->channel[i]);
+               base->channel[i] = NULL;
+
+               cc--;
        }
+       mutex_unlock(&proc_mutex);
 
        return 0;
 }
index 64c67bef105931e14d77303671d81802b2ddabf3..bd6d59cbbd61992ed99ce57d6c8948c2cf5ea1ee 100644 (file)
@@ -156,6 +156,30 @@ int init_hw_struct(void)
        return 0;
 }
 
+/**
+ * init_new_hw_struct - initializes driver description structures for new hardware
+ *
+ * The function init_new_hw_struct() is used to initialize the hardware structure.
+ *
+ * Return Value: returns negative number in the case of fail
+ */
+int init_new_hw_struct(int devnr)
+{
+       int irq_param_idx=0;
+       int chan_param_idx=0;
+
+       if ( (hw[devnr] != NULL) & (devnr < MAX_HW_CARDS) ) {
+               hardware_p->nr_boards++;
+
+               if (init_device_struct(devnr, &chan_param_idx, &irq_param_idx)) {
+                       CANMSG("Error initializing candevice_t structures.\n");
+                       return -ENODEV;
+               }
+       }
+
+       return 0;
+}
+
 /**
  * init_device_struct - initializes single CAN device/board
  * @card: index into @hardware_p HW description
index aff02d3095df5414ce537d9fe46d3083505b46f5..a66e287f698433b7fe81e6b9c22a3d6f739d088a 100644 (file)
@@ -1133,3 +1133,228 @@ int usbcan_fill_chipspecops(struct canchip_t *chip)
 {
        return 0;
 }
+
+
+
+/* --------------------------------------------------------------------------------------------------- */
+
+
+static void ul_usb1_irq(struct urb *urb)
+{
+       struct usb_ul_usb1 *dev = urb->context;
+       struct ul_usb1_combo devc;
+       int retval;
+
+       CANMSG("Interrupt poll\n");
+
+       switch (urb->status) {
+       case 0:
+               /* success */
+               break;
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               /* this urb is terminated, clean up */
+               CANMSG("%s - urb shutting down with status: %d\n", __FUNCTION__, urb->status);
+               return;
+       default:
+               CANMSG("%s - nonzero urb status received: %d\n", __FUNCTION__, urb->status);
+               goto exit;
+       }
+
+       devc.dev = dev;
+       devc.urb = urb;
+
+       dev->candev->chip[0]->chipspecops->irq_handler(0,dev->candev->chip[0]);
+       CANMSG("Interrupt caught\n");
+
+ exit:
+       retval = usb_submit_urb (urb, GFP_ATOMIC);
+       if (retval)
+               CANMSG("%s - usb_submit_urb failed with result %d\n",
+                    __FUNCTION__, retval);
+}
+
+static void ul_usb1_delete(struct usb_ul_usb1 *dev)
+{
+       usb_put_dev(dev->udev);
+       usb_kill_urb(dev->irq);
+       usb_free_urb(dev->irq);
+       kfree(dev->bulk_in_buffer);
+       kfree(dev->int_in_buffer);
+       if (dev->candev){
+               dev->candev->sysdevptr.anydev=NULL;
+               cleanup_usbdev(dev->candev);
+       }
+       kfree(dev);
+}
+
+static int ul_usb1_probe(struct usb_interface *interface, const struct usb_device_id *id)
+{
+       struct usb_ul_usb1 *dev;
+       struct usb_host_interface *iface_desc;
+       struct usb_endpoint_descriptor *endpoint;
+       struct candevice_t *candev;
+       size_t buffer_size;
+       int i;
+       int retval = -ENOMEM;
+
+       /* allocate memory for our device state and initialize it */
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               err("Out of memory");
+               goto error;
+       }
+       sema_init(&dev->limit_sem, WRITES_IN_FLIGHT);
+       mutex_init(&dev->io_mutex);
+       spin_lock_init(&dev->err_lock);
+       init_usb_anchor(&dev->submitted);
+
+//     dev->udev = usb_get_dev(interface_to_usbdev(interface));
+       dev->udev = interface_to_usbdev(interface);
+       dev->interface = interface;
+
+       /* 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 = kmalloc(buffer_size, GFP_KERNEL);
+                       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)) {
+                       /* we found a bulk out endpoint */
+                               dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
+               }
+
+               if (!dev->int_in_endpointAddr &&
+                   usb_endpoint_is_int_in(endpoint)) {
+                       /* we found an interrupt in endpoint */
+                       buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+                       dev->int_in_size = buffer_size;
+                       dev->int_in_endpointAddr = endpoint->bEndpointAddress;
+                       dev->int_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
+                       dev->int_in_interval = endpoint->bInterval;
+                       if (!dev->int_in_buffer) {
+                               err("Could not allocate int_in_buffer");
+                               goto error;
+                       }
+               }
+       }
+       if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr && dev->int_in_endpointAddr)) {
+               err("Could not find all bulk-in, bulk-out and interrupt endpoints");
+               goto error;
+       }
+
+       /* save our data pointer in this interface device */
+       usb_set_intfdata(interface, dev);
+
+       if (main_init_done==1)
+               register_usbdev("ul_usb1",(void *) dev);
+       else {
+               mutex_lock(&usbdev_reg_mutex);
+               if (main_init_done==1)
+                       register_usbdev("ul_usb1",(void *) dev);
+               else {
+                       for (i=0;i<MAX_HW_CARDS;i++){
+                               if (usbregq[i]==NULL){
+                                       usbregq[i]=(struct usbdev_reg_query *)can_checked_malloc(sizeof(struct usbdev_reg_query));
+                                       if (!usbregq[i]){
+                                               CANMSG("Error allocating usbdev_reg_query");
+                                               mutex_unlock(&usbdev_reg_mutex);
+                                               goto error;
+                                       }
+                                       sprintf (usbregq[i]->hwname,"ul_usb1");
+                                       usbregq[i]->anydev=(void *) dev;
+                                       break;
+                               }
+                       }
+                       if (i==MAX_HW_CARDS){
+                               CANMSG("No free space to register new card");
+                               mutex_unlock(&usbdev_reg_mutex);
+                               goto error;
+                       }
+               }
+               mutex_unlock(&usbdev_reg_mutex);
+       }
+
+       dev->irq = usb_alloc_urb(0, GFP_KERNEL);
+       if (!dev->irq){
+               CANMSG("Error allocating usb urb\n");
+               goto error;
+       }
+       dev->irq->dev = dev->udev;
+       usb_fill_int_urb(dev->irq, dev->udev,
+                        usb_rcvintpipe(dev->udev, dev->int_in_endpointAddr),
+                        dev->int_in_buffer, dev->int_in_size,
+                        ul_usb1_irq, dev, dev->int_in_interval);
+/*     usb_fill_bulk_urb(dev->irq, dev->udev,
+                        usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
+                        dev->int_in_buffer, dev->int_in_size,
+                        ul_usb1_irq, dev);*/
+
+/*     dev->irq->transfer_dma = wacom->data_dma;
+       dev->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;*/
+       retval=usb_submit_urb(dev->irq, GFP_KERNEL);
+       if (retval){
+               CANMSG("INT URB %d\n",retval);
+               return -EIO;
+       }else
+               CANMSG("INT URB SUCCCESS\n");
+
+       /* let the user know what node this device is now attached to */
+       info("USB Skeleton device now attached");
+       return 0;
+
+error:
+               ul_usb1_delete(dev);
+       return retval;
+}
+
+static void ul_usb1_disconnect(struct usb_interface *interface)
+{
+       struct usb_ul_usb1 *dev;
+       int minor = interface->minor;
+
+       dev = usb_get_intfdata(interface);
+       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);
+
+       ul_usb1_delete(dev);
+
+       info("USB Skeleton now disconnected");
+}
+
+static struct usb_driver ul_usb1_driver = {
+       .name =         "ul_usb1-can",
+       .id_table = ul_usb1_table,
+       .probe =        ul_usb1_probe,
+       .disconnect =   ul_usb1_disconnect,
+       .id_table =     ul_usb1_table,
+};
+
+int usbcan_init(void){
+       return usb_register(&ul_usb1_driver);
+}
+
+void usbcan_exit(void){
+       usb_deregister(&ul_usb1_driver);
+}