summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2004-08-26 02:04:56 -0700
committerGreg Kroah-Hartman <greg@kroah.com>2004-08-26 02:04:56 -0700
commit530f6dbeec21562bb14daefbe4330844d5aba778 (patch)
tree73c01d94d7b1a6392f95337c28d43889d160ba16
parentc728125eea7e40ef6fde3a9abdf844615d45b677 (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.c145
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;