📄 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.6 2000/03/13 16:44:38 acher Exp $ * * History: * 0.1 04.01.2000 Created *//*****************************************************************************/#define __NO_VERSION__#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 <asm/uaccess.h>#include "usbdevice_fs.h"/* --------------------------------------------------------------------- */static LIST_HEAD(superlist);struct special { const char *name; struct file_operations *fops; 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 struct usb_bus *usbdevfs_findbus(int busnr){ struct list_head *list; struct usb_bus *bus; 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) return bus; } 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) < 0) return 0; filp->f_pos++; i++; /* fall through */ case 1: if (filldir(dirent, "..", 2, i, IROOT) < 0) return 0; filp->f_pos++; i++; /* fall through */ default: while (i >= 2 && i < 2+NRSPECIAL) { spec = &special[filp->f_pos-2]; if (filldir(dirent, spec->name, strlen(spec->name), i, ISPECIAL | (filp->f_pos-2+IROOT)) < 0) return 0; filp->f_pos++; i++; } if (i < 2+NRSPECIAL) return 0; i -= 2+NRSPECIAL; lock_kernel(); for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) { if (i > 0) { i--; continue; } bus = list_entry(list, struct usb_bus, bus_list); sprintf(numbuf, "%03d", bus->busnum); if (filldir(dirent, numbuf, 3, filp->f_pos, IBUS | ((bus->busnum & 0xff) << 8)) < 0) break; filp->f_pos++; } unlock_kernel(); return 0; }}static int bus_readdir(struct usb_device *dev, unsigned long ino, int pos, struct file *filp, void *dirent, filldir_t filldir){ char numbuf[8]; unsigned int i; if (!dev) return pos; sprintf(numbuf, "%03d", dev->devnum); if (pos > 0) pos--; else { if (filldir(dirent, numbuf, 3, filp->f_pos, ino | (dev->devnum & 0xff)) < 0) return -1; filp->f_pos++; } for (i = 0; i < dev->maxchild; i++) { if (!dev->children[i]) continue; pos = bus_readdir(dev->children[i], ino, pos, filp, dirent, filldir); if (pos < 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -