X-Git-Url: http://rtime.felk.cvut.cz/gitweb/lincan.git/blobdiff_plain/8bb61362e6640738a252b1d7cdf325617fd80926..7c28d4d63c2ccd9945d1b0bb11dd3caff4c382b3:/embedded/app/usbcan/ul_usb1.c diff --git a/embedded/app/usbcan/ul_usb1.c b/embedded/app/usbcan/ul_usb1.c index b777b14..36e1c62 100644 --- a/embedded/app/usbcan/ul_usb1.c +++ b/embedded/app/usbcan/ul_usb1.c @@ -1,36 +1,49 @@ -/* ul_usb1.c - * Linux CAN-bus device driver. - * Written by Jan Kriz email:johen@post.cz - * This software is released under the GPL-License. - * Version lincan-0.3 17 Jun 2004 - * - * Based on - * USB Skeleton driver - 2.2 - * - * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2. - * - * This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c - * but has been rewritten to be easier to read and use. - * - */ +/**************************************************************************/ +/* File: ul_usb1.c - UL_USB1 board specific part of USB<->CAN converter */ +/* */ +/* LinCAN - (Not only) Linux CAN bus driver */ +/* Copyright (C) 2002-2011 DCE FEE CTU Prague */ +/* Copyright (C) 2008 Jan Kriz email:johen@post.cz */ +/* */ +/* LinCAN is free software; you can redistribute it and/or modify it */ +/* under terms of the GNU General Public License as published by the */ +/* Free Software Foundation; either version 2, or (at your option) any */ +/* later version. LinCAN is distributed in the hope that it will be */ +/* useful, but WITHOUT ANY WARRANTY; without even the implied warranty */ +/* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */ +/* General Public License for more details. You should have received a */ +/* copy of the GNU General Public License along with LinCAN; see file */ +/* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, */ +/* Cambridge, MA 02139, USA. */ +/* */ +/* To allow use of LinCAN in the compact embedded systems firmware */ +/* and RT-executives (RTEMS for example), main authors agree with next */ +/* special exception: */ +/* */ +/* Including LinCAN header files in a file, instantiating LinCAN generics */ +/* or templates, or linking other files with LinCAN objects to produce */ +/* an application image/executable, does not by itself cause the */ +/* resulting application image/executable to be covered by */ +/* the GNU General Public License. */ +/* This exception does not however invalidate any other reasons */ +/* why the executable file might be covered by the GNU Public License. */ +/* Publication of enhanced or derived LinCAN files is required although. */ +/**************************************************************************/ -#include "./can/ul_usb1.h" #include "./can/can.h" #include "./can/can_sysdep.h" #include "./can/main.h" #include "./can/devcommon.h" #include "./can/setup.h" -#include "./can/finish.h" +// #include "./can/finish.h" #include "./can/i82527.h" //#include "../include/sja1000.h" #include "./can/sja1000p.h" #include "./can/errno.h" +#include "./can/ul_usb1.h" + /* Get a minor range for your devices from the usb maintainer */ #define USB_SKEL_MINOR_BASE 192 @@ -39,7 +52,7 @@ #define CAN_OP_WRITE 0x00 -/* our private defines. if this grows any larger, use your own .h file */ + /* our private defines. if this grows any larger, use your own .h file */ #define MAX_TRANSFER (PAGE_SIZE - 512) /* MAX_TRANSFER is chosen so that the VM is not stressed by allocations > PAGE_SIZE and the number of packets in a page @@ -51,19 +64,6 @@ #define USB_SKEL_VENDOR_ID 0xDEAD #define USB_SKEL_PRODUCT_ID 0x1001 -/* table of devices that work with this driver */ -// static struct usb_device_id ul_usb1_table [] = { -// { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) }, -// { } /* Terminating entry */ -// }; -// MODULE_DEVICE_TABLE(usb, ul_usb1_table); - -extern struct file_operations can_fops; - -struct ul_usb1_combo { - struct usb_ul_usb1 * dev; - struct urb * urb; -}; /* * IO_RANGE is the io-memory range that gets reserved, please adjust according @@ -72,30 +72,6 @@ struct ul_usb1_combo { */ #define IO_RANGE 0x100 -/* Structure to hold all of our device specific stuff */ -struct usb_ul_usb1 { - 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 */ - size_t bulk_in_size; /* the size of the receive buffer */ - unsigned char *int_in_buffer; /* the buffer to receive data */ - size_t int_in_size; /* the size of the receive buffer */ - __u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */ - __u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */ - __u8 int_in_endpointAddr; /* the address of the interrupt in endpoint */ - int int_in_interval; - 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 *irq; - struct candevice_t *candev; -}; - -static struct usb_driver ul_usb1_driver; - /** ul_usb1_request_io * ul_usb1_request_io: - reserve io or memory range for can board * @candev: pointer to candevice/board which asks for io. Field @io_addr @@ -112,7 +88,6 @@ static struct usb_driver ul_usb1_driver; */ int ul_usb1_request_io(struct candevice_t *candev) { - ((struct usb_ul_usb1*)candev->sysdevptr.anydev)->candev=candev; return 0; } @@ -130,20 +105,6 @@ int ul_usb1_request_io(struct candevice_t *candev) */ int ul_usb1_release_io(struct candevice_t *candev) { - struct usb_ul_usb1 *dev; - if (candev->sysdevptr.anydev){ - dev=(struct usb_ul_usb1*) candev->sysdevptr.anydev; - 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); - } return 0; } @@ -159,7 +120,7 @@ int ul_usb1_release_io(struct candevice_t *candev) */ int ul_usb1_reset(struct candevice_t *candev) { - return 0; + return can_init(); } #define RESET_ADDR 0x0 @@ -186,7 +147,7 @@ int ul_usb1_init_hw_data(struct candevice_t *candev) candev->nr_82527_chips=NR_82527; candev->nr_sja1000_chips=NR_SJA1000; candev->nr_all_chips=NR_82527+NR_SJA1000; - //candev->flags |= CANDEV_PROGRAMMABLE_IRQ; + candev->flags |= CANDEV_PROGRAMMABLE_IRQ*0; return 0; } @@ -240,6 +201,9 @@ int ul_usb1_init_chip_data(struct candevice_t *candev, int chipnr) candev->chip[chipnr]->sja_ocr_reg = sjaOCR_MODE_NORMAL | sjaOCR_TX0_LH; + candev->chip[chipnr]->chip_data=(void *)malloc(sizeof(struct ul_usb1_chip_data)); + if (candev->chip[chipnr]->chip_data==NULL) + return -ENOMEM; return 0; } @@ -295,39 +259,9 @@ int ul_usb1_program_irq(struct candevice_t *candev) * Return Value: The function does not return a value * File: src/ul_usb1.c */ -void ul_usb1_write_register(struct candevice_t *candev,unsigned data, unsigned long address) +void ul_usb1_write_register(unsigned data, unsigned long address) { - struct usb_ul_usb1 *dev; - int retval; - int bytes_transferred; - unsigned char buffer[2]; - buffer[0]=((unsigned char)address & ~CAN_OP_MASK)+CAN_OP_WRITE; - buffer[1]=(unsigned char)data; - - dev = (struct usb_ul_usb1 *)candev->sysdevptr.anydev; - - mutex_lock(&dev->io_mutex); - if (!dev) { /* disconnect() was called */ - CANMSG("Sending %lu:%X : ERR No device\n",address,(uint8_t)data); - retval = -ENODEV; - goto exit; - } - if (!dev->interface) { /* disconnect() was called */ - CANMSG("Sending %lu:%X : ERR No interface\n",address,(uint8_t)data); - retval = -ENODEV; - goto exit; - } - - /* do a blocking bulk write to send data to the device */ - retval = usb_bulk_msg(dev->udev, - usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), - buffer, - 2, - &bytes_transferred, 10000); - CANMSG("Sending %lu:%X : retval %d, transferred %d bytes\n",address,(uint8_t)data,retval,bytes_transferred); - -exit: - mutex_unlock(&dev->io_mutex); + can_write(data, address & 0xFF); } /** ul_usb1_read_register @@ -340,59 +274,11 @@ exit: * Return Value: The function returns the value stored in @address * File: src/ul_usb1.c */ -unsigned ul_usb1_read_register(struct candevice_t *candev,unsigned long address) +unsigned ul_usb1_read_register(unsigned long address) { - struct usb_ul_usb1 *dev; - int retval; - int bytes_transferred; - unsigned char buffer[2]; - buffer[0]=((unsigned char)address & ~CAN_OP_MASK)+CAN_OP_READ; - buffer[1]=0x00; - - dev = (struct usb_ul_usb1 *)candev->sysdevptr.anydev; - - mutex_lock(&dev->io_mutex); - if (!dev) { /* disconnect() was called */ - retval = -ENODEV; - goto exit; - } - if (!dev->interface) { /* disconnect() was called */ - retval = -ENODEV; - goto exit; - } - - /* do a blocking bulk write to send data to the device */ - retval = usb_bulk_msg(dev->udev, - usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), - buffer, - 2, - &bytes_transferred, 10000); - - CANMSG("Requested: %ld : retval %d, transferred %d bytes\n",address,retval,bytes_transferred); - if ((retval)||(bytes_transferred!=2)){ - retval = -EFAULT; - goto exit; - } - - /* do a blocking bulk read to get data from the device */ - retval = usb_bulk_msg(dev->udev, - usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr), - dev->bulk_in_buffer, - dev->bulk_in_size, - &bytes_transferred, 10000); - - /* if the read was successful, copy the data to userspace */ - CANMSG("Received %d bytes : %u:%X\n",bytes_transferred,(dev->bulk_in_buffer[0] & 0x7F),dev->bulk_in_buffer[1]); - if (!retval) { - if (bytes_transferred!=2) - retval = -EFAULT; - else - retval = dev->bulk_in_buffer[1]; - } - -exit: - mutex_unlock(&dev->io_mutex); - return retval; + uint8_t data; + data = can_read(address & 0xFF); + return data; } /* !!! Don't change this function !!! */ @@ -410,228 +296,3 @@ int ul_usb1_register(struct hwspecops_t *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;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); -// }