📄 devio.c
字号:
return alts->desc.bInterfaceNumber; } } } return -ENOENT; }static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsigned int index){ int ret = 0; if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype)) return 0; index &= 0xff; switch (requesttype & USB_RECIP_MASK) { case USB_RECIP_ENDPOINT: if ((ret = findintfep(ps->dev, index)) >= 0) ret = checkintf(ps, ret); break; case USB_RECIP_INTERFACE: ret = checkintf(ps, index); break; } return ret;}/* * file operations */static int usbdev_open(struct inode *inode, struct file *file){ struct usb_device *dev; struct dev_state *ps; int ret; /* * no locking necessary here, as chrdev_open has the kernel lock * (still acquire the kernel lock for safety) */ ret = -ENOMEM; if (!(ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL))) goto out_nolock; lock_kernel(); ret = -ENOENT; dev = usb_get_dev(inode->u.generic_ip); if (!dev) { kfree(ps); goto out; } ret = 0; ps->dev = dev; ps->file = file; spin_lock_init(&ps->lock); INIT_LIST_HEAD(&ps->async_pending); INIT_LIST_HEAD(&ps->async_completed); init_waitqueue_head(&ps->wait); ps->discsignr = 0; ps->disctask = current; ps->disccontext = NULL; ps->ifclaimed = 0; wmb(); list_add_tail(&ps->list, &dev->filelist); file->private_data = ps; out: unlock_kernel(); out_nolock: return ret;}static int usbdev_release(struct inode *inode, struct file *file){ struct dev_state *ps = (struct dev_state *)file->private_data; struct usb_device *dev = ps->dev; unsigned int ifnum; down(&dev->serialize); list_del_init(&ps->list); if (connected(dev)) { for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed); ifnum++) if (test_bit(ifnum, &ps->ifclaimed)) releaseintf(ps, ifnum); destroy_all_async(ps); } up(&dev->serialize); usb_put_dev(dev); ps->dev = NULL; kfree(ps); return 0;}static int proc_control(struct dev_state *ps, void __user *arg){ struct usb_device *dev = ps->dev; struct usbdevfs_ctrltransfer ctrl; unsigned int tmo; unsigned char *tbuf; int i, j, ret; if (copy_from_user(&ctrl, arg, sizeof(ctrl))) return -EFAULT; if ((ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex))) return ret; if (ctrl.wLength > PAGE_SIZE) return -EINVAL; if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL))) return -ENOMEM; tmo = (ctrl.timeout * HZ + 999) / 1000; if (ctrl.bRequestType & 0x80) { if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.wLength)) { free_page((unsigned long)tbuf); return -EINVAL; } snoop(&dev->dev, "control read: bRequest=%02x bRrequestType=%02x wValue=%04x wIndex=%04x\n", ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex); i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo); if ((i > 0) && ctrl.wLength) { if (usbfs_snoop) { dev_info(&dev->dev, "control read: data "); for (j = 0; j < ctrl.wLength; ++j) printk ("%02x ", (unsigned char)(tbuf)[j]); printk("\n"); } if (copy_to_user(ctrl.data, tbuf, ctrl.wLength)) { free_page((unsigned long)tbuf); return -EFAULT; } } } else { if (ctrl.wLength) { if (copy_from_user(tbuf, ctrl.data, ctrl.wLength)) { free_page((unsigned long)tbuf); return -EFAULT; } } snoop(&dev->dev, "control write: bRequest=%02x bRrequestType=%02x wValue=%04x wIndex=%04x\n", ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex); if (usbfs_snoop) { dev_info(&dev->dev, "control write: data: "); for (j = 0; j < ctrl.wLength; ++j) printk ("%02x ", (unsigned char)(tbuf)[j]); printk("\n"); } i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, tbuf, ctrl.wLength, tmo); } free_page((unsigned long)tbuf); if (i<0) { dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL " "failed cmd %s rqt %u rq %u len %u ret %d\n", current->comm, ctrl.bRequestType, ctrl.bRequest, ctrl.wLength, i); } return i;}static int proc_bulk(struct dev_state *ps, void __user *arg){ struct usb_device *dev = ps->dev; struct usbdevfs_bulktransfer bulk; unsigned int tmo, len1, pipe; int len2; unsigned char *tbuf; int i, ret; if (copy_from_user(&bulk, arg, sizeof(bulk))) return -EFAULT; if ((ret = findintfep(ps->dev, bulk.ep)) < 0) return ret; if ((ret = checkintf(ps, ret))) return ret; if (bulk.ep & USB_DIR_IN) pipe = usb_rcvbulkpipe(dev, bulk.ep & 0x7f); else pipe = usb_sndbulkpipe(dev, bulk.ep & 0x7f); if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN))) return -EINVAL; len1 = bulk.len; if (!(tbuf = kmalloc(len1, GFP_KERNEL))) return -ENOMEM; tmo = (bulk.timeout * HZ + 999) / 1000; if (bulk.ep & 0x80) { if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) { kfree(tbuf); return -EINVAL; } i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); if (!i && len2) { if (copy_to_user(bulk.data, tbuf, len2)) { kfree(tbuf); return -EFAULT; } } } else { if (len1) { if (copy_from_user(tbuf, bulk.data, len1)) { kfree(tbuf); return -EFAULT; } } i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); } kfree(tbuf); if (i < 0) { dev_warn(&dev->dev, "usbfs: USBDEVFS_BULK failed " "ep 0x%x len %u ret %d\n", bulk.ep, bulk.len, i); return i; } return len2;}static int proc_resetep(struct dev_state *ps, void __user *arg){ unsigned int ep; int ret; if (get_user(ep, (unsigned int __user *)arg)) return -EFAULT; if ((ret = findintfep(ps->dev, ep)) < 0) return ret; if ((ret = checkintf(ps, ret))) return ret; usb_settoggle(ps->dev, ep & 0xf, !(ep & USB_DIR_IN), 0); return 0;}static int proc_clearhalt(struct dev_state *ps, void __user *arg){ unsigned int ep; int pipe; int ret; if (get_user(ep, (unsigned int __user *)arg)) return -EFAULT; if ((ret = findintfep(ps->dev, ep)) < 0) return ret; if ((ret = checkintf(ps, ret))) return ret; if (ep & USB_DIR_IN) pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f); else pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f); return usb_clear_halt(ps->dev, pipe);} static int proc_getdriver(struct dev_state *ps, void __user *arg){ struct usbdevfs_getdriver gd; struct usb_interface *intf; int ret; if (copy_from_user(&gd, arg, sizeof(gd))) return -EFAULT; down_read(&usb_bus_type.subsys.rwsem); intf = usb_ifnum_to_if(ps->dev, gd.interface); if (!intf || !intf->dev.driver) ret = -ENODATA; else { strncpy(gd.driver, intf->dev.driver->name, sizeof(gd.driver)); ret = (copy_to_user(arg, &gd, sizeof(gd)) ? -EFAULT : 0); } up_read(&usb_bus_type.subsys.rwsem); return ret;}static int proc_connectinfo(struct dev_state *ps, void __user *arg){ struct usbdevfs_connectinfo ci; ci.devnum = ps->dev->devnum; ci.slow = ps->dev->speed == USB_SPEED_LOW; if (copy_to_user(arg, &ci, sizeof(ci))) return -EFAULT; return 0;}static int proc_resetdevice(struct dev_state *ps){ return __usb_reset_device(ps->dev);}static int proc_setintf(struct dev_state *ps, void __user *arg){ struct usbdevfs_setinterface setintf; int ret; if (copy_from_user(&setintf, arg, sizeof(setintf))) return -EFAULT; if ((ret = checkintf(ps, setintf.interface))) return ret; return usb_set_interface(ps->dev, setintf.interface, setintf.altsetting);}static int proc_setconfig(struct dev_state *ps, void __user *arg){ unsigned int u; int status = 0; struct usb_host_config *actconfig; if (get_user(u, (unsigned int __user *)arg)) return -EFAULT; actconfig = ps->dev->actconfig; /* Don't touch the device if any interfaces are claimed. * It could interfere with other drivers' operations, and if * an interface is claimed by usbfs it could easily deadlock. */ if (actconfig) { int i; for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) { if (usb_interface_claimed(actconfig->interface[i])) { dev_warn (&ps->dev->dev, "usbfs: interface %d claimed " "while '%s' sets config #%d\n", actconfig->interface[i] ->cur_altsetting ->desc.bInterfaceNumber, current->comm, u);#if 0 /* FIXME: enable in 2.6.10 or so */ status = -EBUSY; break;#endif } } } /* SET_CONFIGURATION is often abused as a "cheap" driver reset, * so avoid usb_set_configuration()'s kick to sysfs */ if (status == 0) { if (actconfig && actconfig->desc.bConfigurationValue == u) status = usb_reset_configuration(ps->dev); else status = usb_set_configuration(ps->dev, u); } return status;}static int proc_submiturb(struct dev_state *ps, void __user *arg){ struct usbdevfs_urb uurb; struct usbdevfs_iso_packet_desc *isopkt = NULL; struct usb_endpoint_descriptor *ep_desc; struct async *as; struct usb_ctrlrequest *dr = NULL; unsigned int u, totlen, isofrmlen; int ret, interval = 0, ifnum = -1; if (copy_from_user(&uurb, arg, sizeof(uurb))) return -EFAULT; if (uurb.flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK| URB_NO_FSBR|URB_ZERO_PACKET)) return -EINVAL; if (!uurb.buffer) return -EINVAL; if (uurb.signr != 0 && (uurb.signr < SIGRTMIN || uurb.signr > SIGRTMAX)) return -EINVAL; if (!(uurb.type == USBDEVFS_URB_TYPE_CONTROL && (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) == 0)) { if ((ifnum = findintfep(ps->dev, uurb.endpoint)) < 0) return ifnum; if ((ret = checkintf(ps, ifnum))) return ret; } switch(uurb.type) { case USBDEVFS_URB_TYPE_CONTROL: if ((uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) != 0) { if (!(ep_desc = usb_epnum_to_ep_desc(ps->dev, uurb.endpoint))) return -ENOENT; if ((ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_CONTROL) return -EINVAL; } /* min 8 byte setup packet, max arbitrary */ if (uurb.buffer_length < 8 || uurb.buffer_length > PAGE_SIZE) return -EINVAL; if (!(dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL))) return -ENOMEM; if (copy_from_user(dr, uurb.buffer, 8)) { kfree(dr); return -EFAULT; } if (uurb.buffer_length < (le16_to_cpup(&dr->wLength) + 8)) { kfree(dr); return -EINVAL; } if ((ret = check_ctrlrecip(ps, dr->bRequestType, le16_to_cpup(&dr->wIndex)))) { kfree(dr); return ret; } uurb.endpoint = (uurb.endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK); uurb.number_of_packets = 0; uurb.buffer_length = le16_to_cpup(&dr->wLength); uurb.buffer += 8; if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length)) { kfree(dr); return -EFAULT; } break; case USBDEVFS_URB_TYPE_BULK: uurb.number_of_packets = 0; if (uurb.buffer_length > 16384) return -EINVAL; if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length)) return -EFAULT; break; case USBDEVFS_URB_TYPE_ISO: /* arbitrary limit */ if (uurb.number_of_packets < 1 || uurb.number_of_packets > 128) return -EINVAL; if (!(ep_desc = usb_epnum_to_ep_desc(ps->dev, uurb.endpoint))) return -ENOENT; interval = 1 << min (15, ep_desc->bInterval - 1); isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb.number_of_packets; if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL))) return -ENOMEM; if (copy_from_user(isopkt, &((struct usbdevfs_urb __user *)arg)->iso_frame_desc, isofrmlen)) { kfree(isopkt); return -EFAULT; } for (totlen = u = 0; u < uurb.number_of_packets; u++) { if (isopkt[u].length > 1023) { kfree(isopkt); return -EINVAL; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -