📄 pwc-if.c
字号:
type_id = 740; /* CCD sensor */ break; case 0x08b5: Info("Logitech QuickCam Orbit/Sphere USB webcam detected.\n"); name = "Logitech QuickCam Orbit"; type_id = 740; /* CCD sensor */ features |= FEATURE_MOTOR_PANTILT; break; case 0x08b6: case 0x08b7: case 0x08b8: Info("Logitech QuickCam detected (reserved ID).\n"); name = "Logitech QuickCam (res.)"; type_id = 730; /* Assuming CMOS */ break; default: return -ENODEV; break; } } else if (vendor_id == 0x055d) { /* I don't know the difference between the C10 and the C30; I suppose the difference is the sensor, but both cameras work equally well with a type_id of 675 */ switch(product_id) { case 0x9000: Info("Samsung MPC-C10 USB webcam detected.\n"); name = "Samsung MPC-C10"; type_id = 675; break; case 0x9001: Info("Samsung MPC-C30 USB webcam detected.\n"); name = "Samsung MPC-C30"; type_id = 675; break; default: return -ENODEV; break; } } else if (vendor_id == 0x041e) { switch(product_id) { case 0x400c: Info("Creative Labs Webcam 5 detected.\n"); name = "Creative Labs Webcam 5"; type_id = 730; break; case 0x4011: Info("Creative Labs Webcam Pro Ex detected.\n"); name = "Creative Labs Webcam Pro Ex"; type_id = 740; break; default: return -ENODEV; break; } } 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; 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) { case 0x1900: Info("Visionite VCS-UC300 USB webcam detected.\n"); name = "Visionite VCS-UC300"; type_id = 740; /* CCD sensor */ break; case 0x1910: Info("Visionite VCS-UM100 USB webcam detected.\n"); name = "Visionite VCS-UM100"; type_id = 730; /* CMOS sensor */ break; default: return -ENODEV; break; } } else return -ENODEV; /* Not any of the know types; but the list keeps growing. */ memset(serial_number, 0, 30); usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29); Trace(TRACE_PROBE, "Device serial number is %s\n", serial_number); if (udev->descriptor.bNumConfigurations > 1) Info("Warning: more than 1 configuration available.\n"); /* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */ pdev = kmalloc(sizeof(struct pwc_device), GFP_KERNEL); if (pdev == NULL) { Err("Oops, could not allocate memory for pwc_device.\n"); return -ENOMEM; } memset(pdev, 0, sizeof(struct pwc_device)); 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) { /* Logitech QuickCam Orbit The ranges have been determined experimentally; they may differ from cam to cam. Also, the exact ranges left-right and up-down are different for my cam */ pdev->angle_range.pan_min = -7000; pdev->angle_range.pan_max = 7000; pdev->angle_range.tilt_min = -3000; pdev->angle_range.tilt_max = 2500; } init_MUTEX(&pdev->modlock); pdev->ptrlock = SPIN_LOCK_UNLOCKED; pdev->udev = udev; init_waitqueue_head(&pdev->frameq); pdev->vcompression = pwc_preferred_compression; /* 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); /* 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; } } } 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); } /* occupy slot */ if (hint < MAX_DEV_HINTS) device_hint[hint].pdev = pdev; Trace(TRACE_PROBE, "probe() function returning struct at 0x%p.\n", pdev); usb_set_intfdata (intf, pdev); return 0;}/* The user janked out the cable... */static void usb_pwc_disconnect(struct usb_interface *intf){ struct pwc_device *pdev; int hint; lock_kernel(); pdev = usb_get_intfdata (intf); usb_set_intfdata (intf, NULL); if (pdev == NULL) { Err("pwc_disconnect() Called without private pointer.\n"); goto disconnect_out; } if (pdev->udev == NULL) { Err("pwc_disconnect() already called for %p\n", pdev); goto disconnect_out; } if (pdev->udev != interface_to_usbdev(intf)) { Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n"); goto disconnect_out; }#ifdef PWC_MAGIC if (pdev->magic != PWC_MAGIC) { Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n"); goto disconnect_out; }#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 */ while (pdev->vopen) 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); /* Free memory (don't set pdev to 0 just yet) */ kfree(pdev);disconnect_out: /* search device_hint[] table if we occupy a slot, by any chance */ for (hint = 0; hint < MAX_DEV_HINTS; hint++) if (device_hint[hint].pdev == pdev) device_hint[hint].pdev = NULL; unlock_kernel();}/* *grunt* We have to do atoi ourselves :-( */static int pwc_atoi(const 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 */static char *size = NULL;static int fps = 0;static int fbufs = 0;static int mbufs = 0;static int trace = -1;static int compression = -1;static int leds[2] = { -1, -1 };static char *dev_hint[MAX_DEV_HINTS] = { };MODULE_PARM(size, "s");MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga");MODULE_PARM(fps, "i");MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30");MODULE_PARM(fbufs, "i");MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve");MODULE_PARM(mbufs, "i");MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers");MODULE_PARM(trace, "i");MODULE_PARM_DESC(trace, "For debugging purposes");MODULE_PARM(power_save, "i");MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off");MODULE_PARM(compression, "i");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-20s");MODULE_PARM_DESC(dev_hint, "Device node hints");MODULE_DESCRIPTION("Philips & OEM USB webcam driver");MODULE_AUTHOR("Nemosoft Unv. <webcam@smcc.demon.nl>");MODULE_LICENSE("GPL");static int __init usb_pwc_init(void){ int i, sz; char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" }; 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) { Err("Framerate out of bounds (4-30).\n"); return -EINVAL; } 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++) { if (!strcmp(sizenames[sz], size)) { /* Found! */ default_size = sz; break; } } if (sz == PSZ_MAX) { Err("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n"); return -EINVAL; } Info("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y); } if (mbufs) { if (mbufs < 1 || mbufs > MAX_IMAGES) { Err("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES); return -EINVAL; } default_mbufs = mbufs; Info("Number of image buffers set to %d.\n", default_mbufs); } if (fbufs) { if (fbufs < 2 || fbufs > MAX_FRAMES) { Err("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES); return -EINVAL; } default_fbufs = fbufs; Info("Number of frame buffers set to %d.\n", default_fbufs); } if (trace >= 0) { Info("Trace options: 0x%04x\n", trace); pwc_trace = trace; } if (compression >= 0) { if (compression > 3) { Err("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n"); return -EINVAL; } pwc_preferred_compression = compression; Info("Preferred compression set to %d.\n", pwc_preferred_compression); } if (power_save) Info("Enabling power save on open/close.\n"); if (leds[0] >= 0) led_on = leds[0]; if (leds[1] >= 0) led_off = leds[1]; /* Big device node whoopla. Basicly, it allows you to assign a device node (/dev/videoX) to a camera, based on its type & 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'; } }#if PWC_DEBUG Debug("device_hint[%d]:\n", i); Debug(" type : %d\n", device_hint[i].type); Debug(" serial# : %s\n", device_hint[i].serial_number); Debug(" node : %d\n", device_hint[i].device_node);#endif } else device_hint[i].type = 0; /* not filled */ } /* ..for MAX_DEV_HINTS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -