mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-09-18 22:14:16 +00:00 
			
		
		
		
	Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6: Driver Core: devtmpfs - kernel-maintained tmpfs-based /dev debugfs: Modify default debugfs directory for debugging pktcdvd. debugfs: Modified default dir of debugfs for debugging UHCI. debugfs: Change debugfs directory of IWMC3200 debugfs: Change debuhgfs directory of trace-events-sample.h debugfs: Fix mount directory of debugfs by default in events.txt hpilo: add poll f_op hpilo: add interrupt handler hpilo: staging for interrupt handling driver core: platform_device_add_data(): use kmemdup() Driver core: Add support for compatibility classes uio: add generic driver for PCI 2.3 devices driver-core: move dma-coherent.c from kernel to driver/base mem_class: fix bug mem_class: use minor as index instead of searching the array driver model: constify attribute groups UIO: remove 'default n' from Kconfig Driver core: Add accessor for device platform data Driver core: move dev_get/set_drvdata to drivers/base/dd.c Driver core: add new device to bus's list before probing
This commit is contained in:
		
						commit
						ab86e5765d
					
				
					 59 changed files with 1287 additions and 239 deletions
				
			
		|  | @ -25,6 +25,10 @@ | |||
| 	<year>2006-2008</year> | ||||
| 	<holder>Hans-Jürgen Koch.</holder> | ||||
| </copyright> | ||||
| <copyright> | ||||
| 	<year>2009</year> | ||||
| 	<holder>Red Hat Inc, Michael S. Tsirkin (mst@redhat.com)</holder> | ||||
| </copyright> | ||||
| 
 | ||||
| <legalnotice> | ||||
| <para> | ||||
|  | @ -41,6 +45,13 @@ GPL version 2. | |||
| </abstract> | ||||
| 
 | ||||
| <revhistory> | ||||
| 	<revision> | ||||
| 	<revnumber>0.9</revnumber> | ||||
| 	<date>2009-07-16</date> | ||||
| 	<authorinitials>mst</authorinitials> | ||||
| 	<revremark>Added generic pci driver | ||||
| 		</revremark> | ||||
| 	</revision> | ||||
| 	<revision> | ||||
| 	<revnumber>0.8</revnumber> | ||||
| 	<date>2008-12-24</date> | ||||
|  | @ -809,6 +820,158 @@ framework to set up sysfs files for this region. Simply leave it alone. | |||
| 
 | ||||
| </chapter> | ||||
| 
 | ||||
| <chapter id="uio_pci_generic" xreflabel="Using Generic driver for PCI cards"> | ||||
| <?dbhtml filename="uio_pci_generic.html"?> | ||||
| <title>Generic PCI UIO driver</title> | ||||
| 	<para> | ||||
| 	The generic driver is a kernel module named uio_pci_generic. | ||||
| 	It can work with any device compliant to PCI 2.3 (circa 2002) and | ||||
| 	any compliant PCI Express device. Using this, you only need to | ||||
|         write the userspace driver, removing the need to write | ||||
|         a hardware-specific kernel module. | ||||
| 	</para> | ||||
| 
 | ||||
| <sect1 id="uio_pci_generic_binding"> | ||||
| <title>Making the driver recognize the device</title> | ||||
| 	<para> | ||||
| Since the driver does not declare any device ids, it will not get loaded | ||||
| automatically and will not automatically bind to any devices, you must load it | ||||
| and allocate id to the driver yourself. For example: | ||||
| 	<programlisting> | ||||
|  modprobe uio_pci_generic | ||||
|  echo "8086 10f5" > /sys/bus/pci/drivers/uio_pci_generic/new_id | ||||
| 	</programlisting> | ||||
| 	</para> | ||||
| 	<para> | ||||
| If there already is a hardware specific kernel driver for your device, the | ||||
| generic driver still won't bind to it, in this case if you want to use the | ||||
| generic driver (why would you?) you'll have to manually unbind the hardware | ||||
| specific driver and bind the generic driver, like this: | ||||
| 	<programlisting> | ||||
|     echo -n 0000:00:19.0 > /sys/bus/pci/drivers/e1000e/unbind | ||||
|     echo -n 0000:00:19.0 > /sys/bus/pci/drivers/uio_pci_generic/bind | ||||
| 	</programlisting> | ||||
| 	</para> | ||||
| 	<para> | ||||
| You can verify that the device has been bound to the driver | ||||
| by looking for it in sysfs, for example like the following: | ||||
| 	<programlisting> | ||||
|     ls -l /sys/bus/pci/devices/0000:00:19.0/driver | ||||
| 	</programlisting> | ||||
| Which if successful should print | ||||
| 	<programlisting> | ||||
|   .../0000:00:19.0/driver -> ../../../bus/pci/drivers/uio_pci_generic | ||||
| 	</programlisting> | ||||
| Note that the generic driver will not bind to old PCI 2.2 devices. | ||||
| If binding the device failed, run the following command: | ||||
| 	<programlisting> | ||||
|   dmesg | ||||
| 	</programlisting> | ||||
| and look in the output for failure reasons | ||||
| 	</para> | ||||
| </sect1> | ||||
| 
 | ||||
| <sect1 id="uio_pci_generic_internals"> | ||||
| <title>Things to know about uio_pci_generic</title> | ||||
| 	<para> | ||||
| Interrupts are handled using the Interrupt Disable bit in the PCI command | ||||
| register and Interrupt Status bit in the PCI status register.  All devices | ||||
| compliant to PCI 2.3 (circa 2002) and all compliant PCI Express devices should | ||||
| support these bits.  uio_pci_generic detects this support, and won't bind to | ||||
| devices which do not support the Interrupt Disable Bit in the command register. | ||||
| 	</para> | ||||
| 	<para> | ||||
| On each interrupt, uio_pci_generic sets the Interrupt Disable bit. | ||||
| This prevents the device from generating further interrupts | ||||
| until the bit is cleared. The userspace driver should clear this | ||||
| bit before blocking and waiting for more interrupts. | ||||
| 	</para> | ||||
| </sect1> | ||||
| <sect1 id="uio_pci_generic_userspace"> | ||||
| <title>Writing userspace driver using uio_pci_generic</title> | ||||
| 	<para> | ||||
| Userspace driver can use pci sysfs interface, or the | ||||
| libpci libray that wraps it, to talk to the device and to | ||||
| re-enable interrupts by writing to the command register. | ||||
| 	</para> | ||||
| </sect1> | ||||
| <sect1 id="uio_pci_generic_example"> | ||||
| <title>Example code using uio_pci_generic</title> | ||||
| 	<para> | ||||
| Here is some sample userspace driver code using uio_pci_generic: | ||||
| <programlisting> | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <unistd.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/stat.h> | ||||
| #include <fcntl.h> | ||||
| #include <errno.h> | ||||
| 
 | ||||
| int main() | ||||
| { | ||||
| 	int uiofd; | ||||
| 	int configfd; | ||||
| 	int err; | ||||
| 	int i; | ||||
| 	unsigned icount; | ||||
| 	unsigned char command_high; | ||||
| 
 | ||||
| 	uiofd = open("/dev/uio0", O_RDONLY); | ||||
| 	if (uiofd < 0) { | ||||
| 		perror("uio open:"); | ||||
| 		return errno; | ||||
| 	} | ||||
| 	configfd = open("/sys/class/uio/uio0/device/config", O_RDWR); | ||||
| 	if (uiofd < 0) { | ||||
| 		perror("config open:"); | ||||
| 		return errno; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Read and cache command value */ | ||||
| 	err = pread(configfd, &command_high, 1, 5); | ||||
| 	if (err != 1) { | ||||
| 		perror("command config read:"); | ||||
| 		return errno; | ||||
| 	} | ||||
| 	command_high &= ~0x4; | ||||
| 
 | ||||
| 	for(i = 0;; ++i) { | ||||
| 		/* Print out a message, for debugging. */ | ||||
| 		if (i == 0) | ||||
| 			fprintf(stderr, "Started uio test driver.\n"); | ||||
| 		else | ||||
| 			fprintf(stderr, "Interrupts: %d\n", icount); | ||||
| 
 | ||||
| 		/****************************************/ | ||||
| 		/* Here we got an interrupt from the | ||||
| 		   device. Do something to it. */ | ||||
| 		/****************************************/ | ||||
| 
 | ||||
| 		/* Re-enable interrupts. */ | ||||
| 		err = pwrite(configfd, &command_high, 1, 5); | ||||
| 		if (err != 1) { | ||||
| 			perror("config write:"); | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		/* Wait for next interrupt. */ | ||||
| 		err = read(uiofd, &icount, 4); | ||||
| 		if (err != 4) { | ||||
| 			perror("uio read:"); | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 	return errno; | ||||
| } | ||||
| 
 | ||||
| </programlisting> | ||||
| 	</para> | ||||
| </sect1> | ||||
| 
 | ||||
| </chapter> | ||||
| 
 | ||||
| <appendix id="app1"> | ||||
| <title>Further information</title> | ||||
| <itemizedlist> | ||||
|  |  | |||
|  | @ -22,12 +22,12 @@ tracing information should be printed. | |||
| --------------------------------- | ||||
| 
 | ||||
| The events which are available for tracing can be found in the file | ||||
| /debug/tracing/available_events. | ||||
| /sys/kernel/debug/tracing/available_events. | ||||
| 
 | ||||
| To enable a particular event, such as 'sched_wakeup', simply echo it | ||||
| to /debug/tracing/set_event. For example: | ||||
| to /sys/kernel/debug/tracing/set_event. For example: | ||||
| 
 | ||||
| 	# echo sched_wakeup >> /debug/tracing/set_event | ||||
| 	# echo sched_wakeup >> /sys/kernel/debug/tracing/set_event | ||||
| 
 | ||||
| [ Note: '>>' is necessary, otherwise it will firstly disable | ||||
|   all the events. ] | ||||
|  | @ -35,15 +35,15 @@ to /debug/tracing/set_event. For example: | |||
| To disable an event, echo the event name to the set_event file prefixed | ||||
| with an exclamation point: | ||||
| 
 | ||||
| 	# echo '!sched_wakeup' >> /debug/tracing/set_event | ||||
| 	# echo '!sched_wakeup' >> /sys/kernel/debug/tracing/set_event | ||||
| 
 | ||||
| To disable all events, echo an empty line to the set_event file: | ||||
| 
 | ||||
| 	# echo > /debug/tracing/set_event | ||||
| 	# echo > /sys/kernel/debug/tracing/set_event | ||||
| 
 | ||||
| To enable all events, echo '*:*' or '*:' to the set_event file: | ||||
| 
 | ||||
| 	# echo *:* > /debug/tracing/set_event | ||||
| 	# echo *:* > /sys/kernel/debug/tracing/set_event | ||||
| 
 | ||||
| The events are organized into subsystems, such as ext4, irq, sched, | ||||
| etc., and a full event name looks like this: <subsystem>:<event>.  The | ||||
|  | @ -52,29 +52,29 @@ file.  All of the events in a subsystem can be specified via the syntax | |||
| "<subsystem>:*"; for example, to enable all irq events, you can use the | ||||
| command: | ||||
| 
 | ||||
| 	# echo 'irq:*' > /debug/tracing/set_event | ||||
| 	# echo 'irq:*' > /sys/kernel/debug/tracing/set_event | ||||
| 
 | ||||
| 2.2 Via the 'enable' toggle | ||||
| --------------------------- | ||||
| 
 | ||||
| The events available are also listed in /debug/tracing/events/ hierarchy | ||||
| The events available are also listed in /sys/kernel/debug/tracing/events/ hierarchy | ||||
| of directories. | ||||
| 
 | ||||
| To enable event 'sched_wakeup': | ||||
| 
 | ||||
| 	# echo 1 > /debug/tracing/events/sched/sched_wakeup/enable | ||||
| 	# echo 1 > /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable | ||||
| 
 | ||||
| To disable it: | ||||
| 
 | ||||
| 	# echo 0 > /debug/tracing/events/sched/sched_wakeup/enable | ||||
| 	# echo 0 > /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable | ||||
| 
 | ||||
| To enable all events in sched subsystem: | ||||
| 
 | ||||
| 	# echo 1 > /debug/tracing/events/sched/enable | ||||
| 	# echo 1 > /sys/kernel/debug/tracing/events/sched/enable | ||||
| 
 | ||||
| To eanble all events: | ||||
| 
 | ||||
| 	# echo 1 > /debug/tracing/events/enable | ||||
| 	# echo 1 > /sys/kernel/debug/tracing/events/enable | ||||
| 
 | ||||
| When reading one of these enable files, there are four results: | ||||
| 
 | ||||
|  |  | |||
|  | @ -2218,6 +2218,13 @@ T:	git git://git.kernel.org/pub/scm/linux/kernel/git/arnd/asm-generic.git | |||
| S:	Maintained | ||||
| F:	include/asm-generic | ||||
| 
 | ||||
| GENERIC UIO DRIVER FOR PCI DEVICES | ||||
| M:	Michael S. Tsirkin <mst@redhat.com> | ||||
| L:	kvm@vger.kernel.org | ||||
| L:	linux-kernel@vger.kernel.org | ||||
| S:	Supported | ||||
| F:	drivers/uio/uio_pci_generic.c | ||||
| 
 | ||||
| GFS2 FILE SYSTEM | ||||
| M:	Steven Whitehouse <swhiteho@redhat.com> | ||||
| L:	cluster-devel@redhat.com | ||||
|  |  | |||
|  | @ -903,7 +903,7 @@ static struct attribute_group disk_attr_group = { | |||
| 	.attrs = disk_attrs, | ||||
| }; | ||||
| 
 | ||||
| static struct attribute_group *disk_attr_groups[] = { | ||||
| static const struct attribute_group *disk_attr_groups[] = { | ||||
| 	&disk_attr_group, | ||||
| 	NULL | ||||
| }; | ||||
|  |  | |||
|  | @ -8,6 +8,31 @@ config UEVENT_HELPER_PATH | |||
| 	  Path to uevent helper program forked by the kernel for | ||||
| 	  every uevent. | ||||
| 
 | ||||
| config DEVTMPFS | ||||
| 	bool "Create a kernel maintained /dev tmpfs (EXPERIMENTAL)" | ||||
| 	depends on HOTPLUG && SHMEM && TMPFS | ||||
| 	help | ||||
| 	  This creates a tmpfs filesystem, and mounts it at bootup | ||||
| 	  and mounts it at /dev. The kernel driver core creates device | ||||
| 	  nodes for all registered devices in that filesystem. All device | ||||
| 	  nodes are owned by root and have the default mode of 0600. | ||||
| 	  Userspace can add and delete the nodes as needed. This is | ||||
| 	  intended to simplify bootup, and make it possible to delay | ||||
| 	  the initial coldplug at bootup done by udev in userspace. | ||||
| 	  It should also provide a simpler way for rescue systems | ||||
| 	  to bring up a kernel with dynamic major/minor numbers. | ||||
| 	  Meaningful symlinks, permissions and device ownership must | ||||
| 	  still be handled by userspace. | ||||
| 	  If unsure, say N here. | ||||
| 
 | ||||
| config DEVTMPFS_MOUNT | ||||
| 	bool "Automount devtmpfs at /dev" | ||||
| 	depends on DEVTMPFS | ||||
| 	help | ||||
| 	  This will mount devtmpfs at /dev if the kernel mounts the root | ||||
| 	  filesystem. It will not affect initramfs based mounting. | ||||
| 	  If unsure, say N here. | ||||
| 
 | ||||
| config STANDALONE | ||||
| 	bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL | ||||
| 	default y | ||||
|  |  | |||
|  | @ -4,8 +4,10 @@ obj-y			:= core.o sys.o bus.o dd.o \ | |||
| 			   driver.o class.o platform.o \
 | ||||
| 			   cpu.o firmware.o init.o map.o devres.o \
 | ||||
| 			   attribute_container.o transport_class.o | ||||
| obj-$(CONFIG_DEVTMPFS)	+= devtmpfs.o | ||||
| obj-y			+= power/ | ||||
| obj-$(CONFIG_HAS_DMA)	+= dma-mapping.o | ||||
| obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o | ||||
| obj-$(CONFIG_ISA)	+= isa.o | ||||
| obj-$(CONFIG_FW_LOADER)	+= firmware_class.o | ||||
| obj-$(CONFIG_NUMA)	+= node.o | ||||
|  |  | |||
|  | @ -70,6 +70,8 @@ struct class_private { | |||
|  * @knode_parent - node in sibling list | ||||
|  * @knode_driver - node in driver list | ||||
|  * @knode_bus - node in bus list | ||||
|  * @driver_data - private pointer for driver specific info.  Will turn into a | ||||
|  * list soon. | ||||
|  * @device - pointer back to the struct class that this structure is | ||||
|  * associated with. | ||||
|  * | ||||
|  | @ -80,6 +82,7 @@ struct device_private { | |||
| 	struct klist_node knode_parent; | ||||
| 	struct klist_node knode_driver; | ||||
| 	struct klist_node knode_bus; | ||||
| 	void *driver_data; | ||||
| 	struct device *device; | ||||
| }; | ||||
| #define to_device_private_parent(obj)	\ | ||||
|  | @ -89,6 +92,8 @@ struct device_private { | |||
| #define to_device_private_bus(obj)	\ | ||||
| 	container_of(obj, struct device_private, knode_bus) | ||||
| 
 | ||||
| extern int device_private_init(struct device *dev); | ||||
| 
 | ||||
| /* initialisation functions */ | ||||
| extern int devices_init(void); | ||||
| extern int buses_init(void); | ||||
|  | @ -104,7 +109,7 @@ extern int system_bus_init(void); | |||
| extern int cpu_dev_init(void); | ||||
| 
 | ||||
| extern int bus_add_device(struct device *dev); | ||||
| extern void bus_attach_device(struct device *dev); | ||||
| extern void bus_probe_device(struct device *dev); | ||||
| extern void bus_remove_device(struct device *dev); | ||||
| 
 | ||||
| extern int bus_add_driver(struct device_driver *drv); | ||||
|  | @ -134,3 +139,9 @@ static inline void module_add_driver(struct module *mod, | |||
| 				     struct device_driver *drv) { } | ||||
| static inline void module_remove_driver(struct device_driver *drv) { } | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_DEVTMPFS | ||||
| extern int devtmpfs_init(void); | ||||
| #else | ||||
| static inline int devtmpfs_init(void) { return 0; } | ||||
| #endif | ||||
|  |  | |||
|  | @ -459,8 +459,9 @@ static inline void remove_deprecated_bus_links(struct device *dev) { } | |||
|  * bus_add_device - add device to bus | ||||
|  * @dev: device being added | ||||
|  * | ||||
|  * - Add device's bus attributes. | ||||
|  * - Create links to device's bus. | ||||
|  * - Add the device to its bus's list of devices. | ||||
|  * - Create link to device's bus. | ||||
|  */ | ||||
| int bus_add_device(struct device *dev) | ||||
| { | ||||
|  | @ -483,6 +484,7 @@ int bus_add_device(struct device *dev) | |||
| 		error = make_deprecated_bus_links(dev); | ||||
| 		if (error) | ||||
| 			goto out_deprecated; | ||||
| 		klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices); | ||||
| 	} | ||||
| 	return 0; | ||||
| 
 | ||||
|  | @ -498,24 +500,19 @@ out_put: | |||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * bus_attach_device - add device to bus | ||||
|  * @dev: device tried to attach to a driver | ||||
|  * bus_probe_device - probe drivers for a new device | ||||
|  * @dev: device to probe | ||||
|  * | ||||
|  * - Add device to bus's list of devices. | ||||
|  * - Try to attach to driver. | ||||
|  * - Automatically probe for a driver if the bus allows it. | ||||
|  */ | ||||
| void bus_attach_device(struct device *dev) | ||||
| void bus_probe_device(struct device *dev) | ||||
| { | ||||
| 	struct bus_type *bus = dev->bus; | ||||
| 	int ret = 0; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (bus) { | ||||
| 		if (bus->p->drivers_autoprobe) | ||||
| 			ret = device_attach(dev); | ||||
| 	if (bus && bus->p->drivers_autoprobe) { | ||||
| 		ret = device_attach(dev); | ||||
| 		WARN_ON(ret < 0); | ||||
| 		if (ret >= 0) | ||||
| 			klist_add_tail(&dev->p->knode_bus, | ||||
| 				       &bus->p->klist_devices); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -488,6 +488,93 @@ void class_interface_unregister(struct class_interface *class_intf) | |||
| 	class_put(parent); | ||||
| } | ||||
| 
 | ||||
| struct class_compat { | ||||
| 	struct kobject *kobj; | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * class_compat_register - register a compatibility class | ||||
|  * @name: the name of the class | ||||
|  * | ||||
|  * Compatibility class are meant as a temporary user-space compatibility | ||||
|  * workaround when converting a family of class devices to a bus devices. | ||||
|  */ | ||||
| struct class_compat *class_compat_register(const char *name) | ||||
| { | ||||
| 	struct class_compat *cls; | ||||
| 
 | ||||
| 	cls = kmalloc(sizeof(struct class_compat), GFP_KERNEL); | ||||
| 	if (!cls) | ||||
| 		return NULL; | ||||
| 	cls->kobj = kobject_create_and_add(name, &class_kset->kobj); | ||||
| 	if (!cls->kobj) { | ||||
| 		kfree(cls); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	return cls; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(class_compat_register); | ||||
| 
 | ||||
| /**
 | ||||
|  * class_compat_unregister - unregister a compatibility class | ||||
|  * @cls: the class to unregister | ||||
|  */ | ||||
| void class_compat_unregister(struct class_compat *cls) | ||||
| { | ||||
| 	kobject_put(cls->kobj); | ||||
| 	kfree(cls); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(class_compat_unregister); | ||||
| 
 | ||||
| /**
 | ||||
|  * class_compat_create_link - create a compatibility class device link to | ||||
|  *			      a bus device | ||||
|  * @cls: the compatibility class | ||||
|  * @dev: the target bus device | ||||
|  * @device_link: an optional device to which a "device" link should be created | ||||
|  */ | ||||
| int class_compat_create_link(struct class_compat *cls, struct device *dev, | ||||
| 			     struct device *device_link) | ||||
| { | ||||
| 	int error; | ||||
| 
 | ||||
| 	error = sysfs_create_link(cls->kobj, &dev->kobj, dev_name(dev)); | ||||
| 	if (error) | ||||
| 		return error; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Optionally add a "device" link (typically to the parent), as a | ||||
| 	 * class device would have one and we want to provide as much | ||||
| 	 * backwards compatibility as possible. | ||||
| 	 */ | ||||
| 	if (device_link) { | ||||
| 		error = sysfs_create_link(&dev->kobj, &device_link->kobj, | ||||
| 					  "device"); | ||||
| 		if (error) | ||||
| 			sysfs_remove_link(cls->kobj, dev_name(dev)); | ||||
| 	} | ||||
| 
 | ||||
| 	return error; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(class_compat_create_link); | ||||
| 
 | ||||
| /**
 | ||||
|  * class_compat_remove_link - remove a compatibility class device link to | ||||
|  *			      a bus device | ||||
|  * @cls: the compatibility class | ||||
|  * @dev: the target bus device | ||||
|  * @device_link: an optional device to which a "device" link was previously | ||||
|  * 		 created | ||||
|  */ | ||||
| void class_compat_remove_link(struct class_compat *cls, struct device *dev, | ||||
| 			      struct device *device_link) | ||||
| { | ||||
| 	if (device_link) | ||||
| 		sysfs_remove_link(&dev->kobj, "device"); | ||||
| 	sysfs_remove_link(cls->kobj, dev_name(dev)); | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(class_compat_remove_link); | ||||
| 
 | ||||
| int __init classes_init(void) | ||||
| { | ||||
| 	class_kset = kset_create_and_add("class", NULL, NULL); | ||||
|  |  | |||
|  | @ -341,7 +341,7 @@ static void device_remove_attributes(struct device *dev, | |||
| } | ||||
| 
 | ||||
| static int device_add_groups(struct device *dev, | ||||
| 			     struct attribute_group **groups) | ||||
| 			     const struct attribute_group **groups) | ||||
| { | ||||
| 	int error = 0; | ||||
| 	int i; | ||||
|  | @ -361,7 +361,7 @@ static int device_add_groups(struct device *dev, | |||
| } | ||||
| 
 | ||||
| static void device_remove_groups(struct device *dev, | ||||
| 				 struct attribute_group **groups) | ||||
| 				 const struct attribute_group **groups) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
|  | @ -843,6 +843,17 @@ static void device_remove_sys_dev_entry(struct device *dev) | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| int device_private_init(struct device *dev) | ||||
| { | ||||
| 	dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL); | ||||
| 	if (!dev->p) | ||||
| 		return -ENOMEM; | ||||
| 	dev->p->device = dev; | ||||
| 	klist_init(&dev->p->klist_children, klist_children_get, | ||||
| 		   klist_children_put); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * device_add - add device to device hierarchy. | ||||
|  * @dev: device. | ||||
|  | @ -868,14 +879,11 @@ int device_add(struct device *dev) | |||
| 	if (!dev) | ||||
| 		goto done; | ||||
| 
 | ||||
| 	dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL); | ||||
| 	if (!dev->p) { | ||||
| 		error = -ENOMEM; | ||||
| 		goto done; | ||||
| 		error = device_private_init(dev); | ||||
| 		if (error) | ||||
| 			goto done; | ||||
| 	} | ||||
| 	dev->p->device = dev; | ||||
| 	klist_init(&dev->p->klist_children, klist_children_get, | ||||
| 		   klist_children_put); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * for statically allocated devices, which should all be converted | ||||
|  | @ -921,6 +929,8 @@ int device_add(struct device *dev) | |||
| 		error = device_create_sys_dev_entry(dev); | ||||
| 		if (error) | ||||
| 			goto devtattrError; | ||||
| 
 | ||||
| 		devtmpfs_create_node(dev); | ||||
| 	} | ||||
| 
 | ||||
| 	error = device_add_class_symlinks(dev); | ||||
|  | @ -945,7 +955,7 @@ int device_add(struct device *dev) | |||
| 					     BUS_NOTIFY_ADD_DEVICE, dev); | ||||
| 
 | ||||
| 	kobject_uevent(&dev->kobj, KOBJ_ADD); | ||||
| 	bus_attach_device(dev); | ||||
| 	bus_probe_device(dev); | ||||
| 	if (parent) | ||||
| 		klist_add_tail(&dev->p->knode_parent, | ||||
| 			       &parent->p->klist_children); | ||||
|  | @ -1067,6 +1077,7 @@ void device_del(struct device *dev) | |||
| 	if (parent) | ||||
| 		klist_del(&dev->p->knode_parent); | ||||
| 	if (MAJOR(dev->devt)) { | ||||
| 		devtmpfs_delete_node(dev); | ||||
| 		device_remove_sys_dev_entry(dev); | ||||
| 		device_remove_file(dev, &devt_attr); | ||||
| 	} | ||||
|  |  | |||
|  | @ -11,8 +11,8 @@ | |||
|  * | ||||
|  * Copyright (c) 2002-5 Patrick Mochel | ||||
|  * Copyright (c) 2002-3 Open Source Development Labs | ||||
|  * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de> | ||||
|  * Copyright (c) 2007 Novell Inc. | ||||
|  * Copyright (c) 2007-2009 Greg Kroah-Hartman <gregkh@suse.de> | ||||
|  * Copyright (c) 2007-2009 Novell Inc. | ||||
|  * | ||||
|  * This file is released under the GPLv2 | ||||
|  */ | ||||
|  | @ -391,3 +391,30 @@ void driver_detach(struct device_driver *drv) | |||
| 		put_device(dev); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * These exports can't be _GPL due to .h files using this within them, and it | ||||
|  * might break something that was previously working... | ||||
|  */ | ||||
| void *dev_get_drvdata(const struct device *dev) | ||||
| { | ||||
| 	if (dev && dev->p) | ||||
| 		return dev->p->driver_data; | ||||
| 	return NULL; | ||||
| } | ||||
| EXPORT_SYMBOL(dev_get_drvdata); | ||||
| 
 | ||||
| void dev_set_drvdata(struct device *dev, void *data) | ||||
| { | ||||
| 	int error; | ||||
| 
 | ||||
| 	if (!dev) | ||||
| 		return; | ||||
| 	if (!dev->p) { | ||||
| 		error = device_private_init(dev); | ||||
| 		if (error) | ||||
| 			return; | ||||
| 	} | ||||
| 	dev->p->driver_data = data; | ||||
| } | ||||
| EXPORT_SYMBOL(dev_set_drvdata); | ||||
|  |  | |||
							
								
								
									
										367
									
								
								drivers/base/devtmpfs.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										367
									
								
								drivers/base/devtmpfs.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,367 @@ | |||
| /*
 | ||||
|  * devtmpfs - kernel-maintained tmpfs-based /dev | ||||
|  * | ||||
|  * Copyright (C) 2009, Kay Sievers <kay.sievers@vrfy.org> | ||||
|  * | ||||
|  * During bootup, before any driver core device is registered, | ||||
|  * devtmpfs, a tmpfs-based filesystem is created. Every driver-core | ||||
|  * device which requests a device node, will add a node in this | ||||
|  * filesystem. The node is named after the the name of the device, | ||||
|  * or the susbsytem can provide a custom name. All devices are | ||||
|  * owned by root and have a mode of 0600. | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/kernel.h> | ||||
| #include <linux/syscalls.h> | ||||
| #include <linux/mount.h> | ||||
| #include <linux/device.h> | ||||
| #include <linux/genhd.h> | ||||
| #include <linux/namei.h> | ||||
| #include <linux/fs.h> | ||||
| #include <linux/shmem_fs.h> | ||||
| #include <linux/cred.h> | ||||
| #include <linux/init_task.h> | ||||
| 
 | ||||
| static struct vfsmount *dev_mnt; | ||||
| 
 | ||||
| #if defined CONFIG_DEVTMPFS_MOUNT | ||||
| static int dev_mount = 1; | ||||
| #else | ||||
| static int dev_mount; | ||||
| #endif | ||||
| 
 | ||||
| static int __init mount_param(char *str) | ||||
| { | ||||
| 	dev_mount = simple_strtoul(str, NULL, 0); | ||||
| 	return 1; | ||||
| } | ||||
| __setup("devtmpfs.mount=", mount_param); | ||||
| 
 | ||||
| static int dev_get_sb(struct file_system_type *fs_type, int flags, | ||||
| 		      const char *dev_name, void *data, struct vfsmount *mnt) | ||||
| { | ||||
| 	return get_sb_single(fs_type, flags, data, shmem_fill_super, mnt); | ||||
| } | ||||
| 
 | ||||
| static struct file_system_type dev_fs_type = { | ||||
| 	.name = "devtmpfs", | ||||
| 	.get_sb = dev_get_sb, | ||||
| 	.kill_sb = kill_litter_super, | ||||
| }; | ||||
| 
 | ||||
| #ifdef CONFIG_BLOCK | ||||
| static inline int is_blockdev(struct device *dev) | ||||
| { | ||||
| 	return dev->class == &block_class; | ||||
| } | ||||
| #else | ||||
| static inline int is_blockdev(struct device *dev) { return 0; } | ||||
| #endif | ||||
| 
 | ||||
| static int dev_mkdir(const char *name, mode_t mode) | ||||
| { | ||||
| 	struct nameidata nd; | ||||
| 	struct dentry *dentry; | ||||
| 	int err; | ||||
| 
 | ||||
| 	err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, | ||||
| 			      name, LOOKUP_PARENT, &nd); | ||||
| 	if (err) | ||||
| 		return err; | ||||
| 
 | ||||
| 	dentry = lookup_create(&nd, 1); | ||||
| 	if (!IS_ERR(dentry)) { | ||||
| 		err = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode); | ||||
| 		dput(dentry); | ||||
| 	} else { | ||||
| 		err = PTR_ERR(dentry); | ||||
| 	} | ||||
| 	mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | ||||
| 
 | ||||
| 	path_put(&nd.path); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static int create_path(const char *nodepath) | ||||
| { | ||||
| 	char *path; | ||||
| 	struct nameidata nd; | ||||
| 	int err = 0; | ||||
| 
 | ||||
| 	path = kstrdup(nodepath, GFP_KERNEL); | ||||
| 	if (!path) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, | ||||
| 			      path, LOOKUP_PARENT, &nd); | ||||
| 	if (err == 0) { | ||||
| 		struct dentry *dentry; | ||||
| 
 | ||||
| 		/* create directory right away */ | ||||
| 		dentry = lookup_create(&nd, 1); | ||||
| 		if (!IS_ERR(dentry)) { | ||||
| 			err = vfs_mkdir(nd.path.dentry->d_inode, | ||||
| 					dentry, 0755); | ||||
| 			dput(dentry); | ||||
| 		} | ||||
| 		mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | ||||
| 
 | ||||
| 		path_put(&nd.path); | ||||
| 	} else if (err == -ENOENT) { | ||||
| 		char *s; | ||||
| 
 | ||||
| 		/* parent directories do not exist, create them */ | ||||
| 		s = path; | ||||
| 		while (1) { | ||||
| 			s = strchr(s, '/'); | ||||
| 			if (!s) | ||||
| 				break; | ||||
| 			s[0] = '\0'; | ||||
| 			err = dev_mkdir(path, 0755); | ||||
| 			if (err && err != -EEXIST) | ||||
| 				break; | ||||
| 			s[0] = '/'; | ||||
| 			s++; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	kfree(path); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| int devtmpfs_create_node(struct device *dev) | ||||
| { | ||||
| 	const char *tmp = NULL; | ||||
| 	const char *nodename; | ||||
| 	const struct cred *curr_cred; | ||||
| 	mode_t mode; | ||||
| 	struct nameidata nd; | ||||
| 	struct dentry *dentry; | ||||
| 	int err; | ||||
| 
 | ||||
| 	if (!dev_mnt) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	nodename = device_get_nodename(dev, &tmp); | ||||
| 	if (!nodename) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	if (is_blockdev(dev)) | ||||
| 		mode = S_IFBLK|0600; | ||||
| 	else | ||||
| 		mode = S_IFCHR|0600; | ||||
| 
 | ||||
| 	curr_cred = override_creds(&init_cred); | ||||
| 	err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, | ||||
| 			      nodename, LOOKUP_PARENT, &nd); | ||||
| 	if (err == -ENOENT) { | ||||
| 		/* create missing parent directories */ | ||||
| 		create_path(nodename); | ||||
| 		err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, | ||||
| 				      nodename, LOOKUP_PARENT, &nd); | ||||
| 		if (err) | ||||
| 			goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	dentry = lookup_create(&nd, 0); | ||||
| 	if (!IS_ERR(dentry)) { | ||||
| 		err = vfs_mknod(nd.path.dentry->d_inode, | ||||
| 				dentry, mode, dev->devt); | ||||
| 		/* mark as kernel created inode */ | ||||
| 		if (!err) | ||||
| 			dentry->d_inode->i_private = &dev_mnt; | ||||
| 		dput(dentry); | ||||
| 	} else { | ||||
| 		err = PTR_ERR(dentry); | ||||
| 	} | ||||
| 	mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | ||||
| 
 | ||||
| 	path_put(&nd.path); | ||||
| out: | ||||
| 	kfree(tmp); | ||||
| 	revert_creds(curr_cred); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static int dev_rmdir(const char *name) | ||||
| { | ||||
| 	struct nameidata nd; | ||||
| 	struct dentry *dentry; | ||||
| 	int err; | ||||
| 
 | ||||
| 	err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, | ||||
| 			      name, LOOKUP_PARENT, &nd); | ||||
| 	if (err) | ||||
| 		return err; | ||||
| 
 | ||||
| 	mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); | ||||
| 	dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len); | ||||
| 	if (!IS_ERR(dentry)) { | ||||
| 		if (dentry->d_inode) | ||||
| 			err = vfs_rmdir(nd.path.dentry->d_inode, dentry); | ||||
| 		else | ||||
| 			err = -ENOENT; | ||||
| 		dput(dentry); | ||||
| 	} else { | ||||
| 		err = PTR_ERR(dentry); | ||||
| 	} | ||||
| 	mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | ||||
| 
 | ||||
| 	path_put(&nd.path); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static int delete_path(const char *nodepath) | ||||
| { | ||||
| 	const char *path; | ||||
| 	int err = 0; | ||||
| 
 | ||||
| 	path = kstrdup(nodepath, GFP_KERNEL); | ||||
| 	if (!path) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	while (1) { | ||||
| 		char *base; | ||||
| 
 | ||||
| 		base = strrchr(path, '/'); | ||||
| 		if (!base) | ||||
| 			break; | ||||
| 		base[0] = '\0'; | ||||
| 		err = dev_rmdir(path); | ||||
| 		if (err) | ||||
| 			break; | ||||
| 	} | ||||
| 
 | ||||
| 	kfree(path); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static int dev_mynode(struct device *dev, struct inode *inode, struct kstat *stat) | ||||
| { | ||||
| 	/* did we create it */ | ||||
| 	if (inode->i_private != &dev_mnt) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	/* does the dev_t match */ | ||||
| 	if (is_blockdev(dev)) { | ||||
| 		if (!S_ISBLK(stat->mode)) | ||||
| 			return 0; | ||||
| 	} else { | ||||
| 		if (!S_ISCHR(stat->mode)) | ||||
| 			return 0; | ||||
| 	} | ||||
| 	if (stat->rdev != dev->devt) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	/* ours */ | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| int devtmpfs_delete_node(struct device *dev) | ||||
| { | ||||
| 	const char *tmp = NULL; | ||||
| 	const char *nodename; | ||||
| 	const struct cred *curr_cred; | ||||
| 	struct nameidata nd; | ||||
| 	struct dentry *dentry; | ||||
| 	struct kstat stat; | ||||
| 	int deleted = 1; | ||||
| 	int err; | ||||
| 
 | ||||
| 	if (!dev_mnt) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	nodename = device_get_nodename(dev, &tmp); | ||||
| 	if (!nodename) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	curr_cred = override_creds(&init_cred); | ||||
| 	err = vfs_path_lookup(dev_mnt->mnt_root, dev_mnt, | ||||
| 			      nodename, LOOKUP_PARENT, &nd); | ||||
| 	if (err) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); | ||||
| 	dentry = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len); | ||||
| 	if (!IS_ERR(dentry)) { | ||||
| 		if (dentry->d_inode) { | ||||
| 			err = vfs_getattr(nd.path.mnt, dentry, &stat); | ||||
| 			if (!err && dev_mynode(dev, dentry->d_inode, &stat)) { | ||||
| 				err = vfs_unlink(nd.path.dentry->d_inode, | ||||
| 						 dentry); | ||||
| 				if (!err || err == -ENOENT) | ||||
| 					deleted = 1; | ||||
| 			} | ||||
| 		} else { | ||||
| 			err = -ENOENT; | ||||
| 		} | ||||
| 		dput(dentry); | ||||
| 	} else { | ||||
| 		err = PTR_ERR(dentry); | ||||
| 	} | ||||
| 	mutex_unlock(&nd.path.dentry->d_inode->i_mutex); | ||||
| 
 | ||||
| 	path_put(&nd.path); | ||||
| 	if (deleted && strchr(nodename, '/')) | ||||
| 		delete_path(nodename); | ||||
| out: | ||||
| 	kfree(tmp); | ||||
| 	revert_creds(curr_cred); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * If configured, or requested by the commandline, devtmpfs will be | ||||
|  * auto-mounted after the kernel mounted the root filesystem. | ||||
|  */ | ||||
| int devtmpfs_mount(const char *mountpoint) | ||||
| { | ||||
| 	struct path path; | ||||
| 	int err; | ||||
| 
 | ||||
| 	if (!dev_mount) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (!dev_mnt) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	err = kern_path(mountpoint, LOOKUP_FOLLOW, &path); | ||||
| 	if (err) | ||||
| 		return err; | ||||
| 	err = do_add_mount(dev_mnt, &path, 0, NULL); | ||||
| 	if (err) | ||||
| 		printk(KERN_INFO "devtmpfs: error mounting %i\n", err); | ||||
| 	else | ||||
| 		printk(KERN_INFO "devtmpfs: mounted\n"); | ||||
| 	path_put(&path); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Create devtmpfs instance, driver-core devices will add their device | ||||
|  * nodes here. | ||||
|  */ | ||||
| int __init devtmpfs_init(void) | ||||
| { | ||||
| 	int err; | ||||
| 	struct vfsmount *mnt; | ||||
| 
 | ||||
| 	err = register_filesystem(&dev_fs_type); | ||||
| 	if (err) { | ||||
| 		printk(KERN_ERR "devtmpfs: unable to register devtmpfs " | ||||
| 		       "type %i\n", err); | ||||
| 		return err; | ||||
| 	} | ||||
| 
 | ||||
| 	mnt = kern_mount(&dev_fs_type); | ||||
| 	if (IS_ERR(mnt)) { | ||||
| 		err = PTR_ERR(mnt); | ||||
| 		printk(KERN_ERR "devtmpfs: unable to create devtmpfs %i\n", err); | ||||
| 		unregister_filesystem(&dev_fs_type); | ||||
| 		return err; | ||||
| 	} | ||||
| 	dev_mnt = mnt; | ||||
| 
 | ||||
| 	printk(KERN_INFO "devtmpfs: initialized\n"); | ||||
| 	return 0; | ||||
| } | ||||
|  | @ -181,7 +181,7 @@ void put_driver(struct device_driver *drv) | |||
| EXPORT_SYMBOL_GPL(put_driver); | ||||
| 
 | ||||
| static int driver_add_groups(struct device_driver *drv, | ||||
| 			     struct attribute_group **groups) | ||||
| 			     const struct attribute_group **groups) | ||||
| { | ||||
| 	int error = 0; | ||||
| 	int i; | ||||
|  | @ -201,7 +201,7 @@ static int driver_add_groups(struct device_driver *drv, | |||
| } | ||||
| 
 | ||||
| static void driver_remove_groups(struct device_driver *drv, | ||||
| 				 struct attribute_group **groups) | ||||
| 				 const struct attribute_group **groups) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ | |||
| void __init driver_init(void) | ||||
| { | ||||
| 	/* These are the core pieces */ | ||||
| 	devtmpfs_init(); | ||||
| 	devices_init(); | ||||
| 	buses_init(); | ||||
| 	classes_init(); | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ | |||
|  * information. | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/string.h> | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/init.h> | ||||
|  | @ -213,14 +214,13 @@ EXPORT_SYMBOL_GPL(platform_device_add_resources); | |||
| int platform_device_add_data(struct platform_device *pdev, const void *data, | ||||
| 			     size_t size) | ||||
| { | ||||
| 	void *d; | ||||
| 	void *d = kmemdup(data, size, GFP_KERNEL); | ||||
| 
 | ||||
| 	d = kmalloc(size, GFP_KERNEL); | ||||
| 	if (d) { | ||||
| 		memcpy(d, data, size); | ||||
| 		pdev->dev.platform_data = d; | ||||
| 		return 0; | ||||
| 	} | ||||
| 	return d ? 0 : -ENOMEM; | ||||
| 	return -ENOMEM; | ||||
| } | ||||
| EXPORT_SYMBOL_GPL(platform_device_add_data); | ||||
| 
 | ||||
|  |  | |||
|  | @ -572,7 +572,7 @@ static struct attribute_group cciss_dev_attr_group = { | |||
| 	.attrs = cciss_dev_attrs, | ||||
| }; | ||||
| 
 | ||||
| static struct attribute_group *cciss_dev_attr_groups[] = { | ||||
| static const struct attribute_group *cciss_dev_attr_groups[] = { | ||||
| 	&cciss_dev_attr_group, | ||||
| 	NULL | ||||
| }; | ||||
|  |  | |||
|  | @ -92,7 +92,7 @@ static struct mutex ctl_mutex;	/* Serialize open/close/setup/teardown */ | |||
| static mempool_t *psd_pool; | ||||
| 
 | ||||
| static struct class	*class_pktcdvd = NULL;    /* /sys/class/pktcdvd */ | ||||
| static struct dentry	*pkt_debugfs_root = NULL; /* /debug/pktcdvd */ | ||||
| static struct dentry	*pkt_debugfs_root = NULL; /* /sys/kernel/debug/pktcdvd */ | ||||
| 
 | ||||
| /* forward declaration */ | ||||
| static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev); | ||||
|  |  | |||
|  | @ -864,71 +864,67 @@ static const struct file_operations kmsg_fops = { | |||
| 	.write =	kmsg_write, | ||||
| }; | ||||
| 
 | ||||
| static const struct { | ||||
| 	unsigned int		minor; | ||||
| 	char			*name; | ||||
| 	umode_t			mode; | ||||
| 	const struct file_operations	*fops; | ||||
| 	struct backing_dev_info	*dev_info; | ||||
| } devlist[] = { /* list of minor devices */ | ||||
| 	{1, "mem",     S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops, | ||||
| 		&directly_mappable_cdev_bdi}, | ||||
| static const struct memdev { | ||||
| 	const char *name; | ||||
| 	const struct file_operations *fops; | ||||
| 	struct backing_dev_info *dev_info; | ||||
| } devlist[] = { | ||||
| 	[ 1] = { "mem", &mem_fops, &directly_mappable_cdev_bdi }, | ||||
| #ifdef CONFIG_DEVKMEM | ||||
| 	{2, "kmem",    S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops, | ||||
| 		&directly_mappable_cdev_bdi}, | ||||
| 	[ 2] = { "kmem", &kmem_fops, &directly_mappable_cdev_bdi }, | ||||
| #endif | ||||
| 	{3, "null",    S_IRUGO | S_IWUGO,           &null_fops, NULL}, | ||||
| 	[ 3] = {"null", &null_fops, NULL }, | ||||
| #ifdef CONFIG_DEVPORT | ||||
| 	{4, "port",    S_IRUSR | S_IWUSR | S_IRGRP, &port_fops, NULL}, | ||||
| 	[ 4] = { "port", &port_fops, NULL }, | ||||
| #endif | ||||
| 	{5, "zero",    S_IRUGO | S_IWUGO,           &zero_fops, &zero_bdi}, | ||||
| 	{7, "full",    S_IRUGO | S_IWUGO,           &full_fops, NULL}, | ||||
| 	{8, "random",  S_IRUGO | S_IWUSR,           &random_fops, NULL}, | ||||
| 	{9, "urandom", S_IRUGO | S_IWUSR,           &urandom_fops, NULL}, | ||||
| 	{11,"kmsg",    S_IRUGO | S_IWUSR,           &kmsg_fops, NULL}, | ||||
| 	[ 5] = { "zero", &zero_fops, &zero_bdi }, | ||||
| 	[ 7] = { "full", &full_fops, NULL }, | ||||
| 	[ 8] = { "random", &random_fops, NULL }, | ||||
| 	[ 9] = { "urandom", &urandom_fops, NULL }, | ||||
| 	[11] = { "kmsg", &kmsg_fops, NULL }, | ||||
| #ifdef CONFIG_CRASH_DUMP | ||||
| 	{12,"oldmem",    S_IRUSR | S_IWUSR | S_IRGRP, &oldmem_fops, NULL}, | ||||
| 	[12] = { "oldmem", &oldmem_fops, NULL }, | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| static int memory_open(struct inode *inode, struct file *filp) | ||||
| { | ||||
| 	int ret = 0; | ||||
| 	int i; | ||||
| 	int minor; | ||||
| 	const struct memdev *dev; | ||||
| 	int ret = -ENXIO; | ||||
| 
 | ||||
| 	lock_kernel(); | ||||
| 
 | ||||
| 	for (i = 0; i < ARRAY_SIZE(devlist); i++) { | ||||
| 		if (devlist[i].minor == iminor(inode)) { | ||||
| 			filp->f_op = devlist[i].fops; | ||||
| 			if (devlist[i].dev_info) { | ||||
| 				filp->f_mapping->backing_dev_info = | ||||
| 					devlist[i].dev_info; | ||||
| 			} | ||||
| 	minor = iminor(inode); | ||||
| 	if (minor >= ARRAY_SIZE(devlist)) | ||||
| 		goto out; | ||||
| 
 | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	dev = &devlist[minor]; | ||||
| 	if (!dev->fops) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	if (i == ARRAY_SIZE(devlist)) | ||||
| 		ret = -ENXIO; | ||||
| 	filp->f_op = dev->fops; | ||||
| 	if (dev->dev_info) | ||||
| 		filp->f_mapping->backing_dev_info = dev->dev_info; | ||||
| 
 | ||||
| 	if (dev->fops->open) | ||||
| 		ret = dev->fops->open(inode, filp); | ||||
| 	else | ||||
| 		if (filp->f_op && filp->f_op->open) | ||||
| 			ret = filp->f_op->open(inode, filp); | ||||
| 
 | ||||
| 		ret = 0; | ||||
| out: | ||||
| 	unlock_kernel(); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static const struct file_operations memory_fops = { | ||||
| 	.open		= memory_open,	/* just a selector for the real open */ | ||||
| 	.open		= memory_open, | ||||
| }; | ||||
| 
 | ||||
| static struct class *mem_class; | ||||
| 
 | ||||
| static int __init chr_dev_init(void) | ||||
| { | ||||
| 	int i; | ||||
| 	int minor; | ||||
| 	int err; | ||||
| 
 | ||||
| 	err = bdi_init(&zero_bdi); | ||||
|  | @ -939,10 +935,12 @@ static int __init chr_dev_init(void) | |||
| 		printk("unable to get major %d for memory devs\n", MEM_MAJOR); | ||||
| 
 | ||||
| 	mem_class = class_create(THIS_MODULE, "mem"); | ||||
| 	for (i = 0; i < ARRAY_SIZE(devlist); i++) | ||||
| 		device_create(mem_class, NULL, | ||||
| 			      MKDEV(MEM_MAJOR, devlist[i].minor), NULL, | ||||
| 			      devlist[i].name); | ||||
| 	for (minor = 1; minor < ARRAY_SIZE(devlist); minor++) { | ||||
| 		if (!devlist[minor].name) | ||||
| 			continue; | ||||
| 		device_create(mem_class, NULL, MKDEV(MEM_MAJOR, minor), | ||||
| 			      NULL, devlist[minor].name); | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  |  | |||
|  | @ -312,7 +312,7 @@ static void init_fw_attribute_group(struct device *dev, | |||
| 	group->groups[0] = &group->group; | ||||
| 	group->groups[1] = NULL; | ||||
| 	group->group.attrs = group->attrs; | ||||
| 	dev->groups = group->groups; | ||||
| 	dev->groups = (const struct attribute_group **) group->groups; | ||||
| } | ||||
| 
 | ||||
| static ssize_t modalias_show(struct device *dev, | ||||
|  |  | |||
|  | @ -139,7 +139,7 @@ static struct attribute_group sys_dmi_attribute_group = { | |||
| 	.attrs = sys_dmi_attributes, | ||||
| }; | ||||
| 
 | ||||
| static struct attribute_group* sys_dmi_attribute_groups[] = { | ||||
| static const struct attribute_group* sys_dmi_attribute_groups[] = { | ||||
| 	&sys_dmi_attribute_group, | ||||
| 	NULL | ||||
| }; | ||||
|  |  | |||
|  | @ -623,7 +623,7 @@ static struct attribute_group ehca_drv_attr_grp = { | |||
| 	.attrs = ehca_drv_attrs | ||||
| }; | ||||
| 
 | ||||
| static struct attribute_group *ehca_drv_attr_groups[] = { | ||||
| static const struct attribute_group *ehca_drv_attr_groups[] = { | ||||
| 	&ehca_drv_attr_grp, | ||||
| 	NULL, | ||||
| }; | ||||
|  |  | |||
|  | @ -1286,7 +1286,7 @@ struct device_driver; | |||
| 
 | ||||
| extern const char ib_ipath_version[]; | ||||
| 
 | ||||
| extern struct attribute_group *ipath_driver_attr_groups[]; | ||||
| extern const struct attribute_group *ipath_driver_attr_groups[]; | ||||
| 
 | ||||
| int ipath_device_create_group(struct device *, struct ipath_devdata *); | ||||
| void ipath_device_remove_group(struct device *, struct ipath_devdata *); | ||||
|  |  | |||
|  | @ -1069,7 +1069,7 @@ static ssize_t show_tempsense(struct device *dev, | |||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| struct attribute_group *ipath_driver_attr_groups[] = { | ||||
| const struct attribute_group *ipath_driver_attr_groups[] = { | ||||
| 	&driver_attr_group, | ||||
| 	NULL, | ||||
| }; | ||||
|  |  | |||
|  | @ -1144,7 +1144,7 @@ static struct attribute_group input_dev_caps_attr_group = { | |||
| 	.attrs	= input_dev_caps_attrs, | ||||
| }; | ||||
| 
 | ||||
| static struct attribute_group *input_dev_attr_groups[] = { | ||||
| static const struct attribute_group *input_dev_attr_groups[] = { | ||||
| 	&input_dev_attr_group, | ||||
| 	&input_dev_id_attr_group, | ||||
| 	&input_dev_caps_attr_group, | ||||
|  |  | |||
|  | @ -238,7 +238,7 @@ static void enclosure_component_release(struct device *dev) | |||
| 	put_device(dev->parent); | ||||
| } | ||||
| 
 | ||||
| static struct attribute_group *enclosure_groups[]; | ||||
| static const struct attribute_group *enclosure_groups[]; | ||||
| 
 | ||||
| /**
 | ||||
|  * enclosure_component_register - add a particular component to an enclosure | ||||
|  | @ -536,7 +536,7 @@ static struct attribute_group enclosure_group = { | |||
| 	.attrs = enclosure_component_attrs, | ||||
| }; | ||||
| 
 | ||||
| static struct attribute_group *enclosure_groups[] = { | ||||
| static const struct attribute_group *enclosure_groups[] = { | ||||
| 	&enclosure_group, | ||||
| 	NULL | ||||
| }; | ||||
|  |  | |||
|  | @ -13,6 +13,7 @@ | |||
| #include <linux/module.h> | ||||
| #include <linux/fs.h> | ||||
| #include <linux/pci.h> | ||||
| #include <linux/interrupt.h> | ||||
| #include <linux/ioport.h> | ||||
| #include <linux/device.h> | ||||
| #include <linux/file.h> | ||||
|  | @ -21,6 +22,8 @@ | |||
| #include <linux/delay.h> | ||||
| #include <linux/uaccess.h> | ||||
| #include <linux/io.h> | ||||
| #include <linux/wait.h> | ||||
| #include <linux/poll.h> | ||||
| #include "hpilo.h" | ||||
| 
 | ||||
| static struct class *ilo_class; | ||||
|  | @ -61,9 +64,10 @@ static inline int desc_mem_sz(int nr_entry) | |||
| static int fifo_enqueue(struct ilo_hwinfo *hw, char *fifobar, int entry) | ||||
| { | ||||
| 	struct fifo *fifo_q = FIFOBARTOHANDLE(fifobar); | ||||
| 	unsigned long flags; | ||||
| 	int ret = 0; | ||||
| 
 | ||||
| 	spin_lock(&hw->fifo_lock); | ||||
| 	spin_lock_irqsave(&hw->fifo_lock, flags); | ||||
| 	if (!(fifo_q->fifobar[(fifo_q->tail + 1) & fifo_q->imask] | ||||
| 	      & ENTRY_MASK_O)) { | ||||
| 		fifo_q->fifobar[fifo_q->tail & fifo_q->imask] |= | ||||
|  | @ -71,7 +75,7 @@ static int fifo_enqueue(struct ilo_hwinfo *hw, char *fifobar, int entry) | |||
| 		fifo_q->tail += 1; | ||||
| 		ret = 1; | ||||
| 	} | ||||
| 	spin_unlock(&hw->fifo_lock); | ||||
| 	spin_unlock_irqrestore(&hw->fifo_lock, flags); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
|  | @ -79,10 +83,11 @@ static int fifo_enqueue(struct ilo_hwinfo *hw, char *fifobar, int entry) | |||
| static int fifo_dequeue(struct ilo_hwinfo *hw, char *fifobar, int *entry) | ||||
| { | ||||
| 	struct fifo *fifo_q = FIFOBARTOHANDLE(fifobar); | ||||
| 	unsigned long flags; | ||||
| 	int ret = 0; | ||||
| 	u64 c; | ||||
| 
 | ||||
| 	spin_lock(&hw->fifo_lock); | ||||
| 	spin_lock_irqsave(&hw->fifo_lock, flags); | ||||
| 	c = fifo_q->fifobar[fifo_q->head & fifo_q->imask]; | ||||
| 	if (c & ENTRY_MASK_C) { | ||||
| 		if (entry) | ||||
|  | @ -93,7 +98,23 @@ static int fifo_dequeue(struct ilo_hwinfo *hw, char *fifobar, int *entry) | |||
| 		fifo_q->head += 1; | ||||
| 		ret = 1; | ||||
| 	} | ||||
| 	spin_unlock(&hw->fifo_lock); | ||||
| 	spin_unlock_irqrestore(&hw->fifo_lock, flags); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int fifo_check_recv(struct ilo_hwinfo *hw, char *fifobar) | ||||
| { | ||||
| 	struct fifo *fifo_q = FIFOBARTOHANDLE(fifobar); | ||||
| 	unsigned long flags; | ||||
| 	int ret = 0; | ||||
| 	u64 c; | ||||
| 
 | ||||
| 	spin_lock_irqsave(&hw->fifo_lock, flags); | ||||
| 	c = fifo_q->fifobar[fifo_q->head & fifo_q->imask]; | ||||
| 	if (c & ENTRY_MASK_C) | ||||
| 		ret = 1; | ||||
| 	spin_unlock_irqrestore(&hw->fifo_lock, flags); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
|  | @ -142,6 +163,13 @@ static int ilo_pkt_dequeue(struct ilo_hwinfo *hw, struct ccb *ccb, | |||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int ilo_pkt_recv(struct ilo_hwinfo *hw, struct ccb *ccb) | ||||
| { | ||||
| 	char *fifobar = ccb->ccb_u3.recv_fifobar; | ||||
| 
 | ||||
| 	return fifo_check_recv(hw, fifobar); | ||||
| } | ||||
| 
 | ||||
| static inline void doorbell_set(struct ccb *ccb) | ||||
| { | ||||
| 	iowrite8(1, ccb->ccb_u5.db_base); | ||||
|  | @ -151,6 +179,7 @@ static inline void doorbell_clr(struct ccb *ccb) | |||
| { | ||||
| 	iowrite8(2, ccb->ccb_u5.db_base); | ||||
| } | ||||
| 
 | ||||
| static inline int ctrl_set(int l2sz, int idxmask, int desclim) | ||||
| { | ||||
| 	int active = 0, go = 1; | ||||
|  | @ -160,6 +189,7 @@ static inline int ctrl_set(int l2sz, int idxmask, int desclim) | |||
| 	       active << CTRL_BITPOS_A | | ||||
| 	       go << CTRL_BITPOS_G; | ||||
| } | ||||
| 
 | ||||
| static void ctrl_setup(struct ccb *ccb, int nr_desc, int l2desc_sz) | ||||
| { | ||||
| 	/* for simplicity, use the same parameters for send and recv ctrls */ | ||||
|  | @ -192,13 +222,10 @@ static void fifo_setup(void *base_addr, int nr_entry) | |||
| 
 | ||||
| static void ilo_ccb_close(struct pci_dev *pdev, struct ccb_data *data) | ||||
| { | ||||
| 	struct ccb *driver_ccb; | ||||
| 	struct ccb __iomem *device_ccb; | ||||
| 	struct ccb *driver_ccb = &data->driver_ccb; | ||||
| 	struct ccb __iomem *device_ccb = data->mapped_ccb; | ||||
| 	int retries; | ||||
| 
 | ||||
| 	driver_ccb = &data->driver_ccb; | ||||
| 	device_ccb = data->mapped_ccb; | ||||
| 
 | ||||
| 	/* complicated dance to tell the hw we are stopping */ | ||||
| 	doorbell_clr(driver_ccb); | ||||
| 	iowrite32(ioread32(&device_ccb->send_ctrl) & ~(1 << CTRL_BITPOS_G), | ||||
|  | @ -225,26 +252,22 @@ static void ilo_ccb_close(struct pci_dev *pdev, struct ccb_data *data) | |||
| 	pci_free_consistent(pdev, data->dma_size, data->dma_va, data->dma_pa); | ||||
| } | ||||
| 
 | ||||
| static int ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot) | ||||
| static int ilo_ccb_setup(struct ilo_hwinfo *hw, struct ccb_data *data, int slot) | ||||
| { | ||||
| 	char *dma_va, *dma_pa; | ||||
| 	int pkt_id, pkt_sz, i, error; | ||||
| 	struct ccb *driver_ccb, *ilo_ccb; | ||||
| 	struct pci_dev *pdev; | ||||
| 
 | ||||
| 	driver_ccb = &data->driver_ccb; | ||||
| 	ilo_ccb = &data->ilo_ccb; | ||||
| 	pdev = hw->ilo_dev; | ||||
| 
 | ||||
| 	data->dma_size = 2 * fifo_sz(NR_QENTRY) + | ||||
| 			 2 * desc_mem_sz(NR_QENTRY) + | ||||
| 			 ILO_START_ALIGN + ILO_CACHE_SZ; | ||||
| 
 | ||||
| 	error = -ENOMEM; | ||||
| 	data->dma_va = pci_alloc_consistent(pdev, data->dma_size, | ||||
| 	data->dma_va = pci_alloc_consistent(hw->ilo_dev, data->dma_size, | ||||
| 					    &data->dma_pa); | ||||
| 	if (!data->dma_va) | ||||
| 		goto out; | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	dma_va = (char *)data->dma_va; | ||||
| 	dma_pa = (char *)data->dma_pa; | ||||
|  | @ -290,10 +313,18 @@ static int ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot) | |||
| 	driver_ccb->ccb_u5.db_base = hw->db_vaddr + (slot << L2_DB_SIZE); | ||||
| 	ilo_ccb->ccb_u5.db_base = NULL; /* hw ccb's doorbell is not used */ | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot) | ||||
| { | ||||
| 	int pkt_id, pkt_sz; | ||||
| 	struct ccb *driver_ccb = &data->driver_ccb; | ||||
| 
 | ||||
| 	/* copy the ccb with physical addrs to device memory */ | ||||
| 	data->mapped_ccb = (struct ccb __iomem *) | ||||
| 				(hw->ram_vaddr + (slot * ILOHW_CCB_SZ)); | ||||
| 	memcpy_toio(data->mapped_ccb, ilo_ccb, sizeof(struct ccb)); | ||||
| 	memcpy_toio(data->mapped_ccb, &data->ilo_ccb, sizeof(struct ccb)); | ||||
| 
 | ||||
| 	/* put packets on the send and receive queues */ | ||||
| 	pkt_sz = 0; | ||||
|  | @ -306,7 +337,14 @@ static int ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot) | |||
| 	for (pkt_id = 0; pkt_id < NR_QENTRY; pkt_id++) | ||||
| 		ilo_pkt_enqueue(hw, driver_ccb, RECVQ, pkt_id, pkt_sz); | ||||
| 
 | ||||
| 	/* the ccb is ready to use */ | ||||
| 	doorbell_clr(driver_ccb); | ||||
| } | ||||
| 
 | ||||
| static int ilo_ccb_verify(struct ilo_hwinfo *hw, struct ccb_data *data) | ||||
| { | ||||
| 	int pkt_id, i; | ||||
| 	struct ccb *driver_ccb = &data->driver_ccb; | ||||
| 
 | ||||
| 	/* make sure iLO is really handling requests */ | ||||
| 	for (i = MAX_WAIT; i > 0; i--) { | ||||
|  | @ -315,20 +353,14 @@ static int ilo_ccb_open(struct ilo_hwinfo *hw, struct ccb_data *data, int slot) | |||
| 		udelay(WAIT_TIME); | ||||
| 	} | ||||
| 
 | ||||
| 	if (i) { | ||||
| 		ilo_pkt_enqueue(hw, driver_ccb, SENDQ, pkt_id, 0); | ||||
| 		doorbell_set(driver_ccb); | ||||
| 	} else { | ||||
| 		dev_err(&pdev->dev, "Open could not dequeue a packet\n"); | ||||
| 		error = -EBUSY; | ||||
| 		goto free; | ||||
| 	if (i == 0) { | ||||
| 		dev_err(&hw->ilo_dev->dev, "Open could not dequeue a packet\n"); | ||||
| 		return -EBUSY; | ||||
| 	} | ||||
| 
 | ||||
| 	ilo_pkt_enqueue(hw, driver_ccb, SENDQ, pkt_id, 0); | ||||
| 	doorbell_set(driver_ccb); | ||||
| 	return 0; | ||||
| free: | ||||
| 	ilo_ccb_close(pdev, data); | ||||
| out: | ||||
| 	return error; | ||||
| } | ||||
| 
 | ||||
| static inline int is_channel_reset(struct ccb *ccb) | ||||
|  | @ -343,19 +375,45 @@ static inline void set_channel_reset(struct ccb *ccb) | |||
| 	FIFOBARTOHANDLE(ccb->ccb_u1.send_fifobar)->reset = 1; | ||||
| } | ||||
| 
 | ||||
| static inline int get_device_outbound(struct ilo_hwinfo *hw) | ||||
| { | ||||
| 	return ioread32(&hw->mmio_vaddr[DB_OUT]); | ||||
| } | ||||
| 
 | ||||
| static inline int is_db_reset(int db_out) | ||||
| { | ||||
| 	return db_out & (1 << DB_RESET); | ||||
| } | ||||
| 
 | ||||
| static inline int is_device_reset(struct ilo_hwinfo *hw) | ||||
| { | ||||
| 	/* check for global reset condition */ | ||||
| 	return ioread32(&hw->mmio_vaddr[DB_OUT]) & (1 << DB_RESET); | ||||
| 	return is_db_reset(get_device_outbound(hw)); | ||||
| } | ||||
| 
 | ||||
| static inline void clear_pending_db(struct ilo_hwinfo *hw, int clr) | ||||
| { | ||||
| 	iowrite32(clr, &hw->mmio_vaddr[DB_OUT]); | ||||
| } | ||||
| 
 | ||||
| static inline void clear_device(struct ilo_hwinfo *hw) | ||||
| { | ||||
| 	/* clear the device (reset bits, pending channel entries) */ | ||||
| 	iowrite32(-1, &hw->mmio_vaddr[DB_OUT]); | ||||
| 	clear_pending_db(hw, -1); | ||||
| } | ||||
| 
 | ||||
| static void ilo_locked_reset(struct ilo_hwinfo *hw) | ||||
| static inline void ilo_enable_interrupts(struct ilo_hwinfo *hw) | ||||
| { | ||||
| 	iowrite8(ioread8(&hw->mmio_vaddr[DB_IRQ]) | 1, &hw->mmio_vaddr[DB_IRQ]); | ||||
| } | ||||
| 
 | ||||
| static inline void ilo_disable_interrupts(struct ilo_hwinfo *hw) | ||||
| { | ||||
| 	iowrite8(ioread8(&hw->mmio_vaddr[DB_IRQ]) & ~1, | ||||
| 		 &hw->mmio_vaddr[DB_IRQ]); | ||||
| } | ||||
| 
 | ||||
| static void ilo_set_reset(struct ilo_hwinfo *hw) | ||||
| { | ||||
| 	int slot; | ||||
| 
 | ||||
|  | @ -368,40 +426,22 @@ static void ilo_locked_reset(struct ilo_hwinfo *hw) | |||
| 			continue; | ||||
| 		set_channel_reset(&hw->ccb_alloc[slot]->driver_ccb); | ||||
| 	} | ||||
| 
 | ||||
| 	clear_device(hw); | ||||
| } | ||||
| 
 | ||||
| static void ilo_reset(struct ilo_hwinfo *hw) | ||||
| { | ||||
| 	spin_lock(&hw->alloc_lock); | ||||
| 
 | ||||
| 	/* reset might have been handled after lock was taken */ | ||||
| 	if (is_device_reset(hw)) | ||||
| 		ilo_locked_reset(hw); | ||||
| 
 | ||||
| 	spin_unlock(&hw->alloc_lock); | ||||
| } | ||||
| 
 | ||||
| static ssize_t ilo_read(struct file *fp, char __user *buf, | ||||
| 			size_t len, loff_t *off) | ||||
| { | ||||
| 	int err, found, cnt, pkt_id, pkt_len; | ||||
| 	struct ccb_data *data; | ||||
| 	struct ccb *driver_ccb; | ||||
| 	struct ilo_hwinfo *hw; | ||||
| 	struct ccb_data *data = fp->private_data; | ||||
| 	struct ccb *driver_ccb = &data->driver_ccb; | ||||
| 	struct ilo_hwinfo *hw = data->ilo_hw; | ||||
| 	void *pkt; | ||||
| 
 | ||||
| 	data = fp->private_data; | ||||
| 	driver_ccb = &data->driver_ccb; | ||||
| 	hw = data->ilo_hw; | ||||
| 
 | ||||
| 	if (is_device_reset(hw) || is_channel_reset(driver_ccb)) { | ||||
| 	if (is_channel_reset(driver_ccb)) { | ||||
| 		/*
 | ||||
| 		 * If the device has been reset, applications | ||||
| 		 * need to close and reopen all ccbs. | ||||
| 		 */ | ||||
| 		ilo_reset(hw); | ||||
| 		return -ENODEV; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -442,23 +482,13 @@ static ssize_t ilo_write(struct file *fp, const char __user *buf, | |||
| 			 size_t len, loff_t *off) | ||||
| { | ||||
| 	int err, pkt_id, pkt_len; | ||||
| 	struct ccb_data *data; | ||||
| 	struct ccb *driver_ccb; | ||||
| 	struct ilo_hwinfo *hw; | ||||
| 	struct ccb_data *data = fp->private_data; | ||||
| 	struct ccb *driver_ccb = &data->driver_ccb; | ||||
| 	struct ilo_hwinfo *hw = data->ilo_hw; | ||||
| 	void *pkt; | ||||
| 
 | ||||
| 	data = fp->private_data; | ||||
| 	driver_ccb = &data->driver_ccb; | ||||
| 	hw = data->ilo_hw; | ||||
| 
 | ||||
| 	if (is_device_reset(hw) || is_channel_reset(driver_ccb)) { | ||||
| 		/*
 | ||||
| 		 * If the device has been reset, applications | ||||
| 		 * need to close and reopen all ccbs. | ||||
| 		 */ | ||||
| 		ilo_reset(hw); | ||||
| 	if (is_channel_reset(driver_ccb)) | ||||
| 		return -ENODEV; | ||||
| 	} | ||||
| 
 | ||||
| 	/* get a packet to send the user command */ | ||||
| 	if (!ilo_pkt_dequeue(hw, driver_ccb, SENDQ, &pkt_id, &pkt_len, &pkt)) | ||||
|  | @ -480,32 +510,48 @@ static ssize_t ilo_write(struct file *fp, const char __user *buf, | |||
| 	return err ? -EFAULT : len; | ||||
| } | ||||
| 
 | ||||
| static unsigned int ilo_poll(struct file *fp, poll_table *wait) | ||||
| { | ||||
| 	struct ccb_data *data = fp->private_data; | ||||
| 	struct ccb *driver_ccb = &data->driver_ccb; | ||||
| 
 | ||||
| 	poll_wait(fp, &data->ccb_waitq, wait); | ||||
| 
 | ||||
| 	if (is_channel_reset(driver_ccb)) | ||||
| 		return POLLERR; | ||||
| 	else if (ilo_pkt_recv(data->ilo_hw, driver_ccb)) | ||||
| 		return POLLIN | POLLRDNORM; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int ilo_close(struct inode *ip, struct file *fp) | ||||
| { | ||||
| 	int slot; | ||||
| 	struct ccb_data *data; | ||||
| 	struct ilo_hwinfo *hw; | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	slot = iminor(ip) % MAX_CCB; | ||||
| 	hw = container_of(ip->i_cdev, struct ilo_hwinfo, cdev); | ||||
| 
 | ||||
| 	spin_lock(&hw->alloc_lock); | ||||
| 
 | ||||
| 	if (is_device_reset(hw)) | ||||
| 		ilo_locked_reset(hw); | ||||
| 	spin_lock(&hw->open_lock); | ||||
| 
 | ||||
| 	if (hw->ccb_alloc[slot]->ccb_cnt == 1) { | ||||
| 
 | ||||
| 		data = fp->private_data; | ||||
| 
 | ||||
| 		spin_lock_irqsave(&hw->alloc_lock, flags); | ||||
| 		hw->ccb_alloc[slot] = NULL; | ||||
| 		spin_unlock_irqrestore(&hw->alloc_lock, flags); | ||||
| 
 | ||||
| 		ilo_ccb_close(hw->ilo_dev, data); | ||||
| 
 | ||||
| 		kfree(data); | ||||
| 		hw->ccb_alloc[slot] = NULL; | ||||
| 	} else | ||||
| 		hw->ccb_alloc[slot]->ccb_cnt--; | ||||
| 
 | ||||
| 	spin_unlock(&hw->alloc_lock); | ||||
| 	spin_unlock(&hw->open_lock); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  | @ -515,6 +561,7 @@ static int ilo_open(struct inode *ip, struct file *fp) | |||
| 	int slot, error; | ||||
| 	struct ccb_data *data; | ||||
| 	struct ilo_hwinfo *hw; | ||||
| 	unsigned long flags; | ||||
| 
 | ||||
| 	slot = iminor(ip) % MAX_CCB; | ||||
| 	hw = container_of(ip->i_cdev, struct ilo_hwinfo, cdev); | ||||
|  | @ -524,22 +571,42 @@ static int ilo_open(struct inode *ip, struct file *fp) | |||
| 	if (!data) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	spin_lock(&hw->alloc_lock); | ||||
| 
 | ||||
| 	if (is_device_reset(hw)) | ||||
| 		ilo_locked_reset(hw); | ||||
| 	spin_lock(&hw->open_lock); | ||||
| 
 | ||||
| 	/* each fd private_data holds sw/hw view of ccb */ | ||||
| 	if (hw->ccb_alloc[slot] == NULL) { | ||||
| 		/* create a channel control block for this minor */ | ||||
| 		error = ilo_ccb_open(hw, data, slot); | ||||
| 		if (!error) { | ||||
| 			hw->ccb_alloc[slot] = data; | ||||
| 			hw->ccb_alloc[slot]->ccb_cnt = 1; | ||||
| 			hw->ccb_alloc[slot]->ccb_excl = fp->f_flags & O_EXCL; | ||||
| 			hw->ccb_alloc[slot]->ilo_hw = hw; | ||||
| 		} else | ||||
| 		error = ilo_ccb_setup(hw, data, slot); | ||||
| 		if (error) { | ||||
| 			kfree(data); | ||||
| 			goto out; | ||||
| 		} | ||||
| 
 | ||||
| 		data->ccb_cnt = 1; | ||||
| 		data->ccb_excl = fp->f_flags & O_EXCL; | ||||
| 		data->ilo_hw = hw; | ||||
| 		init_waitqueue_head(&data->ccb_waitq); | ||||
| 
 | ||||
| 		/* write the ccb to hw */ | ||||
| 		spin_lock_irqsave(&hw->alloc_lock, flags); | ||||
| 		ilo_ccb_open(hw, data, slot); | ||||
| 		hw->ccb_alloc[slot] = data; | ||||
| 		spin_unlock_irqrestore(&hw->alloc_lock, flags); | ||||
| 
 | ||||
| 		/* make sure the channel is functional */ | ||||
| 		error = ilo_ccb_verify(hw, data); | ||||
| 		if (error) { | ||||
| 
 | ||||
| 			spin_lock_irqsave(&hw->alloc_lock, flags); | ||||
| 			hw->ccb_alloc[slot] = NULL; | ||||
| 			spin_unlock_irqrestore(&hw->alloc_lock, flags); | ||||
| 
 | ||||
| 			ilo_ccb_close(hw->ilo_dev, data); | ||||
| 
 | ||||
| 			kfree(data); | ||||
| 			goto out; | ||||
| 		} | ||||
| 
 | ||||
| 	} else { | ||||
| 		kfree(data); | ||||
| 		if (fp->f_flags & O_EXCL || hw->ccb_alloc[slot]->ccb_excl) { | ||||
|  | @ -554,7 +621,8 @@ static int ilo_open(struct inode *ip, struct file *fp) | |||
| 			error = 0; | ||||
| 		} | ||||
| 	} | ||||
| 	spin_unlock(&hw->alloc_lock); | ||||
| out: | ||||
| 	spin_unlock(&hw->open_lock); | ||||
| 
 | ||||
| 	if (!error) | ||||
| 		fp->private_data = hw->ccb_alloc[slot]; | ||||
|  | @ -566,10 +634,46 @@ static const struct file_operations ilo_fops = { | |||
| 	.owner		= THIS_MODULE, | ||||
| 	.read		= ilo_read, | ||||
| 	.write		= ilo_write, | ||||
| 	.poll		= ilo_poll, | ||||
| 	.open 		= ilo_open, | ||||
| 	.release 	= ilo_close, | ||||
| }; | ||||
| 
 | ||||
| static irqreturn_t ilo_isr(int irq, void *data) | ||||
| { | ||||
| 	struct ilo_hwinfo *hw = data; | ||||
| 	int pending, i; | ||||
| 
 | ||||
| 	spin_lock(&hw->alloc_lock); | ||||
| 
 | ||||
| 	/* check for ccbs which have data */ | ||||
| 	pending = get_device_outbound(hw); | ||||
| 	if (!pending) { | ||||
| 		spin_unlock(&hw->alloc_lock); | ||||
| 		return IRQ_NONE; | ||||
| 	} | ||||
| 
 | ||||
| 	if (is_db_reset(pending)) { | ||||
| 		/* wake up all ccbs if the device was reset */ | ||||
| 		pending = -1; | ||||
| 		ilo_set_reset(hw); | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < MAX_CCB; i++) { | ||||
| 		if (!hw->ccb_alloc[i]) | ||||
| 			continue; | ||||
| 		if (pending & (1 << i)) | ||||
| 			wake_up_interruptible(&hw->ccb_alloc[i]->ccb_waitq); | ||||
| 	} | ||||
| 
 | ||||
| 	/* clear the device of the channels that have been handled */ | ||||
| 	clear_pending_db(hw, pending); | ||||
| 
 | ||||
| 	spin_unlock(&hw->alloc_lock); | ||||
| 
 | ||||
| 	return IRQ_HANDLED; | ||||
| } | ||||
| 
 | ||||
| static void ilo_unmap_device(struct pci_dev *pdev, struct ilo_hwinfo *hw) | ||||
| { | ||||
| 	pci_iounmap(pdev, hw->db_vaddr); | ||||
|  | @ -623,6 +727,8 @@ static void ilo_remove(struct pci_dev *pdev) | |||
| 		device_destroy(ilo_class, MKDEV(ilo_major, i)); | ||||
| 
 | ||||
| 	cdev_del(&ilo_hw->cdev); | ||||
| 	ilo_disable_interrupts(ilo_hw); | ||||
| 	free_irq(pdev->irq, ilo_hw); | ||||
| 	ilo_unmap_device(pdev, ilo_hw); | ||||
| 	pci_release_regions(pdev); | ||||
| 	pci_disable_device(pdev); | ||||
|  | @ -658,6 +764,7 @@ static int __devinit ilo_probe(struct pci_dev *pdev, | |||
| 	ilo_hw->ilo_dev = pdev; | ||||
| 	spin_lock_init(&ilo_hw->alloc_lock); | ||||
| 	spin_lock_init(&ilo_hw->fifo_lock); | ||||
| 	spin_lock_init(&ilo_hw->open_lock); | ||||
| 
 | ||||
| 	error = pci_enable_device(pdev); | ||||
| 	if (error) | ||||
|  | @ -676,13 +783,19 @@ static int __devinit ilo_probe(struct pci_dev *pdev, | |||
| 	pci_set_drvdata(pdev, ilo_hw); | ||||
| 	clear_device(ilo_hw); | ||||
| 
 | ||||
| 	error = request_irq(pdev->irq, ilo_isr, IRQF_SHARED, "hpilo", ilo_hw); | ||||
| 	if (error) | ||||
| 		goto unmap; | ||||
| 
 | ||||
| 	ilo_enable_interrupts(ilo_hw); | ||||
| 
 | ||||
| 	cdev_init(&ilo_hw->cdev, &ilo_fops); | ||||
| 	ilo_hw->cdev.owner = THIS_MODULE; | ||||
| 	start = devnum * MAX_CCB; | ||||
| 	error = cdev_add(&ilo_hw->cdev, MKDEV(ilo_major, start), MAX_CCB); | ||||
| 	if (error) { | ||||
| 		dev_err(&pdev->dev, "Could not add cdev\n"); | ||||
| 		goto unmap; | ||||
| 		goto remove_isr; | ||||
| 	} | ||||
| 
 | ||||
| 	for (minor = 0 ; minor < MAX_CCB; minor++) { | ||||
|  | @ -695,6 +808,9 @@ static int __devinit ilo_probe(struct pci_dev *pdev, | |||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| remove_isr: | ||||
| 	ilo_disable_interrupts(ilo_hw); | ||||
| 	free_irq(pdev->irq, ilo_hw); | ||||
| unmap: | ||||
| 	ilo_unmap_device(pdev, ilo_hw); | ||||
| free_regions: | ||||
|  | @ -759,7 +875,7 @@ static void __exit ilo_exit(void) | |||
| 	class_destroy(ilo_class); | ||||
| } | ||||
| 
 | ||||
| MODULE_VERSION("1.1"); | ||||
| MODULE_VERSION("1.2"); | ||||
| MODULE_ALIAS(ILO_NAME); | ||||
| MODULE_DESCRIPTION(ILO_NAME); | ||||
| MODULE_AUTHOR("David Altobelli <david.altobelli@hp.com>"); | ||||
|  |  | |||
|  | @ -46,11 +46,14 @@ struct ilo_hwinfo { | |||
| 
 | ||||
| 	spinlock_t alloc_lock; | ||||
| 	spinlock_t fifo_lock; | ||||
| 	spinlock_t open_lock; | ||||
| 
 | ||||
| 	struct cdev cdev; | ||||
| }; | ||||
| 
 | ||||
| /* offset from mmio_vaddr */ | ||||
| /* offset from mmio_vaddr for enabling doorbell interrupts */ | ||||
| #define DB_IRQ		0xB2 | ||||
| /* offset from mmio_vaddr for outbound communications */ | ||||
| #define DB_OUT		0xD4 | ||||
| /* DB_OUT reset bit */ | ||||
| #define DB_RESET	26 | ||||
|  | @ -131,6 +134,9 @@ struct ccb_data { | |||
| 	/* pointer to hardware device info */ | ||||
| 	struct ilo_hwinfo *ilo_hw; | ||||
| 
 | ||||
| 	/* queue for this ccb to wait for recv data */ | ||||
| 	wait_queue_head_t ccb_waitq; | ||||
| 
 | ||||
| 	/* usage count, to allow for shared ccb's */ | ||||
| 	int	    ccb_cnt; | ||||
| 
 | ||||
|  |  | |||
|  | @ -276,7 +276,7 @@ static struct attribute_group mmc_std_attr_group = { | |||
| 	.attrs = mmc_std_attrs, | ||||
| }; | ||||
| 
 | ||||
| static struct attribute_group *mmc_attr_groups[] = { | ||||
| static const struct attribute_group *mmc_attr_groups[] = { | ||||
| 	&mmc_std_attr_group, | ||||
| 	NULL, | ||||
| }; | ||||
|  |  | |||
|  | @ -314,7 +314,7 @@ static struct attribute_group sd_std_attr_group = { | |||
| 	.attrs = sd_std_attrs, | ||||
| }; | ||||
| 
 | ||||
| static struct attribute_group *sd_attr_groups[] = { | ||||
| static const struct attribute_group *sd_attr_groups[] = { | ||||
| 	&sd_std_attr_group, | ||||
| 	NULL, | ||||
| }; | ||||
|  |  | |||
|  | @ -217,7 +217,7 @@ struct attribute_group mtd_group = { | |||
| 	.attrs		= mtd_attrs, | ||||
| }; | ||||
| 
 | ||||
| struct attribute_group *mtd_groups[] = { | ||||
| const struct attribute_group *mtd_groups[] = { | ||||
| 	&mtd_group, | ||||
| 	NULL, | ||||
| }; | ||||
|  |  | |||
|  | @ -24,8 +24,8 @@ config IWM_DEBUG | |||
| 	  To see the list of debug modules and levels, see iwm/debug.h | ||||
| 
 | ||||
| 	  For example, if you want the full MLME debug output: | ||||
| 	  echo 0xff > /debug/iwm/phyN/debug/mlme | ||||
| 	  echo 0xff > /sys/kernel/debug/iwm/phyN/debug/mlme | ||||
| 
 | ||||
| 	  Or, if you want the full debug, for all modules: | ||||
| 	  echo 0xff > /debug/iwm/phyN/debug/level | ||||
| 	  echo 0xff > /debug/iwm/phyN/debug/modules | ||||
| 	  echo 0xff > /sys/kernel/debug/iwm/phyN/debug/level | ||||
| 	  echo 0xff > /sys/kernel/debug/iwm/phyN/debug/modules | ||||
|  |  | |||
|  | @ -266,7 +266,7 @@ static struct attribute_group subch_attr_group = { | |||
| 	.attrs = subch_attrs, | ||||
| }; | ||||
| 
 | ||||
| static struct attribute_group *default_subch_attr_groups[] = { | ||||
| static const struct attribute_group *default_subch_attr_groups[] = { | ||||
| 	&subch_attr_group, | ||||
| 	NULL, | ||||
| }; | ||||
|  |  | |||
|  | @ -656,7 +656,7 @@ static struct attribute_group ccwdev_attr_group = { | |||
| 	.attrs = ccwdev_attrs, | ||||
| }; | ||||
| 
 | ||||
| static struct attribute_group *ccwdev_attr_groups[] = { | ||||
| static const struct attribute_group *ccwdev_attr_groups[] = { | ||||
| 	&ccwdev_attr_group, | ||||
| 	NULL, | ||||
| }; | ||||
|  |  | |||
|  | @ -2159,7 +2159,7 @@ static struct attribute_group netiucv_drv_attr_group = { | |||
| 	.attrs = netiucv_drv_attrs, | ||||
| }; | ||||
| 
 | ||||
| static struct attribute_group *netiucv_drv_attr_groups[] = { | ||||
| static const struct attribute_group *netiucv_drv_attr_groups[] = { | ||||
| 	&netiucv_drv_attr_group, | ||||
| 	NULL, | ||||
| }; | ||||
|  |  | |||
|  | @ -132,7 +132,7 @@ extern struct scsi_transport_template blank_transport_template; | |||
| extern void __scsi_remove_device(struct scsi_device *); | ||||
| 
 | ||||
| extern struct bus_type scsi_bus_type; | ||||
| extern struct attribute_group *scsi_sysfs_shost_attr_groups[]; | ||||
| extern const struct attribute_group *scsi_sysfs_shost_attr_groups[]; | ||||
| 
 | ||||
| /* scsi_netlink.c */ | ||||
| #ifdef CONFIG_SCSI_NETLINK | ||||
|  |  | |||
|  | @ -275,7 +275,7 @@ struct attribute_group scsi_shost_attr_group = { | |||
| 	.attrs =	scsi_sysfs_shost_attrs, | ||||
| }; | ||||
| 
 | ||||
| struct attribute_group *scsi_sysfs_shost_attr_groups[] = { | ||||
| const struct attribute_group *scsi_sysfs_shost_attr_groups[] = { | ||||
| 	&scsi_shost_attr_group, | ||||
| 	NULL | ||||
| }; | ||||
|  | @ -745,7 +745,7 @@ static struct attribute_group scsi_sdev_attr_group = { | |||
| 	.attrs =	scsi_sdev_attrs, | ||||
| }; | ||||
| 
 | ||||
| static struct attribute_group *scsi_sdev_attr_groups[] = { | ||||
| static const struct attribute_group *scsi_sdev_attr_groups[] = { | ||||
| 	&scsi_sdev_attr_group, | ||||
| 	NULL | ||||
| }; | ||||
|  |  | |||
|  | @ -1,7 +1,6 @@ | |||
| menuconfig UIO | ||||
| 	tristate "Userspace I/O drivers" | ||||
| 	depends on !S390 | ||||
| 	default n | ||||
| 	help | ||||
| 	  Enable this to allow the userspace driver core code to be | ||||
| 	  built.  This code allows userspace programs easy access to | ||||
|  | @ -16,7 +15,6 @@ if UIO | |||
| config UIO_CIF | ||||
| 	tristate "generic Hilscher CIF Card driver" | ||||
| 	depends on PCI | ||||
| 	default n | ||||
| 	help | ||||
| 	  Driver for Hilscher CIF DeviceNet and Profibus cards.  This | ||||
| 	  driver requires a userspace component that handles all of the | ||||
|  | @ -48,7 +46,6 @@ config UIO_PDRV_GENIRQ | |||
| 
 | ||||
| config UIO_SMX | ||||
| 	tristate "SMX cryptengine UIO interface" | ||||
| 	default n | ||||
| 	help | ||||
| 	  Userspace IO interface to the Cryptography engine found on the | ||||
| 	  Nias Digital SMX boards.  These will be available from Q4 2008 | ||||
|  | @ -61,7 +58,6 @@ config UIO_SMX | |||
| config UIO_AEC | ||||
| 	tristate "AEC video timestamp device" | ||||
| 	depends on PCI | ||||
| 	default n | ||||
| 	help | ||||
| 
 | ||||
| 	  UIO driver for the Adrienne Electronics Corporation PCI time | ||||
|  | @ -78,7 +74,6 @@ config UIO_AEC | |||
| 
 | ||||
| config UIO_SERCOS3 | ||||
| 	tristate "Automata Sercos III PCI card driver" | ||||
| 	default n | ||||
| 	help | ||||
| 	  Userspace I/O interface for the Sercos III PCI card from | ||||
| 	  Automata GmbH. The userspace part of this driver will be | ||||
|  | @ -89,4 +84,14 @@ config UIO_SERCOS3 | |||
| 
 | ||||
| 	  If you compile this as a module, it will be called uio_sercos3. | ||||
| 
 | ||||
| config UIO_PCI_GENERIC | ||||
| 	tristate "Generic driver for PCI 2.3 and PCI Express cards" | ||||
| 	depends on PCI | ||||
| 	default n | ||||
| 	help | ||||
| 	  Generic driver that you can bind, dynamically, to any | ||||
| 	  PCI 2.3 compliant and PCI Express card. It is useful, | ||||
| 	  primarily, for virtualization scenarios. | ||||
| 	  If you compile this as a module, it will be called uio_pci_generic. | ||||
| 
 | ||||
| endif | ||||
|  |  | |||
|  | @ -5,3 +5,4 @@ obj-$(CONFIG_UIO_PDRV_GENIRQ)	+= uio_pdrv_genirq.o | |||
| obj-$(CONFIG_UIO_SMX)	+= uio_smx.o | ||||
| obj-$(CONFIG_UIO_AEC)	+= uio_aec.o | ||||
| obj-$(CONFIG_UIO_SERCOS3)	+= uio_sercos3.o | ||||
| obj-$(CONFIG_UIO_PCI_GENERIC)	+= uio_pci_generic.o | ||||
|  |  | |||
							
								
								
									
										207
									
								
								drivers/uio/uio_pci_generic.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										207
									
								
								drivers/uio/uio_pci_generic.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,207 @@ | |||
| /* uio_pci_generic - generic UIO driver for PCI 2.3 devices
 | ||||
|  * | ||||
|  * Copyright (C) 2009 Red Hat, Inc. | ||||
|  * Author: Michael S. Tsirkin <mst@redhat.com> | ||||
|  * | ||||
|  * This work is licensed under the terms of the GNU GPL, version 2. | ||||
|  * | ||||
|  * Since the driver does not declare any device ids, you must allocate | ||||
|  * id and bind the device to the driver yourself.  For example: | ||||
|  * | ||||
|  * # echo "8086 10f5" > /sys/bus/pci/drivers/uio_pci_generic/new_id | ||||
|  * # echo -n 0000:00:19.0 > /sys/bus/pci/drivers/e1000e/unbind | ||||
|  * # echo -n 0000:00:19.0 > /sys/bus/pci/drivers/uio_pci_generic/bind | ||||
|  * # ls -l /sys/bus/pci/devices/0000:00:19.0/driver | ||||
|  * .../0000:00:19.0/driver -> ../../../bus/pci/drivers/uio_pci_generic | ||||
|  * | ||||
|  * Driver won't bind to devices which do not support the Interrupt Disable Bit | ||||
|  * in the command register. All devices compliant to PCI 2.3 (circa 2002) and | ||||
|  * all compliant PCI Express devices should support this bit. | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/device.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/pci.h> | ||||
| #include <linux/uio_driver.h> | ||||
| #include <linux/spinlock.h> | ||||
| 
 | ||||
| #define DRIVER_VERSION	"0.01.0" | ||||
| #define DRIVER_AUTHOR	"Michael S. Tsirkin <mst@redhat.com>" | ||||
| #define DRIVER_DESC	"Generic UIO driver for PCI 2.3 devices" | ||||
| 
 | ||||
| struct uio_pci_generic_dev { | ||||
| 	struct uio_info info; | ||||
| 	struct pci_dev *pdev; | ||||
| 	spinlock_t lock; /* guards command register accesses */ | ||||
| }; | ||||
| 
 | ||||
| static inline struct uio_pci_generic_dev * | ||||
| to_uio_pci_generic_dev(struct uio_info *info) | ||||
| { | ||||
| 	return container_of(info, struct uio_pci_generic_dev, info); | ||||
| } | ||||
| 
 | ||||
| /* Interrupt handler. Read/modify/write the command register to disable
 | ||||
|  * the interrupt. */ | ||||
| static irqreturn_t irqhandler(int irq, struct uio_info *info) | ||||
| { | ||||
| 	struct uio_pci_generic_dev *gdev = to_uio_pci_generic_dev(info); | ||||
| 	struct pci_dev *pdev = gdev->pdev; | ||||
| 	irqreturn_t ret = IRQ_NONE; | ||||
| 	u32 cmd_status_dword; | ||||
| 	u16 origcmd, newcmd, status; | ||||
| 
 | ||||
| 	/* We do a single dword read to retrieve both command and status.
 | ||||
| 	 * Document assumptions that make this possible. */ | ||||
| 	BUILD_BUG_ON(PCI_COMMAND % 4); | ||||
| 	BUILD_BUG_ON(PCI_COMMAND + 2 != PCI_STATUS); | ||||
| 
 | ||||
| 	spin_lock_irq(&gdev->lock); | ||||
| 	pci_block_user_cfg_access(pdev); | ||||
| 
 | ||||
| 	/* Read both command and status registers in a single 32-bit operation.
 | ||||
| 	 * Note: we could cache the value for command and move the status read | ||||
| 	 * out of the lock if there was a way to get notified of user changes | ||||
| 	 * to command register through sysfs. Should be good for shared irqs. */ | ||||
| 	pci_read_config_dword(pdev, PCI_COMMAND, &cmd_status_dword); | ||||
| 	origcmd = cmd_status_dword; | ||||
| 	status = cmd_status_dword >> 16; | ||||
| 
 | ||||
| 	/* Check interrupt status register to see whether our device
 | ||||
| 	 * triggered the interrupt. */ | ||||
| 	if (!(status & PCI_STATUS_INTERRUPT)) | ||||
| 		goto done; | ||||
| 
 | ||||
| 	/* We triggered the interrupt, disable it. */ | ||||
| 	newcmd = origcmd | PCI_COMMAND_INTX_DISABLE; | ||||
| 	if (newcmd != origcmd) | ||||
| 		pci_write_config_word(pdev, PCI_COMMAND, newcmd); | ||||
| 
 | ||||
| 	/* UIO core will signal the user process. */ | ||||
| 	ret = IRQ_HANDLED; | ||||
| done: | ||||
| 
 | ||||
| 	pci_unblock_user_cfg_access(pdev); | ||||
| 	spin_unlock_irq(&gdev->lock); | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| /* Verify that the device supports Interrupt Disable bit in command register,
 | ||||
|  * per PCI 2.3, by flipping this bit and reading it back: this bit was readonly | ||||
|  * in PCI 2.2. */ | ||||
| static int __devinit verify_pci_2_3(struct pci_dev *pdev) | ||||
| { | ||||
| 	u16 orig, new; | ||||
| 	int err = 0; | ||||
| 
 | ||||
| 	pci_block_user_cfg_access(pdev); | ||||
| 	pci_read_config_word(pdev, PCI_COMMAND, &orig); | ||||
| 	pci_write_config_word(pdev, PCI_COMMAND, | ||||
| 			      orig ^ PCI_COMMAND_INTX_DISABLE); | ||||
| 	pci_read_config_word(pdev, PCI_COMMAND, &new); | ||||
| 	/* There's no way to protect against
 | ||||
| 	 * hardware bugs or detect them reliably, but as long as we know | ||||
| 	 * what the value should be, let's go ahead and check it. */ | ||||
| 	if ((new ^ orig) & ~PCI_COMMAND_INTX_DISABLE) { | ||||
| 		err = -EBUSY; | ||||
| 		dev_err(&pdev->dev, "Command changed from 0x%x to 0x%x: " | ||||
| 			"driver or HW bug?\n", orig, new); | ||||
| 		goto err; | ||||
| 	} | ||||
| 	if (!((new ^ orig) & PCI_COMMAND_INTX_DISABLE)) { | ||||
| 		dev_warn(&pdev->dev, "Device does not support " | ||||
| 			 "disabling interrupts: unable to bind.\n"); | ||||
| 		err = -ENODEV; | ||||
| 		goto err; | ||||
| 	} | ||||
| 	/* Now restore the original value. */ | ||||
| 	pci_write_config_word(pdev, PCI_COMMAND, orig); | ||||
| err: | ||||
| 	pci_unblock_user_cfg_access(pdev); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static int __devinit probe(struct pci_dev *pdev, | ||||
| 			   const struct pci_device_id *id) | ||||
| { | ||||
| 	struct uio_pci_generic_dev *gdev; | ||||
| 	int err; | ||||
| 
 | ||||
| 	if (!pdev->irq) { | ||||
| 		dev_warn(&pdev->dev, "No IRQ assigned to device: " | ||||
| 			 "no support for interrupts?\n"); | ||||
| 		return -ENODEV; | ||||
| 	} | ||||
| 
 | ||||
| 	err = pci_enable_device(pdev); | ||||
| 	if (err) { | ||||
| 		dev_err(&pdev->dev, "%s: pci_enable_device failed: %d\n", | ||||
| 			__func__, err); | ||||
| 		return err; | ||||
| 	} | ||||
| 
 | ||||
| 	err = verify_pci_2_3(pdev); | ||||
| 	if (err) | ||||
| 		goto err_verify; | ||||
| 
 | ||||
| 	gdev = kzalloc(sizeof(struct uio_pci_generic_dev), GFP_KERNEL); | ||||
| 	if (!gdev) { | ||||
| 		err = -ENOMEM; | ||||
| 		goto err_alloc; | ||||
| 	} | ||||
| 
 | ||||
| 	gdev->info.name = "uio_pci_generic"; | ||||
| 	gdev->info.version = DRIVER_VERSION; | ||||
| 	gdev->info.irq = pdev->irq; | ||||
| 	gdev->info.irq_flags = IRQF_SHARED; | ||||
| 	gdev->info.handler = irqhandler; | ||||
| 	gdev->pdev = pdev; | ||||
| 	spin_lock_init(&gdev->lock); | ||||
| 
 | ||||
| 	if (uio_register_device(&pdev->dev, &gdev->info)) | ||||
| 		goto err_register; | ||||
| 	pci_set_drvdata(pdev, gdev); | ||||
| 
 | ||||
| 	return 0; | ||||
| err_register: | ||||
| 	kfree(gdev); | ||||
| err_alloc: | ||||
| err_verify: | ||||
| 	pci_disable_device(pdev); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static void remove(struct pci_dev *pdev) | ||||
| { | ||||
| 	struct uio_pci_generic_dev *gdev = pci_get_drvdata(pdev); | ||||
| 
 | ||||
| 	uio_unregister_device(&gdev->info); | ||||
| 	pci_disable_device(pdev); | ||||
| 	kfree(gdev); | ||||
| } | ||||
| 
 | ||||
| static struct pci_driver driver = { | ||||
| 	.name = "uio_pci_generic", | ||||
| 	.id_table = NULL, /* only dynamic id's */ | ||||
| 	.probe = probe, | ||||
| 	.remove = remove, | ||||
| }; | ||||
| 
 | ||||
| static int __init init(void) | ||||
| { | ||||
| 	pr_info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); | ||||
| 	return pci_register_driver(&driver); | ||||
| } | ||||
| 
 | ||||
| static void __exit cleanup(void) | ||||
| { | ||||
| 	pci_unregister_driver(&driver); | ||||
| } | ||||
| 
 | ||||
| module_init(init); | ||||
| module_exit(cleanup); | ||||
| 
 | ||||
| MODULE_VERSION(DRIVER_VERSION); | ||||
| MODULE_LICENSE("GPL v2"); | ||||
| MODULE_AUTHOR(DRIVER_AUTHOR); | ||||
| MODULE_DESCRIPTION(DRIVER_DESC); | ||||
|  | @ -154,7 +154,7 @@ static struct attribute *ep_dev_attrs[] = { | |||
| static struct attribute_group ep_dev_attr_grp = { | ||||
| 	.attrs = ep_dev_attrs, | ||||
| }; | ||||
| static struct attribute_group *ep_dev_groups[] = { | ||||
| static const struct attribute_group *ep_dev_groups[] = { | ||||
| 	&ep_dev_attr_grp, | ||||
| 	NULL | ||||
| }; | ||||
|  |  | |||
|  | @ -573,7 +573,7 @@ static struct attribute_group dev_string_attr_grp = { | |||
| 	.is_visible =	dev_string_attrs_are_visible, | ||||
| }; | ||||
| 
 | ||||
| struct attribute_group *usb_device_groups[] = { | ||||
| const struct attribute_group *usb_device_groups[] = { | ||||
| 	&dev_attr_grp, | ||||
| 	&dev_string_attr_grp, | ||||
| 	NULL | ||||
|  | @ -799,7 +799,7 @@ static struct attribute_group intf_assoc_attr_grp = { | |||
| 	.is_visible =	intf_assoc_attrs_are_visible, | ||||
| }; | ||||
| 
 | ||||
| struct attribute_group *usb_interface_groups[] = { | ||||
| const struct attribute_group *usb_interface_groups[] = { | ||||
| 	&intf_attr_grp, | ||||
| 	&intf_assoc_attr_grp, | ||||
| 	NULL | ||||
|  |  | |||
|  | @ -152,8 +152,8 @@ static inline int is_active(const struct usb_interface *f) | |||
| extern const char *usbcore_name; | ||||
| 
 | ||||
| /* sysfs stuff */ | ||||
| extern struct attribute_group *usb_device_groups[]; | ||||
| extern struct attribute_group *usb_interface_groups[]; | ||||
| extern const struct attribute_group *usb_device_groups[]; | ||||
| extern const struct attribute_group *usb_interface_groups[]; | ||||
| 
 | ||||
| /* usbfs stuff */ | ||||
| extern struct mutex usbfs_mutex; | ||||
|  |  | |||
|  | @ -67,7 +67,7 @@ MODULE_PARM_DESC(ignore_oc, "ignore hardware overcurrent indications"); | |||
|  * debug = 0, no debugging messages | ||||
|  * debug = 1, dump failed URBs except for stalls | ||||
|  * debug = 2, dump all failed URBs (including stalls) | ||||
|  *            show all queues in /debug/uhci/[pci_addr] | ||||
|  *            show all queues in /sys/kernel/debug/uhci/[pci_addr] | ||||
|  * debug = 3, show all TDs in URBs when dumping | ||||
|  */ | ||||
| #ifdef DEBUG | ||||
|  |  | |||
|  | @ -255,7 +255,7 @@ static struct attribute_group dev_attr_group = { | |||
| 	.attrs = dev_attrs, | ||||
| }; | ||||
| 
 | ||||
| static struct attribute_group *groups[] = { | ||||
| static const struct attribute_group *groups[] = { | ||||
| 	&dev_attr_group, | ||||
| 	NULL, | ||||
| }; | ||||
|  |  | |||
|  | @ -312,7 +312,7 @@ static struct attribute_group part_attr_group = { | |||
| 	.attrs = part_attrs, | ||||
| }; | ||||
| 
 | ||||
| static struct attribute_group *part_attr_groups[] = { | ||||
| static const struct attribute_group *part_attr_groups[] = { | ||||
| 	&part_attr_group, | ||||
| #ifdef CONFIG_BLK_DEV_IO_TRACE | ||||
| 	&blk_trace_attr_group, | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ struct attribute_container { | |||
| 	struct list_head	node; | ||||
| 	struct klist		containers; | ||||
| 	struct class		*class; | ||||
| 	struct attribute_group	*grp; | ||||
| 	const struct attribute_group *grp; | ||||
| 	struct device_attribute **attrs; | ||||
| 	int (*match)(struct attribute_container *, struct device *); | ||||
| #define	ATTRIBUTE_CONTAINER_NO_CLASSDEVS	0x01 | ||||
|  |  | |||
|  | @ -2,7 +2,8 @@ | |||
|  * device.h - generic, centralized driver model | ||||
|  * | ||||
|  * Copyright (c) 2001-2003 Patrick Mochel <mochel@osdl.org> | ||||
|  * Copyright (c) 2004-2007 Greg Kroah-Hartman <gregkh@suse.de> | ||||
|  * Copyright (c) 2004-2009 Greg Kroah-Hartman <gregkh@suse.de> | ||||
|  * Copyright (c) 2008-2009 Novell Inc. | ||||
|  * | ||||
|  * This file is released under the GPLv2 | ||||
|  * | ||||
|  | @ -130,7 +131,7 @@ struct device_driver { | |||
| 	void (*shutdown) (struct device *dev); | ||||
| 	int (*suspend) (struct device *dev, pm_message_t state); | ||||
| 	int (*resume) (struct device *dev); | ||||
| 	struct attribute_group **groups; | ||||
| 	const struct attribute_group **groups; | ||||
| 
 | ||||
| 	const struct dev_pm_ops *pm; | ||||
| 
 | ||||
|  | @ -224,6 +225,14 @@ extern void class_unregister(struct class *class); | |||
| 	__class_register(class, &__key);	\ | ||||
| }) | ||||
| 
 | ||||
| struct class_compat; | ||||
| struct class_compat *class_compat_register(const char *name); | ||||
| void class_compat_unregister(struct class_compat *cls); | ||||
| int class_compat_create_link(struct class_compat *cls, struct device *dev, | ||||
| 			     struct device *device_link); | ||||
| void class_compat_remove_link(struct class_compat *cls, struct device *dev, | ||||
| 			      struct device *device_link); | ||||
| 
 | ||||
| extern void class_dev_iter_init(struct class_dev_iter *iter, | ||||
| 				struct class *class, | ||||
| 				struct device *start, | ||||
|  | @ -287,7 +296,7 @@ extern void class_destroy(struct class *cls); | |||
|  */ | ||||
| struct device_type { | ||||
| 	const char *name; | ||||
| 	struct attribute_group **groups; | ||||
| 	const struct attribute_group **groups; | ||||
| 	int (*uevent)(struct device *dev, struct kobj_uevent_env *env); | ||||
| 	char *(*nodename)(struct device *dev); | ||||
| 	void (*release)(struct device *dev); | ||||
|  | @ -381,7 +390,6 @@ struct device { | |||
| 	struct bus_type	*bus;		/* type of bus device is on */ | ||||
| 	struct device_driver *driver;	/* which driver has allocated this
 | ||||
| 					   device */ | ||||
| 	void		*driver_data;	/* data private to the driver */ | ||||
| 	void		*platform_data;	/* Platform specific data, device
 | ||||
| 					   core doesn't touch it */ | ||||
| 	struct dev_pm_info	power; | ||||
|  | @ -412,7 +420,7 @@ struct device { | |||
| 
 | ||||
| 	struct klist_node	knode_class; | ||||
| 	struct class		*class; | ||||
| 	struct attribute_group	**groups;	/* optional groups */ | ||||
| 	const struct attribute_group **groups;	/* optional groups */ | ||||
| 
 | ||||
| 	void	(*release)(struct device *dev); | ||||
| }; | ||||
|  | @ -447,16 +455,6 @@ static inline void set_dev_node(struct device *dev, int node) | |||
| } | ||||
| #endif | ||||
| 
 | ||||
| static inline void *dev_get_drvdata(const struct device *dev) | ||||
| { | ||||
| 	return dev->driver_data; | ||||
| } | ||||
| 
 | ||||
| static inline void dev_set_drvdata(struct device *dev, void *data) | ||||
| { | ||||
| 	dev->driver_data = data; | ||||
| } | ||||
| 
 | ||||
| static inline unsigned int dev_get_uevent_suppress(const struct device *dev) | ||||
| { | ||||
| 	return dev->kobj.uevent_suppress; | ||||
|  | @ -490,6 +488,8 @@ extern int device_rename(struct device *dev, char *new_name); | |||
| extern int device_move(struct device *dev, struct device *new_parent, | ||||
| 		       enum dpm_order dpm_order); | ||||
| extern const char *device_get_nodename(struct device *dev, const char **tmp); | ||||
| extern void *dev_get_drvdata(const struct device *dev); | ||||
| extern void dev_set_drvdata(struct device *dev, void *data); | ||||
| 
 | ||||
| /*
 | ||||
|  * Root device objects for grouping under /sys/devices | ||||
|  | @ -502,6 +502,11 @@ static inline struct device *root_device_register(const char *name) | |||
| } | ||||
| extern void root_device_unregister(struct device *root); | ||||
| 
 | ||||
| static inline void *dev_get_platdata(const struct device *dev) | ||||
| { | ||||
| 	return dev->platform_data; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Manual binding of a device to driver. See drivers/base/bus.c | ||||
|  * for information on use. | ||||
|  | @ -547,6 +552,16 @@ extern void put_device(struct device *dev); | |||
| 
 | ||||
| extern void wait_for_device_probe(void); | ||||
| 
 | ||||
| #ifdef CONFIG_DEVTMPFS | ||||
| extern int devtmpfs_create_node(struct device *dev); | ||||
| extern int devtmpfs_delete_node(struct device *dev); | ||||
| extern int devtmpfs_mount(const char *mountpoint); | ||||
| #else | ||||
| static inline int devtmpfs_create_node(struct device *dev) { return 0; } | ||||
| static inline int devtmpfs_delete_node(struct device *dev) { return 0; } | ||||
| static inline int devtmpfs_mount(const char *mountpoint) { return 0; } | ||||
| #endif | ||||
| 
 | ||||
| /* drivers/base/power/shutdown.c */ | ||||
| extern void device_shutdown(void); | ||||
| 
 | ||||
|  |  | |||
|  | @ -895,7 +895,7 @@ struct net_device | |||
| 	/* class/net/name entry */ | ||||
| 	struct device		dev; | ||||
| 	/* space for optional statistics and wireless sysfs groups */ | ||||
| 	struct attribute_group  *sysfs_groups[3]; | ||||
| 	const struct attribute_group *sysfs_groups[3]; | ||||
| 
 | ||||
| 	/* rtnetlink link ops */ | ||||
| 	const struct rtnl_link_ops *rtnl_link_ops; | ||||
|  |  | |||
|  | @ -42,6 +42,7 @@ | |||
| #define  PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */ | ||||
| 
 | ||||
| #define PCI_STATUS		0x06	/* 16 bits */ | ||||
| #define  PCI_STATUS_INTERRUPT	0x08	/* Interrupt status */ | ||||
| #define  PCI_STATUS_CAP_LIST	0x10	/* Support Capability List */ | ||||
| #define  PCI_STATUS_66MHZ	0x20	/* Support 66 Mhz PCI 2.1 bus */ | ||||
| #define  PCI_STATUS_UDF		0x40	/* Support User Definable Features [obsolete] */ | ||||
|  |  | |||
|  | @ -38,6 +38,9 @@ static inline struct shmem_inode_info *SHMEM_I(struct inode *inode) | |||
| 	return container_of(inode, struct shmem_inode_info, vfs_inode); | ||||
| } | ||||
| 
 | ||||
| extern int init_tmpfs(void); | ||||
| extern int shmem_fill_super(struct super_block *sb, void *data, int silent); | ||||
| 
 | ||||
| #ifdef CONFIG_TMPFS_POSIX_ACL | ||||
| int shmem_check_acl(struct inode *, int); | ||||
| int shmem_acl_init(struct inode *, struct inode *); | ||||
|  |  | |||
|  | @ -55,7 +55,7 @@ struct anon_transport_class cls = {				\ | |||
| 
 | ||||
| struct transport_container { | ||||
| 	struct attribute_container ac; | ||||
| 	struct attribute_group *statistics; | ||||
| 	const struct attribute_group *statistics; | ||||
| }; | ||||
| 
 | ||||
| #define attribute_container_to_transport_container(x) \ | ||||
|  |  | |||
|  | @ -415,7 +415,7 @@ void __init prepare_namespace(void) | |||
| 
 | ||||
| 	mount_root(); | ||||
| out: | ||||
| 	devtmpfs_mount("dev"); | ||||
| 	sys_mount(".", "/", NULL, MS_MOVE, NULL); | ||||
| 	sys_chroot("."); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -68,6 +68,7 @@ | |||
| #include <linux/async.h> | ||||
| #include <linux/kmemcheck.h> | ||||
| #include <linux/kmemtrace.h> | ||||
| #include <linux/shmem_fs.h> | ||||
| #include <trace/boot.h> | ||||
| 
 | ||||
| #include <asm/io.h> | ||||
|  | @ -785,6 +786,7 @@ static void __init do_basic_setup(void) | |||
| 	init_workqueues(); | ||||
| 	cpuset_init_smp(); | ||||
| 	usermodehelper_init(); | ||||
| 	init_tmpfs(); | ||||
| 	driver_init(); | ||||
| 	init_irq_proc(); | ||||
| 	do_ctors(); | ||||
|  |  | |||
|  | @ -90,7 +90,6 @@ obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o | |||
| obj-$(CONFIG_MARKERS) += marker.o | ||||
| obj-$(CONFIG_TRACEPOINTS) += tracepoint.o | ||||
| obj-$(CONFIG_LATENCYTOP) += latencytop.o | ||||
| obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o | ||||
| obj-$(CONFIG_FUNCTION_TRACER) += trace/ | ||||
| obj-$(CONFIG_TRACING) += trace/ | ||||
| obj-$(CONFIG_X86_DS) += trace/ | ||||
|  |  | |||
|  | @ -2298,8 +2298,7 @@ static void shmem_put_super(struct super_block *sb) | |||
| 	sb->s_fs_info = NULL; | ||||
| } | ||||
| 
 | ||||
| static int shmem_fill_super(struct super_block *sb, | ||||
| 			    void *data, int silent) | ||||
| int shmem_fill_super(struct super_block *sb, void *data, int silent) | ||||
| { | ||||
| 	struct inode *inode; | ||||
| 	struct dentry *root; | ||||
|  | @ -2519,7 +2518,7 @@ static struct file_system_type tmpfs_fs_type = { | |||
| 	.kill_sb	= kill_litter_super, | ||||
| }; | ||||
| 
 | ||||
| static int __init init_tmpfs(void) | ||||
| int __init init_tmpfs(void) | ||||
| { | ||||
| 	int error; | ||||
| 
 | ||||
|  | @ -2576,7 +2575,7 @@ static struct file_system_type tmpfs_fs_type = { | |||
| 	.kill_sb	= kill_litter_super, | ||||
| }; | ||||
| 
 | ||||
| static int __init init_tmpfs(void) | ||||
| int __init init_tmpfs(void) | ||||
| { | ||||
| 	BUG_ON(register_filesystem(&tmpfs_fs_type) != 0); | ||||
| 
 | ||||
|  | @ -2687,5 +2686,3 @@ int shmem_zero_setup(struct vm_area_struct *vma) | |||
| 	vma->vm_ops = &shmem_vm_ops; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| module_init(init_tmpfs) | ||||
|  |  | |||
|  | @ -68,7 +68,7 @@ static struct attribute_group bt_link_group = { | |||
| 	.attrs = bt_link_attrs, | ||||
| }; | ||||
| 
 | ||||
| static struct attribute_group *bt_link_groups[] = { | ||||
| static const struct attribute_group *bt_link_groups[] = { | ||||
| 	&bt_link_group, | ||||
| 	NULL | ||||
| }; | ||||
|  | @ -392,7 +392,7 @@ static struct attribute_group bt_host_group = { | |||
| 	.attrs = bt_host_attrs, | ||||
| }; | ||||
| 
 | ||||
| static struct attribute_group *bt_host_groups[] = { | ||||
| static const struct attribute_group *bt_host_groups[] = { | ||||
| 	&bt_host_group, | ||||
| 	NULL | ||||
| }; | ||||
|  |  | |||
|  | @ -493,7 +493,7 @@ void netdev_unregister_kobject(struct net_device * net) | |||
| int netdev_register_kobject(struct net_device *net) | ||||
| { | ||||
| 	struct device *dev = &(net->dev); | ||||
| 	struct attribute_group **groups = net->sysfs_groups; | ||||
| 	const struct attribute_group **groups = net->sysfs_groups; | ||||
| 
 | ||||
| 	dev->class = &net_class; | ||||
| 	dev->platform_data = net; | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| /*
 | ||||
|  * If TRACE_SYSTEM is defined, that will be the directory created | ||||
|  * in the ftrace directory under /debugfs/tracing/events/<system> | ||||
|  * in the ftrace directory under /sys/kernel/debug/tracing/events/<system> | ||||
|  * | ||||
|  * The define_trace.h below will also look for a file name of | ||||
|  * TRACE_SYSTEM.h where TRACE_SYSTEM is what is defined here. | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Linus Torvalds
						Linus Torvalds