Signed-off-by: Andrew Morton --- 25-akpm/Documentation/usb/philips.txt | 87 ++- 25-akpm/drivers/usb/class/cdc-acm.c | 147 ++++- 25-akpm/drivers/usb/class/cdc-acm.h | 14 25-akpm/drivers/usb/core/hub.c | 81 ++- 25-akpm/drivers/usb/core/hub.h | 2 25-akpm/drivers/usb/gadget/dummy_hcd.c | 43 + 25-akpm/drivers/usb/gadget/ether.c | 10 25-akpm/drivers/usb/gadget/file_storage.c | 2 25-akpm/drivers/usb/gadget/inode.c | 184 ++++++ 25-akpm/drivers/usb/gadget/serial.c | 2 25-akpm/drivers/usb/gadget/zero.c | 2 25-akpm/drivers/usb/host/ehci-hcd.c | 29 - 25-akpm/drivers/usb/host/uhci-debug.c | 2 25-akpm/drivers/usb/host/uhci-hcd.c | 19 25-akpm/drivers/usb/host/uhci-hub.c | 4 25-akpm/drivers/usb/media/Kconfig | 2 25-akpm/drivers/usb/media/konicawc.c | 2 25-akpm/drivers/usb/media/pwc-ctrl.c | 775 +++++++++++++---------------- 25-akpm/drivers/usb/media/pwc-if.c | 225 +++++--- 25-akpm/drivers/usb/media/pwc-ioctl.h | 88 ++- 25-akpm/drivers/usb/media/pwc-misc.c | 50 + 25-akpm/drivers/usb/media/pwc-uncompress.c | 33 - 25-akpm/drivers/usb/media/pwc-uncompress.h | 16 25-akpm/drivers/usb/media/pwc.h | 43 - 25-akpm/drivers/usb/net/kaweth.c | 4 25-akpm/drivers/usb/serial/pl2303.c | 52 + 25-akpm/drivers/usb/storage/transport.c | 6 25-akpm/fs/aio.c | 1 drivers/usb/input/hid-tmff.c | 0 29 files changed, 1220 insertions(+), 705 deletions(-) diff -puN Documentation/usb/philips.txt~bk-usb Documentation/usb/philips.txt --- 25/Documentation/usb/philips.txt~bk-usb 2004-06-28 20:21:13.839810040 -0700 +++ 25-akpm/Documentation/usb/philips.txt 2004-06-28 20:21:13.892801984 -0700 @@ -1,13 +1,40 @@ -This file contains some additional information for the Philips webcams. -E-mail: webcam@smcc.demon.nl Last updated: 2001-09-24 - -The main webpage for the Philips driver is http://www.smcc.demon.nl/webcam/. -It contains a lot of extra information, a FAQ, and the binary plugin -'PWCX'. This plugin contains decompression routines that allow you to -use higher image sizes and framerates; in addition the webcam uses less -bandwidth on the USB bus (handy if you want to run more than 1 camera -simultaneously). These routines fall under an NDA, and may therefor not be -distributed as source; however, its use is completely optional. +This file contains some additional information for the Philips and OEM webcams. +E-mail: webcam@smcc.demon.nl Last updated: 2004-01-19 +Site: http://www.smcc.demon.nl/webcam/ + +As of this moment, the following cameras are supported: + * Philips PCA645 + * Philips PCA646 + * Philips PCVC675 + * Philips PCVC680 + * Philips PCVC690 + * Philips PCVC720/40 + * Philips PCVC730 + * Philips PCVC740 + * Philips PCVC750 + * Askey VC010 + * Creative Labs Webcam 5 + * Creative Labs Webcam Pro Ex + * Logitech QuickCam 3000 Pro + * Logitech QuickCam 4000 Pro + * Logitech QuickCam Notebook Pro + * Logitech QuickCam Zoom + * Logitech QuickCam Orbit + * Logitech QuickCam Sphere + * Samsung MPC-C10 + * Samsung MPC-C30 + * Sotec Afina Eye + * AME CU-001 + * Visionite VCS-UM100 + * Visionite VCS-UC300 + +The main webpage for the Philips driver is at the address above. It contains +a lot of extra information, a FAQ, and the binary plugin 'PWCX'. This plugin +contains decompression routines that allow you to use higher image sizes and +framerates; in addition the webcam uses less bandwidth on the USB bus (handy +if you want to run more than 1 camera simultaneously). These routines fall +under a NDA, and may therefor not be distributed as source; however, its use +is completely optional. You can build this code either into your kernel, or as a module. I recommend the latter, since it makes troubleshooting a lot easier. The built-in @@ -27,14 +54,14 @@ fps Specifies the desired framerate. Is an integer in the range of 4-30. fbufs - This parameter specifies the number of internal buffers to use for storing + This paramter specifies the number of internal buffers to use for storing frames from the cam. This will help if the process that reads images from - the cam is a bit slow or momentarily busy. However, on slow machines it + the cam is a bit slow or momentarely busy. However, on slow machines it only introduces lag, so choose carefully. The default is 3, which is reasonable. You can set it between 2 and 5. mbufs - This is an integer between 1 and 4. It will tell the module the number of + This is an integer between 1 and 10. It will tell the module the number of buffers to reserve for mmap(), VIDIOCCGMBUF, VIDIOCMCAPTURE and friends. The default is 2, which is adequate for most applications (double buffering). @@ -45,9 +72,9 @@ mbufs slack when your program is behind. But you need a multi-threaded or forked program to really take advantage of these buffers. - The absolute maximum is 4, but don't set it too high! Every buffer takes - up 1.22 MB of RAM, so unless you have a lot of memory setting this to - something more than 2 is an absolute waste. This memory is only + The absolute maximum is 10, but don't set it too high! Every buffer takes + up 460 KB of RAM, so unless you have a lot of memory setting this to + something more than 4 is an absolute waste. This memory is only allocated during open(), so nothing is wasted when the camera is not in use. @@ -74,9 +101,10 @@ compression (only useful with the plugin introduce some unwanted artefacts. The default is 2, medium compression. See the FAQ on the website for an overview of which modes require compression. - - The compression parameter only applies to the Vesta & ToUCam cameras. - The 645 and 646 have fixed compression parameters. + + The compression parameter does not apply to the 645 and 646 cameras + and OEM models derived from those (only a few). Most cams honour this + parameter. leds This settings takes 2 integers, that define the on/off time for the LED @@ -89,14 +117,17 @@ leds leds=0,0 - the LED never goes on, making it suitable for silent survaillance. + the LED never goes on, making it suitable for silent surveillance. By default the camera's LED is on solid while in use, and turned off when the camera is not used anymore. - This parameter works only with the ToUCam range of cameras (730, 740, - 750). For other cameras this command is silently ignored, and the LED - cannot be controlled. + This parameter works only with the ToUCam range of cameras (720, 730, 740, + 750) and OEMs. For other cameras this command is silently ignored, and + the LED cannot be controlled. + + Finally: this parameters does not take effect UNTIL the first time you + open the camera device. Until then, the LED remains on. dev_hint A long standing problem with USB devices is their dynamic nature: you @@ -126,7 +157,7 @@ dev_hint other cameras will get the first free available slot (see below). - dev_hint=645:1,680=2 The PCA645 camera will get /dev/video1, + dev_hint=645:1,680:2 The PCA645 camera will get /dev/video1, and a PCVC680 /dev/video2. dev_hint=645.0123:3,645.4567:0 The PCA645 camera with serialnumber @@ -176,13 +207,16 @@ trace 64 0x40 Show viewport and image sizes Off + 128 0x80 PWCX debugging Off For example, to trace the open() & read() fuctions, sum 8 + 4 = 12, so you would supply trace=12 during insmod or modprobe. If you want to turn the initialization and probing tracing off, set trace=0. The default value for trace is 35 (0x23). - Example: + + +Example: # modprobe pwc size=cif fps=15 power_save=1 @@ -192,7 +226,7 @@ cameras. Each camera has its own set of size and fps only specify defaults when you open() the device; this is to accommodate some tools that don't set the size. You can change these settings after open() with the Video4Linux ioctl() calls. The default of -defaults is QCIF size at 10 fps, BGR order. +defaults is QCIF size at 10 fps. The compression parameter is semiglobal; it sets the initial compression preference for all camera's, but this parameter can be set per camera with @@ -200,4 +234,3 @@ the VIDIOCPWCSCQUAL ioctl() call. All parameters are optional. - diff -puN drivers/usb/class/cdc-acm.c~bk-usb drivers/usb/class/cdc-acm.c --- 25/drivers/usb/class/cdc-acm.c~bk-usb 2004-06-28 20:21:13.841809736 -0700 +++ 25-akpm/drivers/usb/class/cdc-acm.c 2004-06-28 20:21:13.895801528 -0700 @@ -5,6 +5,7 @@ * Copyright (c) 1999 Pavel Machek * Copyright (c) 1999 Johannes Erdfelt * Copyright (c) 2000 Vojtech Pavlik + * Copyright (c) 2004 Oliver Neukum * * USB Abstract Control Model driver for USB modems and ISDN adapters * @@ -60,6 +61,7 @@ #include #include #include +#include #include "cdc-acm.h" @@ -108,7 +110,7 @@ static void acm_ctrl_irq(struct urb *urb { struct acm *acm = urb->context; struct usb_ctrlrequest *dr = urb->transfer_buffer; - unsigned char *data = (unsigned char *)(dr + 1); + unsigned char *data; int newctrl; int status; @@ -130,6 +132,7 @@ static void acm_ctrl_irq(struct urb *urb if (!ACM_READY(acm)) goto exit; + data = (unsigned char *)(dr + 1); switch (dr->bRequest) { case ACM_IRQ_NETWORK: @@ -139,7 +142,7 @@ static void acm_ctrl_irq(struct urb *urb case ACM_IRQ_LINE_STATE: - newctrl = le16_to_cpup((__u16 *) data); + newctrl = le16_to_cpu(get_unaligned((__u16 *) data)); if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) { dbg("calling hangup"); @@ -172,6 +175,7 @@ exit: static void acm_read_bulk(struct urb *urb, struct pt_regs *regs) { struct acm *acm = urb->context; + dbg("Entering acm_read_bulk with status %d\n", urb->status); if (!ACM_READY(acm)) return; @@ -190,6 +194,7 @@ static void acm_rx_tasklet(unsigned long struct tty_struct *tty = acm->tty; unsigned char *data = urb->transfer_buffer; int i = 0; + dbg("Entering acm_rx_tasklet"); if (urb->actual_length > 0 && !acm->throttle) { for (i = 0; i < urb->actual_length && !acm->throttle; i++) { @@ -200,14 +205,20 @@ static void acm_rx_tasklet(unsigned long } tty_insert_flip_char(tty, data[i], 0); } + dbg("Handed %d bytes to tty layer", i+1); tty_flip_buffer_push(tty); } + spin_lock(&acm->throttle_lock); if (acm->throttle) { + dbg("Throtteling noticed"); memmove(data, data + i, urb->actual_length - i); urb->actual_length -= i; + acm->resubmit_to_unthrottle = 1; + spin_unlock(&acm->throttle_lock); return; } + spin_unlock(&acm->throttle_lock); urb->actual_length = 0; urb->dev = acm->dev; @@ -221,6 +232,7 @@ static void acm_rx_tasklet(unsigned long static void acm_write_bulk(struct urb *urb, struct pt_regs *regs) { struct acm *acm = (struct acm *)urb->context; + dbg("Entering acm_write_bulk with status %d\n", urb->status); if (!ACM_READY(acm)) goto out; @@ -237,7 +249,8 @@ static void acm_softint(void *private) { struct acm *acm = private; struct tty_struct *tty = acm->tty; - + dbg("Entering acm_softint.\n"); + if (!ACM_READY(acm)) return; @@ -254,6 +267,7 @@ static void acm_softint(void *private) static int acm_tty_open(struct tty_struct *tty, struct file *filp) { struct acm *acm = acm_table[tty->index]; + dbg("Entering acm_tty_open.\n"); if (!acm || !acm->dev) return -EINVAL; @@ -279,7 +293,8 @@ static int acm_tty_open(struct tty_struc goto bail_out_and_unlink; } - acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS); + if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS)) + goto full_bailout; /* force low_latency on so that our tty_push actually forces the data through, otherwise it is scheduled, and with high data rates data can get lost. */ @@ -290,6 +305,8 @@ done: up(&open_sem); return 0; +full_bailout: + usb_unlink_urb(acm->readurb); bail_out_and_unlink: usb_unlink_urb(acm->ctrlurb); bail_out: @@ -327,6 +344,7 @@ static int acm_tty_write(struct tty_stru { struct acm *acm = tty->driver_data; int stat; + dbg("Entering acm_tty_write to write %d bytes from %s space,\n", count, from_user ? "user" : "kernel"); if (!ACM_READY(acm)) return -EINVAL; @@ -337,11 +355,13 @@ static int acm_tty_write(struct tty_stru count = (count > acm->writesize) ? acm->writesize : count; + dbg("Get %d bytes from %s space...", count, from_user ? "user" : "kernel"); if (from_user) { - if (copy_from_user(acm->writeurb->transfer_buffer, (void __user *)buf, count)) + if (copy_from_user(acm->write_buffer, (void __user *)buf, count)) return -EFAULT; } else - memcpy(acm->writeurb->transfer_buffer, buf, count); + memcpy(acm->write_buffer, buf, count); + dbg(" Successfully copied.\n"); acm->writeurb->transfer_buffer_length = count; acm->writeurb->dev = acm->dev; @@ -378,7 +398,9 @@ static void acm_tty_throttle(struct tty_ struct acm *acm = tty->driver_data; if (!ACM_READY(acm)) return; + spin_lock_bh(&acm->throttle_lock); acm->throttle = 1; + spin_unlock_bh(&acm->throttle_lock); } static void acm_tty_unthrottle(struct tty_struct *tty) @@ -386,9 +408,13 @@ static void acm_tty_unthrottle(struct tt struct acm *acm = tty->driver_data; if (!ACM_READY(acm)) return; + spin_lock_bh(&acm->throttle_lock); acm->throttle = 0; - if (acm->readurb->status != -EINPROGRESS) + spin_unlock_bh(&acm->throttle_lock); + if (acm->resubmit_to_unthrottle) { + acm->resubmit_to_unthrottle = 0; acm_read_bulk(acm->readurb, NULL); + } } static void acm_tty_break_ctl(struct tty_struct *tty, int state) @@ -510,7 +536,11 @@ static int acm_probe (struct usb_interfa struct acm *acm; int minor; int ctrlsize,readsize; - char *buf; + u8 *buf; + u8 ac_management_function = 0; + u8 call_management_function = 0; + int call_interface_num = -1; + int data_interface_num; if (!buffer) { err("Wierd descriptor references"); @@ -531,6 +561,18 @@ static int acm_probe (struct usb_interfa } union_header = (struct union_desc *)buffer; break; + case CDC_COUNTRY_TYPE: /* maybe somehow export */ + break; /* for now we ignore it */ + case CDC_AC_MANAGEMENT_TYPE: + ac_management_function = buffer[3]; + break; + case CDC_CALL_MANAGEMENT_TYPE: + call_management_function = buffer[3]; + call_interface_num = buffer[4]; + if ((call_management_function & 3) != 3) + err("This device cannot do calls on its own. It is no modem."); + break; + default: err("Ignoring extra header"); break; @@ -546,11 +588,14 @@ next_desc: } control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0); - data_interface = usb_ifnum_to_if(usb_dev, union_header->bSlaveInterface0); + data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0)); if (!control_interface || !data_interface) { dev_dbg(&intf->dev,"no interfaces\n"); return -ENODEV; } + + if (data_interface_num != call_interface_num) + dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported."); if (usb_interface_claimed(data_interface)) { /* valid in this context */ dev_dbg(&intf->dev,"The data interface isn't available\n"); @@ -598,7 +643,7 @@ next_desc: if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) { dev_dbg(&intf->dev, "out of memory (acm kmalloc)\n"); - return -ENOMEM; + goto alloc_fail; } memset(acm, 0, sizeof(struct acm)); @@ -609,54 +654,66 @@ next_desc: acm->data = data_interface; acm->minor = minor; acm->dev = usb_dev; - + acm->ctrl_caps = ac_management_function; + acm->ctrlsize = ctrlsize; + acm->readsize = readsize; acm->bh.func = acm_rx_tasklet; acm->bh.data = (unsigned long) acm; INIT_WORK(&acm->work, acm_softint, acm); + spin_lock_init(&acm->throttle_lock); acm->ready_for_write = 1; - - if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) { - dev_dbg(&intf->dev, "out of memory (buf kmalloc)\n"); - kfree(acm); - return -ENOMEM; + buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); + if (!buf) { + dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)\n"); + goto alloc_fail2; + } + acm->ctrl_buffer = buf; + + buf = usb_buffer_alloc(usb_dev, readsize, GFP_KERNEL, &acm->read_dma); + if (!buf) { + dev_dbg(&intf->dev, "out of memory (read buffer alloc)\n"); + goto alloc_fail3; + } + acm->read_buffer = buf; + + buf = usb_buffer_alloc(usb_dev, acm->writesize, GFP_KERNEL, &acm->write_dma); + if (!buf) { + dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n"); + goto alloc_fail4; } + acm->write_buffer = buf; acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL); if (!acm->ctrlurb) { dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n"); - kfree(acm); - kfree(buf); - return -ENOMEM; + goto alloc_fail5; } acm->readurb = usb_alloc_urb(0, GFP_KERNEL); if (!acm->readurb) { dev_dbg(&intf->dev, "out of memory (readurb kmalloc)\n"); - usb_free_urb(acm->ctrlurb); - kfree(acm); - kfree(buf); - return -ENOMEM; + goto alloc_fail6; } acm->writeurb = usb_alloc_urb(0, GFP_KERNEL); if (!acm->writeurb) { dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)\n"); - usb_free_urb(acm->readurb); - usb_free_urb(acm->ctrlurb); - kfree(acm); - kfree(buf); - return -ENOMEM; + goto alloc_fail7; } usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress), - buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval); + acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval); + acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + acm->ctrlurb->transfer_dma = acm->ctrl_dma; usb_fill_bulk_urb(acm->readurb, usb_dev, usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress), - buf += ctrlsize, readsize, acm_read_bulk, acm); - acm->readurb->transfer_flags |= URB_NO_FSBR; + acm->read_buffer, readsize, acm_read_bulk, acm); + acm->readurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP; + acm->readurb->transfer_dma = acm->read_dma; usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress), - buf += readsize, acm->writesize, acm_write_bulk, acm); - acm->writeurb->transfer_flags |= URB_NO_FSBR; + acm->write_buffer, acm->writesize, acm_write_bulk, acm); + acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP; + acm->writeurb->transfer_dma = acm->write_dma; dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); @@ -673,17 +730,34 @@ next_desc: acm_table[minor] = acm; usb_set_intfdata (intf, acm); return 0; + +alloc_fail7: + usb_free_urb(acm->readurb); +alloc_fail6: + usb_free_urb(acm->ctrlurb); +alloc_fail5: + usb_buffer_free(usb_dev, acm->writesize, acm->write_buffer, acm->write_dma); +alloc_fail4: + usb_buffer_free(usb_dev, readsize, acm->read_buffer, acm->read_dma); +alloc_fail3: + usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); +alloc_fail2: + kfree(acm); +alloc_fail: + return -ENOMEM; } static void acm_disconnect(struct usb_interface *intf) { struct acm *acm = usb_get_intfdata (intf); + struct usb_device *usb_dev = interface_to_usbdev(intf); if (!acm || !acm->dev) { dbg("disconnect on nonexisting interface"); return; } + down(&open_sem); acm->dev = NULL; usb_set_intfdata (intf, NULL); @@ -693,7 +767,9 @@ static void acm_disconnect(struct usb_in flush_scheduled_work(); /* wait for acm_softint */ - kfree(acm->ctrlurb->transfer_buffer); + usb_buffer_free(usb_dev, acm->writesize, acm->write_buffer, acm->write_dma); + usb_buffer_free(usb_dev, acm->readsize, acm->read_buffer, acm->read_dma); + usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma); usb_driver_release_interface(&acm_driver, acm->data); @@ -704,9 +780,12 @@ static void acm_disconnect(struct usb_in usb_free_urb(acm->readurb); usb_free_urb(acm->writeurb); kfree(acm); + up(&open_sem); return; } + up(&open_sem); + if (acm->tty) tty_hangup(acm->tty); } diff -puN drivers/usb/class/cdc-acm.h~bk-usb drivers/usb/class/cdc-acm.h --- 25/drivers/usb/class/cdc-acm.h~bk-usb 2004-06-28 20:21:13.842809584 -0700 +++ 25-akpm/drivers/usb/class/cdc-acm.h 2004-06-28 20:21:13.896801376 -0700 @@ -86,17 +86,23 @@ struct acm { struct usb_interface *data; /* data interface */ struct tty_struct *tty; /* the corresponding tty */ struct urb *ctrlurb, *readurb, *writeurb; /* urbs */ + u8 *ctrl_buffer, *read_buffer, *write_buffer; /* buffers of urbs */ + dma_addr_t ctrl_dma, read_dma, write_dma; /* dma handles of buffers */ struct acm_line line; /* line coding (bits, stop, parity) */ struct work_struct work; /* work queue entry for line discipline waking up */ struct tasklet_struct bh; /* rx processing */ + spinlock_t throttle_lock; /* synchronize throtteling and read callback */ unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */ unsigned int ctrlout; /* output control lines (DTR, RTS) */ unsigned int writesize; /* max packet size for the output bulk endpoint */ + unsigned int readsize,ctrlsize; /* buffer sizes for freeing */ unsigned int used; /* someone has this acm's device open */ unsigned int minor; /* acm minor number */ unsigned char throttle; /* throttled by tty layer */ unsigned char clocal; /* termios CLOCAL */ unsigned char ready_for_write; /* write urb can be used */ + unsigned char resubmit_to_unthrottle; /* throtteling has disabled the read urb */ + unsigned int ctrl_caps; /* control capabilities from the class specific header */ }; /* "Union Functional Descriptor" from CDC spec 5.2.3.X */ @@ -110,6 +116,12 @@ struct union_desc { /* ... and there could be other slave interfaces */ } __attribute__ ((packed)); -#define CDC_UNION_TYPE 0x06 +/* class specific descriptor types */ +#define CDC_CALL_MANAGEMENT_TYPE 0x01 +#define CDC_AC_MANAGEMENT_TYPE 0x02 +#define CDC_UNION_TYPE 0x06 +#define CDC_COUNTRY_TYPE 0x07 + #define CDC_DATA_INTERFACE_TYPE 0x0a + diff -puN drivers/usb/core/hub.c~bk-usb drivers/usb/core/hub.c --- 25/drivers/usb/core/hub.c~bk-usb 2004-06-28 20:21:13.844809280 -0700 +++ 25-akpm/drivers/usb/core/hub.c 2004-06-28 20:21:13.898801072 -0700 @@ -1034,7 +1034,7 @@ static inline void show_string(struct us {} #endif -/* +/** * usb_new_device - perform initial device setup (usbcore-internal) * @udev: newly addressed device (in ADDRESS state) * @@ -1333,13 +1333,14 @@ static int hub_set_address(struct usb_de return retval; } -/* reset device, (re)assign address, get device descriptor. - * device connection is stable, no more debouncing needed. - * returns device in USB_STATE_ADDRESS, except on error. - * on error return, device is no longer usable (ref dropped). +/* Reset device, (re)assign address, get device descriptor. + * Device connection must be stable, no more debouncing needed. + * Returns device in USB_STATE_ADDRESS, except on error. * - * caller owns dev->serialize for the device, guarding against - * config changes and disconnect processing. + * If this is called for an already-existing device (as part of + * usb_reset_device), the caller must own the device lock. For a + * newly detected device that is not accessible through any global + * pointers, it's not necessary to lock the device. */ static int hub_port_init (struct usb_device *hdev, struct usb_device *udev, int port) @@ -1571,6 +1572,7 @@ static void hub_port_connect_change(stru /* Disconnect any existing devices under this port */ if (hdev->children[port]) usb_disconnect(&hdev->children[port]); + clear_bit(port, hub->change_bits); if (portchange & USB_PORT_STAT_C_CONNECTION) { status = hub_port_debounce(hdev, port); @@ -1785,12 +1787,15 @@ static void hub_events(void) /* deal with port status changes */ for (i = 0; i < hub->descriptor->bNbrPorts; i++) { - if (!test_and_clear_bit(i+1, hub->event_bits)) + connect_change = test_bit(i, hub->change_bits); + if (!test_and_clear_bit(i+1, hub->event_bits) && + !connect_change) continue; - ret = hub_port_status(hdev, i, &portstatus, &portchange); + + ret = hub_port_status(hdev, i, + &portstatus, &portchange); if (ret < 0) continue; - connect_change = 0; if (portchange & USB_PORT_STAT_C_CONNECTION) { clear_port_feature(hdev, @@ -1819,7 +1824,7 @@ static void hub_events(void) dev_err (hub_dev, "port %i " "disabled by hub (EMI?), " - "re-enabling...", + "re-enabling...\n", i + 1); connect_change = 1; } @@ -1996,23 +2001,34 @@ static int config_descriptors_changed(st != 0) { dev_dbg(&udev->dev, "config index %d changed (#%d)\n", index, buf->bConfigurationValue); -/* FIXME enable this when we can re-enumerate after reset; - * until then DFU-ish drivers need this and other workarounds - */ -// break; + break; } } kfree(buf); return index != udev->descriptor.bNumConfigurations; } -/* +/** + * usb_reset_devce - perform a USB port reset to reinitialize a device + * @udev: device to reset (not in SUSPENDED or NOTATTACHED state) + * * WARNING - don't reset any device unless drivers for all of its * interfaces are expecting that reset! Maybe some driver->reset() * method should eventually help ensure sufficient cooperation. * - * This is the same as usb_reset_device() except that the caller - * already holds dev->serialize. For example, it's safe to use + * Do a port reset, reassign the device's address, and establish its + * former operating configuration. If the reset fails, or the device's + * descriptors change from their values before the reset, or the original + * configuration and altsettings cannot be restored, a flag will be set + * telling khubd to pretend the device has been disconnected and then + * re-connected. All drivers will be unbound, and the device will be + * re-enumerated and probed all over again. + * + * Returns 0 if the reset succeeded, -ENODEV if the device has been + * flagged for logical disconnection, or some other negative error code + * if the reset wasn't even attempted. + * + * The caller must own the device lock. For example, it's safe to use * this from a driver probe() routine after downloading new firmware. */ int __usb_reset_device(struct usb_device *udev) @@ -2020,13 +2036,23 @@ int __usb_reset_device(struct usb_device struct usb_device *parent = udev->parent; struct usb_device_descriptor descriptor = udev->descriptor; int i, ret, port = -1; + struct usb_hub *hub; + + if (udev->state == USB_STATE_NOTATTACHED || + udev->state == USB_STATE_SUSPENDED) { + dev_dbg(&udev->dev, "device reset not allowed in state %d\n", + udev->state); + return -EINVAL; + } + /* FIXME: This should be legal for regular hubs. Root hubs may + * have special requirements. */ if (udev->maxchild) { /* this requires hub- or hcd-specific logic; * see hub_reset() and OHCI hc_restart() */ dev_dbg(&udev->dev, "%s for hub!\n", __FUNCTION__); - return -EINVAL; + return -EISDIR; } for (i = 0; i < parent->maxchild; i++) @@ -2035,8 +2061,11 @@ int __usb_reset_device(struct usb_device break; } - if (port < 0) + if (port < 0) { + /* If this ever happens, it's very bad */ + dev_err(&udev->dev, "Can't locate device's port!\n"); return -ENOENT; + } ret = hub_port_init(parent, udev, port); if (ret < 0) @@ -2088,8 +2117,18 @@ int __usb_reset_device(struct usb_device return 0; re_enumerate: - /* FIXME make some task re-enumerate; don't just mark unusable */ hub_port_disable(parent, port); + + hub = usb_get_intfdata(parent->actconfig->interface[0]); + set_bit(port, hub->change_bits); + + spin_lock_irq(&hub_event_lock); + if (list_empty(&hub->event_list)) { + list_add_tail(&hub->event_list, &hub_event_list); + wake_up(&khubd_wait); + } + spin_unlock_irq(&hub_event_lock); + return -ENODEV; } EXPORT_SYMBOL(__usb_reset_device); diff -puN drivers/usb/core/hub.h~bk-usb drivers/usb/core/hub.h --- 25/drivers/usb/core/hub.h~bk-usb 2004-06-28 20:21:13.846808976 -0700 +++ 25-akpm/drivers/usb/core/hub.h 2004-06-28 20:21:13.899800920 -0700 @@ -204,6 +204,8 @@ struct usb_hub { struct list_head event_list; /* hubs w/data or errs ready */ unsigned long event_bits[1]; /* status change bitmask */ + unsigned long change_bits[1]; /* ports with logical connect + status change */ #if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */ #error event_bits[] is too short! #endif diff -puN drivers/usb/gadget/dummy_hcd.c~bk-usb drivers/usb/gadget/dummy_hcd.c --- 25/drivers/usb/gadget/dummy_hcd.c~bk-usb 2004-06-28 20:21:13.847808824 -0700 +++ 25-akpm/drivers/usb/gadget/dummy_hcd.c 2004-06-28 20:21:13.900800768 -0700 @@ -146,8 +146,6 @@ struct dummy { u8 fifo_buf [FIFO_SIZE]; u16 devstatus; - struct hcd_dev *hdev; - /* * MASTER/HOST side support */ @@ -159,6 +157,8 @@ struct dummy { struct completion released; unsigned resuming:1; unsigned long re_timeout; + + struct usb_device *udev; }; static struct dummy *the_controller; @@ -739,11 +739,9 @@ stop_activity (struct dummy *dum, struct struct dummy_ep *ep; /* prevent any more requests */ - dum->hdev = 0; dum->address = 0; - /* this might not succeed ... */ - del_timer (&dum->timer); + /* The timer is left running so that outstanding URBs can fail */ /* nuke any pending requests first, so driver i/o is quiesced */ list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list) @@ -784,7 +782,6 @@ usb_gadget_unregister_driver (struct usb driver_unregister (&driver->driver); - del_timer_sync (&dum->timer); return 0; } EXPORT_SYMBOL (usb_gadget_unregister_driver); @@ -825,7 +822,12 @@ static int dummy_urb_enqueue ( dum = container_of (hcd, struct dummy, hcd); spin_lock_irqsave (&dum->lock, flags); - dum->hdev = urb->dev->hcpriv; + if (!dum->udev) { + dum->udev = urb->dev; + usb_get_dev (dum->udev); + } else if (unlikely (dum->udev != urb->dev)) + dev_err (hardware, "usb_device address has changed!\n"); + urb->hcpriv = dum; if (usb_pipetype (urb->pipe) == PIPE_CONTROL) urb->error_count = 1; /* mark as a new urb */ @@ -1032,17 +1034,12 @@ static struct dummy_ep *find_endpoint (s static void dummy_timer (unsigned long _dum) { struct dummy *dum = (struct dummy *) _dum; - struct hcd_dev *hdev = dum->hdev; + struct hcd_dev *hdev; struct list_head *entry, *tmp; unsigned long flags; int limit, total; int i; - if (!hdev) { - dev_err (hardware, "timer fired with device gone?\n"); - return; - } - /* simplistic model for one frame's bandwidth */ switch (dum->gadget.speed) { case USB_SPEED_LOW: @@ -1063,6 +1060,14 @@ static void dummy_timer (unsigned long _ /* look at each urb queued by the host side driver */ spin_lock_irqsave (&dum->lock, flags); + + if (!dum->udev) { + dev_err (hardware, "timer fired with no URBs pending?\n"); + spin_unlock_irqrestore (&dum->lock, flags); + return; + } + hdev = dum->udev->hcpriv; + for (i = 0; i < DUMMY_ENDPOINTS; i++) { if (!ep_name [i]) break; @@ -1334,7 +1339,11 @@ return_urb: /* want a 1 msec delay here */ if (!list_empty (&hdev->urb_list)) - mod_timer (&dum->timer, jiffies + 1); + mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1)); + else { + usb_put_dev (dum->udev); + dum->udev = NULL; + } spin_unlock_irqrestore (&dum->lock, flags); } @@ -1571,10 +1580,12 @@ show_urbs (struct device *dev, char *buf struct urb *urb; size_t size = 0; unsigned long flags; + struct hcd_dev *hdev; spin_lock_irqsave (&dum->lock, flags); - if (dum->hdev) { - list_for_each_entry (urb, &dum->hdev->urb_list, urb_list) { + if (dum->udev) { + hdev = dum->udev->hcpriv; + list_for_each_entry (urb, &hdev->urb_list, urb_list) { size_t temp; temp = show_urb (buf, PAGE_SIZE - size, urb); diff -puN drivers/usb/gadget/ether.c~bk-usb drivers/usb/gadget/ether.c --- 25/drivers/usb/gadget/ether.c~bk-usb 2004-06-28 20:21:13.849808520 -0700 +++ 25-akpm/drivers/usb/gadget/ether.c 2004-06-28 20:21:13.903800312 -0700 @@ -234,7 +234,7 @@ MODULE_PARM_DESC(host_addr, "Host Ethern /* For CDC-incapable hardware, choose the simple cdc subset. * Anything that talks bulk (without notable bugs) can do this. */ -#ifdef CONFIG_USB_GADGET_PXA +#ifdef CONFIG_USB_GADGET_PXA2XX #define DEV_CONFIG_SUBSET #endif @@ -1597,6 +1597,8 @@ done_set_intf: /* respond with data transfer before status phase? */ if (value >= 0) { req->length = value; + req->zero = value < ctrl->wLength + && (value % gadget->ep0->maxpacket) == 0; value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC); if (value < 0) { DEBUG (dev, "ep_queue --> %d\n", value); @@ -2373,6 +2375,7 @@ autoconf_fail: EP_OUT_NAME = ep->name; ep->driver_data = ep; /* claim */ +#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS) /* CDC Ethernet control interface doesn't require a status endpoint. * Since some hosts expect one, try to allocate one anyway. */ @@ -2386,13 +2389,12 @@ autoconf_fail: "can't run RNDIS on %s\n", gadget->name); return -ENODEV; -#ifdef DEV_CONFIG_CDC } else if (cdc) { control_intf.bNumEndpoints = 0; /* FIXME remove endpoint from descriptor list */ -#endif } } +#endif /* one config: cdc, else minimal subset */ if (!cdc) { @@ -2446,7 +2448,7 @@ autoconf_fail: /* Module params for these addresses should come from ID proms. * The host side address is used with CDC and RNDIS, and commonly - * end ups in a persistent config database. + * ends up in a persistent config database. */ get_ether_addr(dev_addr, net->dev_addr); if (cdc || rndis) { diff -puN drivers/usb/gadget/file_storage.c~bk-usb drivers/usb/gadget/file_storage.c --- 25/drivers/usb/gadget/file_storage.c~bk-usb 2004-06-28 20:21:13.851808216 -0700 +++ 25-akpm/drivers/usb/gadget/file_storage.c 2004-06-28 20:21:13.906799856 -0700 @@ -1465,6 +1465,8 @@ static int fsg_setup(struct usb_gadget * /* Respond with data/status or defer until later? */ if (rc >= 0 && rc != DELAYED_STATUS) { fsg->ep0req->length = rc; + fsg->ep0req->zero = rc < ctrl->wLength + && (rc % gadget->ep0->maxpacket) == 0; fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ? "ep0-in" : "ep0-out"); rc = ep0_queue(fsg); diff -puN drivers/usb/gadget/inode.c~bk-usb drivers/usb/gadget/inode.c --- 25/drivers/usb/gadget/inode.c~bk-usb 2004-06-28 20:21:13.852808064 -0700 +++ 25-akpm/drivers/usb/gadget/inode.c 2004-06-28 20:21:13.908799552 -0700 @@ -20,7 +20,7 @@ */ -#define DEBUG 1 /* data to help fault diagnosis */ +// #define DEBUG /* data to help fault diagnosis */ // #define VERBOSE /* extra debug messages (success too) */ #include @@ -44,7 +44,8 @@ * The gadgetfs API maps each endpoint to a file descriptor so that you * can use standard synchronous read/write calls for I/O. There's some * O_NONBLOCK and O_ASYNC/FASYNC style i/o support. Example usermode - * drivers show how this works in practice. + * drivers show how this works in practice. You can also use AIO to + * eliminate I/O gaps between requests, to help when streaming data. * * Key parts that must be USB-specific are protocols defining how the * read/write operations relate to the hardware state machines. There @@ -70,7 +71,7 @@ */ #define DRIVER_DESC "USB Gadget filesystem" -#define DRIVER_VERSION "20 Aug 2003" +#define DRIVER_VERSION "18 Nov 2003" static const char driver_desc [] = DRIVER_DESC; static const char shortname [] = "gadgetfs"; @@ -539,6 +540,177 @@ static int ep_ioctl (struct inode *inode return status; } +/*----------------------------------------------------------------------*/ + +/* ASYNCHRONOUS ENDPOINT I/O OPERATIONS (bulk/intr/iso) */ + +struct kiocb_priv { + struct usb_request *req; + struct ep_data *epdata; + void *buf; + char __user *ubuf; + unsigned actual; +}; + +static int ep_aio_cancel(struct kiocb *iocb, struct io_event *e) +{ + struct kiocb_priv *priv = (void *) &iocb->private; + struct ep_data *epdata; + int value; + + local_irq_disable(); + epdata = priv->epdata; + // spin_lock(&epdata->dev->lock); + kiocbSetCancelled(iocb); + if (likely(epdata && epdata->ep && priv->req)) + value = usb_ep_dequeue (epdata->ep, priv->req); + else + value = -EINVAL; + // spin_unlock(&epdata->dev->lock); + local_irq_enable(); + + aio_put_req(iocb); + return value; +} + +static long ep_aio_read_retry(struct kiocb *iocb) +{ + struct kiocb_priv *priv = (void *) &iocb->private; + int status = priv->actual; + + /* we "retry" to get the right mm context for this: */ + status = copy_to_user(priv->ubuf, priv->buf, priv->actual); + if (unlikely(0 != status)) + status = -EFAULT; + else + status = priv->actual; + kfree(priv->buf); + aio_put_req(iocb); + return status; +} + +static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct kiocb *iocb = req->context; + struct kiocb_priv *priv = (void *) &iocb->private; + struct ep_data *epdata = priv->epdata; + + /* lock against disconnect (and ideally, cancel) */ + spin_lock(&epdata->dev->lock); + priv->req = 0; + priv->epdata = 0; + if (NULL == iocb->ki_retry + || unlikely(0 == req->actual) + || unlikely(kiocbIsCancelled(iocb))) { + kfree(req->buf); + /* aio_complete() reports bytes-transferred _and_ faults */ + if (unlikely(kiocbIsCancelled(iocb))) + aio_put_req(iocb); + else + aio_complete(iocb, + req->actual ? req->actual : req->status, + req->status); + } else { + /* retry() won't report both; so we hide some faults */ + if (unlikely(0 != req->status)) + DBG(epdata->dev, "%s fault %d len %d\n", + ep->name, req->status, req->actual); + + priv->buf = req->buf; + priv->actual = req->actual; + kick_iocb(iocb); + } + spin_unlock(&epdata->dev->lock); + + usb_ep_free_request(ep, req); + put_ep(epdata); +} + +static ssize_t +ep_aio_rwtail(struct kiocb *iocb, char *buf, size_t len, struct ep_data *epdata) +{ + struct kiocb_priv *priv = (void *) &iocb->private; + struct usb_request *req; + ssize_t value; + + value = get_ready_ep(iocb->ki_filp->f_flags, epdata); + if (unlikely(value < 0)) { + kfree(buf); + return value; + } + + iocb->ki_cancel = ep_aio_cancel; + get_ep(epdata); + priv->epdata = epdata; + priv->actual = 0; + + /* each kiocb is coupled to one usb_request, but we can't + * allocate or submit those if the host disconnected. + */ + spin_lock_irq(&epdata->dev->lock); + if (likely(epdata->ep)) { + req = usb_ep_alloc_request(epdata->ep, GFP_ATOMIC); + if (likely(req)) { + priv->req = req; + req->buf = buf; + req->length = len; + req->complete = ep_aio_complete; + req->context = iocb; + value = usb_ep_queue(epdata->ep, req, GFP_ATOMIC); + if (unlikely(0 != value)) + usb_ep_free_request(epdata->ep, req); + } else + value = -EAGAIN; + } else + value = -ENODEV; + spin_unlock_irq(&epdata->dev->lock); + + up(&epdata->lock); + + if (unlikely(value)) + put_ep(epdata); + else + value = -EIOCBQUEUED; + return value; +} + +static ssize_t +ep_aio_read(struct kiocb *iocb, char __user *ubuf, size_t len, loff_t o) +{ + struct kiocb_priv *priv = (void *) &iocb->private; + struct ep_data *epdata = iocb->ki_filp->private_data; + char *buf; + + if (unlikely(epdata->desc.bEndpointAddress & USB_DIR_IN)) + return -EINVAL; + buf = kmalloc(len, GFP_KERNEL); + if (unlikely(!buf)) + return -ENOMEM; + iocb->ki_retry = ep_aio_read_retry; + priv->ubuf = ubuf; + return ep_aio_rwtail(iocb, buf, len, epdata); +} + +static ssize_t +ep_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t len, loff_t o) +{ + struct ep_data *epdata = iocb->ki_filp->private_data; + char *buf; + + if (unlikely(!(epdata->desc.bEndpointAddress & USB_DIR_IN))) + return -EINVAL; + buf = kmalloc(len, GFP_KERNEL); + if (unlikely(!buf)) + return -ENOMEM; + if (unlikely(copy_from_user(buf, ubuf, len) != 0)) { + kfree(buf); + return -EFAULT; + } + return ep_aio_rwtail(iocb, buf, len, epdata); +} + +/*----------------------------------------------------------------------*/ + /* used after endpoint configuration */ static struct file_operations ep_io_operations = { .owner = THIS_MODULE, @@ -547,8 +719,8 @@ static struct file_operations ep_io_oper .ioctl = ep_ioctl, .release = ep_release, - // .aio_read = ep_aio_read, - // .aio_write = ep_aio_write, + .aio_read = ep_aio_read, + .aio_write = ep_aio_write, }; /* ENDPOINT INITIALIZATION @@ -1320,6 +1492,8 @@ delegate: /* proceed with data transfer and status phases? */ if (value >= 0 && dev->state != STATE_SETUP) { req->length = value; + req->zero = value < ctrl->wLength + && (value % gadget->ep0->maxpacket) == 0; value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC); if (value < 0) { DBG (dev, "ep_queue --> %d\n", value); diff -puN drivers/usb/gadget/serial.c~bk-usb drivers/usb/gadget/serial.c --- 25/drivers/usb/gadget/serial.c~bk-usb 2004-06-28 20:21:13.854807760 -0700 +++ 25-akpm/drivers/usb/gadget/serial.c 2004-06-28 20:21:13.910799248 -0700 @@ -1573,6 +1573,8 @@ static int gs_setup(struct usb_gadget *g /* respond with data transfer before status phase? */ if (ret >= 0) { req->length = ret; + req->zero = ret < ctrl->wLength + && (ret % gadget->ep0->maxpacket) == 0; ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); if (ret < 0) { printk(KERN_ERR diff -puN drivers/usb/gadget/zero.c~bk-usb drivers/usb/gadget/zero.c --- 25/drivers/usb/gadget/zero.c~bk-usb 2004-06-28 20:21:13.855807608 -0700 +++ 25-akpm/drivers/usb/gadget/zero.c 2004-06-28 20:21:13.911799096 -0700 @@ -1037,6 +1037,8 @@ unknown: /* respond with data transfer before status phase? */ if (value >= 0) { req->length = value; + req->zero = value < ctrl->wLength + && (value % gadget->ep0->maxpacket) == 0; value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC); if (value < 0) { DBG (dev, "ep_queue --> %d\n", value); diff -puN drivers/usb/host/ehci-hcd.c~bk-usb drivers/usb/host/ehci-hcd.c --- 25/drivers/usb/host/ehci-hcd.c~bk-usb 2004-06-28 20:21:13.857807304 -0700 +++ 25-akpm/drivers/usb/host/ehci-hcd.c 2004-06-28 20:21:13.912798944 -0700 @@ -425,7 +425,6 @@ static int ehci_start (struct usb_hcd *h ehci_mem_cleanup (ehci); return retval; } - writel (INTR_MASK, &ehci->regs->intr_enable); writel (ehci->periodic_dma, &ehci->regs->frame_list); #ifdef CONFIG_PCI @@ -531,7 +530,8 @@ done2: /* * Start, enabling full USB 2.0 functionality ... usb 1.1 devices * are explicitly handed to companion controller(s), so no TT is - * involved with the root hub. + * involved with the root hub. (Except where one is integrated, + * and there's no companion controller unless maybe for USB OTG.) */ ehci->reboot_notifier.notifier_call = ehci_reboot; register_reboot_notifier (&ehci->reboot_notifier); @@ -563,6 +563,8 @@ done2: goto done2; } + writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */ + create_debug_files (ehci); return 0; @@ -573,6 +575,7 @@ done2: static void ehci_stop (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); + u8 rh_ports, port; ehci_dbg (ehci, "stop\n"); @@ -584,7 +587,16 @@ static void ehci_stop (struct usb_hcd *h return; } del_timer_sync (&ehci->watchdog); + + /* Turn off port power on all root hub ports. */ + rh_ports = HCS_N_PORTS (ehci->hcs_params); + for (port = 1; port <= rh_ports; port++) { + ehci_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER, + port, NULL, 0); + } + ehci_reset (ehci); + writel (0, &ehci->regs->intr_enable); /* let companion controllers work when we aren't */ writel (0, &ehci->regs->configured_flag); @@ -704,12 +716,6 @@ static irqreturn_t ehci_irq (struct usb_ status = readl (&ehci->regs->status); - /* shared irq */ - if (status == 0) { - spin_unlock (&ehci->lock); - return IRQ_NONE; - } - /* e.g. cardbus physical eject */ if (status == ~(u32) 0) { ehci_dbg (ehci, "device removed\n"); @@ -717,8 +723,10 @@ static irqreturn_t ehci_irq (struct usb_ } status &= INTR_MASK; - if (!status) /* irq sharing? */ - goto done; + if (!status) { /* irq sharing? */ + spin_unlock(&ehci->lock); + return IRQ_NONE; + } /* clear (just) interrupts */ writel (status, &ehci->regs->status); @@ -789,7 +797,6 @@ dead: if (bh) ehci_work (ehci, regs); -done: spin_unlock (&ehci->lock); return IRQ_HANDLED; } diff -puN drivers/usb/host/uhci-debug.c~bk-usb drivers/usb/host/uhci-debug.c --- 25/drivers/usb/host/uhci-debug.c~bk-usb 2004-06-28 20:21:13.858807152 -0700 +++ 25-akpm/drivers/usb/host/uhci-debug.c 2004-06-28 20:21:13.913798792 -0700 @@ -248,7 +248,7 @@ static int uhci_show_sc(int port, unsign static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len) { char *out = buf; - unsigned int io_addr = uhci->io_addr; + unsigned long io_addr = uhci->io_addr; unsigned short usbcmd, usbstat, usbint, usbfrnum; unsigned int flbaseadd; unsigned char sof; diff -puN drivers/usb/host/uhci-hcd.c~bk-usb drivers/usb/host/uhci-hcd.c --- 25/drivers/usb/host/uhci-hcd.c~bk-usb 2004-06-28 20:21:13.860806848 -0700 +++ 25-akpm/drivers/usb/host/uhci-hcd.c 2004-06-28 20:21:13.915798488 -0700 @@ -1762,7 +1762,7 @@ static void uhci_remove_pending_urbps(st static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); - unsigned int io_addr = uhci->io_addr; + unsigned long io_addr = uhci->io_addr; unsigned short status; struct list_head *tmp, *head; unsigned int age; @@ -1835,7 +1835,7 @@ static irqreturn_t uhci_irq(struct usb_h static void reset_hc(struct uhci_hcd *uhci) { - unsigned int io_addr = uhci->io_addr; + unsigned long io_addr = uhci->io_addr; /* Turn off PIRQ, SMI, and all interrupts. This also turns off * the BIOS's USB Legacy Support. @@ -1856,7 +1856,7 @@ static void reset_hc(struct uhci_hcd *uh static void suspend_hc(struct uhci_hcd *uhci) { - unsigned int io_addr = uhci->io_addr; + unsigned long io_addr = uhci->io_addr; dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); uhci->state = UHCI_SUSPENDED; @@ -1866,7 +1866,7 @@ static void suspend_hc(struct uhci_hcd * static void wakeup_hc(struct uhci_hcd *uhci) { - unsigned int io_addr = uhci->io_addr; + unsigned long io_addr = uhci->io_addr; switch (uhci->state) { case UHCI_SUSPENDED: /* Start the resume */ @@ -1906,7 +1906,7 @@ static void wakeup_hc(struct uhci_hcd *u static int ports_active(struct uhci_hcd *uhci) { - unsigned int io_addr = uhci->io_addr; + unsigned long io_addr = uhci->io_addr; int connection = 0; int i; @@ -1918,7 +1918,7 @@ static int ports_active(struct uhci_hcd static int suspend_allowed(struct uhci_hcd *uhci) { - unsigned int io_addr = uhci->io_addr; + unsigned long io_addr = uhci->io_addr; int i; if (to_pci_dev(uhci_dev(uhci))->vendor != PCI_VENDOR_ID_INTEL) @@ -1983,7 +1983,7 @@ static void hc_state_transitions(struct static void start_hc(struct uhci_hcd *uhci) { - unsigned int io_addr = uhci->io_addr; + unsigned long io_addr = uhci->io_addr; int timeout = 1000; /* @@ -2261,6 +2261,11 @@ static int uhci_start(struct usb_hcd *hc uhci->fl->frame[i] = cpu_to_le32(uhci->skelqh[irq]->dma_handle); } + /* + * Some architectures require a full mb() to enforce completion of + * the memory writes above before the I/O transfers in start_hc(). + */ + mb(); start_hc(uhci); init_stall_timer(hcd); diff -puN drivers/usb/host/uhci-hub.c~bk-usb drivers/usb/host/uhci-hub.c --- 25/drivers/usb/host/uhci-hub.c~bk-usb 2004-06-28 20:21:13.861806696 -0700 +++ 25-akpm/drivers/usb/host/uhci-hub.c 2004-06-28 20:21:13.915798488 -0700 @@ -36,7 +36,7 @@ static __u8 root_hub_hub_des[] = static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); - unsigned int io_addr = uhci->io_addr; + unsigned long io_addr = uhci->io_addr; int i; *buf = 0; @@ -69,7 +69,7 @@ static int uhci_hub_control(struct usb_h { struct uhci_hcd *uhci = hcd_to_uhci(hcd); int status, retval = 0, len = 0; - unsigned int port_addr = uhci->io_addr + USBPORTSC1 + 2 * (wIndex-1); + unsigned long port_addr = uhci->io_addr + USBPORTSC1 + 2 * (wIndex-1); __u16 wPortChange, wPortStatus; switch (typeReq) { diff -puN drivers/usb/input/hid-tmff.c~bk-usb drivers/usb/input/hid-tmff.c diff -puN drivers/usb/media/Kconfig~bk-usb drivers/usb/media/Kconfig --- 25/drivers/usb/media/Kconfig~bk-usb 2004-06-28 20:21:13.863806392 -0700 +++ 25-akpm/drivers/usb/media/Kconfig 2004-06-28 20:21:15.303587512 -0700 @@ -108,7 +108,7 @@ config USB_OV511 config USB_PWC tristate "USB Philips Cameras" - depends on USB && VIDEO_DEV && CONFIG_BROKEN + depends on USB && VIDEO_DEV ---help--- Say Y or M here if you want to use one of these Philips & OEM webcams: diff -puN drivers/usb/media/konicawc.c~bk-usb drivers/usb/media/konicawc.c --- 25/drivers/usb/media/konicawc.c~bk-usb 2004-06-28 20:21:13.865806088 -0700 +++ 25-akpm/drivers/usb/media/konicawc.c 2004-06-28 20:21:15.304587360 -0700 @@ -324,7 +324,7 @@ static void resubmit_urb(struct uvd *uvd } urb->dev = uvd->dev; urb->status = 0; - ret = usb_submit_urb(urb, GFP_KERNEL); + ret = usb_submit_urb(urb, GFP_ATOMIC); DEBUG(3, "submitting urb of length %d", urb->transfer_buffer_length); if(ret) err("usb_submit_urb error (%d)", ret); diff -puN drivers/usb/media/pwc-ctrl.c~bk-usb drivers/usb/media/pwc-ctrl.c --- 25/drivers/usb/media/pwc-ctrl.c~bk-usb 2004-06-28 20:21:13.866805936 -0700 +++ 25-akpm/drivers/usb/media/pwc-ctrl.c 2004-06-28 20:21:15.311586296 -0700 @@ -30,6 +30,7 @@ #include #endif #include +#include #include "pwc.h" #include "pwc-ioctl.h" @@ -127,19 +128,19 @@ static struct Nala_table_entry Nala_tabl /* This tables contains entries for the 675/680/690 (Timon) camera, with 4 different qualities (no compression, low, medium, high). - It lists the bandwidth requirements for said mode by its alternate interface + It lists the bandwidth requirements for said mode by its alternate interface number. An alternate of 0 means that the mode is unavailable. - - There are 6 * 4 * 4 entries: + + There are 6 * 4 * 4 entries: 6 different resolutions subqcif, qsif, qcif, sif, cif, vga 6 framerates: 5, 10, 15, 20, 25, 30 4 compression modi: none, low, medium, high - - When an uncompressed mode is not available, the next available compressed mode + + When an uncompressed mode is not available, the next available compressed mode will be chosen (unless the decompressor is absent). Sometimes there are only 1 or 2 compressed modes available; in that case entries are duplicated. */ -struct Timon_table_entry +struct Timon_table_entry { char alternate; /* USB alternate interface */ unsigned short packetsize; /* Normal packet size */ @@ -147,7 +148,7 @@ struct Timon_table_entry unsigned char mode[13]; /* precomputed mode settings for cam */ }; -static struct Timon_table_entry Timon_table[PSZ_MAX][6][4] = +static struct Timon_table_entry Timon_table[PSZ_MAX][6][4] = { #include "pwc_timon.h" }; @@ -194,7 +195,7 @@ void pwc_hexdump(void *p, int len) int i; unsigned char *s; char buf[100], *d; - + s = (unsigned char *)p; d = buf; *d = '\0'; @@ -230,7 +231,7 @@ static inline int set_video_mode_Nala(st unsigned char buf[3]; int ret, fps; struct Nala_table_entry *pEntry; - int frames2frames[31] = + int frames2frames[31] = { /* closest match of framerate */ 0, 0, 0, 0, 4, /* 0-4 */ 5, 5, 7, 7, 10, /* 5-9 */ @@ -267,9 +268,12 @@ static inline int set_video_mode_Nala(st 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); - + if (pEntry->compressed && pdev->decompressor != 0 && pdev->vpalette != VIDEO_PALETTE_RAW) + pdev->decompressor->init(pdev->type, pdev->release, buf, pdev->decompress_data); + + pdev->cmd_len = 3; + memcpy(pdev->cmd_buf, buf, 3); + /* Set various parameters */ pdev->vframes = frames; pdev->vsize = size; @@ -303,13 +307,13 @@ static inline int set_video_mode_Timon(s if (size == PSZ_VGA && frames > 15) return -EINVAL; fps = (frames / 5) - 1; - + /* Find a supported framerate with progressively higher compression ratios if the preferred ratio is not available. */ pChoose = NULL; if (pdev->decompressor == NULL) { -#if PWC_DEBUG +#if PWC_DEBUG Debug("Trying to find uncompressed mode.\n"); #endif pChoose = &Timon_table[size][fps][0]; @@ -319,7 +323,7 @@ static inline int set_video_mode_Timon(s pChoose = &Timon_table[size][fps][compression]; if (pChoose->alternate != 0) break; - compression++; + compression++; } } if (pChoose == NULL || pChoose->alternate == 0) @@ -332,9 +336,12 @@ static inline int set_video_mode_Timon(s if (ret < 0) return ret; - if (pChoose->bandlength > 0) - pdev->decompressor->init(pdev->release, buf, pdev->decompress_data); - + if (pChoose->bandlength > 0 && pdev->decompressor != 0 && pdev->vpalette != VIDEO_PALETTE_RAW) + pdev->decompressor->init(pdev->type, pdev->release, buf, pdev->decompress_data); + + pdev->cmd_len = 13; + memcpy(pdev->cmd_buf, buf, 13); + /* Set various parameters */ pdev->vframes = frames; pdev->vsize = size; @@ -342,7 +349,7 @@ static inline int set_video_mode_Timon(s pdev->valternate = pChoose->alternate; pdev->image = pwc_image_sizes[size]; pdev->vbandlength = pChoose->bandlength; - if (pChoose->bandlength > 0) + if (pChoose->bandlength > 0) pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4; else pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; @@ -352,33 +359,54 @@ static inline int set_video_mode_Timon(s static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) { - struct Kiara_table_entry *pChoose; + struct Kiara_table_entry *pChoose = 0; int fps, ret; unsigned char buf[12]; - + struct Kiara_table_entry RawEntry = {6, 773, 1272, {0xAD, 0xF4, 0x10, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}}; + if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) return -EINVAL; if (size == PSZ_VGA && frames > 15) return -EINVAL; fps = (frames / 5) - 1; - - /* Find a supported framerate with progressively higher compression ratios - if the preferred ratio is not available. - */ - pChoose = NULL; - if (pdev->decompressor == NULL) { -#if PWC_DEBUG - Debug("Trying to find uncompressed mode.\n"); -#endif - pChoose = &Kiara_table[size][fps][0]; + + /* special case: VGA @ 5 fps and snapshot is raw bayer mode */ + if (size == PSZ_VGA && frames == 5 && snapshot) + { + /* Only available in case the raw palette is selected or + we have the decompressor available. This mode is + only available in compressed form + */ + if (pdev->vpalette == VIDEO_PALETTE_RAW || pdev->decompressor != NULL) + { + Info("Choosing VGA/5 BAYER mode (%d).\n", pdev->vpalette); + pChoose = &RawEntry; + } + else + { + Info("VGA/5 BAYER mode _must_ have a decompressor available, or use RAW palette.\n"); + } } - else { - while (compression <= 3) { - pChoose = &Kiara_table[size][fps][compression]; - if (pChoose->alternate != 0) - break; - compression++; + else + { + /* Find a supported framerate with progressively higher compression ratios + if the preferred ratio is not available. + Skip this step when using RAW modes. + */ + if (pdev->decompressor == NULL && pdev->vpalette != VIDEO_PALETTE_RAW) { +#if PWC_DEBUG + Debug("Trying to find uncompressed mode.\n"); +#endif + pChoose = &Kiara_table[size][fps][0]; } + else { + while (compression <= 3) { + pChoose = &Kiara_table[size][fps][compression]; + if (pChoose->alternate != 0) + break; + compression++; + } + } } if (pChoose == NULL || pChoose->alternate == 0) return -ENOENT; /* Not supported. */ @@ -393,9 +421,11 @@ static inline int set_video_mode_Kiara(s if (ret < 0) return ret; - if (pChoose->bandlength > 0) - pdev->decompressor->init(pdev->release, buf, pdev->decompress_data); - + if (pChoose->bandlength > 0 && pdev->decompressor != 0 && pdev->vpalette != VIDEO_PALETTE_RAW) + pdev->decompressor->init(pdev->type, pdev->release, buf, pdev->decompress_data); + + pdev->cmd_len = 12; + memcpy(pdev->cmd_buf, buf, 12); /* All set and go */ pdev->vframes = frames; pdev->vsize = size; @@ -403,15 +433,15 @@ static inline int set_video_mode_Kiara(s pdev->valternate = pChoose->alternate; pdev->image = pwc_image_sizes[size]; pdev->vbandlength = pChoose->bandlength; - if (pChoose->bandlength > 0) - pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4; - else + if (pdev->vbandlength > 0) + pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4; + else pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; - pdev->frame_size += (pdev->frame_header_size + pdev->frame_trailer_size); return 0; } + /** @pdev: device structure @width: viewport width @@ -422,14 +452,17 @@ static inline int set_video_mode_Kiara(s */ int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot) { - int ret, size; - + int ret, size; + + Trace(TRACE_FLOW, "set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette); size = pwc_decode_size(pdev, width, height); if (size < 0) { Debug("Could not find suitable size.\n"); return -ERANGE; } - ret = -EINVAL; + Debug("decode_size = %d.\n", size); + + ret = -EINVAL; switch(pdev->type) { case 645: case 646: @@ -441,7 +474,7 @@ int pwc_set_video_mode(struct pwc_device case 690: ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot); break; - + case 720: case 730: case 740: @@ -459,6 +492,7 @@ int pwc_set_video_mode(struct pwc_device } pdev->view.x = width; pdev->view.y = height; + pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size; pwc_set_image_buffer_size(pdev); Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y); return 0; @@ -467,23 +501,33 @@ int pwc_set_video_mode(struct pwc_device void pwc_set_image_buffer_size(struct pwc_device *pdev) { - int factor, i, filler = 0; + int i, factor = 0, filler = 0; - factor = 6; - filler = 128; + /* for PALETTE_YUV420P */ + switch(pdev->vpalette) + { + case VIDEO_PALETTE_YUV420P: + factor = 6; + filler = 128; + break; + case VIDEO_PALETTE_RAW: + factor = 6; /* can be uncompressed YUV420P */ + filler = 0; + break; + } /* Set sizes in bytes */ pdev->image.size = pdev->image.x * pdev->image.y * factor / 4; pdev->view.size = pdev->view.x * pdev->view.y * factor / 4; /* Align offset, or you'll get some very weird results in - YUV420 mode... x must be multiple of 4 (to get the Y's in + YUV420 mode... x must be multiple of 4 (to get the Y's in place), and y even (or you'll mixup U & V). This is less of a problem for YUV420P. */ pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC; pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE; - + /* Fill buffers with gray or black */ for (i = 0; i < MAX_IMAGES; i++) { if (pdev->image_ptr[i] != NULL) @@ -499,13 +543,8 @@ int pwc_get_brightness(struct pwc_device { char buf; int ret; - - ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), - GET_LUM_CTL, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - BRIGHTNESS_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + + ret = RecvControlMsg(GET_LUM_CTL, BRIGHTNESS_FORMATTER, 1); if (ret < 0) return ret; return buf << 9; @@ -520,12 +559,7 @@ int pwc_set_brightness(struct pwc_device if (value > 0xffff) value = 0xffff; buf = (value >> 9) & 0x7f; - return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), - SET_LUM_CTL, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - BRIGHTNESS_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + return SendControlMsg(SET_LUM_CTL, BRIGHTNESS_FORMATTER, 1); } /* CONTRAST */ @@ -534,13 +568,8 @@ int pwc_get_contrast(struct pwc_device * { char buf; int ret; - - ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), - GET_LUM_CTL, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - CONTRAST_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + + ret = RecvControlMsg(GET_LUM_CTL, CONTRAST_FORMATTER, 1); if (ret < 0) return ret; return buf << 10; @@ -555,12 +584,7 @@ int pwc_set_contrast(struct pwc_device * if (value > 0xffff) value = 0xffff; buf = (value >> 10) & 0x3f; - return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), - SET_LUM_CTL, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - CONTRAST_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + return SendControlMsg(SET_LUM_CTL, CONTRAST_FORMATTER, 1); } /* GAMMA */ @@ -570,12 +594,7 @@ int pwc_get_gamma(struct pwc_device *pde char buf; int ret; - ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), - GET_LUM_CTL, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - GAMMA_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + ret = RecvControlMsg(GET_LUM_CTL, GAMMA_FORMATTER, 1); if (ret < 0) return ret; return buf << 11; @@ -590,12 +609,7 @@ int pwc_set_gamma(struct pwc_device *pde if (value > 0xffff) value = 0xffff; buf = (value >> 11) & 0x1f; - return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), - SET_LUM_CTL, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - GAMMA_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + return SendControlMsg(SET_LUM_CTL, GAMMA_FORMATTER, 1); } @@ -608,12 +622,7 @@ int pwc_get_saturation(struct pwc_device if (pdev->type < 675) return -1; - ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), - GET_CHROM_CTL, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, - pdev->vcinterface, - &buf, 1, HZ / 2); + ret = RecvControlMsg(GET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1); if (ret < 0) return ret; return 32768 + buf * 327; @@ -631,12 +640,7 @@ int pwc_set_saturation(struct pwc_device value = 0xffff; /* saturation ranges from -100 to +100 */ buf = (value - 32768) / 327; - return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), - SET_CHROM_CTL, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, - pdev->vcinterface, - &buf, 1, HZ / 2); + return SendControlMsg(SET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1); } /* AGC */ @@ -651,12 +655,7 @@ static inline int pwc_set_agc(struct pwc else buf = 0xff; /* fixed */ - ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), - SET_LUM_CTL, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - AGC_MODE_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + ret = SendControlMsg(SET_LUM_CTL, AGC_MODE_FORMATTER, 1); if (!mode && ret >= 0) { if (value < 0) @@ -664,12 +663,7 @@ static inline int pwc_set_agc(struct pwc if (value > 0xffff) value = 0xffff; buf = (value >> 10) & 0x3F; - ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), - SET_LUM_CTL, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - PRESET_AGC_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + ret = SendControlMsg(SET_LUM_CTL, PRESET_AGC_FORMATTER, 1); } if (ret < 0) return ret; @@ -681,22 +675,12 @@ static inline int pwc_get_agc(struct pwc unsigned char buf; int ret; - ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), - GET_LUM_CTL, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - AGC_MODE_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + ret = RecvControlMsg(GET_LUM_CTL, AGC_MODE_FORMATTER, 1); if (ret < 0) return ret; if (buf != 0) { /* fixed */ - ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), - GET_LUM_CTL, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - PRESET_AGC_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + ret = RecvControlMsg(GET_LUM_CTL, PRESET_AGC_FORMATTER, 1); if (ret < 0) return ret; if (buf > 0x3F) @@ -704,12 +688,7 @@ static inline int pwc_get_agc(struct pwc *value = (buf << 10); } else { /* auto */ - ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), - GET_STATUS_CTL, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - READ_AGC_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + ret = RecvControlMsg(GET_STATUS_CTL, READ_AGC_FORMATTER, 1); if (ret < 0) return ret; /* Gah... this value ranges from 0x00 ... 0x9F */ @@ -732,12 +711,7 @@ static inline int pwc_set_shutter_speed( else buf[0] = 0xff; /* fixed */ - ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), - SET_LUM_CTL, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - SHUTTER_MODE_FORMATTER, - pdev->vcinterface, - buf, 1, HZ / 2); + ret = SendControlMsg(SET_LUM_CTL, SHUTTER_MODE_FORMATTER, 1); if (!mode && ret >= 0) { if (value < 0) @@ -763,12 +737,7 @@ static inline int pwc_set_shutter_speed( break; } - ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), - SET_LUM_CTL, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - PRESET_SHUTTER_FORMATTER, - pdev->vcinterface, - &buf, 2, HZ / 2); + ret = SendControlMsg(SET_LUM_CTL, PRESET_SHUTTER_FORMATTER, 2); } return ret; } @@ -787,12 +756,7 @@ int pwc_camera_power(struct pwc_device * buf = 0x00; /* active */ else buf = 0xFF; /* power save */ - return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), - SET_STATUS_CTL, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - SET_POWER_SAVE_MODE_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + return SendControlMsg(SET_STATUS_CTL, SET_POWER_SAVE_MODE_FORMATTER, 1); } @@ -801,32 +765,20 @@ int pwc_camera_power(struct pwc_device * static inline int pwc_restore_user(struct pwc_device *pdev) { - return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), - SET_STATUS_CTL, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - RESTORE_USER_DEFAULTS_FORMATTER, - pdev->vcinterface, - NULL, 0, HZ / 2); + char buf; /* dummy */ + return SendControlMsg(SET_STATUS_CTL, RESTORE_USER_DEFAULTS_FORMATTER, 0); } static inline int pwc_save_user(struct pwc_device *pdev) { - return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), - SET_STATUS_CTL, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - SAVE_USER_DEFAULTS_FORMATTER, - pdev->vcinterface, - NULL, 0, HZ / 2); + char buf; /* dummy */ + return SendControlMsg(SET_STATUS_CTL, SAVE_USER_DEFAULTS_FORMATTER, 0); } static inline int pwc_restore_factory(struct pwc_device *pdev) { - return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), - SET_STATUS_CTL, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - RESTORE_FACTORY_DEFAULTS_FORMATTER, - pdev->vcinterface, - NULL, 0, HZ / 2); + char buf; /* dummy */ + return SendControlMsg(SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, 0); } /* ************************************************* */ @@ -854,12 +806,7 @@ static inline int pwc_set_awb(struct pwc buf = mode & 0x07; /* just the lowest three bits */ - ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), - SET_CHROM_CTL, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - WB_MODE_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + ret = SendControlMsg(SET_CHROM_CTL, WB_MODE_FORMATTER, 1); if (ret < 0) return ret; @@ -871,12 +818,7 @@ static inline int pwc_get_awb(struct pwc unsigned char buf; int ret; - ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), - GET_CHROM_CTL, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - WB_MODE_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + ret = RecvControlMsg(GET_CHROM_CTL, WB_MODE_FORMATTER, 1); if (ret < 0) return ret; @@ -891,34 +833,21 @@ static inline int pwc_set_red_gain(struc value = 0; if (value > 0xffff) value = 0xffff; - - /* only the msb are considered */ + /* only the msb is considered */ buf = value >> 8; - - return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), - SET_CHROM_CTL, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - PRESET_MANUAL_RED_GAIN_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1); } -static inline int pwc_get_red_gain(struct pwc_device *pdev) +static inline int pwc_get_red_gain(struct pwc_device *pdev, int *value) { unsigned char buf; int ret; - ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), - GET_CHROM_CTL, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - PRESET_MANUAL_RED_GAIN_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); - + ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1); if (ret < 0) return ret; - - return (buf << 8); + *value = buf << 8; + return 0; } @@ -930,34 +859,21 @@ static inline int pwc_set_blue_gain(stru value = 0; if (value > 0xffff) value = 0xffff; - - /* linear mapping of 0..0xffff to -0x80..0x7f */ - buf = (value >> 8); - - return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), - SET_CHROM_CTL, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - PRESET_MANUAL_BLUE_GAIN_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + /* only the msb is considered */ + buf = value >> 8; + return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1); } -static inline int pwc_get_blue_gain(struct pwc_device *pdev) +static inline int pwc_get_blue_gain(struct pwc_device *pdev, int *value) { unsigned char buf; int ret; - ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), - GET_CHROM_CTL, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - PRESET_MANUAL_BLUE_GAIN_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); - + ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1); if (ret < 0) return ret; - - return (buf << 8); + *value = buf << 8; + return 0; } @@ -965,40 +881,28 @@ static inline int pwc_get_blue_gain(stru internal red/blue gains, which may be different from the manual gains set or read above. */ -static inline int pwc_read_red_gain(struct pwc_device *pdev) +static inline int pwc_read_red_gain(struct pwc_device *pdev, int *value) { unsigned char buf; int ret; - ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), - GET_STATUS_CTL, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - READ_RED_GAIN_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); - + ret = RecvControlMsg(GET_STATUS_CTL, READ_RED_GAIN_FORMATTER, 1); if (ret < 0) return ret; - - return (buf << 8); + *value = buf << 8; + return 0; } -static inline int pwc_read_blue_gain(struct pwc_device *pdev) +static inline int pwc_read_blue_gain(struct pwc_device *pdev, int *value) { unsigned char buf; int ret; - ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), - GET_STATUS_CTL, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - READ_BLUE_GAIN_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); - + ret = RecvControlMsg(GET_STATUS_CTL, READ_BLUE_GAIN_FORMATTER, 1); if (ret < 0) return ret; - - return (buf << 8); + *value = buf << 8; + return 0; } @@ -1008,28 +912,19 @@ static inline int pwc_set_wb_speed(struc /* useful range is 0x01..0x20 */ buf = speed / 0x7f0; - return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), - SET_CHROM_CTL, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - AWB_CONTROL_SPEED_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1); } -static inline int pwc_get_wb_speed(struct pwc_device *pdev) +static inline int pwc_get_wb_speed(struct pwc_device *pdev, int *value) { unsigned char buf; int ret; - ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), - GET_CHROM_CTL, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - AWB_CONTROL_SPEED_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1); if (ret < 0) return ret; - return (buf * 0x7f0); + *value = buf * 0x7f0; + return 0; } @@ -1039,28 +934,19 @@ static inline int pwc_set_wb_delay(struc /* useful range is 0x01..0x3F */ buf = (delay >> 10); - return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), - SET_CHROM_CTL, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - AWB_CONTROL_DELAY_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1); } -static inline int pwc_get_wb_delay(struct pwc_device *pdev) +static inline int pwc_get_wb_delay(struct pwc_device *pdev, int *value) { unsigned char buf; int ret; - ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), - GET_CHROM_CTL, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - AWB_CONTROL_DELAY_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1); if (ret < 0) return ret; - return (buf << 10); + *value = buf << 10; + return 0; } @@ -1115,12 +1001,7 @@ static inline int pwc_set_contour(struct buf = 0xff; /* auto contour on */ else buf = 0x0; /* auto contour off */ - ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), - SET_LUM_CTL, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - AUTO_CONTOUR_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + ret = SendControlMsg(SET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1); if (ret < 0) return ret; @@ -1130,12 +1011,7 @@ static inline int pwc_set_contour(struct contour = 0xffff; buf = (contour >> 10); /* contour preset is [0..3f] */ - ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), - SET_LUM_CTL, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - PRESET_CONTOUR_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + ret = SendControlMsg(SET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1); if (ret < 0) return ret; return 0; @@ -1146,26 +1022,16 @@ static inline int pwc_get_contour(struct unsigned char buf; int ret; - ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), - GET_LUM_CTL, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - AUTO_CONTOUR_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + ret = RecvControlMsg(GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1); if (ret < 0) return ret; if (buf == 0) { /* auto mode off, query current preset value */ - ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), - GET_LUM_CTL, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - PRESET_CONTOUR_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + ret = RecvControlMsg(GET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1); if (ret < 0) return ret; - *contour = (buf << 10); + *contour = buf << 10; } else *contour = -1; @@ -1181,28 +1047,19 @@ static inline int pwc_set_backlight(stru buf = 0xff; else buf = 0x0; - return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), - SET_LUM_CTL, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - BACK_LIGHT_COMPENSATION_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + return SendControlMsg(SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1); } -static inline int pwc_get_backlight(struct pwc_device *pdev) +static inline int pwc_get_backlight(struct pwc_device *pdev, int *backlight) { int ret; unsigned char buf; - ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), - GET_LUM_CTL, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - BACK_LIGHT_COMPENSATION_FORMATTER, - pdev->vcinterface, - &buf, 1, HZ / 2); + ret = RecvControlMsg(GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1); if (ret < 0) return ret; - return buf; + *backlight = buf; + return 0; } @@ -1217,7 +1074,7 @@ static inline int pwc_set_flicker(struct return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1); } -static inline int pwc_get_flicker(struct pwc_device *pdev) +static inline int pwc_get_flicker(struct pwc_device *pdev, int *flicker) { int ret; unsigned char buf; @@ -1225,7 +1082,8 @@ static inline int pwc_get_flicker(struct ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1); if (ret < 0) return ret; - return buf; + *flicker = buf; + return 0; } @@ -1241,7 +1099,7 @@ static inline int pwc_set_dynamic_noise( return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1); } -static inline int pwc_get_dynamic_noise(struct pwc_device *pdev) +static inline int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise) { int ret; unsigned char buf; @@ -1249,14 +1107,15 @@ static inline int pwc_get_dynamic_noise( ret = RecvControlMsg(GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1); if (ret < 0) return ret; - return buf; + *noise = buf; + return 0; } int pwc_mpt_reset(struct pwc_device *pdev, int flags) { unsigned char buf; - buf = flags & 0x03; // only lower two bits are currently used + buf = flags & 0x03; // only lower two bits are currently used return SendControlMsg(SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, 1); } @@ -1293,7 +1152,7 @@ static inline int pwc_mpt_get_status(str } -int pwc_get_cmos_sensor(struct pwc_device *pdev) +int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) { unsigned char buf; int ret = -1, request; @@ -1305,24 +1164,60 @@ int pwc_get_cmos_sensor(struct pwc_devic else request = SENSOR_TYPE_FORMATTER2; - ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), - GET_STATUS_CTL, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - request, - pdev->vcinterface, - &buf, 1, HZ / 2); + ret = RecvControlMsg(GET_STATUS_CTL, request, 1); if (ret < 0) return ret; if (pdev->type < 675) - return buf | 0x100; + *sensor = buf | 0x100; else - return buf; + *sensor = buf; + return 0; } /* End of Add-Ons */ /* ************************************************* */ +/* Linux 2.5.something and 2.6 pass direct pointers to arguments of + ioctl() calls. With 2.4, you have to do tedious copy_from_user() + and copy_to_user() calls. With these macros we circumvent this, + and let me maintain only one source file. The functionality is + exactly the same otherwise. + */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) + +/* define local variable for arg */ +#define ARG_DEF(ARG_type, ARG_name)\ + ARG_type *ARG_name = arg; +/* copy arg to local variable */ +#define ARG_IN(ARG_name) /* nothing */ +/* argument itself (referenced) */ +#define ARGR(ARG_name) (*ARG_name) +/* argument address */ +#define ARGA(ARG_name) ARG_name +/* copy local variable to arg */ +#define ARG_OUT(ARG_name) /* nothing */ + +#else + +#define ARG_DEF(ARG_type, ARG_name)\ + ARG_type ARG_name; +#define ARG_IN(ARG_name)\ + if (copy_from_user(&ARG_name, arg, sizeof(ARG_name))) {\ + ret = -EFAULT;\ + break;\ + } +#define ARGR(ARG_name) ARG_name +#define ARGA(ARG_name) &ARG_name +#define ARG_OUT(ARG_name)\ + if (copy_to_user(arg, &ARG_name, sizeof(ARG_name))) {\ + ret = -EFAULT;\ + break;\ + } + +#endif + int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) { int ret = 0; @@ -1351,225 +1246,254 @@ int pwc_ioctl(struct pwc_device *pdev, u case VIDIOCPWCSCQUAL: { - int *qual = arg; + ARG_DEF(int, qual) - if (*qual < 0 || *qual > 3) + ARG_IN(qual) + if (ARGR(qual) < 0 || ARGR(qual) > 3) ret = -EINVAL; else - ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, *qual, pdev->vsnapshot); + ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot); if (ret >= 0) - pdev->vcompression = *qual; + pdev->vcompression = ARGR(qual); break; } case VIDIOCPWCGCQUAL: { - int *qual = arg; + ARG_DEF(int, qual) - *qual = pdev->vcompression; + ARGR(qual) = pdev->vcompression; + ARG_OUT(qual) break; } - + case VIDIOCPWCPROBE: { - struct pwc_probe *probe = arg; + ARG_DEF(struct pwc_probe, probe) - strcpy(probe->name, pdev->vdev.name); - probe->type = pdev->type; + strcpy(ARGR(probe).name, pdev->vdev->name); + ARGR(probe).type = pdev->type; + ARG_OUT(probe) + break; + } + + case VIDIOCPWCGSERIAL: + { + ARG_DEF(struct pwc_serial, serial) + + strcpy(ARGR(serial).serial, pdev->serial); + ARG_OUT(serial) break; } case VIDIOCPWCSAGC: { - int *agc = arg; + ARG_DEF(int, agc) - if (pwc_set_agc(pdev, *agc < 0 ? 1 : 0, *agc)) + ARG_IN(agc) + if (pwc_set_agc(pdev, ARGR(agc) < 0 ? 1 : 0, ARGR(agc))) ret = -EINVAL; break; } case VIDIOCPWCGAGC: { - int *agc = arg; + ARG_DEF(int, agc) - if (pwc_get_agc(pdev, agc)) + if (pwc_get_agc(pdev, ARGA(agc))) ret = -EINVAL; + ARG_OUT(agc) break; } case VIDIOCPWCSSHUTTER: { - int *shutter_speed = arg; + ARG_DEF(int, shutter_speed) - ret = pwc_set_shutter_speed(pdev, *shutter_speed < 0 ? 1 : 0, *shutter_speed); + ARG_IN(shutter_speed) + ret = pwc_set_shutter_speed(pdev, ARGR(shutter_speed) < 0 ? 1 : 0, ARGR(shutter_speed)); break; } case VIDIOCPWCSAWB: { - struct pwc_whitebalance *wb = arg; + ARG_DEF(struct pwc_whitebalance, wb) - ret = pwc_set_awb(pdev, wb->mode); - if (ret >= 0 && wb->mode == PWC_WB_MANUAL) { - pwc_set_red_gain(pdev, wb->manual_red); - pwc_set_blue_gain(pdev, wb->manual_blue); + ARG_IN(wb) + ret = pwc_set_awb(pdev, ARGR(wb).mode); + if (ret >= 0 && ARGR(wb).mode == PWC_WB_MANUAL) { + pwc_set_red_gain(pdev, ARGR(wb).manual_red); + pwc_set_blue_gain(pdev, ARGR(wb).manual_blue); } break; } case VIDIOCPWCGAWB: { - struct pwc_whitebalance *wb = arg; + ARG_DEF(struct pwc_whitebalance, wb) - memset(wb, 0, sizeof(*wb)); - wb->mode = pwc_get_awb(pdev); - if (wb->mode < 0) + memset(ARGA(wb), 0, sizeof(struct pwc_whitebalance)); + ARGR(wb).mode = pwc_get_awb(pdev); + if (ARGR(wb).mode < 0) ret = -EINVAL; else { - if (wb->mode == PWC_WB_MANUAL) { - wb->manual_red = pwc_get_red_gain(pdev); - wb->manual_blue = pwc_get_blue_gain(pdev); + if (ARGR(wb).mode == PWC_WB_MANUAL) { + ret = pwc_get_red_gain(pdev, &ARGR(wb).manual_red); + if (ret < 0) + break; + ret = pwc_get_blue_gain(pdev, &ARGR(wb).manual_blue); + if (ret < 0) + break; } - if (wb->mode == PWC_WB_AUTO) { - wb->read_red = pwc_read_red_gain(pdev); - wb->read_blue = pwc_read_blue_gain(pdev); + if (ARGR(wb).mode == PWC_WB_AUTO) { + ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red); + if (ret < 0) + break; + ret =pwc_read_blue_gain(pdev, &ARGR(wb).read_blue); + if (ret < 0) + break; } } + ARG_OUT(wb) break; } case VIDIOCPWCSAWBSPEED: { - struct pwc_wb_speed *wbs = arg; + ARG_DEF(struct pwc_wb_speed, wbs) - if (wbs->control_speed > 0) { - ret = pwc_set_wb_speed(pdev, wbs->control_speed); + if (ARGR(wbs).control_speed > 0) { + ret = pwc_set_wb_speed(pdev, ARGR(wbs).control_speed); } - if (wbs->control_delay > 0) { - ret = pwc_set_wb_delay(pdev, wbs->control_delay); + if (ARGR(wbs).control_delay > 0) { + ret = pwc_set_wb_delay(pdev, ARGR(wbs).control_delay); } break; } case VIDIOCPWCGAWBSPEED: { - struct pwc_wb_speed *wbs = arg; + ARG_DEF(struct pwc_wb_speed, wbs) - ret = pwc_get_wb_speed(pdev); + ret = pwc_get_wb_speed(pdev, &ARGR(wbs).control_speed); if (ret < 0) break; - wbs->control_speed = ret; - ret = pwc_get_wb_delay(pdev); + ret = pwc_get_wb_delay(pdev, &ARGR(wbs).control_delay); if (ret < 0) break; - wbs->control_delay = ret; + ARG_OUT(wbs) break; } case VIDIOCPWCSLED: { - struct pwc_leds *leds = arg; + ARG_DEF(struct pwc_leds, leds) - ret = pwc_set_leds(pdev, leds->led_on, leds->led_off); + ARG_IN(leds) + ret = pwc_set_leds(pdev, ARGR(leds).led_on, ARGR(leds).led_off); break; } case VIDIOCPWCGLED: { - struct pwc_leds *leds = arg; + ARG_DEF(struct pwc_leds, leds) - ret = pwc_get_leds(pdev, &leds->led_on, &leds->led_off); + ret = pwc_get_leds(pdev, &ARGR(leds).led_on, &ARGR(leds).led_off); + ARG_OUT(leds) break; } case VIDIOCPWCSCONTOUR: { - int *contour = arg; + ARG_DEF(int, contour) - ret = pwc_set_contour(pdev, *contour); + ARG_IN(contour) + ret = pwc_set_contour(pdev, ARGR(contour)); break; } case VIDIOCPWCGCONTOUR: { - int *contour = arg; + ARG_DEF(int, contour) - ret = pwc_get_contour(pdev, contour); + ret = pwc_get_contour(pdev, ARGA(contour)); + ARG_OUT(contour) break; } case VIDIOCPWCSBACKLIGHT: { - int *backlight = arg; + ARG_DEF(int, backlight) - ret = pwc_set_backlight(pdev, *backlight); + ARG_IN(backlight) + ret = pwc_set_backlight(pdev, ARGR(backlight)); break; } case VIDIOCPWCGBACKLIGHT: { - int *backlight = arg; + ARG_DEF(int, backlight) - ret = pwc_get_backlight(pdev); - if (ret >= 0) - *backlight = ret; + ret = pwc_get_backlight(pdev, ARGA(backlight)); + ARG_OUT(backlight) break; } case VIDIOCPWCSFLICKER: { - int *flicker = arg; + ARG_DEF(int, flicker) - ret = pwc_set_flicker(pdev, *flicker); + ARG_IN(flicker) + ret = pwc_set_flicker(pdev, ARGR(flicker)); break; } case VIDIOCPWCGFLICKER: { - int *flicker = arg; + ARG_DEF(int, flicker) - ret = pwc_get_flicker(pdev); - if (ret >= 0) - *flicker = ret; + ret = pwc_get_flicker(pdev, ARGA(flicker)); + ARG_OUT(flicker) break; } case VIDIOCPWCSDYNNOISE: { - int *dynnoise = arg; + ARG_DEF(int, dynnoise) - ret = pwc_set_dynamic_noise(pdev, *dynnoise); + ARG_IN(dynnoise) + ret = pwc_set_dynamic_noise(pdev, ARGR(dynnoise)); break; } case VIDIOCPWCGDYNNOISE: { - int *dynnoise = arg; + ARG_DEF(int, dynnoise) - ret = pwc_get_dynamic_noise(pdev); - if (ret < 0) - break; - *dynnoise = ret; + ret = pwc_get_dynamic_noise(pdev, ARGA(dynnoise)); + ARG_OUT(dynnoise); break; } case VIDIOCPWCGREALSIZE: { - struct pwc_imagesize *size = arg; + ARG_DEF(struct pwc_imagesize, size) - size->width = pdev->image.x; - size->height = pdev->image.y; + ARGR(size).width = pdev->image.x; + ARGR(size).height = pdev->image.y; + ARG_OUT(size) break; } case VIDIOCPWCMPTRESET: { - int *flags = arg; - if (pdev->features & FEATURE_MOTOR_PANTILT) { - ret = pwc_mpt_reset(pdev, *flags); + ARG_DEF(int, flags) + + ARG_IN(flags) + ret = pwc_mpt_reset(pdev, ARGR(flags)); if (ret >= 0) { pdev->pan_angle = 0; @@ -1582,11 +1506,15 @@ int pwc_ioctl(struct pwc_device *pdev, u } break; } + case VIDIOCPWCMPTGRANGE: { if (pdev->features & FEATURE_MOTOR_PANTILT) { - memcpy(arg, &pdev->angle_range, sizeof(struct pwc_mpt_range)); + ARG_DEF(struct pwc_mpt_range, range) + + ARGR(range) = pdev->angle_range; + ARG_OUT(range) } else { @@ -1597,23 +1525,25 @@ int pwc_ioctl(struct pwc_device *pdev, u case VIDIOCPWCMPTSANGLE: { - struct pwc_mpt_angles *angles = arg; int new_pan, new_tilt; if (pdev->features & FEATURE_MOTOR_PANTILT) { + ARG_DEF(struct pwc_mpt_angles, angles) + + ARG_IN(angles) /* The camera can only set relative angles, so do some calculations when getting an absolute angle . */ - if (angles->absolute) + if (ARGR(angles).absolute) { - new_pan = angles->pan; - new_tilt = angles->tilt; + new_pan = ARGR(angles).pan; + new_tilt = ARGR(angles).tilt; } else { - new_pan = pdev->pan_angle + angles->pan; - new_tilt = pdev->tilt_angle + angles->tilt; + new_pan = pdev->pan_angle + ARGR(angles).pan; + new_tilt = pdev->tilt_angle + ARGR(angles).tilt; } /* check absolute ranges */ if (new_pan < pdev->angle_range.pan_min || @@ -1649,17 +1579,19 @@ int pwc_ioctl(struct pwc_device *pdev, u ret = -ENXIO; } break; - } - + } + case VIDIOCPWCMPTGANGLE: { - struct pwc_mpt_angles *angles = arg; if (pdev->features & FEATURE_MOTOR_PANTILT) { - angles->absolute = 1; - angles->pan = pdev->pan_angle; - angles->tilt = pdev->tilt_angle; + ARG_DEF(struct pwc_mpt_angles, angles) + + ARGR(angles).absolute = 1; + ARGR(angles).pan = pdev->pan_angle; + ARGR(angles).tilt = pdev->tilt_angle; + ARG_OUT(angles) } else { @@ -1670,19 +1602,34 @@ int pwc_ioctl(struct pwc_device *pdev, u case VIDIOCPWCMPTSTATUS: { - struct pwc_mpt_status *status = arg; - if (pdev->features & FEATURE_MOTOR_PANTILT) { - ret = pwc_mpt_get_status(pdev, status); + ARG_DEF(struct pwc_mpt_status, status) + + ret = pwc_mpt_get_status(pdev, ARGA(status)); + ARG_OUT(status) } else { ret = -ENXIO; } - break; - } - + break; + } + + case VIDIOCPWCGVIDCMD: + { + ARG_DEF(struct pwc_video_command, cmd); + + ARGR(cmd).type = pdev->type; + ARGR(cmd).release = pdev->release; + ARGR(cmd).command_len = pdev->cmd_len; + memcpy(&ARGR(cmd).command_buf, pdev->cmd_buf, pdev->cmd_len); + ARGR(cmd).bandlength = pdev->vbandlength; + ARGR(cmd).frame_size = pdev->frame_size; + ARG_OUT(cmd) + break; + } + default: ret = -ENOIOCTLCMD; break; diff -puN drivers/usb/media/pwc.h~bk-usb drivers/usb/media/pwc.h --- 25/drivers/usb/media/pwc.h~bk-usb 2004-06-28 20:21:13.868805632 -0700 +++ 25-akpm/drivers/usb/media/pwc.h 2004-06-28 20:21:15.321584776 -0700 @@ -22,15 +22,15 @@ #include #include -#include -#include #include +#include #include #include - +#include #include #include +#include "pwc-uncompress.h" #include "pwc-ioctl.h" /* Defines and structures for the Philips webcam */ @@ -65,9 +65,9 @@ #define FEATURE_MOTOR_PANTILT 0x0001 /* Version block */ -#define PWC_MAJOR 8 -#define PWC_MINOR 12 -#define PWC_VERSION "8.12" +#define PWC_MAJOR 9 +#define PWC_MINOR 0 +#define PWC_VERSION "9.0.1" #define PWC_NAME "pwc" /* Turn certain features on/off */ @@ -90,12 +90,6 @@ /* Absolute maximum number of buffers available for mmap() */ #define MAX_IMAGES 10 -struct pwc_coord -{ - int x, y; /* guess what */ - int size; /* size, or offset */ -}; - /* The following structures were based on cpia.h. Why reinvent the wheel? :-) */ struct pwc_iso_buf { @@ -118,7 +112,7 @@ struct pwc_frame_buf struct pwc_device { - struct video_device vdev; + struct video_device *vdev; #ifdef PWC_MAGIC int magic; #endif @@ -128,6 +122,7 @@ struct pwc_device int type; /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */ int release; /* release number */ int features; /* feature bits */ + char serial[30]; /* serial number (string) */ int error_status; /* set when something goes wrong with the cam (unplugged, USB errors) */ int usb_init; /* set when the cam has been initialized over USB */ @@ -137,6 +132,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; /* palette: 420P, RAW or RGBBAYER */ int vframe_count; /* received frames */ int vframes_dumped; /* counter for dumped frames */ int vframes_error; /* frames received in error */ @@ -148,6 +144,9 @@ struct pwc_device char vsnapshot; /* snapshot mode */ char vsync; /* used by isoc handler */ char vmirror; /* for ToUCaM series */ + + int cmd_len; + unsigned char cmd_buf[13]; /* The image acquisition requires 3 to 4 steps: 1. data is gathered in short packets from the USB controller @@ -169,8 +168,9 @@ struct pwc_device struct pwc_frame_buf *full_frames, *full_frames_tail; /* all filled frames */ struct pwc_frame_buf *fill_frame; /* frame currently being filled */ struct pwc_frame_buf *read_frame; /* frame currently read by user process */ - int frame_size; int frame_header_size, frame_trailer_size; + int frame_size; + int frame_total_size; /* including header & trailer */ int drop_frames; #if PWC_DEBUG int sequence; /* Debugging aid */ @@ -187,7 +187,8 @@ struct pwc_device a gray or black border. view_min <= image <= view <= view_max; */ int image_mask; /* bitmask of supported sizes */ - struct pwc_coord view_min, view_max; /* minimum and maximum sizes */ + struct pwc_coord view_min, view_max; /* minimum and maximum viewable sizes */ + struct pwc_coord abs_max; /* maximum supported size with compression */ struct pwc_coord image, view; /* image and viewport size */ struct pwc_coord offset; /* offset within the viewport */ @@ -213,16 +214,6 @@ struct pwc_device #endif }; -/* Enumeration of image sizes */ -#define PSZ_SQCIF 0x00 -#define PSZ_QSIF 0x01 -#define PSZ_QCIF 0x02 -#define PSZ_SIF 0x03 -#define PSZ_CIF 0x04 -#define PSZ_VGA 0x05 -#define PSZ_MAX 6 - - #ifdef __cplusplus extern "C" { @@ -259,7 +250,7 @@ extern int pwc_get_saturation(struct pwc extern int pwc_set_saturation(struct pwc_device *pdev, int value); extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value); extern int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value); -extern int pwc_get_cmos_sensor(struct pwc_device *pdev); +extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor); /* Power down or up the camera; not supported by all models */ extern int pwc_camera_power(struct pwc_device *pdev, int power); diff -puN drivers/usb/media/pwc-if.c~bk-usb drivers/usb/media/pwc-if.c --- 25/drivers/usb/media/pwc-if.c~bk-usb 2004-06-28 20:21:13.869805480 -0700 +++ 25-akpm/drivers/usb/media/pwc-if.c 2004-06-28 20:21:15.316585536 -0700 @@ -1,6 +1,6 @@ -/* Linux driver for Philips webcam +/* Linux driver for Philips webcam USB and Video4Linux interface part. - (C) 1999-2003 Nemosoft Unv. + (C) 1999-2004 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,7 +42,7 @@ - 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 Afina Eye ID + - Jk Fang: Sotec Afina Eye ID - Xavier Roche: QuickCam Pro 4000 ID - Jens Knudsen: QuickCam Zoom ID - J. Debert: QuickCam for Notebooks ID @@ -90,6 +90,7 @@ static struct usb_device_id pwc_device_t { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */ { USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */ { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */ + { USB_DEVICE(0x06BE, 0x8116) }, /* new Afina Eye */ { USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */ { USB_DEVICE(0x0d81, 0x1900) }, { } @@ -151,7 +152,9 @@ static struct video_device pwc_template .name = "Philips Webcam", /* Filled in later */ .type = VID_TYPE_CAPTURE, .hardware = VID_HARDWARE_PWC, + .release = video_device_release, .fops = &pwc_fops, + .minor = -1, }; /***************************************************************************/ @@ -258,7 +261,7 @@ static int pwc_allocate_buffers(struct p return -ENXIO; } #endif - /* Allocate Isochronous pipe buffers */ + /* Allocate Isochronuous pipe buffers */ for (i = 0; i < MAX_ISO_BUFS; i++) { if (pdev->sbuf[i].data == NULL) { kbuf = kmalloc(ISO_BUFFER_SIZE, GFP_KERNEL); @@ -443,7 +446,7 @@ static inline int pwc_next_fill_frame(st { int ret; unsigned long flags; - + ret = 0; spin_lock_irqsave(&pdev->ptrlock, flags); if (pdev->fill_frame != NULL) { @@ -488,7 +491,7 @@ static inline int pwc_next_fill_frame(st /** \brief Reset all buffers, pointers and lists, except for the image_used[] buffer. - + If the image_used[] buffer is cleared too, mmap()/VIDIOCSYNC will run into trouble. */ static void pwc_reset_buffers(struct pwc_device *pdev) @@ -525,7 +528,7 @@ static int pwc_handle_frame(struct pwc_d { int ret = 0; unsigned long flags; - + spin_lock_irqsave(&pdev->ptrlock, flags); /* First grab our read_frame; this is removed from all lists, so we can release the lock after this without problems */ @@ -548,7 +551,7 @@ static int pwc_handle_frame(struct pwc_d Trace(TRACE_SEQUENCE, "Decompressing frame %d\n", pdev->read_frame->sequence); #endif /* Decompression is a lenghty process, so it's outside of the lock. - This gives the isoc_handler the opportunity to fill more frames + This gives the isoc_handler the opportunity to fill more frames in the mean time. */ spin_unlock_irqrestore(&pdev->ptrlock, flags); @@ -643,7 +646,7 @@ static void pwc_isoc_handler(struct urb else { fillptr = fbuf->data + fbuf->filled; } - + /* Reset ISOC error counter. We did get here, after all. */ pdev->visoc_errors = 0; @@ -662,8 +665,8 @@ static void pwc_isoc_handler(struct urb pdev->vsync = 2; /* ...copy data to frame buffer, if possible */ - if (flen + fbuf->filled > pdev->frame_size) { - Trace(TRACE_FLOW, "Frame buffer overflow (flen = %d, frame_size = %d).\n", flen, pdev->frame_size); + if (flen + fbuf->filled > pdev->frame_total_size) { + Trace(TRACE_FLOW, "Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size); pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */ pdev->vframes_error++; } @@ -728,7 +731,7 @@ static void pwc_isoc_handler(struct urb pdev->drop_frames--; else { /* Check for underflow first */ - if (fbuf->filled < pdev->frame_size) { + if (fbuf->filled < pdev->frame_total_size) { Trace(TRACE_FLOW, "Frame buffer underflow (%d bytes); discarded.\n", fbuf->filled); pdev->vframes_error++; } @@ -817,7 +820,7 @@ static int pwc_isoc_init(struct pwc_devi if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) { Err("Failed to find packet size for video endpoint in current alternate setting.\n"); - return -ENFILE; /* Odd error, that should be noticeable */ + return -ENFILE; /* Odd error, that should be noticable */ } /* Set alternate interface */ @@ -874,7 +877,7 @@ static int pwc_isoc_init(struct pwc_devi if (ret) Err("isoc_init() submit_urb %d failed with error %d\n", i, ret); else - Trace(TRACE_OPEN, "URB 0x%p submitted.\n", pdev->sbuf[i].urb); + Trace(TRACE_MEMORY, "URB 0x%p submitted.\n", pdev->sbuf[i].urb); } /* All is done... */ @@ -886,7 +889,7 @@ static int pwc_isoc_init(struct pwc_devi static void pwc_isoc_cleanup(struct pwc_device *pdev) { int i; - + Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n"); if (pdev == NULL) return; @@ -937,9 +940,9 @@ int pwc_try_video_mode(struct pwc_device Trace(TRACE_FLOW, "pwc_set_video_mode attempt 2 failed.\n"); } } - if (start == 0) + if (start == 0) { - if (pwc_isoc_init(pdev) < 0) + if (pwc_isoc_init(pdev) < 0) { Info("Failed to restart ISOC transfers in pwc_try_video_mode.\n"); ret = -EAGAIN; /* let's try again, who knows if it works a second time */ @@ -972,27 +975,31 @@ static int pwc_video_open(struct inode * Trace(TRACE_OPEN, "Doing first time initialization.\n"); pdev->usb_init = 1; - if (pwc_trace & TRACE_OPEN) { + if (pwc_trace & TRACE_OPEN) + { /* Query sensor type */ const char *sensor_type = NULL; + int ret; - 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; + ret = pwc_get_cmos_sensor(pdev, &i); + if (ret >= 0) + { + switch(i) { + 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); + Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i); } } @@ -1037,6 +1044,7 @@ static int pwc_video_open(struct inode * /* Set some defaults */ pdev->vsnapshot = 0; + /* Start iso pipe for video; first try the last used video size (or the default one); if that fails try QCIF/10 or QSIF/10; it that fails too, give up. @@ -1090,7 +1098,7 @@ static int pwc_video_close(struct inode /* Dump statistics, but only if a reasonable amount of frames were processed (to prevent endless log-entries in case of snap-shot - programs) + programs) */ 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); @@ -1111,7 +1119,7 @@ static int pwc_video_close(struct inode Info("Failed to set LED on/off time.\n"); if (power_save) { i = pwc_camera_power(pdev, 0); - if (i < 0) + if (i < 0) Err("Failed to power down camera (%d)\n", i); } } @@ -1139,6 +1147,7 @@ static ssize_t pwc_video_read(struct fil struct pwc_device *pdev; int noblock = file->f_flags & O_NONBLOCK; DECLARE_WAITQUEUE(wait, current); + int bytes_to_read; Trace(TRACE_READ, "video_read(0x%p, %p, %d) called.\n", vdev, buf, count); if (vdev == NULL) @@ -1175,20 +1184,25 @@ static ssize_t pwc_video_read(struct fil } remove_wait_queue(&pdev->frameq, &wait); set_current_state(TASK_RUNNING); - + /* Decompress and release frame */ if (pwc_handle_frame(pdev)) return -EFAULT; } Trace(TRACE_READ, "Copying data to user space.\n"); + if (pdev->vpalette == VIDEO_PALETTE_RAW) + bytes_to_read = pdev->frame_size; + else + bytes_to_read = pdev->view.size; + /* copy bytes to user space; we allow for partial reads */ - if (count + pdev->image_read_pos > pdev->view.size) - count = pdev->view.size - pdev->image_read_pos; + if (count + pdev->image_read_pos > bytes_to_read) + count = bytes_to_read - pdev->image_read_pos; if (copy_to_user(buf, pdev->image_ptr[pdev->fill_image] + pdev->image_read_pos, count)) return -EFAULT; pdev->image_read_pos += count; - if (pdev->image_read_pos >= pdev->view.size) { /* All data has been read */ + if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */ pdev->image_read_pos = 0; pwc_next_image(pdev); } @@ -1260,7 +1274,7 @@ static int pwc_video_do_ioctl(struct ino } case VIDIOCSCHAN: - { + { /* The spec says the argument is an integer, but the bttv driver uses a video_channel arg, which makes sense becasue it also has the norm flag. @@ -1278,8 +1292,6 @@ static int pwc_video_do_ioctl(struct ino struct video_picture *p = arg; int val; - p->colour = 0x8000; - p->hue = 0x8000; val = pwc_get_brightness(pdev); if (val >= 0) p->brightness = val; @@ -1302,11 +1314,11 @@ static int pwc_video_do_ioctl(struct ino else p->colour = 0xffff; p->depth = 24; - p->palette = VIDEO_PALETTE_YUV420P; + p->palette = pdev->vpalette; p->hue = 0xFFFF; /* N/A */ break; } - + case VIDIOCSPICT: { struct video_picture *p = arg; @@ -1318,13 +1330,22 @@ static int pwc_video_do_ioctl(struct ino is used exactly once in the uncompress routine. */ - if (p->palette && p->palette != VIDEO_PALETTE_YUV420P) { - return -EINVAL; - } pwc_set_brightness(pdev, p->brightness); pwc_set_contrast(pdev, p->contrast); pwc_set_gamma(pdev, p->whiteness); pwc_set_saturation(pdev, p->colour); + if (p->palette && p->palette != pdev->vpalette) { + switch (p->palette) { + case VIDEO_PALETTE_YUV420P: + case VIDEO_PALETTE_RAW: + pdev->vpalette = p->palette; + return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); + break; + default: + return -EINVAL; + break; + } + } break; } @@ -1398,13 +1419,23 @@ static int pwc_video_do_ioctl(struct ino various palettes... The driver doesn't support such small images, so I'm working around it. */ - if (vm->format && vm->format != VIDEO_PALETTE_YUV420P) - return -EINVAL; - + if (vm->format) + { + switch (vm->format) + { + case VIDEO_PALETTE_YUV420P: + case VIDEO_PALETTE_RAW: + break; + default: + return -EINVAL; + break; + } + } + if ((vm->width != pdev->view.x || vm->height != pdev->view.y) && (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) { int ret; - + Trace(TRACE_OPEN, "VIDIOCMCAPTURE: changing size to please xawtv :-(.\n"); ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot); if (ret) @@ -1523,7 +1554,7 @@ static int pwc_video_do_ioctl(struct ino { struct video_unit *vu = arg; - vu->video = pdev->vdev.minor & 0x3F; + vu->video = pdev->vdev->minor & 0x3F; vu->audio = -1; /* not known yet */ vu->vbi = -1; vu->radio = -1; @@ -1636,12 +1667,12 @@ static int usb_pwc_probe(struct usb_inte type_id = 690; break; case 0x0310: - Info("Philips PCVC730K (ToUCam Fun) USB webcam detected.\n"); + Info("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n"); name = "Philips 730 webcam"; type_id = 730; break; case 0x0311: - Info("Philips PCVC740K (ToUCam Pro) USB webcam detected.\n"); + Info("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n"); name = "Philips 740 webcam"; type_id = 740; break; @@ -1755,17 +1786,44 @@ static int usb_pwc_probe(struct usb_inte break; } } - else if (vendor_id == 0x04cc) { + else if (vendor_id == 0x04cc) { switch(product_id) { case 0x8116: Info("Sotec Afina Eye USB webcam detected.\n"); name = "Sotec Afina Eye"; type_id = 730; - break; + break; + default: + return -ENODEV; + break; + } + } + else if (vendor_id == 0x06be) { + switch(product_id) { + case 0x8116: + /* Basicly the same as the Sotec Afina Eye */ + Info("AME CU-001 USB webcam detected.\n"); + name = "AME CU-001"; + type_id = 730; + break; + default: + return -ENODEV; + break; + } + } + else if (vendor_id == 0x06be) { + switch(product_id) { + case 0x8116: + /* This is essentially the same cam as the Sotec Afina Eye */ + Info("AME Co. Afina Eye USB webcam detected.\n"); + name = "AME Co. Afina Eye"; + type_id = 750; + break; default: return -ENODEV; break; } + } else if (vendor_id == 0x0d81) { switch(product_id) { @@ -1804,6 +1862,7 @@ static int usb_pwc_probe(struct usb_inte pdev->type = type_id; pdev->vsize = default_size; pdev->vframes = default_fps; + strcpy(pdev->serial, serial_number); pdev->features = features; if (vendor_id == 0x046D && product_id == 0x08B5) { @@ -1815,8 +1874,6 @@ static int usb_pwc_probe(struct usb_inte pdev->angle_range.pan_max = 7000; pdev->angle_range.tilt_min = -3000; pdev->angle_range.tilt_max = 2500; - pdev->angle_range.zoom_min = -1; - pdev->angle_range.zoom_max = -1; } init_MUTEX(&pdev->modlock); @@ -1826,11 +1883,19 @@ static int usb_pwc_probe(struct usb_inte init_waitqueue_head(&pdev->frameq); pdev->vcompression = pwc_preferred_compression; - memcpy(&pdev->vdev, &pwc_template, sizeof(pwc_template)); - strcpy(pdev->vdev.name, name); - pdev->vdev.owner = THIS_MODULE; - pdev->vdev.priv = pdev; - + /* Allocate video_device structure */ + pdev->vdev = video_device_alloc(); + if (pdev->vdev == 0) + { + Err("Err, cannot allocate video_device struture. Failing probe."); + kfree(pdev); + return -ENOMEM; + } + memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template)); + strcpy(pdev->vdev->name, name); + pdev->vdev->owner = THIS_MODULE; + video_set_drvdata(pdev->vdev, pdev); + pdev->release = udev->descriptor.bcdDevice; Trace(TRACE_PROBE, "Release: %04x\n", pdev->release); @@ -1848,15 +1913,16 @@ static int usb_pwc_probe(struct usb_inte } } - pdev->vdev.release = video_device_release; - i = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, video_nr); + pdev->vdev->release = video_device_release; + i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr); if (i < 0) { Err("Failed to register as video device (%d).\n", i); + video_device_release(pdev->vdev); /* Drip... drip... drip... */ kfree(pdev); /* Oops, no memory leaks please */ return -EIO; } else { - Info("Registered as /dev/video%d.\n", pdev->vdev.minor & 0x3F); + Info("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F); } /* occupy slot */ @@ -1894,14 +1960,14 @@ static void usb_pwc_disconnect(struct us Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n"); goto disconnect_out; } -#endif +#endif /* We got unplugged; this is signalled by an EPIPE error code */ if (pdev->vopen) { Info("Disconnected while webcam is in use!\n"); pdev->error_status = EPIPE; } - + /* Alert waiting processes */ wake_up_interruptible(&pdev->frameq); /* Wait until device is closed */ @@ -1909,7 +1975,7 @@ static void usb_pwc_disconnect(struct us schedule(); /* Device is now closed, so we can safely unregister it */ Trace(TRACE_PROBE, "Unregistering video device in disconnect().\n"); - video_unregister_device(&pdev->vdev); + video_unregister_device(pdev->vdev); /* Free memory (don't set pdev to 0 just yet) */ kfree(pdev); @@ -1928,7 +1994,7 @@ disconnect_out: static int pwc_atoi(const char *s) { int k = 0; - + k = 0; while (*s != '\0' && *s >= '0' && *s <= '9') { k = 10 * k + (*s - '0'); @@ -1971,7 +2037,7 @@ MODULE_PARM(dev_hint, "0-20s"); MODULE_PARM_DESC(dev_hint, "Device node hints"); MODULE_DESCRIPTION("Philips & OEM USB webcam driver"); -MODULE_AUTHOR("Nemosoft Unv. "); +MODULE_AUTHOR("Nemosoft Unv. "); MODULE_LICENSE("GPL"); static int __init usb_pwc_init(void) @@ -1979,9 +2045,10 @@ static int __init usb_pwc_init(void) int i, sz; 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, 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"); + Info("Philips webcam module version " PWC_VERSION " loaded.\n"); + Info("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n"); + Info("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n"); + Info("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n"); if (fps) { if (fps < 4 || fps > 30) { @@ -1991,7 +2058,7 @@ static int __init usb_pwc_init(void) default_fps = fps; Info("Default framerate set to %d.\n", default_fps); } - + if (size) { /* string; try matching with array */ for (sz = 0; sz < PSZ_MAX; sz++) { @@ -2041,12 +2108,12 @@ static int __init usb_pwc_init(void) if (leds[1] >= 0) led_off = leds[1]; - /* Big device node whoopla. Basically, it allows you to assign a - device node (/dev/videoX) to a camera, based on its type + /* Big device node whoopla. Basicly, it allows you to assign a + device node (/dev/videoX) to a camera, based on its type & serial number. The format is [type[.serialnumber]:]node. - Any camera that isn't matched by these rules gets the next - available free device node. + Any camera that isn't matched by these rules gets the next + available free device node. */ for (i = 0; i < MAX_DEV_HINTS; i++) { char *s, *colon, *dot; diff -puN drivers/usb/media/pwc-ioctl.h~bk-usb drivers/usb/media/pwc-ioctl.h --- 25/drivers/usb/media/pwc-ioctl.h~bk-usb 2004-06-28 20:21:13.871805176 -0700 +++ 25-akpm/drivers/usb/media/pwc-ioctl.h 2004-06-28 20:21:15.317585384 -0700 @@ -1,8 +1,8 @@ #ifndef PWC_IOCTL_H #define PWC_IOCTL_H -/* (C) 2001-2003 Nemosoft Unv. webcam@smcc.demon.nl - +/* (C) 2001-2004 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 the Free Software Foundation; either version 2 of the License, or @@ -18,19 +18,24 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* This is pwc-ioctl.h belonging to PWC 8.10 */ +/* This is pwc-ioctl.h belonging to PWC 8.12.1 + It contains structures and defines to communicate from user space + directly to the driver. + */ -/* +/* Changes - 2001/08/03 Alvarado Added ioctl constants to access methods for + 2001/08/03 Alvarado Added ioctl constants to access methods for changing white balance and red/blue gains 2002/12/15 G. H. Fernandez-Toribio VIDIOCGREALSIZE + 2003/12/13 Nemosft Unv. Some modifications to make interfacing to + PWCX easier */ /* These are private ioctl() commands, specific for the Philips webcams. They contain functions not found in other webcams, and settings not - specified in the Video4Linux API. - + specified in the Video4Linux API. + The #define names are built up like follows: VIDIOC VIDeo IOCtl prefix PWC Philps WebCam @@ -40,13 +45,21 @@ */ + /* Enumeration of image sizes */ +#define PSZ_SQCIF 0x00 +#define PSZ_QSIF 0x01 +#define PSZ_QCIF 0x02 +#define PSZ_SIF 0x03 +#define PSZ_CIF 0x04 +#define PSZ_VGA 0x05 +#define PSZ_MAX 6 /* The frame rate is encoded in the video_window.flags parameter using the upper 16 bits, since some flags are defined nowadays. The following defines provide a mask and shift to filter out this value. - - In 'Snapshot' mode the camera freezes its automatic exposure and colour + + In 'Snapshot' mode the camera freezes its automatic exposure and colour balance controls. */ #define PWC_FPS_SHIFT 16 @@ -55,14 +68,26 @@ #define PWC_FPS_SNAPSHOT 0x00400000 +/* structure for transfering x & y coordinates */ +struct pwc_coord +{ + int x, y; /* guess what */ + int size; /* size, or offset */ +}; + +/* Used with VIDIOCPWCPROBE */ struct pwc_probe { char name[32]; int type; }; - +struct pwc_serial +{ + char serial[30]; /* String with serial number. Contains terminating 0 */ +}; + /* pwc_whitebalance.mode values */ #define PWC_WB_INDOOR 0 #define PWC_WB_OUTDOOR 1 @@ -78,7 +103,6 @@ struct pwc_probe otherwise undefined. 'read_red' and 'read_blue' are read-only. */ - struct pwc_whitebalance { int mode; @@ -117,7 +141,7 @@ struct pwc_imagesize #define PWC_MPT_TILT 0x02 #define PWC_MPT_TIMEOUT 0x04 /* for status */ -/* Set angles; when absolute = 1, the angle is absolute and the +/* Set angles; when absolute != 0, the angle is absolute and the driver calculates the relative offset for you. This can only be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns absolute angles. @@ -127,18 +151,14 @@ struct pwc_mpt_angles int absolute; /* write-only */ int pan; /* degrees * 100 */ int tilt; /* degress * 100 */ - int zoom; /* N/A, set to -1 */ }; /* Range of angles of the camera, both horizontally and vertically. - The zoom is not used, maybe in the future... - */ struct pwc_mpt_range { int pan_min, pan_max; /* degrees * 100 */ int tilt_min, tilt_max; - int zoom_min, zoom_max; /* -1, -1 */ }; struct pwc_mpt_status @@ -149,6 +169,30 @@ struct pwc_mpt_status }; +/* This is used for out-of-kernel decompression. With it, you can get + all the necessary information to initialize and use the decompressor + routines in standalone applications. + */ +struct pwc_video_command +{ + int type; /* camera type (645, 675, 730, etc.) */ + int release; /* release number */ + + int size; /* one of PSZ_* */ + int alternate; + int command_len; /* length of USB video command */ + unsigned char command_buf[13]; /* Actual USB video command */ + int bandlength; /* >0 = compressed */ + int frame_size; /* Size of one (un)compressed frame */ +}; + +/* Flags for PWCX subroutines. Not all modules honour all flags. */ +#define PWCX_FLAG_PLANAR 0x0001 +#define PWCX_FLAG_BAYER 0x0008 + + +/* IOCTL definitions */ + /* Restore user settings */ #define VIDIOCPWCRUSER _IO('v', 192) /* Save user settings */ @@ -169,16 +213,19 @@ struct pwc_mpt_status #define VIDIOCPWCGCQUAL _IOR('v', 195, int) +/* Retrieve serial number of camera */ +#define VIDIOCPWCGSERIAL _IOR('v', 198, struct pwc_serial) + /* This is a probe function; since so many devices are supported, it becomes difficult to include all the names in programs that want to check for the enhanced Philips stuff. So in stead, try this PROBE; - it returns a structure with the original name, and the corresponding + it returns a structure with the original name, and the corresponding Philips type. To use, fill the structure with zeroes, call PROBE and if that succeeds, compare the name with that returned from VIDIOCGCAP; they should be the same. If so, you can be assured it is a Philips (OEM) cam and the type is valid. - */ + */ #define VIDIOCPWCPROBE _IOR('v', 199, struct pwc_probe) /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */ @@ -225,5 +272,8 @@ struct pwc_mpt_status #define VIDIOCPWCMPTSANGLE _IOW('v', 212, struct pwc_mpt_angles) #define VIDIOCPWCMPTGANGLE _IOR('v', 212, struct pwc_mpt_angles) #define VIDIOCPWCMPTSTATUS _IOR('v', 213, struct pwc_mpt_status) - + + /* Get the USB set-video command; needed for initializing libpwcx */ +#define VIDIOCPWCGVIDCMD _IOR('v', 215, struct pwc_video_command) + #endif diff -puN drivers/usb/media/pwc-misc.c~bk-usb drivers/usb/media/pwc-misc.c --- 25/drivers/usb/media/pwc-misc.c~bk-usb 2004-06-28 20:21:13.872805024 -0700 +++ 25-akpm/drivers/usb/media/pwc-misc.c 2004-06-28 20:21:15.318585232 -0700 @@ -15,13 +15,13 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ +*/ #include #include "pwc.h" -struct pwc_coord pwc_image_sizes[PSZ_MAX] = +struct pwc_coord pwc_image_sizes[PSZ_MAX] = { { 128, 96, 0 }, { 160, 120, 0 }, @@ -36,11 +36,30 @@ int pwc_decode_size(struct pwc_device *p { int i, find; - /* Make sure we don't go beyond our max size */ - if (width > pdev->view_max.x || height > pdev->view_max.y) - return -1; + /* Make sure we don't go beyond our max size. + NB: we have different limits for RAW and normal modes. In case + you don't have the decompressor loaded or use RAW mode, + the maximum viewable size is smaller. + */ + if (pdev->vpalette == VIDEO_PALETTE_RAW) + { + if (width > pdev->abs_max.x || height > pdev->abs_max.y) + { + Debug("VIDEO_PALETTE_RAW: going beyond abs_max.\n"); + return -1; + } + } + else + { + if (width > pdev->view_max.x || height > pdev->view_max.y) + { + Debug("VIDEO_PALETTE_ not RAW: going beyond view_max.\n"); + return -1; + } + } + /* Find the largest size supported by the camera that fits into the - requested size. + requested size. */ find = -1; for (i = 0; i < PSZ_MAX; i++) { @@ -62,6 +81,8 @@ void pwc_construct(struct pwc_device *pd pdev->view_min.y = 96; pdev->view_max.x = 352; pdev->view_max.y = 288; + pdev->abs_max.x = 352; + pdev->abs_max.y = 288; pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QCIF | 1 << PSZ_CIF; pdev->vcinterface = 2; pdev->vendpoint = 4; @@ -77,13 +98,14 @@ void pwc_construct(struct pwc_device *pd if (pdev->decompressor != NULL) { pdev->view_max.x = 640; pdev->view_max.y = 480; - pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA; } else { pdev->view_max.x = 352; pdev->view_max.y = 288; - pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF; } + pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA; + pdev->abs_max.x = 640; + pdev->abs_max.y = 480; pdev->vcinterface = 3; pdev->vendpoint = 4; pdev->frame_header_size = 0; @@ -99,24 +121,26 @@ void pwc_construct(struct pwc_device *pd if (pdev->decompressor != NULL) { pdev->view_max.x = 640; pdev->view_max.y = 480; - pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA; } else { - /* Tell CIF, even though SIF really is the maximum, but some tools really need CIF */ + /* We use CIF, not SIF since some tools really need CIF. So we cheat a bit. */ pdev->view_max.x = 352; pdev->view_max.y = 288; - pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF; } + pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA; + pdev->abs_max.x = 640; + pdev->abs_max.y = 480; pdev->vcinterface = 3; pdev->vendpoint = 5; pdev->frame_header_size = TOUCAM_HEADER_SIZE; pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE; break; } + pdev->vpalette = VIDEO_PALETTE_YUV420P; /* default */ pdev->view_min.size = pdev->view_min.x * pdev->view_min.y; pdev->view_max.size = pdev->view_max.x * pdev->view_max.y; - /* length of image, in YUV format */ - pdev->len_per_image = (pdev->view_max.size * 3) / 2; + /* length of image, in YUV format; always allocate enough memory. */ + pdev->len_per_image = (pdev->abs_max.x * pdev->abs_max.y * 3) / 2; } diff -puN drivers/usb/media/pwc-uncompress.c~bk-usb drivers/usb/media/pwc-uncompress.c --- 25/drivers/usb/media/pwc-uncompress.c~bk-usb 2004-06-28 20:21:13.873804872 -0700 +++ 25-akpm/drivers/usb/media/pwc-uncompress.c 2004-06-28 20:21:15.319585080 -0700 @@ -1,4 +1,4 @@ -/* Linux driver for Philips webcam +/* Linux driver for Philips webcam Decompression frontend. (C) 1999-2003 Nemosoft Unv. (webcam@smcc.demon.nl) @@ -21,7 +21,9 @@ themselves. It also has a decompressor wrapper function. */ +#include #include +// #include #include "pwc.h" #include "pwc-uncompress.h" @@ -81,7 +83,6 @@ int pwc_decompress(struct pwc_device *pd u16 *src; u16 *dsty, *dstu, *dstv; - if (pdev == NULL) return -EFAULT; #if defined(__KERNEL__) && defined(PWC_MAGIC) @@ -97,16 +98,24 @@ int pwc_decompress(struct pwc_device *pd image = pdev->image_ptr[pdev->fill_image]; if (!image) return -EFAULT; - + yuv = fbuf->data + pdev->frame_header_size; /* Skip header */ - if (pdev->vbandlength == 0) { + + /* Raw format; that's easy... */ + if (pdev->vpalette == VIDEO_PALETTE_RAW) + { + memcpy(image, yuv, pdev->frame_size); + return 0; + } + + if (pdev->vbandlength == 0) { /* Uncompressed mode. We copy the data into the output buffer, using the viewport size (which may be larger than the image size). Unfortunately we have to do a bit of byte stuffing to get the desired output format/size. */ - /* - * We do some byte shuffling here to go from the + /* + * We do some byte shuffling here to go from the * native format to YUV420P. */ src = (u16 *)yuv; @@ -140,15 +149,21 @@ int pwc_decompress(struct pwc_device *pd dstu += (stride >> 1); } } - else { - /* Compressed; the decompressor routines will write the data + else { + /* Compressed; the decompressor routines will write the data in planar format immediately. */ + int flags; + + flags = PWCX_FLAG_PLANAR; + if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot) + flags |= PWCX_FLAG_BAYER; + if (pdev->decompressor) pdev->decompressor->decompress( &pdev->image, &pdev->view, &pdev->offset, yuv, image, - 1, + flags, pdev->decompress_data, pdev->vbandlength); else return -ENXIO; /* No such device or address: missing decompressor */ diff -puN drivers/usb/media/pwc-uncompress.h~bk-usb drivers/usb/media/pwc-uncompress.h --- 25/drivers/usb/media/pwc-uncompress.h~bk-usb 2004-06-28 20:21:13.875804568 -0700 +++ 25-akpm/drivers/usb/media/pwc-uncompress.h 2004-06-28 20:21:15.320584928 -0700 @@ -24,9 +24,15 @@ #define PWC_UNCOMPRESS_H #include +#include #include -#include "pwc.h" +#include "pwc-ioctl.h" + +/* from pwc-dec.h */ +#define PWCX_FLAG_PLANAR 0x0001 +/* */ + #ifdef __cplusplus extern "C" { @@ -42,10 +48,10 @@ struct pwc_decompressor int type; /* type of camera (645, 680, etc) */ int table_size; /* memory needed */ - void (* init)(int release, void *buffer, void *table); /* Initialization routine; should be called after each set_video_mode */ - void (* exit)(void); /* Cleanup routine */ - void (* decompress)(struct pwc_coord *image, struct pwc_coord *view, struct pwc_coord *offset, - void *src, void *dst, int planar, + asmlinkage void (* init)(int type, int release, void *buffer, void *table); /* Initialization routine; should be called after each set_video_mode */ + asmlinkage void (* exit)(void); /* Cleanup routine */ + asmlinkage void (* decompress)(struct pwc_coord *image, struct pwc_coord *view, struct pwc_coord *offset, + void *src, void *dst, int flags, void *table, int bandlength); void (* lock)(void); /* make sure module cannot be unloaded */ void (* unlock)(void); /* release lock on module */ diff -puN drivers/usb/net/kaweth.c~bk-usb drivers/usb/net/kaweth.c --- 25/drivers/usb/net/kaweth.c~bk-usb 2004-06-28 20:21:13.876804416 -0700 +++ 25-akpm/drivers/usb/net/kaweth.c 2004-06-28 20:21:15.322584624 -0700 @@ -62,7 +62,7 @@ #include #include -#define DEBUG +#undef DEBUG #ifdef DEBUG #define kaweth_dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" ,##arg) @@ -592,7 +592,7 @@ static void kaweth_usb_receive(struct ur struct sk_buff *skb; - if(unlikely(urb->status == -ECONNRESET || urb->status == -ECONNABORTED)) + if(unlikely(urb->status == -ECONNRESET || urb->status == -ECONNABORTED || urb->status == -ESHUTDOWN)) /* we are killed - set a flag and wake the disconnect handler */ { kaweth->end = 1; diff -puN drivers/usb/serial/pl2303.c~bk-usb drivers/usb/serial/pl2303.c --- 25/drivers/usb/serial/pl2303.c~bk-usb 2004-06-28 20:21:13.878804112 -0700 +++ 25-akpm/drivers/usb/serial/pl2303.c 2004-06-28 20:21:15.323584472 -0700 @@ -62,7 +62,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.10" +#define DRIVER_VERSION "v0.11" #define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver" @@ -172,20 +172,38 @@ static struct usb_serial_device_type pl2 .shutdown = pl2303_shutdown, }; +enum pl2303_type { + type_0, /* don't know the difference between type 0 and */ + type_1, /* type 1, until someone from prolific tells us... */ + HX, /* HX version of the pl2303 chip */ +}; + struct pl2303_private { spinlock_t lock; wait_queue_head_t delta_msr_wait; u8 line_control; u8 line_status; u8 termios_initialized; + enum pl2303_type type; }; static int pl2303_startup (struct usb_serial *serial) { struct pl2303_private *priv; + enum pl2303_type type = type_0; int i; + if (serial->dev->descriptor.bDeviceClass == 0x02) + type = type_0; + else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40) + type = HX; + else if (serial->dev->descriptor.bDeviceClass == 0x00) + type = type_1; + else if (serial->dev->descriptor.bDeviceClass == 0xFF) + type = type_1; + dbg("device type: %d", type); + for (i = 0; i < serial->num_ports; ++i) { priv = kmalloc (sizeof (struct pl2303_private), GFP_KERNEL); if (!priv) @@ -193,6 +211,7 @@ static int pl2303_startup (struct usb_se memset (priv, 0x00, sizeof (struct pl2303_private)); spin_lock_init(&priv->lock); init_waitqueue_head(&priv->delta_msr_wait); + priv->type = type; usb_set_serial_port_data(serial->port[i], priv); } return 0; @@ -395,20 +414,27 @@ static void pl2303_set_termios (struct u buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); if (cflag & CRTSCTS) { - i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), - VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE, - 0x0, 0x41, NULL, 0, 100); - dbg ("0x40:0x1:0x0:0x41 %d", i); + __u16 index; + if (priv->type == HX) + index = 0x61; + else + index = 0x41; + i = usb_control_msg(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + VENDOR_WRITE_REQUEST, + VENDOR_WRITE_REQUEST_TYPE, + 0x0, index, NULL, 0, 100); + dbg ("0x40:0x1:0x0:0x%x %d", index, i); } kfree (buf); -} - +} static int pl2303_open (struct usb_serial_port *port, struct file *filp) { struct termios tmp_termios; struct usb_serial *serial = port->serial; + struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned char *buf; int result; @@ -439,6 +465,18 @@ static int pl2303_open (struct usb_seria SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0x0404, 1); FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8484, 0); FISH (VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, 0x8383, 0); + SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 0, 1); + SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 1, 0); + + if (priv->type == HX) { + /* HX chip */ + SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x44); + /* reset upstream data pipes */ + SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 8, 0); + SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 9, 0); + } else { + SOUP (VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, 2, 0x24); + } kfree(buf); diff -puN drivers/usb/storage/transport.c~bk-usb drivers/usb/storage/transport.c --- 25/drivers/usb/storage/transport.c~bk-usb 2004-06-28 20:21:13.879803960 -0700 +++ 25-akpm/drivers/usb/storage/transport.c 2004-06-28 20:21:15.324584320 -0700 @@ -708,6 +708,12 @@ void usb_stor_invoke_transport(Scsi_Cmnd srb->sense_buffer[0] = 0x0; } } + + /* Did we transfer less than the minimum amount required? */ + if (srb->result == SAM_STAT_GOOD && + srb->request_bufflen - srb->resid < srb->underflow) + srb->result = (DID_ERROR << 16) | (SUGGEST_RETRY << 24); + return; /* abort processing: the bulk-only transport requires a reset diff -puN fs/aio.c~bk-usb fs/aio.c --- 25/fs/aio.c~bk-usb 2004-06-28 20:21:13.882803504 -0700 +++ 25-akpm/fs/aio.c 2004-06-28 20:21:15.325584168 -0700 @@ -624,6 +624,7 @@ void fastcall kick_iocb(struct kiocb *io queue_work(aio_wq, &ctx->wq); } } +EXPORT_SYMBOL(kick_iocb); /* aio_complete * Called when the io request on the given iocb is complete. _