Commit 189ea5d0 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/davem/net-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 3ed5a695 a21dffe4
request_firmware() hotplug interface:
------------------------------------
Copyright (C) 2003 Manuel Estrada Sainz <ranty@debian.org>
Why:
---
Today, the most extended way to use firmware in the Linux kernel is linking
it statically in a header file. Which has political and technical issues:
1) Some firmware is not legal to redistribute.
2) The firmware occupies memory permanently, even though it often is just
used once.
3) Some people, like the Debian crowd, don't consider some firmware free
enough and remove entire drivers (e.g.: keyspan).
about in-kernel persistence:
---------------------------
Under some circumstances, as explained below, it would be interesting to keep
firmware images in non-swappable kernel memory or even in the kernel image
(probably within initramfs).
Note that this functionality has not been implemented.
- Why OPTIONAL in-kernel persistence may be a good idea sometimes:
- If the device that needs the firmware is needed to access the
filesystem. When upon some error the device has to be reset and the
firmware reloaded, it won't be possible to get it from userspace.
e.g.:
- A diskless client with a network card that needs firmware.
- The filesystem is stored in a disk behind an scsi device
that needs firmware.
- Replacing buggy DSDT/SSDT ACPI tables on boot.
Note: this would require the persistent objects to be included
within the kernel image, probably within initramfs.
And the same device can be needed to access the filesystem or not depending
on the setup, so I think that the choice on what firmware to make
persistent should be left to userspace.
- Why register_firmware()+__init can be useful:
- For boot devices needing firmware.
- To make the transition easier:
The firmware can be declared __init and register_firmware()
called on module_init. Then the firmware is warranted to be
there even if "firmware hotplug userspace" is not there yet or
it doesn't yet provide the needed firmware.
Once the firmware is widely available in userspace, it can be
removed from the kernel. Or made optional (CONFIG_.*_FIRMWARE).
In either case, if firmware hotplug support is there, it can move the
firmware out of kernel memory into the real filesystem for later
usage.
Note: If persistence is implemented on top of initramfs,
register_firmware() may not be appropriate.
/*
* firmware_sample_driver.c -
*
* Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org>
*
* Sample code on how to use request_firmware() from drivers.
*
* Note that register_firmware() is currently useless.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/device.h>
#include "linux/firmware.h"
#define WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE
#ifdef WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE
char __init inkernel_firmware[] = "let's say that this is firmware\n";
#endif
static struct device ghost_device = {
.name = "Ghost Device",
.bus_id = "ghost0",
};
static void sample_firmware_load(char *firmware, int size)
{
u8 buf[size+1];
memcpy(buf, firmware, size);
buf[size] = '\0';
printk("firmware_sample_driver: firmware: %s\n", buf);
}
static void sample_probe_default(void)
{
/* uses the default method to get the firmware */
const struct firmware *fw_entry;
printk("firmware_sample_driver: a ghost device got inserted :)\n");
if(request_firmware(&fw_entry, "sample_driver_fw", &ghost_device)!=0)
{
printk(KERN_ERR
"firmware_sample_driver: Firmware not available\n");
return;
}
sample_firmware_load(fw_entry->data, fw_entry->size);
release_firmware(fw_entry);
/* finish setting up the device */
}
static void sample_probe_specific(void)
{
/* Uses some specific hotplug support to get the firmware from
* userspace directly into the hardware, or via some sysfs file */
/* NOTE: This currently doesn't work */
printk("firmware_sample_driver: a ghost device got inserted :)\n");
if(request_firmware(NULL, "sample_driver_fw", &ghost_device)!=0)
{
printk(KERN_ERR
"firmware_sample_driver: Firmware load failed\n");
return;
}
/* request_firmware blocks until userspace finished, so at
* this point the firmware should be already in the device */
/* finish setting up the device */
}
static void sample_probe_async_cont(const struct firmware *fw, void *context)
{
if(!fw){
printk(KERN_ERR
"firmware_sample_driver: firmware load failed\n");
return;
}
printk("firmware_sample_driver: device pointer \"%s\"\n",
(char *)context);
sample_firmware_load(fw->data, fw->size);
}
static void sample_probe_async(void)
{
/* Let's say that I can't sleep */
int error;
error = request_firmware_nowait (THIS_MODULE,
"sample_driver_fw", &ghost_device,
"my device pointer",
sample_probe_async_cont);
if(error){
printk(KERN_ERR
"firmware_sample_driver:"
" request_firmware_nowait failed\n");
}
}
static int sample_init(void)
{
#ifdef WE_CAN_NEED_FIRMWARE_BEFORE_USERSPACE_IS_AVAILABLE
register_firmware("sample_driver_fw", inkernel_firmware,
sizeof(inkernel_firmware));
#endif
device_initialize(&ghost_device);
/* since there is no real hardware insertion I just call the
* sample probe functions here */
sample_probe_specific();
sample_probe_default();
sample_probe_async();
return 0;
}
static void __exit sample_exit(void)
{
}
module_init (sample_init);
module_exit (sample_exit);
MODULE_LICENSE("GPL");
/*
* firmware_sample_firmware_class.c -
*
* Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org>
*
* NOTE: This is just a probe of concept, if you think that your driver would
* be well served by this mechanism please contact me first.
*
* DON'T USE THIS CODE AS IS
*
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <asm/hardirq.h>
#include "linux/firmware.h"
MODULE_AUTHOR("Manuel Estrada Sainz <ranty@debian.org>");
MODULE_DESCRIPTION("Hackish sample for using firmware class directly");
MODULE_LICENSE("GPL");
static inline struct class_device *to_class_dev(struct kobject *obj)
{
return container_of(obj,struct class_device,kobj);
}
static inline
struct class_device_attribute *to_class_dev_attr(struct attribute *_attr)
{
return container_of(_attr,struct class_device_attribute,attr);
}
int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr);
int sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr);
struct firmware_priv {
char fw_id[FIRMWARE_NAME_MAX];
s32 loading:2;
u32 abort:1;
};
extern struct class firmware_class;
static ssize_t firmware_loading_show(struct class_device *class_dev, char *buf)
{
struct firmware_priv *fw_priv = class_get_devdata(class_dev);
return sprintf(buf, "%d\n", fw_priv->loading);
}
static ssize_t firmware_loading_store(struct class_device *class_dev,
const char *buf, size_t count)
{
struct firmware_priv *fw_priv = class_get_devdata(class_dev);
int prev_loading = fw_priv->loading;
fw_priv->loading = simple_strtol(buf, NULL, 10);
switch(fw_priv->loading){
case -1:
/* abort load an panic */
break;
case 1:
/* setup load */
break;
case 0:
if(prev_loading==1){
/* finish load and get the device back to working
* state */
}
break;
}
return count;
}
static CLASS_DEVICE_ATTR(loading, 0644,
firmware_loading_show, firmware_loading_store);
static ssize_t firmware_data_read(struct kobject *kobj,
char *buffer, loff_t offset, size_t count)
{
struct class_device *class_dev = to_class_dev(kobj);
struct firmware_priv *fw_priv = class_get_devdata(class_dev);
/* read from the devices firmware memory */
return count;
}
static ssize_t firmware_data_write(struct kobject *kobj,
char *buffer, loff_t offset, size_t count)
{
struct class_device *class_dev = to_class_dev(kobj);
struct firmware_priv *fw_priv = class_get_devdata(class_dev);
/* write to the devices firmware memory */
return count;
}
static struct bin_attribute firmware_attr_data = {
.attr = {.name = "data", .mode = 0644},
.size = 0,
.read = firmware_data_read,
.write = firmware_data_write,
};
static int fw_setup_class_device(struct class_device *class_dev,
const char *fw_name,
struct device *device)
{
int retval = 0;
struct firmware_priv *fw_priv = kmalloc(sizeof(struct firmware_priv),
GFP_KERNEL);
if(!fw_priv){
retval = -ENOMEM;
goto out;
}
memset(fw_priv, 0, sizeof(*fw_priv));
memset(class_dev, 0, sizeof(*class_dev));
strncpy(fw_priv->fw_id, fw_name, FIRMWARE_NAME_MAX);
fw_priv->fw_id[FIRMWARE_NAME_MAX-1] = '\0';
strncpy(class_dev->class_id, device->bus_id, BUS_ID_SIZE);
class_dev->class_id[BUS_ID_SIZE-1] = '\0';
class_dev->dev = device;
class_dev->class = &firmware_class,
class_set_devdata(class_dev, fw_priv);
retval = class_device_register(class_dev);
if (retval){
printk(KERN_ERR "%s: class_device_register failed\n",
__FUNCTION__);
goto error_free_fw_priv;
}
retval = sysfs_create_bin_file(&class_dev->kobj, &firmware_attr_data);
if (retval){
printk(KERN_ERR "%s: sysfs_create_bin_file failed\n",
__FUNCTION__);
goto error_unreg_class_dev;
}
retval = class_device_create_file(class_dev,
&class_device_attr_loading);
if (retval){
printk(KERN_ERR "%s: class_device_create_file failed\n",
__FUNCTION__);
goto error_remove_data;
}
goto out;
error_remove_data:
sysfs_remove_bin_file(&class_dev->kobj, &firmware_attr_data);
error_unreg_class_dev:
class_device_unregister(class_dev);
error_free_fw_priv:
kfree(fw_priv);
out:
return retval;
}
static void fw_remove_class_device(struct class_device *class_dev)
{
struct firmware_priv *fw_priv = class_get_devdata(class_dev);
class_device_remove_file(class_dev, &class_device_attr_loading);
sysfs_remove_bin_file(&class_dev->kobj, &firmware_attr_data);
class_device_unregister(class_dev);
}
static struct class_device *class_dev;
static struct device my_device = {
.name = "Sample Device",
.bus_id = "my_dev0",
};
static int __init firmware_sample_init(void)
{
int error;
device_initialize(&my_device);
class_dev = kmalloc(sizeof(struct class_device), GFP_KERNEL);
if(!class_dev)
return -ENOMEM;
error = fw_setup_class_device(class_dev, "my_firmware_image",
&my_device);
if(error){
kfree(class_dev);
return error;
}
return 0;
}
static void __exit firmware_sample_exit(void)
{
struct firmware_priv *fw_priv = class_get_devdata(class_dev);
fw_remove_class_device(class_dev);
kfree(fw_priv);
kfree(class_dev);
}
module_init(firmware_sample_init);
module_exit(firmware_sample_exit);
#!/bin/sh
# Simple hotplug script sample:
#
# Both $DEVPATH and $FIRMWARE are already provided in the environment.
HOTPLUG_FW_DIR=/usr/lib/hotplug/firmware/
echo 1 > /sysfs/$DEVPATH/loading
cat $HOTPLUG_FW_DIR/$FIRMWARE > /sysfs/$DEVPATH/data
echo 0 > /sysfs/$DEVPATH/loading
# To cancel the load in case of error:
#
# echo -1 > /sysfs/$DEVPATH/loading
#
......@@ -5,15 +5,8 @@ Patrick Mochel <mochel@osdl.org>
Updated: 3 June 2003
Copyright (c) Patrick Mochel
Copyright (c) Open Source Development Labs
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.2
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled "GNU
Free Documentation License".
Copyright (c) 2003 Patrick Mochel
Copyright (c) 2003 Open Source Development Labs
0. Introduction
......
......@@ -653,6 +653,8 @@ source "drivers/parport/Kconfig"
endmenu
source "drivers/base/Kconfig"
source "drivers/mtd/Kconfig"
source "drivers/pnp/Kconfig"
......
......@@ -156,7 +156,7 @@ EXPORT_SYMBOL(sys_exit);
EXPORT_SYMBOL(sys_write);
EXPORT_SYMBOL(sys_read);
EXPORT_SYMBOL(sys_lseek);
EXPORT_SYMBOL(__kernel_execve);
EXPORT_SYMBOL(execve);
EXPORT_SYMBOL(sys_setsid);
EXPORT_SYMBOL(sys_wait4);
......
......@@ -606,7 +606,8 @@ ret_from_fork:
.globl kernel_thread
.ent kernel_thread
kernel_thread:
ldgp $gp, 0($27) /* we can be called from a module */
/* We can be called from a module. */
ldgp $gp, 0($27)
.prologue 1
subq $sp, SP_OFF+6*8, $sp
br $1, 2f /* load start address */
......@@ -654,26 +655,56 @@ kernel_thread:
.end kernel_thread
/*
* __kernel_execve(path, argv, envp, regs)
* execve(path, argv, envp)
*/
.align 4
.globl __kernel_execve
.ent __kernel_execve
__kernel_execve:
ldgp $gp, 0($27) /* we can be called from modules. */
subq $sp, 16, $sp
.frame $sp, 16, $26, 0
.globl execve
.ent execve
execve:
/* We can be called from a module. */
ldgp $gp, 0($27)
lda $sp, -(32+SIZEOF_PT_REGS+8)($sp)
.frame $sp, 32+SIZEOF_PT_REGS+8, $26, 0
stq $26, 0($sp)
stq $19, 8($sp)
stq $16, 8($sp)
stq $17, 16($sp)
stq $18, 24($sp)
.prologue 1
jsr $26, do_execve
bne $0, 1f /* error! */
ldq $sp, 8($sp)
lda $16, 32($sp)
lda $17, 0
lda $18, SIZEOF_PT_REGS
bsr $26, memset !samegp
/* Avoid the HAE being gratuitously wrong, which would cause us
to do the whole turn off interrupts thing and restore it. */
ldq $2, alpha_mv+HAE_CACHE
stq $2, 152+32($sp)
ldq $16, 8($sp)
ldq $17, 16($sp)
ldq $18, 24($sp)
lda $19, 32($sp)
bsr $26, do_execve !samegp
ldq $26, 0($sp)
bne $0, 1f /* error! */
/* Move the temporary pt_regs struct from its current location
to the top of the kernel stack frame. See copy_thread for
details for a normal process. */
lda $16, 0x4000 - SIZEOF_PT_REGS($8)
lda $17, 32($sp)
lda $18, SIZEOF_PT_REGS
bsr $26, memmove !samegp
/* Take that over as our new stack frame and visit userland! */
lda $sp, 0x4000 - SIZEOF_PT_REGS($8)
br $31, ret_from_sys_call
1: ldq $26, 0($sp)
addq $sp, 16, $sp
1: lda $sp, 32+SIZEOF_PT_REGS+8($sp)
ret
.end __kernel_execve
.end execve
/*
......
......@@ -291,6 +291,7 @@ srmcons_init(void)
driver->type = TTY_DRIVER_TYPE_SYSTEM;
driver->subtype = SYSTEM_TYPE_SYSCONS;
driver->init_termios = tty_std_termios;
tty_set_operations(driver, &srmcons_ops);
err = tty_register_driver(driver);
if (err) {
put_tty_driver(driver);
......
......@@ -15,15 +15,23 @@
.globl bcopy
.ent bcopy
bcopy:
ldgp $29, 0($27)
.prologue 1
mov $16,$0
mov $17,$16
mov $0,$17
br $31, memmove !samegp
.end bcopy
.align 4
.globl memmove
.ent memmove
memmove:
ldgp $29, 0($27)
unop
nop
.prologue 1
addq $16,$18,$4
addq $17,$18,$5
cmpule $4,$17,$1 /* dest + n <= src */
......@@ -32,7 +40,7 @@ memmove:
bis $1,$2,$1
mov $16,$0
xor $16,$17,$2
bne $1,memcpy
bne $1,memcpy !samegp
and $2,7,$2 /* Test for src/dest co-alignment. */
and $16,7,$1
......
......@@ -188,7 +188,7 @@ oprofile_arch_init(struct oprofile_operations **ops)
}
void __exit
void
oprofile_arch_exit(void)
{
}
......@@ -703,6 +703,8 @@ endchoice
source "fs/Kconfig.binfmt"
source "drivers/base/Kconfig"
config PM
bool "Power Management support"
---help---
......
......@@ -297,6 +297,8 @@ config CMDLINE
endmenu
source "drivers/base/Kconfig"
source "drivers/parport/Kconfig"
source "drivers/pnp/Kconfig"
......
......@@ -515,6 +515,8 @@ config ETRAX_POWERBUTTON_BIT
endmenu
source "drivers/base/Kconfig"
# bring in Etrax built-in drivers
source "arch/cris/drivers/Kconfig"
......
......@@ -145,6 +145,8 @@ source "fs/Kconfig.binfmt"
endmenu
source "drivers/base/Kconfig"
source "drivers/block/Kconfig"
source "drivers/ide/Kconfig"
......
......@@ -1194,6 +1194,8 @@ source "fs/Kconfig.binfmt"
endmenu
source "drivers/base/Kconfig"
source "drivers/mtd/Kconfig"
source "drivers/parport/Kconfig"
......
......@@ -281,19 +281,19 @@ unsigned long get_cmos_time(void)
return retval;
}
static struct sysdev_class rtc_sysclass = {
set_kset_name("rtc"),
static struct sysdev_class pit_sysclass = {
set_kset_name("pit"),
};
/* XXX this driverfs stuff should probably go elsewhere later -john */
static struct sys_device device_i8253 = {
.id = 0,
.cls = &rtc_sysclass,
.id = 0,
.cls = &pit_sysclass,
};
static int time_init_device(void)
{
int error = sysdev_class_register(&rtc_sysclass);
int error = sysdev_class_register(&pit_sysclass);
if (!error)
error = sys_device_register(&device_i8253);
return error;
......
......@@ -534,6 +534,8 @@ endif
endmenu
source "drivers/base/Kconfig"
if !IA64_HP_SIM
source "drivers/mtd/Kconfig"
......
......@@ -573,6 +573,8 @@ endif
endmenu
source "drivers/base/Kconfig"
source "drivers/mtd/Kconfig"
source "drivers/block/Kconfig"
......
......@@ -515,6 +515,8 @@ config PM
endmenu
source "drivers/base/Kconfig"
source "drivers/mtd/Kconfig"
source "drivers/parport/Kconfig"
......
......@@ -744,6 +744,8 @@ if ISA
source "drivers/pnp/Kconfig"
endif
source "drivers/base/Kconfig"
source "drivers/mtd/Kconfig"
source "drivers/parport/Kconfig"
......
......@@ -361,6 +361,8 @@ endmenu
source "drivers/pci/Kconfig"
source "drivers/base/Kconfig"
source "drivers/mtd/Kconfig"
source "drivers/parport/Kconfig"
......
......@@ -170,6 +170,8 @@ source "fs/Kconfig.binfmt"
endmenu
source "drivers/base/Kconfig"
# source "drivers/mtd/Kconfig"
source "drivers/parport/Kconfig"
......
......@@ -1163,6 +1163,8 @@ config PIN_TLB
depends on ADVANCED_OPTIONS && 8xx
endmenu
source "drivers/base/Kconfig"
source "drivers/mtd/Kconfig"
source "drivers/pnp/Kconfig"
......
......@@ -241,6 +241,8 @@ config CMDLINE
endmenu
source "drivers/base/Kconfig"
source "drivers/mtd/Kconfig"
source "drivers/parport/Kconfig"
......
......@@ -229,6 +229,8 @@ config PCMCIA
bool
default n
source "drivers/base/Kconfig"
menu "SCSI support"
config SCSI
......
......@@ -767,6 +767,8 @@ source "fs/Kconfig.binfmt"
endmenu
source "drivers/base/Kconfig"
source "drivers/mtd/Kconfig"
source "drivers/parport/Kconfig"
......
......@@ -319,6 +319,8 @@ config PRINTER
endmenu
source "drivers/base/Kconfig"
source "drivers/video/Kconfig"
source "drivers/mtd/Kconfig"
......
......@@ -521,6 +521,8 @@ config WATCHDOG_RIO
endmenu
source "drivers/base/Kconfig"
source "drivers/video/Kconfig"
source "drivers/serial/Kconfig"
......
......@@ -171,6 +171,8 @@ endmenu
source "init/Kconfig"
source "drivers/base/Kconfig"
source "arch/um/Kconfig_char"
source "arch/um/Kconfig_block"
......
......@@ -249,6 +249,8 @@ endmenu
#############################################################################
source "drivers/base/Kconfig"
source drivers/mtd/Kconfig
source drivers/parport/Kconfig
......
......@@ -397,6 +397,8 @@ config UID16
endmenu
source "drivers/base/Kconfig"
source "drivers/mtd/Kconfig"
source "drivers/parport/Kconfig"
......
menu "Generic Driver Options"
config FW_LOADER
tristate "Hotplug firmware loading support"
---help---
This option is provided for the case where no in-kernel-tree modules
require hotplug firmware loading support, but a module built outside
the kernel tree does.
endmenu
......@@ -3,4 +3,5 @@
obj-y := core.o sys.o interface.o power.o bus.o \
driver.o class.o platform.o \
cpu.o firmware.o init.o map.o
obj-$(CONFIG_FW_LOADER) += firmware_class.o
obj-$(CONFIG_NUMA) += node.o memblk.o
/*
* firmware_class.c - Multi purpose firmware loading support
*
* Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org>
*
* Please see Documentation/firmware_class/ for more information.
*
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/vmalloc.h>
#include <asm/hardirq.h>
#include <linux/firmware.h>
#include "base.h"
MODULE_AUTHOR("Manuel Estrada Sainz <ranty@debian.org>");
MODULE_DESCRIPTION("Multi purpose firmware loading support");
MODULE_LICENSE("GPL");
static int loading_timeout = 10; /* In seconds */
struct firmware_priv {
char fw_id[FIRMWARE_NAME_MAX];
struct completion completion;
struct bin_attribute attr_data;
struct firmware *fw;
int loading;
int abort;
int alloc_size;
struct timer_list timeout;
};
static ssize_t
firmware_timeout_show(struct class *class, char *buf)
{
return sprintf(buf, "%d\n", loading_timeout);
}
/**
* firmware_timeout_store:
* Description:
* Sets the number of seconds to wait for the firmware. Once
* this expires an error will be return to the driver and no
* firmware will be provided.
*
* Note: zero means 'wait for ever'
*
**/
static ssize_t
firmware_timeout_store(struct class *class, const char *buf, size_t count)
{
loading_timeout = simple_strtol(buf, NULL, 10);
return count;
}
static CLASS_ATTR(timeout, 0644, firmware_timeout_show, firmware_timeout_store);
static void fw_class_dev_release(struct class_device *class_dev);
int firmware_class_hotplug(struct class_device *dev, char **envp,
int num_envp, char *buffer, int buffer_size);
static struct class firmware_class = {
.name = "firmware",
.hotplug = firmware_class_hotplug,
.release = fw_class_dev_release,
};
int
firmware_class_hotplug(struct class_device *class_dev, char **envp,
int num_envp, char *buffer, int buffer_size)
{
struct firmware_priv *fw_priv = class_get_devdata(class_dev);
int i = 0;
char *scratch = buffer;
if (buffer_size < (FIRMWARE_NAME_MAX + 10))
return -ENOMEM;
if (num_envp < 1)
return -ENOMEM;
envp[i++] = scratch;
scratch += sprintf(scratch, "FIRMWARE=%s", fw_priv->fw_id) + 1;
return 0;
}
static ssize_t
firmware_loading_show(struct class_device *class_dev, char *buf)
{
struct firmware_priv *fw_priv = class_get_devdata(class_dev);
return sprintf(buf, "%d\n", fw_priv->loading);
}
/**
* firmware_loading_store: - loading control file
* Description:
* The relevant values are:
*
* 1: Start a load, discarding any previous partial load.
* 0: Conclude the load and handle the data to the driver code.
* -1: Conclude the load with an error and discard any written data.
**/
static ssize_t
firmware_loading_store(struct class_device *class_dev,
const char *buf, size_t count)
{
struct firmware_priv *fw_priv = class_get_devdata(class_dev);
int prev_loading = fw_priv->loading;
fw_priv->loading = simple_strtol(buf, NULL, 10);
switch (fw_priv->loading) {
case -1:
fw_priv->abort = 1;
wmb();
complete(&fw_priv->completion);
break;
case 1:
kfree(fw_priv->fw->data);
fw_priv->fw->data = NULL;
fw_priv->fw->size = 0;
fw_priv->alloc_size = 0;
break;
case 0:
if (prev_loading == 1)
complete(&fw_priv->completion);
break;
}
return count;
}
static CLASS_DEVICE_ATTR(loading, 0644,
firmware_loading_show, firmware_loading_store);
static ssize_t
firmware_data_read(struct kobject *kobj,
char *buffer, loff_t offset, size_t count)
{
struct class_device *class_dev = to_class_dev(kobj);
struct firmware_priv *fw_priv = class_get_devdata(class_dev);
struct firmware *fw = fw_priv->fw;
if (offset > fw->size)
return 0;
if (offset + count > fw->size)
count = fw->size - offset;
memcpy(buffer, fw->data + offset, count);
return count;
}
static int
fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
{
u8 *new_data;
if (min_size <= fw_priv->alloc_size)
return 0;
new_data = vmalloc(fw_priv->alloc_size + PAGE_SIZE);
if (!new_data) {
printk(KERN_ERR "%s: unable to alloc buffer\n", __FUNCTION__);
/* Make sure that we don't keep incomplete data */
fw_priv->abort = 1;
return -ENOMEM;
}
fw_priv->alloc_size += PAGE_SIZE;
if (fw_priv->fw->data) {
memcpy(new_data, fw_priv->fw->data, fw_priv->fw->size);
vfree(fw_priv->fw->data);
}
fw_priv->fw->data = new_data;
BUG_ON(min_size > fw_priv->alloc_size);
return 0;
}
/**
* firmware_data_write:
*
* Description:
*
* Data written to the 'data' attribute will be later handled to
* the driver as a firmware image.
**/
static ssize_t
firmware_data_write(struct kobject *kobj,
char *buffer, loff_t offset, size_t count)
{
struct class_device *class_dev = to_class_dev(kobj);
struct firmware_priv *fw_priv = class_get_devdata(class_dev);
struct firmware *fw = fw_priv->fw;
int retval;
retval = fw_realloc_buffer(fw_priv, offset + count);
if (retval)
return retval;
memcpy(fw->data + offset, buffer, count);
fw->size = max_t(size_t, offset + count, fw->size);
return count;
}
static struct bin_attribute firmware_attr_data_tmpl = {
.attr = {.name = "data", .mode = 0644},
.size = 0,
.read = firmware_data_read,
.write = firmware_data_write,
};
static void
fw_class_dev_release(struct class_device *class_dev)
{
kfree(class_dev);
}
static void
firmware_class_timeout(u_long data)
{
struct firmware_priv *fw_priv = (struct firmware_priv *) data;
fw_priv->abort = 1;
wmb();
complete(&fw_priv->completion);
}
static inline void
fw_setup_class_device_id(struct class_device *class_dev, struct device *dev)
{
/* XXX warning we should watch out for name collisions */
strncpy(class_dev->class_id, dev->bus_id, BUS_ID_SIZE);
class_dev->class_id[BUS_ID_SIZE - 1] = '\0';
}
static int
fw_setup_class_device(struct class_device **class_dev_p,
const char *fw_name, struct device *device)
{
int retval = 0;
struct firmware_priv *fw_priv = kmalloc(sizeof (struct firmware_priv),
GFP_KERNEL);
struct class_device *class_dev = kmalloc(sizeof (struct class_device),
GFP_KERNEL);
if (!fw_priv || !class_dev) {
retval = -ENOMEM;
goto error_kfree;
}
memset(fw_priv, 0, sizeof (*fw_priv));
memset(class_dev, 0, sizeof (*class_dev));
init_completion(&fw_priv->completion);
memcpy(&fw_priv->attr_data, &firmware_attr_data_tmpl,
sizeof (firmware_attr_data_tmpl));
strncpy(&fw_priv->fw_id[0], fw_name, FIRMWARE_NAME_MAX);
fw_priv->fw_id[FIRMWARE_NAME_MAX - 1] = '\0';
fw_setup_class_device_id(class_dev, device);
class_dev->dev = device;
fw_priv->timeout.function = firmware_class_timeout;
fw_priv->timeout.data = (u_long) fw_priv;
init_timer(&fw_priv->timeout);
class_dev->class = &firmware_class;
class_set_devdata(class_dev, fw_priv);
retval = class_device_register(class_dev);
if (retval) {
printk(KERN_ERR "%s: class_device_register failed\n",
__FUNCTION__);
goto error_kfree;
}
retval = sysfs_create_bin_file(&class_dev->kobj, &fw_priv->attr_data);
if (retval) {
printk(KERN_ERR "%s: sysfs_create_bin_file failed\n",
__FUNCTION__);
goto error_unreg_class_dev;
}
retval = class_device_create_file(class_dev,
&class_device_attr_loading);
if (retval) {
printk(KERN_ERR "%s: class_device_create_file failed\n",
__FUNCTION__);
goto error_remove_data;
}
fw_priv->fw = kmalloc(sizeof (struct firmware), GFP_KERNEL);
if (!fw_priv->fw) {
printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n",
__FUNCTION__);
retval = -ENOMEM;
goto error_remove_loading;
}
memset(fw_priv->fw, 0, sizeof (*fw_priv->fw));
goto out;
error_remove_loading:
class_device_remove_file(class_dev, &class_device_attr_loading);
error_remove_data:
sysfs_remove_bin_file(&class_dev->kobj, &fw_priv->attr_data);
error_unreg_class_dev:
class_device_unregister(class_dev);
error_kfree:
kfree(fw_priv);
kfree(class_dev);
*class_dev_p = NULL;
out:
*class_dev_p = class_dev;
return retval;
}
static void
fw_remove_class_device(struct class_device *class_dev)
{
struct firmware_priv *fw_priv = class_get_devdata(class_dev);
class_device_remove_file(class_dev, &class_device_attr_loading);
sysfs_remove_bin_file(&class_dev->kobj, &fw_priv->attr_data);
class_device_unregister(class_dev);
}
/**
* request_firmware: - request firmware to hotplug and wait for it
* Description:
* @firmware will be used to return a firmware image by the name
* of @name for device @device.
*
* Should be called from user context where sleeping is allowed.
*
* @name will be use as $FIRMWARE in the hotplug environment and
* should be distinctive enough not to be confused with any other
* firmware image for this or any other device.
**/
int
request_firmware(const struct firmware **firmware, const char *name,
struct device *device)
{
struct class_device *class_dev;
struct firmware_priv *fw_priv;
int retval;
if (!firmware)
return -EINVAL;
*firmware = NULL;
retval = fw_setup_class_device(&class_dev, name, device);
if (retval)
goto out;
fw_priv = class_get_devdata(class_dev);
if (loading_timeout) {
fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
add_timer(&fw_priv->timeout);
}
wait_for_completion(&fw_priv->completion);
del_timer(&fw_priv->timeout);
fw_remove_class_device(class_dev);
if (fw_priv->fw->size && !fw_priv->abort) {
*firmware = fw_priv->fw;
} else {
retval = -ENOENT;
vfree(fw_priv->fw->data);
kfree(fw_priv->fw);
}
kfree(fw_priv);
out:
return retval;
}
/**
* release_firmware: - release the resource associated with a firmware image
**/
void
release_firmware(const struct firmware *fw)
{
if (fw) {
vfree(fw->data);
kfree(fw);
}
}
/**
* register_firmware: - provide a firmware image for later usage
*
* Description:
* Make sure that @data will be available by requesting firmware @name.
*
* Note: This will not be possible until some kind of persistence
* is available.
**/
void
register_firmware(const char *name, const u8 *data, size_t size)
{
/* This is meaningless without firmware caching, so until we
* decide if firmware caching is reasonable just leave it as a
* noop */
}
/* Async support */
struct firmware_work {
struct work_struct work;
struct module *module;
const char *name;
struct device *device;
void *context;
void (*cont)(const struct firmware *fw, void *context);
};
static void
request_firmware_work_func(void *arg)
{
struct firmware_work *fw_work = arg;
const struct firmware *fw;
if (!arg)
return;
request_firmware(&fw, fw_work->name, fw_work->device);
fw_work->cont(fw, fw_work->context);
release_firmware(fw);
module_put(fw_work->module);
kfree(fw_work);
}
/**
* request_firmware_nowait:
*
* Description:
* Asynchronous variant of request_firmware() for contexts where
* it is not possible to sleep.
*
* @cont will be called asynchronously when the firmware request is over.
*
* @context will be passed over to @cont.
*
* @fw may be %NULL if firmware request fails.
*
**/
int
request_firmware_nowait(
struct module *module,
const char *name, struct device *device, void *context,
void (*cont)(const struct firmware *fw, void *context))
{
struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work),
GFP_ATOMIC);
if (!fw_work)
return -ENOMEM;
if (!try_module_get(module)) {
kfree(fw_work);
return -EFAULT;
}
*fw_work = (struct firmware_work) {
.module = module,
.name = name,
.device = device,
.context = context,
.cont = cont,
};
INIT_WORK(&fw_work->work, request_firmware_work_func, fw_work);
schedule_work(&fw_work->work);
return 0;
}
static int __init
firmware_class_init(void)
{
int error;
error = class_register(&firmware_class);
if (error) {
printk(KERN_ERR "%s: class_register failed\n", __FUNCTION__);
}
error = class_create_file(&firmware_class, &class_attr_timeout);
if (error) {
printk(KERN_ERR "%s: class_create_file failed\n",
__FUNCTION__);
class_unregister(&firmware_class);
}
return error;
}
static void __exit
firmware_class_exit(void)
{
class_remove_file(&firmware_class, &class_attr_timeout);
class_unregister(&firmware_class);
}
module_init(firmware_class_init);
module_exit(firmware_class_exit);
EXPORT_SYMBOL(release_firmware);
EXPORT_SYMBOL(request_firmware);
EXPORT_SYMBOL(request_firmware_nowait);
EXPORT_SYMBOL(register_firmware);
EXPORT_SYMBOL(firmware_class);
......@@ -74,6 +74,8 @@ void sysdev_remove_file(struct sys_device * s, struct sysdev_attribute * a)
sysfs_remove_file(&s->kobj,&a->attr);
}
EXPORT_SYMBOL(sysdev_create_file);
EXPORT_SYMBOL(sysdev_remove_file);
/*
* declare system_subsys
......@@ -171,6 +173,9 @@ int sys_device_register(struct sys_device * sysdev)
/* Make sure the kset is set */
sysdev->kobj.kset = &cls->kset;
/* But make sure we point to the right type for sysfs translation */
sysdev->kobj.ktype = &ktype_sysdev;
/* set the kobject name */
snprintf(sysdev->kobj.name,KOBJ_NAME_LEN,"%s%d",
cls->kset.kobj.name,sysdev->id);
......@@ -218,9 +223,6 @@ void sys_device_unregister(struct sys_device * sysdev)
if (drv->remove)
drv->remove(sysdev);
}
list_del_init(&sysdev->entry);
up_write(&system_subsys.rwsem);
kobject_unregister(&sysdev->kobj);
......
......@@ -6,4 +6,4 @@ obj-$(CONFIG_ISDN_DRV_ACT2000) += act2000.o
# Multipart objects.
act2000-objs := module.o capi.o act2000_isa.o
act2000-y := module.o capi.o act2000_isa.o
......@@ -13,4 +13,3 @@ obj-$(CONFIG_ISDN_CAPI_CAPIFS) += capifs.o
kernelcapi-y := kcapi.o capiutil.o capilib.o
kernelcapi-$(CONFIG_PROC_FS) += kcapi_proc.o
kernelcapi-objs := $(kernelcapi-y)
......@@ -6,4 +6,4 @@ obj-$(CONFIG_ISDN_DIVERSION) += dss1_divert.o
# Multipart objects.
dss1_divert-objs := isdn_divert.o divert_procfs.o divert_init.o
dss1_divert-y := isdn_divert.o divert_procfs.o divert_init.o
......@@ -7,15 +7,13 @@ obj-$(CONFIG_ISDN_DRV_EICON_DIVAS) += divas.o
# Multipart objects.
eicon-objs := eicon_mod.o eicon_isa.o eicon_pci.o eicon_idi.o \
eicon_io.o
divas-objs := common.o idi.o bri.o pri.o log.o xlog.o kprintf.o fpga.o \
fourbri.o lincfg.o linchr.o linsys.o linio.o Divas_mod.o
eicon-y := eicon_mod.o eicon_isa.o eicon_pci.o \
eicon_idi.o eicon_io.o
eicon-$(CONFIG_ISDN_DRV_EICON_PCI) += common.o idi.o bri.o pri.o log.o \
xlog.o kprintf.o fpga.o fourbri.o lincfg.o \
linchr.o linsys.o linio.o
# Optional parts of multipart objects.
divas-y := common.o idi.o bri.o pri.o log.o xlog.o \
kprintf.o fpga.o fourbri.o lincfg.o \
linchr.o linsys.o linio.o Divas_mod.o
eicon-objs-$(CONFIG_ISDN_DRV_EICON_PCI) += common.o idi.o bri.o pri.o log.o \
xlog.o kprintf.o fpga.o fourbri.o lincfg.o linchr.o \
linsys.o linio.o
eicon-objs += $(eicon-objs-y)
......@@ -123,7 +123,7 @@ eicon_isa_find_card(int Mem, int Irq, char * Id)
int
eicon_isa_bootload(eicon_isa_card *card, eicon_isa_codebuf *cb) {
int tmp;
int timeout;
unsigned long timeout;
eicon_isa_codebuf cbuf;
unsigned char *code;
eicon_isa_boot *boot;
......@@ -300,7 +300,7 @@ int
eicon_isa_load(eicon_isa_card *card, eicon_isa_codebuf *cb) {
eicon_isa_boot *boot;
int tmp;
int timeout;
unsigned long timeout;
int j;
eicon_isa_codebuf cbuf;
unsigned char *code;
......
......@@ -111,7 +111,7 @@ static int b1pci_probe(struct capicardparams *p, struct pci_dev *pdev)
cinfo->capi_ctrl.procinfo = b1pci_procinfo;
cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc;
strcpy(cinfo->capi_ctrl.name, card->name);
cinfo->capi_ctrl.owner = THIS_MODULE;
cinfo->capi_ctrl.owner = THIS_MODULE;
retval = attach_capi_ctr(&cinfo->capi_ctrl);
if (retval) {
......@@ -239,6 +239,7 @@ static int b1pciv4_probe(struct capicardparams *p, struct pci_dev *pdev)
goto err_unmap;
}
cinfo->capi_ctrl.owner = THIS_MODULE;
cinfo->capi_ctrl.driver_name = "b1pciv4";
cinfo->capi_ctrl.driverdata = cinfo;
cinfo->capi_ctrl.register_appl = b1dma_register_appl;
......@@ -249,7 +250,6 @@ static int b1pciv4_probe(struct capicardparams *p, struct pci_dev *pdev)
cinfo->capi_ctrl.procinfo = b1pciv4_procinfo;
cinfo->capi_ctrl.ctr_read_proc = b1dmactl_read_proc;
strcpy(cinfo->capi_ctrl.name, card->name);
cinfo->capi_ctrl.owner = THIS_MODULE;
retval = attach_capi_ctr(&cinfo->capi_ctrl);
if (retval) {
......
......@@ -95,6 +95,7 @@ static int b1pcmcia_add_card(unsigned int port, unsigned irq,
b1_reset(card->port);
b1_getrevision(card);
cinfo->capi_ctrl.owner = THIS_MODULE;
cinfo->capi_ctrl.driver_name = "b1pcmcia";
cinfo->capi_ctrl.driverdata = cinfo;
cinfo->capi_ctrl.register_appl = b1_register_appl;
......@@ -105,7 +106,6 @@ static int b1pcmcia_add_card(unsigned int port, unsigned irq,
cinfo->capi_ctrl.procinfo = b1pcmcia_procinfo;
cinfo->capi_ctrl.ctr_read_proc = b1ctl_read_proc;
strcpy(cinfo->capi_ctrl.name, card->name);
cinfo->capi_ctrl.owner = THIS_MODULE;
retval = attach_capi_ctr(&cinfo->capi_ctrl);
if (retval) {
......
......@@ -109,6 +109,7 @@ static int t1pci_add_card(struct capicardparams *p, struct pci_dev *pdev)
goto err_unmap;
}
cinfo->capi_ctrl.owner = THIS_MODULE;
cinfo->capi_ctrl.driver_name = "t1pci";
cinfo->capi_ctrl.driverdata = cinfo;
cinfo->capi_ctrl.register_appl = b1dma_register_appl;
......@@ -119,7 +120,6 @@ static int t1pci_add_card(struct capicardparams *p, struct pci_dev *pdev)
cinfo->capi_ctrl.procinfo = t1pci_procinfo;
cinfo->capi_ctrl.ctr_read_proc = b1dmactl_read_proc;
strcpy(cinfo->capi_ctrl.name, card->name);
cinfo->capi_ctrl.owner = THIS_MODULE;
retval = attach_capi_ctr(&cinfo->capi_ctrl);
if (retval) {
......
# Makefile for the Eicon DIVA ISDN drivers.
# Multipart objects.
# Each configuration option enables a list of files.
divas-objs := divasmain.o divasfunc.o di.o io.o istream.o diva.o dlist.o divasproc.o diva_dma.o
divacapi-objs := capimain.o capifunc.o message.o capidtmf.o
divadidd-objs := diva_didd.o diddfunc.o dadapter.o
diva_mnt-objs := divamnt.o mntfunc.o debug.o maintidi.o
diva_idi-objs := divasi.o idifunc.o um_idi.o dqueue.o dlist.o
obj-$(CONFIG_ISDN_DIVAS) += divadidd.o divas.o
obj-$(CONFIG_ISDN_DIVAS_MAINT) += diva_mnt.o
obj-$(CONFIG_ISDN_DIVAS_USERIDI) += diva_idi.o
obj-$(CONFIG_ISDN_DIVAS_DIVACAPI) += divacapi.o
# Optional parts of multipart objects.
# Multipart objects.
divas-objs-$(CONFIG_ISDN_DIVAS_BRIPCI) += os_bri.o s_bri.o
divas-objs-$(CONFIG_ISDN_DIVAS_4BRIPCI) += os_4bri.o s_4bri.o
divas-objs-$(CONFIG_ISDN_DIVAS_PRIPCI) += os_pri.o s_pri.o
divas-y := divasmain.o divasfunc.o di.o io.o istream.o \
diva.o dlist.o divasproc.o diva_dma.o
divas-$(CONFIG_ISDN_DIVAS_BRIPCI) += os_bri.o s_bri.o
divas-$(CONFIG_ISDN_DIVAS_4BRIPCI) += os_4bri.o s_4bri.o
divas-$(CONFIG_ISDN_DIVAS_PRIPCI) += os_pri.o s_pri.o
divas-objs += $(sort $(divas-objs-y))
divacapi-y := capimain.o capifunc.o message.o capidtmf.o
# Each configuration option enables a list of files.
divadidd-y := diva_didd.o diddfunc.o dadapter.o
diva_mnt-y := divamnt.o mntfunc.o debug.o maintidi.o
obj-$(CONFIG_ISDN_DIVAS) += divadidd.o divas.o
obj-$(CONFIG_ISDN_DIVAS_MAINT) += diva_mnt.o
obj-$(CONFIG_ISDN_DIVAS_USERIDI) += diva_idi.o
obj-$(CONFIG_ISDN_DIVAS_DIVACAPI) += divacapi.o
diva_idi-y := divasi.o idifunc.o um_idi.o dqueue.o dlist.o
......@@ -17,47 +17,45 @@ obj-$(CONFIG_HISAX_FRITZ_PCIPNP) += hisax_hfcpci.o
# Multipart objects.
hisax_st5481-objs := st5481_init.o st5481_usb.o st5481_d.o st5481_b.o \
st5481_hdlc.o
hisax-objs := config.o isdnl1.o tei.o isdnl2.o isdnl3.o \
lmgr.o q931.o callc.o fsm.o cert.o
# Optional parts of multipart objects.
hisax-objs-$(CONFIG_HISAX_EURO) += l3dss1.o
hisax-objs-$(CONFIG_HISAX_NI1) += l3ni1.o
hisax-objs-$(CONFIG_HISAX_1TR6) += l3_1tr6.o
hisax-objs-$(CONFIG_HISAX_16_0) += teles0.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_16_3) += teles3.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_TELESPCI) += telespci.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_S0BOX) += s0box.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_AVM_A1) += avm_a1.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_AVM_A1_PCMCIA) += avm_a1p.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_FRITZPCI) += avm_pci.o isac.o arcofi.o
hisax-objs-$(CONFIG_HISAX_ELSA) += elsa.o isac.o arcofi.o hscx.o ipac.o
hisax-objs-$(CONFIG_HISAX_IX1MICROR2) += ix1_micro.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o ipac.o ipacx.o
hisax-objs-$(CONFIG_HISAX_ASUSCOM) += asuscom.o isac.o arcofi.o hscx.o ipac.o
hisax-objs-$(CONFIG_HISAX_TELEINT) += teleint.o isac.o arcofi.o hfc_2bs0.o
hisax-objs-$(CONFIG_HISAX_SEDLBAUER) += sedlbauer.o isac.o arcofi.o hscx.o ipac.o isar.o
hisax-objs-$(CONFIG_HISAX_SPORTSTER) += sportster.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_MIC) += mic.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_NETJET) += nj_s.o netjet.o isac.o arcofi.o
hisax-objs-$(CONFIG_HISAX_NETJET_U) += nj_u.o netjet.o icc.o
hisax-objs-$(CONFIG_HISAX_HFCS) += hfcscard.o hfc_2bds0.o
hisax-objs-$(CONFIG_HISAX_HFC_PCI) += hfc_pci.o
hisax-objs-$(CONFIG_HISAX_HFC_SX) += hfc_sx.o
hisax-objs-$(CONFIG_HISAX_NICCY) += niccy.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_ISURF) += isurf.o isac.o arcofi.o isar.o
hisax-objs-$(CONFIG_HISAX_HSTSAPHIR) += saphir.o isac.o arcofi.o hscx.o
hisax-objs-$(CONFIG_HISAX_BKM_A4T) += bkm_a4t.o isac.o arcofi.o jade.o
hisax-objs-$(CONFIG_HISAX_SCT_QUADRO) += bkm_a8.o isac.o arcofi.o hscx.o ipac.o
hisax-objs-$(CONFIG_HISAX_GAZEL) += gazel.o isac.o arcofi.o hscx.o ipac.o
hisax-objs-$(CONFIG_HISAX_W6692) += w6692.o
hisax-objs-$(CONFIG_HISAX_ENTERNOW_PCI) += enternow_pci.o amd7930_fn.o
#hisax-objs-$(CONFIG_HISAX_TESTEMU) += testemu.o
hisax-objs += $(hisax-objs-y)
hisax_st5481-y := st5481_init.o st5481_usb.o st5481_d.o \
st5481_b.o st5481_hdlc.o
hisax-y := config.o isdnl1.o tei.o isdnl2.o isdnl3.o \
lmgr.o q931.o callc.o fsm.o cert.o
hisax-$(CONFIG_HISAX_EURO) += l3dss1.o
hisax-$(CONFIG_HISAX_NI1) += l3ni1.o
hisax-$(CONFIG_HISAX_1TR6) += l3_1tr6.o
hisax-$(CONFIG_HISAX_16_0) += teles0.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_16_3) += teles3.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_TELESPCI) += telespci.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_S0BOX) += s0box.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_AVM_A1) += avm_a1.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_AVM_A1_PCMCIA) += avm_a1p.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_FRITZPCI) += avm_pci.o isac.o arcofi.o
hisax-$(CONFIG_HISAX_ELSA) += elsa.o isac.o arcofi.o hscx.o ipac.o
hisax-$(CONFIG_HISAX_IX1MICROR2) += ix1_micro.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_DIEHLDIVA) += diva.o isac.o arcofi.o hscx.o ipac.o ipacx.o
hisax-$(CONFIG_HISAX_ASUSCOM) += asuscom.o isac.o arcofi.o hscx.o ipac.o
hisax-$(CONFIG_HISAX_TELEINT) += teleint.o isac.o arcofi.o hfc_2bs0.o
hisax-$(CONFIG_HISAX_SEDLBAUER) += sedlbauer.o isac.o arcofi.o hscx.o ipac.o \
isar.o
hisax-$(CONFIG_HISAX_SPORTSTER) += sportster.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_MIC) += mic.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_NETJET) += nj_s.o netjet.o isac.o arcofi.o
hisax-$(CONFIG_HISAX_NETJET_U) += nj_u.o netjet.o icc.o
hisax-$(CONFIG_HISAX_HFCS) += hfcscard.o hfc_2bds0.o
hisax-$(CONFIG_HISAX_HFC_PCI) += hfc_pci.o
hisax-$(CONFIG_HISAX_HFC_SX) += hfc_sx.o
hisax-$(CONFIG_HISAX_NICCY) += niccy.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_ISURF) += isurf.o isac.o arcofi.o isar.o
hisax-$(CONFIG_HISAX_HSTSAPHIR) += saphir.o isac.o arcofi.o hscx.o
hisax-$(CONFIG_HISAX_BKM_A4T) += bkm_a4t.o isac.o arcofi.o jade.o
hisax-$(CONFIG_HISAX_SCT_QUADRO) += bkm_a8.o isac.o arcofi.o hscx.o ipac.o
hisax-$(CONFIG_HISAX_GAZEL) += gazel.o isac.o arcofi.o hscx.o ipac.o
hisax-$(CONFIG_HISAX_W6692) += w6692.o
hisax-$(CONFIG_HISAX_ENTERNOW_PCI) += enternow_pci.o amd7930_fn.o
#hisax-$(CONFIG_HISAX_TESTEMU) += testemu.o
CERT := $(shell cd $(src); md5sum -c md5sums.asc > /dev/null 2> /dev/null ;echo $$?)
CFLAGS_cert.o := -DCERTIFICATION=$(CERT)
......@@ -153,6 +153,8 @@ static dev_link_t *avma1cs_attach(void)
/* Initialize the dev_link_t structure */
link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
if (!link)
return NULL;
memset(link, 0, sizeof(struct dev_link_t));
link->release.function = &avma1cs_release;
link->release.data = (u_long)link;
......@@ -186,6 +188,10 @@ static dev_link_t *avma1cs_attach(void)
/* Allocate space for private device-specific data */
local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
if (!local) {
kfree(link);
return NULL;
}
memset(local, 0, sizeof(local_info_t));
link->priv = local;
......
......@@ -2,15 +2,10 @@
# Each configuration option enables a list of files.
obj-$(CONFIG_HYSDN) += hysdn.o
obj-$(CONFIG_HYSDN) += hysdn.o
# Multipart objects.
hysdn-objs := hysdn_procconf.o hysdn_proclog.o boardergo.o hysdn_boot.o \
hysdn_sched.o hysdn_net.o hysdn_init.o
# Optional parts of multipart objects.
hysdn-objs-$(CONFIG_HYSDN_CAPI) += hycapi.o
hysdn-objs += $(hysdn-objs-y)
hysdn-y := hysdn_procconf.o hysdn_proclog.o boardergo.o \
hysdn_boot.o hysdn_sched.o hysdn_net.o hysdn_init.o
hysdn-$(CONFIG_HYSDN_CAPI) += hycapi.o
......@@ -98,7 +98,8 @@ put_log_buffer(hysdn_card * card, char *cp)
{
struct log_data *ib;
struct procdata *pd = card->proclog;
int i, flags;
int i;
unsigned long flags;
if (!pd)
return;
......@@ -300,7 +301,8 @@ hysdn_log_close(struct inode *ino, struct file *filep)
struct log_data *inf;
struct procdata *pd;
hysdn_card *card;
int flags, retval = 0;
int retval = 0;
unsigned long flags;
lock_kernel();
......
......@@ -2,25 +2,18 @@
# Each configuration option enables a list of files.
obj-$(CONFIG_ISDN) += isdn.o
obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
obj-$(CONFIG_ISDN) += isdn.o
obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
# Multipart objects.
isdn-objs := isdn_net_lib.o \
isdn_fsm.o \
isdn_tty.o isdn_v110.o \
isdn_common.o \
# Optional parts of multipart objects.
isdn-objs-$(CONFIG_ISDN_NET_SIMPLE) += isdn_net.o
isdn-objs-$(CONFIG_ISDN_NET_CISCO) += isdn_ciscohdlck.o
isdn-objs-$(CONFIG_ISDN_PPP) += isdn_ppp.o isdn_ppp_ccp.o
isdn-objs-$(CONFIG_ISDN_PPP_VJ) += isdn_ppp_vj.o
isdn-objs-$(CONFIG_ISDN_MPP) += isdn_ppp_mp.o
isdn-objs-$(CONFIG_ISDN_X25) += isdn_concap.o isdn_x25iface.o
isdn-objs-$(CONFIG_ISDN_AUDIO) += isdn_audio.o
isdn-objs-$(CONFIG_ISDN_TTY_FAX) += isdn_ttyfax.o
isdn-objs += $(isdn-objs-y)
isdn-y := isdn_net_lib.o isdn_fsm.o isdn_tty.o \
isdn_v110.o isdn_common.o
isdn-$(CONFIG_ISDN_NET_SIMPLE) += isdn_net.o
isdn-$(CONFIG_ISDN_NET_CISCO) += isdn_ciscohdlck.o
isdn-$(CONFIG_ISDN_PPP) += isdn_ppp.o isdn_ppp_ccp.o
isdn-$(CONFIG_ISDN_PPP_VJ) += isdn_ppp_vj.o
isdn-$(CONFIG_ISDN_MPP) += isdn_ppp_mp.o
isdn-$(CONFIG_ISDN_X25) += isdn_concap.o isdn_x25iface.o
isdn-$(CONFIG_ISDN_AUDIO) += isdn_audio.o
isdn-$(CONFIG_ISDN_TTY_FAX) += isdn_ttyfax.o
......@@ -300,7 +300,6 @@ static void bsd_free (void *state)
* Finally release the structure itself.
*/
kfree (db);
MOD_DEC_USE_COUNT;
}
}
......@@ -355,8 +354,6 @@ static void *bsd_alloc (struct isdn_ppp_comp_data *data)
return NULL;
}
MOD_INC_USE_COUNT;
/*
* If this is the compression buffer then there is no length data.
* For decompression, the length information is needed as well.
......@@ -907,6 +904,7 @@ static int bsd_decompress (void *state, struct sk_buff *skb_in, struct sk_buff *
*************************************************************/
static struct isdn_ppp_compressor ippp_bsd_compress = {
.owner = THIS_MODULE,
.num = CI_BSD_COMPRESS,
.alloc = bsd_alloc,
.free = bsd_free,
......
......@@ -259,11 +259,14 @@ ippp_ccp_free(struct ippp_ccp *ccp)
{
int id;
if (ccp->comp_stat)
if (ccp->comp_stat) {
ccp->compressor->free(ccp->comp_stat);
if (ccp->decomp_stat)
module_put(ccp->compressor->owner);
}
if (ccp->decomp_stat) {
ccp->decompressor->free(ccp->decomp_stat);
module_put(ccp->decompressor->owner);
}
for (id = 0; id < 256; id++) {
if (ccp->reset->rs[id])
ippp_ccp_reset_free_state(ccp, id);
......@@ -553,13 +556,14 @@ ippp_ccp_send_ccp(struct ippp_ccp *ccp, struct sk_buff *skb)
}
}
static struct isdn_ppp_compressor *ipc_head = NULL;
static LIST_HEAD(ipc_head);
static spinlock_t ipc_head_lock;
int
ippp_ccp_set_compressor(struct ippp_ccp *ccp, int unit,
struct isdn_ppp_comp_data *data)
{
struct isdn_ppp_compressor *ipc = ipc_head;
struct isdn_ppp_compressor *ipc;
int ret;
void *stat;
int num = data->num;
......@@ -568,34 +572,48 @@ ippp_ccp_set_compressor(struct ippp_ccp *ccp, int unit,
printk(KERN_DEBUG "[%d] Set %scompressor type %d\n", unit,
data->flags & IPPP_COMP_FLAG_XMIT ? "" : "de", num);
for (ipc = ipc_head; ipc; ipc = ipc->next) {
if (ipc->num != num)
continue;
stat = ipc->alloc(data);
if (!stat) {
printk(KERN_ERR "Can't alloc (de)compression!\n");
break;
}
ret = ipc->init(stat, data, unit, 0);
if(!ret) {
printk(KERN_ERR "Can't init (de)compression!\n");
ipc->free(stat);
break;
spin_lock(&ipc_head_lock);
list_for_each_entry(ipc, &ipc_head, list) {
if (ipc->num == num &&
try_module_get(ipc->owner))
goto found;
}
spin_unlock(&ipc_head_lock);
return -EINVAL;
found:
spin_unlock(&ipc_head_lock);
stat = ipc->alloc(data);
if (!stat) {
printk(KERN_ERR "Can't alloc (de)compression!\n");
goto err;
}
ret = ipc->init(stat, data, unit, 0);
if(!ret) {
printk(KERN_ERR "Can't init (de)compression!\n");
ipc->free(stat);
goto err;
}
if (data->flags & IPPP_COMP_FLAG_XMIT) {
if (ccp->comp_stat) {
ccp->compressor->free(ccp->comp_stat);
module_put(ccp->compressor->owner);
}
if (data->flags & IPPP_COMP_FLAG_XMIT) {
if (ccp->comp_stat)
ccp->compressor->free(ccp->comp_stat);
ccp->comp_stat = stat;
ccp->compressor = ipc;
} else {
if (ccp->decomp_stat)
ccp->decompressor->free(ccp->decomp_stat);
ccp->decomp_stat = stat;
ccp->decompressor = ipc;
} else {
if (ccp->decomp_stat) {
ccp->decompressor->free(ccp->decomp_stat);
module_put(ccp->decompressor->owner);
}
return 0;
ccp->decomp_stat = stat;
ccp->decompressor = ipc;
}
return 0;
err:
module_put(ipc->owner);
return -EINVAL;
}
......@@ -606,36 +624,34 @@ ippp_ccp_get_compressors(unsigned long protos[8])
int i, j;
memset(protos, 0, sizeof(unsigned long) * 8);
for (ipc = ipc_head; ipc; ipc = ipc->next) {
spin_lock(&ipc_head_lock);
list_for_each_entry(ipc, &ipc_head, list) {
j = ipc->num / (sizeof(long)*8);
i = ipc->num % (sizeof(long)*8);
if (j < 8)
protos[j] |= 1 << i;
}
spin_unlock(&ipc_head_lock);
}
int
isdn_ppp_register_compressor(struct isdn_ppp_compressor *ipc)
{
ipc->next = ipc_head;
ipc->prev = NULL;
if (ipc_head) {
ipc_head->prev = ipc;
}
ipc_head = ipc;
spin_lock(&ipc_head_lock);
list_add_tail(&ipc->list, &ipc_head);
spin_unlock(&ipc_head_lock);
return 0;
}
int
isdn_ppp_unregister_compressor(struct isdn_ppp_compressor *ipc)
{
if (ipc->prev)
ipc->prev->next = ipc->next;
else
ipc_head = ipc->next;
if (ipc->next)
ipc->next->prev = ipc->prev;
ipc->prev = ipc->next = NULL;
spin_lock(&ipc_head_lock);
list_del(&ipc->list);
spin_unlock(&ipc_head_lock);
return 0;
}
......@@ -1983,7 +1983,7 @@ modem_write_profile(atemu * m)
memcpy(m->pmsn, m->msn, ISDN_MSNLEN);
memcpy(m->plmsn, m->lmsn, ISDN_LMSNLEN);
if (dev->profd)
group_send_sig_info(SIGIO, SEND_SIG_PRIV, dev->profd);
kill_pg_info(SIGIO, SEND_SIG_PRIV, dev->profd->pgrp);
}
static struct tty_operations modem_ops = {
......@@ -2095,11 +2095,10 @@ isdn_tty_init(void)
#endif
kfree(info->xmit_buf - 4);
}
err_unregister_tty:
tty_unregister_driver(&isdn_mdm->tty_modem);
tty_unregister_driver(m->tty_modem);
err:
put_tty_driver(&isdn_mdm->tty_modem);
isdn_mdm->tty_modem = NULL;
put_tty_driver(m->tty_modem);
m->tty_modem = NULL;
return retval;
}
......@@ -2118,9 +2117,9 @@ isdn_tty_exit(void)
#endif
kfree(info->xmit_buf - 4);
}
tty_unregister_driver(&isdn_mdm->tty_modem);
put_tty_driver(&isdn_mdm->tty_modem);
isdn_mdm->tty_modem = NULL;
tty_unregister_driver(isdn_mdm.tty_modem);
put_tty_driver(isdn_mdm.tty_modem);
isdn_mdm.tty_modem = NULL;
}
/*
......
......@@ -303,7 +303,7 @@ isdn_tty_cmd_FCLASS1(char **p, modem_info * info)
isdn_ctrl c;
int par;
struct isdn_slot *slot;
long flags;
unsigned long flags;
for (c.parm.aux.cmd = 0; c.parm.aux.cmd < 7; c.parm.aux.cmd++)
if (!strncmp(p[0], cmd[c.parm.aux.cmd], 2))
......
#
# Makefile for the isdnloop ISDN device driver
#
# Each configuration option enables a list of files.
......
......@@ -6,4 +6,4 @@ obj-$(CONFIG_ISDN_DRV_PCBIT) += pcbit.o
# Multipart objects.
pcbit-objs := module.o edss1.o drv.o layer2.o capi.o callbacks.o
pcbit-y := module.o edss1.o drv.o layer2.o capi.o callbacks.o
......@@ -6,5 +6,5 @@ obj-$(CONFIG_ISDN_DRV_SC) += sc.o
# Multipart objects.
sc-objs := shmem.o init.o debug.o packet.o command.o event.o \
ioctl.o interrupt.o message.o timer.o
sc-y := shmem.o init.o debug.o packet.o command.o event.o \
ioctl.o interrupt.o message.o timer.o
......@@ -6,5 +6,6 @@ obj-$(CONFIG_ISDN_DRV_TPAM) += tpam.o
# Multipart objects.
tpam-objs := tpam_main.o tpam_nco.o tpam_memory.o tpam_commands.o \
tpam_queues.o tpam_hdlc.o tpam_crcpc.o
tpam-y := tpam_main.o tpam_nco.o tpam_memory.o \
tpam_commands.o tpam_queues.o tpam_hdlc.o \
tpam_crcpc.o
......@@ -145,6 +145,7 @@ irqreturn_t tpam_irq(int irq, void *dev_id, struct pt_regs *regs)
do {
hpic = readl(card->bar0 + TPAM_HPIC_REGISTER);
if (waiting_too_long++ > 0xfffffff) {
kfree_skb(skb);
spin_unlock(&card->lock);
printk(KERN_ERR "TurboPAM(tpam_irq): "
"waiting too long...\n");
......
......@@ -4,29 +4,11 @@ void *pnp_alloc(long size);
int pnp_interface_attach_device(struct pnp_dev *dev);
void pnp_name_device(struct pnp_dev *dev);
void pnp_fixup_device(struct pnp_dev *dev);
void pnp_free_resources(struct pnp_resources *resources);
void pnp_free_option(struct pnp_option *option);
int __pnp_add_device(struct pnp_dev *dev);
void __pnp_remove_device(struct pnp_dev *dev);
/* resource conflict types */
#define CONFLICT_TYPE_NONE 0x0000 /* there are no conflicts, other than those in the link */
#define CONFLICT_TYPE_RESERVED 0x0001 /* the resource requested was reserved */
#define CONFLICT_TYPE_IN_USE 0x0002 /* there is a conflict because the resource is in use */
#define CONFLICT_TYPE_PCI 0x0004 /* there is a conflict with a pci device */
#define CONFLICT_TYPE_INVALID 0x0008 /* the resource requested is invalid */
#define CONFLICT_TYPE_INTERNAL 0x0010 /* resources within the device conflict with each ohter */
#define CONFLICT_TYPE_PNP_WARM 0x0020 /* there is a conflict with a pnp device that is active */
#define CONFLICT_TYPE_PNP_COLD 0x0040 /* there is a conflict with a pnp device that is disabled */
/* conflict search modes */
#define SEARCH_WARM 1 /* check for conflicts with active devices */
#define SEARCH_COLD 0 /* check for conflicts with disabled devices */
struct pnp_dev * pnp_check_port_conflicts(struct pnp_dev * dev, int idx, int mode);
int pnp_check_port(struct pnp_dev * dev, int idx);
struct pnp_dev * pnp_check_mem_conflicts(struct pnp_dev * dev, int idx, int mode);
int pnp_check_mem(struct pnp_dev * dev, int idx);
struct pnp_dev * pnp_check_irq_conflicts(struct pnp_dev * dev, int idx, int mode);
int pnp_check_irq(struct pnp_dev * dev, int idx);
struct pnp_dev * pnp_check_dma_conflicts(struct pnp_dev * dev, int idx, int mode);
int pnp_check_dma(struct pnp_dev * dev, int idx);
......@@ -104,8 +104,8 @@ static void pnp_free_ids(struct pnp_dev *dev)
static void pnp_release_device(struct device *dmdev)
{
struct pnp_dev * dev = to_pnp_dev(dmdev);
if (dev->possible)
pnp_free_resources(dev->possible);
pnp_free_option(dev->independent);
pnp_free_option(dev->dependent);
pnp_free_ids(dev);
kfree(dev);
}
......@@ -122,7 +122,7 @@ int __pnp_add_device(struct pnp_dev *dev)
list_add_tail(&dev->global_list, &pnp_global);
list_add_tail(&dev->protocol_list, &dev->protocol->devices);
spin_unlock(&pnp_lock);
pnp_auto_config_dev(dev);
ret = device_register(&dev->dev);
if (ret == 0)
pnp_interface_attach_device(dev);
......
......@@ -168,7 +168,8 @@ static void pnp_print_mem(pnp_info_buffer_t *buffer, char *space, struct pnp_mem
pnp_printf(buffer, ", %s\n", s);
}
static void pnp_print_resources(pnp_info_buffer_t *buffer, char *space, struct pnp_resources *res, int dep)
static void pnp_print_option(pnp_info_buffer_t *buffer, char *space,
struct pnp_option *option, int dep)
{
char *s;
struct pnp_port *port;
......@@ -176,49 +177,55 @@ static void pnp_print_resources(pnp_info_buffer_t *buffer, char *space, struct p
struct pnp_dma *dma;
struct pnp_mem *mem;
switch (res->priority) {
case PNP_RES_PRIORITY_PREFERRED:
s = "preferred";
break;
case PNP_RES_PRIORITY_ACCEPTABLE:
s = "acceptable";
break;
case PNP_RES_PRIORITY_FUNCTIONAL:
s = "functional";
break;
default:
s = "invalid";
}
if (dep > 0)
if (dep) {
switch (option->priority) {
case PNP_RES_PRIORITY_PREFERRED:
s = "preferred";
break;
case PNP_RES_PRIORITY_ACCEPTABLE:
s = "acceptable";
break;
case PNP_RES_PRIORITY_FUNCTIONAL:
s = "functional";
break;
default:
s = "invalid";
}
pnp_printf(buffer, "Dependent: %02i - Priority %s\n",dep, s);
for (port = res->port; port; port = port->next)
}
for (port = option->port; port; port = port->next)
pnp_print_port(buffer, space, port);
for (irq = res->irq; irq; irq = irq->next)
for (irq = option->irq; irq; irq = irq->next)
pnp_print_irq(buffer, space, irq);
for (dma = res->dma; dma; dma = dma->next)
for (dma = option->dma; dma; dma = dma->next)
pnp_print_dma(buffer, space, dma);
for (mem = res->mem; mem; mem = mem->next)
for (mem = option->mem; mem; mem = mem->next)
pnp_print_mem(buffer, space, mem);
}
static ssize_t pnp_show_possible_resources(struct device *dmdev, char *buf)
static ssize_t pnp_show_options(struct device *dmdev, char *buf)
{
struct pnp_dev *dev = to_pnp_dev(dmdev);
struct pnp_resources * res = dev->possible;
int ret, dep = 0;
struct pnp_option * independent = dev->independent;
struct pnp_option * dependent = dev->dependent;
int ret, dep = 1;
pnp_info_buffer_t *buffer = (pnp_info_buffer_t *)
pnp_alloc(sizeof(pnp_info_buffer_t));
if (!buffer)
return -ENOMEM;
buffer->len = PAGE_SIZE;
buffer->buffer = buf;
buffer->curr = buffer->buffer;
while (res){
if (dep == 0)
pnp_print_resources(buffer, "", res, dep);
else
pnp_print_resources(buffer, " ", res, dep);
res = res->dep;
if (independent)
pnp_print_option(buffer, "", independent, 0);
while (dependent){
pnp_print_option(buffer, " ", dependent, dep);
dependent = dependent->next;
dep++;
}
ret = (buffer->curr - buf);
......@@ -226,97 +233,8 @@ static ssize_t pnp_show_possible_resources(struct device *dmdev, char *buf)
return ret;
}
static DEVICE_ATTR(possible,S_IRUGO,pnp_show_possible_resources,NULL);
static void pnp_print_conflict_node(pnp_info_buffer_t *buffer, struct pnp_dev * dev)
{
if (!dev)
return;
pnp_printf(buffer, "'%s'.\n", dev->dev.bus_id);
}
static void pnp_print_conflict_desc(pnp_info_buffer_t *buffer, int conflict)
{
if (!conflict)
return;
pnp_printf(buffer, " Conflict Detected: %2x - ", conflict);
switch (conflict) {
case CONFLICT_TYPE_RESERVED:
pnp_printf(buffer, "manually reserved.\n");
break;
case CONFLICT_TYPE_IN_USE:
pnp_printf(buffer, "currently in use.\n");
break;
case CONFLICT_TYPE_PCI:
pnp_printf(buffer, "PCI device.\n");
break;
case CONFLICT_TYPE_INVALID:
pnp_printf(buffer, "invalid.\n");
break;
case CONFLICT_TYPE_INTERNAL:
pnp_printf(buffer, "another resource on this device.\n");
break;
case CONFLICT_TYPE_PNP_WARM:
pnp_printf(buffer, "active PnP device ");
break;
case CONFLICT_TYPE_PNP_COLD:
pnp_printf(buffer, "disabled PnP device ");
break;
default:
pnp_printf(buffer, "Unknown conflict.\n");
break;
}
}
static void pnp_print_conflict(pnp_info_buffer_t *buffer, struct pnp_dev * dev, int idx, int type)
{
struct pnp_dev * cdev, * wdev = NULL;
int conflict;
switch (type) {
case IORESOURCE_IO:
conflict = pnp_check_port(dev, idx);
if (conflict == CONFLICT_TYPE_PNP_WARM)
wdev = pnp_check_port_conflicts(dev, idx, SEARCH_WARM);
cdev = pnp_check_port_conflicts(dev, idx, SEARCH_COLD);
break;
case IORESOURCE_MEM:
conflict = pnp_check_mem(dev, idx);
if (conflict == CONFLICT_TYPE_PNP_WARM)
wdev = pnp_check_mem_conflicts(dev, idx, SEARCH_WARM);
cdev = pnp_check_mem_conflicts(dev, idx, SEARCH_COLD);
break;
case IORESOURCE_IRQ:
conflict = pnp_check_irq(dev, idx);
if (conflict == CONFLICT_TYPE_PNP_WARM)
wdev = pnp_check_irq_conflicts(dev, idx, SEARCH_WARM);
cdev = pnp_check_irq_conflicts(dev, idx, SEARCH_COLD);
break;
case IORESOURCE_DMA:
conflict = pnp_check_dma(dev, idx);
if (conflict == CONFLICT_TYPE_PNP_WARM)
wdev = pnp_check_dma_conflicts(dev, idx, SEARCH_WARM);
cdev = pnp_check_dma_conflicts(dev, idx, SEARCH_COLD);
break;
default:
return;
}
pnp_print_conflict_desc(buffer, conflict);
static DEVICE_ATTR(options,S_IRUGO,pnp_show_options,NULL);
if (wdev)
pnp_print_conflict_node(buffer, wdev);
if (cdev) {
pnp_print_conflict_desc(buffer, CONFLICT_TYPE_PNP_COLD);
pnp_print_conflict_node(buffer, cdev);
}
}
static ssize_t pnp_show_current_resources(struct device *dmdev, char *buf)
{
......@@ -332,12 +250,6 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, char *buf)
buffer->buffer = buf;
buffer->curr = buffer->buffer;
pnp_printf(buffer,"mode = ");
if (dev->config_mode & PNP_CONFIG_MANUAL)
pnp_printf(buffer,"manual\n");
else
pnp_printf(buffer,"auto\n");
pnp_printf(buffer,"state = ");
if (dev->active)
pnp_printf(buffer,"active\n");
......@@ -350,7 +262,6 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, char *buf)
pnp_printf(buffer," 0x%lx-0x%lx \n",
pnp_port_start(dev, i),
pnp_port_end(dev, i));
pnp_print_conflict(buffer, dev, i, IORESOURCE_IO);
}
}
for (i = 0; i < PNP_MAX_MEM; i++) {
......@@ -359,21 +270,18 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, char *buf)
pnp_printf(buffer," 0x%lx-0x%lx \n",
pnp_mem_start(dev, i),
pnp_mem_end(dev, i));
pnp_print_conflict(buffer, dev, i, IORESOURCE_MEM);
}
}
for (i = 0; i < PNP_MAX_IRQ; i++) {
if (pnp_irq_valid(dev, i)) {
pnp_printf(buffer,"irq");
pnp_printf(buffer," %ld \n", pnp_irq(dev, i));
pnp_print_conflict(buffer, dev, i, IORESOURCE_IRQ);
}
}
for (i = 0; i < PNP_MAX_DMA; i++) {
if (pnp_dma_valid(dev, i)) {
pnp_printf(buffer,"dma");
pnp_printf(buffer," %ld \n", pnp_dma(dev, i));
pnp_print_conflict(buffer, dev, i, IORESOURCE_DMA);
}
}
ret = (buffer->curr - buf);
......@@ -381,7 +289,7 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, char *buf)
return ret;
}
extern int pnp_resolve_conflicts(struct pnp_dev *dev);
extern struct semaphore pnp_res_mutex;
static ssize_t
pnp_set_current_resources(struct device * dmdev, const char * ubuf, size_t count)
......@@ -390,6 +298,12 @@ pnp_set_current_resources(struct device * dmdev, const char * ubuf, size_t count
char *buf = (void *)ubuf;
int retval = 0;
if (dev->status & PNP_ATTACHED) {
retval = -EBUSY;
pnp_info("Device %s cannot be configured because it is in use.", dev->dev.bus_id);
goto done;
}
while (isspace(*buf))
++buf;
if (!strnicmp(buf,"disable",7)) {
......@@ -400,41 +314,30 @@ pnp_set_current_resources(struct device * dmdev, const char * ubuf, size_t count
retval = pnp_activate_dev(dev);
goto done;
}
if (!strnicmp(buf,"reset",5)) {
if (!dev->active)
goto done;
retval = pnp_disable_dev(dev);
if (retval)
if (!strnicmp(buf,"fill",4)) {
if (dev->active)
goto done;
retval = pnp_activate_dev(dev);
retval = pnp_auto_config_dev(dev);
goto done;
}
if (!strnicmp(buf,"auto",4)) {
if (dev->active)
goto done;
pnp_init_resources(&dev->res);
retval = pnp_auto_config_dev(dev);
goto done;
}
if (!strnicmp(buf,"clear",5)) {
if (dev->active)
goto done;
spin_lock(&pnp_lock);
dev->config_mode = PNP_CONFIG_MANUAL;
pnp_init_resource_table(&dev->res);
if (dev->rule)
dev->rule->depnum = 0;
spin_unlock(&pnp_lock);
goto done;
}
if (!strnicmp(buf,"resolve",7)) {
retval = pnp_resolve_conflicts(dev);
pnp_init_resources(&dev->res);
goto done;
}
if (!strnicmp(buf,"get",3)) {
spin_lock(&pnp_lock);
down(&pnp_res_mutex);
if (pnp_can_read(dev))
dev->protocol->get(dev, &dev->res);
spin_unlock(&pnp_lock);
up(&pnp_res_mutex);
goto done;
}
if (!strnicmp(buf,"set",3)) {
......@@ -442,9 +345,8 @@ pnp_set_current_resources(struct device * dmdev, const char * ubuf, size_t count
if (dev->active)
goto done;
buf += 3;
spin_lock(&pnp_lock);
dev->config_mode = PNP_CONFIG_MANUAL;
pnp_init_resource_table(&dev->res);
pnp_init_resources(&dev->res);
down(&pnp_res_mutex);
while (1) {
while (isspace(*buf))
++buf;
......@@ -514,7 +416,7 @@ pnp_set_current_resources(struct device * dmdev, const char * ubuf, size_t count
}
break;
}
spin_unlock(&pnp_lock);
up(&pnp_res_mutex);
goto done;
}
done:
......@@ -543,7 +445,7 @@ static DEVICE_ATTR(id,S_IRUGO,pnp_show_current_ids,NULL);
int pnp_interface_attach_device(struct pnp_dev *dev)
{
device_create_file(&dev->dev,&dev_attr_possible);
device_create_file(&dev->dev,&dev_attr_options);
device_create_file(&dev->dev,&dev_attr_resources);
device_create_file(&dev->dev,&dev_attr_id);
return 0;
......
......@@ -31,6 +31,7 @@
* 2002-06-06 Made the use of dma channel 0 configurable
* Gerald Teschl <gerald.teschl@univie.ac.at>
* 2002-10-06 Ported to PnP Layer - Adam Belay <ambx1@neo.rr.com>
* 2003-08-11 Resource Management Updates - Adam Belay <ambx1@neo.rr.com>
*/
#include <linux/config.h>
......@@ -54,7 +55,6 @@
int isapnp_disable; /* Disable ISA PnP */
int isapnp_rdp; /* Read Data Port */
int isapnp_reset = 1; /* reset all PnP cards (deactivate) */
int isapnp_skip_pci_scan; /* skip PCI resource scanning */
int isapnp_verbose = 1; /* verbose mode */
MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
......@@ -66,8 +66,6 @@ MODULE_PARM_DESC(isapnp_rdp, "ISA Plug & Play read data port");
MODULE_PARM(isapnp_reset, "i");
MODULE_PARM_DESC(isapnp_reset, "ISA Plug & Play reset all cards");
MODULE_PARM(isapnp_allow_dma0, "i");
MODULE_PARM(isapnp_skip_pci_scan, "i");
MODULE_PARM_DESC(isapnp_skip_pci_scan, "ISA Plug & Play skip PCI resource scanning");
MODULE_PARM(isapnp_verbose, "i");
MODULE_PARM_DESC(isapnp_verbose, "ISA Plug & Play verbose mode");
MODULE_LICENSE("GPL");
......@@ -460,6 +458,7 @@ static struct pnp_dev * __init isapnp_parse_device(struct pnp_card *card, int si
dev->capabilities |= PNP_READ;
dev->capabilities |= PNP_WRITE;
dev->capabilities |= PNP_DISABLE;
pnp_init_resources(&dev->res);
return dev;
}
......@@ -468,8 +467,8 @@ static struct pnp_dev * __init isapnp_parse_device(struct pnp_card *card, int si
* Add IRQ resource to resources list.
*/
static void __init isapnp_add_irq_resource(struct pnp_dev *dev,
int depnum, int size)
static void __init isapnp_parse_irq_resource(struct pnp_option *option,
int size)
{
unsigned char tmp[3];
struct pnp_irq *irq;
......@@ -483,7 +482,7 @@ static void __init isapnp_add_irq_resource(struct pnp_dev *dev,
irq->flags = tmp[2];
else
irq->flags = IORESOURCE_IRQ_HIGHEDGE;
pnp_add_irq_resource(dev, depnum, irq);
pnp_register_irq_resource(option, irq);
return;
}
......@@ -491,8 +490,8 @@ static void __init isapnp_add_irq_resource(struct pnp_dev *dev,
* Add DMA resource to resources list.
*/
static void __init isapnp_add_dma_resource(struct pnp_dev *dev,
int depnum, int size)
static void __init isapnp_parse_dma_resource(struct pnp_option *option,
int size)
{
unsigned char tmp[2];
struct pnp_dma *dma;
......@@ -503,7 +502,7 @@ static void __init isapnp_add_dma_resource(struct pnp_dev *dev,
return;
dma->map = tmp[0];
dma->flags = tmp[1];
pnp_add_dma_resource(dev, depnum, dma);
pnp_register_dma_resource(option, dma);
return;
}
......@@ -511,8 +510,8 @@ static void __init isapnp_add_dma_resource(struct pnp_dev *dev,
* Add port resource to resources list.
*/
static void __init isapnp_add_port_resource(struct pnp_dev *dev,
int depnum, int size)
static void __init isapnp_parse_port_resource(struct pnp_option *option,
int size)
{
unsigned char tmp[7];
struct pnp_port *port;
......@@ -526,7 +525,7 @@ static void __init isapnp_add_port_resource(struct pnp_dev *dev,
port->align = tmp[5];
port->size = tmp[6];
port->flags = tmp[0] ? PNP_PORT_FLAG_16BITADDR : 0;
pnp_add_port_resource(dev,depnum,port);
pnp_register_port_resource(option,port);
return;
}
......@@ -534,8 +533,8 @@ static void __init isapnp_add_port_resource(struct pnp_dev *dev,
* Add fixed port resource to resources list.
*/
static void __init isapnp_add_fixed_port_resource(struct pnp_dev *dev,
int depnum, int size)
static void __init isapnp_parse_fixed_port_resource(struct pnp_option *option,
int size)
{
unsigned char tmp[3];
struct pnp_port *port;
......@@ -548,7 +547,7 @@ static void __init isapnp_add_fixed_port_resource(struct pnp_dev *dev,
port->size = tmp[2];
port->align = 0;
port->flags = PNP_PORT_FLAG_FIXED;
pnp_add_port_resource(dev,depnum,port);
pnp_register_port_resource(option,port);
return;
}
......@@ -556,8 +555,8 @@ static void __init isapnp_add_fixed_port_resource(struct pnp_dev *dev,
* Add memory resource to resources list.
*/
static void __init isapnp_add_mem_resource(struct pnp_dev *dev,
int depnum, int size)
static void __init isapnp_parse_mem_resource(struct pnp_option *option,
int size)
{
unsigned char tmp[9];
struct pnp_mem *mem;
......@@ -571,7 +570,7 @@ static void __init isapnp_add_mem_resource(struct pnp_dev *dev,
mem->align = (tmp[6] << 8) | tmp[5];
mem->size = ((tmp[8] << 8) | tmp[7]) << 8;
mem->flags = tmp[0];
pnp_add_mem_resource(dev,depnum,mem);
pnp_register_mem_resource(option,mem);
return;
}
......@@ -579,8 +578,8 @@ static void __init isapnp_add_mem_resource(struct pnp_dev *dev,
* Add 32-bit memory resource to resources list.
*/
static void __init isapnp_add_mem32_resource(struct pnp_dev *dev,
int depnum, int size)
static void __init isapnp_parse_mem32_resource(struct pnp_option *option,
int size)
{
unsigned char tmp[17];
struct pnp_mem *mem;
......@@ -594,15 +593,15 @@ static void __init isapnp_add_mem32_resource(struct pnp_dev *dev,
mem->align = (tmp[12] << 24) | (tmp[11] << 16) | (tmp[10] << 8) | tmp[9];
mem->size = (tmp[16] << 24) | (tmp[15] << 16) | (tmp[14] << 8) | tmp[13];
mem->flags = tmp[0];
pnp_add_mem_resource(dev,depnum,mem);
pnp_register_mem_resource(option,mem);
}
/*
* Add 32-bit fixed memory resource to resources list.
*/
static void __init isapnp_add_fixed_mem32_resource(struct pnp_dev *dev,
int depnum, int size)
static void __init isapnp_parse_fixed_mem32_resource(struct pnp_option *option,
int size)
{
unsigned char tmp[9];
struct pnp_mem *mem;
......@@ -615,14 +614,14 @@ static void __init isapnp_add_fixed_mem32_resource(struct pnp_dev *dev,
mem->size = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5];
mem->align = 0;
mem->flags = tmp[0];
pnp_add_mem_resource(dev,depnum,mem);
pnp_register_mem_resource(option,mem);
}
/*
* Parse card name for ISA PnP device.
*/
static void __init
static void __init
isapnp_parse_name(char *name, unsigned int name_max, unsigned short *size)
{
if (name[0] == '\0') {
......@@ -634,7 +633,7 @@ isapnp_parse_name(char *name, unsigned int name_max, unsigned short *size)
/* clean whitespace from end of string */
while (size1 > 0 && name[--size1] == ' ')
name[size1] = '\0';
}
}
}
/*
......@@ -644,14 +643,17 @@ isapnp_parse_name(char *name, unsigned int name_max, unsigned short *size)
static int __init isapnp_create_device(struct pnp_card *card,
unsigned short size)
{
int number = 0, skip = 0, depnum = 0, dependent = 0, compat = 0;
int number = 0, skip = 0, priority = 0, compat = 0;
unsigned char type, tmp[17];
struct pnp_option *option;
struct pnp_dev *dev;
if ((dev = isapnp_parse_device(card, size, number++)) == NULL)
return 1;
if (pnp_build_resource(dev, 0) == NULL)
option = pnp_register_independent_option(dev);
if (!option)
return 1;
pnp_add_card_device(card,dev);
while (1) {
if (isapnp_read_tag(&type, &size)<0)
return 1;
......@@ -662,15 +664,16 @@ static int __init isapnp_create_device(struct pnp_card *card,
if (size >= 5 && size <= 6) {
if ((dev = isapnp_parse_device(card, size, number++)) == NULL)
return 1;
pnp_build_resource(dev,0);
pnp_add_card_device(card,dev);
size = 0;
skip = 0;
option = pnp_register_independent_option(dev);
if (!option)
return 1;
pnp_add_card_device(card,dev);
} else {
skip = 1;
}
dependent = 0;
depnum = 0;
priority = 0;
compat = 0;
break;
case _STAG_COMPATDEVID:
......@@ -684,43 +687,43 @@ static int __init isapnp_create_device(struct pnp_card *card,
case _STAG_IRQ:
if (size < 2 || size > 3)
goto __skip;
isapnp_add_irq_resource(dev, depnum, size);
isapnp_parse_irq_resource(option, size);
size = 0;
break;
case _STAG_DMA:
if (size != 2)
goto __skip;
isapnp_add_dma_resource(dev, depnum, size);
isapnp_parse_dma_resource(option, size);
size = 0;
break;
case _STAG_STARTDEP:
if (size > 1)
goto __skip;
dependent = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE;
priority = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE;
if (size > 0) {
isapnp_peek(tmp, size);
dependent = 0x100 | tmp[0];
priority = 0x100 | tmp[0];
size = 0;
}
pnp_build_resource(dev,dependent);
depnum = pnp_get_max_depnum(dev);
option = pnp_register_dependent_option(dev,priority);
if (!option)
return 1;
break;
case _STAG_ENDDEP:
if (size != 0)
goto __skip;
dependent = 0;
depnum = 0;
priority = 0;
break;
case _STAG_IOPORT:
if (size != 7)
goto __skip;
isapnp_add_port_resource(dev, depnum, size);
isapnp_parse_port_resource(option, size);
size = 0;
break;
case _STAG_FIXEDIO:
if (size != 3)
goto __skip;
isapnp_add_fixed_port_resource(dev, depnum, size);
isapnp_parse_fixed_port_resource(option, size);
size = 0;
break;
case _STAG_VENDOR:
......@@ -728,7 +731,7 @@ static int __init isapnp_create_device(struct pnp_card *card,
case _LTAG_MEMRANGE:
if (size != 9)
goto __skip;
isapnp_add_mem_resource(dev, depnum, size);
isapnp_parse_mem_resource(option, size);
size = 0;
break;
case _LTAG_ANSISTR:
......@@ -743,13 +746,13 @@ static int __init isapnp_create_device(struct pnp_card *card,
case _LTAG_MEM32RANGE:
if (size != 17)
goto __skip;
isapnp_add_mem32_resource(dev, depnum, size);
isapnp_parse_mem32_resource(option, size);
size = 0;
break;
case _LTAG_FIXEDMEM32RANGE:
if (size != 9)
goto __skip;
isapnp_add_fixed_mem32_resource(dev, depnum, size);
isapnp_parse_fixed_mem32_resource(option, size);
size = 0;
break;
case _STAG_END:
......@@ -859,63 +862,6 @@ static void isapnp_parse_card_id(struct pnp_card * card, unsigned short vendor,
pnp_add_card_id(id,card);
}
static int isapnp_parse_current_resources(struct pnp_dev *dev, struct pnp_resource_table * res)
{
int tmp, ret;
struct pnp_rule_table rule;
if (dev->rule)
rule = *dev->rule;
else {
if (!pnp_generate_rule(dev,1,&rule))
return -EINVAL;
}
dev->active = isapnp_read_byte(ISAPNP_CFG_ACTIVATE);
if (dev->active) {
for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) {
ret = isapnp_read_word(ISAPNP_CFG_PORT + (tmp << 1));
if (!ret)
continue;
res->port_resource[tmp].start = ret;
if (rule.port[tmp])
res->port_resource[tmp].end = ret + rule.port[tmp]->size - 1;
else
res->port_resource[tmp].end = ret + 1; /* all we can do is assume 1 :-( */
res->port_resource[tmp].flags = IORESOURCE_IO;
}
for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
ret = isapnp_read_dword(ISAPNP_CFG_MEM + (tmp << 3));
if (!ret)
continue;
res->mem_resource[tmp].start = ret;
if (rule.mem[tmp])
res->mem_resource[tmp].end = ret + rule.mem[tmp]->size - 1;
else
res->mem_resource[tmp].end = ret + 1; /* all we can do is assume 1 :-( */
res->mem_resource[tmp].flags = IORESOURCE_MEM;
}
for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
ret = (isapnp_read_word(ISAPNP_CFG_IRQ + (tmp << 1)) >> 8);
if (!ret)
continue;
res->irq_resource[tmp].start = res->irq_resource[tmp].end = ret;
res->irq_resource[tmp].flags = IORESOURCE_IRQ;
}
for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
ret = isapnp_read_byte(ISAPNP_CFG_DMA + tmp);
if (ret == 4)
continue;
if (rule.dma[tmp]) { /* some isapnp systems forget to set this to 4 so we have to check */
res->dma_resource[tmp].start = res->dma_resource[tmp].end = ret;
res->dma_resource[tmp].flags = IORESOURCE_DMA;
}
}
}
return 0;
}
/*
* Build device list for all present ISA PnP devices.
*/
......@@ -925,7 +871,6 @@ static int __init isapnp_build_device_list(void)
int csn;
unsigned char header[9], checksum;
struct pnp_card *card;
struct pnp_dev *dev;
isapnp_wait();
isapnp_key();
......@@ -959,13 +904,6 @@ static int __init isapnp_build_device_list(void)
card->checksum = isapnp_checksum_value;
card->protocol = &isapnp_protocol;
/* read the current resource data */
card_for_each_dev(card,dev) {
isapnp_device(dev->number);
pnp_init_resource_table(&dev->res);
isapnp_parse_current_resources(dev, &dev->res);
}
pnp_add_card(card);
}
isapnp_wait();
......@@ -1041,12 +979,50 @@ EXPORT_SYMBOL(isapnp_write_dword);
EXPORT_SYMBOL(isapnp_wake);
EXPORT_SYMBOL(isapnp_device);
static int isapnp_read_resources(struct pnp_dev *dev, struct pnp_resource_table *res)
{
int tmp, ret;
dev->active = isapnp_read_byte(ISAPNP_CFG_ACTIVATE);
if (dev->active) {
for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) {
ret = isapnp_read_word(ISAPNP_CFG_PORT + (tmp << 1));
if (!ret)
continue;
res->port_resource[tmp].start = ret;
res->port_resource[tmp].flags = IORESOURCE_IO;
}
for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
ret = isapnp_read_dword(ISAPNP_CFG_MEM + (tmp << 3));
if (!ret)
continue;
res->mem_resource[tmp].start = ret;
res->mem_resource[tmp].flags = IORESOURCE_MEM;
}
for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
ret = (isapnp_read_word(ISAPNP_CFG_IRQ + (tmp << 1)) >> 8);
if (!ret)
continue;
res->irq_resource[tmp].start = res->irq_resource[tmp].end = ret;
res->irq_resource[tmp].flags = IORESOURCE_IRQ;
}
for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
ret = isapnp_read_byte(ISAPNP_CFG_DMA + tmp);
if (ret == 4)
continue;
res->dma_resource[tmp].start = res->dma_resource[tmp].end = ret;
res->dma_resource[tmp].flags = IORESOURCE_DMA;
}
}
return 0;
}
static int isapnp_get_resources(struct pnp_dev *dev, struct pnp_resource_table * res)
{
int ret;
pnp_init_resource_table(res);
pnp_init_resources(res);
isapnp_cfg_begin(dev->card->number, dev->number);
ret = isapnp_parse_current_resources(dev, res);
ret = isapnp_read_resources(dev, res);
isapnp_cfg_end();
return ret;
}
......@@ -1196,7 +1172,6 @@ static int __init isapnp_setup_isapnp(char *str)
{
(void)((get_option(&str,&isapnp_rdp) == 2) &&
(get_option(&str,&isapnp_reset) == 2) &&
(get_option(&str,&isapnp_skip_pci_scan) == 2) &&
(get_option(&str,&isapnp_verbose) == 2));
return 1;
}
......
/*
* manager.c - Resource Management, Conflict Resolution, Activation and Disabling of Devices
*
* based on isapnp.c resource management (c) Jaroslav Kysela <perex@suse.cz>
* Copyright 2003 Adam Belay <ambx1@neo.rr.com>
*
*/
......@@ -20,551 +21,341 @@
#include <linux/pnp.h>
#include "base.h"
DECLARE_MUTEX(pnp_res_mutex);
int pnp_max_moves = 4;
static int pnp_next_port(struct pnp_dev * dev, int idx)
static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
{
struct pnp_port *port;
unsigned long *start, *end, *flags;
if (!dev || idx < 0 || idx >= PNP_MAX_PORT)
return 0;
port = dev->rule->port[idx];
if (!port)
if (!dev || !rule)
return -EINVAL;
if (idx >= PNP_MAX_PORT) {
pnp_err("More than 4 ports is incompatible with pnp specifications.");
/* pretend we were successful so at least the manager won't try again */
return 1;
}
/* check if this resource has been manually set, if so skip */
if (!(dev->res.port_resource[idx].flags & IORESOURCE_AUTO))
return 1;
start = &dev->res.port_resource[idx].start;
end = &dev->res.port_resource[idx].end;
flags = &dev->res.port_resource[idx].flags;
/* set the initial values if this is the first time */
if (*start == 0) {
*start = port->min;
*end = *start + port->size - 1;
*flags = port->flags | IORESOURCE_IO;
if (!pnp_check_port(dev, idx))
return 1;
}
/* set the initial values */
*start = rule->min;
*end = *start + rule->size - 1;
*flags = *flags | rule->flags | IORESOURCE_IO;
/* run through until pnp_check_port is happy */
do {
*start += port->align;
*end = *start + port->size - 1;
if (*start > port->max || !port->align)
while (!pnp_check_port(dev, idx)) {
*start += rule->align;
*end = *start + rule->size - 1;
if (*start > rule->max || !rule->align)
return 0;
} while (pnp_check_port(dev, idx));
}
return 1;
}
static int pnp_next_mem(struct pnp_dev * dev, int idx)
static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
{
struct pnp_mem *mem;
unsigned long *start, *end, *flags;
if (!dev || idx < 0 || idx >= PNP_MAX_MEM)
return 0;
mem = dev->rule->mem[idx];
if (!mem)
if (!dev || !rule)
return -EINVAL;
if (idx >= PNP_MAX_MEM) {
pnp_err("More than 8 mems is incompatible with pnp specifications.");
/* pretend we were successful so at least the manager won't try again */
return 1;
}
/* check if this resource has been manually set, if so skip */
if (!(dev->res.mem_resource[idx].flags & IORESOURCE_AUTO))
return 1;
start = &dev->res.mem_resource[idx].start;
end = &dev->res.mem_resource[idx].end;
flags = &dev->res.mem_resource[idx].flags;
/* set the initial values if this is the first time */
if (*start == 0) {
*start = mem->min;
*end = *start + mem->size -1;
*flags = mem->flags | IORESOURCE_MEM;
if (!(mem->flags & IORESOURCE_MEM_WRITEABLE))
*flags |= IORESOURCE_READONLY;
if (mem->flags & IORESOURCE_MEM_CACHEABLE)
*flags |= IORESOURCE_CACHEABLE;
if (mem->flags & IORESOURCE_MEM_RANGELENGTH)
*flags |= IORESOURCE_RANGELENGTH;
if (mem->flags & IORESOURCE_MEM_SHADOWABLE)
*flags |= IORESOURCE_SHADOWABLE;
if (!pnp_check_mem(dev, idx))
return 1;
}
/* set the initial values */
*start = rule->min;
*end = *start + rule->size -1;
*flags = *flags | rule->flags | IORESOURCE_MEM;
/* convert pnp flags to standard Linux flags */
if (!(rule->flags & IORESOURCE_MEM_WRITEABLE))
*flags |= IORESOURCE_READONLY;
if (rule->flags & IORESOURCE_MEM_CACHEABLE)
*flags |= IORESOURCE_CACHEABLE;
if (rule->flags & IORESOURCE_MEM_RANGELENGTH)
*flags |= IORESOURCE_RANGELENGTH;
if (rule->flags & IORESOURCE_MEM_SHADOWABLE)
*flags |= IORESOURCE_SHADOWABLE;
/* run through until pnp_check_mem is happy */
do {
*start += mem->align;
*end = *start + mem->size - 1;
if (*start > mem->max || !mem->align)
while (!pnp_check_mem(dev, idx)) {
*start += rule->align;
*end = *start + rule->size - 1;
if (*start > rule->max || !rule->align)
return 0;
} while (pnp_check_mem(dev, idx));
}
return 1;
}
static int pnp_next_irq(struct pnp_dev * dev, int idx)
static int pnp_assign_irq(struct pnp_dev * dev, struct pnp_irq *rule, int idx)
{
struct pnp_irq *irq;
unsigned long *start, *end, *flags;
int i, mask;
if (!dev || idx < 0 || idx >= PNP_MAX_IRQ)
return 0;
irq = dev->rule->irq[idx];
if (!irq)
return 1;
int i;
start = &dev->res.irq_resource[idx].start;
end = &dev->res.irq_resource[idx].end;
flags = &dev->res.irq_resource[idx].flags;
/* IRQ priority: this table is good for i386 */
static unsigned short xtab[16] = {
5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2
};
/* set the initial values if this is the first time */
if (*start == -1) {
*start = *end = 0;
*flags = irq->flags | IORESOURCE_IRQ;
if (!pnp_check_irq(dev, idx))
return 1;
}
if (!dev || !rule)
return -EINVAL;
mask = irq->map;
for (i = *start + 1; i < 16; i++)
{
if(mask>>i & 0x01) {
*start = *end = i;
if(!pnp_check_irq(dev, idx))
return 1;
}
if (idx >= PNP_MAX_IRQ) {
pnp_err("More than 2 irqs is incompatible with pnp specifications.");
/* pretend we were successful so at least the manager won't try again */
return 1;
}
return 0;
}
static int pnp_next_dma(struct pnp_dev * dev, int idx)
{
struct pnp_dma *dma;
unsigned long *start, *end, *flags;
int i, mask;
if (!dev || idx < 0 || idx >= PNP_MAX_DMA)
return -EINVAL;
dma = dev->rule->dma[idx];
if (!dma)
/* check if this resource has been manually set, if so skip */
if (!(dev->res.irq_resource[idx].flags & IORESOURCE_AUTO))
return 1;
start = &dev->res.dma_resource[idx].start;
end = &dev->res.dma_resource[idx].end;
flags = &dev->res.dma_resource[idx].flags;
start = &dev->res.irq_resource[idx].start;
end = &dev->res.irq_resource[idx].end;
flags = &dev->res.irq_resource[idx].flags;
/* set the initial values if this is the first time */
if (*start == -1) {
*start = *end = 0;
*flags = dma->flags | IORESOURCE_DMA;
if (!pnp_check_dma(dev, idx))
return 1;
}
/* set the initial values */
*flags = *flags | rule->flags | IORESOURCE_IRQ;
mask = dma->map;
for (i = *start + 1; i < 8; i++)
{
if(mask>>i & 0x01) {
*start = *end = i;
if(!pnp_check_dma(dev, idx))
for (i = 0; i < 16; i++) {
if(rule->map & (1<<xtab[i])) {
*start = *end = xtab[i];
if(pnp_check_irq(dev, idx))
return 1;
}
}
return 0;
}
static int pnp_next_rule(struct pnp_dev *dev)
{
int depnum = dev->rule->depnum;
int max = pnp_get_max_depnum(dev);
int priority = PNP_RES_PRIORITY_PREFERRED;
if (depnum < 0)
return 0;
if (max == 0) {
if (pnp_generate_rule(dev, 0, dev->rule)) {
dev->rule->depnum = -1;
return 1;
}
}
if(depnum > 0) {
struct pnp_resources * res = pnp_find_resources(dev, depnum);
priority = res->priority;
}
for (; priority <= PNP_RES_PRIORITY_FUNCTIONAL; priority++, depnum = 0) {
depnum += 1;
for (; depnum <= max; depnum++) {
struct pnp_resources * res = pnp_find_resources(dev, depnum);
if (res->priority == priority) {
if(pnp_generate_rule(dev, depnum, dev->rule)) {
dev->rule->depnum = depnum;
return 1;
}
}
}
}
return 0;
}
struct pnp_change {
struct list_head change_list;
struct list_head changes;
struct pnp_resource_table res_bak;
struct pnp_rule_table rule_bak;
struct pnp_dev * dev;
};
static void pnp_free_changes(struct pnp_change * parent)
{
struct list_head * pos, * temp;
list_for_each_safe(pos, temp, &parent->changes) {
struct pnp_change * change = list_entry(pos, struct pnp_change, change_list);
list_del(&change->change_list);
kfree(change);
}
}
static void pnp_undo_changes(struct pnp_change * parent)
{
struct list_head * pos, * temp;
list_for_each_safe(pos, temp, &parent->changes) {
struct pnp_change * change = list_entry(pos, struct pnp_change, change_list);
*change->dev->rule = change->rule_bak;
change->dev->res = change->res_bak;
list_del(&change->change_list);
kfree(change);
}
}
static struct pnp_change * pnp_add_change(struct pnp_change * parent, struct pnp_dev * dev)
{
struct pnp_change * change = pnp_alloc(sizeof(struct pnp_change));
if (!change)
return NULL;
change->res_bak = dev->res;
change->rule_bak = *dev->rule;
change->dev = dev;
INIT_LIST_HEAD(&change->changes);
if (parent)
list_add(&change->change_list, &parent->changes);
return change;
}
static void pnp_commit_changes(struct pnp_change * parent, struct pnp_change * change)
{
/* check if it's the root change */
if (!parent)
return;
if (!list_empty(&change->changes))
list_splice_init(&change->changes, &parent->changes);
}
static int pnp_next_config(struct pnp_dev * dev, int move, struct pnp_change * parent);
static int pnp_next_request(struct pnp_dev * dev, int move, struct pnp_change * parent, struct pnp_change * change)
static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
{
unsigned long *start, *end, *flags;
int i;
struct pnp_dev * cdev;
for (i = 0; i < PNP_MAX_PORT; i++) {
if (dev->res.port_resource[i].start == 0
|| pnp_check_port_conflicts(dev,i,SEARCH_WARM)) {
if (!pnp_next_port(dev,i))
return 0;
}
do {
cdev = pnp_check_port_conflicts(dev,i,SEARCH_COLD);
if (cdev && (!move || !pnp_next_config(cdev,move,change))) {
pnp_undo_changes(change);
if (!pnp_next_port(dev,i))
return 0;
}
} while (cdev);
pnp_commit_changes(parent, change);
}
for (i = 0; i < PNP_MAX_MEM; i++) {
if (dev->res.mem_resource[i].start == 0
|| pnp_check_mem_conflicts(dev,i,SEARCH_WARM)) {
if (!pnp_next_mem(dev,i))
return 0;
}
do {
cdev = pnp_check_mem_conflicts(dev,i,SEARCH_COLD);
if (cdev && (!move || !pnp_next_config(cdev,move,change))) {
pnp_undo_changes(change);
if (!pnp_next_mem(dev,i))
return 0;
}
} while (cdev);
pnp_commit_changes(parent, change);
}
for (i = 0; i < PNP_MAX_IRQ; i++) {
if (dev->res.irq_resource[i].start == -1
|| pnp_check_irq_conflicts(dev,i,SEARCH_WARM)) {
if (!pnp_next_irq(dev,i))
return 0;
}
do {
cdev = pnp_check_irq_conflicts(dev,i,SEARCH_COLD);
if (cdev && (!move || !pnp_next_config(cdev,move,change))) {
pnp_undo_changes(change);
if (!pnp_next_irq(dev,i))
return 0;
}
} while (cdev);
pnp_commit_changes(parent, change);
}
for (i = 0; i < PNP_MAX_DMA; i++) {
if (dev->res.dma_resource[i].start == -1
|| pnp_check_dma_conflicts(dev,i,SEARCH_WARM)) {
if (!pnp_next_dma(dev,i))
return 0;
}
do {
cdev = pnp_check_dma_conflicts(dev,i,SEARCH_COLD);
if (cdev && (!move || !pnp_next_config(cdev,move,change))) {
pnp_undo_changes(change);
if (!pnp_next_dma(dev,i))
return 0;
}
} while (cdev);
pnp_commit_changes(parent, change);
}
return 1;
}
static int pnp_next_config(struct pnp_dev * dev, int move, struct pnp_change * parent)
{
struct pnp_change * change;
move--;
if (!dev->rule)
return 0;
change = pnp_add_change(parent,dev);
if (!change)
return 0;
if (!pnp_can_configure(dev))
goto fail;
if (!dev->rule->depnum) {
if (!pnp_next_rule(dev))
goto fail;
}
while (!pnp_next_request(dev, move, parent, change)) {
if(!pnp_next_rule(dev))
goto fail;
pnp_init_resource_table(&dev->res);
}
if (!parent) {
pnp_free_changes(change);
kfree(change);
}
return 1;
/* DMA priority: this table is good for i386 */
static unsigned short xtab[8] = {
1, 3, 5, 6, 7, 0, 2, 4
};
fail:
if (!parent)
kfree(change);
return 0;
}
if (!dev || !rule)
return -EINVAL;
/* this advanced algorithm will shuffle other configs to make room and ensure that the most possible devices have configs */
static int pnp_advanced_config(struct pnp_dev * dev)
{
int move;
/* if the device cannot be configured skip it */
if (!pnp_can_configure(dev))
if (idx >= PNP_MAX_DMA) {
pnp_err("More than 2 dmas is incompatible with pnp specifications.");
/* pretend we were successful so at least the manager won't try again */
return 1;
if (!dev->rule) {
dev->rule = pnp_alloc(sizeof(struct pnp_rule_table));
if (!dev->rule)
return -ENOMEM;
}
spin_lock(&pnp_lock);
for (move = 1; move <= pnp_max_moves; move++) {
dev->rule->depnum = 0;
pnp_init_resource_table(&dev->res);
if (pnp_next_config(dev,move,NULL)) {
spin_unlock(&pnp_lock);
return 1;
}
}
/* check if this resource has been manually set, if so skip */
if (!(dev->res.dma_resource[idx].flags & IORESOURCE_AUTO))
return 1;
pnp_init_resource_table(&dev->res);
dev->rule->depnum = 0;
spin_unlock(&pnp_lock);
pnp_err("res: Unable to resolve resource conflicts for the device '%s', some devices may not be usable.", dev->dev.bus_id);
return 0;
}
start = &dev->res.dma_resource[idx].start;
end = &dev->res.dma_resource[idx].end;
flags = &dev->res.dma_resource[idx].flags;
int pnp_resolve_conflicts(struct pnp_dev *dev)
{
int i;
struct pnp_dev * cdev;
for (i = 0; i < PNP_MAX_PORT; i++)
{
do {
cdev = pnp_check_port_conflicts(dev,i,SEARCH_COLD);
if (cdev)
pnp_advanced_config(cdev);
} while (cdev);
}
for (i = 0; i < PNP_MAX_MEM; i++)
{
do {
cdev = pnp_check_mem_conflicts(dev,i,SEARCH_COLD);
if (cdev)
pnp_advanced_config(cdev);
} while (cdev);
}
for (i = 0; i < PNP_MAX_IRQ; i++)
{
do {
cdev = pnp_check_irq_conflicts(dev,i,SEARCH_COLD);
if (cdev)
pnp_advanced_config(cdev);
} while (cdev);
}
for (i = 0; i < PNP_MAX_DMA; i++)
{
do {
cdev = pnp_check_dma_conflicts(dev,i,SEARCH_COLD);
if (cdev)
pnp_advanced_config(cdev);
} while (cdev);
}
return 1;
}
/* set the initial values */
*flags = *flags | rule->flags | IORESOURCE_DMA;
/* this is a much faster algorithm but it may not leave resources for other devices to use */
static int pnp_simple_config(struct pnp_dev * dev)
{
int i;
spin_lock(&pnp_lock);
if (dev->active) {
spin_unlock(&pnp_lock);
return 1;
}
if (!dev->rule) {
dev->rule = pnp_alloc(sizeof(struct pnp_rule_table));
if (!dev->rule) {
spin_unlock(&pnp_lock);
return -ENOMEM;
}
}
dev->rule->depnum = 0;
pnp_init_resource_table(&dev->res);
while (pnp_next_rule(dev)) {
for (i = 0; i < PNP_MAX_PORT; i++) {
if (!pnp_next_port(dev,i))
continue;
}
for (i = 0; i < PNP_MAX_MEM; i++) {
if (!pnp_next_mem(dev,i))
continue;
}
for (i = 0; i < PNP_MAX_IRQ; i++) {
if (!pnp_next_irq(dev,i))
continue;
}
for (i = 0; i < PNP_MAX_DMA; i++) {
if (!pnp_next_dma(dev,i))
continue;
for (i = 0; i < 8; i++) {
if(rule->map & (1<<xtab[i])) {
*start = *end = xtab[i];
if(pnp_check_dma(dev, idx))
return 1;
}
goto done;
}
pnp_init_resource_table(&dev->res);
dev->rule->depnum = 0;
spin_unlock(&pnp_lock);
return 0;
done:
pnp_resolve_conflicts(dev); /* this is required or we will break the advanced configs */
return 1;
}
static int pnp_compare_resources(struct pnp_resource_table * resa, struct pnp_resource_table * resb)
/**
* pnp_init_resources - Resets a resource table to default values.
* @table: pointer to the desired resource table
*
*/
void pnp_init_resources(struct pnp_resource_table *table)
{
int idx;
down(&pnp_res_mutex);
for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
if (resa->irq_resource[idx].start != resb->irq_resource[idx].start)
return 1;
table->irq_resource[idx].name = NULL;
table->irq_resource[idx].start = -1;
table->irq_resource[idx].end = -1;
table->irq_resource[idx].flags = IORESOURCE_AUTO;
}
for (idx = 0; idx < PNP_MAX_DMA; idx++) {
if (resa->dma_resource[idx].start != resb->dma_resource[idx].start)
return 1;
table->dma_resource[idx].name = NULL;
table->dma_resource[idx].start = -1;
table->dma_resource[idx].end = -1;
table->dma_resource[idx].flags = IORESOURCE_AUTO;
}
for (idx = 0; idx < PNP_MAX_PORT; idx++) {
if (resa->port_resource[idx].start != resb->port_resource[idx].start)
return 1;
if (resa->port_resource[idx].end != resb->port_resource[idx].end)
return 1;
table->port_resource[idx].name = NULL;
table->port_resource[idx].start = 0;
table->port_resource[idx].end = 0;
table->port_resource[idx].flags = IORESOURCE_AUTO;
}
for (idx = 0; idx < PNP_MAX_MEM; idx++) {
if (resa->mem_resource[idx].start != resb->mem_resource[idx].start)
return 1;
if (resa->mem_resource[idx].end != resb->mem_resource[idx].end)
return 1;
table->mem_resource[idx].name = NULL;
table->mem_resource[idx].start = 0;
table->mem_resource[idx].end = 0;
table->mem_resource[idx].flags = IORESOURCE_AUTO;
}
return 0;
up(&pnp_res_mutex);
}
/*
* PnP Device Resource Management
*/
/**
* pnp_auto_config_dev - determines the best possible resource configuration based on available information
* @dev: pointer to the desired device
* pnp_clean_resources - clears resources that were not manually set
* @res - the resources to clean
*
*/
int pnp_auto_config_dev(struct pnp_dev *dev)
{
int error;
if(!dev)
return -EINVAL;
dev->config_mode = PNP_CONFIG_AUTO;
if(dev->active)
error = pnp_resolve_conflicts(dev);
else
error = pnp_advanced_config(dev);
return error;
}
static void pnp_process_manual_resources(struct pnp_resource_table * ctab, struct pnp_resource_table * ntab)
static void pnp_clean_resources(struct pnp_resource_table * res)
{
int idx;
for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
if (ntab->irq_resource[idx].flags & IORESOURCE_AUTO)
if (!(res->irq_resource[idx].flags & IORESOURCE_AUTO))
continue;
ctab->irq_resource[idx].start = ntab->irq_resource[idx].start;
ctab->irq_resource[idx].end = ntab->irq_resource[idx].end;
ctab->irq_resource[idx].flags = ntab->irq_resource[idx].flags;
res->irq_resource[idx].start = -1;
res->irq_resource[idx].end = -1;
res->irq_resource[idx].flags = IORESOURCE_AUTO;
}
for (idx = 0; idx < PNP_MAX_DMA; idx++) {
if (ntab->dma_resource[idx].flags & IORESOURCE_AUTO)
if (!(res->dma_resource[idx].flags & IORESOURCE_AUTO))
continue;
ctab->dma_resource[idx].start = ntab->dma_resource[idx].start;
ctab->dma_resource[idx].end = ntab->dma_resource[idx].end;
ctab->dma_resource[idx].flags = ntab->dma_resource[idx].flags;
res->dma_resource[idx].start = -1;
res->dma_resource[idx].end = -1;
res->dma_resource[idx].flags = IORESOURCE_AUTO;
}
for (idx = 0; idx < PNP_MAX_PORT; idx++) {
if (ntab->port_resource[idx].flags & IORESOURCE_AUTO)
if (!(res->port_resource[idx].flags & IORESOURCE_AUTO))
continue;
ctab->port_resource[idx].start = ntab->port_resource[idx].start;
ctab->port_resource[idx].end = ntab->port_resource[idx].end;
ctab->port_resource[idx].flags = ntab->port_resource[idx].flags;
res->port_resource[idx].start = 0;
res->port_resource[idx].end = 0;
res->port_resource[idx].flags = IORESOURCE_AUTO;
}
for (idx = 0; idx < PNP_MAX_MEM; idx++) {
if (ntab->irq_resource[idx].flags & IORESOURCE_AUTO)
if (!(res->mem_resource[idx].flags & IORESOURCE_AUTO))
continue;
ctab->irq_resource[idx].start = ntab->mem_resource[idx].start;
ctab->irq_resource[idx].end = ntab->mem_resource[idx].end;
ctab->irq_resource[idx].flags = ntab->mem_resource[idx].flags;
res->mem_resource[idx].start = 0;
res->mem_resource[idx].end = 0;
res->mem_resource[idx].flags = IORESOURCE_AUTO;
}
}
/**
* pnp_assign_resources - assigns resources to the device based on the specified dependent number
* @dev: pointer to the desired device
* @depnum: the dependent function number
*
* Only set depnum to 0 if the device does not have dependent options.
*/
int pnp_assign_resources(struct pnp_dev *dev, int depnum)
{
struct pnp_port *port;
struct pnp_mem *mem;
struct pnp_irq *irq;
struct pnp_dma *dma;
int nport = 0, nmem = 0, nirq = 0, ndma = 0;
if (!pnp_can_configure(dev))
return -ENODEV;
down(&pnp_res_mutex);
pnp_clean_resources(&dev->res); /* start with a fresh slate */
if (dev->independent) {
port = dev->independent->port;
mem = dev->independent->mem;
irq = dev->independent->irq;
dma = dev->independent->dma;
while (port) {
if (!pnp_assign_port(dev, port, nport))
goto fail;
nport++;
port = port->next;
}
while (mem) {
if (!pnp_assign_mem(dev, mem, nmem))
goto fail;
nmem++;
mem = mem->next;
}
while (irq) {
if (!pnp_assign_irq(dev, irq, nirq))
goto fail;
nirq++;
irq = irq->next;
}
while (dma) {
if (!pnp_assign_dma(dev, dma, ndma))
goto fail;
ndma++;
dma = dma->next;
}
}
if (depnum) {
struct pnp_option *dep;
int i;
for (i=1,dep=dev->dependent; i<depnum; i++, dep=dep->next)
if(!dep)
goto fail;
port =dep->port;
mem = dep->mem;
irq = dep->irq;
dma = dep->dma;
while (port) {
if (!pnp_assign_port(dev, port, nport))
goto fail;
nport++;
port = port->next;
}
while (mem) {
if (!pnp_assign_mem(dev, mem, nmem))
goto fail;
nmem++;
mem = mem->next;
}
while (irq) {
if (!pnp_assign_irq(dev, irq, nirq))
goto fail;
nirq++;
irq = irq->next;
}
while (dma) {
if (!pnp_assign_dma(dev, dma, ndma))
goto fail;
ndma++;
dma = dma->next;
}
} else if (dev->dependent)
goto fail;
up(&pnp_res_mutex);
return 1;
fail:
pnp_clean_resources(&dev->res);
up(&pnp_res_mutex);
return 0;
}
/**
* pnp_manual_config_dev - Disables Auto Config and Manually sets the resource table
* @dev: pointer to the desired device
......@@ -572,22 +363,21 @@ static void pnp_process_manual_resources(struct pnp_resource_table * ctab, struc
*
* This function can be used by drivers that want to manually set thier resources.
*/
int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table * res, int mode)
{
int i;
struct pnp_resource_table * bak;
if (!dev || !res)
return -EINVAL;
if (dev->active)
return -EBUSY;
if (!pnp_can_configure(dev))
return -ENODEV;
bak = pnp_alloc(sizeof(struct pnp_resource_table));
if (!bak)
return -ENOMEM;
*bak = dev->res;
spin_lock(&pnp_lock);
pnp_process_manual_resources(&dev->res, res);
down(&pnp_res_mutex);
dev->res = *res;
if (!(mode & PNP_CONFIG_FORCE)) {
for (i = 0; i < PNP_MAX_PORT; i++) {
if(pnp_check_port(dev,i))
......@@ -606,27 +396,64 @@ int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table * res,
goto fail;
}
}
dev->config_mode = PNP_CONFIG_MANUAL;
spin_unlock(&pnp_lock);
up(&pnp_res_mutex);
pnp_resolve_conflicts(dev);
pnp_auto_config_dev(dev);
kfree(bak);
return 0;
fail:
dev->res = *bak;
spin_unlock(&pnp_lock);
up(&pnp_res_mutex);
kfree(bak);
return -EINVAL;
}
/**
* pnp_activate_dev - activates a PnP device for use
* pnp_auto_config_dev - automatically assigns resources to a device
* @dev: pointer to the desired device
*
* finds the best resource configuration and then informs the correct pnp protocol
*/
int pnp_auto_config_dev(struct pnp_dev *dev)
{
struct pnp_option *dep;
int i = 1;
if(!dev)
return -EINVAL;
if(!pnp_can_configure(dev)) {
pnp_info("Device %s does not support resource configuration.", dev->dev.bus_id);
return -ENODEV;
}
if (!dev->dependent) {
if (pnp_assign_resources(dev, 0))
return 1;
else
return 0;
}
dep = dev->dependent;
do {
if (pnp_assign_resources(dev, i))
return 1;
/* if this dependent resource failed, try the next one */
dep = dep->next;
i++;
} while (dep);
pnp_err("Unable to assign resources to device %s.", dev->dev.bus_id);
return 0;
}
/**
* pnp_activate_dev - activates a PnP device for use
* @dev: pointer to the desired device
*
* does not validate or set resources so be careful.
*/
int pnp_activate_dev(struct pnp_dev *dev)
{
if (!dev)
......@@ -634,55 +461,25 @@ int pnp_activate_dev(struct pnp_dev *dev)
if (dev->active) {
return 0; /* the device is already active */
}
/* If this condition is true, advanced configuration failed, we need to get this device up and running
* so we use the simple config engine which ignores cold conflicts, this of course may lead to new failures */
if (!pnp_is_active(dev)) {
if (!pnp_simple_config(dev)) {
pnp_err("res: Unable to resolve resource conflicts for the device '%s'.", dev->dev.bus_id);
goto fail;
}
}
spin_lock(&pnp_lock); /* we lock just in case the device is being configured during this call */
dev->active = 1;
spin_unlock(&pnp_lock); /* once the device is claimed active we know it won't be configured so we can unlock */
/* ensure resources are allocated */
if (!pnp_auto_config_dev(dev))
return -EBUSY;
if (dev->config_mode & PNP_CONFIG_INVALID) {
pnp_info("res: Unable to activate the PnP device '%s' because its resource configuration is invalid.", dev->dev.bus_id);
goto fail;
}
if (dev->status != PNP_READY && dev->status != PNP_ATTACHED){
pnp_err("res: Activation failed because the PnP device '%s' is busy.", dev->dev.bus_id);
goto fail;
}
if (!pnp_can_write(dev)) {
pnp_info("res: Unable to activate the PnP device '%s' because this feature is not supported.", dev->dev.bus_id);
goto fail;
pnp_info("Device %s does not supported activation.", dev->dev.bus_id);
return -EINVAL;
}
if (dev->protocol->set(dev, &dev->res)<0) {
pnp_err("res: The protocol '%s' reports that activating the PnP device '%s' has failed.", dev->protocol->name, dev->dev.bus_id);
goto fail;
pnp_err("Failed to activate device %s.", dev->dev.bus_id);
return -EIO;
}
if (pnp_can_read(dev)) {
struct pnp_resource_table * res = pnp_alloc(sizeof(struct pnp_resource_table));
if (!res)
goto fail;
dev->protocol->get(dev, res);
if (pnp_compare_resources(&dev->res, res)) /* if this happens we may be in big trouble but it's best just to continue */
pnp_err("res: The resources requested do not match those set for the PnP device '%s'.", dev->dev.bus_id);
kfree(res);
} else
dev->active = pnp_is_active(dev);
pnp_dbg("res: the device '%s' has been activated.", dev->dev.bus_id);
if (dev->rule) {
kfree(dev->rule);
dev->rule = NULL;
}
return 0;
fail:
dev->active = 0; /* fixes incorrect active state */
return -EINVAL;
dev->active = 1;
pnp_info("Device %s activated.", dev->dev.bus_id);
return 1;
}
/**
......@@ -691,7 +488,6 @@ int pnp_activate_dev(struct pnp_dev *dev)
*
* inform the correct pnp protocol so that resources can be used by other devices
*/
int pnp_disable_dev(struct pnp_dev *dev)
{
if (!dev)
......@@ -699,21 +495,25 @@ int pnp_disable_dev(struct pnp_dev *dev)
if (!dev->active) {
return 0; /* the device is already disabled */
}
if (dev->status != PNP_READY){
pnp_info("res: Disable failed becuase the PnP device '%s' is busy.", dev->dev.bus_id);
return -EINVAL;
}
if (!pnp_can_disable(dev)) {
pnp_info("res: Unable to disable the PnP device '%s' because this feature is not supported.", dev->dev.bus_id);
pnp_info("Device %s does not supported disabling.", dev->dev.bus_id);
return -EINVAL;
}
if (dev->protocol->disable(dev)<0) {
pnp_err("res: The protocol '%s' reports that disabling the PnP device '%s' has failed.", dev->protocol->name, dev->dev.bus_id);
return -1;
pnp_err("Failed to disable device %s.", dev->dev.bus_id);
return -EIO;
}
dev->active = 0; /* just in case the protocol doesn't do this */
pnp_dbg("res: the device '%s' has been disabled.", dev->dev.bus_id);
return 0;
dev->active = 0;
pnp_info("Device %s disabled.", dev->dev.bus_id);
/* release the resources so that other devices can use them */
down(&pnp_res_mutex);
pnp_clean_resources(&dev->res);
up(&pnp_res_mutex);
return 1;
}
/**
......@@ -723,7 +523,6 @@ int pnp_disable_dev(struct pnp_dev *dev)
* @size: size of region
*
*/
void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size)
{
if (resource == NULL)
......@@ -734,19 +533,10 @@ void pnp_resource_change(struct resource *resource, unsigned long start, unsigne
}
EXPORT_SYMBOL(pnp_auto_config_dev);
EXPORT_SYMBOL(pnp_assign_resources);
EXPORT_SYMBOL(pnp_manual_config_dev);
EXPORT_SYMBOL(pnp_auto_config_dev);
EXPORT_SYMBOL(pnp_activate_dev);
EXPORT_SYMBOL(pnp_disable_dev);
EXPORT_SYMBOL(pnp_resource_change);
/* format is: pnp_max_moves=num */
static int __init pnp_setup_max_moves(char *str)
{
get_option(&str,&pnp_max_moves);
return 1;
}
__setup("pnp_max_moves=", pnp_setup_max_moves);
EXPORT_SYMBOL(pnp_init_resources);
......@@ -935,6 +935,10 @@ static int insert_device(struct pnp_dev *dev, struct pnp_bios_node * node)
dev->capabilities |= PNP_REMOVABLE;
dev->protocol = &pnpbios_protocol;
/* clear out the damaged flags */
if (!dev->active)
pnp_init_resources(&dev->res);
pnp_add_device(dev);
pnpbios_interface_attach_device(node);
......
......@@ -30,7 +30,7 @@
static void quirk_awe32_resources(struct pnp_dev *dev)
{
struct pnp_port *port, *port2, *port3;
struct pnp_resources *res = dev->possible->dep;
struct pnp_option *res = dev->dependent;
/*
* Unfortunately the isapnp_add_port_resource is too tightly bound
......@@ -38,7 +38,7 @@ static void quirk_awe32_resources(struct pnp_dev *dev)
* two extra ports (at offset 0x400 and 0x800 from the one given) by
* hand.
*/
for ( ; res ; res = res->dep ) {
for ( ; res ; res = res->next ) {
port2 = pnp_alloc(sizeof(struct pnp_port));
if (!port2)
return;
......@@ -62,9 +62,9 @@ static void quirk_awe32_resources(struct pnp_dev *dev)
static void quirk_cmi8330_resources(struct pnp_dev *dev)
{
struct pnp_resources *res = dev->possible->dep;
struct pnp_option *res = dev->dependent;
for ( ; res ; res = res->dep ) {
for ( ; res ; res = res->next ) {
struct pnp_irq *irq;
struct pnp_dma *dma;
......@@ -82,7 +82,7 @@ static void quirk_cmi8330_resources(struct pnp_dev *dev)
static void quirk_sb16audio_resources(struct pnp_dev *dev)
{
struct pnp_port *port;
struct pnp_resources *res = dev->possible->dep;
struct pnp_option *res = dev->dependent;
int changed = 0;
/*
......@@ -91,7 +91,7 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev)
* auto-configured.
*/
for( ; res ; res = res->dep ) {
for( ; res ; res = res->next ) {
port = res->port;
if(!port)
continue;
......@@ -118,11 +118,11 @@ static void quirk_opl3sax_resources(struct pnp_dev *dev)
* doesn't allow a DMA channel of 0, afflicted card is an
* OPL3Sax where x=4.
*/
struct pnp_resources *res;
struct pnp_option *res;
int max;
res = dev->possible;
res = dev->dependent;
max = 0;
for (res = res->dep; res; res = res->dep) {
for (; res; res = res->next) {
if (res->dma->map > max)
max = res->dma->map;
}
......
......@@ -10,18 +10,19 @@
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <asm/irq.h>
#include <linux/pci.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/pnp.h>
#include "base.h"
int pnp_allow_dma0 = -1; /* allow dma 0 during auto activation: -1=off (:default), 0=off (set by user), 1=on */
int pnp_allow_dma0 = -1; /* allow dma 0 during auto activation:
* -1=off (:default), 0=off (set by user), 1=on */
int pnp_skip_pci_scan; /* skip PCI resource scanning */
int pnp_reserve_irq[16] = { [0 ... 15] = -1 }; /* reserve (don't use) some IRQ */
int pnp_reserve_dma[8] = { [0 ... 7] = -1 }; /* reserve (don't use) some DMA */
......@@ -30,88 +31,75 @@ int pnp_reserve_mem[16] = { [0 ... 15] = -1 }; /* reserve (don't use) some memor
/*
* possible resource registration
* option registration
*/
struct pnp_resources * pnp_build_resource(struct pnp_dev *dev, int dependent)
static struct pnp_option * pnp_build_option(int priority)
{
struct pnp_resources *res, *ptr, *ptra;
struct pnp_option *option = pnp_alloc(sizeof(struct pnp_option));
res = pnp_alloc(sizeof(struct pnp_resources));
if (!res)
/* check if pnp_alloc ran out of memory */
if (!option)
return NULL;
ptr = dev->possible;
if (ptr) { /* add to another list */
ptra = ptr->dep;
while (ptra && ptra->dep)
ptra = ptra->dep;
if (!ptra)
ptr->dep = res;
else
ptra->dep = res;
} else
dev->possible = res;
if (dependent) {
res->priority = dependent & 0xff;
if (res->priority > PNP_RES_PRIORITY_FUNCTIONAL)
res->priority = PNP_RES_PRIORITY_INVALID;
} else
res->priority = PNP_RES_PRIORITY_PREFERRED;
return res;
option->priority = priority & 0xff;
/* make sure the priority is valid */
if (option->priority > PNP_RES_PRIORITY_FUNCTIONAL)
option->priority = PNP_RES_PRIORITY_INVALID;
return option;
}
struct pnp_resources * pnp_find_resources(struct pnp_dev *dev, int depnum)
struct pnp_option * pnp_register_independent_option(struct pnp_dev *dev)
{
int i;
struct pnp_resources *res;
struct pnp_option *option;
if (!dev)
return NULL;
res = dev->possible;
if (!res)
return NULL;
for (i = 0; i < depnum; i++)
{
if (res->dep)
res = res->dep;
else
return NULL;
}
return res;
option = pnp_build_option(PNP_RES_PRIORITY_PREFERRED);
/* this should never happen but if it does we'll try to continue */
if (dev->independent)
pnp_err("independent resource already registered");
dev->independent = option;
return option;
}
int pnp_get_max_depnum(struct pnp_dev *dev)
struct pnp_option * pnp_register_dependent_option(struct pnp_dev *dev, int priority)
{
int num = 0;
struct pnp_resources *res;
struct pnp_option *option;
if (!dev)
return -EINVAL;
res = dev->possible;
if (!res)
return -EINVAL;
while (res->dep){
res = res->dep;
num++;
}
return num;
return NULL;
option = pnp_build_option(priority);
if (dev->dependent) {
struct pnp_option *parent = dev->dependent;
while (parent->next)
parent = parent->next;
parent->next = option;
} else
dev->dependent = option;
return option;
}
int pnp_add_irq_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data)
int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data)
{
int i;
struct pnp_resources *res;
struct pnp_irq *ptr;
res = pnp_find_resources(dev,depnum);
if (!res)
if (!option)
return -EINVAL;
if (!data)
return -EINVAL;
ptr = res->irq;
ptr = option->irq;
while (ptr && ptr->next)
ptr = ptr->next;
if (ptr)
ptr->next = data;
else
res->irq = data;
option->irq = data;
#ifdef CONFIG_PCI
for (i=0; i<16; i++)
if (data->map & (1<<i))
......@@ -120,60 +108,59 @@ int pnp_add_irq_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data)
return 0;
}
int pnp_add_dma_resource(struct pnp_dev *dev, int depnum, struct pnp_dma *data)
int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data)
{
struct pnp_resources *res;
struct pnp_dma *ptr;
res = pnp_find_resources(dev,depnum);
if (!res)
if (!option)
return -EINVAL;
if (!data)
return -EINVAL;
ptr = res->dma;
ptr = option->dma;
while (ptr && ptr->next)
ptr = ptr->next;
if (ptr)
ptr->next = data;
else
res->dma = data;
option->dma = data;
return 0;
}
int pnp_add_port_resource(struct pnp_dev *dev, int depnum, struct pnp_port *data)
int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data)
{
struct pnp_resources *res;
struct pnp_port *ptr;
res = pnp_find_resources(dev,depnum);
if (!res)
if (!option)
return -EINVAL;
if (!data)
return -EINVAL;
ptr = res->port;
ptr = option->port;
while (ptr && ptr->next)
ptr = ptr->next;
if (ptr)
ptr->next = data;
else
res->port = data;
option->port = data;
return 0;
}
int pnp_add_mem_resource(struct pnp_dev *dev, int depnum, struct pnp_mem *data)
int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data)
{
struct pnp_resources *res;
struct pnp_mem *ptr;
res = pnp_find_resources(dev,depnum);
if (!res)
if (!option)
return -EINVAL;
if (!data)
return -EINVAL;
ptr = res->mem;
ptr = option->mem;
while (ptr && ptr->next)
ptr = ptr->next;
if (ptr)
ptr->next = data;
else
res->mem = data;
option->mem = data;
return 0;
}
......@@ -221,18 +208,18 @@ static void pnp_free_mem(struct pnp_mem *mem)
}
}
void pnp_free_resources(struct pnp_resources *resources)
void pnp_free_option(struct pnp_option *option)
{
struct pnp_resources *next;
while (resources) {
next = resources->dep;
pnp_free_port(resources->port);
pnp_free_irq(resources->irq);
pnp_free_dma(resources->dma);
pnp_free_mem(resources->mem);
kfree(resources);
resources = next;
struct pnp_option *next;
while (option) {
next = option->next;
pnp_free_port(option->port);
pnp_free_irq(option->irq);
pnp_free_dma(option->dma);
pnp_free_mem(option->mem);
kfree(option);
option = next;
}
}
......@@ -253,50 +240,23 @@ void pnp_free_resources(struct pnp_resources *resources)
(*(enda) >= *(startb) && *(enda) <= *(endb)) || \
(*(starta) < *(startb) && *(enda) > *(endb)))
struct pnp_dev * pnp_check_port_conflicts(struct pnp_dev * dev, int idx, int mode)
{
int tmp;
unsigned long *port, *end, *tport, *tend;
struct pnp_dev *tdev;
port = &dev->res.port_resource[idx].start;
end = &dev->res.port_resource[idx].end;
/* if the resource doesn't exist, don't complain about it */
if (dev->res.port_resource[idx].start == 0)
return NULL;
/* check for cold conflicts */
pnp_for_each_dev(tdev) {
/* Is the device configurable? */
if (tdev == dev || (mode ? !tdev->active : tdev->active))
continue;
for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) {
if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) {
tport = &tdev->res.port_resource[tmp].start;
tend = &tdev->res.port_resource[tmp].end;
if (ranged_conflict(port,end,tport,tend))
return tdev;
}
}
}
return NULL;
}
int pnp_check_port(struct pnp_dev * dev, int idx)
{
int tmp;
struct pnp_dev *tdev;
unsigned long *port, *end, *tport, *tend;
port = &dev->res.port_resource[idx].start;
end = &dev->res.port_resource[idx].end;
/* if the resource doesn't exist, don't complain about it */
if (dev->res.port_resource[idx].start == 0)
return 0;
return 1;
/* check if the resource is already in use, skip if the device is active because it itself may be in use */
/* check if the resource is already in use, skip if the
* device is active because it itself may be in use */
if(!dev->active) {
if (check_region(*port, length(port,end)))
return CONFLICT_TYPE_IN_USE;
if (__check_region(&ioport_resource, *port, length(port,end)))
return 0;
}
/* check if the resource is reserved */
......@@ -304,7 +264,7 @@ int pnp_check_port(struct pnp_dev * dev, int idx)
int rport = pnp_reserve_io[tmp << 1];
int rend = pnp_reserve_io[(tmp << 1) + 1] + rport - 1;
if (ranged_conflict(port,end,&rport,&rend))
return CONFLICT_TYPE_RESERVED;
return 0;
}
/* check for internal conflicts */
......@@ -313,61 +273,44 @@ int pnp_check_port(struct pnp_dev * dev, int idx)
tport = &dev->res.port_resource[tmp].start;
tend = &dev->res.port_resource[tmp].end;
if (ranged_conflict(port,end,tport,tend))
return CONFLICT_TYPE_INTERNAL;
return 0;
}
}
/* check for warm conflicts */
if (pnp_check_port_conflicts(dev, idx, SEARCH_WARM))
return CONFLICT_TYPE_PNP_WARM;
return 0;
}
struct pnp_dev * pnp_check_mem_conflicts(struct pnp_dev * dev, int idx, int mode)
{
int tmp;
unsigned long *addr, *end, *taddr, *tend;
struct pnp_dev *tdev;
addr = &dev->res.mem_resource[idx].start;
end = &dev->res.mem_resource[idx].end;
/* if the resource doesn't exist, don't complain about it */
if (dev->res.mem_resource[idx].start == 0)
return NULL;
/* check for cold conflicts */
/* check for conflicts with other pnp devices */
pnp_for_each_dev(tdev) {
/* Is the device configurable? */
if (tdev == dev || (mode ? !tdev->active : tdev->active))
if (tdev == dev)
continue;
for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
taddr = &tdev->res.mem_resource[tmp].start;
tend = &tdev->res.mem_resource[tmp].end;
if (ranged_conflict(addr,end,taddr,tend))
return tdev;
for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) {
if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) {
tport = &tdev->res.port_resource[tmp].start;
tend = &tdev->res.port_resource[tmp].end;
if (ranged_conflict(port,end,tport,tend))
return 0;
}
}
}
return NULL;
return 1;
}
int pnp_check_mem(struct pnp_dev * dev, int idx)
{
int tmp;
struct pnp_dev *tdev;
unsigned long *addr, *end, *taddr, *tend;
addr = &dev->res.mem_resource[idx].start;
end = &dev->res.mem_resource[idx].end;
/* if the resource doesn't exist, don't complain about it */
if (dev->res.mem_resource[idx].start == 0)
return 0;
return 1;
/* check if the resource is already in use, skip if the device is active because it itself may be in use */
/* check if the resource is already in use, skip if the
* device is active because it itself may be in use */
if(!dev->active) {
if (__check_region(&iomem_resource, *addr, length(addr,end)))
return CONFLICT_TYPE_IN_USE;
if (check_mem_region(*addr, length(addr,end)))
return 0;
}
/* check if the resource is reserved */
......@@ -375,7 +318,7 @@ int pnp_check_mem(struct pnp_dev * dev, int idx)
int raddr = pnp_reserve_mem[tmp << 1];
int rend = pnp_reserve_mem[(tmp << 1) + 1] + raddr - 1;
if (ranged_conflict(addr,end,&raddr,&rend))
return CONFLICT_TYPE_RESERVED;
return 0;
}
/* check for internal conflicts */
......@@ -384,40 +327,25 @@ int pnp_check_mem(struct pnp_dev * dev, int idx)
taddr = &dev->res.mem_resource[tmp].start;
tend = &dev->res.mem_resource[tmp].end;
if (ranged_conflict(addr,end,taddr,tend))
return CONFLICT_TYPE_INTERNAL;
return 0;
}
}
/* check for warm conflicts */
if (pnp_check_mem_conflicts(dev, idx, SEARCH_WARM))
return CONFLICT_TYPE_PNP_WARM;
return 0;
}
struct pnp_dev * pnp_check_irq_conflicts(struct pnp_dev * dev, int idx, int mode)
{
int tmp;
struct pnp_dev * tdev;
unsigned long * irq = &dev->res.irq_resource[idx].start;
/* if the resource doesn't exist, don't complain about it */
if (dev->res.irq_resource[idx].start == -1)
return NULL;
/* check for cold conflicts */
/* check for conflicts with other pnp devices */
pnp_for_each_dev(tdev) {
/* Is the device configurable? */
if (tdev == dev || (mode ? !tdev->active : tdev->active))
if (tdev == dev)
continue;
for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
if ((tdev->res.irq_resource[tmp].start == *irq))
return tdev;
for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
taddr = &tdev->res.mem_resource[tmp].start;
tend = &tdev->res.mem_resource[tmp].end;
if (ranged_conflict(addr,end,taddr,tend))
return 0;
}
}
}
return NULL;
return 1;
}
static irqreturn_t pnp_test_handler(int irq, void *dev_id, struct pt_regs *regs)
......@@ -428,27 +356,28 @@ static irqreturn_t pnp_test_handler(int irq, void *dev_id, struct pt_regs *regs)
int pnp_check_irq(struct pnp_dev * dev, int idx)
{
int tmp;
struct pnp_dev *tdev;
unsigned long * irq = &dev->res.irq_resource[idx].start;
/* if the resource doesn't exist, don't complain about it */
if (dev->res.irq_resource[idx].start == -1)
return 0;
return 1;
/* check if the resource is valid */
if (*irq < 0 || *irq > 15)
return CONFLICT_TYPE_INVALID;
return 0;
/* check if the resource is reserved */
for (tmp = 0; tmp < 16; tmp++) {
if (pnp_reserve_irq[tmp] == *irq)
return CONFLICT_TYPE_RESERVED;
return 0;
}
/* check for internal conflicts */
for (tmp = 0; tmp < PNP_MAX_IRQ && tmp != idx; tmp++) {
if (dev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
if (dev->res.irq_resource[tmp].start == *irq)
return CONFLICT_TYPE_INTERNAL;
return 0;
}
}
......@@ -458,233 +387,94 @@ int pnp_check_irq(struct pnp_dev * dev, int idx)
struct pci_dev * pci = NULL;
while ((pci = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci)) != NULL) {
if (pci->irq == *irq)
return CONFLICT_TYPE_PCI;
return 0;
}
}
#endif
/* check if the resource is already in use, skip if the device is active because it itself may be in use */
/* check if the resource is already in use, skip if the
* device is active because it itself may be in use */
if(!dev->active) {
if (request_irq(*irq, pnp_test_handler, SA_INTERRUPT, "pnp", NULL))
return CONFLICT_TYPE_IN_USE;
return 0;
free_irq(*irq, NULL);
}
/* check for warm conflicts */
if (pnp_check_irq_conflicts(dev, idx, SEARCH_WARM))
return CONFLICT_TYPE_PNP_WARM;
return 0;
}
struct pnp_dev * pnp_check_dma_conflicts(struct pnp_dev * dev, int idx, int mode)
{
int tmp;
struct pnp_dev * tdev;
unsigned long * dma = &dev->res.dma_resource[idx].start;
/* if the resource doesn't exist, don't complain about it */
if (dev->res.dma_resource[idx].start == -1)
return NULL;
/* check for cold conflicts */
/* check for conflicts with other pnp devices */
pnp_for_each_dev(tdev) {
/* Is the device configurable? */
if (tdev == dev || (mode ? !tdev->active : tdev->active))
if (tdev == dev)
continue;
for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
if ((tdev->res.dma_resource[tmp].start == *dma))
return tdev;
for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
if ((tdev->res.irq_resource[tmp].start == *irq))
return 0;
}
}
}
return NULL;
return 1;
}
int pnp_check_dma(struct pnp_dev * dev, int idx)
{
int tmp, mindma = 1;
struct pnp_dev *tdev;
unsigned long * dma = &dev->res.dma_resource[idx].start;
/* if the resource doesn't exist, don't complain about it */
if (dev->res.dma_resource[idx].start == -1)
return 0;
return 1;
/* check if the resource is valid */
if (pnp_allow_dma0 == 1)
mindma = 0;
if (*dma < mindma || *dma == 4 || *dma > 7)
return CONFLICT_TYPE_INVALID;
return 0;
/* check if the resource is reserved */
for (tmp = 0; tmp < 8; tmp++) {
if (pnp_reserve_dma[tmp] == *dma)
return CONFLICT_TYPE_RESERVED;
return 0;
}
/* check for internal conflicts */
for (tmp = 0; tmp < PNP_MAX_DMA && tmp != idx; tmp++) {
if (dev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
if (dev->res.dma_resource[tmp].start == *dma)
return CONFLICT_TYPE_INTERNAL;
return 0;
}
}
/* check if the resource is already in use, skip if the device is active because it itself may be in use */
/* check if the resource is already in use, skip if the
* device is active because it itself may be in use */
if(!dev->active) {
if (request_dma(*dma, "pnp"))
return CONFLICT_TYPE_IN_USE;
return 0;
free_dma(*dma);
}
/* check for warm conflicts */
if (pnp_check_dma_conflicts(dev, idx, SEARCH_WARM))
return CONFLICT_TYPE_PNP_WARM;
return 0;
}
/**
* pnp_init_resource_table - Resets a resource table to default values.
* @table: pointer to the desired resource table
*
*/
void pnp_init_resource_table(struct pnp_resource_table *table)
{
int idx;
for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
table->irq_resource[idx].name = NULL;
table->irq_resource[idx].start = -1;
table->irq_resource[idx].end = -1;
table->irq_resource[idx].flags = IORESOURCE_AUTO;
}
for (idx = 0; idx < PNP_MAX_DMA; idx++) {
table->dma_resource[idx].name = NULL;
table->dma_resource[idx].start = -1;
table->dma_resource[idx].end = -1;
table->dma_resource[idx].flags = IORESOURCE_AUTO;
}
for (idx = 0; idx < PNP_MAX_PORT; idx++) {
table->port_resource[idx].name = NULL;
table->port_resource[idx].start = 0;
table->port_resource[idx].end = 0;
table->port_resource[idx].flags = IORESOURCE_AUTO;
}
for (idx = 0; idx < PNP_MAX_MEM; idx++) {
table->mem_resource[idx].name = NULL;
table->mem_resource[idx].start = 0;
table->mem_resource[idx].end = 0;
table->mem_resource[idx].flags = IORESOURCE_AUTO;
}
}
/**
* pnp_generate_rule - Creates a rule table structure based on depnum and device.
* @dev: pointer to the desired device
* @depnum: dependent function, if not valid will return an error
* @rule: pointer to a rule structure to record data to
*
*/
int pnp_generate_rule(struct pnp_dev * dev, int depnum, struct pnp_rule_table * rule)
{
int nport = 0, nirq = 0, ndma = 0, nmem = 0;
struct pnp_resources * res;
struct pnp_port * port;
struct pnp_mem * mem;
struct pnp_irq * irq;
struct pnp_dma * dma;
if (depnum < 0 || !rule)
return -EINVAL;
/* independent */
res = pnp_find_resources(dev, 0);
if (!res)
return -ENODEV;
port = res->port;
mem = res->mem;
irq = res->irq;
dma = res->dma;
while (port){
rule->port[nport] = port;
nport++;
port = port->next;
}
while (mem){
rule->mem[nmem] = mem;
nmem++;
mem = mem->next;
}
while (irq){
rule->irq[nirq] = irq;
nirq++;
irq = irq->next;
}
while (dma){
rule->dma[ndma] = dma;
ndma++;
dma = dma->next;
}
/* dependent */
if (depnum == 0)
return 1;
res = pnp_find_resources(dev, depnum);
if (!res)
return -ENODEV;
port = res->port;
mem = res->mem;
irq = res->irq;
dma = res->dma;
while (port){
rule->port[nport] = port;
nport++;
port = port->next;
}
while (mem){
rule->mem[nmem] = mem;
nmem++;
mem = mem->next;
}
while (irq){
rule->irq[nirq] = irq;
nirq++;
irq = irq->next;
}
while (dma){
rule->dma[ndma] = dma;
ndma++;
dma = dma->next;
/* check for conflicts with other pnp devices */
pnp_for_each_dev(tdev) {
if (tdev == dev)
continue;
for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
if ((tdev->res.dma_resource[tmp].start == *dma))
return 0;
}
}
}
/* clear the remaining values */
for (; nport < PNP_MAX_PORT; nport++)
rule->port[nport] = NULL;
for (; nmem < PNP_MAX_MEM; nmem++)
rule->mem[nmem] = NULL;
for (; nirq < PNP_MAX_IRQ; nirq++)
rule->irq[nirq] = NULL;
for (; ndma < PNP_MAX_DMA; ndma++)
rule->dma[ndma] = NULL;
return 1;
}
EXPORT_SYMBOL(pnp_build_resource);
EXPORT_SYMBOL(pnp_find_resources);
EXPORT_SYMBOL(pnp_get_max_depnum);
EXPORT_SYMBOL(pnp_add_irq_resource);
EXPORT_SYMBOL(pnp_add_dma_resource);
EXPORT_SYMBOL(pnp_add_port_resource);
EXPORT_SYMBOL(pnp_add_mem_resource);
EXPORT_SYMBOL(pnp_init_resource_table);
EXPORT_SYMBOL(pnp_generate_rule);
EXPORT_SYMBOL(pnp_register_dependent_option);
EXPORT_SYMBOL(pnp_register_independent_option);
EXPORT_SYMBOL(pnp_register_irq_resource);
EXPORT_SYMBOL(pnp_register_dma_resource);
EXPORT_SYMBOL(pnp_register_port_resource);
EXPORT_SYMBOL(pnp_register_mem_resource);
/* format is: allowdma0 */
......
/*
* support.c - provides standard pnp functions for the use of pnp protocol drivers,
*
* Copyright 2002 Adam Belay <ambx1@neo.rr.com>
* Copyright 2003 Adam Belay <ambx1@neo.rr.com>
*
* Resource parsing functions are based on those in the linux pnpbios driver.
* Copyright Christian Schmidt, Tom Lees, David Hinds, Alan Cox, Thomas Hood,
......@@ -10,6 +10,7 @@
#include <linux/config.h>
#include <linux/module.h>
#include <linux/ctype.h>
#ifdef CONFIG_PNP_DEBUG
#define DEBUG
......@@ -122,7 +123,7 @@ unsigned char * pnp_parse_current_resources(unsigned char * p, unsigned char * e
return NULL;
/* Blank the resource table values */
pnp_init_resource_table(res);
pnp_init_resources(res);
while ((char *)p < (char *)end) {
......@@ -250,51 +251,51 @@ unsigned char * pnp_parse_current_resources(unsigned char * p, unsigned char * e
* Possible resource reading functions *
*/
static void possible_mem(unsigned char *p, int size, int depnum, struct pnp_dev *dev)
static void possible_mem(unsigned char *p, int size, struct pnp_option *option)
{
struct pnp_mem * mem;
mem = pnp_alloc(sizeof(struct pnp_mem));
if (!mem)
return;
mem->min = ((p[3] << 8) | p[2]) << 8;
mem->max = ((p[5] << 8) | p[4]) << 8;
mem->align = (p[7] << 8) | p[6];
mem->size = ((p[9] << 8) | p[8]) << 8;
mem->flags = p[1];
pnp_add_mem_resource(dev,depnum,mem);
mem->min = ((p[5] << 8) | p[4]) << 8;
mem->max = ((p[7] << 8) | p[6]) << 8;
mem->align = (p[9] << 8) | p[8];
mem->size = ((p[11] << 8) | p[10]) << 8;
mem->flags = p[3];
pnp_register_mem_resource(option,mem);
return;
}
static void possible_mem32(unsigned char *p, int size, int depnum, struct pnp_dev *dev)
static void possible_mem32(unsigned char *p, int size, struct pnp_option *option)
{
struct pnp_mem * mem;
mem = pnp_alloc(sizeof(struct pnp_mem));
if (!mem)
return;
mem->min = (p[5] << 24) | (p[4] << 16) | (p[3] << 8) | p[2];
mem->max = (p[9] << 24) | (p[8] << 16) | (p[7] << 8) | p[6];
mem->align = (p[13] << 24) | (p[12] << 16) | (p[11] << 8) | p[10];
mem->size = (p[17] << 24) | (p[16] << 16) | (p[15] << 8) | p[14];
mem->flags = p[1];
pnp_add_mem_resource(dev,depnum,mem);
mem->min = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
mem->max = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8];
mem->align = (p[15] << 24) | (p[14] << 16) | (p[13] << 8) | p[12];
mem->size = (p[19] << 24) | (p[18] << 16) | (p[17] << 8) | p[16];
mem->flags = p[3];
pnp_register_mem_resource(option,mem);
return;
}
static void possible_fixed_mem32(unsigned char *p, int size, int depnum, struct pnp_dev *dev)
static void possible_fixed_mem32(unsigned char *p, int size, struct pnp_option *option)
{
struct pnp_mem * mem;
mem = pnp_alloc(sizeof(struct pnp_mem));
if (!mem)
return;
mem->min = mem->max = (p[5] << 24) | (p[4] << 16) | (p[3] << 8) | p[2];
mem->size = (p[9] << 24) | (p[8] << 16) | (p[7] << 8) | p[6];
mem->min = mem->max = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
mem->size = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8];
mem->align = 0;
mem->flags = p[1];
pnp_add_mem_resource(dev,depnum,mem);
mem->flags = p[3];
pnp_register_mem_resource(option,mem);
return;
}
static void possible_irq(unsigned char *p, int size, int depnum, struct pnp_dev *dev)
static void possible_irq(unsigned char *p, int size, struct pnp_option *option)
{
struct pnp_irq * irq;
irq = pnp_alloc(sizeof(struct pnp_irq));
......@@ -303,11 +304,13 @@ static void possible_irq(unsigned char *p, int size, int depnum, struct pnp_dev
irq->map = (p[2] << 8) | p[1];
if (size > 2)
irq->flags = p[3];
pnp_add_irq_resource(dev,depnum,irq);
else
irq->flags = IORESOURCE_IRQ_HIGHEDGE;
pnp_register_irq_resource(option,irq);
return;
}
static void possible_dma(unsigned char *p, int size, int depnum, struct pnp_dev *dev)
static void possible_dma(unsigned char *p, int size, struct pnp_option *option)
{
struct pnp_dma * dma;
dma = pnp_alloc(sizeof(struct pnp_dma));
......@@ -315,11 +318,11 @@ static void possible_dma(unsigned char *p, int size, int depnum, struct pnp_dev
return;
dma->map = p[1];
dma->flags = p[2];
pnp_add_dma_resource(dev,depnum,dma);
pnp_register_dma_resource(option,dma);
return;
}
static void possible_port(unsigned char *p, int size, int depnum, struct pnp_dev *dev)
static void possible_port(unsigned char *p, int size, struct pnp_option *option)
{
struct pnp_port * port;
port = pnp_alloc(sizeof(struct pnp_port));
......@@ -330,11 +333,11 @@ static void possible_port(unsigned char *p, int size, int depnum, struct pnp_dev
port->align = p[6];
port->size = p[7];
port->flags = p[1] ? PNP_PORT_FLAG_16BITADDR : 0;
pnp_add_port_resource(dev,depnum,port);
pnp_register_port_resource(option,port);
return;
}
static void possible_fixed_port(unsigned char *p, int size, int depnum, struct pnp_dev *dev)
static void possible_fixed_port(unsigned char *p, int size, struct pnp_option *option)
{
struct pnp_port * port;
port = pnp_alloc(sizeof(struct pnp_port));
......@@ -344,7 +347,7 @@ static void possible_fixed_port(unsigned char *p, int size, int depnum, struct p
port->size = p[3];
port->align = 0;
port->flags = PNP_PORT_FLAG_FIXED;
pnp_add_port_resource(dev,depnum,port);
pnp_register_port_resource(option,port);
return;
}
......@@ -358,12 +361,14 @@ static void possible_fixed_port(unsigned char *p, int size, int depnum, struct p
unsigned char * pnp_parse_possible_resources(unsigned char * p, unsigned char * end, struct pnp_dev *dev)
{
int len, depnum = 0, dependent = 0;
int len, priority = 0;
struct pnp_option *option;
if (!p)
return NULL;
if (pnp_build_resource(dev, 0) == NULL)
option = pnp_register_independent_option(dev);
if (!option)
return NULL;
while ((char *)p < (char *)end) {
......@@ -375,21 +380,21 @@ unsigned char * pnp_parse_possible_resources(unsigned char * p, unsigned char *
{
if (len != 9)
goto lrg_err;
possible_mem(p,len,depnum,dev);
possible_mem(p,len,option);
break;
}
case LARGE_TAG_MEM32:
{
if (len != 17)
goto lrg_err;
possible_mem32(p,len,depnum,dev);
possible_mem32(p,len,option);
break;
}
case LARGE_TAG_FIXEDMEM32:
{
if (len != 9)
goto lrg_err;
possible_fixed_mem32(p,len,depnum,dev);
possible_fixed_mem32(p,len,option);
break;
}
default: /* an unkown tag */
......@@ -410,46 +415,46 @@ unsigned char * pnp_parse_possible_resources(unsigned char * p, unsigned char *
{
if (len < 2 || len > 3)
goto sm_err;
possible_irq(p,len,depnum,dev);
possible_irq(p,len,option);
break;
}
case SMALL_TAG_DMA:
{
if (len != 2)
goto sm_err;
possible_dma(p,len,depnum,dev);
possible_dma(p,len,option);
break;
}
case SMALL_TAG_STARTDEP:
{
if (len > 1)
goto sm_err;
dependent = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE;
priority = 0x100 | PNP_RES_PRIORITY_ACCEPTABLE;
if (len > 0)
dependent = 0x100 | p[1];
pnp_build_resource(dev,dependent);
depnum = pnp_get_max_depnum(dev);
priority = 0x100 | p[1];
option = pnp_register_dependent_option(dev, priority);
if (!option)
return NULL;
break;
}
case SMALL_TAG_ENDDEP:
{
if (len != 0)
goto sm_err;
depnum = 0;
break;
}
case SMALL_TAG_PORT:
{
if (len != 7)
goto sm_err;
possible_port(p,len,depnum,dev);
possible_port(p,len,option);
break;
}
case SMALL_TAG_FIXEDPORT:
{
if (len != 3)
goto sm_err;
possible_fixed_port(p,len,depnum,dev);
possible_fixed_port(p,len,option);
break;
}
case SMALL_TAG_END:
......@@ -481,12 +486,12 @@ static void write_mem(unsigned char *p, struct resource * res)
{
unsigned long base = res->start;
unsigned long len = res->end - res->start + 1;
p[2] = (base >> 8) & 0xff;
p[3] = ((base >> 8) >> 8) & 0xff;
p[4] = (base >> 8) & 0xff;
p[5] = ((base >> 8) >> 8) & 0xff;
p[8] = (len >> 8) & 0xff;
p[9] = ((len >> 8) >> 8) & 0xff;
p[6] = (base >> 8) & 0xff;
p[7] = ((base >> 8) >> 8) & 0xff;
p[10] = (len >> 8) & 0xff;
p[11] = ((len >> 8) >> 8) & 0xff;
return;
}
......@@ -494,32 +499,32 @@ static void write_mem32(unsigned char *p, struct resource * res)
{
unsigned long base = res->start;
unsigned long len = res->end - res->start + 1;
p[2] = base & 0xff;
p[3] = (base >> 8) & 0xff;
p[4] = (base >> 16) & 0xff;
p[5] = (base >> 24) & 0xff;
p[6] = base & 0xff;
p[7] = (base >> 8) & 0xff;
p[8] = (base >> 16) & 0xff;
p[9] = (base >> 24) & 0xff;
p[14] = len & 0xff;
p[15] = (len >> 8) & 0xff;
p[16] = (len >> 16) & 0xff;
p[17] = (len >> 24) & 0xff;
p[4] = base & 0xff;
p[5] = (base >> 8) & 0xff;
p[6] = (base >> 16) & 0xff;
p[7] = (base >> 24) & 0xff;
p[8] = base & 0xff;
p[9] = (base >> 8) & 0xff;
p[10] = (base >> 16) & 0xff;
p[11] = (base >> 24) & 0xff;
p[16] = len & 0xff;
p[17] = (len >> 8) & 0xff;
p[18] = (len >> 16) & 0xff;
p[19] = (len >> 24) & 0xff;
return;
}
static void write_fixed_mem32(unsigned char *p, struct resource * res)
{ unsigned long base = res->start;
unsigned long len = res->end - res->start + 1;
p[2] = base & 0xff;
p[3] = (base >> 8) & 0xff;
p[4] = (base >> 16) & 0xff;
p[5] = (base >> 24) & 0xff;
p[6] = len & 0xff;
p[7] = (len >> 8) & 0xff;
p[8] = (len >> 16) & 0xff;
p[9] = (len >> 24) & 0xff;
p[4] = base & 0xff;
p[5] = (base >> 8) & 0xff;
p[6] = (base >> 16) & 0xff;
p[7] = (base >> 24) & 0xff;
p[8] = len & 0xff;
p[9] = (len >> 8) & 0xff;
p[10] = (len >> 16) & 0xff;
p[11] = (len >> 24) & 0xff;
return;
}
......@@ -630,7 +635,7 @@ unsigned char * pnp_write_resources(unsigned char * p, unsigned char * end, stru
{
if (len != 2)
goto sm_err;
write_dma(p, &res->dma_resource[irq]);
write_dma(p, &res->dma_resource[dma]);
dma++;
break;
}
......
......@@ -315,19 +315,6 @@ static const struct pnp_device_id pnp_dev_table[] = {
MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
static inline void avoid_irq_share(struct pnp_dev *dev)
{
unsigned int map = 0x1FF8;
struct pnp_irq *irq;
struct pnp_resources *res = dev->possible;
serial8250_get_irq_map(&map);
for ( ; res; res = res->dep)
for (irq = res->irq; irq; irq = irq->next)
irq->map = map;
}
static char *modem_names[] __devinitdata = {
"MODEM", "Modem", "modem", "FAX", "Fax", "fax",
"56K", "56k", "K56", "33.6", "28.8", "14.4",
......@@ -346,6 +333,29 @@ static int __devinit check_name(char *name)
return 0;
}
static int __devinit check_resources(struct pnp_option *option)
{
struct pnp_option *tmp;
if (!option)
return 0;
for (tmp = option; tmp; tmp = tmp->next) {
struct pnp_port *port;
for (port = tmp->port; port; port = port->next)
if ((port->size == 8) &&
((port->min == 0x2f8) ||
(port->min == 0x3f8) ||
(port->min == 0x2e8) ||
#ifdef CONFIG_X86_PC9800
(port->min == 0x8b0) ||
#endif
(port->min == 0x3e8)))
return 1;
}
return 0;
}
/*
* Given a complete unknown PnP device, try to use some heuristics to
* detect modems. Currently use such heuristic set:
......@@ -357,30 +367,16 @@ static int __devinit check_name(char *name)
* PnP modems, alternatively we must hardcode all modems in pnp_devices[]
* table.
*/
static int serial_pnp_guess_board(struct pnp_dev *dev, int *flags)
static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags)
{
struct pnp_resources *res = dev->possible;
struct pnp_resources *resa;
if (!(check_name(dev->dev.name) || (dev->card && check_name(dev->card->dev.name))))
return -ENODEV;
if (!res)
return -ENODEV;
if (check_resources(dev->independent))
return 0;
for (resa = res->dep; resa; resa = resa->dep) {
struct pnp_port *port;
for (port = res->port; port; port = port->next)
if ((port->size == 8) &&
((port->min == 0x2f8) ||
(port->min == 0x3f8) ||
(port->min == 0x2e8) ||
#ifdef CONFIG_X86_PC9800
(port->min == 0x8b0) ||
#endif
(port->min == 0x3e8)))
return 0;
}
if (check_resources(dev->dependent))
return 0;
return -ENODEV;
}
......@@ -395,8 +391,6 @@ serial_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id)
if (ret < 0)
return ret;
}
if (flags & SPCI_FL_NO_SHIRQ)
avoid_irq_share(dev);
memset(&serial_req, 0, sizeof(serial_req));
serial_req.irq = pnp_irq(dev,0);
serial_req.port = pnp_port_start(dev, 0);
......
......@@ -57,6 +57,15 @@ num_online_cpus(void)
return hweight64(cpu_online_map);
}
extern inline int
any_online_cpu(unsigned int mask)
{
if (mask & cpu_online_map)
return __ffs(mask & cpu_online_map);
return -1;
}
extern int smp_call_function_on_cpu(void (*func) (void *info), void *info,int retry, int wait, unsigned long cpu);
#else /* CONFIG_SMP */
......
......@@ -593,13 +593,7 @@ static inline long read(int fd, char * buf, size_t nr)
return sys_read(fd, buf, nr);
}
extern int __kernel_execve(char *, char **, char **, struct pt_regs *);
static inline long execve(char * file, char ** argvp, char ** envp)
{
struct pt_regs regs;
memset(&regs, 0, sizeof(regs));
return __kernel_execve(file, argvp, envp, &regs);
}
extern long execve(char *, char **, char **);
extern long sys_setsid(void);
static inline long setsid(void)
......
......@@ -822,19 +822,19 @@ xor_alpha_prefetch_5: \n\
");
static struct xor_block_template xor_block_alpha = {
name: "alpha",
do_2: xor_alpha_2,
do_3: xor_alpha_3,
do_4: xor_alpha_4,
do_5: xor_alpha_5,
.name = "alpha",
.do_2 = xor_alpha_2,
.do_3 = xor_alpha_3,
.do_4 = xor_alpha_4,
.do_5 = xor_alpha_5,
};
static struct xor_block_template xor_block_alpha_prefetch = {
name: "alpha prefetch",
do_2: xor_alpha_prefetch_2,
do_3: xor_alpha_prefetch_3,
do_4: xor_alpha_prefetch_4,
do_5: xor_alpha_prefetch_5,
.name = "alpha prefetch",
.do_2 = xor_alpha_prefetch_2,
.do_3 = xor_alpha_prefetch_3,
.do_4 = xor_alpha_prefetch_4,
.do_5 = xor_alpha_prefetch_5,
};
/* For grins, also test the generic routines. */
......
#ifndef _LINUX_FIRMWARE_H
#define _LINUX_FIRMWARE_H
#include <linux/module.h>
#include <linux/types.h>
#define FIRMWARE_NAME_MAX 30
struct firmware {
size_t size;
u8 *data;
};
int request_firmware(const struct firmware **fw, const char *name,
struct device *device);
int request_firmware_nowait(
struct module *module,
const char *name, struct device *device, void *context,
void (*cont)(const struct firmware *fw, void *context));
void release_firmware(const struct firmware *fw);
void register_firmware(const char *name, const u8 *data, size_t size);
#endif
......@@ -283,7 +283,7 @@ typedef struct atemu {
#endif
int mdmcmdl; /* Length of Modem-Commandbuffer */
int pluscount; /* Counter for +++ sequence */
int lastplus; /* Timestamp of last + */
unsigned long lastplus; /* Timestamp of last + */
char mdmcmd[255]; /* Modem-Commandbuffer */
unsigned int charge; /* Charge units of current connection */
} atemu;
......
......@@ -95,7 +95,8 @@ struct isdn_ppp_resetparams {
* check the original include for more information
*/
struct isdn_ppp_compressor {
struct isdn_ppp_compressor *next, *prev;
struct module *owner;
struct list_head list;
int num; /* CCP compression protocol number */
void *(*alloc) (struct isdn_ppp_comp_data *);
......
......@@ -602,6 +602,8 @@
#define PCI_DEVICE_ID_HP_DIVA_TOSCA1 0x1049
#define PCI_DEVICE_ID_HP_DIVA_TOSCA2 0x104A
#define PCI_DEVICE_ID_HP_DIVA_MAESTRO 0x104B
#define PCI_DEVICE_ID_HP_REO_SBA 0x10f0
#define PCI_DEVICE_ID_HP_REO_IOC 0x10f1
#define PCI_DEVICE_ID_HP_VISUALIZE_FXE 0x108b
#define PCI_DEVICE_ID_HP_DIVA_HALFDOME 0x1223
#define PCI_DEVICE_ID_HP_DIVA_KEYSTONE 0x1226
......
......@@ -102,22 +102,13 @@ struct pnp_mem {
#define PNP_RES_PRIORITY_FUNCTIONAL 2
#define PNP_RES_PRIORITY_INVALID 65535
struct pnp_resources {
struct pnp_option {
unsigned short priority; /* priority */
struct pnp_port *port; /* first port */
struct pnp_irq *irq; /* first IRQ */
struct pnp_dma *dma; /* first DMA */
struct pnp_mem *mem; /* first memory resource */
struct pnp_dev *dev; /* parent */
struct pnp_resources *dep; /* dependent resources */
};
struct pnp_rule_table {
int depnum;
struct pnp_port *port[PNP_MAX_PORT];
struct pnp_irq *irq[PNP_MAX_IRQ];
struct pnp_dma *dma[PNP_MAX_DMA];
struct pnp_mem *mem[PNP_MAX_MEM];
struct pnp_option *next; /* used to chain dependent resources */
};
struct pnp_resource_table {
......@@ -187,8 +178,6 @@ static inline void pnp_set_card_drvdata (struct pnp_card_link *pcard, void *data
struct pnp_dev {
struct device dev; /* Driver Model device interface */
unsigned char number; /* used as an index, must be unique */
int active;
int capabilities;
int status;
struct list_head global_list; /* node in global list of devices */
......@@ -201,11 +190,13 @@ struct pnp_dev {
struct pnp_driver * driver;
struct pnp_card_link * card_link;
struct pnp_id * id; /* supported EISA IDs*/
struct pnp_resource_table res; /* contains the currently chosen resources */
struct pnp_resources * possible; /* a list of possible resources */
struct pnp_rule_table * rule; /* the current possible resource set */
int config_mode; /* flags that determine how the device's resources should be configured */
struct pnp_id * id; /* supported EISA IDs*/
int active;
int capabilities;
struct pnp_option * independent;
struct pnp_option * dependent;
struct pnp_resource_table res;
void * protocol_data; /* Used to store protocol specific data */
unsigned short regs; /* ISAPnP: supported registers */
......@@ -252,11 +243,9 @@ struct pnp_fixup {
void (*quirk_function)(struct pnp_dev *dev); /* fixup function */
};
/* config modes */
#define PNP_CONFIG_AUTO 0x0001 /* Use the Resource Configuration Engine to determine resource settings */
#define PNP_CONFIG_MANUAL 0x0002 /* the config has been manually specified */
#define PNP_CONFIG_FORCE 0x0004 /* disables validity checking */
#define PNP_CONFIG_INVALID 0x0008 /* If this flag is set, the pnp layer will refuse to activate the device */
/* config parameters */
#define PNP_CONFIG_NORMAL 0x0001
#define PNP_CONFIG_FORCE 0x0002 /* disables validity checking */
/* capabilities */
#define PNP_READ 0x0001
......@@ -271,7 +260,7 @@ struct pnp_fixup {
((dev)->capabilities & PNP_WRITE))
#define pnp_can_disable(dev) (((dev)->protocol) && ((dev)->protocol->disable) && \
((dev)->capabilities & PNP_DISABLE))
#define pnp_can_configure(dev) ((!(dev)->active) && ((dev)->config_mode & PNP_CONFIG_AUTO) && \
#define pnp_can_configure(dev) ((!(dev)->active) && \
((dev)->capabilities & PNP_CONFIGURABLE))
#ifdef CONFIG_ISAPNP
......@@ -383,7 +372,7 @@ struct pnp_protocol {
#if defined(CONFIG_PNP)
/* core */
/* device management */
int pnp_register_protocol(struct pnp_protocol *protocol);
void pnp_unregister_protocol(struct pnp_protocol *protocol);
int pnp_add_device(struct pnp_dev *dev);
......@@ -392,7 +381,7 @@ int pnp_device_attach(struct pnp_dev *pnp_dev);
void pnp_device_detach(struct pnp_dev *pnp_dev);
extern struct list_head pnp_global;
/* card */
/* multidevice card support */
int pnp_add_card(struct pnp_card *card);
void pnp_remove_card(struct pnp_card *card);
int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev);
......@@ -404,41 +393,35 @@ int pnp_register_card_driver(struct pnp_card_driver * drv);
void pnp_unregister_card_driver(struct pnp_card_driver * drv);
extern struct list_head pnp_cards;
/* resource */
struct pnp_resources * pnp_build_resource(struct pnp_dev *dev, int dependent);
struct pnp_resources * pnp_find_resources(struct pnp_dev *dev, int depnum);
int pnp_get_max_depnum(struct pnp_dev *dev);
int pnp_add_irq_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data);
int pnp_add_dma_resource(struct pnp_dev *dev, int depnum, struct pnp_dma *data);
int pnp_add_port_resource(struct pnp_dev *dev, int depnum, struct pnp_port *data);
int pnp_add_mem_resource(struct pnp_dev *dev, int depnum, struct pnp_mem *data);
void pnp_init_resource_table(struct pnp_resource_table *table);
int pnp_generate_rule(struct pnp_dev * dev, int depnum, struct pnp_rule_table * rule);
/* manager */
/* resource management */
struct pnp_option * pnp_register_independent_option(struct pnp_dev *dev);
struct pnp_option * pnp_register_dependent_option(struct pnp_dev *dev, int priority);
int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data);
int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data);
int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data);
int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data);
void pnp_init_resources(struct pnp_resource_table *table);
int pnp_assign_resources(struct pnp_dev *dev, int depnum);
int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res, int mode);
int pnp_auto_config_dev(struct pnp_dev *dev);
int pnp_validate_config(struct pnp_dev *dev);
int pnp_activate_dev(struct pnp_dev *dev);
int pnp_disable_dev(struct pnp_dev *dev);
void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size);
int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res, int mode);
int pnp_auto_config_dev(struct pnp_dev *dev);
/* driver */
int compare_pnp_id(struct pnp_id * pos, const char * id);
int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev);
int pnp_register_driver(struct pnp_driver *drv);
void pnp_unregister_driver(struct pnp_driver *drv);
/* support */
/* protocol helpers */
int pnp_is_active(struct pnp_dev * dev);
unsigned char * pnp_parse_current_resources(unsigned char * p, unsigned char * end, struct pnp_resource_table * res);
unsigned char * pnp_parse_possible_resources(unsigned char * p, unsigned char * end, struct pnp_dev * dev);
unsigned char * pnp_write_resources(unsigned char * p, unsigned char * end, struct pnp_resource_table * res);
int compare_pnp_id(struct pnp_id * pos, const char * id);
int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev);
int pnp_register_driver(struct pnp_driver *drv);
void pnp_unregister_driver(struct pnp_driver *drv);
#else
/* just in case anyone decides to call these without PnP Support Enabled */
/* core */
/* device management */
static inline int pnp_register_protocol(struct pnp_protocol *protocol) { return -ENODEV; }
static inline void pnp_unregister_protocol(struct pnp_protocol *protocol) { }
static inline int pnp_init_device(struct pnp_dev *dev) { return -ENODEV; }
......@@ -447,7 +430,7 @@ static inline void pnp_remove_device(struct pnp_dev *dev) { }
static inline int pnp_device_attach(struct pnp_dev *pnp_dev) { return -ENODEV; }
static inline void pnp_device_detach(struct pnp_dev *pnp_dev) { ; }
/* card */
/* multidevice card support */
static inline int pnp_add_card(struct pnp_card *card) { return -ENODEV; }
static inline void pnp_remove_card(struct pnp_card *card) { ; }
static inline int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev) { return -ENODEV; }
......@@ -458,35 +441,31 @@ static inline void pnp_release_card_device(struct pnp_dev * dev) { ; }
static inline int pnp_register_card_driver(struct pnp_card_driver * drv) { return -ENODEV; }
static inline void pnp_unregister_card_driver(struct pnp_card_driver * drv) { ; }
/* resource */
static inline struct pnp_resources * pnp_build_resource(struct pnp_dev *dev, int dependent) { return NULL; }
static inline struct pnp_resources * pnp_find_resources(struct pnp_dev *dev, int depnum) { return NULL; }
static inline int pnp_get_max_depnum(struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_add_irq_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) { return -ENODEV; }
static inline int pnp_add_dma_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) { return -ENODEV; }
static inline int pnp_add_port_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) { return -ENODEV; }
static inline int pnp_add_mem_resource(struct pnp_dev *dev, int depnum, struct pnp_irq *data) { return -ENODEV; }
static inline void pnp_init_resource_table(struct pnp_resource_table *table) { ; }
static inline int pnp_generate_rule(struct pnp_dev * dev, int depnum, struct pnp_rule_table * rule) { return -ENODEV; }
/* manager */
static inline int pnp_activate_dev(struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_disable_dev(struct pnp_dev *dev) { return -ENODEV; }
static inline void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size) { ; }
/* resource management */
static inline struct pnp_option * pnp_register_independent_option(struct pnp_dev *dev) { return NULL; }
static inline struct pnp_option * pnp_register_dependent_option(struct pnp_dev *dev, int priority) { return NULL; }
static inline int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data) { return -ENODEV; }
static inline int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data) { return -ENODEV; }
static inline int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data) { return -ENODEV; }
static inline int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data) { return -ENODEV; }
static inline void pnp_init_resources(struct pnp_resource_table *table) { }
static inline int pnp_assign_resources(struct pnp_dev *dev, int depnum) { return -ENODEV; }
static inline int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res, int mode) { return -ENODEV; }
static inline int pnp_auto_config_dev(struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_validate_config(struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_activate_dev(struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_disable_dev(struct pnp_dev *dev) { return -ENODEV; }
static inline void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size) { }
/* driver */
static inline int compare_pnp_id(struct list_head * id_list, const char * id) { return -ENODEV; }
static inline int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_register_driver(struct pnp_driver *drv) { return -ENODEV; }
static inline void pnp_unregister_driver(struct pnp_driver *drv) { ; }
/* support */
static inline int pnp_is_active(struct pnp_dev * dev) { return -ENODEV; }
/* protocol helpers */
static inline int pnp_is_active(struct pnp_dev * dev) { return 0; }
static inline unsigned char * pnp_parse_current_resources(unsigned char * p, unsigned char * end, struct pnp_resource_table * res) { return NULL; }
static inline unsigned char * pnp_parse_possible_resources(unsigned char * p, unsigned char * end, struct pnp_dev * dev) { return NULL; }
static inline unsigned char * pnp_write_resources(unsigned char * p, unsigned char * end, struct pnp_resource_table * res) { return NULL; }
static inline int compare_pnp_id(struct pnp_id * pos, const char * id) { return -ENODEV; }
static inline int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_register_driver(struct pnp_driver *drv) { return -ENODEV; }
static inline void pnp_unregister_driver(struct pnp_driver *drv) { ; }
#endif /* CONFIG_PNP */
......
......@@ -72,7 +72,6 @@ struct sys_device {
u32 id;
struct sysdev_class * cls;
struct kobject kobj;
struct list_head entry;
};
extern int sys_device_register(struct sys_device *);
......
......@@ -592,7 +592,6 @@ EXPORT_SYMBOL(__tasklet_hi_schedule);
/* init task, for moving kthread roots - ought to export a function ?? */
EXPORT_SYMBOL(init_task);
EXPORT_SYMBOL(init_thread_union);
EXPORT_SYMBOL(tasklist_lock);
EXPORT_SYMBOL(find_task_by_pid);
......
......@@ -100,6 +100,9 @@ static void fill_kobj_path(struct kset *kset, struct kobject *kobj, char *path,
#define BUFFER_SIZE 1024 /* should be enough memory for the env */
#define NUM_ENVP 32 /* number of env pointers */
static unsigned long sequence_num;
static spinlock_t sequence_lock = SPIN_LOCK_UNLOCKED;
static void kset_hotplug(const char *action, struct kset *kset,
struct kobject *kobj)
{
......@@ -112,6 +115,7 @@ static void kset_hotplug(const char *action, struct kset *kset,
int kobj_path_length;
char *kobj_path = NULL;
char *name = NULL;
unsigned long seq;
/* If the kset has a filter operation, call it. If it returns
failure, no hotplug event is required. */
......@@ -152,6 +156,13 @@ static void kset_hotplug(const char *action, struct kset *kset,
envp [i++] = scratch;
scratch += sprintf(scratch, "ACTION=%s", action) + 1;
spin_lock(&sequence_lock);
seq = sequence_num++;
spin_unlock(&sequence_lock);
envp [i++] = scratch;
scratch += sprintf(scratch, "SEQNUM=%ld", seq) + 1;
kobj_path_length = get_kobj_path_length (kset, kobj);
kobj_path = kmalloc (kobj_path_length, GFP_KERNEL);
if (!kobj_path)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment