mutex_lock(&chrdevs_lock); for (cd = chrdevs[major_to_index(offset)]; cd; cd = cd->next) { if (cd->major == offset)
seq_printf(f, "%3d %s\n", cd->major, cd->name);
}
mutex_unlock(&chrdevs_lock);
}
#endif/* CONFIG_PROC_FS */
staticint find_dynamic_major(void)
{ int i; struct char_device_struct *cd;
for (i = ARRAY_SIZE(chrdevs)-1; i >= CHRDEV_MAJOR_DYN_END; i--) { if (chrdevs[i] == NULL) return i;
}
for (i = CHRDEV_MAJOR_DYN_EXT_START;
i >= CHRDEV_MAJOR_DYN_EXT_END; i--) { for (cd = chrdevs[major_to_index(i)]; cd; cd = cd->next) if (cd->major == i) break;
if (major >= CHRDEV_MAJOR_MAX) {
pr_err("CHRDEV \"%s\" major requested (%u) is greater than the maximum (%u)\n",
name, major, CHRDEV_MAJOR_MAX-1); return ERR_PTR(-EINVAL);
}
if (minorct > MINORMASK + 1 - baseminor) {
pr_err("CHRDEV \"%s\" minor range requested (%u-%u) is out of range of maximum range (%u-%u) for a single major\n",
name, baseminor, baseminor + minorct - 1, 0, MINORMASK); return ERR_PTR(-EINVAL);
}
cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL); if (cd == NULL) return ERR_PTR(-ENOMEM);
mutex_lock(&chrdevs_lock);
if (major == 0) {
ret = find_dynamic_major(); if (ret < 0) {
pr_err("CHRDEV \"%s\" dynamic allocation region is full\n",
name); goto out;
}
major = ret;
}
ret = -EBUSY;
i = major_to_index(major); for (curr = chrdevs[i]; curr; prev = curr, curr = curr->next) { if (curr->major < major) continue;
if (curr->major > major) break;
if (curr->baseminor + curr->minorct <= baseminor) continue;
if (curr->baseminor >= baseminor + minorct) break;
staticstruct 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()-registerarangeofdevicenumbers *@from:thefirstinthedesiredrangeofdevicenumbers;mustinclude *themajornumber. *@count:thenumberofconsecutivedevicenumbersrequired *@name:thenameofthedeviceordriver. * *Returnvalueiszeroonsuccess,anegativeerrorcodeonfailure.
*/ int register_chrdev_region(dev_t from, unsigned count, constchar *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;
} return0;
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);
}
/** *unregister_chrdev_region()-unregisterarangeofdevicenumbers *@from:thefirstintherangeofnumberstounregister *@count:thenumberofdevicenumberstounregister * *Thisfunctionwillunregisterarangeof@countdevicenumbers, *startingwith@from.Thecallershouldnormallybetheonewho *allocatedthosenumbersinthefirstplace...
*/ 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));
}
}
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;
} elseif (!cdev_get(p))
ret = -ENXIO;
} elseif (!cdev_get(p))
ret = -ENXIO;
spin_unlock(&cdev_lock);
cdev_put(new); if (ret) return ret;
ret = -ENXIO;
fops = fops_get(p->ops); if (!fops) goto out_cdev_put;
replace_fops(filp, fops); if (filp->f_op->open) {
ret = filp->f_op->open(inode, filp); if (ret) goto out_cdev_put;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.