162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/char_dev.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/init.h> 962306a36Sopenharmony_ci#include <linux/fs.h> 1062306a36Sopenharmony_ci#include <linux/kdev_t.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <linux/string.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/major.h> 1562306a36Sopenharmony_ci#include <linux/errno.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/seq_file.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/kobject.h> 2062306a36Sopenharmony_ci#include <linux/kobj_map.h> 2162306a36Sopenharmony_ci#include <linux/cdev.h> 2262306a36Sopenharmony_ci#include <linux/mutex.h> 2362306a36Sopenharmony_ci#include <linux/backing-dev.h> 2462306a36Sopenharmony_ci#include <linux/tty.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include "internal.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic struct kobj_map *cdev_map; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic DEFINE_MUTEX(chrdevs_lock); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define CHRDEV_MAJOR_HASH_SIZE 255 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic struct char_device_struct { 3562306a36Sopenharmony_ci struct char_device_struct *next; 3662306a36Sopenharmony_ci unsigned int major; 3762306a36Sopenharmony_ci unsigned int baseminor; 3862306a36Sopenharmony_ci int minorct; 3962306a36Sopenharmony_ci char name[64]; 4062306a36Sopenharmony_ci struct cdev *cdev; /* will die */ 4162306a36Sopenharmony_ci} *chrdevs[CHRDEV_MAJOR_HASH_SIZE]; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/* index in the above */ 4462306a36Sopenharmony_cistatic inline int major_to_index(unsigned major) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci return major % CHRDEV_MAJOR_HASH_SIZE; 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_civoid chrdev_show(struct seq_file *f, off_t offset) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci struct char_device_struct *cd; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci mutex_lock(&chrdevs_lock); 5662306a36Sopenharmony_ci for (cd = chrdevs[major_to_index(offset)]; cd; cd = cd->next) { 5762306a36Sopenharmony_ci if (cd->major == offset) 5862306a36Sopenharmony_ci seq_printf(f, "%3d %s\n", cd->major, cd->name); 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci mutex_unlock(&chrdevs_lock); 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#endif /* CONFIG_PROC_FS */ 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic int find_dynamic_major(void) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci int i; 6862306a36Sopenharmony_ci struct char_device_struct *cd; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci for (i = ARRAY_SIZE(chrdevs)-1; i >= CHRDEV_MAJOR_DYN_END; i--) { 7162306a36Sopenharmony_ci if (chrdevs[i] == NULL) 7262306a36Sopenharmony_ci return i; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci for (i = CHRDEV_MAJOR_DYN_EXT_START; 7662306a36Sopenharmony_ci i >= CHRDEV_MAJOR_DYN_EXT_END; i--) { 7762306a36Sopenharmony_ci for (cd = chrdevs[major_to_index(i)]; cd; cd = cd->next) 7862306a36Sopenharmony_ci if (cd->major == i) 7962306a36Sopenharmony_ci break; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if (cd == NULL) 8262306a36Sopenharmony_ci return i; 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci return -EBUSY; 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci/* 8962306a36Sopenharmony_ci * Register a single major with a specified minor range. 9062306a36Sopenharmony_ci * 9162306a36Sopenharmony_ci * If major == 0 this function will dynamically allocate an unused major. 9262306a36Sopenharmony_ci * If major > 0 this function will attempt to reserve the range of minors 9362306a36Sopenharmony_ci * with given major. 9462306a36Sopenharmony_ci * 9562306a36Sopenharmony_ci */ 9662306a36Sopenharmony_cistatic struct char_device_struct * 9762306a36Sopenharmony_ci__register_chrdev_region(unsigned int major, unsigned int baseminor, 9862306a36Sopenharmony_ci int minorct, const char *name) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci struct char_device_struct *cd, *curr, *prev = NULL; 10162306a36Sopenharmony_ci int ret; 10262306a36Sopenharmony_ci int i; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (major >= CHRDEV_MAJOR_MAX) { 10562306a36Sopenharmony_ci pr_err("CHRDEV \"%s\" major requested (%u) is greater than the maximum (%u)\n", 10662306a36Sopenharmony_ci name, major, CHRDEV_MAJOR_MAX-1); 10762306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci if (minorct > MINORMASK + 1 - baseminor) { 11162306a36Sopenharmony_ci pr_err("CHRDEV \"%s\" minor range requested (%u-%u) is out of range of maximum range (%u-%u) for a single major\n", 11262306a36Sopenharmony_ci name, baseminor, baseminor + minorct - 1, 0, MINORMASK); 11362306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL); 11762306a36Sopenharmony_ci if (cd == NULL) 11862306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci mutex_lock(&chrdevs_lock); 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci if (major == 0) { 12362306a36Sopenharmony_ci ret = find_dynamic_major(); 12462306a36Sopenharmony_ci if (ret < 0) { 12562306a36Sopenharmony_ci pr_err("CHRDEV \"%s\" dynamic allocation region is full\n", 12662306a36Sopenharmony_ci name); 12762306a36Sopenharmony_ci goto out; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci major = ret; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci ret = -EBUSY; 13362306a36Sopenharmony_ci i = major_to_index(major); 13462306a36Sopenharmony_ci for (curr = chrdevs[i]; curr; prev = curr, curr = curr->next) { 13562306a36Sopenharmony_ci if (curr->major < major) 13662306a36Sopenharmony_ci continue; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci if (curr->major > major) 13962306a36Sopenharmony_ci break; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (curr->baseminor + curr->minorct <= baseminor) 14262306a36Sopenharmony_ci continue; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if (curr->baseminor >= baseminor + minorct) 14562306a36Sopenharmony_ci break; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci goto out; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci cd->major = major; 15162306a36Sopenharmony_ci cd->baseminor = baseminor; 15262306a36Sopenharmony_ci cd->minorct = minorct; 15362306a36Sopenharmony_ci strscpy(cd->name, name, sizeof(cd->name)); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (!prev) { 15662306a36Sopenharmony_ci cd->next = curr; 15762306a36Sopenharmony_ci chrdevs[i] = cd; 15862306a36Sopenharmony_ci } else { 15962306a36Sopenharmony_ci cd->next = prev->next; 16062306a36Sopenharmony_ci prev->next = cd; 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci mutex_unlock(&chrdevs_lock); 16462306a36Sopenharmony_ci return cd; 16562306a36Sopenharmony_ciout: 16662306a36Sopenharmony_ci mutex_unlock(&chrdevs_lock); 16762306a36Sopenharmony_ci kfree(cd); 16862306a36Sopenharmony_ci return ERR_PTR(ret); 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic struct char_device_struct * 17262306a36Sopenharmony_ci__unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct char_device_struct *cd = NULL, **cp; 17562306a36Sopenharmony_ci int i = major_to_index(major); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci mutex_lock(&chrdevs_lock); 17862306a36Sopenharmony_ci for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next) 17962306a36Sopenharmony_ci if ((*cp)->major == major && 18062306a36Sopenharmony_ci (*cp)->baseminor == baseminor && 18162306a36Sopenharmony_ci (*cp)->minorct == minorct) 18262306a36Sopenharmony_ci break; 18362306a36Sopenharmony_ci if (*cp) { 18462306a36Sopenharmony_ci cd = *cp; 18562306a36Sopenharmony_ci *cp = cd->next; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci mutex_unlock(&chrdevs_lock); 18862306a36Sopenharmony_ci return cd; 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci/** 19262306a36Sopenharmony_ci * register_chrdev_region() - register a range of device numbers 19362306a36Sopenharmony_ci * @from: the first in the desired range of device numbers; must include 19462306a36Sopenharmony_ci * the major number. 19562306a36Sopenharmony_ci * @count: the number of consecutive device numbers required 19662306a36Sopenharmony_ci * @name: the name of the device or driver. 19762306a36Sopenharmony_ci * 19862306a36Sopenharmony_ci * Return value is zero on success, a negative error code on failure. 19962306a36Sopenharmony_ci */ 20062306a36Sopenharmony_ciint register_chrdev_region(dev_t from, unsigned count, const char *name) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci struct char_device_struct *cd; 20362306a36Sopenharmony_ci dev_t to = from + count; 20462306a36Sopenharmony_ci dev_t n, next; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci for (n = from; n < to; n = next) { 20762306a36Sopenharmony_ci next = MKDEV(MAJOR(n)+1, 0); 20862306a36Sopenharmony_ci if (next > to) 20962306a36Sopenharmony_ci next = to; 21062306a36Sopenharmony_ci cd = __register_chrdev_region(MAJOR(n), MINOR(n), 21162306a36Sopenharmony_ci next - n, name); 21262306a36Sopenharmony_ci if (IS_ERR(cd)) 21362306a36Sopenharmony_ci goto fail; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci return 0; 21662306a36Sopenharmony_cifail: 21762306a36Sopenharmony_ci to = n; 21862306a36Sopenharmony_ci for (n = from; n < to; n = next) { 21962306a36Sopenharmony_ci next = MKDEV(MAJOR(n)+1, 0); 22062306a36Sopenharmony_ci kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n)); 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci return PTR_ERR(cd); 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci/** 22662306a36Sopenharmony_ci * alloc_chrdev_region() - register a range of char device numbers 22762306a36Sopenharmony_ci * @dev: output parameter for first assigned number 22862306a36Sopenharmony_ci * @baseminor: first of the requested range of minor numbers 22962306a36Sopenharmony_ci * @count: the number of minor numbers required 23062306a36Sopenharmony_ci * @name: the name of the associated device or driver 23162306a36Sopenharmony_ci * 23262306a36Sopenharmony_ci * Allocates a range of char device numbers. The major number will be 23362306a36Sopenharmony_ci * chosen dynamically, and returned (along with the first minor number) 23462306a36Sopenharmony_ci * in @dev. Returns zero or a negative error code. 23562306a36Sopenharmony_ci */ 23662306a36Sopenharmony_ciint alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, 23762306a36Sopenharmony_ci const char *name) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct char_device_struct *cd; 24062306a36Sopenharmony_ci cd = __register_chrdev_region(0, baseminor, count, name); 24162306a36Sopenharmony_ci if (IS_ERR(cd)) 24262306a36Sopenharmony_ci return PTR_ERR(cd); 24362306a36Sopenharmony_ci *dev = MKDEV(cd->major, cd->baseminor); 24462306a36Sopenharmony_ci return 0; 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci/** 24862306a36Sopenharmony_ci * __register_chrdev() - create and register a cdev occupying a range of minors 24962306a36Sopenharmony_ci * @major: major device number or 0 for dynamic allocation 25062306a36Sopenharmony_ci * @baseminor: first of the requested range of minor numbers 25162306a36Sopenharmony_ci * @count: the number of minor numbers required 25262306a36Sopenharmony_ci * @name: name of this range of devices 25362306a36Sopenharmony_ci * @fops: file operations associated with this devices 25462306a36Sopenharmony_ci * 25562306a36Sopenharmony_ci * If @major == 0 this functions will dynamically allocate a major and return 25662306a36Sopenharmony_ci * its number. 25762306a36Sopenharmony_ci * 25862306a36Sopenharmony_ci * If @major > 0 this function will attempt to reserve a device with the given 25962306a36Sopenharmony_ci * major number and will return zero on success. 26062306a36Sopenharmony_ci * 26162306a36Sopenharmony_ci * Returns a -ve errno on failure. 26262306a36Sopenharmony_ci * 26362306a36Sopenharmony_ci * The name of this device has nothing to do with the name of the device in 26462306a36Sopenharmony_ci * /dev. It only helps to keep track of the different owners of devices. If 26562306a36Sopenharmony_ci * your module name has only one type of devices it's ok to use e.g. the name 26662306a36Sopenharmony_ci * of the module here. 26762306a36Sopenharmony_ci */ 26862306a36Sopenharmony_ciint __register_chrdev(unsigned int major, unsigned int baseminor, 26962306a36Sopenharmony_ci unsigned int count, const char *name, 27062306a36Sopenharmony_ci const struct file_operations *fops) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci struct char_device_struct *cd; 27362306a36Sopenharmony_ci struct cdev *cdev; 27462306a36Sopenharmony_ci int err = -ENOMEM; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci cd = __register_chrdev_region(major, baseminor, count, name); 27762306a36Sopenharmony_ci if (IS_ERR(cd)) 27862306a36Sopenharmony_ci return PTR_ERR(cd); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci cdev = cdev_alloc(); 28162306a36Sopenharmony_ci if (!cdev) 28262306a36Sopenharmony_ci goto out2; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci cdev->owner = fops->owner; 28562306a36Sopenharmony_ci cdev->ops = fops; 28662306a36Sopenharmony_ci kobject_set_name(&cdev->kobj, "%s", name); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci err = cdev_add(cdev, MKDEV(cd->major, baseminor), count); 28962306a36Sopenharmony_ci if (err) 29062306a36Sopenharmony_ci goto out; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci cd->cdev = cdev; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci return major ? 0 : cd->major; 29562306a36Sopenharmony_ciout: 29662306a36Sopenharmony_ci kobject_put(&cdev->kobj); 29762306a36Sopenharmony_ciout2: 29862306a36Sopenharmony_ci kfree(__unregister_chrdev_region(cd->major, baseminor, count)); 29962306a36Sopenharmony_ci return err; 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci/** 30362306a36Sopenharmony_ci * unregister_chrdev_region() - unregister a range of device numbers 30462306a36Sopenharmony_ci * @from: the first in the range of numbers to unregister 30562306a36Sopenharmony_ci * @count: the number of device numbers to unregister 30662306a36Sopenharmony_ci * 30762306a36Sopenharmony_ci * This function will unregister a range of @count device numbers, 30862306a36Sopenharmony_ci * starting with @from. The caller should normally be the one who 30962306a36Sopenharmony_ci * allocated those numbers in the first place... 31062306a36Sopenharmony_ci */ 31162306a36Sopenharmony_civoid unregister_chrdev_region(dev_t from, unsigned count) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci dev_t to = from + count; 31462306a36Sopenharmony_ci dev_t n, next; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci for (n = from; n < to; n = next) { 31762306a36Sopenharmony_ci next = MKDEV(MAJOR(n)+1, 0); 31862306a36Sopenharmony_ci if (next > to) 31962306a36Sopenharmony_ci next = to; 32062306a36Sopenharmony_ci kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n)); 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci/** 32562306a36Sopenharmony_ci * __unregister_chrdev - unregister and destroy a cdev 32662306a36Sopenharmony_ci * @major: major device number 32762306a36Sopenharmony_ci * @baseminor: first of the range of minor numbers 32862306a36Sopenharmony_ci * @count: the number of minor numbers this cdev is occupying 32962306a36Sopenharmony_ci * @name: name of this range of devices 33062306a36Sopenharmony_ci * 33162306a36Sopenharmony_ci * Unregister and destroy the cdev occupying the region described by 33262306a36Sopenharmony_ci * @major, @baseminor and @count. This function undoes what 33362306a36Sopenharmony_ci * __register_chrdev() did. 33462306a36Sopenharmony_ci */ 33562306a36Sopenharmony_civoid __unregister_chrdev(unsigned int major, unsigned int baseminor, 33662306a36Sopenharmony_ci unsigned int count, const char *name) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci struct char_device_struct *cd; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci cd = __unregister_chrdev_region(major, baseminor, count); 34162306a36Sopenharmony_ci if (cd && cd->cdev) 34262306a36Sopenharmony_ci cdev_del(cd->cdev); 34362306a36Sopenharmony_ci kfree(cd); 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic DEFINE_SPINLOCK(cdev_lock); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic struct kobject *cdev_get(struct cdev *p) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci struct module *owner = p->owner; 35162306a36Sopenharmony_ci struct kobject *kobj; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci if (owner && !try_module_get(owner)) 35462306a36Sopenharmony_ci return NULL; 35562306a36Sopenharmony_ci kobj = kobject_get_unless_zero(&p->kobj); 35662306a36Sopenharmony_ci if (!kobj) 35762306a36Sopenharmony_ci module_put(owner); 35862306a36Sopenharmony_ci return kobj; 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_civoid cdev_put(struct cdev *p) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci if (p) { 36462306a36Sopenharmony_ci struct module *owner = p->owner; 36562306a36Sopenharmony_ci kobject_put(&p->kobj); 36662306a36Sopenharmony_ci module_put(owner); 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci/* 37162306a36Sopenharmony_ci * Called every time a character special file is opened 37262306a36Sopenharmony_ci */ 37362306a36Sopenharmony_cistatic int chrdev_open(struct inode *inode, struct file *filp) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci const struct file_operations *fops; 37662306a36Sopenharmony_ci struct cdev *p; 37762306a36Sopenharmony_ci struct cdev *new = NULL; 37862306a36Sopenharmony_ci int ret = 0; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci spin_lock(&cdev_lock); 38162306a36Sopenharmony_ci p = inode->i_cdev; 38262306a36Sopenharmony_ci if (!p) { 38362306a36Sopenharmony_ci struct kobject *kobj; 38462306a36Sopenharmony_ci int idx; 38562306a36Sopenharmony_ci spin_unlock(&cdev_lock); 38662306a36Sopenharmony_ci kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx); 38762306a36Sopenharmony_ci if (!kobj) 38862306a36Sopenharmony_ci return -ENXIO; 38962306a36Sopenharmony_ci new = container_of(kobj, struct cdev, kobj); 39062306a36Sopenharmony_ci spin_lock(&cdev_lock); 39162306a36Sopenharmony_ci /* Check i_cdev again in case somebody beat us to it while 39262306a36Sopenharmony_ci we dropped the lock. */ 39362306a36Sopenharmony_ci p = inode->i_cdev; 39462306a36Sopenharmony_ci if (!p) { 39562306a36Sopenharmony_ci inode->i_cdev = p = new; 39662306a36Sopenharmony_ci list_add(&inode->i_devices, &p->list); 39762306a36Sopenharmony_ci new = NULL; 39862306a36Sopenharmony_ci } else if (!cdev_get(p)) 39962306a36Sopenharmony_ci ret = -ENXIO; 40062306a36Sopenharmony_ci } else if (!cdev_get(p)) 40162306a36Sopenharmony_ci ret = -ENXIO; 40262306a36Sopenharmony_ci spin_unlock(&cdev_lock); 40362306a36Sopenharmony_ci cdev_put(new); 40462306a36Sopenharmony_ci if (ret) 40562306a36Sopenharmony_ci return ret; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci ret = -ENXIO; 40862306a36Sopenharmony_ci fops = fops_get(p->ops); 40962306a36Sopenharmony_ci if (!fops) 41062306a36Sopenharmony_ci goto out_cdev_put; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci replace_fops(filp, fops); 41362306a36Sopenharmony_ci if (filp->f_op->open) { 41462306a36Sopenharmony_ci ret = filp->f_op->open(inode, filp); 41562306a36Sopenharmony_ci if (ret) 41662306a36Sopenharmony_ci goto out_cdev_put; 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci return 0; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci out_cdev_put: 42262306a36Sopenharmony_ci cdev_put(p); 42362306a36Sopenharmony_ci return ret; 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_civoid cd_forget(struct inode *inode) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci spin_lock(&cdev_lock); 42962306a36Sopenharmony_ci list_del_init(&inode->i_devices); 43062306a36Sopenharmony_ci inode->i_cdev = NULL; 43162306a36Sopenharmony_ci inode->i_mapping = &inode->i_data; 43262306a36Sopenharmony_ci spin_unlock(&cdev_lock); 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_cistatic void cdev_purge(struct cdev *cdev) 43662306a36Sopenharmony_ci{ 43762306a36Sopenharmony_ci spin_lock(&cdev_lock); 43862306a36Sopenharmony_ci while (!list_empty(&cdev->list)) { 43962306a36Sopenharmony_ci struct inode *inode; 44062306a36Sopenharmony_ci inode = container_of(cdev->list.next, struct inode, i_devices); 44162306a36Sopenharmony_ci list_del_init(&inode->i_devices); 44262306a36Sopenharmony_ci inode->i_cdev = NULL; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci spin_unlock(&cdev_lock); 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci/* 44862306a36Sopenharmony_ci * Dummy default file-operations: the only thing this does 44962306a36Sopenharmony_ci * is contain the open that then fills in the correct operations 45062306a36Sopenharmony_ci * depending on the special file... 45162306a36Sopenharmony_ci */ 45262306a36Sopenharmony_ciconst struct file_operations def_chr_fops = { 45362306a36Sopenharmony_ci .open = chrdev_open, 45462306a36Sopenharmony_ci .llseek = noop_llseek, 45562306a36Sopenharmony_ci}; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistatic struct kobject *exact_match(dev_t dev, int *part, void *data) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci struct cdev *p = data; 46062306a36Sopenharmony_ci return &p->kobj; 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic int exact_lock(dev_t dev, void *data) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci struct cdev *p = data; 46662306a36Sopenharmony_ci return cdev_get(p) ? 0 : -1; 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci/** 47062306a36Sopenharmony_ci * cdev_add() - add a char device to the system 47162306a36Sopenharmony_ci * @p: the cdev structure for the device 47262306a36Sopenharmony_ci * @dev: the first device number for which this device is responsible 47362306a36Sopenharmony_ci * @count: the number of consecutive minor numbers corresponding to this 47462306a36Sopenharmony_ci * device 47562306a36Sopenharmony_ci * 47662306a36Sopenharmony_ci * cdev_add() adds the device represented by @p to the system, making it 47762306a36Sopenharmony_ci * live immediately. A negative error code is returned on failure. 47862306a36Sopenharmony_ci */ 47962306a36Sopenharmony_ciint cdev_add(struct cdev *p, dev_t dev, unsigned count) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci int error; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci p->dev = dev; 48462306a36Sopenharmony_ci p->count = count; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (WARN_ON(dev == WHITEOUT_DEV)) { 48762306a36Sopenharmony_ci error = -EBUSY; 48862306a36Sopenharmony_ci goto err; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci error = kobj_map(cdev_map, dev, count, NULL, 49262306a36Sopenharmony_ci exact_match, exact_lock, p); 49362306a36Sopenharmony_ci if (error) 49462306a36Sopenharmony_ci goto err; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci kobject_get(p->kobj.parent); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci return 0; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cierr: 50162306a36Sopenharmony_ci kfree_const(p->kobj.name); 50262306a36Sopenharmony_ci p->kobj.name = NULL; 50362306a36Sopenharmony_ci return error; 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci/** 50762306a36Sopenharmony_ci * cdev_set_parent() - set the parent kobject for a char device 50862306a36Sopenharmony_ci * @p: the cdev structure 50962306a36Sopenharmony_ci * @kobj: the kobject to take a reference to 51062306a36Sopenharmony_ci * 51162306a36Sopenharmony_ci * cdev_set_parent() sets a parent kobject which will be referenced 51262306a36Sopenharmony_ci * appropriately so the parent is not freed before the cdev. This 51362306a36Sopenharmony_ci * should be called before cdev_add. 51462306a36Sopenharmony_ci */ 51562306a36Sopenharmony_civoid cdev_set_parent(struct cdev *p, struct kobject *kobj) 51662306a36Sopenharmony_ci{ 51762306a36Sopenharmony_ci WARN_ON(!kobj->state_initialized); 51862306a36Sopenharmony_ci p->kobj.parent = kobj; 51962306a36Sopenharmony_ci} 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci/** 52262306a36Sopenharmony_ci * cdev_device_add() - add a char device and it's corresponding 52362306a36Sopenharmony_ci * struct device, linkink 52462306a36Sopenharmony_ci * @dev: the device structure 52562306a36Sopenharmony_ci * @cdev: the cdev structure 52662306a36Sopenharmony_ci * 52762306a36Sopenharmony_ci * cdev_device_add() adds the char device represented by @cdev to the system, 52862306a36Sopenharmony_ci * just as cdev_add does. It then adds @dev to the system using device_add 52962306a36Sopenharmony_ci * The dev_t for the char device will be taken from the struct device which 53062306a36Sopenharmony_ci * needs to be initialized first. This helper function correctly takes a 53162306a36Sopenharmony_ci * reference to the parent device so the parent will not get released until 53262306a36Sopenharmony_ci * all references to the cdev are released. 53362306a36Sopenharmony_ci * 53462306a36Sopenharmony_ci * This helper uses dev->devt for the device number. If it is not set 53562306a36Sopenharmony_ci * it will not add the cdev and it will be equivalent to device_add. 53662306a36Sopenharmony_ci * 53762306a36Sopenharmony_ci * This function should be used whenever the struct cdev and the 53862306a36Sopenharmony_ci * struct device are members of the same structure whose lifetime is 53962306a36Sopenharmony_ci * managed by the struct device. 54062306a36Sopenharmony_ci * 54162306a36Sopenharmony_ci * NOTE: Callers must assume that userspace was able to open the cdev and 54262306a36Sopenharmony_ci * can call cdev fops callbacks at any time, even if this function fails. 54362306a36Sopenharmony_ci */ 54462306a36Sopenharmony_ciint cdev_device_add(struct cdev *cdev, struct device *dev) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci int rc = 0; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci if (dev->devt) { 54962306a36Sopenharmony_ci cdev_set_parent(cdev, &dev->kobj); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci rc = cdev_add(cdev, dev->devt, 1); 55262306a36Sopenharmony_ci if (rc) 55362306a36Sopenharmony_ci return rc; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci rc = device_add(dev); 55762306a36Sopenharmony_ci if (rc && dev->devt) 55862306a36Sopenharmony_ci cdev_del(cdev); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci return rc; 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci/** 56462306a36Sopenharmony_ci * cdev_device_del() - inverse of cdev_device_add 56562306a36Sopenharmony_ci * @dev: the device structure 56662306a36Sopenharmony_ci * @cdev: the cdev structure 56762306a36Sopenharmony_ci * 56862306a36Sopenharmony_ci * cdev_device_del() is a helper function to call cdev_del and device_del. 56962306a36Sopenharmony_ci * It should be used whenever cdev_device_add is used. 57062306a36Sopenharmony_ci * 57162306a36Sopenharmony_ci * If dev->devt is not set it will not remove the cdev and will be equivalent 57262306a36Sopenharmony_ci * to device_del. 57362306a36Sopenharmony_ci * 57462306a36Sopenharmony_ci * NOTE: This guarantees that associated sysfs callbacks are not running 57562306a36Sopenharmony_ci * or runnable, however any cdevs already open will remain and their fops 57662306a36Sopenharmony_ci * will still be callable even after this function returns. 57762306a36Sopenharmony_ci */ 57862306a36Sopenharmony_civoid cdev_device_del(struct cdev *cdev, struct device *dev) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci device_del(dev); 58162306a36Sopenharmony_ci if (dev->devt) 58262306a36Sopenharmony_ci cdev_del(cdev); 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_cistatic void cdev_unmap(dev_t dev, unsigned count) 58662306a36Sopenharmony_ci{ 58762306a36Sopenharmony_ci kobj_unmap(cdev_map, dev, count); 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci/** 59162306a36Sopenharmony_ci * cdev_del() - remove a cdev from the system 59262306a36Sopenharmony_ci * @p: the cdev structure to be removed 59362306a36Sopenharmony_ci * 59462306a36Sopenharmony_ci * cdev_del() removes @p from the system, possibly freeing the structure 59562306a36Sopenharmony_ci * itself. 59662306a36Sopenharmony_ci * 59762306a36Sopenharmony_ci * NOTE: This guarantees that cdev device will no longer be able to be 59862306a36Sopenharmony_ci * opened, however any cdevs already open will remain and their fops will 59962306a36Sopenharmony_ci * still be callable even after cdev_del returns. 60062306a36Sopenharmony_ci */ 60162306a36Sopenharmony_civoid cdev_del(struct cdev *p) 60262306a36Sopenharmony_ci{ 60362306a36Sopenharmony_ci cdev_unmap(p->dev, p->count); 60462306a36Sopenharmony_ci kobject_put(&p->kobj); 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_cistatic void cdev_default_release(struct kobject *kobj) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci struct cdev *p = container_of(kobj, struct cdev, kobj); 61162306a36Sopenharmony_ci struct kobject *parent = kobj->parent; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci cdev_purge(p); 61462306a36Sopenharmony_ci kobject_put(parent); 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cistatic void cdev_dynamic_release(struct kobject *kobj) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci struct cdev *p = container_of(kobj, struct cdev, kobj); 62062306a36Sopenharmony_ci struct kobject *parent = kobj->parent; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci cdev_purge(p); 62362306a36Sopenharmony_ci kfree(p); 62462306a36Sopenharmony_ci kobject_put(parent); 62562306a36Sopenharmony_ci} 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_cistatic struct kobj_type ktype_cdev_default = { 62862306a36Sopenharmony_ci .release = cdev_default_release, 62962306a36Sopenharmony_ci}; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_cistatic struct kobj_type ktype_cdev_dynamic = { 63262306a36Sopenharmony_ci .release = cdev_dynamic_release, 63362306a36Sopenharmony_ci}; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci/** 63662306a36Sopenharmony_ci * cdev_alloc() - allocate a cdev structure 63762306a36Sopenharmony_ci * 63862306a36Sopenharmony_ci * Allocates and returns a cdev structure, or NULL on failure. 63962306a36Sopenharmony_ci */ 64062306a36Sopenharmony_cistruct cdev *cdev_alloc(void) 64162306a36Sopenharmony_ci{ 64262306a36Sopenharmony_ci struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL); 64362306a36Sopenharmony_ci if (p) { 64462306a36Sopenharmony_ci INIT_LIST_HEAD(&p->list); 64562306a36Sopenharmony_ci kobject_init(&p->kobj, &ktype_cdev_dynamic); 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci return p; 64862306a36Sopenharmony_ci} 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci/** 65162306a36Sopenharmony_ci * cdev_init() - initialize a cdev structure 65262306a36Sopenharmony_ci * @cdev: the structure to initialize 65362306a36Sopenharmony_ci * @fops: the file_operations for this device 65462306a36Sopenharmony_ci * 65562306a36Sopenharmony_ci * Initializes @cdev, remembering @fops, making it ready to add to the 65662306a36Sopenharmony_ci * system with cdev_add(). 65762306a36Sopenharmony_ci */ 65862306a36Sopenharmony_civoid cdev_init(struct cdev *cdev, const struct file_operations *fops) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci memset(cdev, 0, sizeof *cdev); 66162306a36Sopenharmony_ci INIT_LIST_HEAD(&cdev->list); 66262306a36Sopenharmony_ci kobject_init(&cdev->kobj, &ktype_cdev_default); 66362306a36Sopenharmony_ci cdev->ops = fops; 66462306a36Sopenharmony_ci} 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_cistatic struct kobject *base_probe(dev_t dev, int *part, void *data) 66762306a36Sopenharmony_ci{ 66862306a36Sopenharmony_ci if (request_module("char-major-%d-%d", MAJOR(dev), MINOR(dev)) > 0) 66962306a36Sopenharmony_ci /* Make old-style 2.4 aliases work */ 67062306a36Sopenharmony_ci request_module("char-major-%d", MAJOR(dev)); 67162306a36Sopenharmony_ci return NULL; 67262306a36Sopenharmony_ci} 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_civoid __init chrdev_init(void) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci cdev_map = kobj_map_init(base_probe, &chrdevs_lock); 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci/* Let modules do char dev stuff */ 68162306a36Sopenharmony_ciEXPORT_SYMBOL(register_chrdev_region); 68262306a36Sopenharmony_ciEXPORT_SYMBOL(unregister_chrdev_region); 68362306a36Sopenharmony_ciEXPORT_SYMBOL(alloc_chrdev_region); 68462306a36Sopenharmony_ciEXPORT_SYMBOL(cdev_init); 68562306a36Sopenharmony_ciEXPORT_SYMBOL(cdev_alloc); 68662306a36Sopenharmony_ciEXPORT_SYMBOL(cdev_del); 68762306a36Sopenharmony_ciEXPORT_SYMBOL(cdev_add); 68862306a36Sopenharmony_ciEXPORT_SYMBOL(cdev_set_parent); 68962306a36Sopenharmony_ciEXPORT_SYMBOL(cdev_device_add); 69062306a36Sopenharmony_ciEXPORT_SYMBOL(cdev_device_del); 69162306a36Sopenharmony_ciEXPORT_SYMBOL(__register_chrdev); 69262306a36Sopenharmony_ciEXPORT_SYMBOL(__unregister_chrdev); 693