#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;
char lnk_name[20];
char lnk_dev[20];
struct proc_dir_entry *lnk;
-};
+};
*/
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);
* 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);
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
#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;
}
}
#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
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; 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);
+ #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;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
+ class_device_destroy(can_class, MKDEV(major, dev_minor));
+ }
+ #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);
+// 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");
* 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"
#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);
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.
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)
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);
}
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;
{
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;
for (board=0; board<hardware_p->nr_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;
{
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;
}
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,
}
return 0;
-}
+}
int remove_object_from_procdir(int chip_nr)
{
for (i=0; i<obj; i++) {
if(!base->channel[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(
* 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"
{
unsigned long offs;
int i, j;
-
+
offs=new_base-candev->dev_base_addr;
candev->dev_base_addr=new_base;
for(i=0;i<candev->nr_all_chips;i++){
/**
* 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.
*/
if(boarddev == anydev)
return 1;
}
-
+
return 0;
}
{
static int next_minor=0;
int i;
-
+
if(minorbase>=0)
next_minor=minorbase;
if(next_minor>=MAX_TOT_MSGOBJS)
{
static int next_chip_slot=0;
int i;
-
+
if(next_chip_slot>=MAX_TOT_CHIPS)
next_chip_slot=0;
i=next_chip_slot;
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
* @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,
* 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
*/
int chipnr;
long bd;
int irqsig=-1;
-
+
candev=(struct candevice_t *)can_checked_malloc(sizeof(struct candevice_t));
if (candev==NULL)
return -ENOMEM;
if(chipnr<irqnum)
irqsig=irq[*irq_param_idx_p+chipnr];
-
+
bd=baudrate[*chan_param_idx_p+chipnr];
if(!bd) bd=baudrate[0];
-
+
if ((ret=init_chip_struct(candev, chipnr, irqsig, bd*1000)))
goto error_chip;
}
-
+
for (chipnr=0; chipnr < candev->nr_all_chips; chipnr++) {
int objnr;
register_chip_struct(chip, m);
-
+
for (objnr=0; objnr<chip->max_objects; objnr++) {
register_obj_struct(chip->msgobj[objnr], m);
if(m>=0) m++;
hardware_p->candevice[card]=NULL;
can_checked_free(candev);
return ret;
-
+
}
/**
* @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
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));
ret=candev->hwspecops->init_obj_data(hostchip,objnr);
if(ret<0) return ret;
-
+
return 0;
}
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);
{
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 ul_usb1_init(void){
+ return usb_register(&ul_usb1_driver);
+}
+
+void ul_usb1_exit(void){
+ usb_deregister(&ul_usb1_driver);
+}