diff options
| author | Patrick Mochel <mochel@osdl.org> | 2002-12-01 01:18:34 -0600 |
|---|---|---|
| committer | Patrick Mochel <mochel@osdl.org> | 2002-12-01 01:18:34 -0600 |
| commit | b00a75ab131dc8ea758b1354428521d0f6279610 (patch) | |
| tree | 93ce1841f2ef4fb0886e021d464876d47f0d4e99 | |
| parent | 6f3caf1587dbccd4cab287c7319af8270a0057e3 (diff) | |
| parent | c9e540101f043fe4a713781513d675e3f3577b55 (diff) | |
Merge osdl.org:/home/mochel/src/kernel/devel/linux-2.5-virgin
into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-core
73 files changed, 1648 insertions, 1116 deletions
diff --git a/Documentation/usb/ov511.txt b/Documentation/usb/ov511.txt index 8c36ebe503fb..e1974ec8217e 100644 --- a/Documentation/usb/ov511.txt +++ b/Documentation/usb/ov511.txt @@ -255,6 +255,15 @@ MODULE PARAMETERS: might be necessary if your camera has a custom lens assembly. This has no effect with video capture devices. + NAME: ov518_color + TYPE: integer (Boolean) + DEFAULT: 0 (off) + DESC: Enable OV518 color support. This is off by default since it doesn't + work most of the time. If you want to try it, you must also load + ov518_decomp with the "nouv=0" parameter. If you get improper colors or + diagonal lines through the image, restart your video app and try again. + Repeat as necessary. + WORKING FEATURES: o Color streaming/capture at most widths and heights that are multiples of 8. o Monochrome (use force_palette=1 to enable) diff --git a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt index ac32a1465338..7e6150c50088 100644 --- a/Documentation/usb/usb-serial.txt +++ b/Documentation/usb/usb-serial.txt @@ -94,10 +94,11 @@ HandSpring Visor, Palm USB, and Clié USB driver Compaq iPAQ, HP Jornada and Casio EM500 driver This driver can be used to connect to Compaq iPAQ, HP Jornada and Casio EM500 - PDAs running Windows CE 3.0 or PocketPC 2002 using a USB cable/cradle. It - has been tested only on the Compaq H3135, but is rumoured to work on - with the H3600 and later models as well as the Jornada 548 and 568. - With minor modifications, it may work for other CE based handhelds too. + PDAs running Windows CE 3.0 or PocketPC 2002 using a USB cable/cradle. + It's very likely that every device supported by ActiveSync USB works with this + driver. The driver supports the Compaq iPAQ, Jornada 548/568 and the Casio + EM500 out of the box. For others, please use module parameters to specify + the product and vendor id. e.g. modprobe ipaq vendor=0x3f0 product=0x1125 The driver presents a serial interface (usually on /dev/ttyUSB0) over which one may run ppp and establish a TCP/IP link to the iPAQ. Once this @@ -105,36 +106,12 @@ Compaq iPAQ, HP Jornada and Casio EM500 driver significant advantage of using USB is speed - you can get 73 to 113 kbytes/sec for download/upload to the iPAQ. - The driver works intermittently with the usb-uhci driver but quite - reliably with the uhci driver. However, performance is much better - with usb-uhci. It does not seem to work with ohci at all. - - You must setup hotplug to invoke pppd as soon as the iPAQ is connected. - A ppp script like the one below should be kept in the file - /etc/hotplug/usb/ipaq Remember to chmod +x. Make sure there are no - options in /etc/ppp/options or ~/.ppprc which conflict with the ones - given below. - - #!/bin/bash - - MYIP=linux.box.ip - REMOTEIP=ipaq.ip - MYDNS=my.dns.server - killall -9 pppd - /usr/sbin/pppd /dev/ttyUSB0 \ - connect "/usr/sbin/chat -v TIMEOUT 60 CLIENT 'CLIENTSERVER\c'" \ - nocrtscts local debug passive $MYIP:$REMOTEIP ms-dns $MYDNS noauth \ - proxyarp - - You must also download and install asyncd from http://synce.sourceforge.net - This is required to emulate keep-alive packets which are exchanged by - ActiveSync and the iPAQ. - - On connecting the cable, you should see the usual "Device Connected", - "User Authenticated" messages flash by on your iPAQ. Once connected, - you can use Win CE programs like ftpView, Pocket Outlook from the iPAQ - and xcerdisp, synce utilities from the Linux side. Remember to enable IP - forwarding. + This driver is only one of a set of components required to utilize + the USB connection. Please visit http://synce.sourceforge.net which + contains the necessary packages and a simple step-by-step howto. + + Once connected, you can use Win CE programs like ftpView, Pocket Outlook + from the iPAQ and xcerdisp, synce utilities from the Linux side. To use Pocket IE, follow the instructions given at http://www.tekguru.co.uk/EM500/usbtonet.htm to achieve the same thing @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 5 -SUBLEVEL = 49 +SUBLEVEL = 50 EXTRAVERSION = # *DOCUMENTATION* diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 2cdcaba1600b..7fd91413caca 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c @@ -711,7 +711,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) /* are we already being traced? */ if (current->ptrace & PT_PTRACED) goto out; - if ((ret = security_ptrace(current->parent, current))) + ret = security_ptrace(current->parent, current); + if (ret) goto out; /* set the ptrace bit in the process flags. */ current->ptrace |= PT_PTRACED; diff --git a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c index cb73b6a2d463..c471cfb27070 100644 --- a/arch/i386/kernel/ptrace.c +++ b/arch/i386/kernel/ptrace.c @@ -160,7 +160,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) /* are we already being traced? */ if (current->ptrace & PT_PTRACED) goto out; - if ((ret = security_ptrace(current->parent, current))) + ret = security_ptrace(current->parent, current); + if (ret) goto out; /* set the ptrace bit in the process flags. */ current->ptrace |= PT_PTRACED; diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index d9a8f6f7d700..c2610f5029ee 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -1101,7 +1101,8 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data, /* are we already being traced? */ if (current->ptrace & PT_PTRACED) goto out; - if ((ret = security_ptrace(current->parent, current))) + ret = security_ptrace(current->parent, current); + if (ret) goto out; current->ptrace |= PT_PTRACED; ret = 0; diff --git a/arch/ppc/kernel/ptrace.c b/arch/ppc/kernel/ptrace.c index 25c5e972080e..1bf399bd794a 100644 --- a/arch/ppc/kernel/ptrace.c +++ b/arch/ppc/kernel/ptrace.c @@ -166,7 +166,8 @@ int sys_ptrace(long request, long pid, long addr, long data) /* are we already being traced? */ if (current->ptrace & PT_PTRACED) goto out; - if ((ret = security_ptrace(current->parent, current))) + ret = security_ptrace(current->parent, current); + if (ret) goto out; /* set the ptrace bit in the process flags. */ current->ptrace |= PT_PTRACED; diff --git a/arch/ppc64/kernel/ptrace.c b/arch/ppc64/kernel/ptrace.c index da14969ddcf8..859af5ffb1ad 100644 --- a/arch/ppc64/kernel/ptrace.c +++ b/arch/ppc64/kernel/ptrace.c @@ -59,7 +59,8 @@ int sys_ptrace(long request, long pid, long addr, long data) /* are we already being traced? */ if (current->ptrace & PT_PTRACED) goto out; - if ((ret = security_ptrace(current->parent, current))) + ret = security_ptrace(current->parent, current); + if (ret) goto out; /* set the ptrace bit in the process flags. */ current->ptrace |= PT_PTRACED; diff --git a/arch/ppc64/kernel/ptrace32.c b/arch/ppc64/kernel/ptrace32.c index 562f2d145989..3309bf2c4439 100644 --- a/arch/ppc64/kernel/ptrace32.c +++ b/arch/ppc64/kernel/ptrace32.c @@ -48,7 +48,8 @@ int sys32_ptrace(long request, long pid, unsigned long addr, unsigned long data) /* are we already being traced? */ if (current->ptrace & PT_PTRACED) goto out; - if ((ret = security_ptrace(current->parent, current))) + ret = security_ptrace(current->parent, current); + if (ret) goto out; /* set the ptrace bit in the process flags. */ current->ptrace |= PT_PTRACED; diff --git a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c index 7d63831bc18e..3b3624c3b554 100644 --- a/arch/ppc64/kernel/sys_ppc32.c +++ b/arch/ppc64/kernel/sys_ppc32.c @@ -3521,7 +3521,8 @@ static int do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * if ((retval = bprm.envc) < 0) goto out_mm; - if ((retval = security_bprm_alloc(&bprm))) + retval = security_bprm_alloc(&bprm); + if (retval) goto out; retval = prepare_binprm(&bprm); diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index 216a2587fdbc..e4820caa2779 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -323,7 +323,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ret = -EPERM; if (current->ptrace & PT_PTRACED) goto out; - if ((ret = security_ptrace(current->parent, current))) + ret = security_ptrace(current->parent, current); + if (ret) goto out; /* set the ptrace bit in the process flags. */ current->ptrace |= PT_PTRACED; diff --git a/arch/s390x/kernel/ptrace.c b/arch/s390x/kernel/ptrace.c index 76c50f71c5cc..5545e7c2a22e 100644 --- a/arch/s390x/kernel/ptrace.c +++ b/arch/s390x/kernel/ptrace.c @@ -563,7 +563,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ret = -EPERM; if (current->ptrace & PT_PTRACED) goto out; - if ((ret = security_ptrace(current->parent, current))) + ret = security_ptrace(current->parent, current); + if (ret) goto out; /* set the ptrace bit in the process flags. */ current->ptrace |= PT_PTRACED; diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c index 119ef00c19e7..fcc3fb80109e 100644 --- a/arch/sparc/kernel/ptrace.c +++ b/arch/sparc/kernel/ptrace.c @@ -291,7 +291,8 @@ asmlinkage void do_ptrace(struct pt_regs *regs) pt_error_return(regs, EPERM); goto out; } - if ((ret = security_ptrace(current->parent, current))) { + ret = security_ptrace(current->parent, current); + if (ret) { pt_error_return(regs, -ret); goto out; } diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index b0145e0a91be..e627070dc292 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -140,7 +140,8 @@ asmlinkage void do_ptrace(struct pt_regs *regs) pt_error_return(regs, EPERM); goto out; } - if ((ret = security_ptrace(current->parent, current))) { + ret = security_ptrace(current->parent, current); + if (ret) { pt_error_return(regs, -ret); goto out; } diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 7f950721beb9..001ce5705865 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -3026,7 +3026,8 @@ do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs) if ((retval = bprm.envc) < 0) goto out_mm; - if ((retval = security_bprm_alloc(&bprm))) + retval = security_bprm_alloc(&bprm); + if (retval) goto out; retval = prepare_binprm(&bprm); diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index ffcd37877457..d6dacf475c33 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -33,7 +33,8 @@ int sys_ptrace(long request, long pid, long addr, long data) if (current->ptrace & PT_PTRACED) goto out; - if ((ret = security_ptrace(current->parent, current))) + ret = security_ptrace(current->parent, current); + if (ret) goto out; /* set the ptrace bit in the process flags. */ diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c index 8542f118d213..70308686725b 100644 --- a/arch/x86_64/kernel/ptrace.c +++ b/arch/x86_64/kernel/ptrace.c @@ -178,7 +178,8 @@ asmlinkage long sys_ptrace(long request, long pid, long addr, long data) /* are we already being traced? */ if (current->ptrace & PT_PTRACED) goto out; - if ((ret = security_ptrace(current->parent, current))) + ret = security_ptrace(current->parent, current); + if (ret) goto out; /* set the ptrace bit in the process flags. */ current->ptrace |= PT_PTRACED; diff --git a/drivers/base/base.h b/drivers/base/base.h index c9eeed6b07e9..6194d88242ec 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -34,7 +34,7 @@ static inline int dev_hotplug(struct device *dev, const char *action) { return 0; } -static int class_hotplug(struct device *dev, const char *action) +static inline int class_hotplug(struct device *dev, const char *action) { return 0; } diff --git a/drivers/base/hotplug.c b/drivers/base/hotplug.c index 3499840e34b5..95937fbe3676 100644 --- a/drivers/base/hotplug.c +++ b/drivers/base/hotplug.c @@ -35,6 +35,8 @@ #define BUFFER_SIZE 1024 /* should be enough memory for the env */ #define NUM_ENVP 32 /* number of env pointers */ +static char prefix [] = "devices"; /* /sys/devices/... */ + static int do_hotplug (struct device *dev, char *argv1, const char *action, int (* hotplug) (struct device *, char **, int, char *, int)) { @@ -72,7 +74,7 @@ static int do_hotplug (struct device *dev, char *argv1, const char *action, } dev_length = get_devpath_length (dev); - dev_length += strlen("root"); + dev_length += strlen(prefix); dev_path = kmalloc (dev_length, GFP_KERNEL); if (!dev_path) { kfree (buffer); @@ -80,7 +82,7 @@ static int do_hotplug (struct device *dev, char *argv1, const char *action, return -ENOMEM; } memset (dev_path, 0x00, dev_length); - strcpy (dev_path, "root"); + strcpy (dev_path, prefix); fill_devpath (dev, dev_path, dev_length); argv [0] = hotplug_path; diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 721c15f295f5..6004a5231186 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -38,18 +38,6 @@ config USB_DEVICEFS Most users want to say Y here. -config USB_LONG_TIMEOUT - bool "Long timeout for slow-responding devices (some MGE Ellipse UPSes)" - depends on USB - help - This option makes the standard time out a bit longer. Basically, - some devices are just slow to respond, so this makes usb more - patient. There should be no harm in selecting this, but it is - needed for some MGE Ellipse UPSes. - - If you have an MGE Ellipse UPS, or you see timeouts in HID - transactions, say Y; otherwise say N. - config USB_BANDWIDTH bool "Enforce USB bandwidth allocation (EXPERIMENTAL)" depends on USB && EXPERIMENTAL diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 8b0bebe8d62e..4199b9332979 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -53,6 +53,7 @@ struct async { struct dev_state *ps; struct task_struct *task; unsigned int signr; + unsigned int intf; void *userbuffer; void *userurb; struct urb *urb; @@ -273,23 +274,47 @@ static void async_completed(struct urb *urb) } } -static void destroy_all_async(struct dev_state *ps) +static void destroy_async (struct dev_state *ps, struct list_head *list) { - struct async *as; - unsigned long flags; + struct async *as; + unsigned long flags; - spin_lock_irqsave(&ps->lock, flags); - while (!list_empty(&ps->async_pending)) { - as = list_entry(ps->async_pending.next, struct async, asynclist); - list_del_init(&as->asynclist); - spin_unlock_irqrestore(&ps->lock, flags); + spin_lock_irqsave(&ps->lock, flags); + while (!list_empty(list)) { + as = list_entry(list->next, struct async, asynclist); + list_del_init(&as->asynclist); + spin_unlock_irqrestore(&ps->lock, flags); /* usb_unlink_urb calls the completion handler with status == -ENOENT */ - usb_unlink_urb(as->urb); - spin_lock_irqsave(&ps->lock, flags); - } - spin_unlock_irqrestore(&ps->lock, flags); - while ((as = async_getcompleted(ps))) - free_async(as); + usb_unlink_urb(as->urb); + spin_lock_irqsave(&ps->lock, flags); + } + spin_unlock_irqrestore(&ps->lock, flags); + while ((as = async_getcompleted(ps))) + free_async(as); +} + +static void destroy_async_on_interface (struct dev_state *ps, unsigned int intf) +{ + struct async *as; + struct list_head *p, hitlist; + unsigned long flags; + + INIT_LIST_HEAD(&hitlist); + spin_lock_irqsave(&ps->lock, flags); + for (p = ps->async_pending.next; p != &ps->async_pending; ) { + as = list_entry(p, struct async, asynclist); + p = p->next; + + if (as->intf == intf) + list_move_tail(&as->asynclist, &hitlist); + } + spin_unlock_irqrestore(&ps->lock, flags); + destroy_async(ps, &hitlist); +} + +extern __inline__ void destroy_all_async(struct dev_state *ps) +{ + destroy_async(ps, &ps->async_pending); } /* @@ -751,7 +776,7 @@ static int proc_submiturb(struct dev_state *ps, void *arg) struct async *as; struct usb_ctrlrequest *dr = NULL; unsigned int u, totlen, isofrmlen; - int ret, interval = 0; + int ret, interval = 0, intf = -1; if (copy_from_user(&uurb, arg, sizeof(uurb))) return -EFAULT; @@ -763,9 +788,9 @@ static int proc_submiturb(struct dev_state *ps, void *arg) if (uurb.signr != 0 && (uurb.signr < SIGRTMIN || uurb.signr > SIGRTMAX)) return -EINVAL; if (!(uurb.type == USBDEVFS_URB_TYPE_CONTROL && (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) { - if ((ret = findintfep(ps->dev, uurb.endpoint)) < 0) - return ret; - if ((ret = checkintf(ps, ret))) + if ((intf = findintfep(ps->dev, uurb.endpoint)) < 0) + return intf; + if ((ret = checkintf(ps, intf))) return ret; } switch(uurb.type) { @@ -889,6 +914,7 @@ static int proc_submiturb(struct dev_state *ps, void *arg) else as->userbuffer = NULL; as->signr = uurb.signr; + as->intf = intf; as->task = current; if (!(uurb.endpoint & USB_DIR_IN)) { if (copy_from_user(as->urb->transfer_buffer, uurb.buffer, as->urb->transfer_buffer_length)) { @@ -1035,7 +1061,10 @@ static int proc_releaseinterface(struct dev_state *ps, void *arg) return -EFAULT; if ((ret = findintfif(ps->dev, intf)) < 0) return ret; - return releaseintf(ps, intf); + if ((ret = releaseintf(ps, intf)) < 0) + return ret; + destroy_async_on_interface (ps, intf); + return 0; } static int proc_ioctl (struct dev_state *ps, void *arg) diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c index 11d4bac4a19c..f4bc1a75248f 100644 --- a/drivers/usb/host/ohci-mem.c +++ b/drivers/usb/host/ohci-mem.c @@ -14,7 +14,8 @@ * - data used only by the HCD ... kmalloc is fine * - async and periodic schedules, shared by HC and HCD ... these * need to use pci_pool or pci_alloc_consistent - * - driver buffers, read/written by HC ... single shot DMA mapped + * - driver buffers, read/written by HC ... the hcd glue or the + * device driver provides us with dma addresses * * There's also PCI "register" data, which is memory mapped. * No memory seen by this driver is pagable. @@ -41,95 +42,6 @@ static void ohci_hcd_free (struct usb_hcd *hcd) /*-------------------------------------------------------------------------*/ -/* Recover a TD/ED using its collision chain */ -static inline void * -dma_to_ed_td (struct hash_list_t * entry, dma_addr_t dma) -{ - struct hash_t * scan = entry->head; - while (scan && scan->dma != dma) - scan = scan->next; - return scan ? scan->virt : 0; -} - -static inline struct td * -dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma) -{ - td_dma &= TD_MASK; - return (struct td *) dma_to_ed_td(&(hc->td_hash [TD_HASH_FUNC(td_dma)]), - td_dma); -} - -// FIXME: when updating the hashtables this way, mem_flags is unusable... - -/* Add a hash entry for a TD/ED; return true on success */ -static inline int -hash_add_ed_td ( - struct hash_list_t *entry, - void *virt, - dma_addr_t dma, - int mem_flags -) -{ - struct hash_t * scan; - - scan = (struct hash_t *) kmalloc (sizeof *scan, mem_flags); - if (!scan) - return 0; - - if (!entry->tail) { - entry->head = entry->tail = scan; - } else { - entry->tail->next = scan; - entry->tail = scan; - } - - scan->virt = virt; - scan->dma = dma; - scan->next = NULL; - return 1; -} - -static inline int -hash_add_td (struct ohci_hcd *hc, struct td *td, int mem_flags) -{ - return hash_add_ed_td (&(hc->td_hash [TD_HASH_FUNC (td->td_dma)]), - td, td->td_dma, mem_flags); -} - - -static inline void -hash_free_ed_td (struct hash_list_t *entry, void *virt) -{ - struct hash_t *scan, *prev; - scan = prev = entry->head; - - // Find and unlink hash entry - while (scan && scan->virt != virt) { - prev = scan; - scan = scan->next; - } - if (scan) { - if (scan == entry->head) { - if (entry->head == entry->tail) - entry->head = entry->tail = NULL; - else - entry->head = scan->next; - } else if (scan == entry->tail) { - entry->tail = prev; - prev->next = NULL; - } else - prev->next = scan->next; - kfree(scan); - } -} - -static inline void -hash_free_td (struct ohci_hcd *hc, struct td * td) -{ - hash_free_ed_td (&(hc->td_hash[TD_HASH_FUNC(td->td_dma)]), td); -} - - static int ohci_mem_init (struct ohci_hcd *ohci) { ohci->td_cache = pci_pool_create ("ohci_td", ohci->hcd.pdev, @@ -161,6 +73,21 @@ static void ohci_mem_cleanup (struct ohci_hcd *ohci) } } +/*-------------------------------------------------------------------------*/ + +/* ohci "done list" processing needs this mapping */ +static inline struct td * +dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma) +{ + struct td *td; + + td_dma &= TD_MASK; + td = hc->td_hash [TD_HASH_FUNC(td_dma)]; + while (td && td->td_dma != td_dma) + td = td->td_hash; + return td; +} + /* TDs ... */ static struct td * td_alloc (struct ohci_hcd *hc, int mem_flags) @@ -170,12 +97,17 @@ td_alloc (struct ohci_hcd *hc, int mem_flags) td = pci_pool_alloc (hc->td_cache, mem_flags, &dma); if (td) { + int hash; + + /* in case hc fetches it, make it look dead */ + memset (td, 0, sizeof *td); + td->hwNextTD = cpu_to_le32 (dma); td->td_dma = dma; + /* hash it for later reverse mapping */ - if (!hash_add_td (hc, td, mem_flags)) { - pci_pool_free (hc->td_cache, td, dma); - return NULL; - } + hash = TD_HASH_FUNC (dma); + td->td_hash = hc->td_hash [hash]; + hc->td_hash [hash] = td; } return td; } @@ -183,10 +115,18 @@ td_alloc (struct ohci_hcd *hc, int mem_flags) static void td_free (struct ohci_hcd *hc, struct td *td) { - hash_free_td (hc, td); + struct td **prev = &hc->td_hash [TD_HASH_FUNC (td->td_dma)]; + + while (*prev && *prev != td) + prev = &(*prev)->td_hash; + if (*prev) + *prev = td->td_hash; + else + dev_dbg (*hc->hcd.controller, "bad hash for td %p\n", td); pci_pool_free (hc->td_cache, td, td->td_dma); } +/*-------------------------------------------------------------------------*/ /* EDs ... */ static struct ed * diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index ed25b8c0588d..5c2e08a4027e 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -111,6 +111,7 @@ struct td { /* rest are purely for the driver's use */ __u8 index; struct ed *ed; + struct td *td_hash; /* dma-->td hashtable */ struct td *next_dl_td; struct urb *urb; @@ -320,23 +321,9 @@ typedef struct urb_priv { #define URB_DEL 1 - -/* Hash struct used for TD/ED hashing */ -struct hash_t { - void *virt; - dma_addr_t dma; - struct hash_t *next; // chaining for collision cases -}; - -/* List of TD/ED hash entries */ -struct hash_list_t { - struct hash_t *head; - struct hash_t *tail; -}; - #define TD_HASH_SIZE 64 /* power'o'two */ - -#define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 5)) % TD_HASH_SIZE) +// sizeof (struct td) ~= 64 == 2^6 ... +#define TD_HASH_FUNC(td_dma) ((td_dma ^ (td_dma >> 6)) % TD_HASH_SIZE) /* @@ -373,7 +360,7 @@ struct ohci_hcd { */ struct pci_pool *td_cache; struct pci_pool *ed_cache; - struct hash_list_t td_hash [TD_HASH_SIZE]; + struct td *td_hash [TD_HASH_SIZE]; /* * driver state diff --git a/drivers/usb/media/Kconfig b/drivers/usb/media/Kconfig index b002ead8c4be..a179a8649c63 100644 --- a/drivers/usb/media/Kconfig +++ b/drivers/usb/media/Kconfig @@ -120,15 +120,26 @@ config USB_PWC tristate "USB Philips Cameras" depends on USB && VIDEO_DEV ---help--- - Say Y or M here if you want to use one of these Philips USB webcams: - PCA645, PCA646, PCVC675, PCVC680, PCVC690, PCVC730, PCVC740, or - the Askey VC010. The PCA635, PCVC665 and PCVC720 are not supported - by this driver and never will be. - - This driver has an optional plugin, which is distributed as a binary - module only. It contains code that allow you to use higher - resolutions and framerates but may not be distributed as source. - But even without this plugin you can these cams for most + Say Y or M here if you want to use one of these Philips & OEM + webcams: + * Philips PCA645, PCA646 + * Philips PCVC675, PCVC680, PCVC690 + * Philips PCVC730, PCVC740, PCVC750 + * Askey VC010 + * Logitech QuickCam Pro 3000, 4000, 'Zoom' and 'Notebook' + * Samsung MPC-C10, MPC-C30 + * Creative Webcam 5 + * SOTECT Afina Eye + * Visionite VCS-UC300, VCS-UM100 + + The PCA635, PCVC665 and PCVC720 are not supported by this driver + and never will be, but the 665 and 720 are supported by other + drivers. + + This driver has an optional plugin (called PWCX), which is + distributed as a binary module only. It contains code that allow you + to use higher resolutions and framerates but may not be distributed + as source. But even without this plugin you can these cams for most applications. See <file:Documentation/usb/philips.txt> for more information and diff --git a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c index 0f8f81143f61..6eb6b2f3f828 100644 --- a/drivers/usb/media/ov511.c +++ b/drivers/usb/media/ov511.c @@ -60,7 +60,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.62 for Linux 2.5" +#define DRIVER_VERSION "v1.63 for Linux 2.5" #define EMAIL "mark@alpha.dyndns.org" #define DRIVER_AUTHOR "Mark McClelland <mark@alpha.dyndns.org> & Bret Wallach \ & Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \ @@ -121,6 +121,7 @@ static int backlight; static int unit_video[OV511_MAX_UNIT_VIDEO]; static int remove_zeros; static int mirror; +static int ov518_color; MODULE_PARM(autobright, "i"); MODULE_PARM_DESC(autobright, "Sensor automatically changes brightness"); @@ -193,6 +194,8 @@ MODULE_PARM_DESC(remove_zeros, "Remove zero-padding from uncompressed incoming data"); MODULE_PARM(mirror, "i"); MODULE_PARM_DESC(mirror, "Reverse image horizontally"); +MODULE_PARM(ov518_color, "i"); +MODULE_PARM_DESC(ov518_color, "Enable OV518 color (experimental)"); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); @@ -259,6 +262,7 @@ static struct symbolic_list camlist[] = { { 100, "Lifeview RoboCam" }, { 102, "AverMedia InterCam Elite" }, { 112, "MediaForte MV300" }, /* or OV7110 evaluation kit */ + { 134, "Ezonics EZCam II" }, { 192, "Webeye 2000B" }, { 253, "Alpha Vision Tech. AlphaCam SE" }, { -1, NULL } @@ -293,6 +297,7 @@ static struct symbolic_list brglist[] = { { -1, NULL } }; +#if defined(CONFIG_VIDEO_PROC_FS) static struct symbolic_list senlist[] = { { SEN_OV76BE, "OV76BE" }, { SEN_OV7610, "OV7610" }, @@ -308,6 +313,7 @@ static struct symbolic_list senlist[] = { { SEN_SAA7111A, "SAA7111A" }, { -1, NULL } }; +#endif /* URB error codes: */ static struct symbolic_list urb_errlist[] = { @@ -321,20 +327,6 @@ static struct symbolic_list urb_errlist[] = { }; /********************************************************************** - * Prototypes - **********************************************************************/ - -static void ov51x_clear_snapshot(struct usb_ov511 *); -static inline int sensor_get_picture(struct usb_ov511 *, - struct video_picture *); -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) -static int sensor_get_exposure(struct usb_ov511 *, unsigned char *); -static int ov51x_control_ioctl(struct inode *, struct file *, unsigned int, - unsigned long); -static int ov51x_check_snapshot(struct usb_ov511 *); -#endif - -/********************************************************************** * Memory management **********************************************************************/ @@ -396,11 +388,19 @@ rvfree(void *mem, unsigned long size) * Based on the CPiA driver version 0.7.4 -claudio **********************************************************************/ -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) +#if defined(CONFIG_VIDEO_PROC_FS) static struct proc_dir_entry *ov511_proc_entry = NULL; extern struct proc_dir_entry *video_proc_entry; +/* Prototypes */ +static void ov51x_clear_snapshot(struct usb_ov511 *); +static int sensor_get_picture(struct usb_ov511 *, struct video_picture *); +static int sensor_get_exposure(struct usb_ov511 *, unsigned char *); +static int ov51x_check_snapshot(struct usb_ov511 *); +static int ov51x_control_ioctl(struct inode *, struct file *, unsigned int, + unsigned long); + static struct file_operations ov511_control_fops = { .ioctl = ov51x_control_ioctl, }; @@ -460,6 +460,8 @@ ov511_read_proc_info(char *page, char **start, off_t off, int count, int *eof, symbolic(senlist, ov->sensor)); out += sprintf(out, "packet_size : %d\n", ov->packet_size); out += sprintf(out, "framebuffer : 0x%p\n", ov->fbuf); + out += sprintf(out, "packet_numbering: %d\n", ov->packet_numbering); + out += sprintf(out, "topology : %s\n", ov->usb_path); len = out - page; len -= off; @@ -637,7 +639,12 @@ proc_ov511_destroy(void) remove_proc_entry("ov511", video_proc_entry); } -#endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */ +#else +static inline void create_proc_ov511_cam(struct usb_ov511 *ov) { } +static inline void destroy_proc_ov511_cam(struct usb_ov511 *ov) { } +static inline void proc_ov511_create(void) { } +static inline void proc_ov511_destroy(void) { } +#endif /* #ifdef CONFIG_VIDEO_PROC_FS */ /********************************************************************** * @@ -1116,7 +1123,7 @@ i2c_w_mask(struct usb_ov511 *ov, * when calling this. This should not be called from outside the i2c I/O * functions. */ -static inline int +static int i2c_set_slave_internal(struct usb_ov511 *ov, unsigned char slave) { int rc; @@ -1357,7 +1364,7 @@ ov51x_clear_snapshot(struct usb_ov511 *ov) } } -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) +#if defined(CONFIG_VIDEO_PROC_FS) /* Checks the status of the snapshot button. Returns 1 if it was pressed since * it was last cleared, and zero in all other cases (including errors) */ static int @@ -1970,7 +1977,7 @@ sensor_get_hue(struct usb_ov511 *ov, unsigned short *val) /* -------------------------------------------------------------------------- */ -static inline int +static int sensor_set_picture(struct usb_ov511 *ov, struct video_picture *p) { int rc; @@ -2001,7 +2008,7 @@ sensor_set_picture(struct usb_ov511 *ov, struct video_picture *p) return 0; } -static inline int +static int sensor_get_picture(struct usb_ov511 *ov, struct video_picture *p) { int rc; @@ -2032,7 +2039,7 @@ sensor_get_picture(struct usb_ov511 *ov, struct video_picture *p) return 0; } -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) +#if defined(CONFIG_VIDEO_PROC_FS) // FIXME: Exposure range is only 0x00-0x7f in interlace mode /* Sets current exposure for sensor. This only has an effect if auto-exposure * is off */ @@ -2117,7 +2124,7 @@ sensor_get_exposure(struct usb_ov511 *ov, unsigned char *val) #endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */ /* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */ -static inline void +static void ov51x_led_control(struct usb_ov511 *ov, int enable) { PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); @@ -2198,7 +2205,7 @@ sensor_set_light_freq(struct usb_ov511 *ov, int freq) * Unsupported: KS0127, KS0127B, SAA7111A * Returns: 0 for success */ -static inline int +static int sensor_set_banding_filter(struct usb_ov511 *ov, int enable) { int rc; @@ -2226,7 +2233,7 @@ sensor_set_banding_filter(struct usb_ov511 *ov, int enable) * Unsupported: KS0127, KS0127B, SAA7111A * Returns: 0 for success */ -static inline int +static int sensor_set_auto_brightness(struct usb_ov511 *ov, int enable) { int rc; @@ -2254,7 +2261,7 @@ sensor_set_auto_brightness(struct usb_ov511 *ov, int enable) * Unsupported: KS0127, KS0127B, SAA7111A * Returns: 0 for success */ -static inline int +static int sensor_set_auto_exposure(struct usb_ov511 *ov, int enable) { PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); @@ -2333,7 +2340,7 @@ sensor_set_backlight(struct usb_ov511 *ov, int enable) return 0; } -static inline int +static int sensor_set_mirror(struct usb_ov511 *ov, int enable) { PDEBUG(4, " (%s)", enable ? "turn on" : "turn off"); @@ -2434,7 +2441,7 @@ mode_init_ov_sensor_regs(struct usb_ov511 *ov, int width, int height, i2c_w(ov, 0x14, qvga?0x24:0x04); break; case SEN_OV6630: - i2c_w(ov, 0x14, qvga?0xa4:0x84); + i2c_w(ov, 0x14, qvga?0xa0:0x80); break; default: err("Invalid sensor"); @@ -2448,13 +2455,33 @@ mode_init_ov_sensor_regs(struct usb_ov511 *ov, int width, int height, /* these aren't valid on the OV6620/OV7620/6630? */ i2c_w_mask(ov, 0x0e, 0x40, 0x40); } - i2c_w_mask(ov, 0x13, 0x20, 0x20); + + if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518 + && ov518_color) { + i2c_w_mask(ov, 0x12, 0x00, 0x10); + i2c_w_mask(ov, 0x13, 0x00, 0x20); + } else { + i2c_w_mask(ov, 0x13, 0x20, 0x20); + } } else { if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) { /* not valid on the OV6620/OV7620/6630? */ i2c_w_mask(ov, 0x0e, 0x00, 0x40); } - i2c_w_mask(ov, 0x13, 0x00, 0x20); + + /* The OV518 needs special treatment. Although both the OV518 + * and the OV6630 support a 16-bit video bus, only the 8 bit Y + * bus is actually used. The UV bus is tied to ground. + * Therefore, the OV6630 needs to be in 8-bit multiplexed + * output mode */ + + if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518 + && ov518_color) { + i2c_w_mask(ov, 0x12, 0x10, 0x10); + i2c_w_mask(ov, 0x13, 0x20, 0x20); + } else { + i2c_w_mask(ov, 0x13, 0x00, 0x20); + } } /******** Clock programming ********/ @@ -2781,8 +2808,29 @@ ov518_mode_init_regs(struct usb_ov511 *ov, reg_w(ov, 0x3d, 0); reg_w(ov, 0x3e, 0); - reg_w(ov, 0x28, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80); - reg_w(ov, 0x38, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80); + if (ov->bridge == BRG_OV518 && ov518_color) { + /* OV518 needs U and V swapped */ + i2c_w_mask(ov, 0x15, 0x00, 0x01); + + if (mode == VIDEO_PALETTE_GREY) { + /* Set 16-bit input format (UV data are ignored) */ + reg_w_mask(ov, 0x20, 0x00, 0x08); + + /* Set 8-bit (4:0:0) output format */ + reg_w_mask(ov, 0x28, 0x00, 0xf0); + reg_w_mask(ov, 0x38, 0x00, 0xf0); + } else { + /* Set 8-bit (YVYU) input format */ + reg_w_mask(ov, 0x20, 0x08, 0x08); + + /* Set 12-bit (4:2:0) output format */ + reg_w_mask(ov, 0x28, 0x80, 0xf0); + reg_w_mask(ov, 0x38, 0x80, 0xf0); + } + } else { + reg_w(ov, 0x28, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80); + reg_w(ov, 0x38, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80); + } hsegs = width / 16; vsegs = height / 4; @@ -3074,7 +3122,7 @@ make_8x8(unsigned char *pIn, unsigned char *pOut, int w) } /* - * For RAW BW (YUV400) images, data shows up in 256 byte segments. + * For RAW BW (YUV 4:0:0) images, data show up in 256 byte segments. * The segments represent 4 squares of 8x8 pixels as follows: * * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199 @@ -3105,7 +3153,7 @@ yuv400raw_to_yuv400p(struct ov511_frame *frame, } /* - * For YUV4:2:0 images, the data shows up in 384 byte segments. + * For YUV 4:2:0 images, the data show up in 384 byte segments. * The first 64 bytes of each segment are U, the next 64 are V. The U and * V are arranged as follows: * @@ -3124,8 +3172,8 @@ yuv400raw_to_yuv400p(struct ov511_frame *frame, * ... ... ... * 56 57 ... 63 120 121 ... 127 ... 248 249 ... 255 * - * Note that the U and V data in one segment represents a 16 x 16 pixel - * area, but the Y data represents a 32 x 8 pixel area. If the width is not an + * Note that the U and V data in one segment represent a 16 x 16 pixel + * area, but the Y data represent a 32 x 8 pixel area. If the width is not an * even multiple of 32, the extra 8x8 blocks within a 32x8 block belong to the * next horizontal stripe. * @@ -3133,7 +3181,7 @@ yuv400raw_to_yuv400p(struct ov511_frame *frame, * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480 * this puts the data on the standard output and can be analyzed with the * parseppm.c utility I wrote. That's a much faster way for figuring out how - * this data is scrambled. + * these data are scrambled. */ /* Converts from raw, uncompressed segments at pIn0 to a YUV420P frame at pOut0. @@ -4285,7 +4333,6 @@ ov51x_v4l1_close(struct inode *inode, struct file *file) } file->private_data = NULL; - return 0; } @@ -4752,7 +4799,7 @@ ov51x_v4l1_ioctl(struct inode *inode, struct file *file, return rc; } -static inline int +static int ov51x_v4l1_read(struct file *file, char *buf, size_t cnt, loff_t *ppos) { struct video_device *vdev = file->private_data; @@ -4882,7 +4929,7 @@ restart: PDEBUG(4, "{copy} count used=%ld, new bytes_read=%ld", count, frame->bytes_read); - /* If all data has been read... */ + /* If all data have been read... */ if (frame->bytes_read >= get_frame_length(frame)) { frame->bytes_read = 0; @@ -4966,7 +5013,7 @@ static struct video_device vdev_template = { .fops = &ov511_fops, }; -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) +#if defined(CONFIG_VIDEO_PROC_FS) static int ov51x_control_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long ularg) @@ -5453,14 +5500,12 @@ ov6xx0_configure(struct usb_ov511 *ov) { OV511_I2C_BUS, 0x4f, 0x04 }, // Do 50-53 have any effect? // Toggle 0x12[2] off and on here? - { OV511_DONE_BUS, 0x0, 0x00 }, + { OV511_DONE_BUS, 0x0, 0x00 }, /* END MARKER */ }; - /* This chip is undocumented so many of these are guesses. OK=verified, - * A=Added since 6620, U=unknown function (not a 6620 reg) */ static struct ov511_regvals aRegvalsNorm6x30[] = { /*OK*/ { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */ - /*00?*/ { OV511_I2C_BUS, 0x11, 0x01 }, + { OV511_I2C_BUS, 0x11, 0x00 }, /*OK*/ { OV511_I2C_BUS, 0x03, 0x60 }, /*0A?*/ { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */ { OV511_I2C_BUS, 0x07, 0xa8 }, @@ -5468,16 +5513,8 @@ ov6xx0_configure(struct usb_ov511 *ov) /*OK*/ { OV511_I2C_BUS, 0x0c, 0x24 }, /*OK*/ { OV511_I2C_BUS, 0x0d, 0x24 }, /*A*/ { OV511_I2C_BUS, 0x0e, 0x20 }, - -// /*24?*/ { OV511_I2C_BUS, 0x12, 0x28 }, /* Enable AGC */ -// { OV511_I2C_BUS, 0x12, 0x24 }, /* Enable AGC */ - -// /*A*/ { OV511_I2C_BUS, 0x13, 0x21 }, -// /*A*/ { OV511_I2C_BUS, 0x13, 0x25 }, /* Tristate Y and UV busses */ - // /*04?*/ { OV511_I2C_BUS, 0x14, 0x80 }, - /* 0x16: 0x06 helps frame stability with moving objects */ - /*03?*/ { OV511_I2C_BUS, 0x16, 0x06 }, + { OV511_I2C_BUS, 0x16, 0x03 }, // /*OK*/ { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */ // 21 & 22? The suggested values look wrong. Go with default /*A*/ { OV511_I2C_BUS, 0x23, 0xc0 }, @@ -5490,49 +5527,34 @@ ov6xx0_configure(struct usb_ov511 *ov) /*OK*/ { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */ // /*OK*/ { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */ -// /*U*/ { OV511_I2C_BUS, 0x2c, 0xa0 }, { OV511_I2C_BUS, 0x2d, 0x99 }, // /*A*/ { OV511_I2C_BUS, 0x33, 0x26 }, // Reserved bits on 6620 // /*d2?*/ { OV511_I2C_BUS, 0x34, 0x03 }, /* Max A/D range */ -// /*U*/ { OV511_I2C_BUS, 0x36, 0x8f }, // May not be necessary -// /*U*/ { OV511_I2C_BUS, 0x37, 0x80 }, // May not be necessary // /*8b?*/ { OV511_I2C_BUS, 0x38, 0x83 }, // /*40?*/ { OV511_I2C_BUS, 0x39, 0xc0 }, // 6630 adds bit 7 // { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */ // { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */ // { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */ - /*OK*/ { OV511_I2C_BUS, 0x3d, 0x80 }, + { OV511_I2C_BUS, 0x3d, 0x80 }, // /*A*/ { OV511_I2C_BUS, 0x3f, 0x0e }, -// /*U*/ { OV511_I2C_BUS, 0x40, 0x00 }, -// /*U*/ { OV511_I2C_BUS, 0x41, 0x00 }, -// /*U*/ { OV511_I2C_BUS, 0x42, 0x80 }, -// /*U*/ { OV511_I2C_BUS, 0x43, 0x3f }, -// /*U*/ { OV511_I2C_BUS, 0x44, 0x80 }, -// /*U*/ { OV511_I2C_BUS, 0x45, 0x20 }, -// /*U*/ { OV511_I2C_BUS, 0x46, 0x20 }, -// /*U*/ { OV511_I2C_BUS, 0x47, 0x80 }, -// /*U*/ { OV511_I2C_BUS, 0x48, 0x7f }, -// /*U*/ { OV511_I2C_BUS, 0x49, 0x00 }, /* These next two registers (0x4a, 0x4b) are undocumented. They * control the color balance */ // /*OK?*/ { OV511_I2C_BUS, 0x4a, 0x80 }, // Check these // /*OK?*/ { OV511_I2C_BUS, 0x4b, 0x80 }, -// /*U*/ { OV511_I2C_BUS, 0x4c, 0xd0 }, - /*d2?*/ { OV511_I2C_BUS, 0x4d, 0x10 }, /* This reduces noise a bit */ + { OV511_I2C_BUS, 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */ /*c1?*/ { OV511_I2C_BUS, 0x4e, 0x40 }, - /*04?*/ { OV511_I2C_BUS, 0x4f, 0x07 }, -// /*U*/ { OV511_I2C_BUS, 0x50, 0xff }, - /*U*/ { OV511_I2C_BUS, 0x54, 0x23 }, -// /*U*/ { OV511_I2C_BUS, 0x55, 0xff }, -// /*U*/ { OV511_I2C_BUS, 0x56, 0x12 }, - /*U*/ { OV511_I2C_BUS, 0x57, 0x81 }, -// /*U*/ { OV511_I2C_BUS, 0x58, 0x75 }, - /*U*/ { OV511_I2C_BUS, 0x59, 0x01 }, - /*U*/ { OV511_I2C_BUS, 0x5a, 0x2c }, - /*U*/ { OV511_I2C_BUS, 0x5b, 0x0f }, -// /*U*/ { OV511_I2C_BUS, 0x5c, 0x10 }, - { OV511_DONE_BUS, 0x0, 0x00 }, + + /* UV average mode, color killer: strongest */ + { OV511_I2C_BUS, 0x4f, 0x07 }, + + { OV511_I2C_BUS, 0x54, 0x23 }, /* Max AGC gain: 18dB */ + { OV511_I2C_BUS, 0x57, 0x81 }, /* (default) */ + { OV511_I2C_BUS, 0x59, 0x01 }, /* AGC dark current comp: +1 */ + { OV511_I2C_BUS, 0x5a, 0x2c }, /* (undocumented) */ + { OV511_I2C_BUS, 0x5b, 0x0f }, /* AWB chrominance levels */ +// { OV511_I2C_BUS, 0x5c, 0x10 }, + { OV511_DONE_BUS, 0x0, 0x00 }, /* END MARKER */ }; PDEBUG(4, "starting sensor configuration"); @@ -5553,16 +5575,19 @@ ov6xx0_configure(struct usb_ov511 *ov) return -1; } - if ((rc & 3) == 0) + if ((rc & 3) == 0) { ov->sensor = SEN_OV6630; - else if ((rc & 3) == 1) + info("Sensor is an OV6630"); + } else if ((rc & 3) == 1) { ov->sensor = SEN_OV6620; - else if ((rc & 3) == 2) + info("Sensor is an OV6620"); + } else if ((rc & 3) == 2) { ov->sensor = SEN_OV6630; - else if ((rc & 3) == 3) + info("Sensor is an OV6630AE"); + } else if ((rc & 3) == 3) { ov->sensor = SEN_OV6630; - - info("Sensor is an %s", symbolic(senlist, ov->sensor)); + info("Sensor is an OV6630AF"); + } /* Set sensor-specific vars */ ov->maxwidth = 352; @@ -5922,7 +5947,7 @@ ov518_configure(struct usb_ov511 *ov) { OV511_REG_BUS, 0x5d, 0x03 }, { OV511_REG_BUS, 0x24, 0x9f }, { OV511_REG_BUS, 0x25, 0x90 }, - { OV511_REG_BUS, 0x20, 0x00 }, /* Was 0x08 */ + { OV511_REG_BUS, 0x20, 0x00 }, { OV511_REG_BUS, 0x51, 0x04 }, { OV511_REG_BUS, 0x71, 0x19 }, { OV511_DONE_BUS, 0x0, 0x00 }, @@ -5935,7 +5960,7 @@ ov518_configure(struct usb_ov511 *ov) { OV511_REG_BUS, 0x5d, 0x03 }, { OV511_REG_BUS, 0x24, 0x9f }, { OV511_REG_BUS, 0x25, 0x90 }, - { OV511_REG_BUS, 0x20, 0x60 }, /* Was 0x08 */ + { OV511_REG_BUS, 0x20, 0x60 }, { OV511_REG_BUS, 0x51, 0x02 }, { OV511_REG_BUS, 0x71, 0x19 }, { OV511_REG_BUS, 0x40, 0xff }, @@ -6151,6 +6176,11 @@ ov51x_probe(struct usb_interface *intf, ov->buf_state = BUF_NOT_ALLOCATED; + if (usb_make_path(dev, ov->usb_path, OV511_USB_PATH_LEN) < 0) { + err("usb_make_path error"); + goto error_dealloc; + } + /* Allocate control transfer buffer. */ /* Must be kmalloc()'ed, for DMA compatibility */ ov->cbuf = kmalloc(OV511_CBUF_SIZE, GFP_KERNEL); @@ -6212,20 +6242,16 @@ ov51x_probe(struct usb_interface *intf, goto error; } - info("Device registered on minor %d", ov->vdev.minor); + info("Device at %s registered to minor %d", ov->usb_path, + ov->vdev.minor); -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) create_proc_ov511_cam(ov); -#endif dev_set_drvdata (&intf->dev, ov); - return 0; + return 0; error: -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) - /* Safe to call even if entry doesn't exist */ destroy_proc_ov511_cam(ov); -#endif if (ov->cbuf) { down(&ov->cbuf_lock); @@ -6274,12 +6300,9 @@ ov51x_disconnect(struct usb_interface *intf) wake_up_interruptible(&ov->wq); ov->streaming = 0; - ov51x_unlink_isoc(ov); -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) destroy_proc_ov511_cam(ov); -#endif ov->dev = NULL; @@ -6396,9 +6419,7 @@ ov511_deregister_decomp_module(int ov518, int mmx) static int __init usb_ov511_init(void) { -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) proc_ov511_create(); -#endif if (usb_register(&ov511_driver) < 0) return -1; @@ -6414,9 +6435,7 @@ usb_ov511_exit(void) usb_deregister(&ov511_driver); info("driver deregistered"); -#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS) proc_ov511_destroy(); -#endif } module_init(usb_ov511_init); diff --git a/drivers/usb/media/ov511.h b/drivers/usb/media/ov511.h index 9fa16de5bb31..347015b72210 100644 --- a/drivers/usb/media/ov511.h +++ b/drivers/usb/media/ov511.h @@ -253,6 +253,9 @@ /* Control transfers use up to 4 bytes */ #define OV511_CBUF_SIZE 4 +/* Size of usb_make_path() buffer */ +#define OV511_USB_PATH_LEN 64 + /* Bridge types */ enum { BRG_UNKNOWN, @@ -450,6 +453,7 @@ struct usb_ov511 { int customid; char *desc; unsigned char iface; + char usb_path[OV511_USB_PATH_LEN]; /* Determined by sensor type */ int maxwidth; diff --git a/drivers/usb/media/pwc-ctrl.c b/drivers/usb/media/pwc-ctrl.c index 71337853115d..6244117a470f 100644 --- a/drivers/usb/media/pwc-ctrl.c +++ b/drivers/usb/media/pwc-ctrl.c @@ -256,8 +256,10 @@ static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int fra memcpy(buf, pEntry->mode, 3); ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3); - if (ret < 0) + if (ret < 0) { + Debug("Failed to send video command... %d\n", ret); return ret; + } if (pEntry->compressed && pdev->decompressor != NULL) pdev->decompressor->init(pdev->release, buf, pdev->decompress_data); @@ -1103,12 +1105,7 @@ int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) buf[0] = on_value; buf[1] = off_value; - return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), - SET_STATUS_CTL, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - LED_FORMATTER, - pdev->vcinterface, - &buf, 2, HZ / 2); + return SendControlMsg(SET_STATUS_CTL, LED_FORMATTER, 2); } int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value) @@ -1122,13 +1119,7 @@ int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value) return 0; } - ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), - GET_STATUS_CTL, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - LED_FORMATTER, - pdev->vcinterface, - &buf, 2, HZ / 2); - + ret = RecvControlMsg(GET_STATUS_CTL, LED_FORMATTER, 2); if (ret < 0) return ret; *on_value = buf[0] * 100; @@ -1279,7 +1270,6 @@ static inline int pwc_get_dynamic_noise(struct pwc_device *pdev) ret = RecvControlMsg(GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1); if (ret < 0) return ret; -//Debug("pwc_get_dynamic_noise = %d\n", buf); return buf; } @@ -1363,12 +1353,10 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) case VIDIOCPWCPROBE: { - struct pwc_probe probe; + struct pwc_probe *probe = arg; - strcpy(probe.name, pdev->vdev->name); - probe.type = pdev->type; - if (copy_to_user(arg, &probe, sizeof(probe))) - ret = -EFAULT; + strcpy(probe->name, pdev->vdev->name); + probe->type = pdev->type; break; } diff --git a/drivers/usb/media/pwc-if.c b/drivers/usb/media/pwc-if.c index f630ff649fd4..2ceefe446df3 100644 --- a/drivers/usb/media/pwc-if.c +++ b/drivers/usb/media/pwc-if.c @@ -1,6 +1,6 @@ /* Linux driver for Philips webcam USB and Video4Linux interface part. - (C) 1999-2001 Nemosoft Unv. + (C) 1999-2002 Nemosoft Unv. 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 @@ -42,32 +42,31 @@ - Alistar Moire: QuickCam 3000 Pro device/product ID - Tony Hoyle: Creative Labs Webcam 5 device/product ID - Mark Burazin: solving hang in VIDIOCSYNC when camera gets unplugged - - Jk Fang: SOTEC device/product ID + - Jk Fang: SOTEC Afina Eye ID + - Xavier Roche: QuickCam Pro 4000 ID + - Jens Knudsen: QuickCam Zoom ID + - J. Debert: QuickCam for Notebooks ID */ #include <linux/errno.h> #include <linux/init.h> +#include <linux/mm.h> #include <linux/module.h> #include <linux/poll.h> #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/wrapper.h> -#include <linux/mm.h> #include <asm/io.h> #include "pwc.h" #include "pwc-ioctl.h" #include "pwc-uncompress.h" -#if !defined(MAP_NR) -#define MAP_NR(a) virt_to_page(a) -#endif - /* Function prototypes and driver templates */ /* hotplug device table support */ static struct usb_device_id pwc_device_table [] = { - { USB_DEVICE(0x0471, 0x0302) }, + { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */ { USB_DEVICE(0x0471, 0x0303) }, { USB_DEVICE(0x0471, 0x0304) }, { USB_DEVICE(0x0471, 0x0307) }, @@ -76,12 +75,17 @@ static struct usb_device_id pwc_device_table [] = { { USB_DEVICE(0x0471, 0x0310) }, { USB_DEVICE(0x0471, 0x0311) }, { USB_DEVICE(0x0471, 0x0312) }, - { USB_DEVICE(0x069A, 0x0001) }, - { USB_DEVICE(0x046D, 0x08b0) }, - { USB_DEVICE(0x055D, 0x9000) }, + { USB_DEVICE(0x069A, 0x0001) }, /* Askey */ + { USB_DEVICE(0x046D, 0x08b0) }, /* Logitech QuickCam Pro 3000 */ + { USB_DEVICE(0x046D, 0x08b1) }, /* Logitech QuickCam for Notebooks */ + { USB_DEVICE(0x046D, 0x08b2) }, /* Logitech QuickCam Pro 4000 */ + { USB_DEVICE(0x046D, 0x08b3) }, /* Logitech QuickCam Zoom */ + { USB_DEVICE(0x055D, 0x9000) }, /* Samsung */ { USB_DEVICE(0x055D, 0x9001) }, - { USB_DEVICE(0x041E, 0x400C) }, - { USB_DEVICE(0x04CC, 0x8116) }, + { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */ + { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */ + { USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */ + { USB_DEVICE(0x0d81, 0x1900) }, { } }; MODULE_DEVICE_TABLE(usb, pwc_device_table); @@ -106,7 +110,7 @@ static int default_fbufs = 3; /* Default number of frame buffers */ static int default_mbufs = 2; /* Default number of mmap() buffers */ int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX; static int power_save = 0; -static int led_on = 1, led_off = 0; /* defaults to LED that is on while in use */ +static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */ int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */ static struct { int type; @@ -167,7 +171,7 @@ static struct video_device pwc_template = { succeeded. The pwc_device struct links back to both structures. When a device is unplugged while in use it will be removed from the - list of known USB devices; I also de-register as a V4L device, but + list of known USB devices; I also de-register it as a V4L device, but unfortunately I can't free the memory since the struct is still in use by the file descriptor. This free-ing is then deferend until the first opportunity. Crude, but it works. @@ -240,7 +244,7 @@ static int pwc_allocate_buffers(struct pwc_device *pdev) int i; void *kbuf; - Trace(TRACE_MEMORY, "Entering allocate_buffers(%p).\n", pdev); + Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev); if (pdev == NULL) return -ENXIO; @@ -315,7 +319,9 @@ static int pwc_allocate_buffers(struct pwc_device *pdev) for (; i < MAX_IMAGES; i++) pdev->image_ptr[i] = NULL; - Trace(TRACE_MEMORY, "Leaving pwc_allocate_buffers().\n"); + kbuf = NULL; + + Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n"); return 0; } @@ -369,6 +375,7 @@ static void pwc_free_buffers(struct pwc_device *pdev) rvfree(pdev->image_data, default_mbufs * pdev->len_per_image); } pdev->image_data = NULL; + Trace(TRACE_MEMORY, "Leaving free_buffers().\n"); } @@ -570,12 +577,10 @@ static inline void pwc_next_image(struct pwc_device *pdev) pdev->fill_image = (pdev->fill_image + 1) % default_mbufs; } -/* 2001-10-14: The YUV420 is still there, but you can only set it from within - a program (YUV420P being the default) */ +/* 2002-10-11: YUV420P is the only palette remaining. */ static int pwc_set_palette(struct pwc_device *pdev, int pal) { - if ( pal == VIDEO_PALETTE_YUV420 - || pal == VIDEO_PALETTE_YUV420P + if ( pal == VIDEO_PALETTE_YUV420P #if PWC_DEBUG || pal == VIDEO_PALETTE_RAW #endif @@ -613,7 +618,7 @@ static void pwc_isoc_handler(struct urb *urb) } #endif if (urb->status == -ENOENT || urb->status == -ECONNRESET) { - Trace(TRACE_OPEN, "pwc_isoc_handler(): URB unlinked.\n"); + Trace(TRACE_OPEN, "pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a"); return; } if (urb->status != -EINPROGRESS && urb->status != 0) { @@ -686,9 +691,22 @@ static void pwc_isoc_handler(struct urb *urb) #if PWC_DEBUG Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence); #endif - pdev->drop_frames = 2; + pdev->drop_frames += 2; pdev->vframes_error++; } + if ((ptr[0] ^ pdev->vmirror) & 0x01) { + if (ptr[0] & 0x01) + Info("Snapshot button pressed.\n"); + else + Info("Snapshot button released.\n"); + } + if ((ptr[0] ^ pdev->vmirror) & 0x02) { + if (ptr[0] & 0x02) + Info("Image is mirrored.\n"); + else + Info("Image is normal.\n"); + } + pdev->vmirror = ptr[0] & 0x03; /* Sometimes the trailer of the 730 is still sent as a 4 byte packet after a short frame; this condition is filtered out specifically. A 4 byte frame doesn't make sense anyway. @@ -705,7 +723,7 @@ static void pwc_isoc_handler(struct urb *urb) /* In case we were instructed to drop the frame, do so silently. The buffer pointers are not updated either (but the counters are reset below). */ - if (pdev->drop_frames) + if (pdev->drop_frames > 0) pdev->drop_frames--; else { /* Check for underflow first */ @@ -741,17 +759,23 @@ static void pwc_isoc_handler(struct urb *urb) } /* .. flen < last_packet_size */ pdev->vlast_packet_size = flen; } /* ..status == 0 */ -#ifdef PWC_DEBUG +#if PWC_DEBUG /* This is normally not interesting to the user, unless you are really debugging something */ - else - Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst); + else { + static int iso_error = 0; + iso_error++; + if (iso_error < 20) + Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst); + } #endif } if (awake) wake_up_interruptible(&pdev->frameq); urb->dev = pdev->udev; - usb_submit_urb(urb, GFP_ATOMIC); + i = usb_submit_urb(urb, GFP_ATOMIC); + if (i != 0) + Err("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i); } @@ -762,7 +786,6 @@ static int pwc_isoc_init(struct pwc_device *pdev) int i, j, ret; struct usb_host_interface *idesc; - int cur_alt; if (pdev == NULL) return -EFAULT; @@ -770,12 +793,11 @@ static int pwc_isoc_init(struct pwc_device *pdev) return 0; pdev->vsync = 0; udev = pdev->udev; - + /* Get the current alternate interface, adjust packet size */ if (!udev->actconfig) return -EFAULT; - cur_alt = udev->actconfig->interface[0].act_altsetting; - idesc = &udev->actconfig->interface[0].altsetting[cur_alt]; + idesc = &udev->actconfig->interface[0].altsetting[pdev->valternate]; if (!idesc) return -EFAULT; @@ -792,7 +814,13 @@ static int pwc_isoc_init(struct pwc_device *pdev) return -ENFILE; /* Odd error, that should be noticable */ } + /* Set alternate interface */ ret = 0; + Trace(TRACE_OPEN, "Setting alternate interface %d\n", pdev->valternate); + ret = usb_set_interface(pdev->udev, 0, pdev->valternate); + if (ret < 0) + return ret; + for (i = 0; i < MAX_ISO_BUFS; i++) { urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); if (urb == NULL) { @@ -801,6 +829,7 @@ static int pwc_isoc_init(struct pwc_device *pdev) break; } pdev->sbuf[i].urb = urb; + Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb); } if (ret) { /* De-allocate in reverse order */ @@ -812,8 +841,7 @@ static int pwc_isoc_init(struct pwc_device *pdev) } return ret; } - - + /* init URB structure */ for (i = 0; i < MAX_ISO_BUFS; i++) { urb = pdev->sbuf[i].urb; @@ -829,7 +857,7 @@ static int pwc_isoc_init(struct pwc_device *pdev) urb->start_frame = 0; urb->number_of_packets = ISO_FRAMES_PER_DESC; for (j = 0; j < ISO_FRAMES_PER_DESC; j++) { - urb->iso_frame_desc[j].offset = j * pdev->vmax_packet_size; + urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE; urb->iso_frame_desc[j].length = pdev->vmax_packet_size; } } @@ -840,11 +868,12 @@ static int pwc_isoc_init(struct pwc_device *pdev) if (ret) Err("isoc_init() submit_urb %d failed with error %d\n", i, ret); else - Trace(TRACE_OPEN, "pwc_isoc_init(): URB submitted.\n"); + Trace(TRACE_OPEN, "URB 0x%p submitted.\n", pdev->sbuf[i].urb); } - /* data should stream in now */ + /* All is done... */ pdev->iso_init = 1; + Trace(TRACE_OPEN, "<< pwc_isoc_init()\n"); return 0; } @@ -852,21 +881,34 @@ static void pwc_isoc_cleanup(struct pwc_device *pdev) { int i; + Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n"); if (pdev == NULL) return; - if (!pdev->iso_init) - return; + + /* Unlinking ISOC buffers one by one */ + for (i = 0; i < MAX_ISO_BUFS; i++) { + struct urb *urb; + + urb = pdev->sbuf[i].urb; + if (urb != 0) { + if (pdev->iso_init) { + Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb); + usb_unlink_urb(urb); + } + Trace(TRACE_MEMORY, "Freeing URB\n"); + usb_free_urb(urb); + pdev->sbuf[i].urb = NULL; + } + } + /* Stop camera, but only if we are sure the camera is still there */ - if (!pdev->unplugged) + if (!pdev->unplugged) { + Trace(TRACE_OPEN, "Setting alternate interface 0.\n"); usb_set_interface(pdev->udev, 0, 0); - /* Unlinking ISOC buffers one by one */ - for (i = MAX_ISO_BUFS - 1; i >= 0; i--) { - //pdev->sbuf[i].urb->next = NULL; - usb_unlink_urb(pdev->sbuf[i].urb); - usb_free_urb(pdev->sbuf[i].urb); - pdev->sbuf[i].urb = NULL; } + pdev->iso_init = 0; + Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n"); } int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot) @@ -881,11 +923,10 @@ int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_f ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot); if (ret) /* That failed... restore old mode (we know that worked) */ ret = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); - else /* Set (new) alternate interface */ - ret = usb_set_interface(pdev->udev, 0, pdev->valternate); if (!ret) - ret = pwc_isoc_init(pdev); - pdev->drop_frames = 1; /* try to avoid garbage during switch */ + if (pwc_isoc_init(pdev) < 0) + Info("Failed to restart ISOC transfer in pwc_try_video_mode.\n"); + pdev->drop_frames++; /* try to avoid garbage during switch */ return ret; } @@ -921,7 +962,7 @@ static int pwc_video_open(struct inode *inode, struct file *file) struct video_device *vdev = video_devdata(file); struct pwc_device *pdev; - Trace(TRACE_OPEN, "video_open called(0x%p).\n", vdev); + Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev); pdev = (struct pwc_device *)vdev->priv; if (pdev == NULL) @@ -932,10 +973,30 @@ static int pwc_video_open(struct inode *inode, struct file *file) down(&pdev->modlock); if (!pdev->usb_init) { Trace(TRACE_OPEN, "Doing first time initialization.\n"); - /* Reset camera */ - if (usb_set_interface(pdev->udev, 0, 0)) - Info("Failed to set alternate interface to 0.\n"); pdev->usb_init = 1; + + if (pwc_trace & TRACE_OPEN) { + /* Query CMOS sensor type */ + const char *sensor_type = NULL; + + i = pwc_get_cmos_sensor(pdev); + switch(i) { + case -1: /* Unknown, show nothing */; break; + case 0x00: sensor_type = "Hyundai CMOS sensor"; break; + case 0x20: sensor_type = "Sony CCD sensor + TDA8787"; break; + case 0x2E: sensor_type = "Sony CCD sensor + Exas 98L59"; break; + case 0x2F: sensor_type = "Sony CCD sensor + ADI 9804"; break; + case 0x30: sensor_type = "Sharp CCD sensor + TDA8787"; break; + case 0x3E: sensor_type = "Sharp CCD sensor + Exas 98L59"; break; + case 0x3F: sensor_type = "Sharp CCD sensor + ADI 9804"; break; + case 0x40: sensor_type = "UPA 1021 sensor"; break; + case 0x100: sensor_type = "VGA sensor"; break; + case 0x101: sensor_type = "PAL MR sensor"; break; + default: sensor_type = "unknown type of sensor"; break; + } + if (sensor_type != NULL) + Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i); + } } /* Turn on camera */ @@ -1000,12 +1061,6 @@ static int pwc_video_open(struct inode *inode, struct file *file) return i; } - i = usb_set_interface(pdev->udev, 0, pdev->valternate); - if (i) { - Trace(TRACE_OPEN, "Failed to set alternate interface = %d.\n", i); - up(&pdev->modlock); - return -EINVAL; - } i = pwc_isoc_init(pdev); if (i) { Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i); @@ -1023,7 +1078,7 @@ static int pwc_video_open(struct inode *inode, struct file *file) if (pdev->decompressor != NULL) pdev->decompressor->lock(); up(&pdev->modlock); - Trace(TRACE_OPEN, "video_open() returning 0.\n"); + Trace(TRACE_OPEN, "<< video_open() returns 0.\n"); return 0; } @@ -1034,15 +1089,12 @@ static int pwc_video_close(struct inode *inode, struct file *file) struct pwc_device *pdev; int i; - Trace(TRACE_OPEN, "video_close called(0x%p).\n", vdev); + Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev); pdev = (struct pwc_device *)vdev->priv; if (pdev->vopen == 0) Info("video_close() called on closed device?\n"); - /* Free isoc URBs */ - pwc_isoc_cleanup(pdev); - /* Dump statistics, but only if a reasonable amount of frames were processed (to prevent endless log-entries in case of snap-shot programs) @@ -1050,15 +1102,14 @@ static int pwc_video_close(struct inode *inode, struct file *file) if (pdev->vframe_count > 20) Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error); - if (!pdev->unplugged) { - /* Normal close: stop isochronuous and interrupt endpoint */ - Trace(TRACE_OPEN, "Normal close(): setting interface to 0.\n"); - usb_set_interface(pdev->udev, 0, 0); + /* Free isoc URBs, stop camera */ + pwc_isoc_cleanup(pdev); + if (!pdev->unplugged) { /* Turn LEDs off */ if (pwc_set_leds(pdev, 0, 0) < 0) - Info("Failed to set LED on/off time..\n"); - /* Power down camere to save energy */ + Info("Failed to set LED on/off time.\n"); + /* Power down camera to save energy */ if (power_save) { i = pwc_camera_power(pdev, 0); if (i < 0) @@ -1077,6 +1128,7 @@ static int pwc_video_close(struct inode *inode, struct file *file) if (pdev->unplugged) wake_up(&pdev->remove_ok); file->private_data = NULL; + Trace(TRACE_OPEN, "<< video_close()\n"); return 0; } @@ -1514,7 +1566,6 @@ static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size); pdev = vdev->priv; - /* FIXME - audit mmap during a read */ pos = (unsigned long)pdev->image_data; while (size > 0) { page = kvirt_to_pa(pos); @@ -1547,14 +1598,14 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id int vendor_id, product_id, type_id; int i, hint; int video_nr = -1; /* default: use next available device */ - char serial_number[30]; + char serial_number[30], *name; free_mem_leak(); /* Check if we can handle this device */ - Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n", - udev->descriptor.idVendor, udev->descriptor.idProduct, - intf->altsetting->desc.bInterfaceNumber); + Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n", + udev->descriptor.idVendor, udev->descriptor.idProduct, + intf->altsetting->desc.bInterfaceNumber); /* the interfaces are probed one by one. We are only interested in the video interface (0) now. @@ -1570,38 +1621,47 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id switch (product_id) { case 0x0302: Info("Philips PCA645VC USB webcam detected.\n"); + name = "Philips 645 webcam"; type_id = 645; break; case 0x0303: Info("Philips PCA646VC USB webcam detected.\n"); + name = "Philips 646 webcam"; type_id = 646; break; case 0x0304: Info("Askey VC010 type 2 USB webcam detected.\n"); + name = "Askey VC010 webcam"; type_id = 646; break; case 0x0307: Info("Philips PCVC675K (Vesta) USB webcam detected.\n"); + name = "Philips 675 webcam"; type_id = 675; break; case 0x0308: Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n"); + name = "Philips 680 webcam"; type_id = 680; break; case 0x030C: Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n"); + name = "Philips 690 webcam"; type_id = 690; break; case 0x0310: Info("Philips PCVC730K (ToUCam Fun) USB webcam detected.\n"); + name = "Philips 730 webcam"; type_id = 730; break; case 0x0311: Info("Philips PCVC740K (ToUCam Pro) USB webcam detected.\n"); + name = "Philips 740 webcam"; type_id = 740; break; case 0x0312: Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n"); + name = "Philips 750 webcam"; type_id = 750; break; default: @@ -1613,6 +1673,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id switch(product_id) { case 0x0001: Info("Askey VC010 type 1 USB webcam detected.\n"); + name = "Askey VC010 webcam"; type_id = 645; break; default: @@ -1623,9 +1684,25 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id else if (vendor_id == 0x046d) { switch(product_id) { case 0x08b0: - Info("Logitech QuickCam 3000 Pro detected.\n"); + Info("Logitech QuickCam Pro 3000 USB webcam detected.\n"); + name = "Logitech QuickCam Pro 3000"; type_id = 730; - break; + break; + case 0x08b1: + Info("Logitech QuickCam for Noteboos USB webcam detected.\n"); + name = "Logitech QuickCam Notebook"; + type_id = 740; /* ?? unknown sensor */ + break; + case 0x08b2: + Info("Logitech QuickCam 4000 Pro USB webcam detected.\n"); + name = "Logitech QuickCam Pro 4000"; + type_id = 740; /* CCD sensor */ + break; + case 0x08b3: + Info("Logitech QuickCam Zoom USB webcam detected.\n"); + name = "Logitech QuickCam Zoom"; + type_id = 740; /* ?? unknown sensor */ + break; default: return -ENODEV; break; @@ -1639,10 +1716,12 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id switch(product_id) { case 0x9000: Info("Samsung MPC-C10 USB webcam detected.\n"); + name = "Samsung MPC-C10"; type_id = 675; break; case 0x9001: Info("Samsung MPC-C30 USB webcam detected.\n"); + name = "Samsung MPC-C30"; type_id = 675; break; default: @@ -1654,6 +1733,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id switch(product_id) { case 0x400c: Info("Creative Labs Webcam 5 detected.\n"); + name = "Creative Labs Webcam 5"; type_id = 730; break; default: @@ -1664,7 +1744,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id else if (vendor_id == 0x04cc) { switch(product_id) { case 0x8116: - Info("SOTEC CMS-001 USB webcam detected.\n"); + Info("Sotec Afina Eye USB webcam detected.\n"); + name = "Sotec Afina Eye"; type_id = 730; break; default: @@ -1672,7 +1753,25 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id break; } } - else return -ENODEV; /* Not Philips, Askey, Logitech, Samsung, Creative or SOTEC, for sure. */ + else if (vendor_id == 0x0d81) { + switch(product_id) { + case 0x1900: + Info("Visionite VCS-UC300 USB webcam detected.\n"); + name = "Visionite VCS-UC300"; + type_id = 740; /* CCD sensor */ + break; + case 0x1910: + Info("Visionite VCS-UM100 USB webcam detected.\n"); + name = "Visionite VCS-UM100"; + type_id = 730; /* CMOS sensor */ + break; + default: + return -ENODEV; + break; + } + } + else + return -ENODEV; /* Not any of the know types; but the list keeps growing. */ memset(serial_number, 0, 30); usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29); @@ -1706,7 +1805,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id return -ENOMEM; } memcpy(vdev, &pwc_template, sizeof(pwc_template)); - sprintf(vdev->name, "Philips %d webcam", pdev->type); + strcpy(vdev->name, name); SET_MODULE_OWNER(vdev); pdev->vdev = vdev; vdev->priv = pdev; @@ -1714,7 +1813,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pdev->release = udev->descriptor.bcdDevice; Trace(TRACE_PROBE, "Release: %04x\n", pdev->release); - /* Now search device_hint[] table for a match, so we can hint a node number. */ for (hint = 0; hint < MAX_DEV_HINTS; hint++) { if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) && @@ -1761,40 +1859,41 @@ static void usb_pwc_disconnect(struct usb_interface *intf) dev_set_drvdata (&intf->dev, NULL); if (pdev == NULL) { Err("pwc_disconnect() Called without private pointer.\n"); - goto out_err; + goto disconnect_out; } if (pdev->udev == NULL) { Err("pwc_disconnect() already called for %p\n", pdev); - goto out_err; + goto disconnect_out; } if (pdev->udev != interface_to_usbdev(intf)) { Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n"); - goto out_err; + goto disconnect_out; } #ifdef PWC_MAGIC if (pdev->magic != PWC_MAGIC) { Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n"); - goto out_err; + goto disconnect_out; } -#endif - +#endif + pdev->unplugged = 1; if (pdev->vdev != NULL) { - video_unregister_device(pdev->vdev); + Trace(TRACE_PROBE, "Unregistering video device.\n"); + video_unregister_device(pdev->vdev); if (pdev->vopen) { Info("Disconnected while device/video is open!\n"); - + /* Wake up any processes that might be waiting for a frame, let them return an error condition */ wake_up(&pdev->frameq); - + /* Wait until we get a 'go' from _close(). This used to have a gigantic race condition, since we kfree() - stuff here, but we have to wait until close() - is finished. + stuff here, but we have to wait until close() + is finished. */ - + Trace(TRACE_PROBE, "Sleeping on remove_ok.\n"); add_wait_queue(&pdev->remove_ok, &wait); set_current_state(TASK_UNINTERRUPTIBLE); @@ -1808,26 +1907,25 @@ static void usb_pwc_disconnect(struct usb_interface *intf) } else { /* Normal disconnect; remove from available devices */ - Trace(TRACE_PROBE, "Unregistering video device normally.\n"); kfree(pdev->vdev); pdev->vdev = NULL; } } +disconnect_out: /* search device_hint[] table if we occupy a slot, by any chance */ for (hint = 0; hint < MAX_DEV_HINTS; hint++) if (device_hint[hint].pdev == pdev) device_hint[hint].pdev = NULL; pdev->udev = NULL; -out_err: unlock_kernel(); kfree(pdev); } /* *grunt* We have to do atoi ourselves :-( */ -static int pwc_atoi(char *s) +static int pwc_atoi(const char *s) { int k = 0; @@ -1872,7 +1970,7 @@ MODULE_PARM_DESC(leds, "LED on,off time in milliseconds"); MODULE_PARM(dev_hint, "0-10s"); MODULE_PARM_DESC(dev_hint, "Device node hints"); -MODULE_DESCRIPTION("Philips USB webcam driver"); +MODULE_DESCRIPTION("Philips & OEM USB webcam driver"); MODULE_AUTHOR("Nemosoft Unv. <nemosoft@smcc.demon.nl>"); MODULE_LICENSE("GPL"); @@ -1882,11 +1980,12 @@ static int __init usb_pwc_init(void) char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" }; Info("Philips PCA645/646 + PCVC675/680/690 + PCVC730/740/750 webcam module version " PWC_VERSION " loaded.\n"); - Info("Also supports the Askey VC010, Logitech Quickcam 3000 Pro, Samsung MPC-C10 and MPC-C30, the Creative WebCam 5 and the SOTEC CMS-001.\n"); + Info("Also supports the Askey VC010, various Logitech QuickCams, Samsung MPC-C10 and MPC-C30,\n"); + Info("the Creative WebCam 5, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n"); if (fps) { - if (fps < 5 || fps > 30) { - Err("Framerate out of bounds (5-30).\n"); + if (fps < 4 || fps > 30) { + Err("Framerate out of bounds (4-30).\n"); return -EINVAL; } default_fps = fps; @@ -1938,9 +2037,9 @@ static int __init usb_pwc_init(void) if (power_save) Info("Enabling power save on open/close.\n"); if (leds[0] >= 0) - led_on = leds[0] / 100; + led_on = leds[0]; if (leds[1] >= 0) - led_off = leds[1] / 100; + led_off = leds[1]; /* Big device node whoopla. Basicly, it allows you to assign a device node (/dev/videoX) to a camera, based on its type @@ -1999,7 +2098,7 @@ static int __init usb_pwc_init(void) device_hint[i].serial_number[k] = '\0'; } } -#ifdef PWC_DEBUG +#if PWC_DEBUG Debug("device_hint[%d]:\n", i); Debug(" type : %d\n", device_hint[i].type); Debug(" serial# : %s\n", device_hint[i].serial_number); diff --git a/drivers/usb/media/pwc-misc.c b/drivers/usb/media/pwc-misc.c index 254da4186dd5..ecb57de7f586 100644 --- a/drivers/usb/media/pwc-misc.c +++ b/drivers/usb/media/pwc-misc.c @@ -1,6 +1,6 @@ /* Linux driver for Philips webcam Various miscellaneous functions and tables. - (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl) + (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl) 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 diff --git a/drivers/usb/media/pwc-uncompress.c b/drivers/usb/media/pwc-uncompress.c index 69f3688359ca..b34074e5d40d 100644 --- a/drivers/usb/media/pwc-uncompress.c +++ b/drivers/usb/media/pwc-uncompress.c @@ -1,6 +1,6 @@ /* Linux driver for Philips webcam Decompression frontend. - (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl) + (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl) 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 @@ -77,7 +77,7 @@ int pwc_decompress(struct pwc_device *pdev) { struct pwc_frame_buf *fbuf; int n, line, col, stride; - void *yuv, *image, *dst; + void *yuv, *image; u16 *src; u16 *dsty, *dstu, *dstv; @@ -114,19 +114,6 @@ int pwc_decompress(struct pwc_device *pdev) to get the desired output format/size. */ switch (pdev->vpalette) { - case VIDEO_PALETTE_YUV420: - /* Calculate byte offsets per line in image & view */ - n = (pdev->image.x * 3) / 2; - col = (pdev->view.x * 3) / 2; - /* Offset into image */ - dst = image + (pdev->view.x * pdev->offset.y + pdev->offset.x) * 3 / 2; - for (line = 0; line < pdev->image.y; line++) { - memcpy(dst, yuv, n); - yuv += n; - dst += col; - } - break; - case VIDEO_PALETTE_YUV420P: /* * We do some byte shuffling here to go from the @@ -163,17 +150,20 @@ int pwc_decompress(struct pwc_device *pdev) dstu += (stride >> 1); } break; + default: + Err("Unsupported palette!"); + break; } } else { /* Compressed; the decompressor routines will write the data - in interlaced or planar format immediately. + in planar format immediately. */ if (pdev->decompressor) pdev->decompressor->decompress( &pdev->image, &pdev->view, &pdev->offset, - yuv, image, - pdev->vpalette == VIDEO_PALETTE_YUV420P ? 1 : 0, + yuv, image, + 1, pdev->decompress_data, pdev->vbandlength); else return -ENXIO; /* No such device or address: missing decompressor */ diff --git a/drivers/usb/media/pwc-uncompress.h b/drivers/usb/media/pwc-uncompress.h index d6220cf82863..58c32aab0792 100644 --- a/drivers/usb/media/pwc-uncompress.h +++ b/drivers/usb/media/pwc-uncompress.h @@ -1,4 +1,4 @@ -/* (C) 1999-2001 Nemosoft Unv. (webcam@smcc.demon.nl) +/* (C) 1999-2002 Nemosoft Unv. (webcam@smcc.demon.nl) 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 diff --git a/drivers/usb/media/pwc.h b/drivers/usb/media/pwc.h index 63856cb7b8a0..913f2d4aa193 100644 --- a/drivers/usb/media/pwc.h +++ b/drivers/usb/media/pwc.h @@ -60,8 +60,8 @@ /* Version block */ #define PWC_MAJOR 8 -#define PWC_MINOR 7 -#define PWC_VERSION "8.7" +#define PWC_MINOR 9 +#define PWC_VERSION "8.9" #define PWC_NAME "pwc" /* Turn certain features on/off */ @@ -130,7 +130,7 @@ struct pwc_device int vcinterface; /* video control interface */ int valternate; /* alternate interface needed */ int vframes, vsize; /* frames-per-second & size (see PSZ_*) */ - int vpalette; /* YUV, RGB24, RGB32, etc */ + int vpalette; /* YUV */ int vframe_count; /* received frames */ int vframes_dumped; /* counter for dumped frames */ int vframes_error; /* frames received in error */ @@ -140,7 +140,8 @@ struct pwc_device int vbandlength; /* compressed band length; 0 is uncompressed */ char vsnapshot; /* snapshot mode */ char vsync; /* used by isoc handler */ - + char vmirror; /* for ToUCaM series */ + /* The image acquisition requires 3 to 4 steps: 1. data is gathered in short packets from the USB controller 2. data is synchronized and packed into a frame buffer diff --git a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c index 1f7138f93133..d7ba9d6440bf 100644 --- a/drivers/usb/media/vicam.c +++ b/drivers/usb/media/vicam.c @@ -1,7 +1,7 @@ /* * USB ViCam WebCam driver * Copyright (c) 2002 Joe Burks (jburks@wavicle.org), - * John Tyner (fill in email address) + * John Tyner (jtyner@cs.ucr.edu) * * Supports 3COM HomeConnect PC Digital WebCam * @@ -29,7 +29,7 @@ * Andy Armstrong who reverse engineered the color encoding and * Pavel Machek and Chris Cheney who worked on reverse engineering the * camera controls and wrote the first generation driver. - * */ + */ #include <linux/kernel.h> #include <linux/wrapper.h> @@ -51,19 +51,25 @@ #define DBG(fmn,args...) do {} while(0) #endif -/* Version Information */ -#define DRIVER_VERSION "v1.0" -#define DRIVER_AUTHOR "Joe Burks, jburks@wavicle.org" -#define DRIVER_DESC "ViCam WebCam Driver" +#define DRIVER_AUTHOR "Joe Burks, jburks@wavicle.org" +#define DRIVER_DESC "ViCam WebCam Driver" /* Define these values to match your device */ #define USB_VICAM_VENDOR_ID 0x04c1 #define USB_VICAM_PRODUCT_ID 0x009d -#define VICAM_BYTES_PER_PIXEL 3 -#define VICAM_MAX_READ_SIZE (512*242+128) -#define VICAM_MAX_FRAME_SIZE (VICAM_BYTES_PER_PIXEL*320*240) -#define VICAM_FRAMES 2 +#define VICAM_BYTES_PER_PIXEL 3 +#define VICAM_MAX_READ_SIZE (512*242+128) +#define VICAM_MAX_FRAME_SIZE (VICAM_BYTES_PER_PIXEL*320*240) +#define VICAM_FRAMES 2 + +#define VICAM_HEADER_SIZE 64 + +#define clamp( x, l, h ) max_t( __typeof__( x ), \ + ( l ), \ + min_t( __typeof__( x ), \ + ( h ), \ + ( x ) ) ) /* Not sure what all the bytes in these char * arrays do, but they're necessary to make @@ -408,7 +414,8 @@ struct vicam_camera { struct video_device vdev; // v4l video device struct usb_device *udev; // usb device - struct semaphore busy_lock; // guard against SMP multithreading + /* guard against simultaneous accesses to the camera */ + struct semaphore cam_lock; int is_initialized; u8 open_count; @@ -424,17 +431,21 @@ struct vicam_camera { static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id); static void vicam_disconnect(struct usb_interface *intf); static void read_frame(struct vicam_camera *cam, int framenum); - -static int -send_control_msg(struct usb_device *udev, u8 request, u16 value, u16 index, - unsigned char *cp, u16 size) +static void vicam_decode_color(const u8 *, u8 *); + +static int __send_control_msg(struct vicam_camera *cam, + u8 request, + u16 value, + u16 index, + unsigned char *cp, + u16 size) { int status; /* cp must be memory that has been allocated by kmalloc */ - status = usb_control_msg(udev, - usb_sndctrlpipe(udev, 0), + status = usb_control_msg(cam->udev, + usb_sndctrlpipe(cam->udev, 0), request, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, value, index, @@ -450,6 +461,22 @@ send_control_msg(struct usb_device *udev, u8 request, u16 value, u16 index, return status; } +static int send_control_msg(struct vicam_camera *cam, + u8 request, + u16 value, + u16 index, + unsigned char *cp, + u16 size) +{ + int status = -ENODEV; + down(&cam->cam_lock); + if (cam->udev) { + status = __send_control_msg(cam, request, value, + index, cp, size); + } + up(&cam->cam_lock); + return status; +} static int initialize_camera(struct vicam_camera *cam) { @@ -465,14 +492,13 @@ initialize_camera(struct vicam_camera *cam) { .data = setup3, .size = sizeof(setup3) }, { .data = NULL, .size = 0 } }; - - struct usb_device *udev = cam->udev; + int err, i; for (i = 0, err = 0; firmware[i].data && !err; i++) { memcpy(cam->cntrlbuf, firmware[i].data, firmware[i].size); - err = send_control_msg(udev, 0xff, 0, 0, + err = send_control_msg(cam, 0xff, 0, 0, cam->cntrlbuf, firmware[i].size); } @@ -484,11 +510,11 @@ set_camera_power(struct vicam_camera *cam, int state) { int status; - if ((status = send_control_msg(cam->udev, 0x50, state, 0, NULL, 0)) < 0) + if ((status = send_control_msg(cam, 0x50, state, 0, NULL, 0)) < 0) return status; if (state) { - send_control_msg(cam->udev, 0x55, 1, 0, NULL, 0); + send_control_msg(cam, 0x55, 1, 0, NULL, 0); } return 0; @@ -504,10 +530,6 @@ vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsign if (!cam) return -ENODEV; - /* make this _really_ smp-safe */ - if (down_interruptible(&cam->busy_lock)) - return -EINTR; - switch (ioctlnr) { /* query capabilites */ case VIDIOCGCAP: @@ -694,6 +716,9 @@ vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsign DBG("VIDIOCSYNC: %d\n", frame); read_frame(cam, frame); + vicam_decode_color(cam->raw_image, + cam->framebuf + + frame * VICAM_MAX_FRAME_SIZE ); break; } @@ -724,7 +749,6 @@ vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsign break; } - up(&cam->busy_lock); return retval; } @@ -741,26 +765,25 @@ vicam_open(struct inode *inode, struct file *file) "vicam video_device improperly initialized"); } - if ( down_interruptible(&cam->busy_lock) ) - return -EINTR; + /* the videodev_lock held above us protects us from + * simultaneous opens...for now. we probably shouldn't + * rely on this fact forever. + */ if (cam->open_count > 0) { printk(KERN_INFO "vicam_open called on already opened camera"); - up(&cam->busy_lock); return -EBUSY; } cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL); if (!cam->raw_image) { - up(&cam->busy_lock); return -ENOMEM; } cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); if (!cam->framebuf) { kfree(cam->raw_image); - up(&cam->busy_lock); return -ENOMEM; } @@ -768,7 +791,6 @@ vicam_open(struct inode *inode, struct file *file) if (!cam->cntrlbuf) { kfree(cam->raw_image); rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); - up(&cam->busy_lock); return -ENOMEM; } @@ -785,8 +807,6 @@ vicam_open(struct inode *inode, struct file *file) cam->needsDummyRead = 1; cam->open_count++; - up(&cam->busy_lock); - file->private_data = cam; return 0; @@ -796,118 +816,105 @@ static int vicam_close(struct inode *inode, struct file *file) { struct vicam_camera *cam = file->private_data; + int open_count; + struct usb_device *udev; + DBG("close\n"); + + /* it's not the end of the world if + * we fail to turn the camera off. + */ + set_camera_power(cam, 0); kfree(cam->raw_image); rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); kfree(cam->cntrlbuf); + down(&cam->cam_lock); + cam->open_count--; + open_count = cam->open_count; + udev = cam->udev; + + up(&cam->cam_lock); + + if (!open_count && !udev) { + kfree(cam); + } return 0; } -inline int pin(int x) +static void vicam_decode_color(const u8 *data, u8 *rgb) { - return((x > 255) ? 255 : ((x < 0) ? 0 : x)); -} + /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB + * Copyright (C) 2002 Monroe Williams (monroe@pobox.com) + */ -inline void writepixel(char *rgb, int Y, int Cr, int Cb) -{ - Y = 1160 * (Y - 16); - - rgb[2] = pin( ( ( Y + ( 1594 * Cr ) ) + 500 ) / 1300 ); - rgb[1] = pin( ( ( Y - ( 392 * Cb ) - ( 813 * Cr ) ) + 500 ) / 1000 ); - rgb[0] = pin( ( ( Y + ( 2017 * Cb ) ) + 500 ) / 900 ); -} + int i, prevY, nextY; -#define DATA_HEADER_SIZE 64 + prevY = 512; + nextY = 512; -// -------------------------------------------------------------------------------- -// vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB -// -// Copyright (C) 2002 Monroe Williams (monroe@pobox.com) -// -------------------------------------------------------------------------------- + data += VICAM_HEADER_SIZE; -static void vicam_decode_color( char *data, char *rgb) -{ - int x,y; - int Cr, Cb; - int sign; - int prevX, nextX, prevY, nextY; - int skip; - unsigned char *src; - unsigned char *dst; + for( i = 0; i < 240; i++, data += 512 ) { + const int y = ( i * 242 ) / 240; - prevY = 512; - nextY = 512; + int j, prevX, nextX; + int Y, Cr, Cb; - src = data + DATA_HEADER_SIZE; - dst = rgb; + if ( y == 242 - 1 ) { + nextY = -512; + } - for(y = 1; y < 241; y += 2) - { - // even line - sign = 1; prevX = 1; nextX = 1; - skip = 0; + for ( j = 0; j < 320; j++, rgb += 3 ) { + const int x = ( j * 512 ) / 320; + const u8 * const src = &data[x]; - dst = rgb + (y-1)*320*3; - - for(x = 0; x < 512; x++) - { - if(x == 512-1) + if ( x == 512 - 1 ) { nextX = -1; + } - Cr = sign * ((src[prevX] - src[0]) + (src[nextX] - src[0])) >> 1; - Cb = sign * ((src[prevY] - src[prevX + prevY]) + (src[prevY] - src[nextX + prevY]) + (src[nextY] - src[prevX + nextY]) + (src[nextY] - src[nextX + nextY])) >> 2; - - writepixel( - dst + ((x*5)>>3)*3, - src[0] + (sign * (Cr >> 1)), - Cr, - Cb); - - src++; - sign *= -1; - prevX = -1; - } - - prevY = -512; + Cr = ( src[prevX] - src[0] ) + + ( src[nextX] - src[0] ); + Cr /= 2; - if(y == (242 - 2)) - nextY = -512; + Cb = ( src[prevY] - src[prevX + prevY] ) + + ( src[prevY] - src[nextX + prevY] ) + + ( src[nextY] - src[prevX + nextY] ) + + ( src[nextY] - src[nextX + nextY] ); + Cb /= 4; - // odd line - sign = 1; - prevX = 1; - nextX = 1; + Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 ); - skip = 0; + if ( i & 1 ) { + int Ct = Cr; + Cr = Cb; + Cb = Ct; + } - dst = rgb + (y)*320*3; - - for(x = 0; x < 512; x++) - { - if(x == 512-1) - nextX = -1; - - Cr = sign * ((src[prevX + prevY] - src[prevY]) + (src[nextX + prevY] - src[prevY]) + (src[prevX + nextY] - src[nextY]) + (src[nextX + nextY] - src[nextY])) >> 2; - Cb = sign * ((src[0] - src[prevX]) + (src[0] - src[nextX])) >> 1; + if ( ( x ^ i ) & 1 ) { + Cr = -Cr; + Cb = -Cb; + } - writepixel( - dst + ((x * 5)>>3)*3, - src[0] - (sign * (Cb >> 1)), - Cr, - Cb); + rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) + + 500 ) / 900, 0, 255 ); + rgb[1] = clamp( ( ( Y - ( 392 * Cb ) - + ( 813 * Cr ) ) + + 500 ) / 1000, 0, 255 ); + rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) + + 500 ) / 1300, 0, 255 ); - src++; - sign *= -1; prevX = -1; } + + prevY = -512; } } @@ -953,12 +960,18 @@ read_frame(struct vicam_camera *cam, int framenum) request[8] = 0; // bytes 9-15 do not seem to affect exposure or image quality - n = send_control_msg(cam->udev, 0x51, 0x80, 0, request, 16); + down(&cam->cam_lock); + + if (!cam->udev) { + goto done; + } + + n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16); if (n < 0) { printk(KERN_ERR " Problem sending frame capture control message"); - return; + goto done; } n = usb_bulk_msg(cam->udev, @@ -971,9 +984,8 @@ read_frame(struct vicam_camera *cam, int framenum) n); } - vicam_decode_color(cam->raw_image, - cam->framebuf + - framenum * VICAM_MAX_FRAME_SIZE ); + done: + up(&cam->cam_lock); } static int @@ -983,17 +995,16 @@ vicam_read( struct file *file, char *buf, size_t count, loff_t *ppos ) DBG("read %d bytes.\n", (int) count); - if ( down_interruptible(&cam->busy_lock) ) - return -EINTR; - if (*ppos >= VICAM_MAX_FRAME_SIZE) { *ppos = 0; - up(&cam->busy_lock); return 0; } if (*ppos == 0) { read_frame(cam, 0); + vicam_decode_color(cam->raw_image, + cam->framebuf + + 0 * VICAM_MAX_FRAME_SIZE); } count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos); @@ -1008,8 +1019,6 @@ vicam_read( struct file *file, char *buf, size_t count, loff_t *ppos ) *ppos = 0; } - up(&cam->busy_lock); - return count; } @@ -1034,10 +1043,6 @@ vicam_mmap(struct file *file, struct vm_area_struct *vma) return -EINVAL; */ - /* make this _really_ smp-safe */ - if (down_interruptible(&cam->busy_lock)) - return -EINTR; - pos = (unsigned long)cam->framebuf; while (size > 0) { page = kvirt_to_pa(pos); @@ -1052,8 +1057,6 @@ vicam_mmap(struct file *file, struct vm_area_struct *vma) size = 0; } - up(&cam->busy_lock); - return 0; } @@ -1285,7 +1288,7 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id) cam->shutter_speed = 15; - init_MUTEX(&cam->busy_lock); + init_MUTEX(&cam->cam_lock); memcpy(&cam->vdev, &vicam_template, sizeof (vicam_template)); @@ -1312,17 +1315,43 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id) static void vicam_disconnect(struct usb_interface *intf) { + int open_count; struct vicam_camera *cam = dev_get_drvdata(&intf->dev); - dev_set_drvdata ( &intf->dev, NULL ); - - cam->udev = NULL; - + + /* we must unregister the device before taking its + * cam_lock. This is because the video open call + * holds the same lock as video unregister. if we + * unregister inside of the cam_lock and open also + * uses the cam_lock, we get deadlock. + */ + video_unregister_device(&cam->vdev); + /* stop the camera from being used */ + + down(&cam->cam_lock); + + /* mark the camera as gone */ + + cam->udev = NULL; + vicam_destroy_proc_entry(cam); - kfree(cam); + /* the only thing left to do is synchronize with + * our close/release function on who should release + * the camera memory. if there are any users using the + * camera, it's their job. if there are no users, + * it's ours. + */ + + open_count = cam->open_count; + + up(&cam->cam_lock); + + if (!open_count) { + kfree(cam); + } printk(KERN_DEBUG "ViCam-based WebCam disconnected\n"); } diff --git a/drivers/usb/misc/tiglusb.c b/drivers/usb/misc/tiglusb.c index c535d28da923..b2ed1ed76bfd 100644 --- a/drivers/usb/misc/tiglusb.c +++ b/drivers/usb/misc/tiglusb.c @@ -185,7 +185,7 @@ tiglusb_read (struct file *filp, char *buf, size_t count, loff_t * f_pos) pipe = usb_rcvbulkpipe (s->dev, 1); result = usb_bulk_msg (s->dev, pipe, buffer, bytes_to_read, - &bytes_read, HZ / (timeout / 10)); + &bytes_read, HZ * 10 / timeout); if (result == -ETIMEDOUT) { /* NAK */ ret = result; if (!bytes_read) { @@ -242,7 +242,7 @@ tiglusb_write (struct file *filp, const char *buf, size_t count, loff_t * f_pos) pipe = usb_sndbulkpipe (s->dev, 2); result = usb_bulk_msg (s->dev, pipe, buffer, bytes_to_write, - &bytes_written, HZ / (timeout / 10)); + &bytes_written, HZ * 10 / timeout); if (result == -ETIMEDOUT) { /* NAK */ warn ("tiglusb_write, NAK received."); @@ -453,6 +453,8 @@ tiglusb_setup (char *str) if (ints[0] > 0) { timeout = ints[1]; } + if (!timeout) + timeout = TIMAXTIME; return 1; } @@ -494,6 +496,9 @@ tiglusb_init (void) info (DRIVER_DESC ", " DRIVER_VERSION); + if (!timeout) + timeout = TIMAXTIME; + return 0; } @@ -516,6 +521,6 @@ MODULE_DESCRIPTION (DRIVER_DESC); MODULE_LICENSE (DRIVER_LICENSE); MODULE_PARM (timeout, "i"); -MODULE_PARM_DESC (timeout, "Timeout (default=1.5 seconds)"); +MODULE_PARM_DESC (timeout, "Timeout in tenths of seconds (default=1.5 seconds)"); /* --------------------------------------------------------------------- */ diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 12cbae5b5704..305058779a37 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -400,5 +400,10 @@ config USB_SERIAL_OMNINET The module will be called omninet.o. If you want to compile it as a module, say M here and read <file:Documentation/modules.txt>. +config USB_EZUSB + bool + depends on USB_SERIAL_KEYSPAN_PDA || USB_SERIAL_XIRCOM || USB_SERIAL_KEYSPAN || USB_SERIAL_WHITEHEAT + default y + endmenu diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 3e3f9d02924a..30b1e6b0fd40 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_USB_SERIAL) += usbserial.o usbserial-obj-$(CONFIG_USB_SERIAL_CONSOLE) += console.o +usbserial-obj-$(CONFIG_USB_EZUSB) += ezusb.o obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o obj-$(CONFIG_USB_SERIAL_IPAQ) += ipaq.o @@ -29,9 +30,9 @@ obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o # Objects that export symbols. -export-objs := usb-serial.o +export-objs := usb-serial.o ezusb.o -usbserial-objs := usb-serial.o $(usbserial-obj-y) +usbserial-objs := usb-serial.o generic.o $(usbserial-obj-y) include $(TOPDIR)/Rules.make diff --git a/drivers/usb/serial/ezusb.c b/drivers/usb/serial/ezusb.c new file mode 100644 index 000000000000..35616b5e23a0 --- /dev/null +++ b/drivers/usb/serial/ezusb.c @@ -0,0 +1,67 @@ +/* + * EZ-USB specific functions used by some of the USB to Serial drivers. + * + * Copyright (C) 1999 - 2002 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 version + * 2 as published by the Free Software Foundation. + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/module.h> +#include <linux/usb.h> + +#ifdef CONFIG_USB_SERIAL_DEBUG + static int debug = 1; +#else + static int debug; +#endif + +#include "usb-serial.h" + +/* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */ +#define CPUCS_REG 0x7F92 + +int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest) +{ + int result; + unsigned char *transfer_buffer; + + /* dbg("ezusb_writememory %x, %d", address, length); */ + if (!serial->dev) { + dbg("%s - no physical device present, failing.", __FUNCTION__); + return -ENODEV; + } + + transfer_buffer = kmalloc (length, GFP_KERNEL); + if (!transfer_buffer) { + err("%s - kmalloc(%d) failed.", __FUNCTION__, length); + return -ENOMEM; + } + memcpy (transfer_buffer, data, length); + result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), bRequest, 0x40, address, 0, transfer_buffer, length, 3*HZ); + kfree (transfer_buffer); + return result; +} + +int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit) +{ + int response; + dbg("%s - %d", __FUNCTION__, reset_bit); + response = ezusb_writememory (serial, CPUCS_REG, &reset_bit, 1, 0xa0); + if (response < 0) { + err("%s- %d failed", __FUNCTION__, reset_bit); + } + return response; +} + + +EXPORT_SYMBOL(ezusb_writememory); +EXPORT_SYMBOL(ezusb_set_reset); + diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c new file mode 100644 index 000000000000..29dc63fa01d7 --- /dev/null +++ b/drivers/usb/serial/generic.c @@ -0,0 +1,304 @@ +/* + * USB Serial Converter Generic functions + * + * Copyright (C) 1999 - 2002 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 version + * 2 as published by the Free Software Foundation. + * + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/module.h> +#include <linux/usb.h> + +#ifdef CONFIG_USB_SERIAL_DEBUG + static int debug = 1; +#else + static int debug; +#endif + +#include "usb-serial.h" + + +#ifdef CONFIG_USB_SERIAL_GENERIC +static __u16 vendor = 0x05f9; +static __u16 product = 0xffff; + +MODULE_PARM(vendor, "h"); +MODULE_PARM_DESC(vendor, "User specified USB idVendor"); + +MODULE_PARM(product, "h"); +MODULE_PARM_DESC(product, "User specified USB idProduct"); + +static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */ + +/* All of the device info needed for the Generic Serial Converter */ +struct usb_serial_device_type usb_serial_generic_device = { + .owner = THIS_MODULE, + .name = "Generic", + .id_table = generic_device_ids, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = NUM_DONT_CARE, + .num_bulk_out = NUM_DONT_CARE, + .num_ports = 1, + .shutdown = usb_serial_generic_shutdown, +}; +#endif + +int usb_serial_generic_register (int _debug) +{ + int retval = 0; + + debug = _debug; +#ifdef CONFIG_USB_SERIAL_GENERIC + generic_device_ids[0].idVendor = vendor; + generic_device_ids[0].idProduct = product; + generic_device_ids[0].match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT; + + /* register our generic driver with ourselves */ + retval = usb_serial_register (&usb_serial_generic_device); +#endif + return retval; +} + +void usb_serial_generic_deregister (void) +{ +#ifdef CONFIG_USB_SERIAL_GENERIC + /* remove our generic driver */ + usb_serial_deregister (&usb_serial_generic_device); +#endif +} + +int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp) +{ + struct usb_serial *serial = port->serial; + int result = 0; + + if (port_paranoia_check (port, __FUNCTION__)) + return -ENODEV; + + dbg("%s - port %d", __FUNCTION__, port->number); + + /* force low_latency on so that our tty_push actually forces the data through, + otherwise it is scheduled, and with high data rates (like with OHCI) data + can get lost. */ + if (port->tty) + port->tty->low_latency = 1; + + /* if we have a bulk interrupt, start reading from it */ + if (serial->num_bulk_in) { + /* Start reading from the device */ + usb_fill_bulk_urb (port->read_urb, serial->dev, + usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, + port->read_urb->transfer_buffer_length, + ((serial->type->read_bulk_callback) ? + serial->type->read_bulk_callback : + usb_serial_generic_read_bulk_callback), + port); + result = usb_submit_urb(port->read_urb, GFP_KERNEL); + if (result) + err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); + } + + return result; +} + +static void generic_cleanup (struct usb_serial_port *port) +{ + struct usb_serial *serial = port->serial; + + dbg("%s - port %d", __FUNCTION__, port->number); + + if (serial->dev) { + /* shutdown any bulk reads that might be going on */ + if (serial->num_bulk_out) + usb_unlink_urb (port->write_urb); + if (serial->num_bulk_in) + usb_unlink_urb (port->read_urb); + } +} + +void usb_serial_generic_close (struct usb_serial_port *port, struct file * filp) +{ + dbg("%s - port %d", __FUNCTION__, port->number); + generic_cleanup (port); +} + +int usb_serial_generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count) +{ + struct usb_serial *serial = port->serial; + int result; + + dbg("%s - port %d", __FUNCTION__, port->number); + + if (count == 0) { + dbg("%s - write request of 0 bytes", __FUNCTION__); + return (0); + } + + /* only do something if we have a bulk out endpoint */ + if (serial->num_bulk_out) { + if (port->write_urb->status == -EINPROGRESS) { + dbg("%s - already writing", __FUNCTION__); + return (0); + } + + count = (count > port->bulk_out_size) ? port->bulk_out_size : count; + + if (from_user) { + if (copy_from_user(port->write_urb->transfer_buffer, buf, count)) + return -EFAULT; + } + else { + memcpy (port->write_urb->transfer_buffer, buf, count); + } + + usb_serial_debug_data (__FILE__, __FUNCTION__, count, port->write_urb->transfer_buffer); + + /* set up our urb */ + usb_fill_bulk_urb (port->write_urb, serial->dev, + usb_sndbulkpipe (serial->dev, + port->bulk_out_endpointAddress), + port->write_urb->transfer_buffer, count, + ((serial->type->write_bulk_callback) ? + serial->type->write_bulk_callback : + usb_serial_generic_write_bulk_callback), port); + + /* send the data out the bulk port */ + result = usb_submit_urb(port->write_urb, GFP_ATOMIC); + if (result) + err("%s - failed submitting write urb, error %d", __FUNCTION__, result); + else + result = count; + + return result; + } + + /* no bulk out, so return 0 bytes written */ + return (0); +} + +int usb_serial_generic_write_room (struct usb_serial_port *port) +{ + struct usb_serial *serial = port->serial; + int room = 0; + + dbg("%s - port %d", __FUNCTION__, port->number); + + if (serial->num_bulk_out) { + if (port->write_urb->status != -EINPROGRESS) + room = port->bulk_out_size; + } + + dbg("%s - returns %d", __FUNCTION__, room); + return (room); +} + +int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port) +{ + struct usb_serial *serial = port->serial; + int chars = 0; + + dbg("%s - port %d", __FUNCTION__, port->number); + + if (serial->num_bulk_out) { + if (port->write_urb->status == -EINPROGRESS) + chars = port->write_urb->transfer_buffer_length; + } + + dbg("%s - returns %d", __FUNCTION__, chars); + return (chars); +} + +void usb_serial_generic_read_bulk_callback (struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); + struct tty_struct *tty; + unsigned char *data = urb->transfer_buffer; + int i; + int result; + + dbg("%s - port %d", __FUNCTION__, port->number); + + if (!serial) { + dbg("%s - bad serial pointer, exiting", __FUNCTION__); + return; + } + + if (urb->status) { + dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); + return; + } + + usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); + + tty = port->tty; + if (tty && urb->actual_length) { + for (i = 0; i < urb->actual_length ; ++i) { + /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */ + if(tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty_flip_buffer_push(tty); + } + /* this doesn't actually push the data through unless tty->low_latency is set */ + tty_insert_flip_char(tty, data[i], 0); + } + tty_flip_buffer_push(tty); + } + + /* Continue trying to always read */ + usb_fill_bulk_urb (port->read_urb, serial->dev, + usb_rcvbulkpipe (serial->dev, + port->bulk_in_endpointAddress), + port->read_urb->transfer_buffer, + port->read_urb->transfer_buffer_length, + ((serial->type->read_bulk_callback) ? + serial->type->read_bulk_callback : + usb_serial_generic_read_bulk_callback), port); + result = usb_submit_urb(port->read_urb, GFP_ATOMIC); + if (result) + err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); +} + +void usb_serial_generic_write_bulk_callback (struct urb *urb) +{ + struct usb_serial_port *port = (struct usb_serial_port *)urb->context; + struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); + + dbg("%s - port %d", __FUNCTION__, port->number); + + if (!serial) { + dbg("%s - bad serial pointer, exiting", __FUNCTION__); + return; + } + + if (urb->status) { + dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); + return; + } + + usb_serial_port_softint((void *)port); + + schedule_work(&port->work); +} + +void usb_serial_generic_shutdown (struct usb_serial *serial) +{ + int i; + + dbg("%s", __FUNCTION__); + + /* stop reads and writes on all ports */ + for (i=0; i < serial->num_ports; ++i) { + generic_cleanup (&serial->port[i]); + } +} + diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index c4a145cb5aa2..8d0a4d5b57a7 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -9,6 +9,10 @@ * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * + * (26/11/2002) ganesh + * Added insmod options to specify product and vendor id. + * Use modprobe ipaq vendor=0xfoo product=0xbar + * * (26/7/2002) ganesh * Fixed up broken error handling in ipaq_open. Retry the "kickstart" * packet much harder - this drastically reduces connection failures. @@ -63,10 +67,13 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.2" + +#define DRIVER_VERSION "v0.4" #define DRIVER_AUTHOR "Ganesh Varadarajan <ganesh@veritas.com>" #define DRIVER_DESC "USB Compaq iPAQ, HP Jornada, Casio EM500 driver" +static int product, vendor; + /* Function prototypes for an ipaq */ static int ipaq_open (struct usb_serial_port *port, struct file *filp); static void ipaq_close (struct usb_serial_port *port, struct file *filp); @@ -85,6 +92,8 @@ static void ipaq_destroy_lists(struct usb_serial_port *port); static struct usb_device_id ipaq_id_table [] = { + /* The first entry is a placeholder for the insmod-specified device */ + { USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_IPAQ_ID) }, { USB_DEVICE(COMPAQ_VENDOR_ID, COMPAQ_IPAQ_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_548_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_JORNADA_568_ID) }, @@ -521,9 +530,14 @@ static void ipaq_shutdown(struct usb_serial *serial) static int __init ipaq_init(void) { + spin_lock_init(&write_list_lock); usb_serial_register(&ipaq_device); - usb_register(&ipaq_driver); info(DRIVER_DESC " " DRIVER_VERSION); + if (vendor) { + ipaq_id_table[0].idVendor = vendor; + ipaq_id_table[0].idProduct = product; + } + usb_register(&ipaq_driver); return 0; } @@ -546,3 +560,8 @@ MODULE_LICENSE("GPL"); MODULE_PARM(debug, "i"); MODULE_PARM_DESC(debug, "Debug enabled or not"); +MODULE_PARM(vendor, "h"); +MODULE_PARM_DESC(vendor, "User specified USB idVendor"); + +MODULE_PARM(product, "h"); +MODULE_PARM_DESC(product, "User specified USB idProduct"); diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 5afe854714ec..2315dbf6299a 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -346,7 +346,7 @@ static int keyspan_write(struct usb_serial_port *port, int from_user, if (this_urb->status == -EINPROGRESS) { if (this_urb->transfer_flags & URB_ASYNC_UNLINK) break; - if (jiffies - p_priv->tx_start_time[flip] < 10 * HZ) + if (time_before(jiffies, p_priv->tx_start_time[flip] + 10 * HZ)) break; this_urb->transfer_flags |= URB_ASYNC_UNLINK; usb_unlink_urb(this_urb); diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 1ee4eace260b..cfcf341f4cbb 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -345,41 +345,12 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.7" +#define DRIVER_VERSION "v1.8" #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/" #define DRIVER_DESC "USB Serial Driver core" -/* function prototypes for a "generic" type serial converter (no flow control, not all endpoints needed) */ -/* need to always compile these in, as some of the other devices use these functions as their own. */ -/* if a driver does not provide a function pointer, the generic function will be called. */ -int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp); -int usb_serial_generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count); -static void generic_close (struct usb_serial_port *port, struct file *filp); -static int generic_write_room (struct usb_serial_port *port); -static int generic_chars_in_buffer (struct usb_serial_port *port); -static void generic_read_bulk_callback (struct urb *urb); -static void generic_write_bulk_callback (struct urb *urb); -static void generic_shutdown (struct usb_serial *serial); - #ifdef CONFIG_USB_SERIAL_GENERIC -static __u16 vendor = 0x05f9; -static __u16 product = 0xffff; - -static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */ - -/* All of the device info needed for the Generic Serial Converter */ -static struct usb_serial_device_type generic_device = { - .owner = THIS_MODULE, - .name = "Generic", - .id_table = generic_device_ids, - .num_interrupt_in = NUM_DONT_CARE, - .num_bulk_in = NUM_DONT_CARE, - .num_bulk_out = NUM_DONT_CARE, - .num_ports = 1, - .shutdown = generic_shutdown, -}; - /* we want to look at all devices, as the vendor/product id can change * depending on the command line argument */ static struct usb_device_id generic_serial_ids[] = { @@ -387,27 +358,6 @@ static struct usb_device_id generic_serial_ids[] = { {} }; -static int generic_register (void) -{ - generic_device_ids[0].idVendor = vendor; - generic_device_ids[0].idProduct = product; - generic_device_ids[0].match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT; - - /* register our generic driver with ourselves */ - return usb_serial_register (&generic_device); -} - -static void generic_deregister (void) -{ - /* remove our generic driver */ - usb_serial_deregister (&generic_device); -} - -#else - -static inline int generic_register (void) { return 0; } -static inline void generic_deregister (void) { } - #endif /* CONFIG_USB_SERIAL_GENERIC */ /* Driver structure we register with the USB core */ @@ -488,45 +438,6 @@ static void return_serial (struct usb_serial *serial) return; } -#ifdef USES_EZUSB_FUNCTIONS -/* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */ -#define CPUCS_REG 0x7F92 - -int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest) -{ - int result; - unsigned char *transfer_buffer; - - /* dbg("ezusb_writememory %x, %d", address, length); */ - if (!serial->dev) { - dbg("%s - no physical device present, failing.", __FUNCTION__); - return -ENODEV; - } - - transfer_buffer = kmalloc (length, GFP_KERNEL); - if (!transfer_buffer) { - err("%s - kmalloc(%d) failed.", __FUNCTION__, length); - return -ENOMEM; - } - memcpy (transfer_buffer, data, length); - result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), bRequest, 0x40, address, 0, transfer_buffer, length, 3*HZ); - kfree (transfer_buffer); - return result; -} - -int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit) -{ - int response; - dbg("%s - %d", __FUNCTION__, reset_bit); - response = ezusb_writememory (serial, CPUCS_REG, &reset_bit, 1, 0xa0); - if (response < 0) { - err("%s- %d failed", __FUNCTION__, reset_bit); - } - return response; -} - -#endif /* USES_EZUSB_FUNCTIONS */ - /***************************************************************************** * Driver tty interface functions *****************************************************************************/ @@ -593,7 +504,7 @@ static void __serial_close(struct usb_serial_port *port, struct file *filp) if (port->serial->type->close) port->serial->type->close(port, filp); else - generic_close(port, filp); + usb_serial_generic_close(port, filp); port->open_count = 0; } @@ -672,7 +583,7 @@ static int serial_write_room (struct tty_struct *tty) if (serial->type->write_room) retval = serial->type->write_room(port); else - retval = generic_write_room(port); + retval = usb_serial_generic_write_room(port); exit: up (&port->sem); @@ -701,7 +612,7 @@ static int serial_chars_in_buffer (struct tty_struct *tty) if (serial->type->chars_in_buffer) retval = serial->type->chars_in_buffer(port); else - retval = generic_chars_in_buffer(port); + retval = usb_serial_generic_chars_in_buffer(port); exit: up (&port->sem); @@ -844,7 +755,7 @@ static void serial_shutdown (struct usb_serial *serial) if (serial->type->shutdown) serial->type->shutdown(serial); else - generic_shutdown(serial); + usb_serial_generic_shutdown(serial); } static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) @@ -889,235 +800,6 @@ done: return ((count < begin+length-off) ? count : begin+length-off); } -/***************************************************************************** - * generic devices specific driver functions - *****************************************************************************/ -int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp) -{ - struct usb_serial *serial = port->serial; - int result = 0; - - if (port_paranoia_check (port, __FUNCTION__)) - return -ENODEV; - - dbg("%s - port %d", __FUNCTION__, port->number); - - /* force low_latency on so that our tty_push actually forces the data through, - otherwise it is scheduled, and with high data rates (like with OHCI) data - can get lost. */ - if (port->tty) - port->tty->low_latency = 1; - - /* if we have a bulk interrupt, start reading from it */ - if (serial->num_bulk_in) { - /* Start reading from the device */ - usb_fill_bulk_urb (port->read_urb, serial->dev, - usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - ((serial->type->read_bulk_callback) ? - serial->type->read_bulk_callback : - generic_read_bulk_callback), - port); - result = usb_submit_urb(port->read_urb, GFP_KERNEL); - if (result) - err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); - } - - return result; -} - -static void generic_cleanup (struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - - dbg("%s - port %d", __FUNCTION__, port->number); - - if (serial->dev) { - /* shutdown any bulk reads that might be going on */ - if (serial->num_bulk_out) - usb_unlink_urb (port->write_urb); - if (serial->num_bulk_in) - usb_unlink_urb (port->read_urb); - } -} - -static void generic_close (struct usb_serial_port *port, struct file * filp) -{ - dbg("%s - port %d", __FUNCTION__, port->number); - generic_cleanup (port); -} - -int usb_serial_generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count) -{ - struct usb_serial *serial = port->serial; - int result; - - dbg("%s - port %d", __FUNCTION__, port->number); - - if (count == 0) { - dbg("%s - write request of 0 bytes", __FUNCTION__); - return (0); - } - - /* only do something if we have a bulk out endpoint */ - if (serial->num_bulk_out) { - if (port->write_urb->status == -EINPROGRESS) { - dbg("%s - already writing", __FUNCTION__); - return (0); - } - - count = (count > port->bulk_out_size) ? port->bulk_out_size : count; - - if (from_user) { - if (copy_from_user(port->write_urb->transfer_buffer, buf, count)) - return -EFAULT; - } - else { - memcpy (port->write_urb->transfer_buffer, buf, count); - } - - usb_serial_debug_data (__FILE__, __FUNCTION__, count, port->write_urb->transfer_buffer); - - /* set up our urb */ - usb_fill_bulk_urb (port->write_urb, serial->dev, - usb_sndbulkpipe (serial->dev, - port->bulk_out_endpointAddress), - port->write_urb->transfer_buffer, count, - ((serial->type->write_bulk_callback) ? - serial->type->write_bulk_callback : - generic_write_bulk_callback), port); - - /* send the data out the bulk port */ - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (result) - err("%s - failed submitting write urb, error %d", __FUNCTION__, result); - else - result = count; - - return result; - } - - /* no bulk out, so return 0 bytes written */ - return (0); -} - -static int generic_write_room (struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - int room = 0; - - dbg("%s - port %d", __FUNCTION__, port->number); - - if (serial->num_bulk_out) { - if (port->write_urb->status != -EINPROGRESS) - room = port->bulk_out_size; - } - - dbg("%s - returns %d", __FUNCTION__, room); - return (room); -} - -static int generic_chars_in_buffer (struct usb_serial_port *port) -{ - struct usb_serial *serial = port->serial; - int chars = 0; - - dbg("%s - port %d", __FUNCTION__, port->number); - - if (serial->num_bulk_out) { - if (port->write_urb->status == -EINPROGRESS) - chars = port->write_urb->transfer_buffer_length; - } - - dbg("%s - returns %d", __FUNCTION__, chars); - return (chars); -} - -static void generic_read_bulk_callback (struct urb *urb) -{ - struct usb_serial_port *port = (struct usb_serial_port *)urb->context; - struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); - struct tty_struct *tty; - unsigned char *data = urb->transfer_buffer; - int i; - int result; - - dbg("%s - port %d", __FUNCTION__, port->number); - - if (!serial) { - dbg("%s - bad serial pointer, exiting", __FUNCTION__); - return; - } - - if (urb->status) { - dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); - return; - } - - usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); - - tty = port->tty; - if (tty && urb->actual_length) { - for (i = 0; i < urb->actual_length ; ++i) { - /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */ - if(tty->flip.count >= TTY_FLIPBUF_SIZE) { - tty_flip_buffer_push(tty); - } - /* this doesn't actually push the data through unless tty->low_latency is set */ - tty_insert_flip_char(tty, data[i], 0); - } - tty_flip_buffer_push(tty); - } - - /* Continue trying to always read */ - usb_fill_bulk_urb (port->read_urb, serial->dev, - usb_rcvbulkpipe (serial->dev, - port->bulk_in_endpointAddress), - port->read_urb->transfer_buffer, - port->read_urb->transfer_buffer_length, - ((serial->type->read_bulk_callback) ? - serial->type->read_bulk_callback : - generic_read_bulk_callback), port); - result = usb_submit_urb(port->read_urb, GFP_ATOMIC); - if (result) - err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); -} - -static void generic_write_bulk_callback (struct urb *urb) -{ - struct usb_serial_port *port = (struct usb_serial_port *)urb->context; - struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); - - dbg("%s - port %d", __FUNCTION__, port->number); - - if (!serial) { - dbg("%s - bad serial pointer, exiting", __FUNCTION__); - return; - } - - if (urb->status) { - dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); - return; - } - - usb_serial_port_softint((void *)port); - - schedule_work(&port->work); -} - -static void generic_shutdown (struct usb_serial *serial) -{ - int i; - - dbg("%s", __FUNCTION__); - - /* stop reads and writes on all ports */ - for (i=0; i < serial->num_ports; ++i) { - generic_cleanup (&serial->port[i]); - } -} - void usb_serial_port_softint(void *private) { struct usb_serial_port *port = (struct usb_serial_port *)private; @@ -1268,7 +950,6 @@ int usb_serial_probe(struct usb_interface *interface, (dev->descriptor.idProduct == PL2303_PRODUCT_ID)) || ((dev->descriptor.idVendor == ATEN_VENDOR_ID) && (dev->descriptor.idProduct == ATEN_PRODUCT_ID))) { - //if (ifnum == 1) { if (interface != &dev->actconfig->interface[0]) { /* check out the endpoints of the other interface*/ //interface = &dev->actconfig->interface[ifnum ^ 1]; @@ -1303,7 +984,7 @@ int usb_serial_probe(struct usb_interface *interface, info("%s converter detected", type->name); #ifdef CONFIG_USB_SERIAL_GENERIC - if (type == &generic_device) { + if (type == &usb_serial_generic_device) { num_ports = num_bulk_out; if (num_ports == 0) { err("Generic device with no bulk out, not allowed."); @@ -1359,7 +1040,7 @@ int usb_serial_probe(struct usb_interface *interface, port->bulk_in_buffer, buffer_size, ((serial->type->read_bulk_callback) ? serial->type->read_bulk_callback : - generic_read_bulk_callback), + usb_serial_generic_read_bulk_callback), port); } @@ -1385,7 +1066,7 @@ int usb_serial_probe(struct usb_interface *interface, port->bulk_out_buffer, buffer_size, ((serial->type->write_bulk_callback) ? serial->type->write_bulk_callback : - generic_write_bulk_callback), + usb_serial_generic_write_bulk_callback), port); } @@ -1504,10 +1185,10 @@ void usb_serial_disconnect(struct usb_interface *interface) port = &serial->port[i]; down (&port->sem); if (port->tty != NULL) { + port->tty->driver_data = NULL; while (port->open_count > 0) { __serial_close(port, NULL); } - port->tty->driver_data = NULL; } up (&port->sem); } @@ -1607,7 +1288,7 @@ static int __init usb_serial_init(void) } /* register the generic driver, if we should */ - result = generic_register(); + result = usb_serial_generic_register(debug); if (result < 0) { err("%s - registering generic driver failed", __FUNCTION__); goto exit; @@ -1637,7 +1318,7 @@ exit_tty: tty_unregister_driver(&serial_tty_driver); exit_generic: - generic_deregister(); + usb_serial_generic_deregister(); exit: err ("%s - returning with error %d", __FUNCTION__, result); @@ -1649,7 +1330,7 @@ static void __exit usb_serial_exit(void) { usb_serial_console_exit(); - generic_deregister(); + usb_serial_generic_deregister(); usb_deregister(&usb_serial_driver); tty_unregister_driver(&serial_tty_driver); @@ -1699,12 +1380,6 @@ EXPORT_SYMBOL(usb_serial_deregister); EXPORT_SYMBOL(usb_serial_probe); EXPORT_SYMBOL(usb_serial_disconnect); EXPORT_SYMBOL(usb_serial_port_softint); -#ifdef USES_EZUSB_FUNCTIONS - EXPORT_SYMBOL(ezusb_writememory); - EXPORT_SYMBOL(ezusb_set_reset); -#endif - - /* Module information */ @@ -1714,11 +1389,3 @@ MODULE_LICENSE("GPL"); MODULE_PARM(debug, "i"); MODULE_PARM_DESC(debug, "Debug enabled or not"); - -#ifdef CONFIG_USB_SERIAL_GENERIC -MODULE_PARM(vendor, "h"); -MODULE_PARM_DESC(vendor, "User specified USB idVendor"); - -MODULE_PARM(product, "h"); -MODULE_PARM_DESC(product, "User specified USB idProduct"); -#endif diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h index 73c83d1a1415..82c75d867f39 100644 --- a/drivers/usb/serial/usb-serial.h +++ b/drivers/usb/serial/usb-serial.h @@ -237,24 +237,8 @@ extern void usb_serial_port_softint(void *private); extern int usb_serial_probe(struct usb_interface *iface, const struct usb_device_id *id); extern void usb_serial_disconnect(struct usb_interface *iface); -/* determine if we should include the EzUSB loader functions */ -#undef USES_EZUSB_FUNCTIONS -#if defined(CONFIG_USB_SERIAL_KEYSPAN_PDA) || defined(CONFIG_USB_SERIAL_KEYSPAN_PDA_MODULE) - #define USES_EZUSB_FUNCTIONS -#endif -#if defined(CONFIG_USB_SERIAL_XIRCOM) || defined(CONFIG_USB_SERIAL_XIRCOM_MODULE) - #define USES_EZUSB_FUNCTIONS -#endif -#if defined(CONFIG_USB_SERIAL_KEYSPAN) || defined(CONFIG_USB_SERIAL_KEYSPAN_MODULE) - #define USES_EZUSB_FUNCTIONS -#endif -#if defined(CONFIG_USB_SERIAL_WHITEHEAT) || defined(CONFIG_USB_SERIAL_WHITEHEAT_MODULE) - #define USES_EZUSB_FUNCTIONS -#endif -#ifdef USES_EZUSB_FUNCTIONS extern int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest); extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit); -#endif /* USB Serial console functions */ #ifdef CONFIG_USB_SERIAL_CONSOLE @@ -265,10 +249,20 @@ static inline void usb_serial_console_init (int debug, int minor) { } static inline void usb_serial_console_exit (void) { } #endif -/* Functions needed by the usb serial console code */ +/* Functions needed by other parts of the usbserial core */ extern struct usb_serial *usb_serial_get_by_minor (unsigned int minor); extern int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp); extern int usb_serial_generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count); +extern void usb_serial_generic_close (struct usb_serial_port *port, struct file *filp); +extern int usb_serial_generic_write_room (struct usb_serial_port *port); +extern int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port); +extern void usb_serial_generic_read_bulk_callback (struct urb *urb); +extern void usb_serial_generic_write_bulk_callback (struct urb *urb); +extern void usb_serial_generic_shutdown (struct usb_serial *serial); +extern int usb_serial_generic_register (int debug); +extern void usb_serial_generic_deregister (void); + +extern struct usb_serial_device_type usb_serial_generic_device; /* Inline functions to check the sanity of a pointer that is passed to us */ static inline int serial_paranoia_check (struct usb_serial *serial, const char *function) diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 9c4ba970eb35..2d05857bb1c5 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -186,6 +186,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) }, + { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) }, { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) }, @@ -209,6 +210,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) }, + { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) }, { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) }, diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h index a06f1e8070b2..3e5c23cb2e23 100644 --- a/drivers/usb/serial/visor.h +++ b/drivers/usb/serial/visor.h @@ -28,6 +28,7 @@ #define PALM_M125_ID 0x0040 #define PALM_M130_ID 0x0050 #define PALM_TUNGSTEN_T_ID 0x0060 +#define PALM_TUNGSTEN_Z_ID 0x0031 #define PALM_ZIRE_ID 0x0070 #define SONY_VENDOR_ID 0x054C diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 74eeef54f871..027354fd948c 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -202,10 +202,23 @@ struct whiteheat_command_private { #define THROTTLED 0x01 #define ACTUALLY_THROTTLED 0x02 +static int urb_pool_size = 8; + +struct whiteheat_urb_wrap { + struct list_head list; + struct urb *urb; +}; + struct whiteheat_private { spinlock_t lock; __u8 flags; __u8 mcr; + struct list_head rx_urbs_free; + struct list_head rx_urbs_submitted; + struct list_head rx_urb_q; + struct work_struct rx_work; + struct list_head tx_urbs_free; + struct list_head tx_urbs_submitted; }; @@ -215,6 +228,11 @@ static void stop_command_port(struct usb_serial *serial); static void command_port_write_callback(struct urb *urb); static void command_port_read_callback(struct urb *urb); +static int start_port_read(struct usb_serial_port *port); +static struct whiteheat_urb_wrap *urb_to_wrap(struct urb *urb, struct list_head *head); +static struct list_head *list_first(struct list_head *head); +static void rx_data_softint(void *private); + static int firm_send_command(struct usb_serial_port *port, __u8 command, __u8 *data, __u8 datasize); static int firm_open(struct usb_serial_port *port); static int firm_close(struct usb_serial_port *port); @@ -330,6 +348,11 @@ static int whiteheat_attach (struct usb_serial *serial) __u8 command[2] = { WHITEHEAT_GET_HW_INFO, 0 }; __u8 result[sizeof(*hw_info) + 1]; int i; + int j; + struct urb *urb; + int buf_size; + struct whiteheat_urb_wrap *wrap; + struct list_head *tmp; command_port = &serial->port[COMMAND_PORT]; @@ -373,18 +396,80 @@ static int whiteheat_attach (struct usb_serial *serial) port = &serial->port[i]; info = (struct whiteheat_private *)kmalloc(sizeof(struct whiteheat_private), GFP_KERNEL); - if (info == NULL) - goto no_memory; + if (info == NULL) { + err("%s: Out of memory for port structures\n", serial->type->name); + goto no_private; + } spin_lock_init(&info->lock); info->flags = 0; info->mcr = 0; + INIT_WORK(&info->rx_work, rx_data_softint, port); + + INIT_LIST_HEAD(&info->rx_urbs_free); + INIT_LIST_HEAD(&info->rx_urbs_submitted); + INIT_LIST_HEAD(&info->rx_urb_q); + INIT_LIST_HEAD(&info->tx_urbs_free); + INIT_LIST_HEAD(&info->tx_urbs_submitted); + + for (j = 0; j < urb_pool_size; j++) { + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + err("No free urbs available"); + goto no_rx_urb; + } + buf_size = port->read_urb->transfer_buffer_length; + urb->transfer_buffer = kmalloc(buf_size, GFP_KERNEL); + if (!urb->transfer_buffer) { + err("Couldn't allocate urb buffer"); + goto no_rx_buf; + } + wrap = kmalloc(sizeof(*wrap), GFP_KERNEL); + if (!wrap) { + err("Couldn't allocate urb wrapper"); + goto no_rx_wrap; + } + usb_fill_bulk_urb(urb, serial->dev, + usb_rcvbulkpipe(serial->dev, + port->bulk_in_endpointAddress), + urb->transfer_buffer, buf_size, + whiteheat_read_callback, port); + wrap->urb = urb; + list_add(&wrap->list, &info->rx_urbs_free); + + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) { + err("No free urbs available"); + goto no_tx_urb; + } + buf_size = port->write_urb->transfer_buffer_length; + urb->transfer_buffer = kmalloc(buf_size, GFP_KERNEL); + if (!urb->transfer_buffer) { + err("Couldn't allocate urb buffer"); + goto no_tx_buf; + } + wrap = kmalloc(sizeof(*wrap), GFP_KERNEL); + if (!wrap) { + err("Couldn't allocate urb wrapper"); + goto no_tx_wrap; + } + usb_fill_bulk_urb(urb, serial->dev, + usb_sndbulkpipe(serial->dev, + port->bulk_out_endpointAddress), + urb->transfer_buffer, buf_size, + whiteheat_write_callback, port); + wrap->urb = urb; + list_add(&wrap->list, &info->tx_urbs_free); + } + port->private = info; } command_info = (struct whiteheat_command_private *)kmalloc(sizeof(struct whiteheat_command_private), GFP_KERNEL); - if (command_info == NULL) - goto no_memory; + if (command_info == NULL) { + err("%s: Out of memory for port structures\n", serial->type->name); + goto no_command_private; + } spin_lock_init(&command_info->lock); command_info->port_running = 0; @@ -402,12 +487,35 @@ no_firmware: err("%s: please contact support@connecttech.com\n", serial->type->name); return -ENODEV; -no_memory: - for (i--; i >= 0; i--) { +no_command_private: + for (i = serial->num_ports - 1; i >= 0; i--) { port = &serial->port[i]; - kfree(port->private); + info = port->private; + for (j = urb_pool_size - 1; j >= 0; j--) { + tmp = list_first(&info->tx_urbs_free); + list_del(tmp); + wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); + urb = wrap->urb; + kfree(wrap); +no_tx_wrap: + kfree(urb->transfer_buffer); +no_tx_buf: + usb_free_urb(urb); +no_tx_urb: + tmp = list_first(&info->rx_urbs_free); + list_del(tmp); + wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); + urb = wrap->urb; + kfree(wrap); +no_rx_wrap: + kfree(urb->transfer_buffer); +no_rx_buf: + usb_free_urb(urb); +no_rx_urb: + } + kfree(info); +no_private: } - err("%s: Out of memory for port structures\n", serial->type->name); return -ENOMEM; } @@ -416,6 +524,11 @@ static void whiteheat_shutdown (struct usb_serial *serial) { struct usb_serial_port *command_port; struct usb_serial_port *port; + struct whiteheat_private *info; + struct whiteheat_urb_wrap *wrap; + struct urb *urb; + struct list_head *tmp; + struct list_head *tmp2; int i; dbg("%s", __FUNCTION__); @@ -423,12 +536,27 @@ static void whiteheat_shutdown (struct usb_serial *serial) /* free up our private data for our command port */ command_port = &serial->port[COMMAND_PORT]; kfree (command_port->private); - command_port->private = NULL; for (i = 0; i < serial->num_ports; i++) { port = &serial->port[i]; - kfree(port->private); - port->private = NULL; + info = port->private; + list_for_each_safe(tmp, tmp2, &info->rx_urbs_free) { + list_del(tmp); + wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); + urb = wrap->urb; + kfree(wrap); + kfree(urb->transfer_buffer); + usb_free_urb(urb); + } + list_for_each_safe(tmp, tmp2, &info->tx_urbs_free) { + list_del(tmp); + wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); + urb = wrap->urb; + kfree(wrap); + kfree(urb->transfer_buffer); + usb_free_urb(urb); + } + kfree(info); } return; @@ -446,6 +574,9 @@ static int whiteheat_open (struct usb_serial_port *port, struct file *filp) if (retval) goto exit; + if (port->tty) + port->tty->low_latency = 1; + /* send an open port command */ retval = firm_open(port); if (retval) { @@ -469,8 +600,7 @@ static int whiteheat_open (struct usb_serial_port *port, struct file *filp) usb_clear_halt(port->serial->dev, port->write_urb->pipe); /* Start reading from the device */ - port->read_urb->dev = port->serial->dev; - retval = usb_submit_urb(port->read_urb, GFP_KERNEL); + retval = start_port_read(port); if (retval) { err("%s - failed submitting read urb, error %d", __FUNCTION__, retval); firm_close(port); @@ -486,6 +616,13 @@ exit: static void whiteheat_close(struct usb_serial_port *port, struct file * filp) { + struct whiteheat_private *info = port->private; + struct whiteheat_urb_wrap *wrap; + struct urb *urb; + struct list_head *tmp; + struct list_head *tmp2; + unsigned long flags; + dbg("%s - port %d", __FUNCTION__, port->number); /* filp is NULL when called from usb_serial_disconnect */ @@ -515,8 +652,26 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp) firm_close(port); /* shutdown our bulk reads and writes */ - usb_unlink_urb (port->write_urb); - usb_unlink_urb (port->read_urb); + spin_lock_irqsave(&info->lock, flags); + list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) { + wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); + urb = wrap->urb; + usb_unlink_urb(urb); + list_del(tmp); + list_add(tmp, &info->rx_urbs_free); + } + list_for_each_safe(tmp, tmp2, &info->rx_urb_q) { + list_del(tmp); + list_add(tmp, &info->rx_urbs_free); + } + list_for_each_safe(tmp, tmp2, &info->tx_urbs_submitted) { + wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); + urb = wrap->urb; + usb_unlink_urb(urb); + list_del(tmp); + list_add(tmp, &info->tx_urbs_free); + } + spin_unlock_irqrestore(&info->lock, flags); stop_command_port(port->serial); @@ -527,7 +682,14 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp) static int whiteheat_write(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count) { struct usb_serial *serial = port->serial; + struct whiteheat_private *info = port->private; + struct whiteheat_urb_wrap *wrap; + struct urb *urb; int result; + int bytes; + int sent = 0; + unsigned long flags; + struct list_head *tmp; dbg("%s - port %d", __FUNCTION__, port->number); @@ -536,43 +698,65 @@ static int whiteheat_write(struct usb_serial_port *port, int from_user, const un return (0); } - if (port->write_urb->status == -EINPROGRESS) { - dbg ("%s - already writing", __FUNCTION__); - return (0); - } + while (count) { + spin_lock_irqsave(&info->lock, flags); + if (list_empty(&info->tx_urbs_free)) { + spin_unlock_irqrestore(&info->lock, flags); + break; + } + tmp = list_first(&info->tx_urbs_free); + list_del(tmp); + spin_unlock_irqrestore(&info->lock, flags); - count = (count > port->bulk_out_size) ? port->bulk_out_size : count; + wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); + urb = wrap->urb; + bytes = (count > port->bulk_out_size) ? port->bulk_out_size : count; + if (from_user) { + if (copy_from_user(urb->transfer_buffer, buf + sent, bytes)) + return -EFAULT; + } else { + memcpy (urb->transfer_buffer, buf + sent, bytes); + } - if (from_user) { - if (copy_from_user(port->write_urb->transfer_buffer, buf, count)) - return -EFAULT; - } - else { - memcpy (port->write_urb->transfer_buffer, buf, count); + usb_serial_debug_data (__FILE__, __FUNCTION__, bytes, urb->transfer_buffer); + + urb->dev = serial->dev; + urb->transfer_buffer_length = bytes; + result = usb_submit_urb(urb, GFP_ATOMIC); + if (result) { + err("%s - failed submitting write urb, error %d", __FUNCTION__, result); + sent = result; + spin_lock_irqsave(&info->lock, flags); + list_add(tmp, &info->tx_urbs_free); + spin_unlock_irqrestore(&info->lock, flags); + break; + } else { + sent += bytes; + count -= bytes; + spin_lock_irqsave(&info->lock, flags); + list_add(tmp, &info->tx_urbs_submitted); + spin_unlock_irqrestore(&info->lock, flags); + } } - usb_serial_debug_data (__FILE__, __FUNCTION__, count, port->write_urb->transfer_buffer); - - port->write_urb->dev = serial->dev; - port->write_urb->transfer_buffer_length = count; - result = usb_submit_urb(port->write_urb, GFP_ATOMIC); - if (result) - err("%s - failed submitting write urb, error %d", __FUNCTION__, result); - else - result = count; - - return result; + return sent; } static int whiteheat_write_room(struct usb_serial_port *port) { + struct whiteheat_private *info = port->private; + struct list_head *tmp; int room = 0; + unsigned long flags; dbg("%s - port %d", __FUNCTION__, port->number); - if (port->write_urb->status != -EINPROGRESS) - room = port->bulk_out_size; + spin_lock_irqsave(&info->lock, flags); + list_for_each(tmp, &info->tx_urbs_free) + room++; + spin_unlock_irqrestore(&info->lock, flags); + room *= port->bulk_out_size; dbg("%s - returns %d", __FUNCTION__, room); return (room); @@ -715,12 +899,20 @@ static void whiteheat_break_ctl(struct usb_serial_port *port, int break_state) { static int whiteheat_chars_in_buffer(struct usb_serial_port *port) { + struct whiteheat_private *info = port->private; + struct list_head *tmp; + struct whiteheat_urb_wrap *wrap; int chars = 0; + unsigned long flags; dbg("%s - port %d", __FUNCTION__, port->number); - if (port->write_urb->status == -EINPROGRESS) - chars = port->write_urb->transfer_buffer_length; + spin_lock_irqsave(&info->lock, flags); + list_for_each(tmp, &info->tx_urbs_submitted) { + wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); + chars += wrap->urb->transfer_buffer_length; + } + spin_unlock_irqrestore(&info->lock, flags); dbg ("%s - returns %d", __FUNCTION__, chars); return (chars); @@ -745,25 +937,19 @@ static void whiteheat_throttle (struct usb_serial_port *port) static void whiteheat_unthrottle (struct usb_serial_port *port) { struct whiteheat_private *info = (struct whiteheat_private *)port->private; - int result; + int actually_throttled; unsigned long flags; dbg("%s - port %d", __FUNCTION__, port->number); spin_lock_irqsave(&info->lock, flags); - - if (info->flags & ACTUALLY_THROTTLED) { - /* Continue trying to always read */ - port->read_urb->dev = port->serial->dev; - result = usb_submit_urb(port->read_urb, GFP_ATOMIC); - if (result) - err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); - } - + actually_throttled = info->flags & ACTUALLY_THROTTLED; info->flags &= ~(THROTTLED | ACTUALLY_THROTTLED); - spin_unlock_irqrestore(&info->lock, flags); + if (actually_throttled) + rx_data_softint(port); + return; } @@ -846,53 +1032,50 @@ static void whiteheat_read_callback(struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); - struct tty_struct *tty; + struct whiteheat_urb_wrap *wrap; unsigned char *data = urb->transfer_buffer; - int i; - int result; struct whiteheat_private *info = (struct whiteheat_private *)port->private; - unsigned long flags; dbg("%s - port %d", __FUNCTION__, port->number); + spin_lock(&info->lock); + wrap = urb_to_wrap(urb, &info->rx_urbs_submitted); + if (!wrap) { + spin_unlock(&info->lock); + err("%s - Not my urb!", __FUNCTION__); + return; + } + list_del(&wrap->list); + spin_unlock(&info->lock); + if (!serial) { dbg("%s - bad serial pointer, exiting", __FUNCTION__); + spin_lock(&info->lock); + list_add(&wrap->list, &info->rx_urbs_free); + spin_unlock(&info->lock); return; } if (urb->status) { dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status); + spin_lock(&info->lock); + list_add(&wrap->list, &info->rx_urbs_free); + spin_unlock(&info->lock); return; } usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data); - tty = port->tty; - if (tty && urb->actual_length) { - for (i = 0; i < urb->actual_length ; ++i) { - /* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */ - if(tty->flip.count >= TTY_FLIPBUF_SIZE) { - tty_flip_buffer_push(tty); - } - /* this doesn't actually push the data through unless tty->low_latency is set */ - tty_insert_flip_char(tty, data[i], 0); - } - tty_flip_buffer_push(tty); - } - - spin_lock_irqsave(&info->lock, flags); + spin_lock(&info->lock); + list_add_tail(&wrap->list, &info->rx_urb_q); if (info->flags & THROTTLED) { info->flags |= ACTUALLY_THROTTLED; - spin_unlock_irqrestore(&info->lock, flags); + spin_unlock(&info->lock); return; } - spin_unlock_irqrestore(&info->lock, flags); + spin_unlock(&info->lock); - /* Continue trying to always read */ - port->read_urb->dev = serial->dev; - result = usb_submit_urb(port->read_urb, GFP_ATOMIC); - if (result) - err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); + schedule_work(&info->rx_work); } @@ -900,9 +1083,22 @@ static void whiteheat_write_callback(struct urb *urb) { struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct usb_serial *serial = get_usb_serial (port, __FUNCTION__); + struct whiteheat_private *info = port->private; + struct whiteheat_urb_wrap *wrap; dbg("%s - port %d", __FUNCTION__, port->number); + spin_lock(&info->lock); + wrap = urb_to_wrap(urb, &info->tx_urbs_submitted); + if (!wrap) { + spin_unlock(&info->lock); + err("%s - Not my urb!", __FUNCTION__); + return; + } + list_del(&wrap->list); + list_add(&wrap->list, &info->tx_urbs_free); + spin_unlock(&info->lock); + if (!serial) { dbg("%s - bad serial pointer, exiting", __FUNCTION__); return; @@ -1176,6 +1372,122 @@ static void stop_command_port(struct usb_serial *serial) } +static int start_port_read(struct usb_serial_port *port) { + struct whiteheat_private *info = port->private; + struct whiteheat_urb_wrap *wrap; + struct urb *urb; + int retval = 0; + unsigned long flags; + struct list_head *tmp; + struct list_head *tmp2; + + spin_lock_irqsave(&info->lock, flags); + + list_for_each_safe(tmp, tmp2, &info->rx_urbs_free) { + list_del(tmp); + wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); + urb = wrap->urb; + urb->dev = port->serial->dev; + retval = usb_submit_urb(urb, GFP_KERNEL); + if (retval) { + list_add(tmp, &info->rx_urbs_free); + list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) { + wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); + urb = wrap->urb; + usb_unlink_urb(urb); + list_del(tmp); + list_add(tmp, &info->rx_urbs_free); + } + break; + } + list_add(tmp, &info->rx_urbs_submitted); + } + + spin_unlock_irqrestore(&info->lock, flags); + + return retval; +} + + +static struct whiteheat_urb_wrap *urb_to_wrap(struct urb* urb, struct list_head *head) { + struct whiteheat_urb_wrap *wrap; + struct list_head *tmp; + + list_for_each(tmp, head) { + wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); + if (wrap->urb == urb) + return wrap; + } + + return NULL; +} + + +static struct list_head *list_first(struct list_head *head) { + return head->next; +} + + +static void rx_data_softint(void *private) { + struct usb_serial_port *port = (struct usb_serial_port *)private; + struct whiteheat_private *info = port->private; + struct tty_struct *tty = port->tty; + struct whiteheat_urb_wrap *wrap; + struct urb *urb; + unsigned long flags; + struct list_head *tmp; + struct list_head *tmp2; + int result; + int sent = 0; + + spin_lock_irqsave(&info->lock, flags); + if (info->flags & THROTTLED) { + spin_unlock_irqrestore(&info->lock, flags); + return; + } + + list_for_each_safe(tmp, tmp2, &info->rx_urb_q) { + list_del(tmp); + spin_unlock_irqrestore(&info->lock, flags); + + wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); + urb = wrap->urb; + + if (tty && urb->actual_length) { + if (urb->actual_length > TTY_FLIPBUF_SIZE - tty->flip.count) { + spin_lock_irqsave(&info->lock, flags); + list_add(tmp, &info->rx_urb_q); + spin_unlock_irqrestore(&info->lock, flags); + tty_flip_buffer_push(tty); + schedule_work(&info->rx_work); + return; + } + + memcpy(tty->flip.char_buf_ptr, urb->transfer_buffer, urb->actual_length); + tty->flip.char_buf_ptr += urb->actual_length; + tty->flip.count += urb->actual_length; + sent += urb->actual_length; + } + + urb->dev = port->serial->dev; + result = usb_submit_urb(urb, GFP_ATOMIC); + if (result) { + err("%s - failed resubmitting read urb, error %d", __FUNCTION__, result); + spin_lock_irqsave(&info->lock, flags); + list_add(tmp, &info->rx_urbs_free); + continue; + } + + spin_lock_irqsave(&info->lock, flags); + list_add(tmp, &info->rx_urbs_submitted); + } + spin_unlock_irqrestore(&info->lock, flags); + + if (sent) + tty_flip_buffer_push(tty); +} + + /***************************************************************************** * Connect Tech's White Heat module functions *****************************************************************************/ @@ -1204,5 +1516,8 @@ MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_LICENSE("GPL"); +MODULE_PARM(urb_pool_size, "i"); +MODULE_PARM_DESC(urb_pool_size, "Number of urbs to use for buffering"); + MODULE_PARM(debug, "i"); MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/fs/attr.c b/fs/attr.c index af45dd627c01..c7c414b9929c 100644 --- a/fs/attr.c +++ b/fs/attr.c @@ -157,7 +157,8 @@ int notify_change(struct dentry * dentry, struct iattr * attr) return 0; if (inode->i_op && inode->i_op->setattr) { - if (!(error = security_inode_setattr(dentry, attr))) + error = security_inode_setattr(dentry, attr); + if (!error) error = inode->i_op->setattr(dentry, attr); } else { error = inode_change_ok(inode, attr); diff --git a/fs/dquot.c b/fs/dquot.c index dca590bbd8fb..5da20a7049ce 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -1307,7 +1307,8 @@ int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path) error = -EIO; if (!f->f_op || !f->f_op->read || !f->f_op->write) goto out_f; - if ((error = security_quota_on(f))) + error = security_quota_on(f); + if (error) goto out_f; inode = f->f_dentry->d_inode; error = -EACCES; diff --git a/fs/exec.c b/fs/exec.c index 3757201478c3..a0a4aa824ae6 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -841,7 +841,8 @@ int prepare_binprm(struct linux_binprm *bprm) } /* fill in binprm security blob */ - if ((retval = security_bprm_set(bprm))) + retval = security_bprm_set(bprm); + if (retval) return retval; memset(bprm->buf,0,BINPRM_BUF_SIZE); @@ -958,7 +959,8 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) } } #endif - if ((retval = security_bprm_check(bprm))) + retval = security_bprm_check(bprm); + if (retval) return retval; /* kernel module loader fixup */ @@ -1054,7 +1056,8 @@ int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs if ((retval = bprm.envc) < 0) goto out_mm; - if ((retval = security_bprm_alloc(&bprm))) + retval = security_bprm_alloc(&bprm); + if (retval) goto out; retval = prepare_binprm(&bprm); diff --git a/fs/fcntl.c b/fs/fcntl.c index 90900d2188a0..041b84ffd0ce 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -274,7 +274,8 @@ int f_setown(struct file *filp, unsigned long arg, int force) { int err; - if ((err = security_file_set_fowner(filp))) + err = security_file_set_fowner(filp); + if (err) return err; f_modown(filp, arg, current->uid, current->euid, force); @@ -367,7 +368,8 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) if (!filp) goto out; - if ((err = security_file_fcntl(filp, cmd, arg))) { + err = security_file_fcntl(filp, cmd, arg); + if (err) { fput(filp); return err; } @@ -390,7 +392,8 @@ asmlinkage long sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg if (!filp) goto out; - if ((err = security_file_fcntl(filp, cmd, arg))) { + err = security_file_fcntl(filp, cmd, arg); + if (err) { fput(filp); return err; } diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 2c9b1d26b8fd..d55097f12302 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -209,7 +209,7 @@ static void hugetlbfs_delete_inode(struct inode *inode) if (inode->i_data.nrpages) truncate_hugepages(&inode->i_data, 0); - security_ops->inode_delete(inode); + security_inode_delete(inode); clear_inode(inode); destroy_inode(inode); @@ -333,7 +333,7 @@ static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr) if (error) goto out; - error = security_ops->inode_setattr(dentry, attr); + error = security_inode_setattr(dentry, attr); if (error) goto out; diff --git a/fs/ioctl.c b/fs/ioctl.c index b0b6b2ed4c3b..9e16c74d67f0 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -59,7 +59,8 @@ asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) goto out; error = 0; - if ((error = security_file_ioctl(filp, cmd, arg))) { + error = security_file_ioctl(filp, cmd, arg); + if (error) { fput(filp); goto out; } diff --git a/fs/locks.c b/fs/locks.c index dac9a048ed35..04600003a4a0 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1185,7 +1185,8 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg) return -EACCES; if (!S_ISREG(inode->i_mode)) return -EINVAL; - if ((error = security_file_lock(filp, arg))) + error = security_file_lock(filp, arg); + if (error) return error; lock_kernel(); @@ -1298,7 +1299,8 @@ asmlinkage long sys_flock(unsigned int fd, unsigned int cmd) if (error) goto out_putf; - if ((error = security_file_lock(filp, cmd))) + error = security_file_lock(filp, cmd); + if (error) goto out_free; for (;;) { @@ -1449,7 +1451,8 @@ int fcntl_setlk(struct file *filp, unsigned int cmd, struct flock *l) goto out; } - if ((error = security_file_lock(filp, file_lock->fl_type))) + error = security_file_lock(filp, file_lock->fl_type); + if (error) goto out; if (filp->f_op && filp->f_op->lock != NULL) { @@ -1588,7 +1591,8 @@ int fcntl_setlk64(struct file *filp, unsigned int cmd, struct flock64 *l) goto out; } - if ((error = security_file_lock(filp, file_lock->fl_type))) + error = security_file_lock(filp, file_lock->fl_type); + if (error) goto out; if (filp->f_op && filp->f_op->lock != NULL) { diff --git a/fs/namei.c b/fs/namei.c index 8961c2eaba74..179732c79ece 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -413,7 +413,8 @@ static inline int do_follow_link(struct dentry *dentry, struct nameidata *nd) current->state = TASK_RUNNING; schedule(); } - if ((err = security_inode_follow_link(dentry, nd))) + err = security_inode_follow_link(dentry, nd); + if (err) goto loop; current->link_count++; current->total_link_count++; @@ -1124,7 +1125,8 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode) return -EACCES; /* shouldn't it be ENOSYS? */ mode &= S_IALLUGO; mode |= S_IFREG; - if ((error = security_inode_create(dir, dentry, mode))) + error = security_inode_create(dir, dentry, mode); + if (error) return error; DQUOT_INIT(dir); error = dir->i_op->create(dir, dentry, mode); @@ -1343,7 +1345,8 @@ do_link: * stored in nd->last.name and we will have to putname() it when we * are done. Procfs-like symlinks just set LAST_BIND. */ - if ((error = security_inode_follow_link(dentry, nd))) + error = security_inode_follow_link(dentry, nd); + if (error) goto exit_dput; UPDATE_ATIME(dentry->d_inode); error = dentry->d_inode->i_op->follow_link(dentry, nd); @@ -1408,7 +1411,8 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) if (!dir->i_op || !dir->i_op->mknod) return -EPERM; - if ((error = security_inode_mknod(dir, dentry, mode, dev))) + error = security_inode_mknod(dir, dentry, mode, dev); + if (error) return error; DQUOT_INIT(dir); @@ -1476,7 +1480,8 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) return -EPERM; mode &= (S_IRWXUGO|S_ISVTX); - if ((error = security_inode_mkdir(dir, dentry, mode))) + error = security_inode_mkdir(dir, dentry, mode); + if (error) return error; DQUOT_INIT(dir); @@ -1568,7 +1573,8 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) if (d_mountpoint(dentry)) error = -EBUSY; else { - if (!(error = security_inode_rmdir(dir, dentry))) { + error = security_inode_rmdir(dir, dentry); + if (!error) { error = dir->i_op->rmdir(dir, dentry); if (!error) dentry->d_inode->i_flags |= S_DEAD; @@ -1641,7 +1647,8 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) if (d_mountpoint(dentry)) error = -EBUSY; else { - if (!(error = security_inode_unlink(dir, dentry))) + error = security_inode_unlink(dir, dentry); + if (error) error = dir->i_op->unlink(dir, dentry); } up(&dentry->d_inode->i_sem); @@ -1704,7 +1711,8 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) if (!dir->i_op || !dir->i_op->symlink) return -EPERM; - if ((error = security_inode_symlink(dir, dentry, oldname))) + error = security_inode_symlink(dir, dentry, oldname); + if (error) return error; DQUOT_INIT(dir); @@ -1774,7 +1782,8 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de if (S_ISDIR(old_dentry->d_inode->i_mode)) return -EPERM; - if ((error = security_inode_link(old_dentry, dir, new_dentry))) + error = security_inode_link(old_dentry, dir, new_dentry); + if (error) return error; down(&old_dentry->d_inode->i_sem); @@ -1882,7 +1891,8 @@ int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, return error; } - if ((error = security_inode_rename(old_dir, old_dentry, new_dir, new_dentry))) + error = security_inode_rename(old_dir, old_dentry, new_dir, new_dentry); + if (error) return error; target = new_dentry->d_inode; @@ -1916,7 +1926,8 @@ int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry, struct inode *target; int error; - if ((error = security_inode_rename(old_dir, old_dentry, new_dir, new_dentry))) + error = security_inode_rename(old_dir, old_dentry, new_dir, new_dentry); + if (error) return error; dget(new_dentry); diff --git a/fs/namespace.c b/fs/namespace.c index 1841cc0bdd7b..64b4b149895f 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -289,7 +289,8 @@ static int do_umount(struct vfsmount *mnt, int flags) struct super_block * sb = mnt->mnt_sb; int retval = 0; - if ((retval = security_sb_umount(mnt, flags))) + retval = security_sb_umount(mnt, flags); + if (retval) return retval; /* @@ -470,7 +471,8 @@ static int graft_tree(struct vfsmount *mnt, struct nameidata *nd) if (IS_DEADDIR(nd->dentry->d_inode)) goto out_unlock; - if ((err = security_sb_check_sb(mnt, nd))) + err = security_sb_check_sb(mnt, nd); + if (err) goto out_unlock; spin_lock(&dcache_lock); @@ -740,7 +742,8 @@ long do_mount(char * dev_name, char * dir_name, char *type_page, if (retval) return retval; - if ((retval = security_sb_mount(dev_name, &nd, type_page, flags, data_page))) + retval = security_sb_mount(dev_name, &nd, type_page, flags, data_page); + if (retval) goto dput_out; if (flags & MS_REMOUNT) @@ -985,7 +988,8 @@ asmlinkage long sys_pivot_root(const char *new_root, const char *put_old) if (error) goto out1; - if ((error = security_sb_pivotroot(&old_nd, &new_nd))) { + error = security_sb_pivotroot(&old_nd, &new_nd); + if (error) { path_release(&old_nd); goto out1; } diff --git a/fs/open.c b/fs/open.c index ecfb462a282d..e06322405948 100644 --- a/fs/open.c +++ b/fs/open.c @@ -31,7 +31,8 @@ int vfs_statfs(struct super_block *sb, struct statfs *buf) retval = -ENOSYS; if (sb->s_op && sb->s_op->statfs) { memset(buf, 0, sizeof(struct statfs)); - if ((retval = security_sb_statfs(sb))) + retval = security_sb_statfs(sb); + if (retval) return retval; retval = sb->s_op->statfs(sb, buf); } diff --git a/fs/read_write.c b/fs/read_write.c index f8e221b2e9ff..13af577513b9 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -193,7 +193,8 @@ ssize_t vfs_read(struct file *file, char *buf, size_t count, loff_t *pos) ret = locks_verify_area(FLOCK_VERIFY_READ, inode, file, *pos, count); if (!ret) { - if (!(ret = security_file_permission (file, MAY_READ))) { + ret = security_file_permission (file, MAY_READ); + if (!ret) { if (file->f_op->read) ret = file->f_op->read(file, buf, count, pos); else @@ -232,7 +233,8 @@ ssize_t vfs_write(struct file *file, const char *buf, size_t count, loff_t *pos) ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file, *pos, count); if (!ret) { - if (!(ret = security_file_permission (file, MAY_WRITE))) { + ret = security_file_permission (file, MAY_WRITE); + if (!ret) { if (file->f_op->write) ret = file->f_op->write(file, buf, count, pos); else diff --git a/fs/readdir.c b/fs/readdir.c index 31c6298d6202..69312c338eba 100644 --- a/fs/readdir.c +++ b/fs/readdir.c @@ -22,7 +22,8 @@ int vfs_readdir(struct file *file, filldir_t filler, void *buf) if (!file->f_op || !file->f_op->readdir) goto out; - if ((res = security_file_permission(file, MAY_READ))) + res = security_file_permission(file, MAY_READ); + if (res) goto out; down(&inode->i_sem); diff --git a/fs/stat.c b/fs/stat.c index 9ecf6c7db0a1..375661315ecd 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -38,7 +38,8 @@ int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) struct inode *inode = dentry->d_inode; int retval; - if ((retval = security_inode_getattr(mnt, dentry))) + retval = security_inode_getattr(mnt, dentry); + if (retval) return retval; if (inode->i_op->getattr) @@ -241,7 +242,8 @@ asmlinkage long sys_readlink(const char * path, char * buf, int bufsiz) error = -EINVAL; if (inode->i_op && inode->i_op->readlink) { - if (!(error = security_inode_readlink(nd.dentry))) { + error = security_inode_readlink(nd.dentry); + if (!error) { UPDATE_ATIME(inode); error = inode->i_op->readlink(nd.dentry, buf, bufsiz); } diff --git a/fs/xattr.c b/fs/xattr.c index 933a94031f5b..a0ad0fa76d59 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -86,7 +86,8 @@ setxattr(struct dentry *d, char *name, void *value, size_t size, int flags) error = -EOPNOTSUPP; if (d->d_inode->i_op && d->d_inode->i_op->setxattr) { - if ((error = security_inode_setxattr(d, kname, kvalue, size, flags))) + error = security_inode_setxattr(d, kname, kvalue, size, flags); + if (error) goto out; down(&d->d_inode->i_sem); error = d->d_inode->i_op->setxattr(d, kname, kvalue, size, flags); @@ -162,7 +163,8 @@ getxattr(struct dentry *d, char *name, void *value, size_t size) error = -EOPNOTSUPP; if (d->d_inode->i_op && d->d_inode->i_op->getxattr) { - if ((error = security_inode_getxattr(d, kname))) + error = security_inode_getxattr(d, kname); + if (error) goto out; down(&d->d_inode->i_sem); error = d->d_inode->i_op->getxattr(d, kname, kvalue, size); @@ -234,7 +236,8 @@ listxattr(struct dentry *d, char *list, size_t size) error = -EOPNOTSUPP; if (d->d_inode->i_op && d->d_inode->i_op->listxattr) { - if ((error = security_inode_listxattr(d))) + error = security_inode_listxattr(d); + if (error) goto out; down(&d->d_inode->i_sem); error = d->d_inode->i_op->listxattr(d, klist, size); @@ -308,7 +311,8 @@ removexattr(struct dentry *d, char *name) error = -EOPNOTSUPP; if (d->d_inode->i_op && d->d_inode->i_op->removexattr) { - if ((error = security_inode_removexattr(d, kname))) + error = security_inode_removexattr(d, kname); + if (error) goto out; down(&d->d_inode->i_sem); error = d->d_inode->i_op->removexattr(d, kname); diff --git a/include/linux/usb.h b/include/linux/usb.h index 0f486d95bdb7..774d35815121 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -901,14 +901,11 @@ extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate); /* * timeouts, in seconds, used for sending/receiving control messages * they typically complete within a few frames (msec) after they're issued + * USB identifies 5 second timeouts, maybe more in a few cases, and a few + * slow devices (like some MGE Ellipse UPSes) actually push that limit. */ -#ifdef CONFIG_USB_LONG_TIMEOUT -#define USB_CTRL_GET_TIMEOUT 4 -#else -#define USB_CTRL_GET_TIMEOUT 3 -#endif - -#define USB_CTRL_SET_TIMEOUT 3 +#define USB_CTRL_GET_TIMEOUT 5 +#define USB_CTRL_SET_TIMEOUT 5 /** diff --git a/ipc/msg.c b/ipc/msg.c index 8ec4c70d0256..3df7cd96955a 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -101,7 +101,8 @@ static int newque (key_t key, int msgflg) msq->q_perm.key = key; msq->q_perm.security = NULL; - if ((retval = security_msg_queue_alloc(msq))) { + retval = security_msg_queue_alloc(msq); + if (retval) { ipc_rcu_free(msq, sizeof(*msq)); return retval; } diff --git a/ipc/sem.c b/ipc/sem.c index 4fe11b41cd80..166f839d0995 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -136,7 +136,8 @@ static int newary (key_t key, int nsems, int semflg) sma->sem_perm.key = key; sma->sem_perm.security = NULL; - if ((retval = security_sem_alloc(sma))) { + retval = security_sem_alloc(sma); + if (retval) { ipc_rcu_free(sma, size); return retval; } diff --git a/ipc/shm.c b/ipc/shm.c index 45ef77080165..8a6b7a5244bb 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -188,7 +188,8 @@ static int newseg (key_t key, int shmflg, size_t size) shp->shm_flags = (shmflg & S_IRWXUGO); shp->shm_perm.security = NULL; - if ((error = security_shm_alloc(shp))) { + error = security_shm_alloc(shp); + if (error) { ipc_rcu_free(shp, sizeof(*shp)); return error; } diff --git a/kernel/acct.c b/kernel/acct.c index 1a5a5a3532ab..9e9276d635f7 100644 --- a/kernel/acct.c +++ b/kernel/acct.c @@ -223,7 +223,8 @@ asmlinkage long sys_acct(const char *name) } } - if ((error = security_acct(file))) + error = security_acct(file); + if (error) return error; spin_lock(&acct_globals.lock); diff --git a/kernel/fork.c b/kernel/fork.c index 3ae5525863af..f1ec2c2d2fe0 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -717,7 +717,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, if ((clone_flags & CLONE_DETACHED) && !(clone_flags & CLONE_THREAD)) return ERR_PTR(-EINVAL); - if ((retval = security_task_create(clone_flags))) + retval = security_task_create(clone_flags); + if (retval) goto fork_out; retval = -ENOMEM; diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 3657ada2e235..7e20ed1c1d8a 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -101,7 +101,8 @@ int ptrace_attach(struct task_struct *task) /* the same process cannot be attached many times */ if (task->ptrace & PT_PTRACED) goto bad; - if ((retval = security_ptrace(current, task))) + retval = security_ptrace(current, task); + if (retval) goto bad; /* Go */ diff --git a/kernel/sched.c b/kernel/sched.c index d76d3dbb698e..b7c0cff29846 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1348,7 +1348,8 @@ asmlinkage long sys_nice(int increment) if (nice > 19) nice = 19; - if ((retval = security_task_setnice(current, nice))) + retval = security_task_setnice(current, nice); + if (retval) return retval; set_user_nice(current, nice); @@ -1469,7 +1470,8 @@ static int setscheduler(pid_t pid, int policy, struct sched_param *param) !capable(CAP_SYS_NICE)) goto out_unlock; - if ((retval = security_task_setscheduler(p, policy, &lp))) + retval = security_task_setscheduler(p, policy, &lp); + if (retval) goto out_unlock; array = p->array; @@ -1532,7 +1534,8 @@ asmlinkage long sys_sched_getscheduler(pid_t pid) read_lock(&tasklist_lock); p = find_process_by_pid(pid); if (p) { - if (!(retval = security_task_getscheduler(p))) + retval = security_task_getscheduler(p); + if (!retval) retval = p->policy; } read_unlock(&tasklist_lock); @@ -1561,7 +1564,8 @@ asmlinkage long sys_sched_getparam(pid_t pid, struct sched_param *param) if (!p) goto out_unlock; - if ((retval = security_task_getscheduler(p))) + retval = security_task_getscheduler(p); + if (retval) goto out_unlock; lp.sched_priority = p->rt_priority; @@ -1820,7 +1824,8 @@ asmlinkage long sys_sched_rr_get_interval(pid_t pid, struct timespec *interval) if (!p) goto out_unlock; - if ((retval = security_task_getscheduler(p))) + retval = security_task_getscheduler(p); + if (retval) goto out_unlock; jiffies_to_timespec(p->policy & SCHED_FIFO ? diff --git a/kernel/signal.c b/kernel/signal.c index fd8e2124aed0..6aa968dde2bf 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -739,7 +739,8 @@ specific_send_sig_info(int sig, struct siginfo *info, struct task_struct *t, int ret = -EPERM; if (bad_signal(sig, info, t)) goto out; - if ((ret = security_task_kill(t, info, sig))) + ret = security_task_kill(t, info, sig); + if (ret) goto out; /* The null signal is a permissions and process existence probe. diff --git a/kernel/sys.c b/kernel/sys.c index 24f9fd7af045..9e4b66388c29 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -485,7 +485,8 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid) int new_egid = old_egid; int retval; - if ((retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE))) + retval = security_task_setgid(rgid, egid, (gid_t)-1, LSM_SETID_RE); + if (retval) return retval; if (rgid != (gid_t) -1) { @@ -530,7 +531,8 @@ asmlinkage long sys_setgid(gid_t gid) int old_egid = current->egid; int retval; - if ((retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID))) + retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_ID); + if (retval) return retval; if (capable(CAP_SETGID)) @@ -603,7 +605,8 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid) int old_ruid, old_euid, old_suid, new_ruid, new_euid; int retval; - if ((retval = security_task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE))) + retval = security_task_setuid(ruid, euid, (uid_t)-1, LSM_SETID_RE); + if (retval) return retval; new_ruid = old_ruid = current->uid; @@ -663,7 +666,8 @@ asmlinkage long sys_setuid(uid_t uid) int old_ruid, old_suid, new_ruid, new_suid; int retval; - if ((retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID))) + retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_ID); + if (retval) return retval; old_ruid = new_ruid = current->uid; @@ -700,7 +704,8 @@ asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid) int old_suid = current->suid; int retval; - if ((retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES))) + retval = security_task_setuid(ruid, euid, suid, LSM_SETID_RES); + if (retval) return retval; if (!capable(CAP_SETUID)) { @@ -751,7 +756,8 @@ asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid) { int retval; - if ((retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES))) + retval = security_task_setgid(rgid, egid, sgid, LSM_SETID_RES); + if (retval) return retval; if (!capable(CAP_SETGID)) { @@ -804,7 +810,8 @@ asmlinkage long sys_setfsuid(uid_t uid) int old_fsuid; int retval; - if ((retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS))) + retval = security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS); + if (retval) return retval; old_fsuid = current->fsuid; @@ -820,7 +827,8 @@ asmlinkage long sys_setfsuid(uid_t uid) current->fsuid = uid; } - if ((retval = security_task_post_setuid(old_fsuid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS))) + retval = security_task_post_setuid(old_fsuid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS); + if (retval) return retval; return old_fsuid; @@ -834,7 +842,8 @@ asmlinkage long sys_setfsgid(gid_t gid) int old_fsgid; int retval; - if ((retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS))) + retval = security_task_setgid(gid, (gid_t)-1, (gid_t)-1, LSM_SETID_FS); + if (retval) return retval; old_fsgid = current->fsgid; @@ -959,7 +968,8 @@ asmlinkage long sys_getpgid(pid_t pid) retval = -ESRCH; if (p) { - if (!(retval = security_task_getpgid(p))) + retval = security_task_getpgid(p); + if (!retval) retval = p->pgrp; } read_unlock(&tasklist_lock); @@ -986,7 +996,8 @@ asmlinkage long sys_getsid(pid_t pid) retval = -ESRCH; if(p) { - if (!(retval = security_task_getsid(p))) + retval = security_task_getsid(p); + if (!retval) retval = p->session; } read_unlock(&tasklist_lock); @@ -1067,7 +1078,8 @@ asmlinkage long sys_setgroups(int gidsetsize, gid_t *grouplist) return -EINVAL; if(copy_from_user(groups, grouplist, gidsetsize * sizeof(gid_t))) return -EFAULT; - if ((retval = security_task_setgroups(gidsetsize, groups))) + retval = security_task_setgroups(gidsetsize, groups); + if (retval) return retval; memcpy(current->groups, groups, gidsetsize * sizeof(gid_t)); current->ngroups = gidsetsize; @@ -1230,7 +1242,8 @@ asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit *rlim) return -EPERM; } - if ((retval = security_task_setrlimit(resource, &new_rlim))) + retval = security_task_setrlimit(resource, &new_rlim); + if (retval) return retval; *old_rlim = new_rlim; @@ -1304,7 +1317,8 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, int error = 0; int sig; - if ((error = security_task_prctl(option, arg2, arg3, arg4, arg5))) + error = security_task_prctl(option, arg2, arg3, arg4, arg5); + if (error) return error; switch (option) { diff --git a/kernel/uid16.c b/kernel/uid16.c index 53d054061dad..6158db4e718f 100644 --- a/kernel/uid16.c +++ b/kernel/uid16.c @@ -140,7 +140,8 @@ asmlinkage long sys_setgroups16(int gidsetsize, old_gid_t *grouplist) return -EFAULT; for (i = 0 ; i < gidsetsize ; i++) new_groups[i] = (gid_t)groups[i]; - if ((i = security_task_setgroups(gidsetsize, new_groups))) + i = security_task_setgroups(gidsetsize, new_groups); + if (i) return i; memcpy(current->groups, new_groups, gidsetsize * sizeof(gid_t)); current->ngroups = gidsetsize; diff --git a/mm/mmap.c b/mm/mmap.c index a65ca807cd36..76800c94aaad 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -504,7 +504,8 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, } } - if ((error = security_file_mmap(file, prot, flags))) + error = security_file_mmap(file, prot, flags); + if (error) return error; /* Clear old maps */ diff --git a/mm/mprotect.c b/mm/mprotect.c index 722cff4d16f0..978a9509c350 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -263,7 +263,8 @@ sys_mprotect(unsigned long start, size_t len, unsigned long prot) goto out; } - if ((error = security_file_mprotect(vma, prot))) + error = security_file_mprotect(vma, prot); + if (error) goto out; if (vma->vm_end > end) { diff --git a/net/core/scm.c b/net/core/scm.c index 2a51809ce125..9e14001c8a44 100644 --- a/net/core/scm.c +++ b/net/core/scm.c @@ -217,7 +217,8 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm) for (i=0, cmfptr=(int*)CMSG_DATA(cm); i<fdmax; i++, cmfptr++) { int new_fd; - if ((err = security_file_receive(fp[i]))) + err = security_file_receive(fp[i]); + if (err) break; err = get_unused_fd(); if (err < 0) |
