⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 base.c

📁 《嵌入式系统设计与实例开发实验教材二源码》Linux内核移植与编译实验
💻 C
📖 第 1 页 / 共 5 页
字号:
 *		this to whatever you like, and change it once the file is opened (the next *		file opened will not see this change). * *	Returns a handle which may later be used in a call to devfs_unregister(). *	On failure %NULL is returned. */devfs_handle_t devfs_register (devfs_handle_t dir, const char *name,			       unsigned int flags,			       unsigned int major, unsigned int minor,			       umode_t mode, void *ops, void *info){    char devtype = S_ISCHR (mode) ? DEVFS_SPECIAL_CHR : DEVFS_SPECIAL_BLK;    int err;    kdev_t devnum = NODEV;    struct devfs_entry *de;    if (name == NULL)    {	PRINTK ("(): NULL name pointer\n");	return NULL;    }    if (ops == NULL)    {	if ( S_ISBLK (mode) ) ops = (void *) get_blkfops (major);	if (ops == NULL)	{	    PRINTK ("(%s): NULL ops pointer\n", name);	    return NULL;	}	PRINTK ("(%s): NULL ops, got %p from major table\n", name, ops);    }    if ( S_ISDIR (mode) )    {	PRINTK ("(%s): creating directories is not allowed\n", name);	return NULL;    }    if ( S_ISLNK (mode) )    {	PRINTK ("(%s): creating symlinks is not allowed\n", name);	return NULL;    }    if ( ( S_ISCHR (mode) || S_ISBLK (mode) ) &&	 (flags & DEVFS_FL_AUTO_DEVNUM) )    {	if ( kdev_none ( devnum = devfs_alloc_devnum (devtype) ) )	{	    PRINTK ("(%s): exhausted %s device numbers\n",		    name, S_ISCHR (mode) ? "char" : "block");	    return NULL;	}	major = major (devnum);	minor = minor (devnum);    }    if ( ( de = _devfs_prepare_leaf (&dir, name, mode) ) == NULL )    {	PRINTK ("(%s): could not prepare leaf\n", name);	if ( !kdev_none (devnum) ) devfs_dealloc_devnum (devtype, devnum);	return NULL;    }    if ( S_ISCHR (mode) || S_ISBLK (mode) )    {	de->u.fcb.u.device.major = major;	de->u.fcb.u.device.minor = minor;	de->u.fcb.autogen = kdev_none (devnum) ? FALSE : TRUE;    }    else if ( !S_ISREG (mode) )    {	PRINTK ("(%s): illegal mode: %x\n", name, mode);	devfs_put (de);	devfs_put (dir);	return (NULL);    }    de->info = info;    if (flags & DEVFS_FL_CURRENT_OWNER)    {	de->inode.uid = current->uid;	de->inode.gid = current->gid;    }    else    {	de->inode.uid = 0;	de->inode.gid = 0;    }    de->u.fcb.ops = ops;    de->u.fcb.auto_owner = (flags & DEVFS_FL_AUTO_OWNER) ? TRUE : FALSE;    de->u.fcb.aopen_notify = (flags & DEVFS_FL_AOPEN_NOTIFY) ? TRUE : FALSE;    de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE;    if (flags & DEVFS_FL_REMOVABLE) de->u.fcb.removable = TRUE;    if ( ( err = _devfs_append_entry (dir, de, de->u.fcb.removable, NULL) )	 != 0 )    {	PRINTK ("(%s): could not append to parent, err: %d\n", name, err);	devfs_put (dir);	if ( !kdev_none (devnum) ) devfs_dealloc_devnum (devtype, devnum);	return NULL;    }    DPRINTK (DEBUG_REGISTER, "(%s): de: %p dir: %p \"%s\"  pp: %p\n",	     name, de, dir, dir->name, dir->parent);    devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, flags & DEVFS_FL_WAIT);    devfs_put (dir);    return de;}   /*  End Function devfs_register  *//** *	_devfs_unhook - Unhook a device entry from its parents list *	@de: The entry to unhook. * *	Returns %TRUE if the entry was unhooked, else %FALSE if it was *		previously unhooked. *	The caller must have a write lock on the parent directory. */static int _devfs_unhook (struct devfs_entry *de){    struct devfs_entry *parent;    if ( !de || (de->prev == de) ) return FALSE;    parent = de->parent;    if (de->prev == NULL) parent->u.dir.first = de->next;    else de->prev->next = de->next;    if (de->next == NULL) parent->u.dir.last = de->prev;    else de->next->prev = de->prev;    de->prev = de;          /*  Indicate we're unhooked                      */    de->next = NULL;        /*  Force early termination for <devfs_readdir>  */    if ( ( S_ISREG (de->mode) || S_ISCHR (de->mode) || S_ISBLK (de->mode) ) &&	 de->u.fcb.removable )	--parent->u.dir.num_removable;    return TRUE;}   /*  End Function _devfs_unhook  *//** *	_devfs_unregister - Unregister a device entry from it's parent. *	@dir: The parent directory. *	@de: The entry to unregister. * *	The caller must have a write lock on the parent directory, which is *	unlocked by this function. */static void _devfs_unregister (struct devfs_entry *dir, struct devfs_entry *de){    int unhooked = _devfs_unhook (de);    write_unlock (&dir->u.dir.lock);    if (!unhooked) return;    devfs_get (dir);    devfs_unregister (de->slave);  /*  Let it handle the locking  */    devfsd_notify (de, DEVFSD_NOTIFY_UNREGISTERED, 0);    free_dentry (de);    devfs_put (dir);    if ( !S_ISDIR (de->mode) ) return;    while (TRUE)  /*  Recursively unregister: this is a stack chomper  */    {	struct devfs_entry *child;	write_lock (&de->u.dir.lock);	de->u.dir.no_more_additions = TRUE;	child = de->u.dir.first;	VERIFY_ENTRY (child);	_devfs_unregister (de, child);	if (!child) break;	DPRINTK (DEBUG_UNREGISTER, "(%s): child: %p  refcount: %d\n",		 child->name, child, atomic_read (&child->refcount) );	devfs_put (child);    }}   /*  End Function _devfs_unregister  *//** *	devfs_unregister - Unregister a device entry. *	@de: A handle previously created by devfs_register() or returned from *		devfs_get_handle(). If this is %NULL the routine does nothing. */void devfs_unregister (devfs_handle_t de){    VERIFY_ENTRY (de);    if ( (de == NULL) || (de->parent == NULL) ) return;    DPRINTK (DEBUG_UNREGISTER, "(%s): de: %p  refcount: %d\n",	     de->name, de, atomic_read (&de->refcount) );    write_lock (&de->parent->u.dir.lock);    _devfs_unregister (de->parent, de);    devfs_put (de);}   /*  End Function devfs_unregister  */static int devfs_do_symlink (devfs_handle_t dir, const char *name,			     unsigned int flags, const char *link,			     devfs_handle_t *handle, void *info){    int err;    unsigned int linklength;    char *newlink;    struct devfs_entry *de;    if (handle != NULL) *handle = NULL;    if (name == NULL)    {	PRINTK ("(): NULL name pointer\n");	return -EINVAL;    }    if (link == NULL)    {	PRINTK ("(%s): NULL link pointer\n", name);	return -EINVAL;    }    linklength = strlen (link);    if ( ( newlink = kmalloc (linklength + 1, GFP_KERNEL) ) == NULL )	return -ENOMEM;    memcpy (newlink, link, linklength);    newlink[linklength] = '\0';    if ( ( de = _devfs_prepare_leaf (&dir, name, S_IFLNK | S_IRUGO | S_IXUGO) )	 == NULL )    {	PRINTK ("(%s): could not prepare leaf\n", name);	kfree (newlink);	return -ENOTDIR;    }    de->info = info;    de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE;    de->u.symlink.linkname = newlink;    de->u.symlink.length = linklength;    if ( ( err = _devfs_append_entry (dir, de, FALSE, NULL) ) != 0 )    {	PRINTK ("(%s): could not append to parent, err: %d\n", name, err);	devfs_put (dir);	return err;    }    devfs_put (dir);#ifdef CONFIG_DEVFS_DEBUG    spin_lock (&stat_lock);    stat_num_bytes += linklength + 1;    spin_unlock (&stat_lock);#endif    if (handle != NULL) *handle = de;    return 0;}   /*  End Function devfs_do_symlink  *//** *	devfs_mk_symlink Create a symbolic link in the devfs namespace. *	@dir: The handle to the parent devfs directory entry. If this is %NULL the *		new name is relative to the root of the devfs. *	@name: The name of the entry. *	@flags: A set of bitwise-ORed flags (DEVFS_FL_*). *	@link: The destination name. *	@handle: The handle to the symlink entry is written here. This may be %NULL. *	@info: An arbitrary pointer which will be associated with the entry. * *	Returns 0 on success, else a negative error code is returned. */int devfs_mk_symlink (devfs_handle_t dir, const char *name, unsigned int flags,		      const char *link, devfs_handle_t *handle, void *info){    int err;    devfs_handle_t de;    if (handle != NULL) *handle = NULL;    DPRINTK (DEBUG_REGISTER, "(%s)\n", name);    err = devfs_do_symlink (dir, name, flags, link, &de, info);    if (err) return err;    if (handle == NULL) de->vfs_deletable = TRUE;    else *handle = de;    devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, flags & DEVFS_FL_WAIT);    return 0;}   /*  End Function devfs_mk_symlink  *//** *	devfs_mk_dir - Create a directory in the devfs namespace. *	@dir: The handle to the parent devfs directory entry. If this is %NULL the *		new name is relative to the root of the devfs. *	@name: The name of the entry. *	@info: An arbitrary pointer which will be associated with the entry. * *	Use of this function is optional. The devfs_register() function *	will automatically create intermediate directories as needed. This function *	is provided for efficiency reasons, as it provides a handle to a directory. *	Returns a handle which may later be used in a call to devfs_unregister(). *	On failure %NULL is returned. */devfs_handle_t devfs_mk_dir (devfs_handle_t dir, const char *name, void *info){    int err;    struct devfs_entry *de, *old;    if (name == NULL)    {	PRINTK ("(): NULL name pointer\n");	return NULL;    }    if ( ( de = _devfs_prepare_leaf (&dir, name, MODE_DIR) ) == NULL )    {	PRINTK ("(%s): could not prepare leaf\n", name);	return NULL;    }    de->info = info;    if ( ( err = _devfs_append_entry (dir, de, FALSE, &old) ) != 0 )    {#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,1)	if ( old && S_ISDIR (old->mode) )	{	    PRINTK ("(%s): using old entry in dir: %p \"%s\"\n",		    name, dir, dir->name);	    old->vfs_deletable = FALSE;	    devfs_put (dir);	    return old;	}#endif	PRINTK ("(%s): could not append to dir: %p \"%s\", err: %d\n",		name, dir, dir->name, err);	devfs_put (old);	devfs_put (dir);	return NULL;    }    DPRINTK (DEBUG_REGISTER, "(%s): de: %p dir: %p \"%s\"\n",	     name, de, dir, dir->name);    devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED, 0);    devfs_put (dir);    return de;}   /*  End Function devfs_mk_dir  *//** *	devfs_get_handle - Find the handle of a devfs entry. *	@dir: The handle to the parent devfs directory entry. If this is %NULL the *		name is relative to the root of the devfs. *	@name: The name of the entry. *	@major: The major number. This is used if @name is %NULL. *	@minor: The minor number. This is used if @name is %NULL. *	@type: The type of special file to search for. This may be either *		%DEVFS_SPECIAL_CHR or %DEVFS_SPECIAL_BLK. *	@traverse_symlinks: If %TRUE then symlink entries in the devfs namespace are *		traversed. Symlinks pointing out of the devfs namespace will cause a *		failure. Symlink traversal consumes stack space. * *	Returns a handle which may later be used in a call to *	devfs_unregister(), devfs_get_flags(), or devfs_set_flags(). A *	subsequent devfs_put() is required to decrement the refcount. *	On failure %NULL is returned. */devfs_handle_t devfs_get_handle (devfs_handle_t dir, const char *name,				 unsigned int major, unsigned int minor,				 char type, int traverse_symlinks){    if ( (name != NULL) && (name[0] == '\0') ) name = NULL;    return _devfs_find_entry (dir, name, major, minor, type,traverse_symlinks);}   /*  End Function devfs_get_handle  *//*  Compatibility function. Will be removed in sometime in 2.5  */devfs_handle_t devfs_find_handle (devfs_handle_t dir, const char *name,				  unsigned int major, unsigned int minor,				  char type, int traverse_symlinks){    devfs_handle_t de;    de = devfs_get_handle (dir, name, major, minor, type, traverse_symlinks);    devfs_put (de);    return de;}   /*  End Function devfs_find_handle  *//** *	devfs_get_flags - Get the flags for a devfs entry. *	@de: The handle to the device entry. *	@flags: The flags are written here. * *	Returns 0

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -