📄 zc030x_main.c
字号:
up (&dev->sem); /* Return */ return -ENODEV; } /* Stop isochronous transfers */ zc030x_isoc_stop(dev); /* Wake up frame queue */ for (i = 0; i < ZC030X_NUMFRAMES; i++) { if (waitqueue_active(&dev->frame[i].wq)) wake_up_interruptible(&dev->frame[i].wq); } /* Check if the device is already unplugged */ if(!dev->present && !dev->open) { /* the device was unplugged before the file was released */ up (&dev->sem);#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) MOD_DEC_USE_COUNT;#endif return 0; } /* Decrement our usage count for the device */ --dev->open; /* How could this happen ? */ if (dev->open <= 0) { dev->open = 0; } /* decrement our usage count for the module */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) MOD_DEC_USE_COUNT;#endif /* Release the lock */ up (&dev->sem); /* Okay exit */ PDEBUG(3,"<< zc030x_release()"); return 0;}/* Read a frame from the device */ssize_t zc030x_read (struct file *file, char *buf, size_t count, loff_t * ppos){ /* Iterator */ int i = 0; /* Frame index */ int frmx = -1; /* Check for non blocking reading */ int noblock = file->f_flags&O_NONBLOCK; /* Need to have a temporary frame */ zc030x_frame *frame; /* Get the video device */ struct video_device *vdev = video_devdata(file); /* And the USB device too */ struct usb_zc030x *dev; /* Debug this function */ PDEBUG(3,">> zc030x_read()"); /* Check parameter */ if (vdev == NULL) { PDEBUG (2, "vdev is NULL, returning"); return 0; } /* Get USB device too */ dev = video_get_drvdata(vdev); if (dev == NULL) { PDEBUG (2, "dev is NULL, returning"); return 0; } /* Check parameter */ if (buf == NULL) { PDEBUG(2, "Bad NULL buffer to store the frame"); return -EFAULT; } /* What is this ? */ PDEBUG(4, "%d bytes, noblock=%d", count, noblock); /* Check if a signal is pending, so return interrupted */ if (signal_pending(current)) return -EINTR; /* Lock this object */ down (&dev->sem); /* Verify that the device wasn't unplugged */ if (!dev->present) { up (&dev->sem); return -ENODEV; } /* Check the device was streaming */ if(!dev->streaming) { up(&dev->sem); return -EIO; } /* Release the device before sleeping */ up(&dev->sem); /* Set the frame to wait on */ if (down_trylock(&dev->frame[0].Lock)) { return -EIO; } /* Change this state */ /* Now this frame is ready to be grabbed into */ dev->frame[0].GrabState = FRAME_READY; /* Release it */ up(&dev->frame[0].Lock); /* Sleep until this frame is available */ PDEBUG(4,"sleep interruptible!"); interruptible_sleep_on(&dev->frame[0].wq); PDEBUG(4,"signal pending test!"); /* And relock the device now */ down (&dev->sem); /* Check if a signal is pending, so return interrupted */ if (signal_pending(current)) { up( &dev->sem); return -EINTR; } /* Now we should have a frame */ if (dev->frame[0].GrabState == FRAME_DONE) frmx = i; /* Found at index */ PDEBUG(4, "Frame number: %d", frmx); if (frmx < 0) { /* Done frame not found */ PDEBUG(2, "frame not ready to be read %d", frmx); up (&dev->sem); return -EFAULT; } /* Get the frame */ frame = &dev->frame[frmx]; /* Lock the frame too */ down (&frame->Lock); /* Need to check the user demand */ i = (frame->HeaderWidth * frame->HeaderHeight * frame->Depth) >> 3; /* To avoid overflow (ie->reading kernel memory space) */ if (copy_to_user(buf, frame->Data, count < i ? count : i)) { PDEBUG(2, "Copy failed! %d bytes not copied", i); up (&frame->Lock); up (&dev->sem); return -EFAULT; } PDEBUG(2, "Maximum size is %dx%dx%d = %d asked %d", frame->HeaderWidth, frame->HeaderHeight, frame->Depth, i, count); /* Release the frame */ frame->GrabState = FRAME_READY; /* Unlock it */ up(&frame->Lock); /* Unlock the device */ up (&dev->sem); /* Return */ PDEBUG(3,"<< zc030x_read()"); return count < i ? count : i;}/* Map a kernel memory page to user space */int zc030x_mmap(struct file *file, struct vm_area_struct *vma){ /* Start address */ unsigned long start = vma->vm_start; /* Size of mapping */ unsigned long size = vma->vm_end - vma->vm_start; /* The page */ unsigned long page; /* And the position */ unsigned long pos; /* Get the video device */ struct video_device *vdev = video_devdata(file); /* And the USB device too */ struct usb_zc030x *dev; /* Debug this function */ PDEBUG(3,">> zc030x_mmap()"); /* Check parameter */ if (vdev == NULL) { PDEBUG (2, "vdev is NULL, returning"); return 0; } /* Get USB device too */ dev = video_get_drvdata(vdev); if (dev == NULL) { PDEBUG (2, "dev is NULL, returning"); return 0; } /* Check if the device is still here */ if (!dev->present) return -EIO; /* Debug here too */ PDEBUG(4, "mmap: %ld (%lX) bytes", size, size); /* Check the asked size */ if (size > (((ZC030X_NUMFRAMES * MAX_VIDEODATA_SIZE) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) return -EINVAL; /* Convert the kernel address to userspace */ pos = (unsigned long)dev->fbuf; /* And remap all concerned page to shared space */ while (size > 0) {#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10) page = page_to_pfn(vmalloc_to_page((void *)pos)); if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))#else page = kvirt_to_pa(pos);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) || defined (RH9_REMAP) if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))#else /* RH9_REMAP */ if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED))#endif /* RH9_REMAP */#endif return -EAGAIN; start += PAGE_SIZE; pos += PAGE_SIZE; if (size > PAGE_SIZE) size -= PAGE_SIZE; else size = 0; } /* Okay return */ return 0;}/* Perform IOCTLs now */int zc030x_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ /* Return code */ int rc ; /* Get the video device */ struct video_device *vdev = video_devdata(file); /* And the USB device too */ struct usb_zc030x *dev; /* Debug this function */ PDEBUG(3,">> zc030x_ioctl()"); /* Check parameter */ if (vdev == NULL) { PDEBUG (2, "vdev is NULL, returning"); return 0; } /* Get USB device too */ dev = video_get_drvdata(vdev); if (dev == NULL) { PDEBUG (2, "dev is NULL, returning"); return 0; } /* Check if the device is still here */ if (!dev->present) return -EIO; /* Zc030x specific ioctl */ switch (cmd) { /* Users asked register mapping */ case ZCI2CREGISTERMAP: { /* Call the register mapping function */ /* //unsigned char buf[1]; unsigned char val[255]; unsigned char prev = 0; int ret; int i; struct register_map * prm = (struct register_map*) arg; zc030x_i2c_init(dev->udev, 0x0c); // Write : PDEBUG(2, "HHHHHH ------------------------- Separator --------------"); for (i = 0; i < 256; i ++) { // Save previous value (bug reported on ML) prev = zc030x_i2c_reg_read(dev->udev, i, 1); PDEBUG(2, "HHHHHH Read %02X at address %02X", prev, i); prm[i].addr = i; prm[i].value = 0xff; prm[i].mode = RM_ReadWrite; zc030x_i2c_reg_write(dev->udev, i, 0xff); val[i] = zc030x_i2c_reg_read(dev->udev, i, 1); if (val[i] != 0xff) { PDEBUG(2, "REGISTERMAP: [FF] (%02X) contains some read only bit with %02X value", i, val[i]); prm[i].value = val[i]; if (val[i] == 0) prm[i].mode = RM_Unused; } zc030x_i2c_reg_write(dev->udev, i, 0x00); ret = zc030x_i2c_reg_read(dev->udev, i, 1); if (ret != 0x00) { PDEBUG(2, "REGISTERMAP: [00] (%02X) contains some read only bit with %02X value", i, ret); } if (val[i] == ret && ret != 00) { PDEBUG(2, "REGISTERMAP-OK: [ID] (%02X) is read only with %02X value", i, ret); prm[i].addr = i; prm[i].value = ret; prm[i].mode = RM_ReadOnly; } // Restore previous value zc030x_i2c_reg_write(dev->udev, i, prev); } */ /* And return */ rc = 0; break; } /* User asked sensor identification */ case ZCIDSENSOR: { /* Call sensor identification function now */ //unsigned char buf[1]; int ret = 0; /* Currently not supported */ ret = 0; /* struct sensor_list * psl = (struct sensor_list*) arg; PDEBUG (2, ">>> ZCIDSENSOR asked for : %s, (%d)",psl->name, psl->id); // Let's try to read the i2c first register (I've no idea about how to read an I2C register but...) //buf[0] = 0x00; // Okay, try to find the sensor given its id usb_set_interface (dev->udev, 0, 0); //fuck! as this has gone to main.c and is declared extern here, sizeof doesn't work! //ret = zc030x_find_sensor_by_id(dev->udev, slist, sizeof(slist) / sizeof(slist[0])); ret = zc030x_find_sensor_by_id(dev->udev, slist, 16); usb_set_interface (dev->udev, 0, 7); if (ret != -1) { psl->id = slist[ret].id; sprintf(psl->name, "%s", slist[ret].name); psl->minwidth = slist[ret].minwidth; psl->maxwidth = slist[ret].maxwidth; psl->minheight = slist[ret].minheight; psl->maxheight = slist[ret].maxheight; } else { psl->id = 0; sprintf(psl->name, "Unknown"); psl->minwidth = 0; psl->maxwidth = 0; psl->minheight = 0; psl->maxheight = 0; } psl->i2c_sig = NULL; PDEBUG (2, "<<< ZCIDSENSOR asked for : %s, (%d)",psl->name, psl->id); */ /* Okay return now */ rc = 0; break; } /* Video for Linux specific IOCTLs */ default: rc = video_usercopy(inode, file, cmd, arg, zc030x_v4l_ioctl); } /* Return now */ PDEBUG (2, "<< zc030x_ioctl() arg = %08X", (unsigned int)arg); return rc;}/* Module loading */static int __init usb_zc030x_init (void){ int result; PDEBUG(1,"Loading experimental zc030x... \n"); /* register this driver with the USB subsystem */ result = usb_register (&zc030x_driver); if (result < 0) { err ("usb_register failed for the " __FILE__ " driver. Error number %d", result); return -1; } PDEBUG (5, DRIVER_DESC " " DRIVER_VERSION);#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)//TODO: proc entry has been temorarily removed zc030x_proc_create();#endif return 0;}/* Module unloading */static void __exit usb_zc030x_exit (void){#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)//TODO: proc entry management zc030x_proc_destroy();#endif /* stop isoc stream (if streaming) ) */ /* deregister this driver with the USB subsystem */ PDEBUG (1,"Unloading experimental zc030x.\n"); usb_deregister (&zc030x_driver);}module_init (usb_zc030x_init);module_exit (usb_zc030x_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -