linux C 字符串qu'',Linux字符设备驱动程序源文件

/*

*  linux/fs/char_dev.c

*

*  Copyright (C) 1991, 1992  Linus Torvalds

*/

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include "internal.h"

/*

* capabilities for /dev/mem, /dev/kmem and similar directly mappable character

* devices

* - permits shared-mmap for read, write and/or exec

* - does not permit private mmap in NOMMU mode (can't do COW)

* - no readahead or I/O queue unplugging required

*/

struct backing_dev_info directly_mappable_cdev_bdi = {

.name = "char",

.capabilities    = (

#ifdef CONFIG_MMU

/* permit private copies of the data to be taken */

BDI_CAP_MAP_COPY |

#endif

/* permit direct mmap, for read, write or exec */

BDI_CAP_MAP_DIRECT |

BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP |

/* no writeback happens */

BDI_CAP_NO_ACCT_AND_WRITEBACK),

};

static struct kobj_map *cdev_map;

static DEFINE_MUTEX(chrdevs_lock);

static struct char_device_struct {

struct char_device_struct *next;

unsigned int major;

unsigned int baseminor;

int minorct;

char name[64];

struct cdev *cdev;        /* will die */

} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];

/* index in the above */

static inline int major_to_index(int major)

{

return major % CHRDEV_MAJOR_HASH_SIZE;

}

#ifdef CONFIG_PROC_FS

void chrdev_show(struct seq_file *f, off_t offset)

{

struct char_device_struct *cd;

if (offset < CHRDEV_MAJOR_HASH_SIZE) {

mutex_lock(&chrdevs_lock);

for (cd = chrdevs[offset]; cd; cd = cd->next)

seq_printf(f, "%3d %s\n", cd->major, cd->name);

mutex_unlock(&chrdevs_lock);

}

}

#endif /* CONFIG_PROC_FS */

/*

* Register a single major with a specified minor range.

*

* If major == 0 this functions will dynamically allocate a major and return

* its number.

*

* If major > 0 this function will attempt to reserve the passed range of

* minors and will return zero on success.

*

* Returns a -ve errno on failure.

*/

static struct char_device_struct *

__register_chrdev_region(unsigned int major, unsigned int baseminor,

int minorct, const char *name)

{

struct char_device_struct *cd, **cp;

int ret = 0;

int i;

cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);

if (cd == NULL)

return ERR_PTR(-ENOMEM);

mutex_lock(&chrdevs_lock);

/* temporary */

if (major == 0) {

for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) {

if (chrdevs[i] == NULL)

break;

}

if (i == 0) {

ret = -EBUSY;

goto out;

}

major = i;

ret = major;

}

cd->major = major;

cd->baseminor = baseminor;

cd->minorct = minorct;

strlcpy(cd->name, name, sizeof(cd->name));

i = major_to_index(major);

for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)

if ((*cp)->major > major ||

((*cp)->major == major &&

(((*cp)->baseminor >= baseminor) ||

((*cp)->baseminor + (*cp)->minorct > baseminor))))

break;

/* Check for overlapping minor ranges.  */

if (*cp && (*cp)->major == major) {

int old_min = (*cp)->baseminor;

int old_max = (*cp)->baseminor + (*cp)->minorct - 1;

int new_min = baseminor;

int new_max = baseminor + minorct - 1;

/* New driver overlaps from the left.  */

if (new_max >= old_min && new_max <= old_max) {

ret = -EBUSY;

goto out;

}

/* New driver overlaps from the right.  */

if (new_min <= old_max && new_min >= old_min) {

ret = -EBUSY;

goto out;

}

}

cd->next = *cp;

*cp = cd;

mutex_unlock(&chrdevs_lock);

return cd;

out:

mutex_unlock(&chrdevs_lock);

kfree(cd);

return ERR_PTR(ret);

}

static struct char_device_struct *

__unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct)

{

struct char_device_struct *cd = NULL, **cp;

int i = major_to_index(major);

mutex_lock(&chrdevs_lock);

for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)

if ((*cp)->major == major &&

(*cp)->baseminor == baseminor &&

(*cp)->minorct == minorct)

break;

if (*cp) {

cd = *cp;

*cp = cd->next;

}

mutex_unlock(&chrdevs_lock);

return cd;

}

/**

* register_chrdev_region() - register a range of device numbers

* @from: the first in the desired range of device numbers; must include

*        the major number.

* @count: the number of consecutive device numbers required

* @name: the name of the device or driver.

*

* Return value is zero on success, a negative error code on failure.

*/

int register_chrdev_region(dev_t from, unsigned count, const char *name)

{

struct char_device_struct *cd;

dev_t to = from + count;

dev_t n, next;

for (n = from; n < to; n = next) {

next = MKDEV(MAJOR(n)+1, 0);

if (next > to)

next = to;

cd = __register_chrdev_region(MAJOR(n), MINOR(n),

next - n, name);

if (IS_ERR(cd))

goto fail;

}

return 0;

fail:

to = n;

for (n = from; n < to; n = next) {

next = MKDEV(MAJOR(n)+1, 0);

kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));

}

return PTR_ERR(cd);

}

/**

* alloc_chrdev_region() - register a range of char device numbers

* @dev: output parameter for first assigned number

* @baseminor: first of the requested range of minor numbers

* @count: the number of minor numbers required

* @name: the name of the associated device or driver

*

* Allocates a range of char device numbers.  The major number will be

* chosen dynamically, and returned (along with the first minor number)

* in @dev.  Returns zero or a negative error code.

*/

int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,

const char *name)

{

struct char_device_struct *cd;

cd = __register_chrdev_region(0, baseminor, count, name);

if (IS_ERR(cd))

return PTR_ERR(cd);

*dev = MKDEV(cd->major, cd->baseminor);

return 0;

}

/**

* __register_chrdev() - create and register a cdev occupying a range of minors

* @major: major device number or 0 for dynamic allocation

* @baseminor: first of the requested range of minor numbers

* @count: the number of minor numbers required

* @name: name of this range of devices

* @fops: file operations associated with this devices

*

* If @major == 0 this functions will dynamically allocate a major and return

* its number.

*

* If @major > 0 this function will attempt to reserve a device with the given

* major number and will return zero on success.

*

* Returns a -ve errno on failure.

*

* The name of this device has nothing to do with the name of the device in

* /dev. It only helps to keep track of the different owners of devices. If

* your module name has only one type of devices it's ok to use e.g. the name

* of the module here.

*/

int __register_chrdev(unsigned int major, unsigned int baseminor,

unsigned int count, const char *name,

const struct file_operations *fops)

{

struct char_device_struct *cd;

struct cdev *cdev;

int err = -ENOMEM;

cd = __register_chrdev_region(major, baseminor, count, name);

if (IS_ERR(cd))

return PTR_ERR(cd);

cdev = cdev_alloc();

if (!cdev)

goto out2;

cdev->owner = fops->owner;

cdev->ops = fops;

kobject_set_name(&cdev->kobj, "%s", name);

err = cdev_add(cdev, MKDEV(cd->major, baseminor), count);

if (err)

goto out;

cd->cdev = cdev;

return major ? 0 : cd->major;

out:

kobject_put(&cdev->kobj);

out2:

kfree(__unregister_chrdev_region(cd->major, baseminor, count));

return err;

}

/**

* unregister_chrdev_region() - return a range of device numbers

* @from: the first in the range of numbers to unregister

* @count: the number of device numbers to unregister

*

* This function will unregister a range of @count device numbers,

* starting with @from.  The caller should normally be the one who

* allocated those numbers in the first place...

*/

void unregister_chrdev_region(dev_t from, unsigned count)

{

dev_t to = from + count;

dev_t n, next;

for (n = from; n < to; n = next) {

next = MKDEV(MAJOR(n)+1, 0);

if (next > to)

next = to;

kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));

}

}

/**

* __unregister_chrdev - unregister and destroy a cdev

* @major: major device number

* @baseminor: first of the range of minor numbers

* @count: the number of minor numbers this cdev is occupying

* @name: name of this range of devices

*

* Unregister and destroy the cdev occupying the region described by

* @major, @baseminor and @count.  This function undoes what

* __register_chrdev() did.

*/

void __unregister_chrdev(unsigned int major, unsigned int baseminor,

unsigned int count, const char *name)

{

struct char_device_struct *cd;

cd = __unregister_chrdev_region(major, baseminor, count);

if (cd && cd->cdev)

cdev_del(cd->cdev);

kfree(cd);

}

static DEFINE_SPINLOCK(cdev_lock);

static struct kobject *cdev_get(struct cdev *p)

{

struct module *owner = p->owner;

struct kobject *kobj;

if (owner && !try_module_get(owner))

return NULL;

kobj = kobject_get(&p->kobj);

if (!kobj)

module_put(owner);

return kobj;

}

void cdev_put(struct cdev *p)

{

if (p) {

struct module *owner = p->owner;

kobject_put(&p->kobj);

module_put(owner);

}

}

/*

* Called every time a character special file is opened

*/

static int chrdev_open(struct inode *inode, struct file *filp)

{

struct cdev *p;

struct cdev *new = NULL;

int ret = 0;

spin_lock(&cdev_lock);

p = inode->i_cdev;

if (!p) {

struct kobject *kobj;

int idx;

spin_unlock(&cdev_lock);

kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx);

if (!kobj)

return -ENXIO;

new = container_of(kobj, struct cdev, kobj);

spin_lock(&cdev_lock);

/* Check i_cdev again in case somebody beat us to it while

we dropped the lock. */

p = inode->i_cdev;

if (!p) {

inode->i_cdev = p = new;

list_add(&inode->i_devices, &p->list);

new = NULL;

} else if (!cdev_get(p))

ret = -ENXIO;

} else if (!cdev_get(p))

ret = -ENXIO;

spin_unlock(&cdev_lock);

cdev_put(new);

if (ret)

return ret;

ret = -ENXIO;

filp->f_op = fops_get(p->ops);

if (!filp->f_op)

goto out_cdev_put;

if (filp->f_op->open) {

ret = filp->f_op->open(inode,filp);

if (ret)

goto out_cdev_put;

}

return 0;

out_cdev_put:

cdev_put(p);

return ret;

}

int cdev_index(struct inode *inode)

{

int idx;

struct kobject *kobj;

kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx);

if (!kobj)

return -1;

kobject_put(kobj);

return idx;

}

void cd_forget(struct inode *inode)

{

spin_lock(&cdev_lock);

list_del_init(&inode->i_devices);

inode->i_cdev = NULL;

spin_unlock(&cdev_lock);

}

static void cdev_purge(struct cdev *cdev)

{

spin_lock(&cdev_lock);

while (!list_empty(&cdev->list)) {

struct inode *inode;

inode = container_of(cdev->list.next, struct inode, i_devices);

list_del_init(&inode->i_devices);

inode->i_cdev = NULL;

}

spin_unlock(&cdev_lock);

}

/*

* Dummy default file-operations: the only thing this does

* is contain the open that then fills in the correct operations

* depending on the special file...

*/

const struct file_operations def_chr_fops = {

.open = chrdev_open,

};

static struct kobject *exact_match(dev_t dev, int *part, void *data)

{

struct cdev *p = data;

return &p->kobj;

}

static int exact_lock(dev_t dev, void *data)

{

struct cdev *p = data;

return cdev_get(p) ? 0 : -1;

}

/**

* cdev_add() - add a char device to the system

* @p: the cdev structure for the device

* @dev: the first device number for which this device is responsible

* @count: the number of consecutive minor numbers corresponding to this

*         device

*

* cdev_add() adds the device represented by @p to the system, making it

* live immediately.  A negative error code is returned on failure.

*/

int cdev_add(struct cdev *p, dev_t dev, unsigned count)

{

p->dev = dev;

p->count = count;

return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);

}

static void cdev_unmap(dev_t dev, unsigned count)

{

kobj_unmap(cdev_map, dev, count);

}

/**

* cdev_del() - remove a cdev from the system

* @p: the cdev structure to be removed

*

* cdev_del() removes @p from the system, possibly freeing the structure

* itself.

*/

void cdev_del(struct cdev *p)

{

cdev_unmap(p->dev, p->count);

kobject_put(&p->kobj);

}

static void cdev_default_release(struct kobject *kobj)

{

struct cdev *p = container_of(kobj, struct cdev, kobj);

cdev_purge(p);

}

static void cdev_dynamic_release(struct kobject *kobj)

{

struct cdev *p = container_of(kobj, struct cdev, kobj);

cdev_purge(p);

kfree(p);

}

static struct kobj_type ktype_cdev_default = {

.release    = cdev_default_release,

};

static struct kobj_type ktype_cdev_dynamic = {

.release    = cdev_dynamic_release,

};

/**

* cdev_alloc() - allocate a cdev structure

*

* Allocates and returns a cdev structure, or NULL on failure.

*/

struct cdev *cdev_alloc(void)

{

struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);

if (p) {

INIT_LIST_HEAD(&p->list);

kobject_init(&p->kobj, &ktype_cdev_dynamic);

}

return p;

}

/**

* cdev_init() - initialize a cdev structure

* @cdev: the structure to initialize

* @fops: the file_operations for this device

*

* Initializes @cdev, remembering @fops, making it ready to add to the

* system with cdev_add().

*/

void cdev_init(struct cdev *cdev, const struct file_operations *fops)

{

memset(cdev, 0, sizeof *cdev);

INIT_LIST_HEAD(&cdev->list);

kobject_init(&cdev->kobj, &ktype_cdev_default);

cdev->ops = fops;

}

static struct kobject *base_probe(dev_t dev, int *part, void *data)

{

if (request_module("char-major-%d-%d", MAJOR(dev), MINOR(dev)) > 0)

/* Make old-style 2.4 aliases work */

request_module("char-major-%d", MAJOR(dev));

return NULL;

}

void __init chrdev_init(void)

{

cdev_map = kobj_map_init(base_probe, &chrdevs_lock);

bdi_init(&directly_mappable_cdev_bdi);

}

/* Let modules do char dev stuff */

EXPORT_SYMBOL(register_chrdev_region);

EXPORT_SYMBOL(unregister_chrdev_region);

EXPORT_SYMBOL(alloc_chrdev_region);

EXPORT_SYMBOL(cdev_init);

EXPORT_SYMBOL(cdev_alloc);

EXPORT_SYMBOL(cdev_del);

EXPORT_SYMBOL(cdev_add);

EXPORT_SYMBOL(cdev_index);

EXPORT_SYMBOL(__register_chrdev);

EXPORT_SYMBOL(__unregister_chrdev);

EXPORT_SYMBOL(directly_mappable_cdev_bdi);

/drivers/base/base.h

/**

003 * struct bus_type_private - structure to hold the private to the driver core portions of the bus_type structure.

004 *

005 * @subsys - the struct kset that defines this bus.  This is the main kobject

006 * @drivers_kset - the list of drivers associated with this bus

007 * @devices_kset - the list of devices associated with this bus

008 * @klist_devices - the klist to iterate over the @devices_kset

009 * @klist_drivers - the klist to iterate over the @drivers_kset

010 * @bus_notifier - the bus notifier list for anything that cares about things

011 * on this bus.

012 * @bus - pointer back to the struct bus_type that this structure is associated

013 * with.

014 *

015 * This structure is the one that is the actual kobject allowing struct

016 * bus_type to be statically allocated safely.  Nothing outside of the driver

017 * core should ever touch these fields.

018 */

019 struct bus_type_private {

020         struct kset subsys;

021         struct kset *drivers_kset;

022         struct kset *devices_kset;

023         struct klist klist_devices;

024         struct klist klist_drivers;

025         struct blocking_notifier_head bus_notifier;

026         unsigned int drivers_autoprobe:1;

027         struct bus_type *bus;

028 };

029

030 struct driver_private {

031         struct kobject kobj;

032         struct klist klist_devices;

033         struct klist_node knode_bus;

034         struct module_kobject *mkobj;

035         struct device_driver *driver;

036 };

037 #define to_driver(obj) container_of(obj, struct driver_private, kobj)

038

039

040 /**

041 * struct class_private - structure to hold the private to the driver core portions of the class structure.

042 *

043 * @class_subsys - the struct kset that defines this class.  This is the main kobject

044 * @class_devices - list of devices associated with this class

045 * @class_interfaces - list of class_interfaces associated with this class

046 * @class_dirs - "glue" directory for virtual devices associated with this class

047 * @class_mutex - mutex to protect the children, devices, and interfaces lists.

048 * @class - pointer back to the struct class that this structure is associated

049 * with.

050 *

051 * This structure is the one that is the actual kobject allowing struct

052 * class to be statically allocated safely.  Nothing outside of the driver

053 * core should ever touch these fields.

054 */

055 struct class_private {

056         struct kset class_subsys;

057         struct klist class_devices;

058         struct list_head class_interfaces;

059         struct kset class_dirs;

060         struct mutex class_mutex;

061         struct class *class;

062 };

063 #define to_class(obj)   \

064         container_of(obj, struct class_private, class_subsys.kobj)

065

066 /**

067 * struct device_private - structure to hold the private to the driver core portions of the device structure.

068 *

069 * @klist_children - klist containing all children of this device

070 * @knode_parent - node in sibling list

071 * @knode_driver - node in driver list

072 * @knode_bus - node in bus list

073 * @driver_data - private pointer for driver specific info.  Will turn into a

074 * list soon.

075 * @device - pointer back to the struct class that this structure is

076 * associated with.

077 *

078 * Nothing outside of the driver core should ever touch these fields.

079 */

080 struct device_private {

081         struct klist klist_children;

082         struct klist_node knode_parent;

083         struct klist_node knode_driver;

084         struct klist_node knode_bus;

085         void *driver_data;

086         struct device *device;

087 };

088 #define to_device_private_parent(obj)   \

089         container_of(obj, struct device_private, knode_parent)

090 #define to_device_private_driver(obj)   \

091         container_of(obj, struct device_private, knode_driver)

092 #define to_device_private_bus(obj)      \

093         container_of(obj, struct device_private, knode_bus)

094

095 extern int device_private_init(struct device *dev);

096

097 /* initialisation functions */

098 extern int devices_init(void);

099 extern int buses_init(void);

100 extern int classes_init(void);

101 extern int firmware_init(void);

102 #ifdef CONFIG_SYS_HYPERVISOR

103 extern int hypervisor_init(void);

104 #else

105 static inline int hypervisor_init(void) { return 0; }

106 #endif

107 extern int platform_bus_init(void);

108 extern int system_bus_init(void);

109 extern int cpu_dev_init(void);

110

111 extern int bus_add_device(struct device *dev);

112 extern void bus_probe_device(struct device *dev);

113 extern void bus_remove_device(struct device *dev);

114

115 extern int bus_add_driver(struct device_driver *drv);

116 extern void bus_remove_driver(struct device_driver *drv);

117

118 extern void driver_detach(struct device_driver *drv);

119 extern int driver_probe_device(struct device_driver *drv, struct device *dev);

120 static inline int driver_match_device(struct device_driver *drv,

121                                       struct device *dev)

122 {

123         return drv->bus->match ? drv->bus->match(dev, drv) : 1;

124 }

125

126 extern void sysdev_shutdown(void);

127

128 extern char *make_class_name(const char *name, struct kobject *kobj);

129

130 extern int devres_release_all(struct device *dev);

131

132 extern struct kset *devices_kset;

133

134 #if defined(CONFIG_MODULES) && defined(CONFIG_SYSFS)

135 extern void module_add_driver(struct module *mod, struct device_driver *drv);

136 extern void module_remove_driver(struct device_driver *drv);

137 #else

138 static inline void module_add_driver(struct module *mod,

139                                      struct device_driver *drv) { }

140 static inline void module_remove_driver(struct device_driver *drv) { }

141 #endif

142

143 #ifdef CONFIG_DEVTMPFS

144 extern int devtmpfs_init(void);

145 #else

146 static inline int devtmpfs_init(void) { return 0; }

147 #endif0b1331709591d260c1c78e86d0c51c18.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值