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>
|
<year>2006-2008</year>
|
||||||
<holder>Hans-Jürgen Koch.</holder>
|
<holder>Hans-Jürgen Koch.</holder>
|
||||||
</copyright>
|
</copyright>
|
||||||
|
<copyright>
|
||||||
|
<year>2009</year>
|
||||||
|
<holder>Red Hat Inc, Michael S. Tsirkin (mst@redhat.com)</holder>
|
||||||
|
</copyright>
|
||||||
|
|
||||||
<legalnotice>
|
<legalnotice>
|
||||||
<para>
|
<para>
|
||||||
|
@ -41,6 +45,13 @@ GPL version 2.
|
||||||
</abstract>
|
</abstract>
|
||||||
|
|
||||||
<revhistory>
|
<revhistory>
|
||||||
|
<revision>
|
||||||
|
<revnumber>0.9</revnumber>
|
||||||
|
<date>2009-07-16</date>
|
||||||
|
<authorinitials>mst</authorinitials>
|
||||||
|
<revremark>Added generic pci driver
|
||||||
|
</revremark>
|
||||||
|
</revision>
|
||||||
<revision>
|
<revision>
|
||||||
<revnumber>0.8</revnumber>
|
<revnumber>0.8</revnumber>
|
||||||
<date>2008-12-24</date>
|
<date>2008-12-24</date>
|
||||||
|
@ -809,6 +820,158 @@ framework to set up sysfs files for this region. Simply leave it alone.
|
||||||
|
|
||||||
</chapter>
|
</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">
|
<appendix id="app1">
|
||||||
<title>Further information</title>
|
<title>Further information</title>
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
|
|
|
@ -22,12 +22,12 @@ tracing information should be printed.
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
||||||
The events which are available for tracing can be found in the file
|
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 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
|
[ Note: '>>' is necessary, otherwise it will firstly disable
|
||||||
all the events. ]
|
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
|
To disable an event, echo the event name to the set_event file prefixed
|
||||||
with an exclamation point:
|
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:
|
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:
|
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,
|
The events are organized into subsystems, such as ext4, irq, sched,
|
||||||
etc., and a full event name looks like this: <subsystem>:<event>. The
|
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
|
"<subsystem>:*"; for example, to enable all irq events, you can use the
|
||||||
command:
|
command:
|
||||||
|
|
||||||
# echo 'irq:*' > /debug/tracing/set_event
|
# echo 'irq:*' > /sys/kernel/debug/tracing/set_event
|
||||||
|
|
||||||
2.2 Via the 'enable' toggle
|
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.
|
of directories.
|
||||||
|
|
||||||
To enable event 'sched_wakeup':
|
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:
|
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:
|
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:
|
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:
|
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
|
S: Maintained
|
||||||
F: include/asm-generic
|
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
|
GFS2 FILE SYSTEM
|
||||||
M: Steven Whitehouse <swhiteho@redhat.com>
|
M: Steven Whitehouse <swhiteho@redhat.com>
|
||||||
L: cluster-devel@redhat.com
|
L: cluster-devel@redhat.com
|
||||||
|
|
|
@ -903,7 +903,7 @@ static struct attribute_group disk_attr_group = {
|
||||||
.attrs = disk_attrs,
|
.attrs = disk_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute_group *disk_attr_groups[] = {
|
static const struct attribute_group *disk_attr_groups[] = {
|
||||||
&disk_attr_group,
|
&disk_attr_group,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,6 +8,31 @@ config UEVENT_HELPER_PATH
|
||||||
Path to uevent helper program forked by the kernel for
|
Path to uevent helper program forked by the kernel for
|
||||||
every uevent.
|
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
|
config STANDALONE
|
||||||
bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL
|
bool "Select only drivers that don't need compile-time external firmware" if EXPERIMENTAL
|
||||||
default y
|
default y
|
||||||
|
|
|
@ -4,8 +4,10 @@ obj-y := core.o sys.o bus.o dd.o \
|
||||||
driver.o class.o platform.o \
|
driver.o class.o platform.o \
|
||||||
cpu.o firmware.o init.o map.o devres.o \
|
cpu.o firmware.o init.o map.o devres.o \
|
||||||
attribute_container.o transport_class.o
|
attribute_container.o transport_class.o
|
||||||
|
obj-$(CONFIG_DEVTMPFS) += devtmpfs.o
|
||||||
obj-y += power/
|
obj-y += power/
|
||||||
obj-$(CONFIG_HAS_DMA) += dma-mapping.o
|
obj-$(CONFIG_HAS_DMA) += dma-mapping.o
|
||||||
|
obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
|
||||||
obj-$(CONFIG_ISA) += isa.o
|
obj-$(CONFIG_ISA) += isa.o
|
||||||
obj-$(CONFIG_FW_LOADER) += firmware_class.o
|
obj-$(CONFIG_FW_LOADER) += firmware_class.o
|
||||||
obj-$(CONFIG_NUMA) += node.o
|
obj-$(CONFIG_NUMA) += node.o
|
||||||
|
|
|
@ -70,6 +70,8 @@ struct class_private {
|
||||||
* @knode_parent - node in sibling list
|
* @knode_parent - node in sibling list
|
||||||
* @knode_driver - node in driver list
|
* @knode_driver - node in driver list
|
||||||
* @knode_bus - node in bus 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
|
* @device - pointer back to the struct class that this structure is
|
||||||
* associated with.
|
* associated with.
|
||||||
*
|
*
|
||||||
|
@ -80,6 +82,7 @@ struct device_private {
|
||||||
struct klist_node knode_parent;
|
struct klist_node knode_parent;
|
||||||
struct klist_node knode_driver;
|
struct klist_node knode_driver;
|
||||||
struct klist_node knode_bus;
|
struct klist_node knode_bus;
|
||||||
|
void *driver_data;
|
||||||
struct device *device;
|
struct device *device;
|
||||||
};
|
};
|
||||||
#define to_device_private_parent(obj) \
|
#define to_device_private_parent(obj) \
|
||||||
|
@ -89,6 +92,8 @@ struct device_private {
|
||||||
#define to_device_private_bus(obj) \
|
#define to_device_private_bus(obj) \
|
||||||
container_of(obj, struct device_private, knode_bus)
|
container_of(obj, struct device_private, knode_bus)
|
||||||
|
|
||||||
|
extern int device_private_init(struct device *dev);
|
||||||
|
|
||||||
/* initialisation functions */
|
/* initialisation functions */
|
||||||
extern int devices_init(void);
|
extern int devices_init(void);
|
||||||
extern int buses_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 cpu_dev_init(void);
|
||||||
|
|
||||||
extern int bus_add_device(struct device *dev);
|
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 void bus_remove_device(struct device *dev);
|
||||||
|
|
||||||
extern int bus_add_driver(struct device_driver *drv);
|
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) { }
|
struct device_driver *drv) { }
|
||||||
static inline void module_remove_driver(struct device_driver *drv) { }
|
static inline void module_remove_driver(struct device_driver *drv) { }
|
||||||
#endif
|
#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
|
* bus_add_device - add device to bus
|
||||||
* @dev: device being added
|
* @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.
|
* - Add the device to its bus's list of devices.
|
||||||
* - Create link to device's bus.
|
|
||||||
*/
|
*/
|
||||||
int bus_add_device(struct device *dev)
|
int bus_add_device(struct device *dev)
|
||||||
{
|
{
|
||||||
|
@ -483,6 +484,7 @@ int bus_add_device(struct device *dev)
|
||||||
error = make_deprecated_bus_links(dev);
|
error = make_deprecated_bus_links(dev);
|
||||||
if (error)
|
if (error)
|
||||||
goto out_deprecated;
|
goto out_deprecated;
|
||||||
|
klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -498,24 +500,19 @@ out_put:
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* bus_attach_device - add device to bus
|
* bus_probe_device - probe drivers for a new device
|
||||||
* @dev: device tried to attach to a driver
|
* @dev: device to probe
|
||||||
*
|
*
|
||||||
* - Add device to bus's list of devices.
|
* - Automatically probe for a driver if the bus allows it.
|
||||||
* - Try to attach to driver.
|
|
||||||
*/
|
*/
|
||||||
void bus_attach_device(struct device *dev)
|
void bus_probe_device(struct device *dev)
|
||||||
{
|
{
|
||||||
struct bus_type *bus = dev->bus;
|
struct bus_type *bus = dev->bus;
|
||||||
int ret = 0;
|
int ret;
|
||||||
|
|
||||||
if (bus) {
|
if (bus && bus->p->drivers_autoprobe) {
|
||||||
if (bus->p->drivers_autoprobe)
|
ret = device_attach(dev);
|
||||||
ret = device_attach(dev);
|
|
||||||
WARN_ON(ret < 0);
|
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);
|
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)
|
int __init classes_init(void)
|
||||||
{
|
{
|
||||||
class_kset = kset_create_and_add("class", NULL, NULL);
|
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,
|
static int device_add_groups(struct device *dev,
|
||||||
struct attribute_group **groups)
|
const struct attribute_group **groups)
|
||||||
{
|
{
|
||||||
int error = 0;
|
int error = 0;
|
||||||
int i;
|
int i;
|
||||||
|
@ -361,7 +361,7 @@ static int device_add_groups(struct device *dev,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void device_remove_groups(struct device *dev,
|
static void device_remove_groups(struct device *dev,
|
||||||
struct attribute_group **groups)
|
const struct attribute_group **groups)
|
||||||
{
|
{
|
||||||
int i;
|
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.
|
* device_add - add device to device hierarchy.
|
||||||
* @dev: device.
|
* @dev: device.
|
||||||
|
@ -868,14 +879,11 @@ int device_add(struct device *dev)
|
||||||
if (!dev)
|
if (!dev)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);
|
|
||||||
if (!dev->p) {
|
if (!dev->p) {
|
||||||
error = -ENOMEM;
|
error = device_private_init(dev);
|
||||||
goto done;
|
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
|
* 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);
|
error = device_create_sys_dev_entry(dev);
|
||||||
if (error)
|
if (error)
|
||||||
goto devtattrError;
|
goto devtattrError;
|
||||||
|
|
||||||
|
devtmpfs_create_node(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
error = device_add_class_symlinks(dev);
|
error = device_add_class_symlinks(dev);
|
||||||
|
@ -945,7 +955,7 @@ int device_add(struct device *dev)
|
||||||
BUS_NOTIFY_ADD_DEVICE, dev);
|
BUS_NOTIFY_ADD_DEVICE, dev);
|
||||||
|
|
||||||
kobject_uevent(&dev->kobj, KOBJ_ADD);
|
kobject_uevent(&dev->kobj, KOBJ_ADD);
|
||||||
bus_attach_device(dev);
|
bus_probe_device(dev);
|
||||||
if (parent)
|
if (parent)
|
||||||
klist_add_tail(&dev->p->knode_parent,
|
klist_add_tail(&dev->p->knode_parent,
|
||||||
&parent->p->klist_children);
|
&parent->p->klist_children);
|
||||||
|
@ -1067,6 +1077,7 @@ void device_del(struct device *dev)
|
||||||
if (parent)
|
if (parent)
|
||||||
klist_del(&dev->p->knode_parent);
|
klist_del(&dev->p->knode_parent);
|
||||||
if (MAJOR(dev->devt)) {
|
if (MAJOR(dev->devt)) {
|
||||||
|
devtmpfs_delete_node(dev);
|
||||||
device_remove_sys_dev_entry(dev);
|
device_remove_sys_dev_entry(dev);
|
||||||
device_remove_file(dev, &devt_attr);
|
device_remove_file(dev, &devt_attr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
*
|
*
|
||||||
* Copyright (c) 2002-5 Patrick Mochel
|
* Copyright (c) 2002-5 Patrick Mochel
|
||||||
* Copyright (c) 2002-3 Open Source Development Labs
|
* Copyright (c) 2002-3 Open Source Development Labs
|
||||||
* Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de>
|
* Copyright (c) 2007-2009 Greg Kroah-Hartman <gregkh@suse.de>
|
||||||
* Copyright (c) 2007 Novell Inc.
|
* Copyright (c) 2007-2009 Novell Inc.
|
||||||
*
|
*
|
||||||
* This file is released under the GPLv2
|
* This file is released under the GPLv2
|
||||||
*/
|
*/
|
||||||
|
@ -391,3 +391,30 @@ void driver_detach(struct device_driver *drv)
|
||||||
put_device(dev);
|
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);
|
EXPORT_SYMBOL_GPL(put_driver);
|
||||||
|
|
||||||
static int driver_add_groups(struct device_driver *drv,
|
static int driver_add_groups(struct device_driver *drv,
|
||||||
struct attribute_group **groups)
|
const struct attribute_group **groups)
|
||||||
{
|
{
|
||||||
int error = 0;
|
int error = 0;
|
||||||
int i;
|
int i;
|
||||||
|
@ -201,7 +201,7 @@ static int driver_add_groups(struct device_driver *drv,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void driver_remove_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;
|
int i;
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
void __init driver_init(void)
|
void __init driver_init(void)
|
||||||
{
|
{
|
||||||
/* These are the core pieces */
|
/* These are the core pieces */
|
||||||
|
devtmpfs_init();
|
||||||
devices_init();
|
devices_init();
|
||||||
buses_init();
|
buses_init();
|
||||||
classes_init();
|
classes_init();
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
* information.
|
* information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/string.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/init.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,
|
int platform_device_add_data(struct platform_device *pdev, const void *data,
|
||||||
size_t size)
|
size_t size)
|
||||||
{
|
{
|
||||||
void *d;
|
void *d = kmemdup(data, size, GFP_KERNEL);
|
||||||
|
|
||||||
d = kmalloc(size, GFP_KERNEL);
|
|
||||||
if (d) {
|
if (d) {
|
||||||
memcpy(d, data, size);
|
|
||||||
pdev->dev.platform_data = d;
|
pdev->dev.platform_data = d;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
return d ? 0 : -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(platform_device_add_data);
|
EXPORT_SYMBOL_GPL(platform_device_add_data);
|
||||||
|
|
||||||
|
|
|
@ -572,7 +572,7 @@ static struct attribute_group cciss_dev_attr_group = {
|
||||||
.attrs = cciss_dev_attrs,
|
.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,
|
&cciss_dev_attr_group,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
|
@ -92,7 +92,7 @@ static struct mutex ctl_mutex; /* Serialize open/close/setup/teardown */
|
||||||
static mempool_t *psd_pool;
|
static mempool_t *psd_pool;
|
||||||
|
|
||||||
static struct class *class_pktcdvd = NULL; /* /sys/class/pktcdvd */
|
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 */
|
/* forward declaration */
|
||||||
static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev);
|
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,
|
.write = kmsg_write,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct {
|
static const struct memdev {
|
||||||
unsigned int minor;
|
const char *name;
|
||||||
char *name;
|
const struct file_operations *fops;
|
||||||
umode_t mode;
|
struct backing_dev_info *dev_info;
|
||||||
const struct file_operations *fops;
|
} devlist[] = {
|
||||||
struct backing_dev_info *dev_info;
|
[ 1] = { "mem", &mem_fops, &directly_mappable_cdev_bdi },
|
||||||
} devlist[] = { /* list of minor devices */
|
|
||||||
{1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops,
|
|
||||||
&directly_mappable_cdev_bdi},
|
|
||||||
#ifdef CONFIG_DEVKMEM
|
#ifdef CONFIG_DEVKMEM
|
||||||
{2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops,
|
[ 2] = { "kmem", &kmem_fops, &directly_mappable_cdev_bdi },
|
||||||
&directly_mappable_cdev_bdi},
|
|
||||||
#endif
|
#endif
|
||||||
{3, "null", S_IRUGO | S_IWUGO, &null_fops, NULL},
|
[ 3] = {"null", &null_fops, NULL },
|
||||||
#ifdef CONFIG_DEVPORT
|
#ifdef CONFIG_DEVPORT
|
||||||
{4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops, NULL},
|
[ 4] = { "port", &port_fops, NULL },
|
||||||
#endif
|
#endif
|
||||||
{5, "zero", S_IRUGO | S_IWUGO, &zero_fops, &zero_bdi},
|
[ 5] = { "zero", &zero_fops, &zero_bdi },
|
||||||
{7, "full", S_IRUGO | S_IWUGO, &full_fops, NULL},
|
[ 7] = { "full", &full_fops, NULL },
|
||||||
{8, "random", S_IRUGO | S_IWUSR, &random_fops, NULL},
|
[ 8] = { "random", &random_fops, NULL },
|
||||||
{9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops, NULL},
|
[ 9] = { "urandom", &urandom_fops, NULL },
|
||||||
{11,"kmsg", S_IRUGO | S_IWUSR, &kmsg_fops, NULL},
|
[11] = { "kmsg", &kmsg_fops, NULL },
|
||||||
#ifdef CONFIG_CRASH_DUMP
|
#ifdef CONFIG_CRASH_DUMP
|
||||||
{12,"oldmem", S_IRUSR | S_IWUSR | S_IRGRP, &oldmem_fops, NULL},
|
[12] = { "oldmem", &oldmem_fops, NULL },
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static int memory_open(struct inode *inode, struct file *filp)
|
static int memory_open(struct inode *inode, struct file *filp)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int minor;
|
||||||
int i;
|
const struct memdev *dev;
|
||||||
|
int ret = -ENXIO;
|
||||||
|
|
||||||
lock_kernel();
|
lock_kernel();
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(devlist); i++) {
|
minor = iminor(inode);
|
||||||
if (devlist[i].minor == iminor(inode)) {
|
if (minor >= ARRAY_SIZE(devlist))
|
||||||
filp->f_op = devlist[i].fops;
|
goto out;
|
||||||
if (devlist[i].dev_info) {
|
|
||||||
filp->f_mapping->backing_dev_info =
|
|
||||||
devlist[i].dev_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
dev = &devlist[minor];
|
||||||
}
|
if (!dev->fops)
|
||||||
}
|
goto out;
|
||||||
|
|
||||||
if (i == ARRAY_SIZE(devlist))
|
filp->f_op = dev->fops;
|
||||||
ret = -ENXIO;
|
if (dev->dev_info)
|
||||||
|
filp->f_mapping->backing_dev_info = dev->dev_info;
|
||||||
|
|
||||||
|
if (dev->fops->open)
|
||||||
|
ret = dev->fops->open(inode, filp);
|
||||||
else
|
else
|
||||||
if (filp->f_op && filp->f_op->open)
|
ret = 0;
|
||||||
ret = filp->f_op->open(inode, filp);
|
out:
|
||||||
|
|
||||||
unlock_kernel();
|
unlock_kernel();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations memory_fops = {
|
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 struct class *mem_class;
|
||||||
|
|
||||||
static int __init chr_dev_init(void)
|
static int __init chr_dev_init(void)
|
||||||
{
|
{
|
||||||
int i;
|
int minor;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = bdi_init(&zero_bdi);
|
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);
|
printk("unable to get major %d for memory devs\n", MEM_MAJOR);
|
||||||
|
|
||||||
mem_class = class_create(THIS_MODULE, "mem");
|
mem_class = class_create(THIS_MODULE, "mem");
|
||||||
for (i = 0; i < ARRAY_SIZE(devlist); i++)
|
for (minor = 1; minor < ARRAY_SIZE(devlist); minor++) {
|
||||||
device_create(mem_class, NULL,
|
if (!devlist[minor].name)
|
||||||
MKDEV(MEM_MAJOR, devlist[i].minor), NULL,
|
continue;
|
||||||
devlist[i].name);
|
device_create(mem_class, NULL, MKDEV(MEM_MAJOR, minor),
|
||||||
|
NULL, devlist[minor].name);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -312,7 +312,7 @@ static void init_fw_attribute_group(struct device *dev,
|
||||||
group->groups[0] = &group->group;
|
group->groups[0] = &group->group;
|
||||||
group->groups[1] = NULL;
|
group->groups[1] = NULL;
|
||||||
group->group.attrs = group->attrs;
|
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,
|
static ssize_t modalias_show(struct device *dev,
|
||||||
|
|
|
@ -139,7 +139,7 @@ static struct attribute_group sys_dmi_attribute_group = {
|
||||||
.attrs = sys_dmi_attributes,
|
.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,
|
&sys_dmi_attribute_group,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
|
@ -623,7 +623,7 @@ static struct attribute_group ehca_drv_attr_grp = {
|
||||||
.attrs = ehca_drv_attrs
|
.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,
|
&ehca_drv_attr_grp,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1286,7 +1286,7 @@ struct device_driver;
|
||||||
|
|
||||||
extern const char ib_ipath_version[];
|
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 *);
|
int ipath_device_create_group(struct device *, struct ipath_devdata *);
|
||||||
void ipath_device_remove_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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct attribute_group *ipath_driver_attr_groups[] = {
|
const struct attribute_group *ipath_driver_attr_groups[] = {
|
||||||
&driver_attr_group,
|
&driver_attr_group,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1144,7 +1144,7 @@ static struct attribute_group input_dev_caps_attr_group = {
|
||||||
.attrs = input_dev_caps_attrs,
|
.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_attr_group,
|
||||||
&input_dev_id_attr_group,
|
&input_dev_id_attr_group,
|
||||||
&input_dev_caps_attr_group,
|
&input_dev_caps_attr_group,
|
||||||
|
|
|
@ -238,7 +238,7 @@ static void enclosure_component_release(struct device *dev)
|
||||||
put_device(dev->parent);
|
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
|
* enclosure_component_register - add a particular component to an enclosure
|
||||||
|
@ -536,7 +536,7 @@ static struct attribute_group enclosure_group = {
|
||||||
.attrs = enclosure_component_attrs,
|
.attrs = enclosure_component_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute_group *enclosure_groups[] = {
|
static const struct attribute_group *enclosure_groups[] = {
|
||||||
&enclosure_group,
|
&enclosure_group,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/file.h>
|
#include <linux/file.h>
|
||||||
|
@ -21,6 +22,8 @@
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
#include <linux/wait.h>
|
||||||
|
#include <linux/poll.h>
|
||||||
#include "hpilo.h"
|
#include "hpilo.h"
|
||||||
|
|
||||||
static struct class *ilo_class;
|
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)
|
static int fifo_enqueue(struct ilo_hwinfo *hw, char *fifobar, int entry)
|
||||||
{
|
{
|
||||||
struct fifo *fifo_q = FIFOBARTOHANDLE(fifobar);
|
struct fifo *fifo_q = FIFOBARTOHANDLE(fifobar);
|
||||||
|
unsigned long flags;
|
||||||
int ret = 0;
|
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]
|
if (!(fifo_q->fifobar[(fifo_q->tail + 1) & fifo_q->imask]
|
||||||
& ENTRY_MASK_O)) {
|
& ENTRY_MASK_O)) {
|
||||||
fifo_q->fifobar[fifo_q->tail & fifo_q->imask] |=
|
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;
|
fifo_q->tail += 1;
|
||||||
ret = 1;
|
ret = 1;
|
||||||
}
|
}
|
||||||
spin_unlock(&hw->fifo_lock);
|
spin_unlock_irqrestore(&hw->fifo_lock, flags);
|
||||||
|
|
||||||
return ret;
|
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)
|
static int fifo_dequeue(struct ilo_hwinfo *hw, char *fifobar, int *entry)
|
||||||
{
|
{
|
||||||
struct fifo *fifo_q = FIFOBARTOHANDLE(fifobar);
|
struct fifo *fifo_q = FIFOBARTOHANDLE(fifobar);
|
||||||
|
unsigned long flags;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
u64 c;
|
u64 c;
|
||||||
|
|
||||||
spin_lock(&hw->fifo_lock);
|
spin_lock_irqsave(&hw->fifo_lock, flags);
|
||||||
c = fifo_q->fifobar[fifo_q->head & fifo_q->imask];
|
c = fifo_q->fifobar[fifo_q->head & fifo_q->imask];
|
||||||
if (c & ENTRY_MASK_C) {
|
if (c & ENTRY_MASK_C) {
|
||||||
if (entry)
|
if (entry)
|
||||||
|
@ -93,7 +98,23 @@ static int fifo_dequeue(struct ilo_hwinfo *hw, char *fifobar, int *entry)
|
||||||
fifo_q->head += 1;
|
fifo_q->head += 1;
|
||||||
ret = 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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -142,6 +163,13 @@ static int ilo_pkt_dequeue(struct ilo_hwinfo *hw, struct ccb *ccb,
|
||||||
return ret;
|
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)
|
static inline void doorbell_set(struct ccb *ccb)
|
||||||
{
|
{
|
||||||
iowrite8(1, ccb->ccb_u5.db_base);
|
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);
|
iowrite8(2, ccb->ccb_u5.db_base);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int ctrl_set(int l2sz, int idxmask, int desclim)
|
static inline int ctrl_set(int l2sz, int idxmask, int desclim)
|
||||||
{
|
{
|
||||||
int active = 0, go = 1;
|
int active = 0, go = 1;
|
||||||
|
@ -160,6 +189,7 @@ static inline int ctrl_set(int l2sz, int idxmask, int desclim)
|
||||||
active << CTRL_BITPOS_A |
|
active << CTRL_BITPOS_A |
|
||||||
go << CTRL_BITPOS_G;
|
go << CTRL_BITPOS_G;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ctrl_setup(struct ccb *ccb, int nr_desc, int l2desc_sz)
|
static void ctrl_setup(struct ccb *ccb, int nr_desc, int l2desc_sz)
|
||||||
{
|
{
|
||||||
/* for simplicity, use the same parameters for send and recv ctrls */
|
/* 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)
|
static void ilo_ccb_close(struct pci_dev *pdev, struct ccb_data *data)
|
||||||
{
|
{
|
||||||
struct ccb *driver_ccb;
|
struct ccb *driver_ccb = &data->driver_ccb;
|
||||||
struct ccb __iomem *device_ccb;
|
struct ccb __iomem *device_ccb = data->mapped_ccb;
|
||||||
int retries;
|
int retries;
|
||||||
|
|
||||||
driver_ccb = &data->driver_ccb;
|
|
||||||
device_ccb = data->mapped_ccb;
|
|
||||||
|
|
||||||
/* complicated dance to tell the hw we are stopping */
|
/* complicated dance to tell the hw we are stopping */
|
||||||
doorbell_clr(driver_ccb);
|
doorbell_clr(driver_ccb);
|
||||||
iowrite32(ioread32(&device_ccb->send_ctrl) & ~(1 << CTRL_BITPOS_G),
|
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);
|
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;
|
char *dma_va, *dma_pa;
|
||||||
int pkt_id, pkt_sz, i, error;
|
|
||||||
struct ccb *driver_ccb, *ilo_ccb;
|
struct ccb *driver_ccb, *ilo_ccb;
|
||||||
struct pci_dev *pdev;
|
|
||||||
|
|
||||||
driver_ccb = &data->driver_ccb;
|
driver_ccb = &data->driver_ccb;
|
||||||
ilo_ccb = &data->ilo_ccb;
|
ilo_ccb = &data->ilo_ccb;
|
||||||
pdev = hw->ilo_dev;
|
|
||||||
|
|
||||||
data->dma_size = 2 * fifo_sz(NR_QENTRY) +
|
data->dma_size = 2 * fifo_sz(NR_QENTRY) +
|
||||||
2 * desc_mem_sz(NR_QENTRY) +
|
2 * desc_mem_sz(NR_QENTRY) +
|
||||||
ILO_START_ALIGN + ILO_CACHE_SZ;
|
ILO_START_ALIGN + ILO_CACHE_SZ;
|
||||||
|
|
||||||
error = -ENOMEM;
|
data->dma_va = pci_alloc_consistent(hw->ilo_dev, data->dma_size,
|
||||||
data->dma_va = pci_alloc_consistent(pdev, data->dma_size,
|
|
||||||
&data->dma_pa);
|
&data->dma_pa);
|
||||||
if (!data->dma_va)
|
if (!data->dma_va)
|
||||||
goto out;
|
return -ENOMEM;
|
||||||
|
|
||||||
dma_va = (char *)data->dma_va;
|
dma_va = (char *)data->dma_va;
|
||||||
dma_pa = (char *)data->dma_pa;
|
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);
|
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 */
|
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 */
|
/* copy the ccb with physical addrs to device memory */
|
||||||
data->mapped_ccb = (struct ccb __iomem *)
|
data->mapped_ccb = (struct ccb __iomem *)
|
||||||
(hw->ram_vaddr + (slot * ILOHW_CCB_SZ));
|
(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 */
|
/* put packets on the send and receive queues */
|
||||||
pkt_sz = 0;
|
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++)
|
for (pkt_id = 0; pkt_id < NR_QENTRY; pkt_id++)
|
||||||
ilo_pkt_enqueue(hw, driver_ccb, RECVQ, pkt_id, pkt_sz);
|
ilo_pkt_enqueue(hw, driver_ccb, RECVQ, pkt_id, pkt_sz);
|
||||||
|
|
||||||
|
/* the ccb is ready to use */
|
||||||
doorbell_clr(driver_ccb);
|
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 */
|
/* make sure iLO is really handling requests */
|
||||||
for (i = MAX_WAIT; i > 0; i--) {
|
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);
|
udelay(WAIT_TIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i) {
|
if (i == 0) {
|
||||||
ilo_pkt_enqueue(hw, driver_ccb, SENDQ, pkt_id, 0);
|
dev_err(&hw->ilo_dev->dev, "Open could not dequeue a packet\n");
|
||||||
doorbell_set(driver_ccb);
|
return -EBUSY;
|
||||||
} else {
|
|
||||||
dev_err(&pdev->dev, "Open could not dequeue a packet\n");
|
|
||||||
error = -EBUSY;
|
|
||||||
goto free;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ilo_pkt_enqueue(hw, driver_ccb, SENDQ, pkt_id, 0);
|
||||||
|
doorbell_set(driver_ccb);
|
||||||
return 0;
|
return 0;
|
||||||
free:
|
|
||||||
ilo_ccb_close(pdev, data);
|
|
||||||
out:
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int is_channel_reset(struct ccb *ccb)
|
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;
|
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)
|
static inline int is_device_reset(struct ilo_hwinfo *hw)
|
||||||
{
|
{
|
||||||
/* check for global reset condition */
|
/* 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)
|
static inline void clear_device(struct ilo_hwinfo *hw)
|
||||||
{
|
{
|
||||||
/* clear the device (reset bits, pending channel entries) */
|
/* 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;
|
int slot;
|
||||||
|
|
||||||
|
@ -368,40 +426,22 @@ static void ilo_locked_reset(struct ilo_hwinfo *hw)
|
||||||
continue;
|
continue;
|
||||||
set_channel_reset(&hw->ccb_alloc[slot]->driver_ccb);
|
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,
|
static ssize_t ilo_read(struct file *fp, char __user *buf,
|
||||||
size_t len, loff_t *off)
|
size_t len, loff_t *off)
|
||||||
{
|
{
|
||||||
int err, found, cnt, pkt_id, pkt_len;
|
int err, found, cnt, pkt_id, pkt_len;
|
||||||
struct ccb_data *data;
|
struct ccb_data *data = fp->private_data;
|
||||||
struct ccb *driver_ccb;
|
struct ccb *driver_ccb = &data->driver_ccb;
|
||||||
struct ilo_hwinfo *hw;
|
struct ilo_hwinfo *hw = data->ilo_hw;
|
||||||
void *pkt;
|
void *pkt;
|
||||||
|
|
||||||
data = fp->private_data;
|
if (is_channel_reset(driver_ccb)) {
|
||||||
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
|
* If the device has been reset, applications
|
||||||
* need to close and reopen all ccbs.
|
* need to close and reopen all ccbs.
|
||||||
*/
|
*/
|
||||||
ilo_reset(hw);
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,23 +482,13 @@ static ssize_t ilo_write(struct file *fp, const char __user *buf,
|
||||||
size_t len, loff_t *off)
|
size_t len, loff_t *off)
|
||||||
{
|
{
|
||||||
int err, pkt_id, pkt_len;
|
int err, pkt_id, pkt_len;
|
||||||
struct ccb_data *data;
|
struct ccb_data *data = fp->private_data;
|
||||||
struct ccb *driver_ccb;
|
struct ccb *driver_ccb = &data->driver_ccb;
|
||||||
struct ilo_hwinfo *hw;
|
struct ilo_hwinfo *hw = data->ilo_hw;
|
||||||
void *pkt;
|
void *pkt;
|
||||||
|
|
||||||
data = fp->private_data;
|
if (is_channel_reset(driver_ccb))
|
||||||
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);
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
|
||||||
|
|
||||||
/* get a packet to send the user command */
|
/* get a packet to send the user command */
|
||||||
if (!ilo_pkt_dequeue(hw, driver_ccb, SENDQ, &pkt_id, &pkt_len, &pkt))
|
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;
|
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)
|
static int ilo_close(struct inode *ip, struct file *fp)
|
||||||
{
|
{
|
||||||
int slot;
|
int slot;
|
||||||
struct ccb_data *data;
|
struct ccb_data *data;
|
||||||
struct ilo_hwinfo *hw;
|
struct ilo_hwinfo *hw;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
slot = iminor(ip) % MAX_CCB;
|
slot = iminor(ip) % MAX_CCB;
|
||||||
hw = container_of(ip->i_cdev, struct ilo_hwinfo, cdev);
|
hw = container_of(ip->i_cdev, struct ilo_hwinfo, cdev);
|
||||||
|
|
||||||
spin_lock(&hw->alloc_lock);
|
spin_lock(&hw->open_lock);
|
||||||
|
|
||||||
if (is_device_reset(hw))
|
|
||||||
ilo_locked_reset(hw);
|
|
||||||
|
|
||||||
if (hw->ccb_alloc[slot]->ccb_cnt == 1) {
|
if (hw->ccb_alloc[slot]->ccb_cnt == 1) {
|
||||||
|
|
||||||
data = fp->private_data;
|
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);
|
ilo_ccb_close(hw->ilo_dev, data);
|
||||||
|
|
||||||
kfree(data);
|
kfree(data);
|
||||||
hw->ccb_alloc[slot] = NULL;
|
|
||||||
} else
|
} else
|
||||||
hw->ccb_alloc[slot]->ccb_cnt--;
|
hw->ccb_alloc[slot]->ccb_cnt--;
|
||||||
|
|
||||||
spin_unlock(&hw->alloc_lock);
|
spin_unlock(&hw->open_lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -515,6 +561,7 @@ static int ilo_open(struct inode *ip, struct file *fp)
|
||||||
int slot, error;
|
int slot, error;
|
||||||
struct ccb_data *data;
|
struct ccb_data *data;
|
||||||
struct ilo_hwinfo *hw;
|
struct ilo_hwinfo *hw;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
slot = iminor(ip) % MAX_CCB;
|
slot = iminor(ip) % MAX_CCB;
|
||||||
hw = container_of(ip->i_cdev, struct ilo_hwinfo, cdev);
|
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)
|
if (!data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
spin_lock(&hw->alloc_lock);
|
spin_lock(&hw->open_lock);
|
||||||
|
|
||||||
if (is_device_reset(hw))
|
|
||||||
ilo_locked_reset(hw);
|
|
||||||
|
|
||||||
/* each fd private_data holds sw/hw view of ccb */
|
/* each fd private_data holds sw/hw view of ccb */
|
||||||
if (hw->ccb_alloc[slot] == NULL) {
|
if (hw->ccb_alloc[slot] == NULL) {
|
||||||
/* create a channel control block for this minor */
|
/* create a channel control block for this minor */
|
||||||
error = ilo_ccb_open(hw, data, slot);
|
error = ilo_ccb_setup(hw, data, slot);
|
||||||
if (!error) {
|
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
|
|
||||||
kfree(data);
|
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 {
|
} else {
|
||||||
kfree(data);
|
kfree(data);
|
||||||
if (fp->f_flags & O_EXCL || hw->ccb_alloc[slot]->ccb_excl) {
|
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;
|
error = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spin_unlock(&hw->alloc_lock);
|
out:
|
||||||
|
spin_unlock(&hw->open_lock);
|
||||||
|
|
||||||
if (!error)
|
if (!error)
|
||||||
fp->private_data = hw->ccb_alloc[slot];
|
fp->private_data = hw->ccb_alloc[slot];
|
||||||
|
@ -566,10 +634,46 @@ static const struct file_operations ilo_fops = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.read = ilo_read,
|
.read = ilo_read,
|
||||||
.write = ilo_write,
|
.write = ilo_write,
|
||||||
|
.poll = ilo_poll,
|
||||||
.open = ilo_open,
|
.open = ilo_open,
|
||||||
.release = ilo_close,
|
.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)
|
static void ilo_unmap_device(struct pci_dev *pdev, struct ilo_hwinfo *hw)
|
||||||
{
|
{
|
||||||
pci_iounmap(pdev, hw->db_vaddr);
|
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));
|
device_destroy(ilo_class, MKDEV(ilo_major, i));
|
||||||
|
|
||||||
cdev_del(&ilo_hw->cdev);
|
cdev_del(&ilo_hw->cdev);
|
||||||
|
ilo_disable_interrupts(ilo_hw);
|
||||||
|
free_irq(pdev->irq, ilo_hw);
|
||||||
ilo_unmap_device(pdev, ilo_hw);
|
ilo_unmap_device(pdev, ilo_hw);
|
||||||
pci_release_regions(pdev);
|
pci_release_regions(pdev);
|
||||||
pci_disable_device(pdev);
|
pci_disable_device(pdev);
|
||||||
|
@ -658,6 +764,7 @@ static int __devinit ilo_probe(struct pci_dev *pdev,
|
||||||
ilo_hw->ilo_dev = pdev;
|
ilo_hw->ilo_dev = pdev;
|
||||||
spin_lock_init(&ilo_hw->alloc_lock);
|
spin_lock_init(&ilo_hw->alloc_lock);
|
||||||
spin_lock_init(&ilo_hw->fifo_lock);
|
spin_lock_init(&ilo_hw->fifo_lock);
|
||||||
|
spin_lock_init(&ilo_hw->open_lock);
|
||||||
|
|
||||||
error = pci_enable_device(pdev);
|
error = pci_enable_device(pdev);
|
||||||
if (error)
|
if (error)
|
||||||
|
@ -676,13 +783,19 @@ static int __devinit ilo_probe(struct pci_dev *pdev,
|
||||||
pci_set_drvdata(pdev, ilo_hw);
|
pci_set_drvdata(pdev, ilo_hw);
|
||||||
clear_device(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);
|
cdev_init(&ilo_hw->cdev, &ilo_fops);
|
||||||
ilo_hw->cdev.owner = THIS_MODULE;
|
ilo_hw->cdev.owner = THIS_MODULE;
|
||||||
start = devnum * MAX_CCB;
|
start = devnum * MAX_CCB;
|
||||||
error = cdev_add(&ilo_hw->cdev, MKDEV(ilo_major, start), MAX_CCB);
|
error = cdev_add(&ilo_hw->cdev, MKDEV(ilo_major, start), MAX_CCB);
|
||||||
if (error) {
|
if (error) {
|
||||||
dev_err(&pdev->dev, "Could not add cdev\n");
|
dev_err(&pdev->dev, "Could not add cdev\n");
|
||||||
goto unmap;
|
goto remove_isr;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (minor = 0 ; minor < MAX_CCB; minor++) {
|
for (minor = 0 ; minor < MAX_CCB; minor++) {
|
||||||
|
@ -695,6 +808,9 @@ static int __devinit ilo_probe(struct pci_dev *pdev,
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
remove_isr:
|
||||||
|
ilo_disable_interrupts(ilo_hw);
|
||||||
|
free_irq(pdev->irq, ilo_hw);
|
||||||
unmap:
|
unmap:
|
||||||
ilo_unmap_device(pdev, ilo_hw);
|
ilo_unmap_device(pdev, ilo_hw);
|
||||||
free_regions:
|
free_regions:
|
||||||
|
@ -759,7 +875,7 @@ static void __exit ilo_exit(void)
|
||||||
class_destroy(ilo_class);
|
class_destroy(ilo_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
MODULE_VERSION("1.1");
|
MODULE_VERSION("1.2");
|
||||||
MODULE_ALIAS(ILO_NAME);
|
MODULE_ALIAS(ILO_NAME);
|
||||||
MODULE_DESCRIPTION(ILO_NAME);
|
MODULE_DESCRIPTION(ILO_NAME);
|
||||||
MODULE_AUTHOR("David Altobelli <david.altobelli@hp.com>");
|
MODULE_AUTHOR("David Altobelli <david.altobelli@hp.com>");
|
||||||
|
|
|
@ -46,11 +46,14 @@ struct ilo_hwinfo {
|
||||||
|
|
||||||
spinlock_t alloc_lock;
|
spinlock_t alloc_lock;
|
||||||
spinlock_t fifo_lock;
|
spinlock_t fifo_lock;
|
||||||
|
spinlock_t open_lock;
|
||||||
|
|
||||||
struct cdev cdev;
|
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
|
#define DB_OUT 0xD4
|
||||||
/* DB_OUT reset bit */
|
/* DB_OUT reset bit */
|
||||||
#define DB_RESET 26
|
#define DB_RESET 26
|
||||||
|
@ -131,6 +134,9 @@ struct ccb_data {
|
||||||
/* pointer to hardware device info */
|
/* pointer to hardware device info */
|
||||||
struct ilo_hwinfo *ilo_hw;
|
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 */
|
/* usage count, to allow for shared ccb's */
|
||||||
int ccb_cnt;
|
int ccb_cnt;
|
||||||
|
|
||||||
|
|
|
@ -276,7 +276,7 @@ static struct attribute_group mmc_std_attr_group = {
|
||||||
.attrs = mmc_std_attrs,
|
.attrs = mmc_std_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute_group *mmc_attr_groups[] = {
|
static const struct attribute_group *mmc_attr_groups[] = {
|
||||||
&mmc_std_attr_group,
|
&mmc_std_attr_group,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
|
@ -314,7 +314,7 @@ static struct attribute_group sd_std_attr_group = {
|
||||||
.attrs = sd_std_attrs,
|
.attrs = sd_std_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute_group *sd_attr_groups[] = {
|
static const struct attribute_group *sd_attr_groups[] = {
|
||||||
&sd_std_attr_group,
|
&sd_std_attr_group,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
|
@ -217,7 +217,7 @@ struct attribute_group mtd_group = {
|
||||||
.attrs = mtd_attrs,
|
.attrs = mtd_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct attribute_group *mtd_groups[] = {
|
const struct attribute_group *mtd_groups[] = {
|
||||||
&mtd_group,
|
&mtd_group,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,8 +24,8 @@ config IWM_DEBUG
|
||||||
To see the list of debug modules and levels, see iwm/debug.h
|
To see the list of debug modules and levels, see iwm/debug.h
|
||||||
|
|
||||||
For example, if you want the full MLME debug output:
|
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:
|
Or, if you want the full debug, for all modules:
|
||||||
echo 0xff > /debug/iwm/phyN/debug/level
|
echo 0xff > /sys/kernel/debug/iwm/phyN/debug/level
|
||||||
echo 0xff > /debug/iwm/phyN/debug/modules
|
echo 0xff > /sys/kernel/debug/iwm/phyN/debug/modules
|
||||||
|
|
|
@ -266,7 +266,7 @@ static struct attribute_group subch_attr_group = {
|
||||||
.attrs = subch_attrs,
|
.attrs = subch_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute_group *default_subch_attr_groups[] = {
|
static const struct attribute_group *default_subch_attr_groups[] = {
|
||||||
&subch_attr_group,
|
&subch_attr_group,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
|
@ -656,7 +656,7 @@ static struct attribute_group ccwdev_attr_group = {
|
||||||
.attrs = ccwdev_attrs,
|
.attrs = ccwdev_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute_group *ccwdev_attr_groups[] = {
|
static const struct attribute_group *ccwdev_attr_groups[] = {
|
||||||
&ccwdev_attr_group,
|
&ccwdev_attr_group,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
|
@ -2159,7 +2159,7 @@ static struct attribute_group netiucv_drv_attr_group = {
|
||||||
.attrs = netiucv_drv_attrs,
|
.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,
|
&netiucv_drv_attr_group,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
|
@ -132,7 +132,7 @@ extern struct scsi_transport_template blank_transport_template;
|
||||||
extern void __scsi_remove_device(struct scsi_device *);
|
extern void __scsi_remove_device(struct scsi_device *);
|
||||||
|
|
||||||
extern struct bus_type scsi_bus_type;
|
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 */
|
/* scsi_netlink.c */
|
||||||
#ifdef CONFIG_SCSI_NETLINK
|
#ifdef CONFIG_SCSI_NETLINK
|
||||||
|
|
|
@ -275,7 +275,7 @@ struct attribute_group scsi_shost_attr_group = {
|
||||||
.attrs = scsi_sysfs_shost_attrs,
|
.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,
|
&scsi_shost_attr_group,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
@ -745,7 +745,7 @@ static struct attribute_group scsi_sdev_attr_group = {
|
||||||
.attrs = scsi_sdev_attrs,
|
.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,
|
&scsi_sdev_attr_group,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
menuconfig UIO
|
menuconfig UIO
|
||||||
tristate "Userspace I/O drivers"
|
tristate "Userspace I/O drivers"
|
||||||
depends on !S390
|
depends on !S390
|
||||||
default n
|
|
||||||
help
|
help
|
||||||
Enable this to allow the userspace driver core code to be
|
Enable this to allow the userspace driver core code to be
|
||||||
built. This code allows userspace programs easy access to
|
built. This code allows userspace programs easy access to
|
||||||
|
@ -16,7 +15,6 @@ if UIO
|
||||||
config UIO_CIF
|
config UIO_CIF
|
||||||
tristate "generic Hilscher CIF Card driver"
|
tristate "generic Hilscher CIF Card driver"
|
||||||
depends on PCI
|
depends on PCI
|
||||||
default n
|
|
||||||
help
|
help
|
||||||
Driver for Hilscher CIF DeviceNet and Profibus cards. This
|
Driver for Hilscher CIF DeviceNet and Profibus cards. This
|
||||||
driver requires a userspace component that handles all of the
|
driver requires a userspace component that handles all of the
|
||||||
|
@ -48,7 +46,6 @@ config UIO_PDRV_GENIRQ
|
||||||
|
|
||||||
config UIO_SMX
|
config UIO_SMX
|
||||||
tristate "SMX cryptengine UIO interface"
|
tristate "SMX cryptengine UIO interface"
|
||||||
default n
|
|
||||||
help
|
help
|
||||||
Userspace IO interface to the Cryptography engine found on the
|
Userspace IO interface to the Cryptography engine found on the
|
||||||
Nias Digital SMX boards. These will be available from Q4 2008
|
Nias Digital SMX boards. These will be available from Q4 2008
|
||||||
|
@ -61,7 +58,6 @@ config UIO_SMX
|
||||||
config UIO_AEC
|
config UIO_AEC
|
||||||
tristate "AEC video timestamp device"
|
tristate "AEC video timestamp device"
|
||||||
depends on PCI
|
depends on PCI
|
||||||
default n
|
|
||||||
help
|
help
|
||||||
|
|
||||||
UIO driver for the Adrienne Electronics Corporation PCI time
|
UIO driver for the Adrienne Electronics Corporation PCI time
|
||||||
|
@ -78,7 +74,6 @@ config UIO_AEC
|
||||||
|
|
||||||
config UIO_SERCOS3
|
config UIO_SERCOS3
|
||||||
tristate "Automata Sercos III PCI card driver"
|
tristate "Automata Sercos III PCI card driver"
|
||||||
default n
|
|
||||||
help
|
help
|
||||||
Userspace I/O interface for the Sercos III PCI card from
|
Userspace I/O interface for the Sercos III PCI card from
|
||||||
Automata GmbH. The userspace part of this driver will be
|
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.
|
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
|
endif
|
||||||
|
|
|
@ -5,3 +5,4 @@ obj-$(CONFIG_UIO_PDRV_GENIRQ) += uio_pdrv_genirq.o
|
||||||
obj-$(CONFIG_UIO_SMX) += uio_smx.o
|
obj-$(CONFIG_UIO_SMX) += uio_smx.o
|
||||||
obj-$(CONFIG_UIO_AEC) += uio_aec.o
|
obj-$(CONFIG_UIO_AEC) += uio_aec.o
|
||||||
obj-$(CONFIG_UIO_SERCOS3) += uio_sercos3.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 = {
|
static struct attribute_group ep_dev_attr_grp = {
|
||||||
.attrs = ep_dev_attrs,
|
.attrs = ep_dev_attrs,
|
||||||
};
|
};
|
||||||
static struct attribute_group *ep_dev_groups[] = {
|
static const struct attribute_group *ep_dev_groups[] = {
|
||||||
&ep_dev_attr_grp,
|
&ep_dev_attr_grp,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
|
@ -573,7 +573,7 @@ static struct attribute_group dev_string_attr_grp = {
|
||||||
.is_visible = dev_string_attrs_are_visible,
|
.is_visible = dev_string_attrs_are_visible,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct attribute_group *usb_device_groups[] = {
|
const struct attribute_group *usb_device_groups[] = {
|
||||||
&dev_attr_grp,
|
&dev_attr_grp,
|
||||||
&dev_string_attr_grp,
|
&dev_string_attr_grp,
|
||||||
NULL
|
NULL
|
||||||
|
@ -799,7 +799,7 @@ static struct attribute_group intf_assoc_attr_grp = {
|
||||||
.is_visible = intf_assoc_attrs_are_visible,
|
.is_visible = intf_assoc_attrs_are_visible,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct attribute_group *usb_interface_groups[] = {
|
const struct attribute_group *usb_interface_groups[] = {
|
||||||
&intf_attr_grp,
|
&intf_attr_grp,
|
||||||
&intf_assoc_attr_grp,
|
&intf_assoc_attr_grp,
|
||||||
NULL
|
NULL
|
||||||
|
|
|
@ -152,8 +152,8 @@ static inline int is_active(const struct usb_interface *f)
|
||||||
extern const char *usbcore_name;
|
extern const char *usbcore_name;
|
||||||
|
|
||||||
/* sysfs stuff */
|
/* sysfs stuff */
|
||||||
extern struct attribute_group *usb_device_groups[];
|
extern const struct attribute_group *usb_device_groups[];
|
||||||
extern struct attribute_group *usb_interface_groups[];
|
extern const struct attribute_group *usb_interface_groups[];
|
||||||
|
|
||||||
/* usbfs stuff */
|
/* usbfs stuff */
|
||||||
extern struct mutex usbfs_mutex;
|
extern struct mutex usbfs_mutex;
|
||||||
|
|
|
@ -67,7 +67,7 @@ MODULE_PARM_DESC(ignore_oc, "ignore hardware overcurrent indications");
|
||||||
* debug = 0, no debugging messages
|
* debug = 0, no debugging messages
|
||||||
* debug = 1, dump failed URBs except for stalls
|
* debug = 1, dump failed URBs except for stalls
|
||||||
* debug = 2, dump all failed URBs (including 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
|
* debug = 3, show all TDs in URBs when dumping
|
||||||
*/
|
*/
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
|
@ -255,7 +255,7 @@ static struct attribute_group dev_attr_group = {
|
||||||
.attrs = dev_attrs,
|
.attrs = dev_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute_group *groups[] = {
|
static const struct attribute_group *groups[] = {
|
||||||
&dev_attr_group,
|
&dev_attr_group,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
|
@ -312,7 +312,7 @@ static struct attribute_group part_attr_group = {
|
||||||
.attrs = part_attrs,
|
.attrs = part_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute_group *part_attr_groups[] = {
|
static const struct attribute_group *part_attr_groups[] = {
|
||||||
&part_attr_group,
|
&part_attr_group,
|
||||||
#ifdef CONFIG_BLK_DEV_IO_TRACE
|
#ifdef CONFIG_BLK_DEV_IO_TRACE
|
||||||
&blk_trace_attr_group,
|
&blk_trace_attr_group,
|
||||||
|
|
|
@ -17,7 +17,7 @@ struct attribute_container {
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
struct klist containers;
|
struct klist containers;
|
||||||
struct class *class;
|
struct class *class;
|
||||||
struct attribute_group *grp;
|
const struct attribute_group *grp;
|
||||||
struct device_attribute **attrs;
|
struct device_attribute **attrs;
|
||||||
int (*match)(struct attribute_container *, struct device *);
|
int (*match)(struct attribute_container *, struct device *);
|
||||||
#define ATTRIBUTE_CONTAINER_NO_CLASSDEVS 0x01
|
#define ATTRIBUTE_CONTAINER_NO_CLASSDEVS 0x01
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
* device.h - generic, centralized driver model
|
* device.h - generic, centralized driver model
|
||||||
*
|
*
|
||||||
* Copyright (c) 2001-2003 Patrick Mochel <mochel@osdl.org>
|
* 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
|
* This file is released under the GPLv2
|
||||||
*
|
*
|
||||||
|
@ -130,7 +131,7 @@ struct device_driver {
|
||||||
void (*shutdown) (struct device *dev);
|
void (*shutdown) (struct device *dev);
|
||||||
int (*suspend) (struct device *dev, pm_message_t state);
|
int (*suspend) (struct device *dev, pm_message_t state);
|
||||||
int (*resume) (struct device *dev);
|
int (*resume) (struct device *dev);
|
||||||
struct attribute_group **groups;
|
const struct attribute_group **groups;
|
||||||
|
|
||||||
const struct dev_pm_ops *pm;
|
const struct dev_pm_ops *pm;
|
||||||
|
|
||||||
|
@ -224,6 +225,14 @@ extern void class_unregister(struct class *class);
|
||||||
__class_register(class, &__key); \
|
__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,
|
extern void class_dev_iter_init(struct class_dev_iter *iter,
|
||||||
struct class *class,
|
struct class *class,
|
||||||
struct device *start,
|
struct device *start,
|
||||||
|
@ -287,7 +296,7 @@ extern void class_destroy(struct class *cls);
|
||||||
*/
|
*/
|
||||||
struct device_type {
|
struct device_type {
|
||||||
const char *name;
|
const char *name;
|
||||||
struct attribute_group **groups;
|
const struct attribute_group **groups;
|
||||||
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
|
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
|
||||||
char *(*nodename)(struct device *dev);
|
char *(*nodename)(struct device *dev);
|
||||||
void (*release)(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 bus_type *bus; /* type of bus device is on */
|
||||||
struct device_driver *driver; /* which driver has allocated this
|
struct device_driver *driver; /* which driver has allocated this
|
||||||
device */
|
device */
|
||||||
void *driver_data; /* data private to the driver */
|
|
||||||
void *platform_data; /* Platform specific data, device
|
void *platform_data; /* Platform specific data, device
|
||||||
core doesn't touch it */
|
core doesn't touch it */
|
||||||
struct dev_pm_info power;
|
struct dev_pm_info power;
|
||||||
|
@ -412,7 +420,7 @@ struct device {
|
||||||
|
|
||||||
struct klist_node knode_class;
|
struct klist_node knode_class;
|
||||||
struct class *class;
|
struct class *class;
|
||||||
struct attribute_group **groups; /* optional groups */
|
const struct attribute_group **groups; /* optional groups */
|
||||||
|
|
||||||
void (*release)(struct device *dev);
|
void (*release)(struct device *dev);
|
||||||
};
|
};
|
||||||
|
@ -447,16 +455,6 @@ static inline void set_dev_node(struct device *dev, int node)
|
||||||
}
|
}
|
||||||
#endif
|
#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)
|
static inline unsigned int dev_get_uevent_suppress(const struct device *dev)
|
||||||
{
|
{
|
||||||
return dev->kobj.uevent_suppress;
|
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,
|
extern int device_move(struct device *dev, struct device *new_parent,
|
||||||
enum dpm_order dpm_order);
|
enum dpm_order dpm_order);
|
||||||
extern const char *device_get_nodename(struct device *dev, const char **tmp);
|
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
|
* 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);
|
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
|
* Manual binding of a device to driver. See drivers/base/bus.c
|
||||||
* for information on use.
|
* for information on use.
|
||||||
|
@ -547,6 +552,16 @@ extern void put_device(struct device *dev);
|
||||||
|
|
||||||
extern void wait_for_device_probe(void);
|
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 */
|
/* drivers/base/power/shutdown.c */
|
||||||
extern void device_shutdown(void);
|
extern void device_shutdown(void);
|
||||||
|
|
||||||
|
|
|
@ -895,7 +895,7 @@ struct net_device
|
||||||
/* class/net/name entry */
|
/* class/net/name entry */
|
||||||
struct device dev;
|
struct device dev;
|
||||||
/* space for optional statistics and wireless sysfs groups */
|
/* space for optional statistics and wireless sysfs groups */
|
||||||
struct attribute_group *sysfs_groups[3];
|
const struct attribute_group *sysfs_groups[3];
|
||||||
|
|
||||||
/* rtnetlink link ops */
|
/* rtnetlink link ops */
|
||||||
const struct rtnl_link_ops *rtnl_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_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */
|
||||||
|
|
||||||
#define PCI_STATUS 0x06 /* 16 bits */
|
#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_CAP_LIST 0x10 /* Support Capability List */
|
||||||
#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */
|
#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */
|
||||||
#define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */
|
#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);
|
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
|
#ifdef CONFIG_TMPFS_POSIX_ACL
|
||||||
int shmem_check_acl(struct inode *, int);
|
int shmem_check_acl(struct inode *, int);
|
||||||
int shmem_acl_init(struct inode *, struct inode *);
|
int shmem_acl_init(struct inode *, struct inode *);
|
||||||
|
|
|
@ -55,7 +55,7 @@ struct anon_transport_class cls = { \
|
||||||
|
|
||||||
struct transport_container {
|
struct transport_container {
|
||||||
struct attribute_container ac;
|
struct attribute_container ac;
|
||||||
struct attribute_group *statistics;
|
const struct attribute_group *statistics;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define attribute_container_to_transport_container(x) \
|
#define attribute_container_to_transport_container(x) \
|
||||||
|
|
|
@ -415,7 +415,7 @@ void __init prepare_namespace(void)
|
||||||
|
|
||||||
mount_root();
|
mount_root();
|
||||||
out:
|
out:
|
||||||
|
devtmpfs_mount("dev");
|
||||||
sys_mount(".", "/", NULL, MS_MOVE, NULL);
|
sys_mount(".", "/", NULL, MS_MOVE, NULL);
|
||||||
sys_chroot(".");
|
sys_chroot(".");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,7 @@
|
||||||
#include <linux/async.h>
|
#include <linux/async.h>
|
||||||
#include <linux/kmemcheck.h>
|
#include <linux/kmemcheck.h>
|
||||||
#include <linux/kmemtrace.h>
|
#include <linux/kmemtrace.h>
|
||||||
|
#include <linux/shmem_fs.h>
|
||||||
#include <trace/boot.h>
|
#include <trace/boot.h>
|
||||||
|
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
|
@ -785,6 +786,7 @@ static void __init do_basic_setup(void)
|
||||||
init_workqueues();
|
init_workqueues();
|
||||||
cpuset_init_smp();
|
cpuset_init_smp();
|
||||||
usermodehelper_init();
|
usermodehelper_init();
|
||||||
|
init_tmpfs();
|
||||||
driver_init();
|
driver_init();
|
||||||
init_irq_proc();
|
init_irq_proc();
|
||||||
do_ctors();
|
do_ctors();
|
||||||
|
|
|
@ -90,7 +90,6 @@ obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o
|
||||||
obj-$(CONFIG_MARKERS) += marker.o
|
obj-$(CONFIG_MARKERS) += marker.o
|
||||||
obj-$(CONFIG_TRACEPOINTS) += tracepoint.o
|
obj-$(CONFIG_TRACEPOINTS) += tracepoint.o
|
||||||
obj-$(CONFIG_LATENCYTOP) += latencytop.o
|
obj-$(CONFIG_LATENCYTOP) += latencytop.o
|
||||||
obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o
|
|
||||||
obj-$(CONFIG_FUNCTION_TRACER) += trace/
|
obj-$(CONFIG_FUNCTION_TRACER) += trace/
|
||||||
obj-$(CONFIG_TRACING) += trace/
|
obj-$(CONFIG_TRACING) += trace/
|
||||||
obj-$(CONFIG_X86_DS) += trace/
|
obj-$(CONFIG_X86_DS) += trace/
|
||||||
|
|
|
@ -2298,8 +2298,7 @@ static void shmem_put_super(struct super_block *sb)
|
||||||
sb->s_fs_info = NULL;
|
sb->s_fs_info = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int shmem_fill_super(struct super_block *sb,
|
int shmem_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
void *data, int silent)
|
|
||||||
{
|
{
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
struct dentry *root;
|
struct dentry *root;
|
||||||
|
@ -2519,7 +2518,7 @@ static struct file_system_type tmpfs_fs_type = {
|
||||||
.kill_sb = kill_litter_super,
|
.kill_sb = kill_litter_super,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init init_tmpfs(void)
|
int __init init_tmpfs(void)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
@ -2576,7 +2575,7 @@ static struct file_system_type tmpfs_fs_type = {
|
||||||
.kill_sb = kill_litter_super,
|
.kill_sb = kill_litter_super,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init init_tmpfs(void)
|
int __init init_tmpfs(void)
|
||||||
{
|
{
|
||||||
BUG_ON(register_filesystem(&tmpfs_fs_type) != 0);
|
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;
|
vma->vm_ops = &shmem_vm_ops;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(init_tmpfs)
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ static struct attribute_group bt_link_group = {
|
||||||
.attrs = bt_link_attrs,
|
.attrs = bt_link_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute_group *bt_link_groups[] = {
|
static const struct attribute_group *bt_link_groups[] = {
|
||||||
&bt_link_group,
|
&bt_link_group,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
@ -392,7 +392,7 @@ static struct attribute_group bt_host_group = {
|
||||||
.attrs = bt_host_attrs,
|
.attrs = bt_host_attrs,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct attribute_group *bt_host_groups[] = {
|
static const struct attribute_group *bt_host_groups[] = {
|
||||||
&bt_host_group,
|
&bt_host_group,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
|
@ -493,7 +493,7 @@ void netdev_unregister_kobject(struct net_device * net)
|
||||||
int netdev_register_kobject(struct net_device *net)
|
int netdev_register_kobject(struct net_device *net)
|
||||||
{
|
{
|
||||||
struct device *dev = &(net->dev);
|
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->class = &net_class;
|
||||||
dev->platform_data = net;
|
dev->platform_data = net;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* If TRACE_SYSTEM is defined, that will be the directory created
|
* 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
|
* The define_trace.h below will also look for a file name of
|
||||||
* TRACE_SYSTEM.h where TRACE_SYSTEM is what is defined here.
|
* TRACE_SYSTEM.h where TRACE_SYSTEM is what is defined here.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue