X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmedia%2Fvideo%2Fpwc%2Fpwc-if.c;h=41418294a32bc96440de0180e393c5fdf1c9a48b;hb=9464c7cf61b9433057924c36e6e02f303a00e768;hp=d4703944df9c12c39bb719b311da043da60cb1d9;hpb=41689045f6a3cbe0550e1d34e9cc20d2e8c432ba;p=linux-2.6.git diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index d4703944d..41418294a 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c @@ -1,7 +1,7 @@ /* Linux driver for Philips webcam USB and Video4Linux interface part. (C) 1999-2004 Nemosoft Unv. - (C) 2004-2006 Luc Saillard (luc@saillard.org) + (C) 2004 Luc Saillard (luc@saillard.org) NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx driver and thus may have bugs that are not present in the original version. @@ -62,21 +62,18 @@ #include #include #include -#include #include -#include #include "pwc.h" +#include "pwc-ioctl.h" #include "pwc-kiara.h" #include "pwc-timon.h" -#include "pwc-dec23.h" -#include "pwc-dec1.h" #include "pwc-uncompress.h" /* Function prototypes and driver templates */ /* hotplug device table support */ -static const struct usb_device_id pwc_device_table [] = { +static struct usb_device_id pwc_device_table [] = { { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */ { USB_DEVICE(0x0471, 0x0303) }, { USB_DEVICE(0x0471, 0x0304) }, @@ -84,10 +81,9 @@ static const struct usb_device_id pwc_device_table [] = { { USB_DEVICE(0x0471, 0x0308) }, { USB_DEVICE(0x0471, 0x030C) }, { USB_DEVICE(0x0471, 0x0310) }, - { USB_DEVICE(0x0471, 0x0311) }, /* Philips ToUcam PRO II */ + { USB_DEVICE(0x0471, 0x0311) }, { USB_DEVICE(0x0471, 0x0312) }, { USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */ - { USB_DEVICE(0x0471, 0x0329) }, /* Philips SPC 900NC PC Camera */ { USB_DEVICE(0x069A, 0x0001) }, /* Askey */ { USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */ { USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */ @@ -98,9 +94,8 @@ static const struct usb_device_id pwc_device_table [] = { { USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */ { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */ { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */ - { USB_DEVICE(0x055D, 0x9000) }, /* Samsung MPC-C10 */ - { USB_DEVICE(0x055D, 0x9001) }, /* Samsung MPC-C30 */ - { USB_DEVICE(0x055D, 0x9002) }, /* Samsung SNC-35E (Ver3.0) */ + { USB_DEVICE(0x055D, 0x9000) }, /* Samsung */ + { USB_DEVICE(0x055D, 0x9001) }, { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */ { USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */ { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */ @@ -127,13 +122,11 @@ static struct usb_driver pwc_driver = { static int default_size = PSZ_QCIF; static int default_fps = 10; static int default_fbufs = 3; /* Default number of frame buffers */ - int pwc_mbufs = 2; /* Default number of mmap() buffers */ -#if CONFIG_PWC_DEBUG - int pwc_trace = PWC_DEBUG_LEVEL; -#endif +static int default_mbufs = 2; /* Default number of mmap() buffers */ + int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX; static int power_save = 0; static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */ -static int pwc_preferred_compression = 1; /* 0..3 = uncompressed..high */ +static int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */ static struct { int type; char serial_number[30]; @@ -145,7 +138,7 @@ static struct { static int pwc_video_open(struct inode *inode, struct file *file); static int pwc_video_close(struct inode *inode, struct file *file); -static ssize_t pwc_video_read(struct file *file, char __user *buf, +static ssize_t pwc_video_read(struct file *file, char __user * buf, size_t count, loff_t *ppos); static unsigned int pwc_video_poll(struct file *file, poll_table *wait); static int pwc_video_ioctl(struct inode *inode, struct file *file, @@ -210,44 +203,52 @@ static struct video_device pwc_template = { /* Here we want the physical address of the memory. * This is used when initializing the contents of the area. */ +static inline unsigned long kvirt_to_pa(unsigned long adr) +{ + unsigned long kva, ret; + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ + ret = __pa(kva); + return ret; +} - -static void *pwc_rvmalloc(unsigned long size) +static void * rvmalloc(unsigned long size) { void * mem; unsigned long adr; + size=PAGE_ALIGN(size); mem=vmalloc_32(size); - if (!mem) - return NULL; - - memset(mem, 0, size); /* Clear the ram out, no junk to the user */ - adr=(unsigned long) mem; - while (size > 0) - { - SetPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } + if (mem) + { + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr=(unsigned long) mem; + while (size > 0) + { + SetPageReserved(vmalloc_to_page((void *)adr)); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + } return mem; } -static void pwc_rvfree(void * mem, unsigned long size) +static void rvfree(void * mem, unsigned long size) { unsigned long adr; - if (!mem) - return; - - adr=(unsigned long) mem; - while ((long) size > 0) - { - ClearPageReserved(vmalloc_to_page((void *)adr)); - adr += PAGE_SIZE; - size -= PAGE_SIZE; - } - vfree(mem); + if (mem) + { + adr=(unsigned long) mem; + while ((long) size > 0) + { + ClearPageReserved(vmalloc_to_page((void *)adr)); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + vfree(mem); + } } @@ -255,83 +256,100 @@ static void pwc_rvfree(void * mem, unsigned long size) static int pwc_allocate_buffers(struct pwc_device *pdev) { - int i, err; + int i; void *kbuf; - PWC_DEBUG_MEMORY(">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev); + Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev); if (pdev == NULL) return -ENXIO; - /* Allocate Isochronuous pipe buffers */ +#ifdef PWC_MAGIC + if (pdev->magic != PWC_MAGIC) { + Err("allocate_buffers(): magic failed.\n"); + return -ENXIO; + } +#endif + /* Allocate Isochronous pipe buffers */ for (i = 0; i < MAX_ISO_BUFS; i++) { if (pdev->sbuf[i].data == NULL) { - kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL); + kbuf = kmalloc(ISO_BUFFER_SIZE, GFP_KERNEL); if (kbuf == NULL) { - PWC_ERROR("Failed to allocate iso buffer %d.\n", i); + Err("Failed to allocate iso buffer %d.\n", i); return -ENOMEM; } - PWC_DEBUG_MEMORY("Allocated iso buffer at %p.\n", kbuf); + Trace(TRACE_MEMORY, "Allocated iso buffer at %p.\n", kbuf); pdev->sbuf[i].data = kbuf; + memset(kbuf, 0, ISO_BUFFER_SIZE); } } /* Allocate frame buffer structure */ if (pdev->fbuf == NULL) { - kbuf = kzalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL); + kbuf = kmalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL); if (kbuf == NULL) { - PWC_ERROR("Failed to allocate frame buffer structure.\n"); + Err("Failed to allocate frame buffer structure.\n"); return -ENOMEM; } - PWC_DEBUG_MEMORY("Allocated frame buffer structure at %p.\n", kbuf); + Trace(TRACE_MEMORY, "Allocated frame buffer structure at %p.\n", kbuf); pdev->fbuf = kbuf; + memset(kbuf, 0, default_fbufs * sizeof(struct pwc_frame_buf)); } - /* create frame buffers, and make circular ring */ for (i = 0; i < default_fbufs; i++) { if (pdev->fbuf[i].data == NULL) { kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */ if (kbuf == NULL) { - PWC_ERROR("Failed to allocate frame buffer %d.\n", i); + Err("Failed to allocate frame buffer %d.\n", i); return -ENOMEM; } - PWC_DEBUG_MEMORY("Allocated frame buffer %d at %p.\n", i, kbuf); + Trace(TRACE_MEMORY, "Allocated frame buffer %d at %p.\n", i, kbuf); pdev->fbuf[i].data = kbuf; - memset(kbuf, 0, PWC_FRAME_SIZE); + memset(kbuf, 128, PWC_FRAME_SIZE); } } /* Allocate decompressor table space */ - if (DEVICE_USE_CODEC1(pdev->type)) - err = pwc_dec1_alloc(pdev); - else - err = pwc_dec23_alloc(pdev); - - if (err) { - PWC_ERROR("Failed to allocate decompress table.\n"); - return err; - } + kbuf = NULL; + switch (pdev->type) + { + case 675: + case 680: + case 690: + case 720: + case 730: + case 740: + case 750: +#if 0 + Trace(TRACE_MEMORY,"private_data(%zu)\n",sizeof(struct pwc_dec23_private)); + kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); /* Timon & Kiara */ + break; + case 645: + case 646: + /* TODO & FIXME */ + kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); + break; +#endif + ; + } + pdev->decompress_data = kbuf; /* Allocate image buffer; double buffer for mmap() */ - kbuf = pwc_rvmalloc(pwc_mbufs * pdev->len_per_image); + kbuf = rvmalloc(default_mbufs * pdev->len_per_image); if (kbuf == NULL) { - PWC_ERROR("Failed to allocate image buffer(s). needed (%d)\n", - pwc_mbufs * pdev->len_per_image); + Err("Failed to allocate image buffer(s). needed (%d)\n",default_mbufs * pdev->len_per_image); return -ENOMEM; } - PWC_DEBUG_MEMORY("Allocated image buffer at %p.\n", kbuf); + Trace(TRACE_MEMORY, "Allocated image buffer at %p.\n", kbuf); pdev->image_data = kbuf; - for (i = 0; i < pwc_mbufs; i++) { - pdev->images[i].offset = i * pdev->len_per_image; - pdev->images[i].vma_use_count = 0; - } - for (; i < MAX_IMAGES; i++) { - pdev->images[i].offset = 0; - } + for (i = 0; i < default_mbufs; i++) + pdev->image_ptr[i] = kbuf + i * pdev->len_per_image; + for (; i < MAX_IMAGES; i++) + pdev->image_ptr[i] = NULL; kbuf = NULL; - PWC_DEBUG_MEMORY("<< pwc_allocate_buffers()\n"); + Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n"); return 0; } @@ -339,14 +357,21 @@ static void pwc_free_buffers(struct pwc_device *pdev) { int i; - PWC_DEBUG_MEMORY("Entering free_buffers(%p).\n", pdev); + Trace(TRACE_MEMORY, "Entering free_buffers(%p).\n", pdev); if (pdev == NULL) return; +#ifdef PWC_MAGIC + if (pdev->magic != PWC_MAGIC) { + Err("free_buffers(): magic failed.\n"); + return; + } +#endif + /* Release Iso-pipe buffers */ for (i = 0; i < MAX_ISO_BUFS; i++) if (pdev->sbuf[i].data != NULL) { - PWC_DEBUG_MEMORY("Freeing ISO buffer at %p.\n", pdev->sbuf[i].data); + Trace(TRACE_MEMORY, "Freeing ISO buffer at %p.\n", pdev->sbuf[i].data); kfree(pdev->sbuf[i].data); pdev->sbuf[i].data = NULL; } @@ -355,7 +380,7 @@ static void pwc_free_buffers(struct pwc_device *pdev) if (pdev->fbuf != NULL) { for (i = 0; i < default_fbufs; i++) { if (pdev->fbuf[i].data != NULL) { - PWC_DEBUG_MEMORY("Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data); + Trace(TRACE_MEMORY, "Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data); vfree(pdev->fbuf[i].data); pdev->fbuf[i].data = NULL; } @@ -366,19 +391,20 @@ static void pwc_free_buffers(struct pwc_device *pdev) /* Intermediate decompression buffer & tables */ if (pdev->decompress_data != NULL) { - PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n", pdev->decompress_data); + Trace(TRACE_MEMORY, "Freeing decompression buffer at %p.\n", pdev->decompress_data); kfree(pdev->decompress_data); pdev->decompress_data = NULL; } + pdev->decompressor = NULL; /* Release image buffers */ if (pdev->image_data != NULL) { - PWC_DEBUG_MEMORY("Freeing image buffer at %p.\n", pdev->image_data); - pwc_rvfree(pdev->image_data, pwc_mbufs * pdev->len_per_image); + Trace(TRACE_MEMORY, "Freeing image buffer at %p.\n", pdev->image_data); + rvfree(pdev->image_data, default_mbufs * pdev->len_per_image); } pdev->image_data = NULL; - PWC_DEBUG_MEMORY("Leaving free_buffers().\n"); + Trace(TRACE_MEMORY, "Leaving free_buffers().\n"); } /* The frame & image buffer mess. @@ -438,7 +464,7 @@ static void pwc_free_buffers(struct pwc_device *pdev) /** \brief Find next frame buffer to fill. Take from empty or full list, whichever comes first. */ -static int pwc_next_fill_frame(struct pwc_device *pdev) +static inline int pwc_next_fill_frame(struct pwc_device *pdev) { int ret; unsigned long flags; @@ -463,17 +489,23 @@ static int pwc_next_fill_frame(struct pwc_device *pdev) } else { /* Hmm. Take it from the full list */ +#if PWC_DEBUG /* sanity check */ if (pdev->full_frames == NULL) { - PWC_ERROR("Neither empty or full frames available!\n"); + Err("Neither empty or full frames available!\n"); spin_unlock_irqrestore(&pdev->ptrlock, flags); return -EINVAL; } +#endif pdev->fill_frame = pdev->full_frames; pdev->full_frames = pdev->full_frames->next; ret = 1; } pdev->fill_frame->next = NULL; +#if PWC_DEBUG + Trace(TRACE_SEQUENCE, "Assigning sequence number %d.\n", pdev->sequence); + pdev->fill_frame->sequence = pdev->sequence++; +#endif spin_unlock_irqrestore(&pdev->ptrlock, flags); return ret; } @@ -489,8 +521,6 @@ static void pwc_reset_buffers(struct pwc_device *pdev) int i; unsigned long flags; - PWC_DEBUG_MEMORY(">> %s __enter__\n", __FUNCTION__); - spin_lock_irqsave(&pdev->ptrlock, flags); pdev->full_frames = NULL; pdev->full_frames_tail = NULL; @@ -510,15 +540,13 @@ static void pwc_reset_buffers(struct pwc_device *pdev) pdev->image_read_pos = 0; pdev->fill_image = 0; spin_unlock_irqrestore(&pdev->ptrlock, flags); - - PWC_DEBUG_MEMORY("<< %s __leaving__\n", __FUNCTION__); } /** \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers. */ -int pwc_handle_frame(struct pwc_device *pdev) +static int pwc_handle_frame(struct pwc_device *pdev) { int ret = 0; unsigned long flags; @@ -528,40 +556,41 @@ int pwc_handle_frame(struct pwc_device *pdev) we can release the lock after this without problems */ if (pdev->read_frame != NULL) { /* This can't theoretically happen */ - PWC_ERROR("Huh? Read frame still in use?\n"); - spin_unlock_irqrestore(&pdev->ptrlock, flags); - return ret; - } - - - if (pdev->full_frames == NULL) { - PWC_ERROR("Woops. No frames ready.\n"); + Err("Huh? Read frame still in use?\n"); } else { - pdev->read_frame = pdev->full_frames; - pdev->full_frames = pdev->full_frames->next; - pdev->read_frame->next = NULL; - } - - if (pdev->read_frame != NULL) { - /* Decompression is a lenghty process, so it's outside of the lock. - This gives the isoc_handler the opportunity to fill more frames - in the mean time. - */ - spin_unlock_irqrestore(&pdev->ptrlock, flags); - ret = pwc_decompress(pdev); - spin_lock_irqsave(&pdev->ptrlock, flags); - - /* We're done with read_buffer, tack it to the end of the empty buffer list */ - if (pdev->empty_frames == NULL) { - pdev->empty_frames = pdev->read_frame; - pdev->empty_frames_tail = pdev->empty_frames; + if (pdev->full_frames == NULL) { + Err("Woops. No frames ready.\n"); } else { - pdev->empty_frames_tail->next = pdev->read_frame; - pdev->empty_frames_tail = pdev->read_frame; + pdev->read_frame = pdev->full_frames; + pdev->full_frames = pdev->full_frames->next; + pdev->read_frame->next = NULL; + } + + if (pdev->read_frame != NULL) { +#if PWC_DEBUG + 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 + in the mean time. + */ + spin_unlock_irqrestore(&pdev->ptrlock, flags); + ret = pwc_decompress(pdev); + spin_lock_irqsave(&pdev->ptrlock, flags); + + /* We're done with read_buffer, tack it to the end of the empty buffer list */ + if (pdev->empty_frames == NULL) { + pdev->empty_frames = pdev->read_frame; + pdev->empty_frames_tail = pdev->empty_frames; + } + else { + pdev->empty_frames_tail->next = pdev->read_frame; + pdev->empty_frames_tail = pdev->read_frame; + } + pdev->read_frame = NULL; } - pdev->read_frame = NULL; } spin_unlock_irqrestore(&pdev->ptrlock, flags); return ret; @@ -570,114 +599,12 @@ int pwc_handle_frame(struct pwc_device *pdev) /** \brief Advance pointers of image buffer (after each user request) */ -void pwc_next_image(struct pwc_device *pdev) +static inline void pwc_next_image(struct pwc_device *pdev) { pdev->image_used[pdev->fill_image] = 0; - pdev->fill_image = (pdev->fill_image + 1) % pwc_mbufs; + pdev->fill_image = (pdev->fill_image + 1) % default_mbufs; } -/** - * Print debug information when a frame is discarded because all of our buffer - * is full - */ -static void pwc_frame_dumped(struct pwc_device *pdev) -{ - pdev->vframes_dumped++; - if (pdev->vframe_count < FRAME_LOWMARK) - return; - - if (pdev->vframes_dumped < 20) - PWC_DEBUG_FLOW("Dumping frame %d\n", pdev->vframe_count); - else if (pdev->vframes_dumped == 20) - PWC_DEBUG_FLOW("Dumping frame %d (last message)\n", - pdev->vframe_count); -} - -static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_buf *fbuf) -{ - int awake = 0; - - /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus - frames on the USB wire after an exposure change. This conditition is - however detected in the cam and a bit is set in the header. - */ - if (pdev->type == 730) { - unsigned char *ptr = (unsigned char *)fbuf->data; - - if (ptr[1] == 1 && ptr[0] & 0x10) { - PWC_TRACE("Hyundai CMOS sensor bug. Dropping frame.\n"); - pdev->drop_frames += 2; - pdev->vframes_error++; - } - if ((ptr[0] ^ pdev->vmirror) & 0x01) { - if (ptr[0] & 0x01) { - pdev->snapshot_button_status = 1; - PWC_TRACE("Snapshot button pressed.\n"); - } - else { - PWC_TRACE("Snapshot button released.\n"); - } - } - 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 - after a short frame; this condition is filtered out specifically. A 4 byte - frame doesn't make sense anyway. - So we get either this sequence: - drop_bit set -> 4 byte frame -> short frame -> good frame - Or this one: - drop_bit set -> short frame -> good frame - So we drop either 3 or 2 frames in all! - */ - if (fbuf->filled == 4) - pdev->drop_frames++; - } - else if (pdev->type == 740 || pdev->type == 720) { - unsigned char *ptr = (unsigned char *)fbuf->data; - if ((ptr[0] ^ pdev->vmirror) & 0x01) { - if (ptr[0] & 0x01) { - pdev->snapshot_button_status = 1; - PWC_TRACE("Snapshot button pressed.\n"); - } - else - PWC_TRACE("Snapshot button released.\n"); - } - pdev->vmirror = ptr[0] & 0x03; - } - - /* In case we were instructed to drop the frame, do so silently. - The buffer pointers are not updated either (but the counters are reset below). - */ - 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); - pdev->vframes_error++; - } - else { - /* Send only once per EOF */ - awake = 1; /* delay wake_ups */ - - /* Find our next frame to fill. This will always succeed, since we - * nick a frame from either empty or full list, but if we had to - * take it from the full list, it means a frame got dropped. - */ - if (pwc_next_fill_frame(pdev)) - pwc_frame_dumped(pdev); - - } - } /* !drop_frames */ - pdev->vframe_count++; - return awake; -} /* This gets called for the Isochronous pipe (video). This is done in * interrupt time, so it has to be fast, not crash, and not stall. Neat. @@ -693,12 +620,17 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs) awake = 0; pdev = (struct pwc_device *)urb->context; if (pdev == NULL) { - PWC_ERROR("isoc_handler() called with NULL device?!\n"); + Err("isoc_handler() called with NULL device?!\n"); return; } - +#ifdef PWC_MAGIC + if (pdev->magic != PWC_MAGIC) { + Err("isoc_handler() called with bad magic!\n"); + return; + } +#endif if (urb->status == -ENOENT || urb->status == -ECONNRESET) { - PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a"); + Trace(TRACE_OPEN, "pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a"); return; } if (urb->status != -EINPROGRESS && urb->status != 0) { @@ -713,13 +645,13 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs) case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break; case -ETIMEDOUT: errmsg = "NAK (device does not respond)"; break; } - PWC_DEBUG_FLOW("pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg); + Trace(TRACE_FLOW, "pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg); /* Give up after a number of contiguous errors on the USB bus. Appearantly something is wrong so we simulate an unplug event. */ if (++pdev->visoc_errors > MAX_ISOC_ERRORS) { - PWC_INFO("Too many ISOC errors, bailing out.\n"); + Info("Too many ISOC errors, bailing out.\n"); pdev->error_status = EIO; awake = 1; wake_up_interruptible(&pdev->frameq); @@ -729,7 +661,7 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs) fbuf = pdev->fill_frame; if (fbuf == NULL) { - PWC_ERROR("pwc_isoc_handler without valid fill frame.\n"); + Err("pwc_isoc_handler without valid fill frame.\n"); awake = 1; goto handler_end; } @@ -756,7 +688,7 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs) /* ...copy data to frame buffer, if possible */ if (flen + fbuf->filled > pdev->frame_total_size) { - PWC_DEBUG_FLOW("Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, 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++; } @@ -772,28 +704,96 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs) /* Shorter packet... We probably have the end of an image-frame; wake up read() process and let select()/poll() do something. Decompression is done in user time over there. - */ + */ if (pdev->vsync == 2) { - if (pwc_rcv_short_packet(pdev, fbuf)) { - awake = 1; - fbuf = pdev->fill_frame; + /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus + frames on the USB wire after an exposure change. This conditition is + however detected in the cam and a bit is set in the header. + */ + if (pdev->type == 730) { + unsigned char *ptr = (unsigned char *)fbuf->data; + + if (ptr[1] == 1 && ptr[0] & 0x10) { +#if PWC_DEBUG + Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence); +#endif + pdev->drop_frames += 2; + pdev->vframes_error++; + } + if ((ptr[0] ^ pdev->vmirror) & 0x01) { + if (ptr[0] & 0x01) + Info("Snapshot button pressed.\n"); + else + Info("Snapshot button released.\n"); + } + if ((ptr[0] ^ pdev->vmirror) & 0x02) { + if (ptr[0] & 0x02) + Info("Image is mirrored.\n"); + else + Info("Image is normal.\n"); + } + pdev->vmirror = ptr[0] & 0x03; + /* Sometimes the trailer of the 730 is still sent as a 4 byte packet + after a short frame; this condition is filtered out specifically. A 4 byte + frame doesn't make sense anyway. + So we get either this sequence: + drop_bit set -> 4 byte frame -> short frame -> good frame + Or this one: + drop_bit set -> short frame -> good frame + So we drop either 3 or 2 frames in all! + */ + if (fbuf->filled == 4) + pdev->drop_frames++; } + + /* In case we were instructed to drop the frame, do so silently. + The buffer pointers are not updated either (but the counters are reset below). + */ + if (pdev->drop_frames > 0) + pdev->drop_frames--; + else { + /* Check for underflow first */ + if (fbuf->filled < pdev->frame_total_size) { + Trace(TRACE_FLOW, "Frame buffer underflow (%d bytes); discarded.\n", fbuf->filled); + pdev->vframes_error++; + } + else { + /* Send only once per EOF */ + awake = 1; /* delay wake_ups */ + + /* Find our next frame to fill. This will always succeed, since we + * nick a frame from either empty or full list, but if we had to + * take it from the full list, it means a frame got dropped. + */ + if (pwc_next_fill_frame(pdev)) { + pdev->vframes_dumped++; + if ((pdev->vframe_count > FRAME_LOWMARK) && (pwc_trace & TRACE_FLOW)) { + if (pdev->vframes_dumped < 20) + Trace(TRACE_FLOW, "Dumping frame %d.\n", pdev->vframe_count); + if (pdev->vframes_dumped == 20) + Trace(TRACE_FLOW, "Dumping frame %d (last message).\n", pdev->vframe_count); + } + } + fbuf = pdev->fill_frame; + } + } /* !drop_frames */ + pdev->vframe_count++; } fbuf->filled = 0; fillptr = fbuf->data; pdev->vsync = 1; - } - + } /* .. flen < last_packet_size */ pdev->vlast_packet_size = flen; } /* ..status == 0 */ +#if PWC_DEBUG + /* This is normally not interesting to the user, unless you are really debugging something */ else { - /* This is normally not interesting to the user, unless - * you are really debugging something */ static int iso_error = 0; iso_error++; if (iso_error < 20) - PWC_DEBUG_FLOW("Iso frame %d of USB has error %d\n", i, fst); + Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst); } +#endif } handler_end: @@ -803,11 +803,11 @@ handler_end: urb->dev = pdev->udev; i = usb_submit_urb(urb, GFP_ATOMIC); if (i != 0) - PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i); + Err("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i); } -int pwc_isoc_init(struct pwc_device *pdev) +static int pwc_isoc_init(struct pwc_device *pdev) { struct usb_device *udev; struct urb *urb; @@ -826,6 +826,7 @@ int pwc_isoc_init(struct pwc_device *pdev) /* Get the current alternate interface, adjust packet size */ if (!udev->actconfig) return -EFAULT; + intf = usb_ifnum_to_if(udev, 0); if (intf) idesc = usb_altnum_to_altsetting(intf, pdev->valternate); @@ -835,21 +836,20 @@ int pwc_isoc_init(struct pwc_device *pdev) /* Search video endpoint */ pdev->vmax_packet_size = -1; - for (i = 0; i < idesc->desc.bNumEndpoints; i++) { + 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"); + Err("Failed to find packet size for video endpoint in current alternate setting.\n"); return -ENFILE; /* Odd error, that should be noticeable */ } /* Set alternate interface */ ret = 0; - PWC_DEBUG_OPEN("Setting alternate interface %d\n", pdev->valternate); + Trace(TRACE_OPEN, "Setting alternate interface %d\n", pdev->valternate); ret = usb_set_interface(pdev->udev, 0, pdev->valternate); if (ret < 0) return ret; @@ -857,12 +857,12 @@ int pwc_isoc_init(struct pwc_device *pdev) for (i = 0; i < MAX_ISO_BUFS; i++) { urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); if (urb == NULL) { - PWC_ERROR("Failed to allocate urb %d\n", i); + Err("Failed to allocate urb %d\n", i); ret = -ENOMEM; break; } pdev->sbuf[i].urb = urb; - PWC_DEBUG_MEMORY("Allocated URB at 0x%p\n", urb); + Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb); } if (ret) { /* De-allocate in reverse order */ @@ -899,26 +899,24 @@ int pwc_isoc_init(struct pwc_device *pdev) for (i = 0; i < MAX_ISO_BUFS; i++) { ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL); if (ret) - PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret); + Err("isoc_init() submit_urb %d failed with error %d\n", i, ret); else - PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->sbuf[i].urb); + Trace(TRACE_MEMORY, "URB 0x%p submitted.\n", pdev->sbuf[i].urb); } /* All is done... */ pdev->iso_init = 1; - PWC_DEBUG_OPEN("<< pwc_isoc_init()\n"); + Trace(TRACE_OPEN, "<< pwc_isoc_init()\n"); return 0; } -void pwc_isoc_cleanup(struct pwc_device *pdev) +static void pwc_isoc_cleanup(struct pwc_device *pdev) { int i; - PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n"); + Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n"); if (pdev == NULL) return; - if (pdev->iso_init == 0) - return; /* Unlinking ISOC buffers one by one */ for (i = 0; i < MAX_ISO_BUFS; i++) { @@ -927,10 +925,10 @@ void pwc_isoc_cleanup(struct pwc_device *pdev) urb = pdev->sbuf[i].urb; if (urb != 0) { if (pdev->iso_init) { - PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb); + Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb); usb_kill_urb(urb); } - PWC_DEBUG_MEMORY("Freeing URB\n"); + Trace(TRACE_MEMORY, "Freeing URB\n"); usb_free_urb(urb); pdev->sbuf[i].urb = NULL; } @@ -940,12 +938,12 @@ void pwc_isoc_cleanup(struct pwc_device *pdev) is signalled by EPIPE) */ if (pdev->error_status && pdev->error_status != EPIPE) { - PWC_DEBUG_OPEN("Setting alternate interface 0.\n"); + Trace(TRACE_OPEN, "Setting alternate interface 0.\n"); usb_set_interface(pdev->udev, 0, 0); } pdev->iso_init = 0; - PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n"); + Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n"); } int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot) @@ -959,18 +957,18 @@ int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_f /* Try to set video mode... */ start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot); if (ret) { - PWC_DEBUG_FLOW("pwc_set_video_mode attempt 1 failed.\n"); + Trace(TRACE_FLOW, "pwc_set_video_mode attempt 1 failed.\n"); /* That failed... restore old mode (we know that worked) */ start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); if (start) { - PWC_DEBUG_FLOW("pwc_set_video_mode attempt 2 failed.\n"); + Trace(TRACE_FLOW, "pwc_set_video_mode attempt 2 failed.\n"); } } if (start == 0) { if (pwc_isoc_init(pdev) < 0) { - PWC_WARNING("Failed to restart ISOC transfers in pwc_try_video_mode.\n"); + 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 */ } } @@ -978,129 +976,54 @@ int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_f return ret; /* Return original error code */ } -/********* - * sysfs - *********/ -static struct pwc_device *cd_to_pwc(struct class_device *cd) -{ - struct video_device *vdev = to_video_device(cd); - return video_get_drvdata(vdev); -} - -static ssize_t show_pan_tilt(struct class_device *class_dev, char *buf) -{ - struct pwc_device *pdev = cd_to_pwc(class_dev); - return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle); -} - -static ssize_t store_pan_tilt(struct class_device *class_dev, const char *buf, - size_t count) -{ - struct pwc_device *pdev = cd_to_pwc(class_dev); - int pan, tilt; - int ret = -EINVAL; - - if (strncmp(buf, "reset", 5) == 0) - ret = pwc_mpt_reset(pdev, 0x3); - - else if (sscanf(buf, "%d %d", &pan, &tilt) > 0) - ret = pwc_mpt_set_angle(pdev, pan, tilt); - - if (ret < 0) - return ret; - return strlen(buf); -} -static CLASS_DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt, - store_pan_tilt); - -static ssize_t show_snapshot_button_status(struct class_device *class_dev, char *buf) -{ - struct pwc_device *pdev = cd_to_pwc(class_dev); - int status = pdev->snapshot_button_status; - pdev->snapshot_button_status = 0; - return sprintf(buf, "%d\n", status); -} - -static CLASS_DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status, - NULL); - -static void pwc_create_sysfs_files(struct video_device *vdev) -{ - struct pwc_device *pdev = video_get_drvdata(vdev); - if (pdev->features & FEATURE_MOTOR_PANTILT) - video_device_create_file(vdev, &class_device_attr_pan_tilt); - video_device_create_file(vdev, &class_device_attr_button); -} - -static void pwc_remove_sysfs_files(struct video_device *vdev) -{ - struct pwc_device *pdev = video_get_drvdata(vdev); - if (pdev->features & FEATURE_MOTOR_PANTILT) - video_device_remove_file(vdev, &class_device_attr_pan_tilt); - video_device_remove_file(vdev, &class_device_attr_button); -} - -#if CONFIG_PWC_DEBUG -static const char *pwc_sensor_type_to_string(unsigned int sensor_type) -{ - switch(sensor_type) { - case 0x00: - return "Hyundai CMOS sensor"; - case 0x20: - return "Sony CCD sensor + TDA8787"; - case 0x2E: - return "Sony CCD sensor + Exas 98L59"; - case 0x2F: - return "Sony CCD sensor + ADI 9804"; - case 0x30: - return "Sharp CCD sensor + TDA8787"; - case 0x3E: - return "Sharp CCD sensor + Exas 98L59"; - case 0x3F: - return "Sharp CCD sensor + ADI 9804"; - case 0x40: - return "UPA 1021 sensor"; - case 0x100: - return "VGA sensor"; - case 0x101: - return "PAL MR sensor"; - default: - return "unknown type of sensor"; - } -} -#endif /***************************************************************************/ /* Video4Linux functions */ static int pwc_video_open(struct inode *inode, struct file *file) { - int i, ret; + int i; struct video_device *vdev = video_devdata(file); struct pwc_device *pdev; - PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev); + Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev); pdev = (struct pwc_device *)vdev->priv; if (pdev == NULL) BUG(); - if (pdev->vopen) { - PWC_DEBUG_OPEN("I'm busy, someone is using the device.\n"); + if (pdev->vopen) return -EBUSY; - } down(&pdev->modlock); if (!pdev->usb_init) { - PWC_DEBUG_OPEN("Doing first time initialization.\n"); + Trace(TRACE_OPEN, "Doing first time initialization.\n"); pdev->usb_init = 1; - /* Query sensor type */ - ret = pwc_get_cmos_sensor(pdev, &i); - if (ret >= 0) + if (pwc_trace & TRACE_OPEN) { - PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n", - pdev->vdev->name, - pwc_sensor_type_to_string(i), i); + /* Query sensor type */ + const char *sensor_type = NULL; + int ret; + + 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); } } @@ -1108,32 +1031,34 @@ static int pwc_video_open(struct inode *inode, struct file *file) if (power_save) { i = pwc_camera_power(pdev, 1); if (i < 0) - PWC_DEBUG_OPEN("Failed to restore power to the camera! (%d)\n", i); + Info("Failed to restore power to the camera! (%d)\n", i); } /* Set LED on/off time */ if (pwc_set_leds(pdev, led_on, led_off) < 0) - PWC_DEBUG_OPEN("Failed to set LED on/off time.\n"); + Info("Failed to set LED on/off time.\n"); pwc_construct(pdev); /* set min/max sizes correct */ /* So far, so good. Allocate memory. */ i = pwc_allocate_buffers(pdev); if (i < 0) { - PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n"); - pwc_free_buffers(pdev); + Trace(TRACE_OPEN, "Failed to allocate buffer memory.\n"); up(&pdev->modlock); return i; } /* Reset buffers & parameters */ pwc_reset_buffers(pdev); - for (i = 0; i < pwc_mbufs; i++) + for (i = 0; i < default_mbufs; i++) pdev->image_used[i] = 0; pdev->vframe_count = 0; pdev->vframes_dumped = 0; pdev->vframes_error = 0; pdev->visoc_errors = 0; pdev->error_status = 0; +#if PWC_DEBUG + pdev->sequence = 0; +#endif pwc_construct(pdev); /* set min/max sizes correct */ /* Set some defaults */ @@ -1145,44 +1070,29 @@ static int pwc_video_open(struct inode *inode, struct file *file) */ i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0); if (i) { - unsigned int default_resolution; - PWC_DEBUG_OPEN("First attempt at set_video_mode failed.\n"); - if (pdev->type>= 730) - default_resolution = PSZ_QSIF; + Trace(TRACE_OPEN, "First attempt at set_video_mode failed.\n"); + if (pdev->type == 730 || pdev->type == 740 || pdev->type == 750) + i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QSIF].x, pwc_image_sizes[PSZ_QSIF].y, 10, pdev->vcompression, 0); else - default_resolution = PSZ_QCIF; - - i = pwc_set_video_mode(pdev, - pwc_image_sizes[default_resolution].x, - pwc_image_sizes[default_resolution].y, - 10, - pdev->vcompression, - 0); + i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QCIF].x, pwc_image_sizes[PSZ_QCIF].y, 10, pdev->vcompression, 0); } if (i) { - PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n"); - pwc_free_buffers(pdev); + Trace(TRACE_OPEN, "Second attempt at set_video_mode failed.\n"); up(&pdev->modlock); return i; } i = pwc_isoc_init(pdev); if (i) { - PWC_DEBUG_OPEN("Failed to init ISOC stuff = %d.\n", i); - pwc_isoc_cleanup(pdev); - pwc_free_buffers(pdev); + Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i); up(&pdev->modlock); return i; } - /* Initialize the webcam to sane value */ - pwc_set_brightness(pdev, 0x7fff); - pwc_set_agc(pdev, 1, 0); - pdev->vopen++; file->private_data = vdev; up(&pdev->modlock); - PWC_DEBUG_OPEN("<< video_open() returns 0.\n"); + Trace(TRACE_OPEN, "<< video_open() returns 0.\n"); return 0; } @@ -1193,23 +1103,35 @@ static int pwc_video_close(struct inode *inode, struct file *file) struct pwc_device *pdev; int i; - PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev); + Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev); pdev = (struct pwc_device *)vdev->priv; if (pdev->vopen == 0) - PWC_DEBUG_MODULE("video_close() called on closed device?\n"); + Info("video_close() called on closed device?\n"); /* Dump statistics, but only if a reasonable amount of frames were processed (to prevent endless log-entries in case of snap-shot programs) */ if (pdev->vframe_count > 20) - PWC_DEBUG_MODULE("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error); + Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error); - if (DEVICE_USE_CODEC1(pdev->type)) - pwc_dec1_exit(); - else - pwc_dec23_exit(); + switch (pdev->type) + { + case 675: + case 680: + case 690: + case 720: + case 730: + case 740: + case 750: +/* pwc_dec23_exit(); *//* Timon & Kiara */ + break; + case 645: + case 646: +/* pwc_dec1_exit(); */ + break; + } pwc_isoc_cleanup(pdev); pwc_free_buffers(pdev); @@ -1218,15 +1140,15 @@ static int pwc_video_close(struct inode *inode, struct file *file) if (pdev->error_status != EPIPE) { /* Turn LEDs off */ if (pwc_set_leds(pdev, 0, 0) < 0) - PWC_DEBUG_MODULE("Failed to set LED on/off time.\n"); + Info("Failed to set LED on/off time.\n"); if (power_save) { i = pwc_camera_power(pdev, 0); if (i < 0) - PWC_ERROR("Failed to power down camera (%d)\n", i); + Err("Failed to power down camera (%d)\n", i); } } - pdev->vopen--; - PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen); + pdev->vopen = 0; + Trace(TRACE_OPEN, "<< video_close()\n"); return 0; } @@ -1242,7 +1164,7 @@ static int pwc_video_close(struct inode *inode, struct file *file) device is tricky anyhow. */ -static ssize_t pwc_video_read(struct file *file, char __user *buf, +static ssize_t pwc_video_read(struct file *file, char __user * buf, size_t count, loff_t *ppos) { struct video_device *vdev = file->private_data; @@ -1250,10 +1172,8 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf, int noblock = file->f_flags & O_NONBLOCK; DECLARE_WAITQUEUE(wait, current); int bytes_to_read; - void *image_buffer_addr; - PWC_DEBUG_READ("pwc_video_read(vdev=0x%p, buf=%p, count=%zd) called.\n", - vdev, buf, count); + Trace(TRACE_READ, "video_read(0x%p, %p, %zu) called.\n", vdev, buf, count); if (vdev == NULL) return -EFAULT; pdev = vdev->priv; @@ -1294,19 +1214,16 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf, return -EFAULT; } - PWC_DEBUG_READ("Copying data to user space.\n"); + Trace(TRACE_READ, "Copying data to user space.\n"); if (pdev->vpalette == VIDEO_PALETTE_RAW) - bytes_to_read = pdev->frame_size + sizeof(struct pwc_raw_frame); + 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 > bytes_to_read) count = bytes_to_read - pdev->image_read_pos; - image_buffer_addr = pdev->image_data; - image_buffer_addr += pdev->images[pdev->fill_image].offset; - image_buffer_addr += pdev->image_read_pos; - if (copy_to_user(buf, image_buffer_addr, count)) + 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 >= bytes_to_read) { /* All data has been read */ @@ -1336,56 +1253,370 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait) return 0; } +static int pwc_video_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) +{ + struct video_device *vdev = file->private_data; + struct pwc_device *pdev; + DECLARE_WAITQUEUE(wait, current); + + if (vdev == NULL) + return -EFAULT; + pdev = vdev->priv; + if (pdev == NULL) + return -EFAULT; + + switch (cmd) { + /* Query cabapilities */ + case VIDIOCGCAP: + { + struct video_capability *caps = arg; + + strcpy(caps->name, vdev->name); + caps->type = VID_TYPE_CAPTURE; + caps->channels = 1; + caps->audios = 1; + caps->minwidth = pdev->view_min.x; + caps->minheight = pdev->view_min.y; + caps->maxwidth = pdev->view_max.x; + caps->maxheight = pdev->view_max.y; + break; + } + + /* Channel functions (simulate 1 channel) */ + case VIDIOCGCHAN: + { + struct video_channel *v = arg; + + if (v->channel != 0) + return -EINVAL; + v->flags = 0; + v->tuners = 0; + v->type = VIDEO_TYPE_CAMERA; + strcpy(v->name, "Webcam"); + return 0; + } + + 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. + */ + struct video_channel *v = arg; + if (v->channel != 0) + return -EINVAL; + return 0; + } + + + /* Picture functions; contrast etc. */ + case VIDIOCGPICT: + { + struct video_picture *p = arg; + int val; + + val = pwc_get_brightness(pdev); + if (val >= 0) + p->brightness = val; + else + p->brightness = 0xffff; + val = pwc_get_contrast(pdev); + if (val >= 0) + p->contrast = val; + else + p->contrast = 0xffff; + /* Gamma, Whiteness, what's the difference? :) */ + val = pwc_get_gamma(pdev); + if (val >= 0) + p->whiteness = val; + else + p->whiteness = 0xffff; + val = pwc_get_saturation(pdev); + if (val >= 0) + p->colour = val; + else + p->colour = 0xffff; + p->depth = 24; + p->palette = pdev->vpalette; + p->hue = 0xFFFF; /* N/A */ + break; + } + + case VIDIOCSPICT: + { + struct video_picture *p = arg; + /* + * FIXME: Suppose we are mid read + ANSWER: No problem: the firmware of the camera + can handle brightness/contrast/etc + changes at _any_ time, and the palette + is used exactly once in the uncompress + routine. + */ + 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; + } + + /* Window/size parameters */ + case VIDIOCGWIN: + { + struct video_window *vw = arg; + + vw->x = 0; + vw->y = 0; + vw->width = pdev->view.x; + vw->height = pdev->view.y; + vw->chromakey = 0; + vw->flags = (pdev->vframes << PWC_FPS_SHIFT) | + (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0); + break; + } + + case VIDIOCSWIN: + { + struct video_window *vw = arg; + int fps, snapshot, ret; + + fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT; + snapshot = vw->flags & PWC_FPS_SNAPSHOT; + if (fps == 0) + fps = pdev->vframes; + if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot) + return 0; + ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot); + if (ret) + return ret; + break; + } + + /* We don't have overlay support (yet) */ + case VIDIOCGFBUF: + { + struct video_buffer *vb = arg; + + memset(vb,0,sizeof(*vb)); + break; + } + + /* mmap() functions */ + case VIDIOCGMBUF: + { + /* Tell the user program how much memory is needed for a mmap() */ + struct video_mbuf *vm = arg; + int i; + + memset(vm, 0, sizeof(*vm)); + vm->size = default_mbufs * pdev->len_per_image; + vm->frames = default_mbufs; /* double buffering should be enough for most applications */ + for (i = 0; i < default_mbufs; i++) + vm->offsets[i] = i * pdev->len_per_image; + break; + } + + case VIDIOCMCAPTURE: + { + /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */ + struct video_mmap *vm = arg; + + Trace(TRACE_READ, "VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format); + if (vm->frame < 0 || vm->frame >= default_mbufs) + return -EINVAL; + + /* xawtv is nasty. It probes the available palettes + by setting a very small image size and trying + various palettes... The driver doesn't support + such small images, so I'm working around it. + */ + 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) + return ret; + } /* ... size mismatch */ + + /* FIXME: should we lock here? */ + if (pdev->image_used[vm->frame]) + return -EBUSY; /* buffer wasn't available. Bummer */ + pdev->image_used[vm->frame] = 1; + + /* Okay, we're done here. In the SYNC call we wait until a + frame comes available, then expand image into the given + buffer. + In contrast to the CPiA cam the Philips cams deliver a + constant stream, almost like a grabber card. Also, + we have separate buffers for the rawdata and the image, + meaning we can nearly always expand into the requested buffer. + */ + Trace(TRACE_READ, "VIDIOCMCAPTURE done.\n"); + break; + } + + case VIDIOCSYNC: + { + /* The doc says: "Whenever a buffer is used it should + call VIDIOCSYNC to free this frame up and continue." + + The only odd thing about this whole procedure is + that MCAPTURE flags the buffer as "in use", and + SYNC immediately unmarks it, while it isn't + after SYNC that you know that the buffer actually + got filled! So you better not start a CAPTURE in + the same frame immediately (use double buffering). + This is not a problem for this cam, since it has + extra intermediate buffers, but a hardware + grabber card will then overwrite the buffer + you're working on. + */ + int *mbuf = arg; + int ret; + + Trace(TRACE_READ, "VIDIOCSYNC called (%d).\n", *mbuf); + + /* bounds check */ + if (*mbuf < 0 || *mbuf >= default_mbufs) + return -EINVAL; + /* check if this buffer was requested anyway */ + if (pdev->image_used[*mbuf] == 0) + return -EINVAL; + + /* Add ourselves to the frame wait-queue. + + FIXME: needs auditing for safety. + QUESTION: In what respect? I think that using the + frameq is safe now. + */ + add_wait_queue(&pdev->frameq, &wait); + while (pdev->full_frames == NULL) { + if (pdev->error_status) { + remove_wait_queue(&pdev->frameq, &wait); + set_current_state(TASK_RUNNING); + return -pdev->error_status; + } + + if (signal_pending(current)) { + remove_wait_queue(&pdev->frameq, &wait); + set_current_state(TASK_RUNNING); + return -ERESTARTSYS; + } + schedule(); + set_current_state(TASK_INTERRUPTIBLE); + } + remove_wait_queue(&pdev->frameq, &wait); + set_current_state(TASK_RUNNING); + + /* The frame is ready. Expand in the image buffer + requested by the user. I don't care if you + mmap() 5 buffers and request data in this order: + buffer 4 2 3 0 1 2 3 0 4 3 1 . . . + Grabber hardware may not be so forgiving. + */ + Trace(TRACE_READ, "VIDIOCSYNC: frame ready.\n"); + pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */ + /* Decompress, etc */ + ret = pwc_handle_frame(pdev); + pdev->image_used[*mbuf] = 0; + if (ret) + return -EFAULT; + break; + } + + case VIDIOCGAUDIO: + { + struct video_audio *v = arg; + + strcpy(v->name, "Microphone"); + v->audio = -1; /* unknown audio minor */ + v->flags = 0; + v->mode = VIDEO_SOUND_MONO; + v->volume = 0; + v->bass = 0; + v->treble = 0; + v->balance = 0x8000; + v->step = 1; + break; + } + + case VIDIOCSAUDIO: + { + /* Dummy: nothing can be set */ + break; + } + + case VIDIOCGUNIT: + { + struct video_unit *vu = arg; + + vu->video = pdev->vdev->minor & 0x3F; + vu->audio = -1; /* not known yet */ + vu->vbi = -1; + vu->radio = -1; + vu->teletext = -1; + break; + } + default: + return pwc_ioctl(pdev, cmd, arg); + } /* ..switch */ + return 0; +} + static int pwc_video_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl); } + static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) { struct video_device *vdev = file->private_data; struct pwc_device *pdev; - unsigned long start; - unsigned long size; - unsigned long page, pos = 0; - int index; + unsigned long start = vma->vm_start; + unsigned long size = vma->vm_end-vma->vm_start; + unsigned long page, pos; - PWC_DEBUG_MEMORY(">> %s\n", __FUNCTION__); + Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size); pdev = vdev->priv; - size = vma->vm_end - vma->vm_start; - start = vma->vm_start; - /* Find the idx buffer for this mapping */ - for (index = 0; index < pwc_mbufs; index++) { - pos = pdev->images[index].offset; - if ((pos>>PAGE_SHIFT) == vma->vm_pgoff) - break; - } - if (index == MAX_IMAGES) - return -EINVAL; - if (index == 0) { - /* - * Special case for v4l1. In v4l1, we map only one big buffer, - * but in v4l2 each buffer is mapped - */ - unsigned long total_size; - total_size = pwc_mbufs * pdev->len_per_image; - if (size != pdev->len_per_image && size != total_size) { - PWC_ERROR("Wrong size (%lu) needed to be len_per_image=%d or total_size=%lu\n", - size, pdev->len_per_image, total_size); - return -EINVAL; - } - } else if (size > pdev->len_per_image) - return -EINVAL; + vma->vm_flags |= VM_IO; - vma->vm_flags |= VM_IO; /* from 2.6.9-acX */ - - pos += (unsigned long)pdev->image_data; + pos = (unsigned long)pdev->image_data; while (size > 0) { page = vmalloc_to_pfn((void *)pos); if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) return -EAGAIN; + start += PAGE_SIZE; pos += PAGE_SIZE; if (size > PAGE_SIZE) @@ -1393,6 +1624,7 @@ static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) else size = 0; } + return 0; } @@ -1413,12 +1645,10 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id int video_nr = -1; /* default: use next available device */ char serial_number[30], *name; - vendor_id = le16_to_cpu(udev->descriptor.idVendor); - product_id = le16_to_cpu(udev->descriptor.idProduct); - /* Check if we can handle this device */ - PWC_DEBUG_PROBE("probe() called [%04X %04X], if %d\n", - vendor_id, product_id, + Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct), intf->altsetting->desc.bInterfaceNumber); /* the interfaces are probed one by one. We are only interested in the @@ -1428,63 +1658,61 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id if (intf->altsetting->desc.bInterfaceNumber > 0) return -ENODEV; + vendor_id = le16_to_cpu(udev->descriptor.idVendor); + product_id = le16_to_cpu(udev->descriptor.idProduct); + if (vendor_id == 0x0471) { switch (product_id) { case 0x0302: - PWC_INFO("Philips PCA645VC USB webcam detected.\n"); + Info("Philips PCA645VC USB webcam detected.\n"); name = "Philips 645 webcam"; type_id = 645; break; case 0x0303: - PWC_INFO("Philips PCA646VC USB webcam detected.\n"); + Info("Philips PCA646VC USB webcam detected.\n"); name = "Philips 646 webcam"; type_id = 646; break; case 0x0304: - PWC_INFO("Askey VC010 type 2 USB webcam detected.\n"); + Info("Askey VC010 type 2 USB webcam detected.\n"); name = "Askey VC010 webcam"; type_id = 646; break; case 0x0307: - PWC_INFO("Philips PCVC675K (Vesta) USB webcam detected.\n"); + Info("Philips PCVC675K (Vesta) USB webcam detected.\n"); name = "Philips 675 webcam"; type_id = 675; break; case 0x0308: - PWC_INFO("Philips PCVC680K (Vesta Pro) USB webcam detected.\n"); + Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n"); name = "Philips 680 webcam"; type_id = 680; break; case 0x030C: - PWC_INFO("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n"); + Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n"); name = "Philips 690 webcam"; type_id = 690; break; case 0x0310: - PWC_INFO("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) 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: - PWC_INFO("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n"); + Info("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n"); name = "Philips 740 webcam"; type_id = 740; break; case 0x0312: - PWC_INFO("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n"); + Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n"); name = "Philips 750 webcam"; type_id = 750; break; case 0x0313: - PWC_INFO("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n"); + Info("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n"); name = "Philips 720K/40 webcam"; type_id = 720; break; - case 0x0329: - PWC_INFO("Philips SPC 900NC USB webcam detected.\n"); - name = "Philips SPC 900NC webcam"; - type_id = 720; - break; default: return -ENODEV; break; @@ -1493,7 +1721,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id else if (vendor_id == 0x069A) { switch(product_id) { case 0x0001: - PWC_INFO("Askey VC010 type 1 USB webcam detected.\n"); + Info("Askey VC010 type 1 USB webcam detected.\n"); name = "Askey VC010 webcam"; type_id = 645; break; @@ -1505,33 +1733,32 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id else if (vendor_id == 0x046d) { switch(product_id) { case 0x08b0: - PWC_INFO("Logitech QuickCam Pro 3000 USB webcam detected.\n"); + Info("Logitech QuickCam Pro 3000 USB webcam detected.\n"); name = "Logitech QuickCam Pro 3000"; type_id = 740; /* CCD sensor */ break; case 0x08b1: - PWC_INFO("Logitech QuickCam Notebook Pro USB webcam detected.\n"); + Info("Logitech QuickCam Notebook Pro USB webcam detected.\n"); name = "Logitech QuickCam Notebook Pro"; type_id = 740; /* CCD sensor */ break; case 0x08b2: - PWC_INFO("Logitech QuickCam 4000 Pro USB webcam detected.\n"); + Info("Logitech QuickCam 4000 Pro USB webcam detected.\n"); name = "Logitech QuickCam Pro 4000"; type_id = 740; /* CCD sensor */ break; case 0x08b3: - PWC_INFO("Logitech QuickCam Zoom USB webcam detected.\n"); + Info("Logitech QuickCam Zoom USB webcam detected.\n"); name = "Logitech QuickCam Zoom"; type_id = 740; /* CCD sensor */ break; case 0x08B4: - PWC_INFO("Logitech QuickCam Zoom (new model) USB webcam detected.\n"); + Info("Logitech QuickCam Zoom (new model) USB webcam detected.\n"); name = "Logitech QuickCam Zoom"; type_id = 740; /* CCD sensor */ - power_save = 1; break; case 0x08b5: - PWC_INFO("Logitech QuickCam Orbit/Sphere USB webcam detected.\n"); + Info("Logitech QuickCam Orbit/Sphere USB webcam detected.\n"); name = "Logitech QuickCam Orbit"; type_id = 740; /* CCD sensor */ features |= FEATURE_MOTOR_PANTILT; @@ -1539,7 +1766,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id case 0x08b6: case 0x08b7: case 0x08b8: - PWC_INFO("Logitech QuickCam detected (reserved ID).\n"); + Info("Logitech QuickCam detected (reserved ID).\n"); name = "Logitech QuickCam (res.)"; type_id = 730; /* Assuming CMOS */ break; @@ -1555,20 +1782,15 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id */ switch(product_id) { case 0x9000: - PWC_INFO("Samsung MPC-C10 USB webcam detected.\n"); + Info("Samsung MPC-C10 USB webcam detected.\n"); name = "Samsung MPC-C10"; type_id = 675; break; case 0x9001: - PWC_INFO("Samsung MPC-C30 USB webcam detected.\n"); + Info("Samsung MPC-C30 USB webcam detected.\n"); name = "Samsung MPC-C30"; type_id = 675; break; - case 0x9002: - PWC_INFO("Samsung SNC-35E (v3.0) USB webcam detected.\n"); - name = "Samsung MPC-C30"; - type_id = 740; - break; default: return -ENODEV; break; @@ -1577,12 +1799,12 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id else if (vendor_id == 0x041e) { switch(product_id) { case 0x400c: - PWC_INFO("Creative Labs Webcam 5 detected.\n"); + Info("Creative Labs Webcam 5 detected.\n"); name = "Creative Labs Webcam 5"; type_id = 730; break; case 0x4011: - PWC_INFO("Creative Labs Webcam Pro Ex detected.\n"); + Info("Creative Labs Webcam Pro Ex detected.\n"); name = "Creative Labs Webcam Pro Ex"; type_id = 740; break; @@ -1594,7 +1816,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id else if (vendor_id == 0x04cc) { switch(product_id) { case 0x8116: - PWC_INFO("Sotec Afina Eye USB webcam detected.\n"); + Info("Sotec Afina Eye USB webcam detected.\n"); name = "Sotec Afina Eye"; type_id = 730; break; @@ -1607,7 +1829,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id switch(product_id) { case 0x8116: /* This is essentially the same cam as the Sotec Afina Eye */ - PWC_INFO("AME Co. Afina Eye USB webcam detected.\n"); + Info("AME Co. Afina Eye USB webcam detected.\n"); name = "AME Co. Afina Eye"; type_id = 750; break; @@ -1620,12 +1842,12 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id else if (vendor_id == 0x0d81) { switch(product_id) { case 0x1900: - PWC_INFO("Visionite VCS-UC300 USB webcam detected.\n"); + Info("Visionite VCS-UC300 USB webcam detected.\n"); name = "Visionite VCS-UC300"; type_id = 740; /* CCD sensor */ break; case 0x1910: - PWC_INFO("Visionite VCS-UM100 USB webcam detected.\n"); + Info("Visionite VCS-UM100 USB webcam detected.\n"); name = "Visionite VCS-UM100"; type_id = 730; /* CMOS sensor */ break; @@ -1639,15 +1861,15 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id 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); + Trace(TRACE_PROBE, "Device serial number is %s\n", serial_number); if (udev->descriptor.bNumConfigurations > 1) - PWC_WARNING("Warning: more than 1 configuration available.\n"); + Info("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"); + Err("Oops, could not allocate memory for pwc_device.\n"); return -ENOMEM; } pdev->type = type_id; @@ -1678,18 +1900,17 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pdev->vdev = video_device_alloc(); if (pdev->vdev == 0) { - PWC_ERROR("Err, cannot allocate video_device struture. Failing probe."); + Err("Err, cannot allocate video_device struture. Failing probe."); kfree(pdev); return -ENOMEM; } memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template)); - pdev->vdev->dev = &(udev->dev); strcpy(pdev->vdev->name, name); pdev->vdev->owner = THIS_MODULE; video_set_drvdata(pdev->vdev, pdev); pdev->release = le16_to_cpu(udev->descriptor.bcdDevice); - PWC_DEBUG_PROBE("Release: %04x\n", pdev->release); + 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++) { @@ -1697,10 +1918,10 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id (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; - PWC_DEBUG_PROBE("Found hint, will try to register as /dev/video%d\n", video_nr); - break; + /* 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; } } } @@ -1708,27 +1929,21 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pdev->vdev->release = video_device_release; i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr); if (i < 0) { - PWC_ERROR("Failed to register as video device (%d).\n", i); + 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 { - PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F); + Info("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F); } /* occupy slot */ if (hint < MAX_DEV_HINTS) device_hint[hint].pdev = pdev; - PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev); + Trace(TRACE_PROBE, "probe() function returning struct at 0x%p.\n", pdev); usb_set_intfdata (intf, pdev); - pwc_create_sysfs_files(pdev->vdev); - - /* Set the leds off */ - pwc_set_leds(pdev, 0, 0); - pwc_camera_power(pdev, 0); - return 0; } @@ -1742,21 +1957,27 @@ static void usb_pwc_disconnect(struct usb_interface *intf) pdev = usb_get_intfdata (intf); usb_set_intfdata (intf, NULL); if (pdev == NULL) { - PWC_ERROR("pwc_disconnect() Called without private pointer.\n"); + Err("pwc_disconnect() Called without private pointer.\n"); goto disconnect_out; } if (pdev->udev == NULL) { - PWC_ERROR("pwc_disconnect() already called for %p\n", pdev); + Err("pwc_disconnect() already called for %p\n", pdev); goto disconnect_out; } if (pdev->udev != interface_to_usbdev(intf)) { - PWC_ERROR("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n"); + 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) { - PWC_INFO("Disconnected while webcam is in use!\n"); + Info("Disconnected while webcam is in use!\n"); pdev->error_status = EPIPE; } @@ -1766,8 +1987,7 @@ static void usb_pwc_disconnect(struct usb_interface *intf) while (pdev->vopen) schedule(); /* Device is now closed, so we can safely unregister it */ - PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n"); - pwc_remove_sysfs_files(pdev->vdev); + Trace(TRACE_PROBE, "Unregistering video device in disconnect().\n"); video_unregister_device(pdev->vdev); /* Free memory (don't set pdev to 0 just yet) */ @@ -1801,64 +2021,58 @@ static int pwc_atoi(const char *s) * Initialization code & module stuff */ -static char *size; -static int fps; -static int fbufs; -static int mbufs; +static char size[10]; +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 int leds_nargs; -static char *dev_hint[MAX_DEV_HINTS]; -static int dev_hint_nargs; - -module_param(size, charp, 0444); -module_param(fps, int, 0444); -module_param(fbufs, int, 0444); -module_param(mbufs, int, 0444); -#if CONFIG_PWC_DEBUG -module_param_named(trace, pwc_trace, int, 0644); -#endif -module_param(power_save, int, 0444); -module_param(compression, int, 0444); -module_param_array(leds, int, &leds_nargs, 0444); -module_param_array(dev_hint, charp, &dev_hint_nargs, 0444); +static char *dev_hint[MAX_DEV_HINTS] = { }; +module_param_string(size, size, sizeof(size), 0); MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga"); +module_param(fps, int, 0000); MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30"); +module_param(fbufs, int, 0000); MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve"); +module_param(mbufs, int, 0000); MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers"); +module_param(trace, int, 0000); MODULE_PARM_DESC(trace, "For debugging purposes"); +module_param(power_save, bool, 0000); MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off"); +module_param(compression, int, 0000); MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)"); +module_param_array(leds, int, NULL, 0000); MODULE_PARM_DESC(leds, "LED on,off time in milliseconds"); +module_param_array(dev_hint, charp, NULL, 0000); MODULE_PARM_DESC(dev_hint, "Device node hints"); MODULE_DESCRIPTION("Philips & OEM USB webcam driver"); MODULE_AUTHOR("Luc Saillard "); MODULE_LICENSE("GPL"); -MODULE_ALIAS("pwcx"); -MODULE_VERSION( PWC_VERSION ); static int __init usb_pwc_init(void) { int i, sz; char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" }; - PWC_INFO("Philips webcam module version " PWC_VERSION " loaded.\n"); - PWC_INFO("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n"); - PWC_INFO("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n"); - PWC_INFO("the Creative WebCam 5 & Pro Ex, 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) { - PWC_ERROR("Framerate out of bounds (4-30).\n"); + Err("Framerate out of bounds (4-30).\n"); return -EINVAL; } default_fps = fps; - PWC_DEBUG_MODULE("Default framerate set to %d.\n", default_fps); + Info("Default framerate set to %d.\n", default_fps); } - if (size) { + if (size[0]) { /* string; try matching with array */ for (sz = 0; sz < PSZ_MAX; sz++) { if (!strcmp(sizenames[sz], size)) { /* Found! */ @@ -1867,42 +2081,41 @@ static int __init usb_pwc_init(void) } } if (sz == PSZ_MAX) { - PWC_ERROR("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n"); + Err("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n"); return -EINVAL; } - PWC_DEBUG_MODULE("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y); + 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) { - PWC_ERROR("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES); + Err("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES); return -EINVAL; } - pwc_mbufs = mbufs; - PWC_DEBUG_MODULE("Number of image buffers set to %d.\n", pwc_mbufs); + default_mbufs = mbufs; + Info("Number of image buffers set to %d.\n", default_mbufs); } if (fbufs) { if (fbufs < 2 || fbufs > MAX_FRAMES) { - PWC_ERROR("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES); + Err("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES); return -EINVAL; } default_fbufs = fbufs; - PWC_DEBUG_MODULE("Number of frame buffers set to %d.\n", default_fbufs); + Info("Number of frame buffers set to %d.\n", default_fbufs); } -#if CONFIG_PWC_DEBUG - if (pwc_trace >= 0) { - PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace); + if (trace >= 0) { + Info("Trace options: 0x%04x\n", trace); + pwc_trace = trace; } -#endif if (compression >= 0) { if (compression > 3) { - PWC_ERROR("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n"); + Err("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n"); return -EINVAL; } pwc_preferred_compression = compression; - PWC_DEBUG_MODULE("Preferred compression set to %d.\n", pwc_preferred_compression); + Info("Preferred compression set to %d.\n", pwc_preferred_compression); } if (power_save) - PWC_DEBUG_MODULE("Enabling power save on open/close.\n"); + Info("Enabling power save on open/close.\n"); if (leds[0] >= 0) led_on = leds[0]; if (leds[1] >= 0) @@ -1933,14 +2146,14 @@ static int __init usb_pwc_init(void) dot++; /* Few sanity checks */ if (*dot != '\0' && dot > colon) { - PWC_ERROR("Malformed camera hint: the colon must be after the dot.\n"); + Err("Malformed camera hint: the colon must be after the dot.\n"); return -EINVAL; } if (*colon == '\0') { /* No colon */ if (*dot != '\0') { - PWC_ERROR("Malformed camera hint: no colon + device node given.\n"); + Err("Malformed camera hint: no colon + device node given.\n"); return -EINVAL; } else { @@ -1965,27 +2178,28 @@ static int __init usb_pwc_init(void) device_hint[i].serial_number[k] = '\0'; } } - PWC_TRACE("device_hint[%d]:\n", i); - PWC_TRACE(" type : %d\n", device_hint[i].type); - PWC_TRACE(" serial# : %s\n", device_hint[i].serial_number); - PWC_TRACE(" node : %d\n", device_hint[i].device_node); +#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 */ - PWC_DEBUG_PROBE("Registering driver at address 0x%p.\n", &pwc_driver); + Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver); return usb_register(&pwc_driver); } static void __exit usb_pwc_exit(void) { - PWC_DEBUG_MODULE("Deregistering driver.\n"); + Trace(TRACE_MODULE, "Deregistering driver.\n"); usb_deregister(&pwc_driver); - PWC_INFO("Philips webcam module removed.\n"); + Info("Philips webcam module removed.\n"); } module_init(usb_pwc_init); module_exit(usb_pwc_exit); -/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */