diff options
Diffstat (limited to 'drivers/usb/core/devio.c')
| -rw-r--r-- | drivers/usb/core/devio.c | 326 | 
1 files changed, 234 insertions, 92 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 71dc5d768fa..257876ea03a 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -62,7 +62,7 @@  /* Mutual exclusion for removal, open, and release */  DEFINE_MUTEX(usbfs_mutex); -struct dev_state { +struct usb_dev_state {  	struct list_head list;      /* state list */  	struct usb_device *dev;  	struct file *file; @@ -81,7 +81,7 @@ struct dev_state {  struct async {  	struct list_head asynclist; -	struct dev_state *ps; +	struct usb_dev_state *ps;  	struct pid *pid;  	const struct cred *cred;  	unsigned int signr; @@ -118,7 +118,7 @@ module_param(usbfs_memory_mb, uint, 0644);  MODULE_PARM_DESC(usbfs_memory_mb,  		"maximum MB allowed for usbfs buffers (0 = no limit)"); -/* Hard limit, necessary to avoid aithmetic overflow */ +/* Hard limit, necessary to avoid arithmetic overflow */  #define USBFS_XFER_MAX		(UINT_MAX / 2 - 1000000)  static atomic_t usbfs_memory_usage;	/* Total memory currently allocated */ @@ -151,7 +151,7 @@ static void usbfs_decrease_memory_usage(unsigned amount)  	atomic_sub(amount, &usbfs_memory_usage);  } -static int connected(struct dev_state *ps) +static int connected(struct usb_dev_state *ps)  {  	return (!list_empty(&ps->list) &&  			ps->dev->state != USB_STATE_NOTATTACHED); @@ -184,7 +184,7 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)  static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes,  			   loff_t *ppos)  { -	struct dev_state *ps = file->private_data; +	struct usb_dev_state *ps = file->private_data;  	struct usb_device *dev = ps->dev;  	ssize_t ret = 0;  	unsigned len; @@ -307,7 +307,7 @@ static void free_async(struct async *as)  static void async_newpending(struct async *as)  { -	struct dev_state *ps = as->ps; +	struct usb_dev_state *ps = as->ps;  	unsigned long flags;  	spin_lock_irqsave(&ps->lock, flags); @@ -317,7 +317,7 @@ static void async_newpending(struct async *as)  static void async_removepending(struct async *as)  { -	struct dev_state *ps = as->ps; +	struct usb_dev_state *ps = as->ps;  	unsigned long flags;  	spin_lock_irqsave(&ps->lock, flags); @@ -325,7 +325,7 @@ static void async_removepending(struct async *as)  	spin_unlock_irqrestore(&ps->lock, flags);  } -static struct async *async_getcompleted(struct dev_state *ps) +static struct async *async_getcompleted(struct usb_dev_state *ps)  {  	unsigned long flags;  	struct async *as = NULL; @@ -340,7 +340,7 @@ static struct async *async_getcompleted(struct dev_state *ps)  	return as;  } -static struct async *async_getpending(struct dev_state *ps, +static struct async *async_getpending(struct usb_dev_state *ps,  					     void __user *userurb)  {  	struct async *as; @@ -448,7 +448,7 @@ static int copy_urb_data_to_user(u8 __user *userbuffer, struct urb *urb)  #define AS_CONTINUATION	1  #define AS_UNLINK	2 -static void cancel_bulk_urbs(struct dev_state *ps, unsigned bulk_addr) +static void cancel_bulk_urbs(struct usb_dev_state *ps, unsigned bulk_addr)  __releases(ps->lock)  __acquires(ps->lock)  { @@ -489,7 +489,7 @@ __acquires(ps->lock)  static void async_completed(struct urb *urb)  {  	struct async *as = urb->context; -	struct dev_state *ps = as->ps; +	struct usb_dev_state *ps = as->ps;  	struct siginfo sinfo;  	struct pid *pid = NULL;  	u32 secid = 0; @@ -529,7 +529,7 @@ static void async_completed(struct urb *urb)  	wake_up(&ps->wait);  } -static void destroy_async(struct dev_state *ps, struct list_head *list) +static void destroy_async(struct usb_dev_state *ps, struct list_head *list)  {  	struct urb *urb;  	struct async *as; @@ -551,7 +551,7 @@ static void destroy_async(struct dev_state *ps, struct list_head *list)  	spin_unlock_irqrestore(&ps->lock, flags);  } -static void destroy_async_on_interface(struct dev_state *ps, +static void destroy_async_on_interface(struct usb_dev_state *ps,  				       unsigned int ifnum)  {  	struct list_head *p, *q, hitlist; @@ -566,7 +566,7 @@ static void destroy_async_on_interface(struct dev_state *ps,  	destroy_async(ps, &hitlist);  } -static void destroy_all_async(struct dev_state *ps) +static void destroy_all_async(struct usb_dev_state *ps)  {  	destroy_async(ps, &ps->async_pending);  } @@ -585,7 +585,7 @@ static int driver_probe(struct usb_interface *intf,  static void driver_disconnect(struct usb_interface *intf)  { -	struct dev_state *ps = usb_get_intfdata(intf); +	struct usb_dev_state *ps = usb_get_intfdata(intf);  	unsigned int ifnum = intf->altsetting->desc.bInterfaceNumber;  	if (!ps) @@ -628,7 +628,7 @@ struct usb_driver usbfs_driver = {  	.resume =	driver_resume,  }; -static int claimintf(struct dev_state *ps, unsigned int ifnum) +static int claimintf(struct usb_dev_state *ps, unsigned int ifnum)  {  	struct usb_device *dev = ps->dev;  	struct usb_interface *intf; @@ -650,7 +650,7 @@ static int claimintf(struct dev_state *ps, unsigned int ifnum)  	return err;  } -static int releaseintf(struct dev_state *ps, unsigned int ifnum) +static int releaseintf(struct usb_dev_state *ps, unsigned int ifnum)  {  	struct usb_device *dev;  	struct usb_interface *intf; @@ -670,7 +670,7 @@ static int releaseintf(struct dev_state *ps, unsigned int ifnum)  	return err;  } -static int checkintf(struct dev_state *ps, unsigned int ifnum) +static int checkintf(struct usb_dev_state *ps, unsigned int ifnum)  {  	if (ps->dev->state != USB_STATE_CONFIGURED)  		return -EHOSTUNREACH; @@ -710,7 +710,7 @@ static int findintfep(struct usb_device *dev, unsigned int ep)  	return -ENOENT;  } -static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, +static int check_ctrlrecip(struct usb_dev_state *ps, unsigned int requesttype,  			   unsigned int request, unsigned int index)  {  	int ret = 0; @@ -769,6 +769,88 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,  	return ret;  } +static struct usb_host_endpoint *ep_to_host_endpoint(struct usb_device *dev, +						     unsigned char ep) +{ +	if (ep & USB_ENDPOINT_DIR_MASK) +		return dev->ep_in[ep & USB_ENDPOINT_NUMBER_MASK]; +	else +		return dev->ep_out[ep & USB_ENDPOINT_NUMBER_MASK]; +} + +static int parse_usbdevfs_streams(struct usb_dev_state *ps, +				  struct usbdevfs_streams __user *streams, +				  unsigned int *num_streams_ret, +				  unsigned int *num_eps_ret, +				  struct usb_host_endpoint ***eps_ret, +				  struct usb_interface **intf_ret) +{ +	unsigned int i, num_streams, num_eps; +	struct usb_host_endpoint **eps; +	struct usb_interface *intf = NULL; +	unsigned char ep; +	int ifnum, ret; + +	if (get_user(num_streams, &streams->num_streams) || +	    get_user(num_eps, &streams->num_eps)) +		return -EFAULT; + +	if (num_eps < 1 || num_eps > USB_MAXENDPOINTS) +		return -EINVAL; + +	/* The XHCI controller allows max 2 ^ 16 streams */ +	if (num_streams_ret && (num_streams < 2 || num_streams > 65536)) +		return -EINVAL; + +	eps = kmalloc(num_eps * sizeof(*eps), GFP_KERNEL); +	if (!eps) +		return -ENOMEM; + +	for (i = 0; i < num_eps; i++) { +		if (get_user(ep, &streams->eps[i])) { +			ret = -EFAULT; +			goto error; +		} +		eps[i] = ep_to_host_endpoint(ps->dev, ep); +		if (!eps[i]) { +			ret = -EINVAL; +			goto error; +		} + +		/* usb_alloc/free_streams operate on an usb_interface */ +		ifnum = findintfep(ps->dev, ep); +		if (ifnum < 0) { +			ret = ifnum; +			goto error; +		} + +		if (i == 0) { +			ret = checkintf(ps, ifnum); +			if (ret < 0) +				goto error; +			intf = usb_ifnum_to_if(ps->dev, ifnum); +		} else { +			/* Verify all eps belong to the same interface */ +			if (ifnum != intf->altsetting->desc.bInterfaceNumber) { +				ret = -EINVAL; +				goto error; +			} +		} +	} + +	if (num_streams_ret) +		*num_streams_ret = num_streams; +	*num_eps_ret = num_eps; +	*eps_ret = eps; +	*intf_ret = intf; + +	return 0; + +error: +	kfree(eps); +	return ret; +} +  static int match_devt(struct device *dev, void *data)  {  	return dev->devt == (dev_t) (unsigned long) data; @@ -791,11 +873,11 @@ static struct usb_device *usbdev_lookup_by_devt(dev_t devt)  static int usbdev_open(struct inode *inode, struct file *file)  {  	struct usb_device *dev = NULL; -	struct dev_state *ps; +	struct usb_dev_state *ps;  	int ret;  	ret = -ENOMEM; -	ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL); +	ps = kmalloc(sizeof(struct usb_dev_state), GFP_KERNEL);  	if (!ps)  		goto out_free_ps; @@ -852,7 +934,7 @@ static int usbdev_open(struct inode *inode, struct file *file)  static int usbdev_release(struct inode *inode, struct file *file)  { -	struct dev_state *ps = file->private_data; +	struct usb_dev_state *ps = file->private_data;  	struct usb_device *dev = ps->dev;  	unsigned int ifnum;  	struct async *as; @@ -883,7 +965,7 @@ static int usbdev_release(struct inode *inode, struct file *file)  	return 0;  } -static int proc_control(struct dev_state *ps, void __user *arg) +static int proc_control(struct usb_dev_state *ps, void __user *arg)  {  	struct usb_device *dev = ps->dev;  	struct usbdevfs_ctrltransfer ctrl; @@ -914,10 +996,8 @@ static int proc_control(struct dev_state *ps, void __user *arg)  	snoop(&dev->dev, "control urb: bRequestType=%02x "  		"bRequest=%02x wValue=%04x "  		"wIndex=%04x wLength=%04x\n", -		ctrl.bRequestType, ctrl.bRequest, -		__le16_to_cpup(&ctrl.wValue), -		__le16_to_cpup(&ctrl.wIndex), -		__le16_to_cpup(&ctrl.wLength)); +		ctrl.bRequestType, ctrl.bRequest, ctrl.wValue, +		ctrl.wIndex, ctrl.wLength);  	if (ctrl.bRequestType & 0x80) {  		if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data,  					       ctrl.wLength)) { @@ -972,7 +1052,7 @@ static int proc_control(struct dev_state *ps, void __user *arg)  	return ret;  } -static int proc_bulk(struct dev_state *ps, void __user *arg) +static int proc_bulk(struct usb_dev_state *ps, void __user *arg)  {  	struct usb_device *dev = ps->dev;  	struct usbdevfs_bulktransfer bulk; @@ -1045,7 +1125,21 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)  	return ret;  } -static int proc_resetep(struct dev_state *ps, void __user *arg) +static void check_reset_of_active_ep(struct usb_device *udev, +		unsigned int epnum, char *ioctl_name) +{ +	struct usb_host_endpoint **eps; +	struct usb_host_endpoint *ep; + +	eps = (epnum & USB_DIR_IN) ? udev->ep_in : udev->ep_out; +	ep = eps[epnum & 0x0f]; +	if (ep && !list_empty(&ep->urb_list)) +		dev_warn(&udev->dev, "Process %d (%s) called USBDEVFS_%s for active endpoint 0x%02x\n", +				task_pid_nr(current), current->comm, +				ioctl_name, epnum); +} + +static int proc_resetep(struct usb_dev_state *ps, void __user *arg)  {  	unsigned int ep;  	int ret; @@ -1058,11 +1152,12 @@ static int proc_resetep(struct dev_state *ps, void __user *arg)  	ret = checkintf(ps, ret);  	if (ret)  		return ret; +	check_reset_of_active_ep(ps->dev, ep, "RESETEP");  	usb_reset_endpoint(ps->dev, ep);  	return 0;  } -static int proc_clearhalt(struct dev_state *ps, void __user *arg) +static int proc_clearhalt(struct usb_dev_state *ps, void __user *arg)  {  	unsigned int ep;  	int pipe; @@ -1076,6 +1171,7 @@ static int proc_clearhalt(struct dev_state *ps, void __user *arg)  	ret = checkintf(ps, ret);  	if (ret)  		return ret; +	check_reset_of_active_ep(ps->dev, ep, "CLEAR_HALT");  	if (ep & USB_DIR_IN)  		pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f);  	else @@ -1084,7 +1180,7 @@ static int proc_clearhalt(struct dev_state *ps, void __user *arg)  	return usb_clear_halt(ps->dev, pipe);  } -static int proc_getdriver(struct dev_state *ps, void __user *arg) +static int proc_getdriver(struct usb_dev_state *ps, void __user *arg)  {  	struct usbdevfs_getdriver gd;  	struct usb_interface *intf; @@ -1103,7 +1199,7 @@ static int proc_getdriver(struct dev_state *ps, void __user *arg)  	return ret;  } -static int proc_connectinfo(struct dev_state *ps, void __user *arg) +static int proc_connectinfo(struct usb_dev_state *ps, void __user *arg)  {  	struct usbdevfs_connectinfo ci = {  		.devnum = ps->dev->devnum, @@ -1115,12 +1211,12 @@ static int proc_connectinfo(struct dev_state *ps, void __user *arg)  	return 0;  } -static int proc_resetdevice(struct dev_state *ps) +static int proc_resetdevice(struct usb_dev_state *ps)  {  	return usb_reset_device(ps->dev);  } -static int proc_setintf(struct dev_state *ps, void __user *arg) +static int proc_setintf(struct usb_dev_state *ps, void __user *arg)  {  	struct usbdevfs_setinterface setintf;  	int ret; @@ -1129,11 +1225,14 @@ static int proc_setintf(struct dev_state *ps, void __user *arg)  		return -EFAULT;  	if ((ret = checkintf(ps, setintf.interface)))  		return ret; + +	destroy_async_on_interface(ps, setintf.interface); +  	return usb_set_interface(ps->dev, setintf.interface,  			setintf.altsetting);  } -static int proc_setconfig(struct dev_state *ps, void __user *arg) +static int proc_setconfig(struct usb_dev_state *ps, void __user *arg)  {  	int u;  	int status = 0; @@ -1181,7 +1280,7 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg)  	return status;  } -static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, +static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb,  			struct usbdevfs_iso_packet_desc __user *iso_frame_desc,  			void __user *arg)  { @@ -1191,6 +1290,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  	struct usb_ctrlrequest *dr = NULL;  	unsigned int u, totlen, isofrmlen;  	int i, ret, is_in, num_sgs = 0, ifnum = -1; +	int number_of_packets = 0; +	unsigned int stream_id = 0;  	void *buf;  	if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP | @@ -1211,15 +1312,10 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  		if (ret)  			return ret;  	} -	if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) { -		is_in = 1; -		ep = ps->dev->ep_in[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; -	} else { -		is_in = 0; -		ep = ps->dev->ep_out[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; -	} +	ep = ep_to_host_endpoint(ps->dev, uurb->endpoint);  	if (!ep)  		return -ENOENT; +	is_in = (uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0;  	u = 0;  	switch(uurb->type) { @@ -1244,7 +1340,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  				      le16_to_cpup(&dr->wIndex));  		if (ret)  			goto error; -		uurb->number_of_packets = 0;  		uurb->buffer_length = le16_to_cpup(&dr->wLength);  		uurb->buffer += 8;  		if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) { @@ -1274,17 +1369,17 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  			uurb->type = USBDEVFS_URB_TYPE_INTERRUPT;  			goto interrupt_urb;  		} -		uurb->number_of_packets = 0;  		num_sgs = DIV_ROUND_UP(uurb->buffer_length, USB_SG_SIZE);  		if (num_sgs == 1 || num_sgs > ps->dev->bus->sg_tablesize)  			num_sgs = 0; +		if (ep->streams) +			stream_id = uurb->stream_id;  		break;  	case USBDEVFS_URB_TYPE_INTERRUPT:  		if (!usb_endpoint_xfer_int(&ep->desc))  			return -EINVAL;   interrupt_urb: -		uurb->number_of_packets = 0;  		break;  	case USBDEVFS_URB_TYPE_ISO: @@ -1294,15 +1389,16 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  			return -EINVAL;  		if (!usb_endpoint_xfer_isoc(&ep->desc))  			return -EINVAL; +		number_of_packets = uurb->number_of_packets;  		isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * -				   uurb->number_of_packets; +				   number_of_packets;  		if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))  			return -ENOMEM;  		if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) {  			ret = -EFAULT;  			goto error;  		} -		for (totlen = u = 0; u < uurb->number_of_packets; u++) { +		for (totlen = u = 0; u < number_of_packets; u++) {  			/*  			 * arbitrary limit need for USB 3.0  			 * bMaxBurst (0~15 allowed, 1~16 packets) @@ -1333,7 +1429,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  		ret = -EFAULT;  		goto error;  	} -	as = alloc_async(uurb->number_of_packets); +	as = alloc_async(number_of_packets);  	if (!as) {  		ret = -ENOMEM;  		goto error; @@ -1427,7 +1523,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  	as->urb->setup_packet = (unsigned char *)dr;  	dr = NULL;  	as->urb->start_frame = uurb->start_frame; -	as->urb->number_of_packets = uurb->number_of_packets; +	as->urb->number_of_packets = number_of_packets; +	as->urb->stream_id = stream_id;  	if (uurb->type == USBDEVFS_URB_TYPE_ISO ||  			ps->dev->speed == USB_SPEED_HIGH)  		as->urb->interval = 1 << min(15, ep->desc.bInterval - 1); @@ -1435,7 +1532,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  		as->urb->interval = ep->desc.bInterval;  	as->urb->context = as;  	as->urb->complete = async_completed; -	for (totlen = u = 0; u < uurb->number_of_packets; u++) { +	for (totlen = u = 0; u < number_of_packets; u++) {  		as->urb->iso_frame_desc[u].offset = totlen;  		as->urb->iso_frame_desc[u].length = isopkt[u].length;  		totlen += isopkt[u].length; @@ -1510,7 +1607,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  	return ret;  } -static int proc_submiturb(struct dev_state *ps, void __user *arg) +static int proc_submiturb(struct usb_dev_state *ps, void __user *arg)  {  	struct usbdevfs_urb uurb; @@ -1522,7 +1619,7 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg)  			arg);  } -static int proc_unlinkurb(struct dev_state *ps, void __user *arg) +static int proc_unlinkurb(struct usb_dev_state *ps, void __user *arg)  {  	struct urb *urb;  	struct async *as; @@ -1582,7 +1679,7 @@ err_out:  	return -EFAULT;  } -static struct async *reap_as(struct dev_state *ps) +static struct async *reap_as(struct usb_dev_state *ps)  {  	DECLARE_WAITQUEUE(wait, current);  	struct async *as = NULL; @@ -1605,7 +1702,7 @@ static struct async *reap_as(struct dev_state *ps)  	return as;  } -static int proc_reapurb(struct dev_state *ps, void __user *arg) +static int proc_reapurb(struct usb_dev_state *ps, void __user *arg)  {  	struct async *as = reap_as(ps);  	if (as) { @@ -1618,7 +1715,7 @@ static int proc_reapurb(struct dev_state *ps, void __user *arg)  	return -EIO;  } -static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg) +static int proc_reapurbnonblock(struct usb_dev_state *ps, void __user *arg)  {  	int retval;  	struct async *as; @@ -1633,37 +1730,37 @@ static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg)  }  #ifdef CONFIG_COMPAT -static int proc_control_compat(struct dev_state *ps, +static int proc_control_compat(struct usb_dev_state *ps,  				struct usbdevfs_ctrltransfer32 __user *p32)  { -        struct usbdevfs_ctrltransfer __user *p; -        __u32 udata; -        p = compat_alloc_user_space(sizeof(*p)); -        if (copy_in_user(p, p32, (sizeof(*p32) - sizeof(compat_caddr_t))) || -            get_user(udata, &p32->data) || +	struct usbdevfs_ctrltransfer __user *p; +	__u32 udata; +	p = compat_alloc_user_space(sizeof(*p)); +	if (copy_in_user(p, p32, (sizeof(*p32) - sizeof(compat_caddr_t))) || +	    get_user(udata, &p32->data) ||  	    put_user(compat_ptr(udata), &p->data))  		return -EFAULT; -        return proc_control(ps, p); +	return proc_control(ps, p);  } -static int proc_bulk_compat(struct dev_state *ps, +static int proc_bulk_compat(struct usb_dev_state *ps,  			struct usbdevfs_bulktransfer32 __user *p32)  { -        struct usbdevfs_bulktransfer __user *p; -        compat_uint_t n; -        compat_caddr_t addr; +	struct usbdevfs_bulktransfer __user *p; +	compat_uint_t n; +	compat_caddr_t addr; -        p = compat_alloc_user_space(sizeof(*p)); +	p = compat_alloc_user_space(sizeof(*p)); -        if (get_user(n, &p32->ep) || put_user(n, &p->ep) || -            get_user(n, &p32->len) || put_user(n, &p->len) || -            get_user(n, &p32->timeout) || put_user(n, &p->timeout) || -            get_user(addr, &p32->data) || put_user(compat_ptr(addr), &p->data)) -                return -EFAULT; +	if (get_user(n, &p32->ep) || put_user(n, &p->ep) || +	    get_user(n, &p32->len) || put_user(n, &p->len) || +	    get_user(n, &p32->timeout) || put_user(n, &p->timeout) || +	    get_user(addr, &p32->data) || put_user(compat_ptr(addr), &p->data)) +		return -EFAULT; -        return proc_bulk(ps, p); +	return proc_bulk(ps, p);  } -static int proc_disconnectsignal_compat(struct dev_state *ps, void __user *arg) +static int proc_disconnectsignal_compat(struct usb_dev_state *ps, void __user *arg)  {  	struct usbdevfs_disconnectsignal32 ds; @@ -1701,7 +1798,7 @@ static int get_urb32(struct usbdevfs_urb *kurb,  	return 0;  } -static int proc_submiturb_compat(struct dev_state *ps, void __user *arg) +static int proc_submiturb_compat(struct usb_dev_state *ps, void __user *arg)  {  	struct usbdevfs_urb uurb; @@ -1747,7 +1844,7 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)  	return 0;  } -static int proc_reapurb_compat(struct dev_state *ps, void __user *arg) +static int proc_reapurb_compat(struct usb_dev_state *ps, void __user *arg)  {  	struct async *as = reap_as(ps);  	if (as) { @@ -1760,7 +1857,7 @@ static int proc_reapurb_compat(struct dev_state *ps, void __user *arg)  	return -EIO;  } -static int proc_reapurbnonblock_compat(struct dev_state *ps, void __user *arg) +static int proc_reapurbnonblock_compat(struct usb_dev_state *ps, void __user *arg)  {  	int retval;  	struct async *as; @@ -1777,7 +1874,7 @@ static int proc_reapurbnonblock_compat(struct dev_state *ps, void __user *arg)  #endif -static int proc_disconnectsignal(struct dev_state *ps, void __user *arg) +static int proc_disconnectsignal(struct usb_dev_state *ps, void __user *arg)  {  	struct usbdevfs_disconnectsignal ds; @@ -1788,7 +1885,7 @@ static int proc_disconnectsignal(struct dev_state *ps, void __user *arg)  	return 0;  } -static int proc_claiminterface(struct dev_state *ps, void __user *arg) +static int proc_claiminterface(struct usb_dev_state *ps, void __user *arg)  {  	unsigned int ifnum; @@ -1797,7 +1894,7 @@ static int proc_claiminterface(struct dev_state *ps, void __user *arg)  	return claimintf(ps, ifnum);  } -static int proc_releaseinterface(struct dev_state *ps, void __user *arg) +static int proc_releaseinterface(struct usb_dev_state *ps, void __user *arg)  {  	unsigned int ifnum;  	int ret; @@ -1810,7 +1907,7 @@ static int proc_releaseinterface(struct dev_state *ps, void __user *arg)  	return 0;  } -static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) +static int proc_ioctl(struct usb_dev_state *ps, struct usbdevfs_ioctl *ctl)  {  	int			size;  	void			*buf = NULL; @@ -1886,7 +1983,7 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)  	return retval;  } -static int proc_ioctl_default(struct dev_state *ps, void __user *arg) +static int proc_ioctl_default(struct usb_dev_state *ps, void __user *arg)  {  	struct usbdevfs_ioctl	ctrl; @@ -1896,7 +1993,7 @@ static int proc_ioctl_default(struct dev_state *ps, void __user *arg)  }  #ifdef CONFIG_COMPAT -static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg) +static int proc_ioctl_compat(struct usb_dev_state *ps, compat_uptr_t arg)  {  	struct usbdevfs_ioctl32 __user *uioc;  	struct usbdevfs_ioctl ctrl; @@ -1914,7 +2011,7 @@ static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg)  }  #endif -static int proc_claim_port(struct dev_state *ps, void __user *arg) +static int proc_claim_port(struct usb_dev_state *ps, void __user *arg)  {  	unsigned portnum;  	int rc; @@ -1928,7 +2025,7 @@ static int proc_claim_port(struct dev_state *ps, void __user *arg)  	return rc;  } -static int proc_release_port(struct dev_state *ps, void __user *arg) +static int proc_release_port(struct usb_dev_state *ps, void __user *arg)  {  	unsigned portnum; @@ -1937,7 +2034,7 @@ static int proc_release_port(struct dev_state *ps, void __user *arg)  	return usb_hub_release_port(ps->dev, portnum, ps);  } -static int proc_get_capabilities(struct dev_state *ps, void __user *arg) +static int proc_get_capabilities(struct usb_dev_state *ps, void __user *arg)  {  	__u32 caps; @@ -1953,7 +2050,7 @@ static int proc_get_capabilities(struct dev_state *ps, void __user *arg)  	return 0;  } -static int proc_disconnect_claim(struct dev_state *ps, void __user *arg) +static int proc_disconnect_claim(struct usb_dev_state *ps, void __user *arg)  {  	struct usbdevfs_disconnect_claim dc;  	struct usb_interface *intf; @@ -1985,6 +2082,45 @@ static int proc_disconnect_claim(struct dev_state *ps, void __user *arg)  	return claimintf(ps, dc.interface);  } +static int proc_alloc_streams(struct usb_dev_state *ps, void __user *arg) +{ +	unsigned num_streams, num_eps; +	struct usb_host_endpoint **eps; +	struct usb_interface *intf; +	int r; + +	r = parse_usbdevfs_streams(ps, arg, &num_streams, &num_eps, +				   &eps, &intf); +	if (r) +		return r; + +	destroy_async_on_interface(ps, +				   intf->altsetting[0].desc.bInterfaceNumber); + +	r = usb_alloc_streams(intf, eps, num_eps, num_streams, GFP_KERNEL); +	kfree(eps); +	return r; +} + +static int proc_free_streams(struct usb_dev_state *ps, void __user *arg) +{ +	unsigned num_eps; +	struct usb_host_endpoint **eps; +	struct usb_interface *intf; +	int r; + +	r = parse_usbdevfs_streams(ps, arg, NULL, &num_eps, &eps, &intf); +	if (r) +		return r; + +	destroy_async_on_interface(ps, +				   intf->altsetting[0].desc.bInterfaceNumber); + +	r = usb_free_streams(intf, eps, num_eps, GFP_KERNEL); +	kfree(eps); +	return r; +} +  /*   * NOTE:  All requests here that have interface numbers as parameters   * are assuming that somehow the configuration has been prevented from @@ -1993,7 +2129,7 @@ static int proc_disconnect_claim(struct dev_state *ps, void __user *arg)  static long usbdev_do_ioctl(struct file *file, unsigned int cmd,  				void __user *p)  { -	struct dev_state *ps = file->private_data; +	struct usb_dev_state *ps = file->private_data;  	struct inode *inode = file_inode(file);  	struct usb_device *dev = ps->dev;  	int ret = -ENOTTY; @@ -2161,6 +2297,12 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,  	case USBDEVFS_DISCONNECT_CLAIM:  		ret = proc_disconnect_claim(ps, p);  		break; +	case USBDEVFS_ALLOC_STREAMS: +		ret = proc_alloc_streams(ps, p); +		break; +	case USBDEVFS_FREE_STREAMS: +		ret = proc_free_streams(ps, p); +		break;  	}  	usb_unlock_device(dev);  	if (ret >= 0) @@ -2194,7 +2336,7 @@ static long usbdev_compat_ioctl(struct file *file, unsigned int cmd,  static unsigned int usbdev_poll(struct file *file,  				struct poll_table_struct *wait)  { -	struct dev_state *ps = file->private_data; +	struct usb_dev_state *ps = file->private_data;  	unsigned int mask = 0;  	poll_wait(file, &ps->wait, wait); @@ -2220,11 +2362,11 @@ const struct file_operations usbdev_file_operations = {  static void usbdev_remove(struct usb_device *udev)  { -	struct dev_state *ps; +	struct usb_dev_state *ps;  	struct siginfo sinfo;  	while (!list_empty(&udev->filelist)) { -		ps = list_entry(udev->filelist.next, struct dev_state, list); +		ps = list_entry(udev->filelist.next, struct usb_dev_state, list);  		destroy_all_async(ps);  		wake_up_all(&ps->wait);  		list_del_init(&ps->list);  | 
