📄 vivi_usb_drv.c
字号:
ret = 0; break; } } up(&(vivi->sem)); return ret ? ret : bytes_read;}static intioctl_vivi_s3c2410(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct usb_device *dev; kdev_t vivi_minor; vivi_minor = USB_VIVI_MINOR(inode); if (!p_vivi_table[vivi_minor]) { err("ioctl_vivi_s3c2410(%d): invalid vivi_minor", vivi_minor); return -ENODEV; } dev = p_vivi_table[vivi_minor]->vivi_dev; switch (cmd) { case VIVI_IOCTL_VENDOR : return (put_user(dev->descriptor.idVendor, (unsigned int *) arg)); case VIVI_IOCTL_PRODUCT : return (put_user(dev->descriptor.idProduct, (unsigned int *) arg)); case VIVI_IOCTL_CTRLMSG: { struct ctrlmsg_ioctl { usb_devrequest req; void *data; } cmsg; int pipe, nb, ret; unsigned char buf[64]; if (copy_from_user(&cmsg, (void *)arg, sizeof(cmsg))) return -EFAULT; nb = le16_to_cpup(&cmsg.req.length); if (nb > sizeof(buf)) return -EINVAL; if ((cmsg.req.requesttype & 0x80) == 0) { pipe = usb_sndctrlpipe(dev, 0); if (nb > 0 && copy_from_user(buf, cmsg.data, nb)) return -EFAULT; } else { pipe = usb_rcvctrlpipe(dev, 0); } ret = usb_control_msg(dev, pipe, cmsg.req.request, cmsg.req.requesttype, le16_to_cpup(&cmsg.req.value), le16_to_cpup(&cmsg.req.index), buf, nb, HZ); if (ret < 0) { err("ioctl_vivi_s3c2410(%d): control_msg returned %d\n", vivi_minor, ret); return -EIO; } if (nb > 0 && (cmsg.req.requesttype & 0x80) && copy_to_user(cmsg.data, buf, nb)) return -EFAULT; return 0; } default: return -ENOTTY; } return 0;}static structfile_operations usb_vivi_s3c2410_fops = { read: read_vivi_s3c2410, write: write_vivi_s3c2410, ioctl: ioctl_vivi_s3c2410, open: open_vivi_s3c2410, release: close_vivi_s3c2410,};static void *probe_vivi_s3c2410(struct usb_device *dev, unsigned int ifnum, const struct usb_device_id *id){ struct vivi_usb_data *vivi; struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *endpoint; int ep_cnt; int ix; kdev_t vivi_minor; char valid_device = 0; char have_bulk_in, have_bulk_out, have_intr; char name[10]; if (vendor != -1 && product != -1) { info("probe_vivi_s3c2410: User specified USB vivi_s3c2410 -- Vendor:Product - %x:%x", vendor, product); } dbg("probe_vivi_s3c2410: USB dev address:%p", dev); dbg("probe_vivi_s3c2410: ifnum:%u", ifnum);/* * 1. Check Vendor/Product * 2. Determine/Assign Bulk Endpoints */ for (ix = 0; ix < sizeof (vivi_s3c2410_device_ids) / sizeof (struct usb_device_id); ix++) { if ((dev->descriptor.idVendor == vivi_s3c2410_device_ids [ix].idVendor) && (dev->descriptor.idProduct == vivi_s3c2410_device_ids [ix].idProduct)) { valid_device = 1; break; } } if (dev->descriptor.idVendor == vendor && /* User specified */ dev->descriptor.idProduct == product) { /* User specified */ valid_device = 1; } if (!valid_device) return NULL; /* We didn't find anything pleasing *//* * After this point we can be a little noisy about what we are trying to * configure. */ if (dev->descriptor.bNumConfigurations != 1) { info("probe_vivi_s3c2410: Only one device configuration is supported."); return NULL; } if (dev->config[0].bNumInterfaces != 1) { info("probe_vivi_s3c2410: Only one device interface is supported."); return NULL; } interface = dev->config[0].interface[ifnum].altsetting; endpoint = interface[ifnum].endpoint;/* * Start checking for two bulk endpoints: bulk in and/or bulk out */ info("probe_vivi_s3c2410: Number of Endpoints:%d", (int) interface->bNumEndpoints); ep_cnt = have_bulk_in = have_bulk_out = 0; while (ep_cnt < interface->bNumEndpoints) { if (!have_bulk_in && IS_EP_BULK_IN(endpoint[ep_cnt])) { have_bulk_in = endpoint[ep_cnt].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; ep_cnt++; info("probe_vivi_s3c2410: bulk_in_ep:%d", have_bulk_in); continue; } if (!have_bulk_out && IS_EP_BULK_OUT(endpoint[ep_cnt])) { have_bulk_out = endpoint[ep_cnt].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; ep_cnt++; info("probe_vivi_s3c2410: bulk_out_ep:%d", have_bulk_out); continue; } info("probe_vivi_s3c2410: Undetected endpoint -- consult Documentation/usb/scanner.txt."); return NULL; /* Shouldn't ever get here unless we have something weird */ }/* * Perform a quick check to make sure that everything worked as it * should have. */ if (!have_bulk_in || !have_bulk_out) { info("probe_vivi_s3c2410: Two bulk endpoints required."); return NULL; }/* * Determine a minor number and initialize the structure associated * with it. The problem with this is that we are counting on the fact * that the user will sequentially add device nodes for the vivi_s3c2410 * devices. */ down(&vivi_mutex); for (vivi_minor = 0; vivi_minor < VIVI_MAX_MNR; vivi_minor++) { if (!p_vivi_table[vivi_minor]) break; }/* Check to make sure that the last slot isn't already taken */ if (p_vivi_table[vivi_minor]) { err("probe_vivi_s3c2410: No more minor devices remaining."); up(&vivi_mutex); return NULL; } dbg("probe_vivi_s3c2410: Allocated minor:%d", vivi_minor); if (!(vivi = kmalloc (sizeof (struct vivi_usb_data), GFP_KERNEL))) { err("probe_vivi_s3c2410: Out of memory."); up(&vivi_mutex); return NULL; } memset (vivi, 0, sizeof(struct vivi_usb_data)); init_MUTEX(&(vivi->sem)); /* Initializes to unlocked */ dbg ("probe_vivi_s3c2410(%d): Address of vivi:%p", vivi_minor, vivi);/* Ok, now initialize all the relevant values */ if (!(vivi->obuf = (char *)kmalloc(OBUF_SIZE, GFP_KERNEL))) { err("probe_vivi_s3c2410(%d): Not enough memory for the output buffer.", vivi_minor); kfree(vivi); up(&vivi_mutex); return NULL; } dbg("probe_vivi_s3c2410(%d): obuf address:%p", vivi_minor, vivi->obuf); if (!(vivi->ibuf = (char *)kmalloc(IBUF_SIZE, GFP_KERNEL))) { err("probe_vivi_s3c2410(%d): Not enough memory for the input buffer.", vivi_minor); kfree(vivi->obuf); kfree(vivi); up(&vivi_mutex); return NULL; } dbg("probe_vivi_s3c2410(%d): ibuf address:%p", vivi_minor, vivi->ibuf); vivi->rd_nak_timeout = HZ * 40; if (read_timeout > 0) { /* User specified read timeout overrides everything */ info("probe_vivi_s3c2410: User specified USB read timeout - %d", read_timeout); vivi->rd_nak_timeout = read_timeout; } vivi->bulk_in_ep = have_bulk_in; vivi->bulk_out_ep = have_bulk_out; vivi->intr_ep = have_intr; vivi->present = 1; vivi->vivi_dev = dev; vivi->vivi_minor = vivi_minor; vivi->isopen = 0; sprintf(name, "vivi_s3c2410%d", vivi->vivi_minor); vivi->devfs = devfs_register(usb_devfs_handle, name, DEVFS_FL_DEFAULT, USB_MAJOR, VIVI_BASE_MNR + vivi->vivi_minor, S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, &usb_vivi_s3c2410_fops, NULL); if (vivi->devfs == NULL) dbg("vivi_s3c2410%d: device node registration failed", vivi_minor); p_vivi_table[vivi_minor] = vivi; up(&vivi_mutex); return vivi;}static voiddisconnect_vivi_s3c2410(struct usb_device *dev, void *ptr){ struct vivi_usb_data *vivi = (struct vivi_usb_data *) ptr; down (&vivi_mutex); down (&(vivi->sem)); if(vivi->intr_ep) { dbg("disconnect_vivi_s3c2410(%d): Unlinking IRQ URB", vivi->vivi_minor); usb_unlink_urb(&vivi->vivi_irq); } usb_driver_release_interface(&vivi_s3c2410_driver, &vivi->vivi_dev->actconfig->interface[vivi->ifnum]); kfree(vivi->ibuf); kfree(vivi->obuf); dbg("disconnect_vivi_s3c2410: De-allocating minor:%d", vivi->vivi_minor); devfs_unregister(vivi->devfs); p_vivi_table[vivi->vivi_minor] = NULL; up (&(vivi->sem)); kfree (vivi); up (&vivi_mutex);}static structusb_driver vivi_s3c2410_driver = { name: "usb_vivi_s3c2410", probe: probe_vivi_s3c2410, disconnect: disconnect_vivi_s3c2410, fops: &usb_vivi_s3c2410_fops, minor: VIVI_BASE_MNR, id_table: NULL, /* This would be vivi_s3c2410_device_ids, but we need to check every USB device, in case we match a user defined vendor/product ID. */};void __exitusb_vivi_s3c2410_exit(void){ usb_deregister(&vivi_s3c2410_driver);}int __initusb_vivi_s3c2410_init (void){ if (usb_register(&vivi_s3c2410_driver) < 0) return -1; info(DRIVER_VERSION ":" DRIVER_DESC); return 0;}module_init(usb_vivi_s3c2410_init);module_exit(usb_vivi_s3c2410_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -