diff options
Diffstat (limited to 'drivers/usb/ezusb.c')
-rw-r--r-- | drivers/usb/ezusb.c | 1096 |
1 files changed, 0 insertions, 1096 deletions
diff --git a/drivers/usb/ezusb.c b/drivers/usb/ezusb.c deleted file mode 100644 index eb6b23927..000000000 --- a/drivers/usb/ezusb.c +++ /dev/null @@ -1,1096 +0,0 @@ -/*****************************************************************************/ - -/* - * ezusb.c -- Firmware download miscdevice for Anchorchips EZUSB microcontrollers. - * - * Copyright (C) 1999 - * Thomas Sailer (sailer@ife.ee.ethz.ch) - * - * 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; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * History: - * 0.1 26.05.99 Created - * 0.2 23.07.99 Removed EZUSB_INTERRUPT. Interrupt pipes may be polled with - * bulk reads. - * Implemented EZUSB_SETINTERFACE, more sanity checks for EZUSB_BULK. - * Preliminary ISO support - * 0.3 01.09.99 Async Bulk and ISO support - * 0.4 01.09.99 Set callback_frames to the total number of frames to make - * it work with OHCI-HCD - * 03.12.99 Now that USB error codes are negative, return them to application - * instead of ENXIO - * $Id: ezusb.c,v 1.22 1999/12/03 15:06:28 tom Exp $ - */ - -/*****************************************************************************/ -#include <linux/version.h> -#include <linux/module.h> -#include <linux/socket.h> -#include <linux/miscdevice.h> -#include <linux/list.h> -#include <linux/vmalloc.h> -#include <linux/slab.h> -#include <asm/uaccess.h> - -//#include <linux/spinlock.h> - -#include "usb.h" -#include "ezusb.h" - -/* --------------------------------------------------------------------- */ - -#define NREZUSB 1 - -static struct ezusb { - struct semaphore mutex; - struct usb_device *usbdev; - struct list_head async_pending; - struct list_head async_completed; - wait_queue_head_t wait; - spinlock_t lock; -} ezusb[NREZUSB]; - -struct async { - struct list_head asynclist; - struct ezusb *ez; - void *userdata; - unsigned datalen; - void *context; - urb_t urb; -}; - -/*-------------------------------------------------------------------*/ - -static struct async *alloc_async(unsigned int numisoframes) -{ - unsigned int assize = sizeof(struct async) + numisoframes * sizeof(iso_packet_descriptor_t); - struct async *as = kmalloc(assize, GFP_KERNEL); - if (!as) - return NULL; - memset(as, 0, assize); - as->urb.number_of_packets = numisoframes; - return as; -} - -static void free_async(struct async *as) -{ - if (as->urb.transfer_buffer) - kfree(as->urb.transfer_buffer); - kfree(as); -} - -/* --------------------------------------------------------------------- */ - -extern inline unsigned int ld2(unsigned int x) -{ - unsigned int r = 0; - - if (x >= 0x10000) { - x >>= 16; - r += 16; - } - if (x >= 0x100) { - x >>= 8; - r += 8; - } - if (x >= 0x10) { - x >>= 4; - r += 4; - } - if (x >= 4) { - x >>= 2; - r += 2; - } - if (x >= 2) - r++; - return r; -} - -#if 0 -/* why doesn't this work properly on i386? */ -extern inline unsigned int ld2(unsigned int x) -{ - unsigned int r; - - __asm__("bsrl %1,%0" : "=r" (r) : "g" (x)); - return r; -} -#endif - -/* --------------------------------------------------------------------- */ - -extern __inline__ void async_removelist(struct async *as) -{ - struct ezusb *ez = as->ez; - unsigned long flags; - - spin_lock_irqsave(&ez->lock, flags); - list_del(&as->asynclist); - INIT_LIST_HEAD(&as->asynclist); - spin_unlock_irqrestore(&ez->lock, flags); -} - -extern __inline__ void async_newpending(struct async *as) -{ - struct ezusb *ez = as->ez; - unsigned long flags; - - spin_lock_irqsave(&ez->lock, flags); - list_add_tail(&as->asynclist, &ez->async_pending); - spin_unlock_irqrestore(&ez->lock, flags); -} - -extern __inline__ void async_removepending(struct async *as) -{ - struct ezusb *ez = as->ez; - unsigned long flags; - - spin_lock_irqsave(&ez->lock, flags); - list_del(&as->asynclist); - INIT_LIST_HEAD(&as->asynclist); - spin_unlock_irqrestore(&ez->lock, flags); -} - -extern __inline__ struct async *async_getcompleted(struct ezusb *ez) -{ - unsigned long flags; - struct async *as = NULL; - - spin_lock_irqsave(&ez->lock, flags); - if (!list_empty(&ez->async_completed)) { - as = list_entry(ez->async_completed.next, struct async, asynclist); - list_del(&as->asynclist); - INIT_LIST_HEAD(&as->asynclist); - } - spin_unlock_irqrestore(&ez->lock, flags); - return as; -} - -extern __inline__ struct async *async_getpending(struct ezusb *ez, void *context) -{ - unsigned long flags; - struct async *as; - struct list_head *p; - - spin_lock_irqsave(&ez->lock, flags); - for (p = ez->async_pending.next; p != &ez->async_pending; ) { - as = list_entry(p, struct async, asynclist); - p = p->next; - if (as->context != context) - continue; - list_del(&as->asynclist); - INIT_LIST_HEAD(&as->asynclist); - spin_unlock_irqrestore(&ez->lock, flags); - return as; - } - spin_unlock_irqrestore(&ez->lock, flags); - return NULL; -} - -/* --------------------------------------------------------------------- */ - -static void async_completed(purb_t urb) -{ - struct async *as = (struct async *)urb->context; - struct ezusb *ez = as->ez; - unsigned cnt; - -printk(KERN_DEBUG "ezusb: async_completed: status %d errcount %d actlen %d pipe 0x%x\n", - urb->status, urb->error_count, urb->actual_length, urb->pipe); - spin_lock(&ez->lock); - list_del(&as->asynclist); - list_add_tail(&as->asynclist, &ez->async_completed); - spin_unlock(&ez->lock); - wake_up(&ez->wait); -} - -static void destroy_all_async(struct ezusb *ez) -{ - struct async *as; - unsigned long flags; - - spin_lock_irqsave(&ez->lock, flags); - if (!list_empty(&ez->async_pending)) { - as = list_entry(ez->async_pending.next, struct async, asynclist); - list_del(&as->asynclist); - INIT_LIST_HEAD(&as->asynclist); - spin_unlock_irqrestore(&ez->lock, flags); - /* discard_urb calls the completion handler with status == USB_ST_URB_KILLED */ - usb_unlink_urb(&as->urb); - spin_lock_irqsave(&ez->lock, flags); - } - spin_unlock_irqrestore(&ez->lock, flags); - while ((as = async_getcompleted(ez))) - free_async(as); -} - -/* --------------------------------------------------------------------- */ - -static loff_t ezusb_llseek(struct file *file, loff_t offset, int origin) -{ - struct ezusb *ez = (struct ezusb *)file->private_data; - - switch(origin) { - case 1: - offset += file->f_pos; - break; - case 2: - offset += 0x10000; - break; - } - if (offset < 0 || offset >= 0x10000) - return -EINVAL; - return (file->f_pos = offset); -} - -static ssize_t ezusb_read(struct file *file, char *buf, size_t sz, loff_t *ppos) -{ - struct ezusb *ez = (struct ezusb *)file->private_data; - unsigned pos = *ppos; - unsigned ret = 0; - unsigned len; - unsigned char b[64]; - int i; - - if (*ppos < 0 || *ppos >= 0x10000) - return -EINVAL; - down(&ez->mutex); - if (!ez->usbdev) { - up(&ez->mutex); - return -EIO; - } - while (sz > 0 && pos < 0x10000) { - len = sz; - if (len > sizeof(b)) - len = sizeof(b); - if (pos + len > 0x10000) - len = 0x10000 - pos; - i = usb_control_msg(ez->usbdev, usb_rcvctrlpipe(ez->usbdev, 0), 0xa0, 0xc0, pos, 0, b, len, HZ); - if (i < 0) { - up(&ez->mutex); - printk(KERN_WARNING "ezusb: upload failed pos %u len %u ret %d\n", pos, len, i); - *ppos = pos; - if (ret) - return ret; - return i; - } - if (copy_to_user(buf, b, len)) { - up(&ez->mutex); - *ppos = pos; - if (ret) - return ret; - return -EFAULT; - } - pos += len; - buf += len; - sz -= len; - ret += len; - } - up(&ez->mutex); - *ppos = pos; - return ret; -} - -static ssize_t ezusb_write(struct file *file, const char *buf, size_t sz, loff_t *ppos) -{ - struct ezusb *ez = (struct ezusb *)file->private_data; - unsigned pos = *ppos; - unsigned ret = 0; - unsigned len; - unsigned char b[64]; - int i; - - if (*ppos < 0 || *ppos >= 0x10000) - return -EINVAL; - down(&ez->mutex); - if (!ez->usbdev) { - up(&ez->mutex); - return -EIO; - } - while (sz > 0 && pos < 0x10000) { - len = sz; - if (len > sizeof(b)) - len = sizeof(b); - if (pos + len > 0x10000) - len = 0x10000 - pos; - if (copy_from_user(b, buf, len)) { - up(&ez->mutex); - *ppos = pos; - if (ret) - return ret; - return -EFAULT; - } - printk("writemem: %d %p %d\n",pos,b,len); - i = usb_control_msg(ez->usbdev, usb_sndctrlpipe(ez->usbdev, 0), 0xa0, 0x40, pos, 0, b, len, HZ); - if (i < 0) { - up(&ez->mutex); - printk(KERN_WARNING "ezusb: download failed pos %u len %u ret %d\n", pos, len, i); - *ppos = pos; - if (ret) - return ret; - return i; - } - pos += len; - buf += len; - sz -= len; - ret += len; - } - up(&ez->mutex); - *ppos = pos; - return ret; -} - -static int ezusb_open(struct inode *inode, struct file *file) -{ - struct ezusb *ez = &ezusb[0]; - - down(&ez->mutex); - while (!ez->usbdev) { - up(&ez->mutex); - if (!(file->f_flags & O_NONBLOCK)) { - return -EIO; - } - schedule_timeout(HZ/2); - if (signal_pending(current)) - return -EAGAIN; - down(&ez->mutex); - } - up(&ez->mutex); - file->f_pos = 0; - file->private_data = ez; - MOD_INC_USE_COUNT; - return 0; -} - -static int ezusb_release(struct inode *inode, struct file *file) -{ - struct ezusb *ez = (struct ezusb *)file->private_data; - - down(&ez->mutex); - destroy_all_async(ez); - up(&ez->mutex); - MOD_DEC_USE_COUNT; - return 0; -} - -static int ezusb_control(struct usb_device *usbdev, unsigned char requesttype, - unsigned char request, unsigned short value, - unsigned short index, unsigned short length, - unsigned int timeout, void *data) -{ - unsigned char *tbuf = NULL; - unsigned int pipe; - int i; - - if (length > PAGE_SIZE) - return -EINVAL; - /* __range_ok is broken; - with unsigned short size, it gave - addl %si,%edx ; sbbl %ecx,%ecx; cmpl %edx,12(%eax); sbbl $0,%ecx - */ - if (requesttype & 0x80) { - pipe = usb_rcvctrlpipe(usbdev, 0); - if (length > 0 && !access_ok(VERIFY_WRITE, data, (unsigned int)length)) - return -EFAULT; - } else - pipe = usb_sndctrlpipe(usbdev, 0); - if (length > 0) { - if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL))) - return -ENOMEM; - if (!(requesttype & 0x80)) { - if (copy_from_user(tbuf, data, length)) { - free_page((unsigned long)tbuf); - return -EFAULT; - } - } - } - i = usb_control_msg(usbdev, pipe, request, requesttype, value, index, tbuf, length, timeout); - if (i < 0) { - if (length > 0) - free_page((unsigned long)tbuf); - printk(KERN_WARNING "ezusb: EZUSB_CONTROL failed rqt %u rq %u len %u ret %d\n", - requesttype, request, length, i); - return i; - } - if (requesttype & 0x80 && length > 0 && copy_to_user(data, tbuf, length)) - i = -EFAULT; - if (length > 0) - free_page((unsigned long)tbuf); - return i; -} - -static int ezusb_bulk(struct usb_device *usbdev, unsigned int ep, unsigned int length, unsigned int timeout, void *data) -{ - unsigned char *tbuf = NULL; - unsigned int pipe; - unsigned long len2 = 0; - int ret = 0; - - if (length > PAGE_SIZE) - return -EINVAL; - if ((ep & ~0x80) >= 16) - return -EINVAL; - if (ep & 0x80) { - pipe = usb_rcvbulkpipe(usbdev, ep & 0x7f); - if (length > 0 && !access_ok(VERIFY_WRITE, data, length)) - return -EFAULT; - } else - pipe = usb_sndbulkpipe(usbdev, ep & 0x7f); - if (!usb_maxpacket(usbdev, pipe, !(ep & 0x80))) - return -EINVAL; - if (length > 0) { - if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL))) - return -ENOMEM; - if (!(ep & 0x80)) { - if (copy_from_user(tbuf, data, length)) { - free_page((unsigned long)tbuf); - return -EFAULT; - } - } - } - ret = usb_bulk_msg(usbdev, pipe, tbuf, length, &len2, timeout); - if (ret < 0) { - if (length > 0) - free_page((unsigned long)tbuf); - printk(KERN_WARNING "ezusb: EZUSB_BULK failed ep 0x%x len %u ret %d\n", - ep, length, ret); - return -ENXIO; - } - if (len2 > length) - len2 = length; - ret = len2; - if (ep & 0x80 && len2 > 0 && copy_to_user(data, tbuf, len2)) - ret = -EFAULT; - if (length > 0) - free_page((unsigned long)tbuf); - return ret; -} - -static int ezusb_resetep(struct usb_device *usbdev, unsigned int ep) -{ - if ((ep & ~0x80) >= 16) - return -EINVAL; - usb_settoggle(usbdev, ep & 0xf, !(ep & 0x80), 0); - return 0; -} - -static int ezusb_setinterface(struct usb_device *usbdev, unsigned int interface, unsigned int altsetting) -{ - if (usb_set_interface(usbdev, interface, altsetting) < 0) - return -EINVAL; - return 0; -} - -static int ezusb_setconfiguration(struct usb_device *usbdev, unsigned int config) -{ - if (usb_set_configuration(usbdev, config) < 0) - return -EINVAL; - return 0; -} - -#define usb_sndintpipe(dev,endpoint) ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint)) -#define usb_rcvintpipe(dev,endpoint) ((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN) - -char* stuff[512]; - -static void int_compl(purb_t purb) -{ - printk("INT_COMPL\n"); - -} - -static int ezusb_interrupt(struct ezusb *ez, struct ezusb_interrupt *ab) -{ - urb_t *urb; - unsigned int pipe; - - urb=(urb_t*)kmalloc(sizeof(urb_t),GFP_KERNEL); - if (!urb) - { - return -ENOMEM; - } - memset(urb,0,sizeof(urb_t)); - - - if ((ab->ep & ~0x80) >= 16) - return -EINVAL; - if (ab->ep & 0x80) - { - pipe = usb_rcvintpipe(ez->usbdev, ab->ep & 0x7f); - if (ab->len > 0 && !access_ok(VERIFY_WRITE, ab->data, ab->len)) - return -EFAULT; - } - else - pipe = usb_sndintpipe(ez->usbdev, ab->ep & 0x7f); - - memcpy(stuff,ab->data,64); - urb->transfer_buffer=stuff; - urb->transfer_buffer_length=ab->len; - urb->complete=int_compl; - urb->pipe=pipe; - urb->dev=ez->usbdev; - urb->interval=ab->interval; - return usb_submit_urb(urb); -} - -static int ezusb_requestbulk(struct ezusb *ez, struct ezusb_asyncbulk *ab) -{ - struct async *as = NULL; - void *data = NULL; - unsigned int pipe; - int ret; - - if (ab->len > PAGE_SIZE) - return -EINVAL; - if ((ab->ep & ~0x80) >= 16) - return -EINVAL; - if (ab->ep & 0x80) { - pipe = usb_rcvbulkpipe(ez->usbdev, ab->ep & 0x7f); - if (ab->len > 0 && !access_ok(VERIFY_WRITE, ab->data, ab->len)) - return -EFAULT; - } else - pipe = usb_sndbulkpipe(ez->usbdev, ab->ep & 0x7f); - if (!usb_maxpacket(ez->usbdev, pipe, !(ab->ep & 0x80))) - return -EINVAL; - if (ab->len > 0 && !(data = kmalloc(ab->len, GFP_KERNEL))) - return -ENOMEM; - if (!(as = alloc_async(0))) { - if (data) - kfree(data); - return -ENOMEM; - } - INIT_LIST_HEAD(&as->asynclist); - as->ez = ez; - as->userdata = ab->data; - as->datalen = ab->len; - as->context = ab->context; - as->urb.dev = ez->usbdev; - as->urb.pipe = pipe; - as->urb.transfer_flags = 0; - as->urb.transfer_buffer = data; - as->urb.transfer_buffer_length = ab->len; - as->urb.context = as; - as->urb.complete = (usb_complete_t)async_completed; - if (ab->len > 0 && !(ab->ep & 0x80)) { - if (copy_from_user(data, ab->data, ab->len)) { - free_async(as); - return -EFAULT; - } - as->userdata = NULL; /* no need to copy back at completion */ - } - async_newpending(as); - if ((ret = usb_submit_urb(&as->urb))) { - printk(KERN_DEBUG "ezusb: bulk: usb_submit_urb returned %d\n", ret); - async_removepending(as); - free_async(as); - return -EINVAL; /* return ret; */ - } - return 0; -} - -static int ezusb_requestiso(struct ezusb *ez, struct ezusb_asynciso *ai, unsigned char *cmd) -{ - struct async *as; - void *data = NULL; - unsigned int maxpkt, pipe, dsize, totsize, i, j; - int ret; - - if ((ai->ep & ~0x80) >= 16 || ai->framecnt < 1 || ai->framecnt > 128) - return -EINVAL; - if (ai->ep & 0x80) - pipe = usb_rcvisocpipe(ez->usbdev, ai->ep & 0x7f); - else - pipe = usb_sndisocpipe(ez->usbdev, ai->ep & 0x7f); - if (!(maxpkt = usb_maxpacket(ez->usbdev, pipe, !(ai->ep & 0x80)))) - return -EINVAL; - dsize = maxpkt * ai->framecnt; -//printk(KERN_DEBUG "ezusb: iso: dsize %d\n", dsize); - if (dsize > 65536) - return -EINVAL; - if (ai->ep & 0x80) - if (dsize > 0 && !access_ok(VERIFY_WRITE, ai->data, dsize)) - return -EFAULT; - if (dsize > 0 && !(data = kmalloc(dsize, GFP_KERNEL))) - { - printk("dsize: %d failed\n",dsize); - return -ENOMEM; - } - if (!(as = alloc_async(ai->framecnt))) { - if (data) - kfree(data); - printk("alloc_async failed\n"); - return -ENOMEM; - } - INIT_LIST_HEAD(&as->asynclist); - - as->ez = ez; - as->userdata = ai->data; - as->datalen = dsize; - as->context = ai->context; - - as->urb.dev = ez->usbdev; - as->urb.pipe = pipe; - as->urb.transfer_flags = USB_ISO_ASAP; - as->urb.transfer_buffer = data; - as->urb.transfer_buffer_length = dsize; - as->urb.context = as; - as->urb.complete = (usb_complete_t)async_completed; - - for (i = totsize = 0; i < as->urb.number_of_packets; i++) { - as->urb.iso_frame_desc[i].offset = totsize; - if (get_user(j, (int *)(cmd + i * sizeof(struct ezusb_isoframestat)))) { - free_async(as); - return -EFAULT; - } - as->urb.iso_frame_desc[i].length = j; - totsize += j; - } - if (dsize > 0 && totsize > 0 && !(ai->ep & 0x80)) { - if (copy_from_user(data, ai->data, totsize)) { - free_async(as); - return -EFAULT; - } - as->userdata = NULL; /* no need to copy back at completion */ - } - async_newpending(as); - if ((ret = usb_submit_urb(&as->urb))) { - printk(KERN_DEBUG "ezusb: iso: usb_submit_urb returned %d\n", ret); - async_removepending(as); - free_async(as); - return -EINVAL; /* return ret; */ - } - return 0; -} - -static int ezusb_terminateasync(struct ezusb *ez, void *context) -{ - struct async *as; - int ret = 0; - - while ((as = async_getpending(ez, context))) { - usb_unlink_urb(&as->urb); - ret++; - } - return ret; -} - -static int ezusb_asynccompl(struct async *as, void *arg) -{ - struct ezusb_asynccompleted *cpl; - unsigned int numframes, cplsize, i; - - if (as->userdata) { - if (copy_to_user(as->userdata, as->urb.transfer_buffer, as->datalen)) { - free_async(as); - return -EFAULT; - } - } - numframes = as->urb.number_of_packets; - cplsize = sizeof(struct ezusb_asynccompleted) + numframes * sizeof(struct ezusb_isoframestat); - if (!(cpl = kmalloc(cplsize, GFP_KERNEL))) { - free_async(as); - return -ENOMEM; - } - cpl->status = as->urb.status; - cpl->length = as->urb.actual_length; - cpl->context = as->context; - for (i = 0; i < numframes; i++) { - cpl->isostat[i].length = as->urb.iso_frame_desc[i].length; - cpl->isostat[i].status = as->urb.iso_frame_desc[i].status; - } - free_async(as); - if (copy_to_user(arg, cpl, cplsize)) { - kfree(cpl); - return -EFAULT; - } - kfree(cpl); - return 0; -} - -static int ezusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct ezusb *ez = (struct ezusb *)file->private_data; - DECLARE_WAITQUEUE(wait, current); - struct usb_proc_ctrltransfer pctrl; - struct usb_proc_bulktransfer pbulk; - struct usb_proc_old_ctrltransfer opctrl; - struct usb_proc_old_bulktransfer opbulk; - struct usb_proc_setinterface psetintf; - struct ezusb_ctrltransfer ctrl; - struct ezusb_bulktransfer bulk; - struct ezusb_old_ctrltransfer octrl; - struct ezusb_old_bulktransfer obulk; - struct ezusb_setinterface setintf; - struct ezusb_asyncbulk abulk; - struct ezusb_asynciso aiso; - struct ezusb_interrupt ezint; - struct async *as; - void *context; - unsigned int ep, cfg; - int i, ret = 0; - - down(&ez->mutex); - if (!ez->usbdev) { - up(&ez->mutex); - return -EIO; - } - switch (cmd) { - case USB_PROC_CONTROL: - if (copy_from_user(&pctrl, (void *)arg, sizeof(pctrl))) { - ret = -EFAULT; - break; - } - ret = ezusb_control(ez->usbdev, pctrl.requesttype, pctrl.request, - pctrl.value, pctrl.index, pctrl.length, - (pctrl.timeout * HZ + 500) / 1000, pctrl.data); - break; - - case USB_PROC_BULK: - if (copy_from_user(&pbulk, (void *)arg, sizeof(pbulk))) { - ret = -EFAULT; - break; - } - ret = ezusb_bulk(ez->usbdev, pbulk.ep, pbulk.len, - (pbulk.timeout * HZ + 500) / 1000, pbulk.data); - break; - - case USB_PROC_OLD_CONTROL: - if (copy_from_user(&opctrl, (void *)arg, sizeof(opctrl))) { - ret = -EFAULT; - break; - } - ret = ezusb_control(ez->usbdev, opctrl.requesttype, opctrl.request, - opctrl.value, opctrl.index, opctrl.length, HZ, opctrl.data); - break; - - case USB_PROC_OLD_BULK: - if (copy_from_user(&opbulk, (void *)arg, sizeof(opbulk))) { - ret = -EFAULT; - break; - } - ret = ezusb_bulk(ez->usbdev, opbulk.ep, opbulk.len, 5*HZ, opbulk.data); - break; - - case USB_PROC_RESETEP: - if (get_user(ep, (unsigned int *)arg)) { - ret = -EFAULT; - break; - } - ret = ezusb_resetep(ez->usbdev, ep); - break; - - case USB_PROC_SETINTERFACE: - if (copy_from_user(&psetintf, (void *)arg, sizeof(psetintf))) { - ret = -EFAULT; - break; - } - ret = ezusb_setinterface(ez->usbdev, psetintf.interface, psetintf.altsetting); - break; - - case USB_PROC_SETCONFIGURATION: - if (get_user(cfg, (unsigned int *)arg)) { - ret = -EFAULT; - break; - } - ret = ezusb_setconfiguration(ez->usbdev, cfg); - break; - - case EZUSB_CONTROL: - if (copy_from_user(&ctrl, (void *)arg, sizeof(ctrl))) { - ret = -EFAULT; - break; - } - ret = ezusb_control(ez->usbdev, ctrl.requesttype, ctrl.request, - ctrl.value, ctrl.index, ctrl.length, - (ctrl.timeout * HZ + 500) / 1000, ctrl.data); - break; - - case EZUSB_BULK: - if (copy_from_user(&bulk, (void *)arg, sizeof(bulk))) { - ret = -EFAULT; - break; - } - ret = ezusb_bulk(ez->usbdev, bulk.ep, bulk.len, - (bulk.timeout * HZ + 500) / 1000, bulk.data); - break; - - case EZUSB_OLD_CONTROL: - if (copy_from_user(&octrl, (void *)arg, sizeof(octrl))) { - ret = -EFAULT; - break; - } - if (octrl.dlen != octrl.length) { - ret = -EINVAL; - break; - } - ret = ezusb_control(ez->usbdev, octrl.requesttype, octrl.request, - octrl.value, octrl.index, octrl.length, HZ, octrl.data); - break; - - case EZUSB_OLD_BULK: - if (copy_from_user(&obulk, (void *)arg, sizeof(obulk))) { - ret = -EFAULT; - break; - } - ret = ezusb_bulk(ez->usbdev, obulk.ep, obulk.len, 5*HZ, obulk.data); - break; - - case EZUSB_RESETEP: - if (get_user(ep, (unsigned int *)arg)) { - ret = -EFAULT; - break; - } - ret = ezusb_resetep(ez->usbdev, ep); - break; - - case EZUSB_SETINTERFACE: - if (copy_from_user(&setintf, (void *)arg, sizeof(setintf))) { - ret = -EFAULT; - break; - } - ret = ezusb_setinterface(ez->usbdev, setintf.interface, setintf.altsetting); - break; - - case EZUSB_SETCONFIGURATION: - if (get_user(cfg, (unsigned int *)arg)) { - ret = -EFAULT; - break; - } - ret = ezusb_setconfiguration(ez->usbdev, cfg); - break; - - case EZUSB_ASYNCCOMPLETED: - as = NULL; - current->state = TASK_INTERRUPTIBLE; - add_wait_queue(&ez->wait, &wait); - for (;;) { - if (!ez->usbdev) - break; - if ((as = async_getcompleted(ez))) - break; - if (signal_pending(current)) - break; - up(&ez->mutex); - schedule(); - down(&ez->mutex); - } - remove_wait_queue(&ez->wait, &wait); - current->state = TASK_RUNNING; - if (as) { - ret = ezusb_asynccompl(as, (void *)arg); - break; - } - if (signal_pending(current)) { - ret = -EINTR; - break; - } - ret = -EIO; - break; - - case EZUSB_ASYNCCOMPLETEDNB: - if ((as = async_getcompleted(ez))) { - ret = ezusb_asynccompl(as, (void *)arg); - break; - } - ret = -EAGAIN; - break; - - case EZUSB_REQUESTBULK: - if (copy_from_user(&abulk, (void *)arg, sizeof(abulk))) { - ret = -EFAULT; - break; - } - ret = ezusb_requestbulk(ez, &abulk); - break; - - case EZUSB_REQUESTISO: - if (copy_from_user(&aiso, (void *)arg, sizeof(aiso))) { - ret = -EFAULT; - break; - } - ret = ezusb_requestiso(ez, &aiso, ((unsigned char *)arg)+sizeof(aiso)); - break; - - case EZUSB_TERMINATEASYNC: - if (get_user(context, (void **)arg)) { - ret = -EFAULT; - break; - } - ret = ezusb_terminateasync(ez, context); - break; - - case EZUSB_GETFRAMENUMBER: - i = usb_get_current_frame_number(ez->usbdev); - ret = put_user(i, (int *)arg); - break; - - case EZUSB_INTERRUPT: - printk("INT START\n"); - if (copy_from_user(&ezint, (void *)arg, sizeof(ezint))) { - ret = -EFAULT; - break; - } - ret=ezusb_interrupt(ez,&ezint); - break; - default: - ret = -ENOIOCTLCMD; - break; - } - up(&ez->mutex); - return ret; -} - -static struct file_operations ezusb_fops = { - ezusb_llseek, - ezusb_read, - ezusb_write, - NULL, /* readdir */ - NULL, /* poll */ - ezusb_ioctl, - NULL, /* mmap */ - ezusb_open, - NULL, /* flush */ - ezusb_release, - NULL, /* fsync */ - NULL, /* fasync */ - NULL /* lock */ -}; - -/* --------------------------------------------------------------------- */ - -static void * ezusb_probe(struct usb_device *usbdev, unsigned int ifnum) -{ - struct ezusb *ez = &ezusb[0]; - struct usb_interface_descriptor *interface; - struct usb_endpoint_descriptor *endpoint; - -#undef KERN_DEBUG -#define KERN_DEBUG "" - printk(KERN_DEBUG "ezusb: probe: vendor id 0x%x, device id 0x%x\n", - usbdev->descriptor.idVendor, usbdev->descriptor.idProduct); - - /* the 1234:5678 is just a self assigned test ID */ - if ((usbdev->descriptor.idVendor != 0x0547 || usbdev->descriptor.idProduct != 0x2131) - #if 1 - && - (usbdev->descriptor.idVendor != 0x0547 || usbdev->descriptor.idProduct != 0x9999) && - (usbdev->descriptor.idVendor != 0x1234 || usbdev->descriptor.idProduct != 0x5678) - #endif - ) - return NULL; - - /* We don't handle multiple configurations */ - if (usbdev->descriptor.bNumConfigurations != 1) - return NULL; - -#if 0 - /* We don't handle multiple interfaces */ - if (usbdev->config[0].bNumInterfaces != 1) - return NULL; -#endif - - down(&ez->mutex); - if (ez->usbdev) { - up(&ez->mutex); - printk(KERN_INFO "ezusb: device already used\n"); - return NULL; - } - ez->usbdev = usbdev; - if (usb_set_configuration(usbdev, usbdev->config[0].bConfigurationValue) < 0) { - printk(KERN_ERR "ezusb: set_configuration failed\n"); - goto err; - } - - interface = &usbdev->config[0].interface[0].altsetting[1]; - if (usb_set_interface(usbdev, 0, 1) < 0) { - printk(KERN_ERR "ezusb: set_interface failed\n"); - goto err; - } - up(&ez->mutex); - MOD_INC_USE_COUNT; - return ez; - - err: - up(&ez->mutex); - ez->usbdev = NULL; - return NULL; -} - -static void ezusb_disconnect(struct usb_device *usbdev, void *ptr) -{ - struct ezusb *ez = (struct ezusb *)ptr; - - down(&ez->mutex); - destroy_all_async(ez); - ez->usbdev = NULL; - up(&ez->mutex); - wake_up(&ez->wait); - MOD_DEC_USE_COUNT; -} - -static struct usb_driver ezusb_driver = { - "ezusb", - ezusb_probe, - ezusb_disconnect, - { NULL, NULL }, - &ezusb_fops, - 192 -}; - -/* --------------------------------------------------------------------- */ - -int ezusb_init(void) -{ - unsigned u; - - /* initialize struct */ - for (u = 0; u < NREZUSB; u++) { - init_MUTEX(&ezusb[u].mutex); - ezusb[u].usbdev = NULL; - INIT_LIST_HEAD(&ezusb[u].async_pending); - INIT_LIST_HEAD(&ezusb[u].async_completed); - init_waitqueue_head(&ezusb[u].wait); - spin_lock_init(&ezusb[u].lock); - } - /* register misc device */ - usb_register(&ezusb_driver); - printk(KERN_INFO "ezusb: Anchorchip firmware download driver registered\n"); - return 0; -} - -void ezusb_cleanup(void) -{ - usb_deregister(&ezusb_driver); -} - -/* --------------------------------------------------------------------- */ - -#ifdef MODULE - -int minor = 192; - -int init_module(void) -{ - return ezusb_init(); -} - -void cleanup_module(void) -{ - ezusb_cleanup(); -} - -#endif - -/* --------------------------------------------------------------------- */ |