Commit 530f6dbe authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[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: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarGreg Kroah-Hartman <greg@kroah.com>
parent c728125e
/* /*
* inode.c -- user mode filesystem api for usb gadget controllers * 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 * Copyright (C) 2003 Agilent Technologies
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -71,7 +71,7 @@ ...@@ -71,7 +71,7 @@
*/ */
#define DRIVER_DESC "USB Gadget filesystem" #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 driver_desc [] = DRIVER_DESC;
static const char shortname [] = "gadgetfs"; static const char shortname [] = "gadgetfs";
...@@ -229,41 +229,12 @@ static void put_ep (struct ep_data *data) ...@@ -229,41 +229,12 @@ static void put_ep (struct ep_data *data)
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
/* most "how to use the hardware" policy choices are in userspace: /* most "how to use the hardware" policy choices are in userspace:
* mapping endpoint roles the driver needs to the capabilities that * mapping endpoint roles (which the driver needs) to the capabilities
* the usb controller exposes. * 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 static const char *CHIP;
/* 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
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
...@@ -562,7 +533,7 @@ struct kiocb_priv { ...@@ -562,7 +533,7 @@ struct kiocb_priv {
static int ep_aio_cancel(struct kiocb *iocb, struct io_event *e) 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; struct ep_data *epdata;
int value; int value;
...@@ -583,7 +554,7 @@ static int ep_aio_cancel(struct kiocb *iocb, struct io_event *e) ...@@ -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) 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; int status = priv->actual;
/* we "retry" to get the right mm context for this: */ /* we "retry" to get the right mm context for this: */
...@@ -593,6 +564,7 @@ static long ep_aio_read_retry(struct kiocb *iocb) ...@@ -593,6 +564,7 @@ static long ep_aio_read_retry(struct kiocb *iocb)
else else
status = priv->actual; status = priv->actual;
kfree(priv->buf); kfree(priv->buf);
kfree(priv);
aio_put_req(iocb); aio_put_req(iocb);
return status; return status;
} }
...@@ -600,7 +572,7 @@ static long ep_aio_read_retry(struct kiocb *iocb) ...@@ -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) static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
{ {
struct kiocb *iocb = req->context; struct kiocb *iocb = req->context;
struct kiocb_priv *priv = (void *) &iocb->private; struct kiocb_priv *priv = iocb->private;
struct ep_data *epdata = priv->epdata; struct ep_data *epdata = priv->epdata;
/* lock against disconnect (and ideally, cancel) */ /* lock against disconnect (and ideally, cancel) */
...@@ -611,6 +583,8 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) ...@@ -611,6 +583,8 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
|| unlikely(0 == req->actual) || unlikely(0 == req->actual)
|| unlikely(kiocbIsCancelled(iocb))) { || unlikely(kiocbIsCancelled(iocb))) {
kfree(req->buf); kfree(req->buf);
kfree(priv);
iocb->private = 0;
/* aio_complete() reports bytes-transferred _and_ faults */ /* aio_complete() reports bytes-transferred _and_ faults */
if (unlikely(kiocbIsCancelled(iocb))) if (unlikely(kiocbIsCancelled(iocb)))
aio_put_req(iocb); aio_put_req(iocb);
...@@ -635,17 +609,33 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req) ...@@ -635,17 +609,33 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
} }
static ssize_t 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 kiocb_priv *priv = (void *) &iocb->private;
struct usb_request *req; struct usb_request *req;
ssize_t value; ssize_t value;
value = get_ready_ep(iocb->ki_filp->f_flags, epdata); priv = kmalloc(sizeof *priv, GFP_KERNEL);
if (unlikely(value < 0)) { if (!priv) {
value = -ENOMEM;
fail:
kfree(buf); kfree(buf);
return value; 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; iocb->ki_cancel = ep_aio_cancel;
get_ep(epdata); get_ep(epdata);
...@@ -675,9 +665,10 @@ ep_aio_rwtail(struct kiocb *iocb, char *buf, size_t len, struct ep_data *epdata) ...@@ -675,9 +665,10 @@ ep_aio_rwtail(struct kiocb *iocb, char *buf, size_t len, struct ep_data *epdata)
up(&epdata->lock); up(&epdata->lock);
if (unlikely(value)) if (unlikely(value)) {
kfree(priv);
put_ep(epdata); put_ep(epdata);
else } else
value = -EIOCBQUEUED; value = -EIOCBQUEUED;
return value; return value;
} }
...@@ -685,7 +676,6 @@ ep_aio_rwtail(struct kiocb *iocb, char *buf, size_t len, struct ep_data *epdata) ...@@ -685,7 +676,6 @@ ep_aio_rwtail(struct kiocb *iocb, char *buf, size_t len, struct ep_data *epdata)
static ssize_t static ssize_t
ep_aio_read(struct kiocb *iocb, char __user *ubuf, size_t len, loff_t o) 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; struct ep_data *epdata = iocb->ki_filp->private_data;
char *buf; char *buf;
...@@ -695,8 +685,7 @@ ep_aio_read(struct kiocb *iocb, char __user *ubuf, size_t len, loff_t o) ...@@ -695,8 +685,7 @@ ep_aio_read(struct kiocb *iocb, char __user *ubuf, size_t len, loff_t o)
if (unlikely(!buf)) if (unlikely(!buf))
return -ENOMEM; return -ENOMEM;
iocb->ki_retry = ep_aio_read_retry; iocb->ki_retry = ep_aio_read_retry;
priv->ubuf = ubuf; return ep_aio_rwtail(iocb, buf, len, epdata, ubuf);
return ep_aio_rwtail(iocb, buf, len, epdata);
} }
static ssize_t static ssize_t
...@@ -714,7 +703,7 @@ ep_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t len, loff_t o) ...@@ -714,7 +703,7 @@ ep_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t len, loff_t o)
kfree(buf); kfree(buf);
return -EFAULT; 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) ...@@ -722,6 +711,8 @@ ep_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t len, loff_t o)
/* used after endpoint configuration */ /* used after endpoint configuration */
static struct file_operations ep_io_operations = { static struct file_operations ep_io_operations = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek,
.read = ep_read, .read = ep_read,
.write = ep_write, .write = ep_write,
.ioctl = ep_ioctl, .ioctl = ep_ioctl,
...@@ -878,6 +869,8 @@ ep_open (struct inode *inode, struct file *fd) ...@@ -878,6 +869,8 @@ ep_open (struct inode *inode, struct file *fd)
/* used before endpoint configuration */ /* used before endpoint configuration */
static struct file_operations ep_config_operations = { static struct file_operations ep_config_operations = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek,
.open = ep_open, .open = ep_open,
.write = ep_config, .write = ep_config,
.release = ep_release, .release = ep_release,
...@@ -984,6 +977,18 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) ...@@ -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); retval = usb_ep_queue (ep, req, GFP_ATOMIC);
dev->state = STATE_CONNECTED; 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 */ } else { /* collect OUT data */
if ((fd->f_flags & O_NONBLOCK) != 0 if ((fd->f_flags & O_NONBLOCK) != 0
&& !dev->setup_out_ready) { && !dev->setup_out_ready) {
...@@ -1234,6 +1239,8 @@ static int dev_ioctl (struct inode *inode, struct file *fd, ...@@ -1234,6 +1239,8 @@ static int dev_ioctl (struct inode *inode, struct file *fd,
/* used after device configuration */ /* used after device configuration */
static struct file_operations ep0_io_operations = { static struct file_operations ep0_io_operations = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek,
.read = ep0_read, .read = ep0_read,
.write = ep0_write, .write = ep0_write,
.fasync = ep0_fasync, .fasync = ep0_fasync,
...@@ -1410,19 +1417,25 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) ...@@ -1410,19 +1417,25 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
if (0 == (u8) ctrl->wValue) { if (0 == (u8) ctrl->wValue) {
value = 0; value = 0;
dev->current_config = 0; dev->current_config = 0;
usb_gadget_vbus_draw(gadget, 8 /* mA */ );
// user mode expected to disable endpoints // user mode expected to disable endpoints
} else { } else {
u8 config; u8 config, power;
#ifdef HIGHSPEED #ifdef HIGHSPEED
if (gadget->speed == USB_SPEED_HIGH) if (gadget->speed == USB_SPEED_HIGH) {
config = dev->hs_config->bConfigurationValue; config = dev->hs_config->bConfigurationValue;
else power = dev->hs_config->bMaxPower;
} else
#endif #endif
{
config = dev->config->bConfigurationValue; config = dev->config->bConfigurationValue;
power = dev->config->bMaxPower;
}
if (config == (u8) ctrl->wValue) { if (config == (u8) ctrl->wValue) {
value = 0; value = 0;
dev->current_config = config; dev->current_config = config;
usb_gadget_vbus_draw(gadget, 2 * power);
} }
} }
...@@ -1640,8 +1653,8 @@ gadgetfs_bind (struct usb_gadget *gadget) ...@@ -1640,8 +1653,8 @@ gadgetfs_bind (struct usb_gadget *gadget)
if (!dev) if (!dev)
return -ESRCH; return -ESRCH;
if (0 != strcmp (CHIP, gadget->name)) { if (0 != strcmp (CHIP, gadget->name)) {
printk (KERN_ERR "%s expected " CHIP " controller not %s\n", printk (KERN_ERR "%s expected %s controller not %s\n",
shortname, gadget->name); shortname, CHIP, gadget->name);
return -ENODEV; return -ENODEV;
} }
...@@ -1731,6 +1744,26 @@ static struct usb_gadget_driver gadgetfs_driver = { ...@@ -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 /* DEVICE INITIALIZATION
* *
* fd = open ("/dev/gadget/$CHIP", O_RDWR) * fd = open ("/dev/gadget/$CHIP", O_RDWR)
...@@ -1767,6 +1800,7 @@ static int is_valid_config (struct usb_config_descriptor *config) ...@@ -1767,6 +1800,7 @@ static int is_valid_config (struct usb_config_descriptor *config)
&& config->bConfigurationValue != 0 && config->bConfigurationValue != 0
&& (config->bmAttributes & USB_CONFIG_ATT_ONE) != 0 && (config->bmAttributes & USB_CONFIG_ATT_ONE) != 0
&& (config->bmAttributes & USB_CONFIG_ATT_WAKEUP) == 0; && (config->bmAttributes & USB_CONFIG_ATT_WAKEUP) == 0;
/* FIXME if gadget->is_otg, _must_ include an otg descriptor */
/* FIXME check lengths: walk to end */ /* FIXME check lengths: walk to end */
} }
...@@ -1885,6 +1919,8 @@ dev_open (struct inode *inode, struct file *fd) ...@@ -1885,6 +1919,8 @@ dev_open (struct inode *inode, struct file *fd)
static struct file_operations dev_init_operations = { static struct file_operations dev_init_operations = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek,
.open = dev_open, .open = dev_open,
.write = dev_config, .write = dev_config,
.fasync = ep0_fasync, .fasync = ep0_fasync,
...@@ -1980,6 +2016,11 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent) ...@@ -1980,6 +2016,11 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent)
if (the_device) if (the_device)
return -ESRCH; return -ESRCH;
/* fake probe to determine $CHIP */
(void) usb_gadget_register_driver (&probe_driver);
if (!CHIP)
return -ENODEV;
/* superblock */ /* superblock */
sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize = PAGE_CACHE_SIZE;
sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment