📄 inode.c
字号:
/*****************************************************************************//* * inode.c -- Inode/Dentry functions for the USB device file system. * * Copyright (C) 2000 * Thomas Sailer (sailer@ife.ee.ethz.ch) * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: inode.c,v 1.1.1.1 2004/03/25 05:51:21 laputa Exp $ * * History: * 0.1 04.01.2000 Created *//*****************************************************************************/#define __NO_VERSION__#include <linux/config.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/sched.h>#include <linux/smp_lock.h>#include <linux/locks.h>#include <linux/init.h>#include <linux/proc_fs.h>#include <linux/usb.h>#include <linux/usbdevice_fs.h>#include <asm/uaccess.h>/* --------------------------------------------------------------------- *//* * This list of superblocks is still used, * but since usbdevfs became FS_SINGLE * there is only one super_block. */static LIST_HEAD(superlist);struct special { const char *name; struct file_operations *fops; struct inode *inode; struct list_head inodes;};static struct special special[] = { { "devices", &usbdevfs_devices_fops, }, { "drivers", &usbdevfs_drivers_fops, }};#define NRSPECIAL (sizeof(special)/sizeof(special[0]))/* --------------------------------------------------------------------- */static int dnumber(struct dentry *dentry){ const char *name; unsigned int s; if (dentry->d_name.len != 3) return -1; name = dentry->d_name.name; if (name[0] < '0' || name[0] > '9' || name[1] < '0' || name[1] > '9' || name[2] < '0' || name[2] > '9') return -1; s = name[0] - '0'; s = s * 10 + name[1] - '0'; s = s * 10 + name[2] - '0'; return s;}/* * utility functions; should be called with the kernel lock held * to protect against busses/devices appearing/disappearing */static void new_dev_inode(struct usb_device *dev, struct super_block *sb){ struct inode *inode; unsigned int devnum = dev->devnum; unsigned int busnum = dev->bus->busnum; if (devnum < 1 || devnum > 127 || busnum > 255) return; inode = iget(sb, IDEVICE | (busnum << 8) | devnum); if (!inode) { printk(KERN_ERR "usbdevfs: cannot create inode for bus %u device %u\n", busnum, devnum); return; } inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; inode->i_uid = sb->u.usbdevfs_sb.devuid; inode->i_gid = sb->u.usbdevfs_sb.devgid; inode->i_mode = sb->u.usbdevfs_sb.devmode | S_IFREG; inode->i_fop = &usbdevfs_device_file_operations; inode->i_size = sizeof(struct usb_device_descriptor); inode->u.usbdev_i.p.dev = dev; list_add_tail(&inode->u.usbdev_i.slist, &sb->u.usbdevfs_sb.ilist); list_add_tail(&inode->u.usbdev_i.dlist, &dev->inodes);}static void recurse_new_dev_inode(struct usb_device *dev, struct super_block *sb){ unsigned int i; if (!dev) return; new_dev_inode(dev, sb); for (i = 0; i < dev->maxchild; i++) { if (!dev->children[i]) continue; recurse_new_dev_inode(dev->children[i], sb); }}static void new_bus_inode(struct usb_bus *bus, struct super_block *sb){ struct inode *inode; unsigned int busnum = bus->busnum; if (busnum > 255) return; inode = iget(sb, IBUS | (busnum << 8)); if (!inode) { printk(KERN_ERR "usbdevfs: cannot create inode for bus %u\n", busnum); return; } inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; inode->i_uid = sb->u.usbdevfs_sb.busuid; inode->i_gid = sb->u.usbdevfs_sb.busgid; inode->i_mode = sb->u.usbdevfs_sb.busmode | S_IFDIR; inode->i_op = &usbdevfs_bus_inode_operations; inode->i_fop = &usbdevfs_bus_file_operations; inode->u.usbdev_i.p.bus = bus; list_add_tail(&inode->u.usbdev_i.slist, &sb->u.usbdevfs_sb.ilist); list_add_tail(&inode->u.usbdev_i.dlist, &bus->inodes);}static void free_inode(struct inode *inode){ inode->u.usbdev_i.p.bus = NULL; inode->u.usbdev_i.p.dev = NULL; inode->i_mode &= ~S_IRWXUGO; inode->i_uid = inode->i_gid = 0; inode->i_size = 0; list_del(&inode->u.usbdev_i.slist); INIT_LIST_HEAD(&inode->u.usbdev_i.slist); list_del(&inode->u.usbdev_i.dlist); INIT_LIST_HEAD(&inode->u.usbdev_i.dlist); iput(inode);}static int parse_options(struct super_block *s, char *data){ uid_t devuid = 0, busuid = 0, listuid = 0; gid_t devgid = 0, busgid = 0, listgid = 0; umode_t devmode = S_IWUSR | S_IRUGO, busmode = S_IXUGO | S_IRUGO, listmode = S_IRUGO; char *curopt = NULL, *value; /* parse options */ if (data) curopt = strtok(data, ","); for (; curopt; curopt = strtok(NULL, ",")) { if ((value = strchr(curopt, '=')) != NULL) *value++ = 0; if (!strcmp(curopt, "devuid")) { if (!value || !value[0]) return -EINVAL; devuid = simple_strtoul(value, &value, 0); if (*value) return -EINVAL; } if (!strcmp(curopt, "devgid")) { if (!value || !value[0]) return -EINVAL; devgid = simple_strtoul(value, &value, 0); if (*value) return -EINVAL; } if (!strcmp(curopt, "devmode")) { if (!value || !value[0]) return -EINVAL; devmode = simple_strtoul(value, &value, 0) & S_IRWXUGO; if (*value) return -EINVAL; } if (!strcmp(curopt, "busuid")) { if (!value || !value[0]) return -EINVAL; busuid = simple_strtoul(value, &value, 0); if (*value) return -EINVAL; } if (!strcmp(curopt, "busgid")) { if (!value || !value[0]) return -EINVAL; busgid = simple_strtoul(value, &value, 0); if (*value) return -EINVAL; } if (!strcmp(curopt, "busmode")) { if (!value || !value[0]) return -EINVAL; busmode = simple_strtoul(value, &value, 0) & S_IRWXUGO; if (*value) return -EINVAL; } if (!strcmp(curopt, "listuid")) { if (!value || !value[0]) return -EINVAL; listuid = simple_strtoul(value, &value, 0); if (*value) return -EINVAL; } if (!strcmp(curopt, "listgid")) { if (!value || !value[0]) return -EINVAL; listgid = simple_strtoul(value, &value, 0); if (*value) return -EINVAL; } if (!strcmp(curopt, "listmode")) { if (!value || !value[0]) return -EINVAL; listmode = simple_strtoul(value, &value, 0) & S_IRWXUGO; if (*value) return -EINVAL; } } s->u.usbdevfs_sb.devuid = devuid; s->u.usbdevfs_sb.devgid = devgid; s->u.usbdevfs_sb.devmode = devmode; s->u.usbdevfs_sb.busuid = busuid; s->u.usbdevfs_sb.busgid = busgid; s->u.usbdevfs_sb.busmode = busmode; s->u.usbdevfs_sb.listuid = listuid; s->u.usbdevfs_sb.listgid = listgid; s->u.usbdevfs_sb.listmode = listmode; return 0;}static struct usb_bus *usbdevfs_findbus(int busnr){ struct list_head *list; struct usb_bus *bus; down (&usb_bus_list_lock); for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) { bus = list_entry(list, struct usb_bus, bus_list); if (bus->busnum == busnr) { up (&usb_bus_list_lock); return bus; } } up (&usb_bus_list_lock); return NULL;}#if 0static struct usb_device *finddev(struct usb_device *dev, int devnr){ unsigned int i; struct usb_device *d2; if (!dev) return NULL; if (dev->devnum == devnr) return dev; for (i = 0; i < dev->maxchild; i++) { if (!dev->children[i]) continue; if ((d2 = finddev(dev->children[i], devnr))) return d2; } return NULL;}static struct usb_device *usbdevfs_finddevice(struct usb_bus *bus, int devnr){ return finddev(bus->root_hub, devnr);}#endif/* --------------------------------------------------------------------- */static int usbdevfs_revalidate(struct dentry *dentry, int flags){ struct inode *inode = dentry->d_inode; if (!inode) return 0; if (ITYPE(inode->i_ino) == IBUS && !inode->u.usbdev_i.p.bus) return 0; if (ITYPE(inode->i_ino) == IDEVICE && !inode->u.usbdev_i.p.dev) return 0; return 1;}static struct dentry_operations usbdevfs_dentry_operations = { d_revalidate: usbdevfs_revalidate,};static struct dentry *usbdevfs_root_lookup(struct inode *dir, struct dentry *dentry){ int busnr; unsigned long ino = 0; unsigned int i; struct inode *inode; /* sanity check */ if (dir->i_ino != IROOT) return ERR_PTR(-EINVAL); dentry->d_op = &usbdevfs_dentry_operations; busnr = dnumber(dentry); if (busnr >= 0 && busnr <= 255) ino = IBUS | (busnr << 8); if (!ino) { for (i = 0; i < NRSPECIAL; i++) { if (strlen(special[i].name) == dentry->d_name.len && !strncmp(special[i].name, dentry->d_name.name, dentry->d_name.len)) { ino = ISPECIAL | (i + IROOT + 1); break; } } } if (!ino) return ERR_PTR(-ENOENT); inode = iget(dir->i_sb, ino); if (!inode) return ERR_PTR(-EINVAL); if (inode && ITYPE(ino) == IBUS && inode->u.usbdev_i.p.bus == NULL) { iput(inode); inode = NULL; } d_add(dentry, inode); return NULL;}static struct dentry *usbdevfs_bus_lookup(struct inode *dir, struct dentry *dentry){ struct inode *inode; int devnr; /* sanity check */ if (ITYPE(dir->i_ino) != IBUS) return ERR_PTR(-EINVAL); dentry->d_op = &usbdevfs_dentry_operations; devnr = dnumber(dentry); if (devnr < 1 || devnr > 127) return ERR_PTR(-ENOENT); inode = iget(dir->i_sb, IDEVICE | (dir->i_ino & (0xff << 8)) | devnr); if (!inode) return ERR_PTR(-EINVAL); if (inode && inode->u.usbdev_i.p.dev == NULL) { iput(inode); inode = NULL; } d_add(dentry, inode); return NULL;}static int usbdevfs_root_readdir(struct file *filp, void *dirent, filldir_t filldir){ struct inode *inode = filp->f_dentry->d_inode; unsigned long ino = inode->i_ino; struct special *spec; struct list_head *list; struct usb_bus *bus; char numbuf[8]; unsigned int i; /* sanity check */ if (ino != IROOT) return -EINVAL; i = filp->f_pos; switch (i) { case 0: if (filldir(dirent, ".", 1, i, IROOT, DT_DIR) < 0) return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -