cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

file.c (6349B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * drivers/usb/core/file.c
      4 *
      5 * (C) Copyright Linus Torvalds 1999
      6 * (C) Copyright Johannes Erdfelt 1999-2001
      7 * (C) Copyright Andreas Gal 1999
      8 * (C) Copyright Gregory P. Smith 1999
      9 * (C) Copyright Deti Fliegl 1999 (new USB architecture)
     10 * (C) Copyright Randy Dunlap 2000
     11 * (C) Copyright David Brownell 2000-2001 (kernel hotplug, usb_device_id,
     12 *	more docs, etc)
     13 * (C) Copyright Yggdrasil Computing, Inc. 2000
     14 *     (usb_device_id matching changes by Adam J. Richter)
     15 * (C) Copyright Greg Kroah-Hartman 2002-2003
     16 *
     17 * Released under the GPLv2 only.
     18 */
     19
     20#include <linux/module.h>
     21#include <linux/errno.h>
     22#include <linux/rwsem.h>
     23#include <linux/slab.h>
     24#include <linux/string.h>
     25#include <linux/usb.h>
     26
     27#include "usb.h"
     28
     29#define MAX_USB_MINORS	256
     30static const struct file_operations *usb_minors[MAX_USB_MINORS];
     31static DECLARE_RWSEM(minor_rwsem);
     32static DEFINE_MUTEX(init_usb_class_mutex);
     33
     34static int usb_open(struct inode *inode, struct file *file)
     35{
     36	int err = -ENODEV;
     37	const struct file_operations *new_fops;
     38
     39	down_read(&minor_rwsem);
     40	new_fops = fops_get(usb_minors[iminor(inode)]);
     41
     42	if (!new_fops)
     43		goto done;
     44
     45	replace_fops(file, new_fops);
     46	/* Curiouser and curiouser... NULL ->open() as "no device" ? */
     47	if (file->f_op->open)
     48		err = file->f_op->open(inode, file);
     49 done:
     50	up_read(&minor_rwsem);
     51	return err;
     52}
     53
     54static const struct file_operations usb_fops = {
     55	.owner =	THIS_MODULE,
     56	.open =		usb_open,
     57	.llseek =	noop_llseek,
     58};
     59
     60static struct usb_class {
     61	struct kref kref;
     62	struct class *class;
     63} *usb_class;
     64
     65static char *usb_devnode(struct device *dev, umode_t *mode)
     66{
     67	struct usb_class_driver *drv;
     68
     69	drv = dev_get_drvdata(dev);
     70	if (!drv || !drv->devnode)
     71		return NULL;
     72	return drv->devnode(dev, mode);
     73}
     74
     75static int init_usb_class(void)
     76{
     77	int result = 0;
     78
     79	if (usb_class != NULL) {
     80		kref_get(&usb_class->kref);
     81		goto exit;
     82	}
     83
     84	usb_class = kmalloc(sizeof(*usb_class), GFP_KERNEL);
     85	if (!usb_class) {
     86		result = -ENOMEM;
     87		goto exit;
     88	}
     89
     90	kref_init(&usb_class->kref);
     91	usb_class->class = class_create(THIS_MODULE, "usbmisc");
     92	if (IS_ERR(usb_class->class)) {
     93		result = PTR_ERR(usb_class->class);
     94		printk(KERN_ERR "class_create failed for usb devices\n");
     95		kfree(usb_class);
     96		usb_class = NULL;
     97		goto exit;
     98	}
     99	usb_class->class->devnode = usb_devnode;
    100
    101exit:
    102	return result;
    103}
    104
    105static void release_usb_class(struct kref *kref)
    106{
    107	/* Ok, we cheat as we know we only have one usb_class */
    108	class_destroy(usb_class->class);
    109	kfree(usb_class);
    110	usb_class = NULL;
    111}
    112
    113static void destroy_usb_class(void)
    114{
    115	mutex_lock(&init_usb_class_mutex);
    116	kref_put(&usb_class->kref, release_usb_class);
    117	mutex_unlock(&init_usb_class_mutex);
    118}
    119
    120int usb_major_init(void)
    121{
    122	int error;
    123
    124	error = register_chrdev(USB_MAJOR, "usb", &usb_fops);
    125	if (error)
    126		printk(KERN_ERR "Unable to get major %d for usb devices\n",
    127		       USB_MAJOR);
    128
    129	return error;
    130}
    131
    132void usb_major_cleanup(void)
    133{
    134	unregister_chrdev(USB_MAJOR, "usb");
    135}
    136
    137/**
    138 * usb_register_dev - register a USB device, and ask for a minor number
    139 * @intf: pointer to the usb_interface that is being registered
    140 * @class_driver: pointer to the usb_class_driver for this device
    141 *
    142 * This should be called by all USB drivers that use the USB major number.
    143 * If CONFIG_USB_DYNAMIC_MINORS is enabled, the minor number will be
    144 * dynamically allocated out of the list of available ones.  If it is not
    145 * enabled, the minor number will be based on the next available free minor,
    146 * starting at the class_driver->minor_base.
    147 *
    148 * This function also creates a usb class device in the sysfs tree.
    149 *
    150 * usb_deregister_dev() must be called when the driver is done with
    151 * the minor numbers given out by this function.
    152 *
    153 * Return: -EINVAL if something bad happens with trying to register a
    154 * device, and 0 on success.
    155 */
    156int usb_register_dev(struct usb_interface *intf,
    157		     struct usb_class_driver *class_driver)
    158{
    159	int retval;
    160	int minor_base = class_driver->minor_base;
    161	int minor;
    162	char name[20];
    163
    164#ifdef CONFIG_USB_DYNAMIC_MINORS
    165	/*
    166	 * We don't care what the device tries to start at, we want to start
    167	 * at zero to pack the devices into the smallest available space with
    168	 * no holes in the minor range.
    169	 */
    170	minor_base = 0;
    171#endif
    172
    173	if (class_driver->fops == NULL)
    174		return -EINVAL;
    175	if (intf->minor >= 0)
    176		return -EADDRINUSE;
    177
    178	mutex_lock(&init_usb_class_mutex);
    179	retval = init_usb_class();
    180	mutex_unlock(&init_usb_class_mutex);
    181
    182	if (retval)
    183		return retval;
    184
    185	dev_dbg(&intf->dev, "looking for a minor, starting at %d\n", minor_base);
    186
    187	down_write(&minor_rwsem);
    188	for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) {
    189		if (usb_minors[minor])
    190			continue;
    191
    192		usb_minors[minor] = class_driver->fops;
    193		intf->minor = minor;
    194		break;
    195	}
    196	if (intf->minor < 0) {
    197		up_write(&minor_rwsem);
    198		return -EXFULL;
    199	}
    200
    201	/* create a usb class device for this usb interface */
    202	snprintf(name, sizeof(name), class_driver->name, minor - minor_base);
    203	intf->usb_dev = device_create(usb_class->class, &intf->dev,
    204				      MKDEV(USB_MAJOR, minor), class_driver,
    205				      "%s", kbasename(name));
    206	if (IS_ERR(intf->usb_dev)) {
    207		usb_minors[minor] = NULL;
    208		intf->minor = -1;
    209		retval = PTR_ERR(intf->usb_dev);
    210	}
    211	up_write(&minor_rwsem);
    212	return retval;
    213}
    214EXPORT_SYMBOL_GPL(usb_register_dev);
    215
    216/**
    217 * usb_deregister_dev - deregister a USB device's dynamic minor.
    218 * @intf: pointer to the usb_interface that is being deregistered
    219 * @class_driver: pointer to the usb_class_driver for this device
    220 *
    221 * Used in conjunction with usb_register_dev().  This function is called
    222 * when the USB driver is finished with the minor numbers gotten from a
    223 * call to usb_register_dev() (usually when the device is disconnected
    224 * from the system.)
    225 *
    226 * This function also removes the usb class device from the sysfs tree.
    227 *
    228 * This should be called by all drivers that use the USB major number.
    229 */
    230void usb_deregister_dev(struct usb_interface *intf,
    231			struct usb_class_driver *class_driver)
    232{
    233	if (intf->minor == -1)
    234		return;
    235
    236	dev_dbg(&intf->dev, "removing %d minor\n", intf->minor);
    237	device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
    238
    239	down_write(&minor_rwsem);
    240	usb_minors[intf->minor] = NULL;
    241	up_write(&minor_rwsem);
    242
    243	intf->usb_dev = NULL;
    244	intf->minor = -1;
    245	destroy_usb_class();
    246}
    247EXPORT_SYMBOL_GPL(usb_deregister_dev);