Hi, Here's a patch against 2.4.17-pre1 from Nemosoft that updates the USB pwc driver to the latest version.
thanks, greg k-h diff -Nru a/Documentation/usb/philips.txt b/Documentation/usb/philips.txt --- a/Documentation/usb/philips.txt Thu Nov 29 22:23:47 2001 +++ b/Documentation/usb/philips.txt Thu Nov 29 22:23:47 2001 @@ -1,5 +1,5 @@ This file contains some additional information for the Philips webcams. -E-mail: [EMAIL PROTECTED] Last updated: 2001-07-27 +E-mail: [EMAIL PROTECTED] 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 @@ -13,11 +13,9 @@ the latter, since it makes troubleshooting a lot easier. The built-in microphone is supported through the USB Audio class. -(Taken from install.html) - When you load the module you can set some default settings for the -camera; some programs depend on a particular image-size or -format. The -options are: +camera; some programs depend on a particular image-size or -format and +don't know how to set it properly in the driver. The options are: size Can be one of 'sqcif', 'qsif', 'qcif', 'sif', 'cif' or @@ -99,6 +97,57 @@ 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. + +dev_hint + A long standing problem with USB devices is their dynamic nature: you + never know what device a camera gets assigned; it depends on module load + order, the hub configuration, the order in which devices are plugged in, + and the phase of the moon (i.e. it can be random). With this option you + can give the driver a hint as to what video device node (/dev/videoX) it + should use with a specific camera. This is also handy if you have two + cameras of the same model. + + A camera is specified by its type (the number from the camera model, + like PCA645, PCVC750VC, etc) and optionally the serial number (visible + in /proc/bus/usb/devices). A hint consists of a string with the following + format: + + [type[.serialnumber]:]node + + The square brackets mean that both the type and the serialnumber are + optional, but a serialnumber cannot be specified without a type (which + would be rather pointless). The serialnumber is separated from the type + by a '.'; the node number by a ':'. + + This somewhat cryptic syntax is best explained by a few examples: + + dev_hint=3,5 The first detected cam gets assigned + /dev/video3, the second /dev/video5. Any + other cameras will get the first free + available slot (see below). + + 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 + 0123 goes to /dev/video3, the same + camera model with the 4567 serial + gets /dev/video0. + + dev_hint=750:1,4,5,6 The PCVC750 camera will get /dev/video1, the + next 3 Philips cams will use /dev/video4 + through /dev/video6. + + Some points worth knowing: + - Serialnumbers are case sensitive and must be written full, including + leading zeroes (it's treated as a string). + - If a device node is already occupied, registration will fail and + the webcam is not available. + - You can have up to 64 video devices; be sure to make enough device + nodes in /dev if you want to spread the numbers (this does not apply + to devfs). After /dev/video9 comes /dev/video10 (not /dev/videoA). + - If a camera does not match any dev_hint, it will simply get assigned + the first available device node, just as it used to be. trace In order to better detect problems, it is now possible to turn on a diff -Nru a/drivers/usb/pwc-ctrl.c b/drivers/usb/pwc-ctrl.c --- a/drivers/usb/pwc-ctrl.c Thu Nov 29 22:23:46 2001 +++ b/drivers/usb/pwc-ctrl.c Thu Nov 29 22:23:46 2001 @@ -782,7 +782,7 @@ { char buf; - if (pdev->type < 675 || pdev->release < 6) + if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6)) return 0; /* Not supported by Nala or Timon < release 6 */ if (power) diff -Nru a/drivers/usb/pwc-if.c b/drivers/usb/pwc-if.c --- a/drivers/usb/pwc-if.c Thu Nov 29 22:23:48 2001 +++ b/drivers/usb/pwc-if.c Thu Nov 29 22:23:48 2001 @@ -91,6 +91,8 @@ disconnect: usb_pwc_disconnect, /* disconnect() */ }; +#define MAX_DEV_HINTS 10 + static int default_size = PSZ_QCIF; static int default_fps = 10; static int default_palette = VIDEO_PALETTE_YUV420P; /* This format is understood by most tools */ @@ -99,13 +101,17 @@ int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX; static int power_save = 0; static int led_on = 1, led_off = 0; /* defaults to LED that is on while in use */ -int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */ + int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */ +static struct { + int type; + char serial_number[30]; + int device_node; + struct pwc_device *pdev; +} device_hint[MAX_DEV_HINTS]; static struct semaphore mem_lock; static void *mem_leak = NULL; /* For delayed kfree()s. See below */ -static int video_nr = -1; - /***/ static int pwc_video_open(struct video_device *vdev, int mode); @@ -647,7 +653,8 @@ errmsg = "Unknown"; switch(urb->status) { case -ENOSR: errmsg = "Buffer error (overrun)"; break; - case -EPIPE: errmsg = "Babble/stalled (bad cable?)"; break; + case -EPIPE: errmsg = "Stalled (device not +responding)"; break; + case -EOVERFLOW: errmsg = "Babble (bad cable?)"; break; case -EPROTO: errmsg = "Bit-stuff error (bad cable?)"; break; case -EILSEQ: errmsg = "CRC/Timeout"; break; case -ETIMEDOUT: errmsg = "NAK (device does not respond)"; break; @@ -765,6 +772,11 @@ } /* .. flen < last_packet_size */ pdev->vlast_packet_size = flen; } /* ..status == 0 */ +#ifdef PWC_DEBUG + /* This is normally not interesting to the user, unless you are really +debugging something */ + else + Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, +fst); +#endif } if (awake) wake_up_interruptible(&pdev->frameq); @@ -1140,7 +1152,7 @@ return -ERESTARTSYS; } schedule(); - set_current_state(TASK_INTERRUPTIBLE); + set_current_state(TASK_INTERRUPTIBLE); } remove_wait_queue(&pdev->frameq, &wait); set_current_state(TASK_RUNNING); @@ -1595,7 +1607,9 @@ struct pwc_device *pdev = NULL; struct video_device *vdev; int vendor_id, product_id, type_id; - int i; + int i, hint; + int video_nr = -1; /* default: use next available device */ + char serial_number[30]; free_mem_leak(); @@ -1698,6 +1712,10 @@ } else return NULL; /* Not Philips, Askey, Logitech or Samsung, for sure. */ + memset(serial_number, 0, 30); + usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29); + Trace(TRACE_PROBE, "Device serial number is %s\n", serial_number); + if (udev->descriptor.bNumConfigurations > 1) Info("Warning: more than 1 configuration available.\n"); @@ -1734,6 +1752,21 @@ pdev->release = udev->descriptor.bcdDevice; Trace(TRACE_PROBE, "Release: %04x\n", pdev->release); + + /* Now search device_hint[] table for a match, so we can hint a node number. */ + for (hint = 0; hint < MAX_DEV_HINTS; hint++) { + if (((device_hint[hint].type == -1) || (device_hint[hint].type == +pdev->type)) && + (device_hint[hint].pdev == NULL)) { + /* so far, so good... try serial number */ + if ((device_hint[hint].serial_number[0] == '*') || +!strcmp(device_hint[hint].serial_number, serial_number)) { + /* match! */ + video_nr = device_hint[hint].device_node; + Trace(TRACE_PROBE, "Found hint, will try to register +as /dev/video%d\n", video_nr); + break; + } + } + } + i = video_register_device(vdev, VFL_TYPE_GRABBER, video_nr); if (i < 0) { Err("Failed to register as video device (%d).\n", i); @@ -1743,6 +1776,9 @@ Trace(TRACE_PROBE, "Registered video struct at 0x%p.\n", vdev); Info("Registered as /dev/video%d.\n", vdev->minor & 0x3F); } + /* occupy slot */ + if (hint < MAX_DEV_HINTS) + device_hint[hint].pdev = pdev; #if 0 /* Shut down camera now (some people like the LED off) */ @@ -1762,6 +1798,7 @@ static void usb_pwc_disconnect(struct usb_device *udev, void *ptr) { struct pwc_device *pdev; + int hint; lock_kernel(); free_mem_leak(); @@ -1815,12 +1852,31 @@ pdev->vdev = NULL; } } + + /* search device_hint[] table if we occupy a slot, by any chance */ + for (hint = 0; hint < MAX_DEV_HINTS; hint++) + if (device_hint[hint].pdev == pdev) + device_hint[hint].pdev = NULL; + pdev->udev = NULL; unlock_kernel(); kfree(pdev); } +/* *grunt* We have to do atoi ourselves :-( */ +static int pwc_atoi(char *s) +{ + int k = 0; + + k = 0; + while (*s != '\0' && *s >= '0' && *s <= '9') { + k = 10 * k + (*s - '0'); + s++; + } + return k; +} + /* * Initialization code & module stuff @@ -1833,8 +1889,8 @@ static int trace = -1; static int compression = -1; static int leds[2] = { -1, -1 }; +static char *dev_hint[10] = { }; -MODULE_PARM(video_nr, "i"); MODULE_PARM(size, "s"); MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga"); MODULE_PARM(fps, "i"); @@ -1851,13 +1907,16 @@ MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)"); MODULE_PARM(leds, "2i"); MODULE_PARM_DESC(leds, "LED on,off time in milliseconds"); +MODULE_PARM(dev_hint, "0-10s"); +MODULE_PARM_DESC(dev_hint, "Device node hints"); + MODULE_DESCRIPTION("Philips USB webcam driver"); MODULE_AUTHOR("Nemosoft Unv. <[EMAIL PROTECTED]>"); MODULE_LICENSE("GPL"); static int __init usb_pwc_init(void) { - int s; + 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"); @@ -1874,13 +1933,13 @@ if (size) { /* string; try matching with array */ - for (s = 0; s < PSZ_MAX; s++) { - if (!strcmp(sizenames[s], size)) { /* Found! */ - default_size = s; + for (sz = 0; sz < PSZ_MAX; sz++) { + if (!strcmp(sizenames[sz], size)) { /* Found! */ + default_size = sz; break; } } - if (s == PSZ_MAX) { + if (sz == PSZ_MAX) { Err("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n"); return -EINVAL; } @@ -1920,6 +1979,74 @@ led_on = leds[0] / 100; if (leds[1] >= 0) led_off = leds[1] / 100; + + /* 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. + */ + for (i = 0; i < MAX_DEV_HINTS; i++) { + char *s, *colon, *dot; + + /* This loop also initializes the array */ + device_hint[i].pdev = NULL; + s = dev_hint[i]; + if (s != NULL && *s != '\0') { + device_hint[i].type = -1; /* wildcard */ + strcpy(device_hint[i].serial_number, "*"); + + /* parse string: chop at ':' & '/' */ + colon = dot = s; + while (*colon != '\0' && *colon != ':') + colon++; + while (*dot != '\0' && *dot != '.') + dot++; + /* Few sanity checks */ + if (*dot != '\0' && dot > colon) { + Err("Malformed camera hint: the colon must be after +the dot.\n"); + return -EINVAL; + } + + if (*colon == '\0') { + /* No colon */ + if (*dot != '\0') { + Err("Malformed camera hint: no colon + device +node given.\n"); + return -EINVAL; + } + else { + /* No type or serial number specified, just a +number. */ + device_hint[i].device_node = pwc_atoi(s); + } + } + else { + /* There's a colon, so we have at least a type and a +device node */ + device_hint[i].type = pwc_atoi(s); + device_hint[i].device_node = pwc_atoi(colon + 1); + if (*dot != '\0') { + /* There's a serial number as well */ + int k; + + dot++; + k = 0; + while (*dot != ':' && k < 29) { + device_hint[i].serial_number[k++] = +*dot; + dot++; + } + device_hint[i].serial_number[k] = '\0'; + } + } +#ifdef PWC_DEBUG + Debug("device_hint[%d]:\n", i); + Debug(" type : %d\n", device_hint[i].type); + Debug(" serial# : %s\n", device_hint[i].serial_number); + Debug(" node : %d\n", device_hint[i].device_node); +#endif + } + else + device_hint[i].type = 0; /* not filled */ + } /* ..for MAX_DEV_HINTS */ init_MUTEX(&mem_lock); Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver); diff -Nru a/drivers/usb/pwc.h b/drivers/usb/pwc.h --- a/drivers/usb/pwc.h Thu Nov 29 22:23:48 2001 +++ b/drivers/usb/pwc.h Thu Nov 29 22:23:48 2001 @@ -60,8 +60,8 @@ /* Version block */ #define PWC_MAJOR 8 -#define PWC_MINOR 3 -#define PWC_VERSION "8.3" +#define PWC_MINOR 4 +#define PWC_VERSION "8.4" #define PWC_NAME "pwc" /* Turn certain features on/off */ _______________________________________________ [EMAIL PROTECTED] To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel