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
*
* 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;
......
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