diff options
| author | David Brownell <david-b@pacbell.net> | 2004-08-26 02:04:56 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <greg@kroah.com> | 2004-08-26 02:04:56 -0700 |
| commit | 530f6dbeec21562bb14daefbe4330844d5aba778 (patch) | |
| tree | 73c01d94d7b1a6392f95337c28d43889d160ba16 | |
| parent | c728125eea7e40ef6fde3a9abdf844615d45b677 (diff) | |
[PATCH] USB: gadgetfs minor updates
Gadgetfs updates:
- Resolve a problem that came from a change in the API to AIO:
kiocb->private type and size changed, but the name remained
the same ... so GCC wouldn't report pending memory-corruption.
- Probe the controller at runtime, eliminatingting config-specific
defines which need to be updated for each new controller. Rip
out the old #defines.
- Use newish APIs to let VBUS current be used to recharge
batteries (or whatever).
- Use no_llseek() ... endpoints are pure data streams.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
| -rw-r--r-- | drivers/usb/gadget/inode.c | 145 |
1 files changed, 93 insertions, 52 deletions
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index a0edda18a041..d8ed62bc09b1 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -1,7 +1,7 @@ /* * inode.c -- user mode filesystem api for usb gadget controllers * - * Copyright (C) 2003 David Brownell + * Copyright (C) 2003-2004 David Brownell * Copyright (C) 2003 Agilent Technologies * * This program is free software; you can redistribute it and/or modify @@ -71,7 +71,7 @@ */ #define DRIVER_DESC "USB Gadget filesystem" -#define DRIVER_VERSION "18 Nov 2003" +#define DRIVER_VERSION "24 Aug 2004" static const char driver_desc [] = DRIVER_DESC; static const char shortname [] = "gadgetfs"; @@ -229,41 +229,12 @@ static void put_ep (struct ep_data *data) /*----------------------------------------------------------------------*/ /* most "how to use the hardware" policy choices are in userspace: - * mapping endpoint roles the driver needs to the capabilities that - * the usb controller exposes. + * mapping endpoint roles (which the driver needs) to the capabilities + * which the usb controller has. most of those capabilities are exposed + * implicitly, starting with the driver name and then endpoint names. */ -#ifdef CONFIG_USB_GADGET_DUMMY_HCD -/* act (mostly) like a net2280 */ -#define CONFIG_USB_GADGET_NET2280 -#endif - -#ifdef CONFIG_USB_GADGET_NET2280 -#define CHIP "net2280" -#define HIGHSPEED -#endif - -#ifdef CONFIG_USB_GADGET_PXA2XX -#define CHIP "pxa2xx_udc" -/* earlier hardware doesn't have UDCCFR, races set_{config,interface} */ -#warning works best with pxa255 or newer -#endif - -#ifdef CONFIG_USB_GADGET_GOKU -#define CHIP "goku_udc" -#endif - -#ifdef CONFIG_USB_GADGET_OMAP -#define CHIP "omap_udc" -#endif - -#ifdef CONFIG_USB_GADGET_SA1100 -#define CHIP "sa1100" -#endif - -#ifdef CONFIG_USB_GADGET_LH7A40X -#define CHIP "lh7a40x_udc" -#endif +static const char *CHIP; /*----------------------------------------------------------------------*/ @@ -562,7 +533,7 @@ struct kiocb_priv { static int ep_aio_cancel(struct kiocb *iocb, struct io_event *e) { - struct kiocb_priv *priv = (void *) &iocb->private; + struct kiocb_priv *priv = iocb->private; struct ep_data *epdata; int value; @@ -583,7 +554,7 @@ static int ep_aio_cancel(struct kiocb *iocb, struct io_event *e) static long ep_aio_read_retry(struct kiocb *iocb) { - struct kiocb_priv *priv = (void *) &iocb->private; + struct kiocb_priv *priv = iocb->private; int status = priv->actual; /* we "retry" to get the right mm context for this: */ @@ -593,6 +564,7 @@ static long ep_aio_read_retry(struct kiocb *iocb) else status = priv->actual; kfree(priv->buf); + kfree(priv); aio_put_req(iocb); return status; } @@ -600,7 +572,7 @@ static long ep_aio_read_retry(struct kiocb *iocb) static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) { struct kiocb *iocb = req->context; - struct kiocb_priv *priv = (void *) &iocb->private; + struct kiocb_priv *priv = iocb->private; struct ep_data *epdata = priv->epdata; /* lock against disconnect (and ideally, cancel) */ @@ -611,6 +583,8 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) || unlikely(0 == req->actual) || unlikely(kiocbIsCancelled(iocb))) { kfree(req->buf); + kfree(priv); + iocb->private = 0; /* aio_complete() reports bytes-transferred _and_ faults */ if (unlikely(kiocbIsCancelled(iocb))) aio_put_req(iocb); @@ -635,17 +609,33 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) } static ssize_t -ep_aio_rwtail(struct kiocb *iocb, char *buf, size_t len, struct ep_data *epdata) +ep_aio_rwtail( + struct kiocb *iocb, + char *buf, + size_t len, + struct ep_data *epdata, + char __user *ubuf +) { struct kiocb_priv *priv = (void *) &iocb->private; struct usb_request *req; ssize_t value; - value = get_ready_ep(iocb->ki_filp->f_flags, epdata); - if (unlikely(value < 0)) { + priv = kmalloc(sizeof *priv, GFP_KERNEL); + if (!priv) { + value = -ENOMEM; +fail: kfree(buf); return value; } + iocb->private = priv; + priv->ubuf = ubuf; + + value = get_ready_ep(iocb->ki_filp->f_flags, epdata); + if (unlikely(value < 0)) { + kfree(priv); + goto fail; + } iocb->ki_cancel = ep_aio_cancel; get_ep(epdata); @@ -675,9 +665,10 @@ ep_aio_rwtail(struct kiocb *iocb, char *buf, size_t len, struct ep_data *epdata) up(&epdata->lock); - if (unlikely(value)) + if (unlikely(value)) { + kfree(priv); put_ep(epdata); - else + } else value = -EIOCBQUEUED; return value; } @@ -685,7 +676,6 @@ ep_aio_rwtail(struct kiocb *iocb, char *buf, size_t len, struct ep_data *epdata) static ssize_t ep_aio_read(struct kiocb *iocb, char __user *ubuf, size_t len, loff_t o) { - struct kiocb_priv *priv = (void *) &iocb->private; struct ep_data *epdata = iocb->ki_filp->private_data; char *buf; @@ -695,8 +685,7 @@ ep_aio_read(struct kiocb *iocb, char __user *ubuf, size_t len, loff_t o) if (unlikely(!buf)) return -ENOMEM; iocb->ki_retry = ep_aio_read_retry; - priv->ubuf = ubuf; - return ep_aio_rwtail(iocb, buf, len, epdata); + return ep_aio_rwtail(iocb, buf, len, epdata, ubuf); } static ssize_t @@ -714,7 +703,7 @@ ep_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t len, loff_t o) kfree(buf); return -EFAULT; } - return ep_aio_rwtail(iocb, buf, len, epdata); + return ep_aio_rwtail(iocb, buf, len, epdata, 0); } /*----------------------------------------------------------------------*/ @@ -722,6 +711,8 @@ ep_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t len, loff_t o) /* used after endpoint configuration */ static struct file_operations ep_io_operations = { .owner = THIS_MODULE, + .llseek = no_llseek, + .read = ep_read, .write = ep_write, .ioctl = ep_ioctl, @@ -878,6 +869,8 @@ ep_open (struct inode *inode, struct file *fd) /* used before endpoint configuration */ static struct file_operations ep_config_operations = { .owner = THIS_MODULE, + .llseek = no_llseek, + .open = ep_open, .write = ep_config, .release = ep_release, @@ -984,6 +977,18 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) retval = usb_ep_queue (ep, req, GFP_ATOMIC); dev->state = STATE_CONNECTED; + /* assume that was SET_CONFIGURATION */ + if (dev->current_config) { + unsigned power; +#ifdef HIGHSPEED + if (dev->gadget->speed == USB_SPEED_HIGH) + power = dev->hs_config->bMaxPower; + else +#endif + power = dev->config->bMaxPower; + usb_gadget_vbus_draw(dev->gadget, 2 * power); + } + } else { /* collect OUT data */ if ((fd->f_flags & O_NONBLOCK) != 0 && !dev->setup_out_ready) { @@ -1234,6 +1239,8 @@ static int dev_ioctl (struct inode *inode, struct file *fd, /* used after device configuration */ static struct file_operations ep0_io_operations = { .owner = THIS_MODULE, + .llseek = no_llseek, + .read = ep0_read, .write = ep0_write, .fasync = ep0_fasync, @@ -1410,19 +1417,25 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) if (0 == (u8) ctrl->wValue) { value = 0; dev->current_config = 0; + usb_gadget_vbus_draw(gadget, 8 /* mA */ ); // user mode expected to disable endpoints } else { - u8 config; + u8 config, power; #ifdef HIGHSPEED - if (gadget->speed == USB_SPEED_HIGH) + if (gadget->speed == USB_SPEED_HIGH) { config = dev->hs_config->bConfigurationValue; - else + power = dev->hs_config->bMaxPower; + } else #endif + { config = dev->config->bConfigurationValue; + power = dev->config->bMaxPower; + } if (config == (u8) ctrl->wValue) { value = 0; dev->current_config = config; + usb_gadget_vbus_draw(gadget, 2 * power); } } @@ -1640,8 +1653,8 @@ gadgetfs_bind (struct usb_gadget *gadget) if (!dev) return -ESRCH; if (0 != strcmp (CHIP, gadget->name)) { - printk (KERN_ERR "%s expected " CHIP " controller not %s\n", - shortname, gadget->name); + printk (KERN_ERR "%s expected %s controller not %s\n", + shortname, CHIP, gadget->name); return -ENODEV; } @@ -1731,6 +1744,26 @@ static struct usb_gadget_driver gadgetfs_driver = { /*----------------------------------------------------------------------*/ +static void gadgetfs_nop(struct usb_gadget *arg) { } + +static int gadgetfs_probe (struct usb_gadget *gadget) +{ + CHIP = gadget->name; + return -EISNAM; +} + +static struct usb_gadget_driver probe_driver = { + .speed = USB_SPEED_HIGH, + .bind = gadgetfs_probe, + .unbind = gadgetfs_nop, + .setup = (void *)gadgetfs_nop, + .disconnect = gadgetfs_nop, + .driver = { + .name = "nop", + }, +}; + + /* DEVICE INITIALIZATION * * fd = open ("/dev/gadget/$CHIP", O_RDWR) @@ -1767,6 +1800,7 @@ static int is_valid_config (struct usb_config_descriptor *config) && config->bConfigurationValue != 0 && (config->bmAttributes & USB_CONFIG_ATT_ONE) != 0 && (config->bmAttributes & USB_CONFIG_ATT_WAKEUP) == 0; + /* FIXME if gadget->is_otg, _must_ include an otg descriptor */ /* FIXME check lengths: walk to end */ } @@ -1885,6 +1919,8 @@ dev_open (struct inode *inode, struct file *fd) static struct file_operations dev_init_operations = { .owner = THIS_MODULE, + .llseek = no_llseek, + .open = dev_open, .write = dev_config, .fasync = ep0_fasync, @@ -1980,6 +2016,11 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent) if (the_device) return -ESRCH; + /* fake probe to determine $CHIP */ + (void) usb_gadget_register_driver (&probe_driver); + if (!CHIP) + return -ENODEV; + /* superblock */ sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; |
