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

Reply via email to