From 0f4c88ce2a8b8a25441c97c3ce2279c7353c92ab Mon Sep 17 00:00:00 2001 From: Jan Kriz Date: Tue, 15 Jul 2008 14:24:20 +0200 Subject: [PATCH] Unoptimized usb extension, adds proc and devfs entry removing function, changed proc structures usage (proc.c) --- lincan/include/proc.h | 4 +- lincan/include/setup.h | 1 + lincan/include/usbcan.h | 13 +++ lincan/src/main.c | 222 +++++++++++++++++++++++++++++++++++++++ lincan/src/proc.c | 167 +++++++++++++++++++++-------- lincan/src/setup.c | 68 ++++++++---- lincan/src/usbcan.c | 225 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 632 insertions(+), 68 deletions(-) diff --git a/lincan/include/proc.h b/lincan/include/proc.h index c2a3c96..504b58a 100644 --- a/lincan/include/proc.h +++ b/lincan/include/proc.h @@ -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; @@ -31,4 +33,4 @@ struct objectproc_t { char lnk_name[20]; char lnk_dev[20]; struct proc_dir_entry *lnk; -}; +}; diff --git a/lincan/include/setup.h b/lincan/include/setup.h index d35a8b1..d07e3fd 100644 --- a/lincan/include/setup.h +++ b/lincan/include/setup.h @@ -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); diff --git a/lincan/include/usbcan.h b/lincan/include/usbcan.h index 35ee4f1..94fa0fc 100644 --- a/lincan/include/usbcan.h +++ b/lincan/include/usbcan.h @@ -5,6 +5,16 @@ * Version lincan-0.3 17 Jul 2008 */ +#ifndef USBCAN_H +#define USBCAN_H + +#include +#include +#include +#include +#include +#include + 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 diff --git a/lincan/src/main.c b/lincan/src/main.c index 319a09e..115354e 100644 --- a/lincan/src/main.c +++ b/lincan/src/main.c @@ -74,6 +74,10 @@ #include "../include/can_iortl.h" #endif /*CAN_WITH_RTL*/ +#if defined(CONFIG_OC_LINCAN_CARD_ul_usb1) + #include "../include/usbcan.h" +#endif + can_spinlock_t canuser_manipulation_lock; int major=CAN_MAJOR; @@ -351,6 +355,15 @@ int init_module(void) } } #endif + +#if defined(CONFIG_OC_LINCAN_CARD_ul_usb1) + 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 @@ -396,10 +409,219 @@ 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]; + + 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; jnr_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;ihostchip->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); + #else /* >= 2.6.15 */ + this_dev=class_device_create(can_class, NULL, MKDEV(major, dev_minor), NULL, "can%d", dev_minor); + #endif /* >= 2.6.15 */ + if(IS_ERR(this_dev)){ + CANMSG("problem to create device \"can%d\" in the class \"can\"\n", dev_minor); + }else{ + /*this_dev->class_data=objects_p[i];*/ + class_set_devdata(this_dev,objects_p[i]); + } + #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; + +#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;ihostchip->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 + class_device_destroy(can_class, MKDEV(major, dev_minor)); + } + #endif + } +#endif + + for(i=0;ihostchip->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;ihostdevice != 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); +// if ( can_del_mem_list() ) +// CANMSG("Error deallocating memory\n"); + +} + + + + void cleanup_module(void) { int res=0,i=0; +#if defined(CONFIG_OC_LINCAN_CARD_ul_usb1) + ul_usb1_exit(); +#endif + #ifdef CONFIG_PROC_FS if (can_delete_procdir()) CANMSG("Error unregistering /proc/can entry.\n"); diff --git a/lincan/src/proc.c b/lincan/src/proc.c index 3957e5f..a73f71e 100644 --- a/lincan/src/proc.c +++ b/lincan/src/proc.c @@ -5,7 +5,7 @@ * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. * Version lincan-0.3 17 Jun 2004 - */ + */ #include "../include/can.h" #include "../include/can_sysdep.h" @@ -15,9 +15,11 @@ #define __NO_VERSION__ #include +#include 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); @@ -29,6 +31,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. @@ -48,14 +51,14 @@ static struct proc_dir_entry * can_create_proc_entry(const char *name, mode_t mo struct proc_dir_entry *new_entry = NULL; char *namestore; int namelen; - + if(!name || !parent) return NULL; namelen=strlen(name); if(!namelen) return NULL; - new_entry = (struct proc_dir_entry *) + new_entry = (struct proc_dir_entry *) can_checked_malloc(sizeof(struct proc_dir_entry)+namelen+1); if (new_entry == NULL) @@ -94,7 +97,7 @@ static int can_remove_proc_entry(struct proc_dir_entry *del, struct proc_dir_ent static int can_proc_readlink(struct proc_dir_entry *ent, char *page) { char *link_dest = (char*)ent->data; - + strcpy(page, link_dest); return strlen(link_dest); } @@ -106,8 +109,8 @@ static inline struct proc_dir_entry *can_proc_symlink(const char *name, struct proc_dir_entry *parent, const char *dest) { struct proc_dir_entry *entry; - - + + entry = can_create_proc_entry(name, S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, parent); if (entry == NULL) return NULL; @@ -149,7 +152,10 @@ int can_init_procdir(void) { int board; struct candevice_t *candev; - base->can_proc_entry = can_create_proc_entry("can", S_IFDIR | S_IRUGO | + + mutex_init(&proc_mutex); + + base->can_proc_entry = can_create_proc_entry("can", S_IFDIR | S_IRUGO | S_IXUGO, &proc_root); if (base->can_proc_entry == NULL) return -ENODEV; @@ -157,24 +163,45 @@ int can_init_procdir(void) for (board=0; boardnr_boards; board++) { candev=hardware_p->candevice[board]; if(candev) add_channel_to_procdir(candev); - } + } 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, &proc_root)) + if (can_remove_proc_entry(base->can_proc_entry, &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; } -static int can_chip_procinfo(char *buf, char **start, off_t offset, +static int can_chip_procinfo(char *buf, char **start, off_t offset, int count, int *eof, void *data) { struct canchip_t *chip=data; @@ -207,58 +234,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); - - base->channel[cc]->ch_entry = can_create_proc_entry( - base->channel[cc]->ch_name, + sprintf(base->channel[i]->ch_name, "channel%d",i); + + 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) { - - while (cc != 0) { + int i=0; + + mutex_lock(&proc_mutex); + for (i=0; i < MAX_TOT_CHIPS; i++){ + if (!chips_p[i]) continue; + cc--; - - if(!base->channel[cc]) continue; - - remove_proc_entry("chip_info", base->channel[cc]->ch_entry); - - if (remove_object_from_procdir(cc)) - return -ENODEV; - + + 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[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; } @@ -279,7 +356,7 @@ int add_object_to_procdir(int chip_nr) sprintf(base->channel[chip_nr]->object[i]->obj_name,"object%d",i); sprintf(base->channel[chip_nr]->object[i]->lnk_name,"dev"); - + base->channel[chip_nr]->object[i]->obj_entry = can_create_proc_entry( base->channel[chip_nr]->object[i]->obj_name, S_IFDIR | S_IRUGO | S_IXUGO, @@ -299,7 +376,7 @@ int add_object_to_procdir(int chip_nr) } return 0; -} +} int remove_object_from_procdir(int chip_nr) { @@ -309,10 +386,10 @@ int remove_object_from_procdir(int chip_nr) for (i=0; ichannel[chip_nr]->object[i]) continue; - + /* name: base->channel[chip_nr]->object[i]->lnk_name */ if (can_remove_proc_entry( base->channel[chip_nr]->object[i]->lnk, - base->channel[chip_nr]->object[i]->obj_entry)) + base->channel[chip_nr]->object[i]->obj_entry)) return -ENODEV; /* name: base->channel[chip_nr]->object[i]->obj_name */ if (can_remove_proc_entry( diff --git a/lincan/src/setup.c b/lincan/src/setup.c index ac83789..c966584 100644 --- a/lincan/src/setup.c +++ b/lincan/src/setup.c @@ -5,7 +5,7 @@ * email:pisa@cmp.felk.cvut.cz * This software is released under the GPL-License. * Version lincan-0.3 17 Jun 2004 - */ + */ #include "../include/can.h" #include "../include/can_sysdep.h" @@ -34,7 +34,7 @@ int can_base_addr_fixup(struct candevice_t *candev, unsigned long new_base) { unsigned long offs; int i, j; - + offs=new_base-candev->dev_base_addr; candev->dev_base_addr=new_base; for(i=0;inr_all_chips;i++){ @@ -47,7 +47,7 @@ int can_base_addr_fixup(struct candevice_t *candev, unsigned long new_base) /** * can_check_dev_taken - checks if bus device description is already taken by driver - * @anydev: pointer to bus specific Linux device description + * @anydev: pointer to bus specific Linux device description * * Returns: Returns 1 if device is already used by LinCAN driver, 0 otherwise. */ @@ -64,7 +64,7 @@ int can_check_dev_taken(void *anydev) if(boarddev == anydev) return 1; } - + return 0; } @@ -80,7 +80,7 @@ int register_obj_struct(struct msgobj_t *obj, int minorbase) { static int next_minor=0; int i; - + if(minorbase>=0) next_minor=minorbase; if(next_minor>=MAX_TOT_MSGOBJS) @@ -111,7 +111,7 @@ int register_chip_struct(struct canchip_t *chip, int minorbase) { static int next_chip_slot=0; int i; - + if(next_chip_slot>=MAX_TOT_CHIPS) next_chip_slot=0; i=next_chip_slot; @@ -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 @@ -163,7 +187,7 @@ int init_hw_struct(void) * @irq_param_idx_p: pointer to the index into arrays of the per CAN channel IRQ parameters * * The function builds representation of the one board from parameters provided - * in the module parameters arrays: + * in the module parameters arrays: * @hw[card] .. hardware type, * @io[card] .. base IO address, * @baudrate[chan_param_idx] .. per channel baudrate, @@ -172,10 +196,10 @@ int init_hw_struct(void) * The indexes are advanced after consumed parameters if the registration is successful. * * The hardware specific operations of the device/board are initialized by call to - * init_hwspecops() function. Then board data are initialized by board specific + * init_hwspecops() function. Then board data are initialized by board specific * init_hw_data() function. Then chips and objects representation is build by * init_chip_struct() function. If all above steps are successful, chips and - * message objects are registered into global arrays. + * message objects are registered into global arrays. * * Return Value: returns negative number in the case of fail */ @@ -187,7 +211,7 @@ int init_device_struct(int card, int *chan_param_idx_p, int *irq_param_idx_p) int chipnr; long bd; int irqsig=-1; - + candev=(struct candevice_t *)can_checked_malloc(sizeof(struct candevice_t)); if (candev==NULL) return -ENOMEM; @@ -220,14 +244,14 @@ int init_device_struct(int card, int *chan_param_idx_p, int *irq_param_idx_p) if(chipnrnr_all_chips; chipnr++) { @@ -236,7 +260,7 @@ int init_device_struct(int card, int *chan_param_idx_p, int *irq_param_idx_p) int objnr; register_chip_struct(chip, m); - + for (objnr=0; objnrmax_objects; objnr++) { register_obj_struct(chip->msgobj[objnr], m); if(m>=0) m++; @@ -261,7 +285,7 @@ int init_device_struct(int card, int *chan_param_idx_p, int *irq_param_idx_p) hardware_p->candevice[card]=NULL; can_checked_free(candev); return ret; - + } /** @@ -271,9 +295,9 @@ int init_device_struct(int card, int *chan_param_idx_p, int *irq_param_idx_p) * @irq: chip IRQ number or (-1) if not appropriate * @baudrate: baudrate in the units of 1Bd * - * Chip structure is allocated and chip specific operations are filled by + * Chip structure is allocated and chip specific operations are filled by * call to board specific init_chip_data() which calls chip specific - * fill_chipspecops(). The message objects are generated by + * fill_chipspecops(). The message objects are generated by * calls to init_obj_struct() function. * * Return Value: returns negative number in the case of fail @@ -335,7 +359,7 @@ int init_obj_struct(struct candevice_t *candev, struct canchip_t *hostchip, int obj=(struct msgobj_t *)can_checked_malloc(sizeof(struct msgobj_t)); hostchip->msgobj[objnr]=obj; - if (obj == NULL) + if (obj == NULL) return -ENOMEM; memset(obj, 0, sizeof(struct msgobj_t)); @@ -360,7 +384,7 @@ int init_obj_struct(struct candevice_t *candev, struct canchip_t *hostchip, int ret=candev->hwspecops->init_obj_data(hostchip,objnr); if(ret<0) return ret; - + return 0; } @@ -379,14 +403,14 @@ int init_obj_struct(struct candevice_t *candev, struct canchip_t *hostchip, int int init_hwspecops(struct candevice_t *candev, int *irqnum_p) { const struct boardtype_t *brp; - + brp = boardtype_find(candev->hwname); - + if(!brp) { CANMSG("Sorry, hardware \"%s\" is currently not supported.\n",candev->hwname); return -EINVAL; } - + if(irqnum_p) *irqnum_p=brp->irqnum; brp->board_register(candev->hwspecops); diff --git a/lincan/src/usbcan.c b/lincan/src/usbcan.c index aff02d3..ad79d58 100644 --- a/lincan/src/usbcan.c +++ b/lincan/src/usbcan.c @@ -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;ihwname,"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 ul_usb1_init(void){ + return usb_register(&ul_usb1_driver); +} + +void ul_usb1_exit(void){ + usb_deregister(&ul_usb1_driver); +} -- 2.39.2