/* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus framesontheUSBwireafteranexposurechange.Thiscondititionis howeverdetectedinthecamandabitissetintheheader.
*/ if (pdev->type == 730) { unsignedchar *ptr = (unsignedchar *)fbuf->data;
if (ptr[1] == 1 && ptr[0] & 0x10) {
PWC_TRACE("Hyundai CMOS sensor bug. Dropping frame.\n");
pdev->drop_frames += 2;
} if ((ptr[0] ^ pdev->vmirror) & 0x01) {
pwc_snapshot_button(pdev, ptr[0] & 0x01);
} if ((ptr[0] ^ pdev->vmirror) & 0x02) { if (ptr[0] & 0x02)
PWC_TRACE("Image is mirrored.\n"); else
PWC_TRACE("Image is normal.\n");
}
pdev->vmirror = ptr[0] & 0x03; /* Sometimes the trailer of the 730 is still sent as a 4 byte packet afterashortframe;thisconditionisfilteredoutspecifically.A4byte framedoesn'tmakesenseanyway. Sowegeteitherthissequence: drop_bitset->4byteframe->shortframe->goodframe Orthisone: drop_bitset->shortframe->goodframe Sowedropeither3or2framesinall!
*/ if (fbuf->filled == 4)
pdev->drop_frames++;
} elseif (pdev->type == 740 || pdev->type == 720) { unsignedchar *ptr = (unsignedchar *)fbuf->data; if ((ptr[0] ^ pdev->vmirror) & 0x01) {
pwc_snapshot_button(pdev, ptr[0] & 0x01);
}
pdev->vmirror = ptr[0] & 0x03;
}
/* In case we were instructed to drop the frame, do so silently. */ if (pdev->drop_frames > 0) {
pdev->drop_frames--;
} else { /* Check for underflow first */ if (fbuf->filled < pdev->frame_total_size) {
PWC_DEBUG_FLOW("Frame buffer underflow (%d bytes); discarded.\n",
fbuf->filled);
} else {
fbuf->vb.field = V4L2_FIELD_NONE;
fbuf->vb.sequence = pdev->vframe_count;
vb2_buffer_done(&fbuf->vb.vb2_buf, VB2_BUF_STATE_DONE);
pdev->fill_buf = NULL;
pdev->vsync = 0;
}
} /* !drop_frames */
pdev->vframe_count++;
}
/* This gets called for the Isochronous pipe (video). This is done in *interrupttime,soithastobefast,notcrash,andnotstall.Neat.
*/ staticvoid pwc_isoc_handler(struct urb *urb)
{ struct pwc_device *pdev = (struct pwc_device *)urb->context; struct device *dmadev = urb->dev->bus->sysdev; int i, fst, flen; unsignedchar *iso_buf = NULL;
if (pdev->fill_buf == NULL)
pdev->fill_buf = pwc_get_next_fill_buf(pdev);
if (urb->status != 0) { constchar *errmsg;
errmsg = "Unknown"; switch(urb->status) { case -ENOSR: errmsg = "Buffer error (overrun)"; 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 (could be anything)"; break; case -ETIME: errmsg = "Device does not respond"; break;
}
PWC_ERROR("pwc_isoc_handler() called with status %d [%s].\n",
urb->status, errmsg); /* Give up after a number of contiguous errors */ if (++pdev->visoc_errors > MAX_ISOC_ERRORS)
{
PWC_ERROR("Too many ISOC errors, bailing out.\n"); if (pdev->fill_buf) {
vb2_buffer_done(&pdev->fill_buf->vb.vb2_buf,
VB2_BUF_STATE_ERROR);
pdev->fill_buf = NULL;
}
}
pdev->vsync = 0; /* Drop the current frame */ goto handler_end;
}
/* Reset ISOC error counter. We did get here, after all. */
pdev->visoc_errors = 0;
i = usb_submit_urb(urb, GFP_ATOMIC); if (i != 0)
PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
}
/* Both v4l2_lock and vb_queue_lock should be locked when calling this */ staticint pwc_isoc_init(struct pwc_device *pdev)
{ struct usb_device *udev; struct urb *urb; int i, j, ret; struct usb_interface *intf; struct usb_host_interface *idesc = NULL; int compression = 0; /* 0..3 = uncompressed..high */
retry: /* We first try with low compression and then retry with a higher
compression setting if there is not enough bandwidth. */
ret = pwc_set_video_mode(pdev, pdev->width, pdev->height, pdev->pixfmt,
pdev->vframes, &compression, 1);
/* Get the current alternate interface, adjust packet size */
intf = usb_ifnum_to_if(udev, 0); if (intf)
idesc = usb_altnum_to_altsetting(intf, pdev->valternate); if (!idesc) return -EIO;
/* Search video endpoint */
pdev->vmax_packet_size = -1; for (i = 0; i < idesc->desc.bNumEndpoints; i++) { if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) {
pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize); break;
}
}
if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) {
PWC_ERROR("Failed to find packet size for video endpoint in current alternate setting.\n"); return -ENFILE; /* Odd error, that should be noticeable */
}
/* Set alternate interface */
PWC_DEBUG_OPEN("Setting alternate interface %d\n", pdev->valternate);
ret = usb_set_interface(pdev->udev, 0, pdev->valternate); if (ret == -ENOSPC && compression < 3) {
compression++; goto retry;
} if (ret < 0) return ret;
/* Allocate and init Isochronuous urbs */ for (i = 0; i < MAX_ISO_BUFS; i++) {
urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); if (urb == NULL) {
pwc_isoc_cleanup(pdev); return -ENOMEM;
}
pdev->urbs[i] = urb;
PWC_DEBUG_MEMORY("Allocated URB at 0x%p\n", urb);
/* link */ for (i = 0; i < MAX_ISO_BUFS; i++) {
ret = usb_submit_urb(pdev->urbs[i], GFP_KERNEL); if (ret == -ENOSPC && compression < 3) {
compression++;
pwc_isoc_cleanup(pdev); goto retry;
} if (ret) {
PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret);
pwc_isoc_cleanup(pdev); return ret;
}
PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->urbs[i]);
}
/* All is done... */
PWC_DEBUG_OPEN("<< pwc_isoc_init()\n"); return0;
}
staticvoid pwc_iso_stop(struct pwc_device *pdev)
{ int i;
/* Unlinking ISOC buffers one by one */ for (i = 0; i < MAX_ISO_BUFS; i++) { if (pdev->urbs[i]) {
PWC_DEBUG_MEMORY("Unlinking URB %p\n", pdev->urbs[i]);
usb_kill_urb(pdev->urbs[i]);
}
}
}
staticvoid pwc_iso_free(struct pwc_device *pdev)
{ int i;
/* Freeing ISOC buffers one by one */ for (i = 0; i < MAX_ISO_BUFS; i++) { struct urb *urb = pdev->urbs[i];
if (urb) {
PWC_DEBUG_MEMORY("Freeing URB\n"); if (urb->transfer_buffer)
pwc_free_urb_buffer(urb->dev,
urb->transfer_buffer_length,
urb->transfer_buffer,
urb->transfer_dma);
usb_free_urb(urb);
pdev->urbs[i] = NULL;
}
}
}
/* Both v4l2_lock and vb_queue_lock should be locked when calling this */ staticvoid pwc_isoc_cleanup(struct pwc_device *pdev)
{
PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");
/* Must be called with vb_queue_lock hold */ staticvoid pwc_cleanup_queued_bufs(struct pwc_device *pdev, enum vb2_buffer_state state)
{ unsignedlong flags = 0;
spin_lock_irqsave(&pdev->queued_bufs_lock, flags); while (!list_empty(&pdev->queued_bufs)) { struct pwc_frame_buf *buf;
if (mutex_lock_interruptible(&pdev->v4l2_lock)) return -ERESTARTSYS; /* Turn on camera and set LEDS on */
pwc_camera_power(pdev, 1);
pwc_set_leds(pdev, leds[0], leds[1]);
r = pwc_isoc_init(pdev); if (r) { /* If we failed turn camera and LEDS back off */
pwc_set_leds(pdev, 0, 0);
pwc_camera_power(pdev, 0); /* And cleanup any queued bufs!! */
pwc_cleanup_queued_bufs(pdev, VB2_BUF_STATE_QUEUED);
}
mutex_unlock(&pdev->v4l2_lock);
/* Check if we can handle this device */
PWC_DEBUG_PROBE("probe() called [%04X %04X], if %d\n",
vendor_id, product_id,
intf->altsetting->desc.bInterfaceNumber);
/* the interfaces are probed one by one. We are only interested in the videointerface(0)now. Interface1istheAudioControl,andinterface2Audioitself.
*/ if (intf->altsetting->desc.bInterfaceNumber > 0) return -ENODEV;
if (vendor_id == 0x0471) { switch (product_id) { case0x0302:
PWC_INFO("Philips PCA645VC USB webcam detected.\n");
name = "Philips 645 webcam";
type_id = 645; break; case0x0303:
PWC_INFO("Philips PCA646VC USB webcam detected.\n");
name = "Philips 646 webcam";
type_id = 646; break; case0x0304:
PWC_INFO("Askey VC010 type 2 USB webcam detected.\n");
name = "Askey VC010 webcam";
type_id = 646; break; case0x0307:
PWC_INFO("Philips PCVC675K (Vesta) USB webcam detected.\n");
name = "Philips 675 webcam";
type_id = 675; break; case0x0308:
PWC_INFO("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
name = "Philips 680 webcam";
type_id = 680; break; case0x030C:
PWC_INFO("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
name = "Philips 690 webcam";
type_id = 690; break; case0x0310:
PWC_INFO("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");
name = "Philips 730 webcam";
type_id = 730; break; case0x0311:
PWC_INFO("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");
name = "Philips 740 webcam";
type_id = 740; break; case0x0312:
PWC_INFO("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
name = "Philips 750 webcam";
type_id = 750; break; case0x0313:
PWC_INFO("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
name = "Philips 720K/40 webcam";
type_id = 720; break; case0x0329:
PWC_INFO("Philips SPC 900NC USB webcam detected.\n");
name = "Philips SPC 900NC webcam";
type_id = 740; break; case0x032C:
PWC_INFO("Philips SPC 880NC USB webcam detected.\n");
name = "Philips SPC 880NC webcam";
type_id = 740; break; default: return -ENODEV;
}
} elseif (vendor_id == 0x069A) { switch(product_id) { case0x0001:
PWC_INFO("Askey VC010 type 1 USB webcam detected.\n");
name = "Askey VC010 webcam";
type_id = 645; break; default: return -ENODEV;
}
} elseif (vendor_id == 0x046d) { switch(product_id) { case0x08b0:
PWC_INFO("Logitech QuickCam Pro 3000 USB webcam detected.\n");
name = "Logitech QuickCam Pro 3000";
type_id = 740; /* CCD sensor */ break; case0x08b1:
PWC_INFO("Logitech QuickCam Notebook Pro USB webcam detected.\n");
name = "Logitech QuickCam Notebook Pro";
type_id = 740; /* CCD sensor */ break; case0x08b2:
PWC_INFO("Logitech QuickCam 4000 Pro USB webcam detected.\n");
name = "Logitech QuickCam Pro 4000";
type_id = 740; /* CCD sensor */ if (my_power_save == -1)
my_power_save = 1; break; case0x08b3:
PWC_INFO("Logitech QuickCam Zoom USB webcam detected.\n");
name = "Logitech QuickCam Zoom";
type_id = 740; /* CCD sensor */ break; case0x08B4:
PWC_INFO("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
name = "Logitech QuickCam Zoom";
type_id = 740; /* CCD sensor */ if (my_power_save == -1)
my_power_save = 1; break; case0x08b5:
PWC_INFO("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
name = "Logitech QuickCam Orbit";
type_id = 740; /* CCD sensor */ if (my_power_save == -1)
my_power_save = 1;
features |= FEATURE_MOTOR_PANTILT; break; case0x08b6:
PWC_INFO("Logitech/Cisco VT Camera webcam detected.\n");
name = "Cisco VT Camera";
type_id = 740; /* CCD sensor */ break; case0x08b7:
PWC_INFO("Logitech ViewPort AV 100 webcam detected.\n");
name = "Logitech ViewPort AV 100";
type_id = 740; /* CCD sensor */ break; case0x08b8: /* Where this released? */
PWC_INFO("Logitech QuickCam detected (reserved ID).\n");
name = "Logitech QuickCam (res.)";
type_id = 730; /* Assuming CMOS */ break; default: return -ENODEV;
}
} elseif (vendor_id == 0x055d) { /* I don't know the difference between the C10 and the C30; Isupposethedifferenceisthesensor,butbothcameras workequallywellwithatype_idof675
*/ switch(product_id) { case0x9000:
PWC_INFO("Samsung MPC-C10 USB webcam detected.\n");
name = "Samsung MPC-C10";
type_id = 675; break; case0x9001:
PWC_INFO("Samsung MPC-C30 USB webcam detected.\n");
name = "Samsung MPC-C30";
type_id = 675; break; case0x9002:
PWC_INFO("Samsung SNC-35E (v3.0) USB webcam detected.\n");
name = "Samsung MPC-C30";
type_id = 740; break; default: return -ENODEV;
}
} elseif (vendor_id == 0x041e) { switch(product_id) { case0x400c:
PWC_INFO("Creative Labs Webcam 5 detected.\n");
name = "Creative Labs Webcam 5";
type_id = 730; if (my_power_save == -1)
my_power_save = 1; break; case0x4011:
PWC_INFO("Creative Labs Webcam Pro Ex detected.\n");
name = "Creative Labs Webcam Pro Ex";
type_id = 740; break; default: return -ENODEV;
}
} elseif (vendor_id == 0x04cc) { switch(product_id) { case0x8116:
PWC_INFO("Sotec Afina Eye USB webcam detected.\n");
name = "Sotec Afina Eye";
type_id = 730; break; default: return -ENODEV;
}
} elseif (vendor_id == 0x06be) { switch(product_id) { case0x8116: /* This is essentially the same cam as the Sotec Afina Eye */
PWC_INFO("AME Co. Afina Eye USB webcam detected.\n");
name = "AME Co. Afina Eye";
type_id = 750; break; default: return -ENODEV;
}
} elseif (vendor_id == 0x0d81) { switch(product_id) { case0x1900:
PWC_INFO("Visionite VCS-UC300 USB webcam detected.\n");
name = "Visionite VCS-UC300";
type_id = 740; /* CCD sensor */ break; case0x1910:
PWC_INFO("Visionite VCS-UM100 USB webcam detected.\n");
name = "Visionite VCS-UM100";
type_id = 730; /* CMOS sensor */ break; default: return -ENODEV;
}
} else return -ENODEV; /* Not any of the know types; but the list keeps growing. */
if (my_power_save == -1)
my_power_save = 0;
memset(serial_number, 0, 30);
usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
PWC_DEBUG_PROBE("Device serial number is %s\n", serial_number);
if (udev->descriptor.bNumConfigurations > 1)
PWC_WARNING("Warning: more than 1 configuration available.\n");
/* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */
pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL); if (pdev == NULL) {
PWC_ERROR("Oops, could not allocate memory for pwc_device.\n"); return -ENOMEM;
}
pdev->type = type_id;
pdev->features = features;
pwc_construct(pdev); /* set min/max sizes correct */
/* Allocate USB command buffers */
pdev->ctrl_buf = kmalloc(sizeof(pdev->cmd_buf), GFP_KERNEL); if (!pdev->ctrl_buf) {
PWC_ERROR("Oops, could not allocate memory for pwc_device.\n");
rc = -ENOMEM; goto err_free_mem;
}
#ifdef CONFIG_USB_PWC_DEBUG /* Query sensor type */ if (pwc_get_cmos_sensor(pdev, &rc) >= 0) {
PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n",
pdev->vdev.name,
pwc_sensor_type_to_string(rc), rc);
} #endif
rc = video_register_device(&pdev->vdev, VFL_TYPE_VIDEO, -1); if (rc < 0) {
PWC_ERROR("Failed to register as video device (%d).\n", rc); goto err_unregister_v4l2_dev;
}
PWC_INFO("Registered as %s.\n", video_device_node_name(&pdev->vdev));
/* The user yanked out the cable... */ staticvoid usb_pwc_disconnect(struct usb_interface *intf)
{ struct v4l2_device *v = usb_get_intfdata(intf); struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev);
mutex_lock(&pdev->vb_queue_lock);
mutex_lock(&pdev->v4l2_lock); /* No need to keep the urbs around after disconnection */ if (pdev->vb_queue.streaming)
pwc_isoc_cleanup(pdev);
pdev->udev = NULL;
#ifdef CONFIG_USB_PWC_DEBUG
MODULE_PARM_DESC(trace, "For debugging purposes"); #endif
MODULE_PARM_DESC(power_save, "Turn power saving for new cameras on or off");
MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.