📄 inode.c
字号:
gadget_for_each_ep (ep, dev->gadget) { struct ep_data *data; data = kmalloc (sizeof *data, GFP_KERNEL); if (!data) goto enomem; memset (data, 0, sizeof data); data->state = STATE_EP_DISABLED; init_MUTEX (&data->lock); init_waitqueue_head (&data->wait); strncpy (data->name, ep->name, sizeof (data->name) - 1); atomic_set (&data->count, 1); data->dev = dev; get_dev (dev); data->ep = ep; ep->driver_data = data; data->req = usb_ep_alloc_request (ep, GFP_KERNEL); if (!data->req) goto enomem; data->inode = gadgetfs_create_file (dev->sb, data->name, data, &ep_config_operations, &data->dentry); if (!data->inode) { kfree (data); goto enomem; } list_add_tail (&data->epfiles, &dev->epfiles); } return 0;enomem: DBG (dev, "%s enomem\n", __FUNCTION__); destroy_ep_files (dev); return -ENOMEM;}static voidgadgetfs_unbind (struct usb_gadget *gadget){ struct dev_data *dev = get_gadget_data (gadget); DBG (dev, "%s\n", __FUNCTION__); spin_lock_irq (&dev->lock); dev->state = STATE_DEV_UNBOUND; spin_unlock_irq (&dev->lock); destroy_ep_files (dev); gadget->ep0->driver_data = NULL; set_gadget_data (gadget, NULL); /* we've already been disconnected ... no i/o is active */ if (dev->req) usb_ep_free_request (gadget->ep0, dev->req); DBG (dev, "%s done\n", __FUNCTION__); put_dev (dev);}static struct dev_data *the_device;static intgadgetfs_bind (struct usb_gadget *gadget){ struct dev_data *dev = the_device; if (!dev) return -ESRCH; if (0 != strcmp (CHIP, gadget->name)) { printk (KERN_ERR "%s expected %s controller not %s\n", shortname, CHIP, gadget->name); return -ENODEV; } set_gadget_data (gadget, dev); dev->gadget = gadget; gadget->ep0->driver_data = dev; dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket; /* preallocate control response and buffer */ dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL); if (!dev->req) goto enomem; dev->req->context = NULL; dev->req->complete = epio_complete; if (activate_ep_files (dev) < 0) goto enomem; INFO (dev, "bound to %s driver\n", gadget->name); dev->state = STATE_UNCONNECTED; get_dev (dev); return 0;enomem: gadgetfs_unbind (gadget); return -ENOMEM;}static voidgadgetfs_disconnect (struct usb_gadget *gadget){ struct dev_data *dev = get_gadget_data (gadget); if (dev->state == STATE_UNCONNECTED) { DBG (dev, "already unconnected\n"); return; } dev->state = STATE_UNCONNECTED; INFO (dev, "disconnected\n"); spin_lock (&dev->lock); next_event (dev, GADGETFS_DISCONNECT); ep0_readable (dev); spin_unlock (&dev->lock);}static voidgadgetfs_suspend (struct usb_gadget *gadget){ struct dev_data *dev = get_gadget_data (gadget); INFO (dev, "suspended from state %d\n", dev->state); spin_lock (&dev->lock); switch (dev->state) { case STATE_SETUP: // VERY odd... host died?? case STATE_CONNECTED: case STATE_UNCONNECTED: next_event (dev, GADGETFS_SUSPEND); ep0_readable (dev); /* FALLTHROUGH */ default: break; } spin_unlock (&dev->lock);}static struct usb_gadget_driver gadgetfs_driver = {#ifdef HIGHSPEED .speed = USB_SPEED_HIGH,#else .speed = USB_SPEED_FULL,#endif .function = (char *) driver_desc, .bind = gadgetfs_bind, .unbind = gadgetfs_unbind, .setup = gadgetfs_setup, .disconnect = gadgetfs_disconnect, .suspend = gadgetfs_suspend, .driver = { .name = (char *) shortname, // .shutdown = ... // .suspend = ... // .resume = ... },};/*----------------------------------------------------------------------*/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) * status = write (fd, descriptors, sizeof descriptors) * * That write establishes the device configuration, so the kernel can * bind to the controller ... guaranteeing it can handle enumeration * at all necessary speeds. Descriptor order is: * * . message tag (u32, host order) ... for now, must be zero; it * would change to support features like multi-config devices * . full/low speed config ... all wTotalLength bytes (with interface, * class, altsetting, endpoint, and other descriptors) * . high speed config ... all descriptors, for high speed operation; * this one's optional except for high-speed hardware * . device descriptor * * Endpoints are not yet enabled. Drivers may want to immediately * initialize them, using the /dev/gadget/ep* files that are available * as soon as the kernel sees the configuration, or they can wait * until device configuration and interface altsetting changes create * the need to configure (or unconfigure) them. * * After initialization, the device stays active for as long as that * $CHIP file is open. Events may then be read from that descriptor, * such configuration notifications. More complex drivers will handle * some control requests in user space. */static int is_valid_config (struct usb_config_descriptor *config){ return config->bDescriptorType == USB_DT_CONFIG && config->bLength == USB_DT_CONFIG_SIZE && 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 */}static ssize_tdev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr){ struct dev_data *dev = fd->private_data; ssize_t value = len, length = len; unsigned total; u32 tag; char *kbuf; if (dev->state != STATE_OPENED) return -EEXIST; if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4)) return -EINVAL; /* we might need to change message format someday */ if (copy_from_user (&tag, buf, 4)) return -EFAULT; if (tag != 0) return -EINVAL; buf += 4; length -= 4; kbuf = kmalloc (length, SLAB_KERNEL); if (!kbuf) return -ENOMEM; if (copy_from_user (kbuf, buf, length)) { kfree (kbuf); return -EFAULT; } spin_lock_irq (&dev->lock); value = -EINVAL; if (dev->buf) goto fail; dev->buf = kbuf; /* full or low speed config */ dev->config = (void *) kbuf; total = le16_to_cpup (&dev->config->wTotalLength); if (!is_valid_config (dev->config) || total >= length) goto fail; kbuf += total; length -= total; /* optional high speed config */ if (kbuf [1] == USB_DT_CONFIG) { dev->hs_config = (void *) kbuf; total = le16_to_cpup (&dev->hs_config->wTotalLength); if (!is_valid_config (dev->hs_config) || total >= length) goto fail; kbuf += total; length -= total; } /* could support multiple configs, using another encoding! */ /* device descriptor (tweaked for paranoia) */ if (length != USB_DT_DEVICE_SIZE) goto fail; dev->dev = (void *)kbuf; if (dev->dev->bLength != USB_DT_DEVICE_SIZE || dev->dev->bDescriptorType != USB_DT_DEVICE || dev->dev->bNumConfigurations != 1) goto fail; dev->dev->bNumConfigurations = 1; dev->dev->bcdUSB = __constant_cpu_to_le16 (0x0200); /* triggers gadgetfs_bind(); then we can enumerate. */ spin_unlock_irq (&dev->lock); value = usb_gadget_register_driver (&gadgetfs_driver); if (value != 0) { kfree (dev->buf); dev->buf = NULL; } else { /* at this point "good" hardware has for the first time * let the USB the host see us. alternatively, if users * unplug/replug that will clear all the error state. * * note: everything running before here was guaranteed * to choke driver model style diagnostics. from here * on, they can work ... except in cleanup paths that * kick in after the ep0 descriptor is closed. */ fd->f_op = &ep0_io_operations; value = len; } return value;fail: spin_unlock_irq (&dev->lock); pr_debug ("%s: %s fail %Zd, %p\n", shortname, __FUNCTION__, value, dev); kfree (dev->buf); dev->buf = NULL; return value;}static intdev_open (struct inode *inode, struct file *fd){ struct dev_data *dev = inode->u.generic_ip; int value = -EBUSY; if (dev->state == STATE_DEV_DISABLED) { dev->ev_next = 0; dev->state = STATE_OPENED; fd->private_data = dev; get_dev (dev); value = 0; } return value;}static struct file_operations dev_init_operations = { .owner = THIS_MODULE, .llseek = no_llseek, .open = dev_open, .write = dev_config, .fasync = ep0_fasync, .ioctl = dev_ioctl, .release = dev_release,};/*----------------------------------------------------------------------*//* FILESYSTEM AND SUPERBLOCK OPERATIONS * * Mounting the filesystem creates a controller file, used first for * device configuration then later for event monitoring. *//* FIXME PAM etc could set this security policy without mount options * if epfiles inherited ownership and permissons from ep0 ... */static unsigned default_uid;static unsigned default_gid;static unsigned default_perm = S_IRUSR | S_IWUSR;module_param (default_uid, uint, 0644);module_param (default_gid, uint, 0644);module_param (default_perm, uint, 0644);static struct inode *gadgetfs_make_inode (struct super_block *sb, void *data, struct file_operations *fops, int mode){ struct inode *inode = new_inode (sb); if (inode) { inode->i_mode = mode; inode->i_uid = default_uid; inode->i_gid = default_gid; inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; inode->u.generic_ip = data; inode->i_fop = fops; } return inode;}/* creates in fs root directory, so non-renamable and non-linkable. * so inode and dentry are paired, until device reconfig. */static struct inode *gadgetfs_create_file (struct super_block *sb, char const *name, void *data, struct file_operations *fops, struct dentry **dentry_p){ struct dentry *dentry; struct inode *inode; dentry = d_alloc_name(sb->s_root, name); if (!dentry) return NULL; inode = gadgetfs_make_inode (sb, data, fops, S_IFREG | (default_perm & S_IRWXUGO)); if (!inode) { dput(dentry); return NULL; } d_add (dentry, inode); *dentry_p = dentry; return inode;}static struct super_operations gadget_fs_operations = { .statfs = simple_statfs, .drop_inode = generic_delete_inode,};static intgadgetfs_fill_super (struct super_block *sb, void *opts, int silent){ struct inode *inode; struct dentry *d; struct dev_data *dev; 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; sb->s_magic = GADGETFS_MAGIC; sb->s_op = &gadget_fs_operations; sb->s_time_gran = 1; /* root inode */ inode = gadgetfs_make_inode (sb, NULL, &simple_dir_operations, S_IFDIR | S_IRUGO | S_IXUGO); if (!inode) return -ENOMEM; inode->i_op = &simple_dir_inode_operations; if (!(d = d_alloc_root (inode))) { iput (inode); return -ENOMEM; } sb->s_root = d; /* the ep0 file is named after the controller we expect; * user mode code can use it for sanity checks, like we do. */ dev = dev_new (); if (!dev) return -ENOMEM; dev->sb = sb; if (!(inode = gadgetfs_create_file (sb, CHIP, dev, &dev_init_operations, &dev->dentry))) { put_dev(dev); return -ENOMEM; } /* other endpoint files are available after hardware setup, * from binding to a controller. */ the_device = dev; return 0;}/* "mount -t gadgetfs path /dev/gadget" ends up here */static struct super_block *gadgetfs_get_sb (struct file_system_type *t, int flags, const char *path, void *opts){ return get_sb_single (t, flags, opts, gadgetfs_fill_super);}static voidgadgetfs_kill_sb (struct super_block *sb){ kill_litter_super (sb); if (the_device) { put_dev (the_device); the_device = NULL; }}/*----------------------------------------------------------------------*/static struct file_system_type gadgetfs_type = { .owner = THIS_MODULE, .name = shortname, .get_sb = gadgetfs_get_sb, .kill_sb = gadgetfs_kill_sb,};/*----------------------------------------------------------------------*/static int __init init (void){ int status; status = register_filesystem (&gadgetfs_type); if (status == 0) pr_info ("%s: %s, version " DRIVER_VERSION "\n", shortname, driver_desc); return status;}module_init (init);static void __exit cleanup (void){ pr_debug ("unregister %s\n", shortname); unregister_filesystem (&gadgetfs_type);}module_exit (cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -