📄 inode.c
字号:
/*
* inode.c -- user mode filesystem api for usb gadget controllers
*
* Copyright (C) 2003-2004 David Brownell
* Copyright (C) 2003 Agilent Technologies
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// #define DEBUG /* data to help fault diagnosis */
// #define VERBOSE /* extra debug messages (success too) */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
#include <linux/uts.h>
#include <linux/wait.h>
#include <linux/compiler.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/moduleparam.h>
#include <linux/usb_gadgetfs.h>
#include <linux/usb_gadget.h>
/*
* The gadgetfs API maps each endpoint to a file descriptor so that you
* can use standard synchronous read/write calls for I/O. There's some
* O_NONBLOCK and O_ASYNC/FASYNC style i/o support. Example usermode
* drivers show how this works in practice. You can also use AIO to
* eliminate I/O gaps between requests, to help when streaming data.
*
* Key parts that must be USB-specific are protocols defining how the
* read/write operations relate to the hardware state machines. There
* are two types of files. One type is for the device, implementing ep0.
* The other type is for each IN or OUT endpoint. In both cases, the
* user mode driver must configure the hardware before using it.
*
* - First, dev_config() is called when /dev/gadget/$CHIP is configured
* (by writing configuration and device descriptors). Afterwards it
* may serve as a source of device events, used to handle all control
* requests other than basic enumeration.
*
* - Then either immediately, or after a SET_CONFIGURATION control request,
* ep_config() is called when each /dev/gadget/ep* file is configured
* (by writing endpoint descriptors). Afterwards these files are used
* to write() IN data or to read() OUT data. To halt the endpoint, a
* "wrong direction" request is issued (like reading an IN endpoint).
*
* Unlike "usbfs" the only ioctl()s are for things that are rare, and maybe
* not possible on all hardware. For example, precise fault handling with
* respect to data left in endpoint fifos after aborted operations; or
* selective clearing of endpoint halts, to implement SET_INTERFACE.
*/
#define DRIVER_DESC "USB Gadget filesystem"
#define DRIVER_VERSION "24 Aug 2004"
static const char driver_desc [] = DRIVER_DESC;
static const char shortname [] = "gadgetfs";
MODULE_DESCRIPTION (DRIVER_DESC);
MODULE_AUTHOR ("David Brownell");
MODULE_LICENSE ("GPL");
/*----------------------------------------------------------------------*/
#define GADGETFS_MAGIC 0xaee71ee7
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
/* /dev/gadget/$CHIP represents ep0 and the whole device */
enum ep0_state {
/* DISBLED is the initial state.
*/
STATE_DEV_DISABLED = 0,
/* Only one open() of /dev/gadget/$CHIP; only one file tracks
* ep0/device i/o modes and binding to the controller. Driver
* must always write descriptors to initialize the device, then
* the device becomes UNCONNECTED until enumeration.
*/
STATE_OPENED,
/* From then on, ep0 fd is in either of two basic modes:
* - (UN)CONNECTED: read usb_gadgetfs_event(s) from it
* - SETUP: read/write will transfer control data and succeed;
* or if "wrong direction", performs protocol stall
*/
STATE_UNCONNECTED,
STATE_CONNECTED,
STATE_SETUP,
/* UNBOUND means the driver closed ep0, so the device won't be
* accessible again (DEV_DISABLED) until all fds are closed.
*/
STATE_DEV_UNBOUND,
};
/* enough for the whole queue: most events invalidate others */
#define N_EVENT 5
struct dev_data {
spinlock_t lock;
atomic_t count;
enum ep0_state state;
struct usb_gadgetfs_event event [N_EVENT];
unsigned ev_next;
struct fasync_struct *fasync;
u8 current_config;
/* drivers reading ep0 MUST handle control requests (SETUP)
* reported that way; else the host will time out.
*/
unsigned usermode_setup : 1,
setup_in : 1,
setup_can_stall : 1,
setup_out_ready : 1,
setup_out_error : 1,
setup_abort : 1;
/* the rest is basically write-once */
struct usb_config_descriptor *config, *hs_config;
struct usb_device_descriptor *dev;
struct usb_request *req;
struct usb_gadget *gadget;
struct list_head epfiles;
void *buf;
wait_queue_head_t wait;
struct super_block *sb;
struct dentry *dentry;
/* except this scratch i/o buffer for ep0 */
u8 rbuf [256];
};
static inline void get_dev (struct dev_data *data)
{
atomic_inc (&data->count);
}
static void put_dev (struct dev_data *data)
{
if (likely (!atomic_dec_and_test (&data->count)))
return;
/* needs no more cleanup */
BUG_ON (waitqueue_active (&data->wait));
kfree (data);
}
static struct dev_data *dev_new (void)
{
struct dev_data *dev;
dev = kmalloc (sizeof *dev, GFP_KERNEL);
if (!dev)
return NULL;
memset (dev, 0, sizeof *dev);
dev->state = STATE_DEV_DISABLED;
atomic_set (&dev->count, 1);
spin_lock_init (&dev->lock);
INIT_LIST_HEAD (&dev->epfiles);
init_waitqueue_head (&dev->wait);
return dev;
}
/*----------------------------------------------------------------------*/
/* other /dev/gadget/$ENDPOINT files represent endpoints */
enum ep_state {
STATE_EP_DISABLED = 0,
STATE_EP_READY,
STATE_EP_DEFER_ENABLE,
STATE_EP_ENABLED,
STATE_EP_UNBOUND,
};
struct ep_data {
struct semaphore lock;
enum ep_state state;
atomic_t count;
struct dev_data *dev;
/* must hold dev->lock before accessing ep or req */
struct usb_ep *ep;
struct usb_request *req;
ssize_t status;
char name [16];
struct usb_endpoint_descriptor desc, hs_desc;
struct list_head epfiles;
wait_queue_head_t wait;
struct dentry *dentry;
struct inode *inode;
};
static inline void get_ep (struct ep_data *data)
{
atomic_inc (&data->count);
}
static void put_ep (struct ep_data *data)
{
if (likely (!atomic_dec_and_test (&data->count)))
return;
put_dev (data->dev);
/* needs no more cleanup */
BUG_ON (!list_empty (&data->epfiles));
BUG_ON (waitqueue_active (&data->wait));
BUG_ON (down_trylock (&data->lock) != 0);
kfree (data);
}
/*----------------------------------------------------------------------*/
/* most "how to use the hardware" policy choices are in userspace:
* 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.
*/
static const char *CHIP;
/*----------------------------------------------------------------------*/
/* NOTE: don't use dev_printk calls before binding to the gadget
* at the end of ep0 configuration, or after unbind.
*/
/* too wordy: dev_printk(level , &(d)->gadget->dev , fmt , ## args) */
#define xprintk(d,level,fmt,args...) \
printk(level "%s: " fmt , shortname , ## args)
#ifdef DEBUG
#define DBG(dev,fmt,args...) \
xprintk(dev , KERN_DEBUG , fmt , ## args)
#else
#define DBG(dev,fmt,args...) \
do { } while (0)
#endif /* DEBUG */
#ifdef VERBOSE
#define VDEBUG DBG
#else
#define VDEBUG(dev,fmt,args...) \
do { } while (0)
#endif /* DEBUG */
#define ERROR(dev,fmt,args...) \
xprintk(dev , KERN_ERR , fmt , ## args)
#define WARN(dev,fmt,args...) \
xprintk(dev , KERN_WARNING , fmt , ## args)
#define INFO(dev,fmt,args...) \
xprintk(dev , KERN_INFO , fmt , ## args)
/*----------------------------------------------------------------------*/
/* SYNCHRONOUS ENDPOINT OPERATIONS (bulk/intr/iso)
*
* After opening, configure non-control endpoints. Then use normal
* stream read() and write() requests; and maybe ioctl() to get more
* precise FIFO status when recovering from cancellation.
*/
static void epio_complete (struct usb_ep *ep, struct usb_request *req)
{
struct ep_data *epdata = ep->driver_data;
if (!req->context)
return;
if (req->status)
epdata->status = req->status;
else
epdata->status = req->actual;
complete ((struct completion *)req->context);
}
/* tasklock endpoint, returning when it's connected.
* still need dev->lock to use epdata->ep.
*/
static int
get_ready_ep (unsigned f_flags, struct ep_data *epdata)
{
int val;
if (f_flags & O_NONBLOCK) {
if (down_trylock (&epdata->lock) != 0)
goto nonblock;
if (epdata->state != STATE_EP_ENABLED) {
up (&epdata->lock);
nonblock:
val = -EAGAIN;
} else
val = 0;
return val;
}
if ((val = down_interruptible (&epdata->lock)) < 0)
return val;
newstate:
switch (epdata->state) {
case STATE_EP_ENABLED:
break;
case STATE_EP_DEFER_ENABLE:
DBG (epdata->dev, "%s wait for host\n", epdata->name);
if ((val = wait_event_interruptible (epdata->wait,
epdata->state != STATE_EP_DEFER_ENABLE
|| epdata->dev->state == STATE_DEV_UNBOUND
)) < 0)
goto fail;
goto newstate;
// case STATE_EP_DISABLED: /* "can't happen" */
// case STATE_EP_READY: /* "can't happen" */
default: /* error! */
pr_debug ("%s: ep %p not available, state %d\n",
shortname, epdata, epdata->state);
// FALLTHROUGH
case STATE_EP_UNBOUND: /* clean disconnect */
val = -ENODEV;
fail:
up (&epdata->lock);
}
return val;
}
static ssize_t
ep_io (struct ep_data *epdata, void *buf, unsigned len)
{
DECLARE_COMPLETION (done);
int value;
spin_lock_irq (&epdata->dev->lock);
if (likely (epdata->ep != NULL)) {
struct usb_request *req = epdata->req;
req->context = &done;
req->complete = epio_complete;
req->buf = buf;
req->length = len;
value = usb_ep_queue (epdata->ep, req, GFP_ATOMIC);
} else
value = -ENODEV;
spin_unlock_irq (&epdata->dev->lock);
if (likely (value == 0)) {
value = wait_event_interruptible (done.wait, done.done);
if (value != 0) {
spin_lock_irq (&epdata->dev->lock);
if (likely (epdata->ep != NULL)) {
DBG (epdata->dev, "%s i/o interrupted\n",
epdata->name);
usb_ep_dequeue (epdata->ep, epdata->req);
spin_unlock_irq (&epdata->dev->lock);
wait_event (done.wait, done.done);
if (epdata->status == -ECONNRESET)
epdata->status = -EINTR;
} else {
spin_unlock_irq (&epdata->dev->lock);
DBG (epdata->dev, "endpoint gone\n");
epdata->status = -ENODEV;
}
}
return epdata->status;
}
return value;
}
/* handle a synchronous OUT bulk/intr/iso transfer */
static ssize_t
ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
{
struct ep_data *data = fd->private_data;
void *kbuf;
ssize_t value;
if ((value = get_ready_ep (fd->f_flags, data)) < 0)
return value;
/* halt any endpoint by doing a "wrong direction" i/o call */
if (data->desc.bEndpointAddress & USB_DIR_IN) {
if ((data->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_ISOC)
return -EINVAL;
DBG (data->dev, "%s halt\n", data->name);
spin_lock_irq (&data->dev->lock);
if (likely (data->ep != NULL))
usb_ep_set_halt (data->ep);
spin_unlock_irq (&data->dev->lock);
up (&data->lock);
return -EBADMSG;
}
/* FIXME readahead for O_NONBLOCK and poll(); careful with ZLPs */
value = -ENOMEM;
kbuf = kmalloc (len, SLAB_KERNEL);
if (unlikely (!kbuf))
goto free1;
value = ep_io (data, kbuf, len);
VDEBUG (data->dev, "%s read %zu OUT, status %d\n",
data->name, len, (int) value);
if (value >= 0 && copy_to_user (buf, kbuf, value))
value = -EFAULT;
free1:
up (&data->lock);
kfree (kbuf);
return value;
}
/* handle a synchronous IN bulk/intr/iso transfer */
static ssize_t
ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
{
struct ep_data *data = fd->private_data;
void *kbuf;
ssize_t value;
if ((value = get_ready_ep (fd->f_flags, data)) < 0)
return value;
/* halt any endpoint by doing a "wrong direction" i/o call */
if (!(data->desc.bEndpointAddress & USB_DIR_IN)) {
if ((data->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_ISOC)
return -EINVAL;
DBG (data->dev, "%s halt\n", data->name);
spin_lock_irq (&data->dev->lock);
if (likely (data->ep != NULL))
usb_ep_set_halt (data->ep);
spin_unlock_irq (&data->dev->lock);
up (&data->lock);
return -EBADMSG;
}
/* FIXME writebehind for O_NONBLOCK and poll(), qlen = 1 */
value = -ENOMEM;
kbuf = kmalloc (len, SLAB_KERNEL);
if (!kbuf)
goto free1;
if (copy_from_user (kbuf, buf, len)) {
value = -EFAULT;
goto free1;
}
value = ep_io (data, kbuf, len);
VDEBUG (data->dev, "%s write %zu IN, status %d\n",
data->name, len, (int) value);
free1:
up (&data->lock);
kfree (kbuf);
return value;
}
static int
ep_release (struct inode *inode, struct file *fd)
{
struct ep_data *data = fd->private_data;
/* clean up if this can be reopened */
if (data->state != STATE_EP_UNBOUND) {
data->state = STATE_EP_DISABLED;
data->desc.bDescriptorType = 0;
data->hs_desc.bDescriptorType = 0;
usb_ep_disable(data->ep);
}
put_ep (data);
return 0;
}
static int ep_ioctl (struct inode *inode, struct file *fd,
unsigned code, unsigned long value)
{
struct ep_data *data = fd->private_data;
int status;
if ((status = get_ready_ep (fd->f_flags, data)) < 0)
return status;
spin_lock_irq (&data->dev->lock);
if (likely (data->ep != NULL)) {
switch (code) {
case GADGETFS_FIFO_STATUS:
status = usb_ep_fifo_status (data->ep);
break;
case GADGETFS_FIFO_FLUSH:
usb_ep_fifo_flush (data->ep);
break;
case GADGETFS_CLEAR_HALT:
status = usb_ep_clear_halt (data->ep);
break;
default:
status = -ENOTTY;
}
} else
status = -ENODEV;
spin_unlock_irq (&data->dev->lock);
up (&data->lock);
return status;
}
/*----------------------------------------------------------------------*/
/* ASYNCHRONOUS ENDPOINT I/O OPERATIONS (bulk/intr/iso) */
struct kiocb_priv {
struct usb_request *req;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -