Commit 3935761c authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/gregkh/linux/pci-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents 65458f96 c1cdc0d2
...@@ -204,7 +204,7 @@ GENKSYMS = scripts/genksyms/genksyms ...@@ -204,7 +204,7 @@ GENKSYMS = scripts/genksyms/genksyms
DEPMOD = /sbin/depmod DEPMOD = /sbin/depmod
KALLSYMS = scripts/kallsyms KALLSYMS = scripts/kallsyms
PERL = perl PERL = perl
CHECK = /home/torvalds/parser/check CHECK = sparse
MODFLAGS = -DMODULE MODFLAGS = -DMODULE
CFLAGS_MODULE = $(MODFLAGS) CFLAGS_MODULE = $(MODFLAGS)
AFLAGS_MODULE = $(MODFLAGS) AFLAGS_MODULE = $(MODFLAGS)
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include <linux/config.h> #include <linux/config.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/cpufreq.h>
#include <asm/leds.h> #include <asm/leds.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -66,13 +65,6 @@ int suspend(void) ...@@ -66,13 +65,6 @@ int suspend(void)
*/ */
device_resume(RESUME_POWER_ON); device_resume(RESUME_POWER_ON);
/*
* Restore the CPU frequency settings.
*/
#ifdef CONFIG_CPU_FREQ
cpufreq_restore();
#endif
/* /*
* Resume LDM devices. * Resume LDM devices.
*/ */
......
...@@ -25,6 +25,9 @@ ...@@ -25,6 +25,9 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/mc146818rtc.h> #include <linux/mc146818rtc.h>
#include <linux/kernel_stat.h> #include <linux/kernel_stat.h>
#include <linux/sysdev.h>
#include <linux/module.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#include <asm/smp.h> #include <asm/smp.h>
...@@ -460,9 +463,6 @@ void __init setup_local_APIC (void) ...@@ -460,9 +463,6 @@ void __init setup_local_APIC (void)
#ifdef CONFIG_PM #ifdef CONFIG_PM
#include <linux/device.h>
#include <linux/module.h>
static struct { static struct {
/* 'active' is true if the local APIC was enabled by us and /* 'active' is true if the local APIC was enabled by us and
not the BIOS; this signifies that we are also responsible not the BIOS; this signifies that we are also responsible
...@@ -484,13 +484,11 @@ static struct { ...@@ -484,13 +484,11 @@ static struct {
unsigned int apic_thmr; unsigned int apic_thmr;
} apic_pm_state; } apic_pm_state;
static int lapic_suspend(struct device *dev, u32 state, u32 level) static int lapic_suspend(struct sys_device *dev, u32 state)
{ {
unsigned int l, h; unsigned int l, h;
unsigned long flags; unsigned long flags;
if (level != SUSPEND_POWER_DOWN)
return 0;
if (!apic_pm_state.active) if (!apic_pm_state.active)
return 0; return 0;
...@@ -517,13 +515,11 @@ static int lapic_suspend(struct device *dev, u32 state, u32 level) ...@@ -517,13 +515,11 @@ static int lapic_suspend(struct device *dev, u32 state, u32 level)
return 0; return 0;
} }
static int lapic_resume(struct device *dev, u32 level) static int lapic_resume(struct sys_device *dev)
{ {
unsigned int l, h; unsigned int l, h;
unsigned long flags; unsigned long flags;
if (level != RESUME_POWER_ON)
return 0;
if (!apic_pm_state.active) if (!apic_pm_state.active)
return 0; return 0;
...@@ -557,38 +553,37 @@ static int lapic_resume(struct device *dev, u32 level) ...@@ -557,38 +553,37 @@ static int lapic_resume(struct device *dev, u32 level)
return 0; return 0;
} }
static struct device_driver lapic_driver = {
.name = "lapic", static struct sysdev_class lapic_sysclass = {
.bus = &system_bus_type, set_kset_name("lapic"),
.resume = lapic_resume, .resume = lapic_resume,
.suspend = lapic_suspend, .suspend = lapic_suspend,
}; };
/* not static, needed by child devices */ static struct sys_device device_lapic = {
struct sys_device device_lapic = { .id = 0,
.name = "lapic", .cls = &lapic_sysclass,
.id = 0,
.dev = {
.name = "lapic",
.driver = &lapic_driver,
},
}; };
EXPORT_SYMBOL(device_lapic);
static void __init apic_pm_activate(void) static void __init apic_pm_activate(void)
{ {
apic_pm_state.active = 1; apic_pm_state.active = 1;
} }
static int __init init_lapic_devicefs(void) static int __init init_lapic_sysfs(void)
{ {
int error;
if (!cpu_has_apic) if (!cpu_has_apic)
return 0; return 0;
/* XXX: remove suspend/resume procs if !apic_pm_state.active? */ /* XXX: remove suspend/resume procs if !apic_pm_state.active? */
driver_register(&lapic_driver);
return sys_device_register(&device_lapic); error = sysdev_class_register(&lapic_sysclass);
if (!error)
error = sys_device_register(&device_lapic);
return error;
} }
device_initcall(init_lapic_devicefs); device_initcall(init_lapic_sysfs);
#else /* CONFIG_PM */ #else /* CONFIG_PM */
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/cpu.h>
#include <asm/mtrr.h> #include <asm/mtrr.h>
...@@ -546,6 +547,58 @@ static void init_other_cpus(void) ...@@ -546,6 +547,58 @@ static void init_other_cpus(void)
} }
} }
struct mtrr_value {
mtrr_type ltype;
unsigned long lbase;
unsigned int lsize;
};
static struct mtrr_value * mtrr_state;
static int mtrr_save(struct sys_device * sysdev, u32 state)
{
int i;
int size = num_var_ranges * sizeof(struct mtrr_value);
mtrr_state = kmalloc(size,GFP_KERNEL);
if (mtrr_state)
memset(mtrr_state,0,size);
else
return -ENOMEM;
for (i = 0; i < num_var_ranges; i++) {
mtrr_if->get(i,
&mtrr_state[i].lbase,
&mtrr_state[i].lsize,
&mtrr_state[i].ltype);
}
return 0;
}
static int mtrr_restore(struct sys_device * sysdev)
{
int i;
for (i = 0; i < num_var_ranges; i++) {
if (mtrr_state[i].lsize)
set_mtrr(i,
mtrr_state[i].lbase,
mtrr_state[i].lsize,
mtrr_state[i].ltype);
}
kfree(mtrr_state);
return 0;
}
static struct sysdev_driver mtrr_sysdev_driver = {
.save = mtrr_save,
.restore = mtrr_restore,
};
/** /**
* mtrr_init - initialie mtrrs on the boot CPU * mtrr_init - initialie mtrrs on the boot CPU
* *
...@@ -630,8 +683,11 @@ static int __init mtrr_init(void) ...@@ -630,8 +683,11 @@ static int __init mtrr_init(void)
set_num_var_ranges(); set_num_var_ranges();
init_table(); init_table();
init_other_cpus(); init_other_cpus();
return sysdev_driver_register(&cpu_sysdev_class,
&mtrr_sysdev_driver);
} }
return mtrr_if ? -ENXIO : 0; return -ENXIO;
} }
char *mtrr_strings[MTRR_NUM_TYPES] = char *mtrr_strings[MTRR_NUM_TYPES] =
...@@ -645,5 +701,5 @@ char *mtrr_strings[MTRR_NUM_TYPES] = ...@@ -645,5 +701,5 @@ char *mtrr_strings[MTRR_NUM_TYPES] =
"write-back", /* 6 */ "write-back", /* 6 */
}; };
core_initcall(mtrr_init); subsys_initcall(mtrr_init);
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel_stat.h> #include <linux/kernel_stat.h>
#include <linux/device.h> #include <linux/sysdev.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -238,35 +238,31 @@ void mask_and_ack_8259A(unsigned int irq) ...@@ -238,35 +238,31 @@ void mask_and_ack_8259A(unsigned int irq)
} }
} }
static int i8259A_resume(struct device *dev, u32 level) static int i8259A_resume(struct sys_device *dev)
{ {
if (level == RESUME_POWER_ON) init_8259A(0);
init_8259A(0);
return 0; return 0;
} }
static struct device_driver i8259A_driver = { static struct sysdev_class i8259_sysdev_class = {
.name = "pic", set_kset_name("i8259"),
.bus = &system_bus_type, .resume = i8259A_resume,
.resume = i8259A_resume,
}; };
static struct sys_device device_i8259A = { static struct sys_device device_i8259A = {
.name = "pic", .id = 0,
.id = 0, .cls = &i8259_sysdev_class,
.dev = {
.name = "i8259A PIC",
.driver = &i8259A_driver,
},
}; };
static int __init init_8259A_devicefs(void) static int __init i8259A_init_sysfs(void)
{ {
driver_register(&i8259A_driver); int error = sysdev_class_register(&i8259_sysdev_class);
return sys_device_register(&device_i8259A); if (!error)
error = sys_device_register(&device_i8259A);
return error;
} }
device_initcall(init_8259A_devicefs); device_initcall(i8259A_init_sysfs);
void init_8259A(int auto_eoi) void init_8259A(int auto_eoi)
{ {
...@@ -385,35 +381,31 @@ static void setup_timer(void) ...@@ -385,35 +381,31 @@ static void setup_timer(void)
spin_unlock_irqrestore(&i8253_lock, flags); spin_unlock_irqrestore(&i8253_lock, flags);
} }
static int timer_resume(struct device *dev, u32 level) static int timer_resume(struct sys_device *dev)
{ {
if (level == RESUME_POWER_ON) setup_timer();
setup_timer();
return 0; return 0;
} }
static struct device_driver timer_driver = { static struct sysdev_class timer_sysclass = {
.name = "timer", set_kset_name("timer"),
.bus = &system_bus_type, .resume = timer_resume,
.resume = timer_resume,
}; };
static struct sys_device device_timer = { static struct sys_device device_timer = {
.name = "timer", .id = 0,
.id = 0, .cls = &timer_sysclass,
.dev = {
.name = "timer",
.driver = &timer_driver,
},
}; };
static int __init init_timer_devicefs(void) static int __init init_timer_sysfs(void)
{ {
driver_register(&timer_driver); int error = sysdev_class_register(&timer_sysclass);
return sys_device_register(&device_timer); if (!error)
error = sys_device_register(&device_timer);
return error;
} }
device_initcall(init_timer_devicefs); device_initcall(init_timer_sysfs);
void __init init_IRQ(void) void __init init_IRQ(void)
{ {
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/mc146818rtc.h> #include <linux/mc146818rtc.h>
#include <linux/kernel_stat.h> #include <linux/kernel_stat.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/sysdev.h>
#include <asm/smp.h> #include <asm/smp.h>
#include <asm/mtrr.h> #include <asm/mtrr.h>
...@@ -180,53 +181,48 @@ void enable_lapic_nmi_watchdog(void) ...@@ -180,53 +181,48 @@ void enable_lapic_nmi_watchdog(void)
#ifdef CONFIG_PM #ifdef CONFIG_PM
#include <linux/device.h>
static int nmi_pm_active; /* nmi_active before suspend */ static int nmi_pm_active; /* nmi_active before suspend */
static int lapic_nmi_suspend(struct device *dev, u32 state, u32 level) static int lapic_nmi_suspend(struct sys_device *dev, u32 state)
{ {
if (level != SUSPEND_POWER_DOWN)
return 0;
nmi_pm_active = nmi_active; nmi_pm_active = nmi_active;
disable_lapic_nmi_watchdog(); disable_lapic_nmi_watchdog();
return 0; return 0;
} }
static int lapic_nmi_resume(struct device *dev, u32 level) static int lapic_nmi_resume(struct sys_device *dev)
{ {
if (level != RESUME_POWER_ON)
return 0;
if (nmi_pm_active > 0) if (nmi_pm_active > 0)
enable_lapic_nmi_watchdog(); enable_lapic_nmi_watchdog();
return 0; return 0;
} }
static struct device_driver lapic_nmi_driver = {
.name = "lapic_nmi", static struct sysdev_class nmi_sysclass = {
.bus = &system_bus_type, set_kset_name("lapic_nmi"),
.resume = lapic_nmi_resume, .resume = lapic_nmi_resume,
.suspend = lapic_nmi_suspend, .suspend = lapic_nmi_suspend,
}; };
static struct sys_device device_lapic_nmi = { static struct sys_device device_lapic_nmi = {
.name = "lapic_nmi", .id = 0,
.id = 0, .cls = &nmi_sysclass,
.dev = {
.name = "lapic_nmi",
.driver = &lapic_nmi_driver,
.parent = &device_lapic.dev,
},
}; };
static int __init init_lapic_nmi_devicefs(void) static int __init init_lapic_nmi_sysfs(void)
{ {
int error;
if (nmi_active == 0) if (nmi_active == 0)
return 0; return 0;
driver_register(&lapic_nmi_driver);
return sys_device_register(&device_lapic_nmi); error = sysdev_class_register(&nmi_sysclass);
if (!error)
error = sys_device_register(&device_lapic_nmi);
return error;
} }
/* must come after the local APIC's device_initcall() */ /* must come after the local APIC's device_initcall() */
late_initcall(init_lapic_nmi_devicefs); late_initcall(init_lapic_nmi_sysfs);
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
......
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/device.h> #include <linux/sysdev.h>
#include <linux/bcd.h> #include <linux/bcd.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -278,18 +278,22 @@ unsigned long get_cmos_time(void) ...@@ -278,18 +278,22 @@ unsigned long get_cmos_time(void)
return retval; return retval;
} }
static struct sysdev_class rtc_sysclass = {
set_kset_name("rtc"),
};
/* XXX this driverfs stuff should probably go elsewhere later -john */ /* XXX this driverfs stuff should probably go elsewhere later -john */
static struct sys_device device_i8253 = { static struct sys_device device_i8253 = {
.name = "rtc",
.id = 0, .id = 0,
.dev = { .cls = &rtc_sysclass,
.name = "i8253 Real Time Clock",
},
}; };
static int time_init_device(void) static int time_init_device(void)
{ {
return sys_device_register(&device_i8253); int error = sysdev_class_register(&rtc_sysclass);
if (!error)
error = sys_device_register(&device_i8253);
return error;
} }
device_initcall(time_init_device); device_initcall(time_init_device);
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/oprofile.h> #include <linux/oprofile.h>
#include <linux/device.h> #include <linux/sysdev.h>
#include <asm/nmi.h> #include <asm/nmi.h>
#include <asm/msr.h> #include <asm/msr.h>
#include <asm/apic.h> #include <asm/apic.h>
...@@ -31,53 +31,48 @@ static int nmi_enabled = 0; ...@@ -31,53 +31,48 @@ static int nmi_enabled = 0;
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int nmi_suspend(struct device *dev, u32 state, u32 level) static int nmi_suspend(struct sys_device *dev, u32 state)
{ {
if (level != SUSPEND_POWER_DOWN)
return 0;
if (nmi_enabled == 1) if (nmi_enabled == 1)
nmi_stop(); nmi_stop();
return 0; return 0;
} }
static int nmi_resume(struct device *dev, u32 level) static int nmi_resume(struct sys_device *dev)
{ {
if (level != RESUME_POWER_ON)
return 0;
if (nmi_enabled == 1) if (nmi_enabled == 1)
nmi_start(); nmi_start();
return 0; return 0;
} }
static struct device_driver nmi_driver = { static struct sysdev_class oprofile_sysclass = {
.name = "oprofile", set_kset_name("oprofile"),
.bus = &system_bus_type,
.resume = nmi_resume, .resume = nmi_resume,
.suspend = nmi_suspend, .suspend = nmi_suspend,
}; };
static struct device device_nmi = { static struct sys_device device_oprofile = {
.name = "oprofile", .id = 0,
.bus_id = "oprofile", .cls = &oprofile_sysclass,
.driver = &nmi_driver,
.parent = &device_lapic.dev,
}; };
static int __init init_driverfs(void) static int __init init_driverfs(void)
{ {
driver_register(&nmi_driver); int error;
return device_register(&device_nmi); if (!(error = sysdev_class_register(&oprofile_sysclass)))
error = sys_device_register(&device_oprofile);
return error;
} }
static void __exit exit_driverfs(void) static void __exit exit_driverfs(void)
{ {
device_unregister(&device_nmi); sys_device_unregister(&device_oprofile);
driver_unregister(&nmi_driver); sysdev_class_unregister(&oprofile_sysclass);
} }
#else #else
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel_stat.h> #include <linux/kernel_stat.h>
#include <linux/device.h> #include <linux/sysdev.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -413,35 +413,31 @@ static void setup_timer(void) ...@@ -413,35 +413,31 @@ static void setup_timer(void)
outb(LATCH >> 8 , 0x40); /* MSB */ outb(LATCH >> 8 , 0x40); /* MSB */
} }
static int timer_resume(struct device *dev, u32 level) static int timer_resume(struct sys_device *dev)
{ {
if (level == RESUME_POWER_ON) setup_timer();
setup_timer();
return 0; return 0;
} }
static struct device_driver timer_driver = { static struct sysdev_class timer_sysclass = {
.name = "timer", set_kset_name("timer"),
.bus = &system_bus_type,
.resume = timer_resume, .resume = timer_resume,
}; };
static struct sys_device device_timer = { static struct sys_device device_timer = {
.name = "timer",
.id = 0, .id = 0,
.dev = { .cls &timer_sysclass,
.name = "timer",
.driver = &timer_driver,
},
}; };
static int __init init_timer_devicefs(void) static int __init init_timer_sysfs(void)
{ {
driver_register(&timer_driver); int error = sysdev_class_register(&timer_sysclass);
return sys_device_register(&device_timer); if (!error)
error = sys_device_register(&device_timer);
return error;
} }
device_initcall(init_timer_devicefs); device_initcall(init_timer_sysfs);
void __init init_IRQ(void) void __init init_IRQ(void)
{ {
......
...@@ -2,23 +2,18 @@ ...@@ -2,23 +2,18 @@
* drivers/base/cpu.c - basic CPU class support * drivers/base/cpu.c - basic CPU class support
*/ */
#include <linux/device.h> #include <linux/sysdev.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/topology.h> #include <linux/topology.h>
struct class cpu_class = { struct sysdev_class cpu_sysdev_class = {
.name = "cpu", set_kset_name("cpu"),
}; };
struct device_driver cpu_driver = {
.name = "cpu",
.bus = &system_bus_type,
};
/* /*
* register_cpu - Setup a driverfs device for a CPU. * register_cpu - Setup a driverfs device for a CPU.
* @num - CPU number to use when creating the device. * @num - CPU number to use when creating the device.
...@@ -27,42 +22,15 @@ struct device_driver cpu_driver = { ...@@ -27,42 +22,15 @@ struct device_driver cpu_driver = {
*/ */
int __init register_cpu(struct cpu *cpu, int num, struct node *root) int __init register_cpu(struct cpu *cpu, int num, struct node *root)
{ {
int retval;
cpu->node_id = cpu_to_node(num); cpu->node_id = cpu_to_node(num);
cpu->sysdev.name = "cpu";
cpu->sysdev.id = num; cpu->sysdev.id = num;
if (root) cpu->sysdev.cls = &cpu_sysdev_class;
cpu->sysdev.root = &root->sysroot; return sys_device_register(&cpu->sysdev);
snprintf(cpu->sysdev.dev.name, DEVICE_NAME_SIZE, "CPU %u", num);
cpu->sysdev.dev.driver = &cpu_driver;
retval = sys_device_register(&cpu->sysdev);
if (retval)
return retval;
memset(&cpu->sysdev.class_dev, 0x00, sizeof(struct class_device));
cpu->sysdev.class_dev.dev = &cpu->sysdev.dev;
cpu->sysdev.class_dev.class = &cpu_class;
snprintf(cpu->sysdev.class_dev.class_id, BUS_ID_SIZE, "cpu%d", num);
retval = class_device_register(&cpu->sysdev.class_dev);
if (retval) {
sys_device_unregister(&cpu->sysdev);
return retval;
}
return 0;
} }
int __init cpu_dev_init(void) int __init cpu_dev_init(void)
{ {
int error; return sysdev_class_register(&cpu_sysdev_class);
error = class_register(&cpu_class);
if (error)
goto out;
error = driver_register(&cpu_driver);
if (error)
class_unregister(&cpu_class);
out:
return error;
} }
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
* drivers/base/memblk.c - basic Memory Block class support * drivers/base/memblk.c - basic Memory Block class support
*/ */
#include <linux/device.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/memblk.h> #include <linux/memblk.h>
...@@ -10,8 +9,8 @@ ...@@ -10,8 +9,8 @@
#include <linux/topology.h> #include <linux/topology.h>
static struct class memblk_class = { static struct sysdev_class memblk_class = {
.name = "memblk", set_kset_name("memblk"),
}; };
...@@ -29,27 +28,23 @@ static struct device_driver memblk_driver = { ...@@ -29,27 +28,23 @@ static struct device_driver memblk_driver = {
*/ */
int __init register_memblk(struct memblk *memblk, int num, struct node *root) int __init register_memblk(struct memblk *memblk, int num, struct node *root)
{ {
int error;
memblk->node_id = memblk_to_node(num); memblk->node_id = memblk_to_node(num);
memblk->sysdev.name = "memblk"; memblk->sysdev.cls = &memblk_class,
memblk->sysdev.id = num; memblk->sysdev.id = num;
if (root)
memblk->sysdev.root = &root->sysroot; error = sys_device_register(&memblk->sysdev);
snprintf(memblk->sysdev.dev.name, DEVICE_NAME_SIZE, "Memory Block %u", num); if (!error)
memblk->sysdev.dev.driver = &memblk_driver; error = sysfs_create_link(&root->sysdev.kobj,
return sys_device_register(&memblk->sysdev); &memblk->sysdev,kobj,
memblk->sysdev.kobj.name);
return error;
} }
int __init register_memblk_type(void) int __init register_memblk_type(void)
{ {
int error; return sysdev_class_register(&memblk_class);
error = class_register(&memblk_class);
if (!error) {
error = driver_register(&memblk_driver);
if (error)
class_unregister(&memblk_class);
}
return error;
} }
postcore_initcall(register_memblk_type); postcore_initcall(register_memblk_type);
...@@ -9,15 +9,8 @@ ...@@ -9,15 +9,8 @@
#include <linux/node.h> #include <linux/node.h>
#include <linux/topology.h> #include <linux/topology.h>
static struct sysdev_class node_class = {
static struct class node_class = { set_kset_name("node"),
.name = "node",
};
static struct device_driver node_driver = {
.name = "node",
.bus = &system_bus_type,
}; };
...@@ -26,7 +19,7 @@ static ssize_t node_read_cpumap(struct device * dev, char * buf) ...@@ -26,7 +19,7 @@ static ssize_t node_read_cpumap(struct device * dev, char * buf)
struct node *node_dev = to_node(to_root(dev)); struct node *node_dev = to_node(to_root(dev));
return sprintf(buf,"%lx\n",node_dev->cpumap); return sprintf(buf,"%lx\n",node_dev->cpumap);
} }
static DEVICE_ATTR(cpumap,S_IRUGO,node_read_cpumap,NULL); static SYSDEV_ATTR(cpumap,S_IRUGO,node_read_cpumap,NULL);
#define K(x) ((x) << (PAGE_SHIFT - 10)) #define K(x) ((x) << (PAGE_SHIFT - 10))
static ssize_t node_read_meminfo(struct device * dev, char * buf) static ssize_t node_read_meminfo(struct device * dev, char * buf)
...@@ -52,7 +45,7 @@ static ssize_t node_read_meminfo(struct device * dev, char * buf) ...@@ -52,7 +45,7 @@ static ssize_t node_read_meminfo(struct device * dev, char * buf)
nid, K(i.freeram-i.freehigh)); nid, K(i.freeram-i.freehigh));
} }
#undef K #undef K
static DEVICE_ATTR(meminfo,S_IRUGO,node_read_meminfo,NULL); static SYSDEV_ATTR(meminfo,S_IRUGO,node_read_meminfo,NULL);
/* /*
...@@ -66,17 +59,13 @@ int __init register_node(struct node *node, int num, struct node *parent) ...@@ -66,17 +59,13 @@ int __init register_node(struct node *node, int num, struct node *parent)
int error; int error;
node->cpumap = node_to_cpumask(num); node->cpumap = node_to_cpumask(num);
node->sysroot.id = num; node->sysdev.id = num;
if (parent) node->sysdev.cls = &node_class;
node->sysroot.dev.parent = &parent->sysroot.sysdev; error = sys_device_register(&node->sysdev);
snprintf(node->sysroot.dev.name, DEVICE_NAME_SIZE, "Node %u", num);
snprintf(node->sysroot.dev.bus_id, BUS_ID_SIZE, "node%u", num);
node->sysroot.dev.driver = &node_driver;
node->sysroot.dev.bus = &system_bus_type;
error = sys_register_root(&node->sysroot);
if (!error){ if (!error){
device_create_file(&node->sysroot.dev, &dev_attr_cpumap); sys_device_create_file(&node->sysroot.dev, &attr_cpumap);
device_create_file(&node->sysroot.dev, &dev_attr_meminfo); sys_device_create_file(&node->sysroot.dev, &attr_meminfo);
} }
return error; return error;
} }
...@@ -84,14 +73,6 @@ int __init register_node(struct node *node, int num, struct node *parent) ...@@ -84,14 +73,6 @@ int __init register_node(struct node *node, int num, struct node *parent)
int __init register_node_type(void) int __init register_node_type(void)
{ {
int error; return sysdev_class_register(&node_class);
error = class_register(&node_class);
if (!error) {
error = driver_register(&node_driver);
if (error)
class_unregister(&node_class);
}
return error;
} }
postcore_initcall(register_node_type); postcore_initcall(register_node_type);
...@@ -21,6 +21,21 @@ ...@@ -21,6 +21,21 @@
extern struct subsystem devices_subsys; extern struct subsystem devices_subsys;
/**
* We handle system devices differently - we suspend and shut them
* down first and resume them first. That way, we do anything stupid like
* shutting down the interrupt controller before any devices..
*
* Note that there are not different stages for power management calls -
* they only get one called once when interrupts are disabled.
*/
extern int sysdev_shutdown(void);
extern int sysdev_save(u32 state);
extern int sysdev_suspend(u32 state);
extern int sysdev_resume(void);
extern int sysdev_restore(void);
/** /**
* device_suspend - suspend/remove all devices on the device ree * device_suspend - suspend/remove all devices on the device ree
* @state: state we're entering * @state: state we're entering
...@@ -50,6 +65,21 @@ int device_suspend(u32 state, u32 level) ...@@ -50,6 +65,21 @@ int device_suspend(u32 state, u32 level)
} }
} }
up_write(&devices_subsys.rwsem); up_write(&devices_subsys.rwsem);
/*
* Make sure system devices are suspended.
*/
switch(level) {
case SUSPEND_SAVE_STATE:
sysdev_save(state);
break;
case SUSPEND_POWER_DOWN:
sysdev_suspend(state);
break;
default:
break;
}
return error; return error;
} }
...@@ -65,6 +95,17 @@ void device_resume(u32 level) ...@@ -65,6 +95,17 @@ void device_resume(u32 level)
{ {
struct list_head * node; struct list_head * node;
switch (level) {
case RESUME_POWER_ON:
sysdev_resume();
break;
case RESUME_RESTORE_STATE:
sysdev_restore();
break;
default:
break;
}
down_write(&devices_subsys.rwsem); down_write(&devices_subsys.rwsem);
list_for_each_prev(node,&devices_subsys.kset.list) { list_for_each_prev(node,&devices_subsys.kset.list) {
struct device * dev = to_dev(node); struct device * dev = to_dev(node);
...@@ -98,6 +139,8 @@ void device_shutdown(void) ...@@ -98,6 +139,8 @@ void device_shutdown(void)
pr_debug("Ignored.\n"); pr_debug("Ignored.\n");
} }
up_write(&devices_subsys.rwsem); up_write(&devices_subsys.rwsem);
sysdev_shutdown();
} }
EXPORT_SYMBOL(device_suspend); EXPORT_SYMBOL(device_suspend);
......
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
* add themselves as children of the system bus. * add themselves as children of the system bus.
*/ */
#undef DEBUG #define DEBUG
#include <linux/device.h> #include <linux/sysdev.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
...@@ -22,130 +22,435 @@ ...@@ -22,130 +22,435 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/string.h> #include <linux/string.h>
/* The default system device parent. */
static struct device system_bus = { extern struct subsystem devices_subsys;
.name = "System Bus",
.bus_id = "sys", #define to_sysdev(k) container_of(k,struct sys_device,kobj)
#define to_sysdev_attr(a) container_of(a,struct sysdev_attribute,attr)
static ssize_t
sysdev_show(struct kobject * kobj, struct attribute * attr, char * buffer)
{
struct sys_device * sysdev = to_sysdev(kobj);
struct sysdev_attribute * sysdev_attr = to_sysdev_attr(attr);
if (sysdev_attr->show)
return sysdev_attr->show(sysdev,buffer);
return 0;
}
static ssize_t
sysdev_store(struct kobject * kobj, struct attribute * attr,
const char * buffer, size_t count)
{
struct sys_device * sysdev = to_sysdev(kobj);
struct sysdev_attribute * sysdev_attr = to_sysdev_attr(attr);
if (sysdev_attr->store)
return sysdev_attr->store(sysdev,buffer,count);
return 0;
}
static struct sysfs_ops sysfs_ops = {
.show = sysdev_show,
.store = sysdev_store,
};
static struct kobj_type ktype_sysdev = {
.sysfs_ops = &sysfs_ops,
}; };
/*
* declare system_subsys
*/
decl_subsys(system,&ktype_sysdev,NULL);
int sysdev_class_register(struct sysdev_class * cls)
{
pr_debug("Registering sysdev class '%s'\n",cls->kset.kobj.name);
INIT_LIST_HEAD(&cls->drivers);
cls->kset.subsys = &system_subsys;
kset_set_kset_s(cls,system_subsys);
return kset_register(&cls->kset);
}
void sysdev_class_unregister(struct sysdev_class * cls)
{
pr_debug("Unregistering sysdev class '%s'\n",cls->kset.kobj.name);
kset_unregister(&cls->kset);
}
EXPORT_SYMBOL(sysdev_class_register);
EXPORT_SYMBOL(sysdev_class_unregister);
static LIST_HEAD(global_drivers);
/** /**
* sys_register_root - add a subordinate system root * sysdev_driver_register - Register auxillary driver
* @root: new root * @cls: Device class driver belongs to.
* * @drv: Driver.
* This is for NUMA-like systems so they can accurately
* represent the topology of the entire system.
* As boards are discovered, a new struct sys_root should
* be allocated and registered.
* The discovery mechanism should initialize the id field
* of the struture, as well as much of the embedded device
* structure as possible, inlcuding the name, the bus_id
* and parent fields.
* *
* This simply calls device_register on the embedded device. * If @cls is valid, then @drv is inserted into @cls->drivers to be
* On success, it will use the struct @root->sysdev * called on each operation on devices of that class. The refcount
* device to create a pseudo-parent for system devices * of @cls is incremented.
* on that board. * Otherwise, @drv is inserted into global_drivers, and called for
* each device.
*/
int sysdev_driver_register(struct sysdev_class * cls,
struct sysdev_driver * drv)
{
down_write(&system_subsys.rwsem);
if (cls && kset_get(&cls->kset))
list_add_tail(&drv->entry,&cls->drivers);
else
list_add_tail(&drv->entry,&global_drivers);
up_write(&system_subsys.rwsem);
return 0;
}
/**
* sysdev_driver_unregister - Remove an auxillary driver.
* @cls: Class driver belongs to.
* @drv: Driver.
*/
void sysdev_driver_unregister(struct sysdev_class * cls,
struct sysdev_driver * drv)
{
down_write(&system_subsys.rwsem);
list_del_init(&drv->entry);
if (cls)
kset_put(&cls->kset);
up_write(&system_subsys.rwsem);
}
/**
* sys_device_register - add a system device to the tree
* @sysdev: device in question
* *
* The platform code can then use @root to specifiy the
* controlling board when discovering and registering
* system devices.
*/ */
int sys_register_root(struct sys_root * root) int sys_device_register(struct sys_device * sysdev)
{ {
int error = 0; int error;
struct sysdev_class * cls = sysdev->cls;
if (!root) if (!cls)
return -EINVAL; return -EINVAL;
if (!root->dev.parent) /* Make sure the kset is set */
root->dev.parent = &system_bus; sysdev->kobj.kset = &cls->kset;
/* set the kobject name */
snprintf(sysdev->kobj.name,KOBJ_NAME_LEN,"%s%d",
cls->kset.kobj.name,sysdev->id);
pr_debug("Registering system board %d\n",root->id); pr_debug("Registering sys device '%s'\n",sysdev->kobj.name);
/* Register the object */
error = kobject_register(&sysdev->kobj);
error = device_register(&root->dev);
if (!error) { if (!error) {
strlcpy(root->sysdev.bus_id,"sys",BUS_ID_SIZE); struct sysdev_driver * drv;
strlcpy(root->sysdev.name,"System Bus",DEVICE_NAME_SIZE);
root->sysdev.parent = &root->dev; down_read(&system_subsys.rwsem);
error = device_register(&root->sysdev); /* Generic notification is implicit, because it's that
}; * code that should have called us.
*/
/* Notify global drivers */
list_for_each_entry(drv,&global_drivers,entry) {
if (drv->add)
drv->add(sysdev);
}
/* Notify class auxillary drivers */
list_for_each_entry(drv,&cls->drivers,entry) {
if (drv->add)
drv->add(sysdev);
}
up_read(&system_subsys.rwsem);
}
return error; return error;
} }
void sys_device_unregister(struct sys_device * sysdev)
{
struct sysdev_driver * drv;
down_read(&system_subsys.rwsem);
list_for_each_entry(drv,&global_drivers,entry) {
if (drv->remove)
drv->remove(sysdev);
}
list_for_each_entry(drv,&sysdev->cls->drivers,entry) {
if (drv->remove)
drv->remove(sysdev);
}
up_read(&system_subsys.rwsem);
kobject_unregister(&sysdev->kobj);
}
/** /**
* sys_unregister_root - remove subordinate root from tree * sysdev_shutdown - Shut down all system devices.
* @root: subordinate root in question. *
* Loop over each class of system devices, and the devices in each
* of those classes. For each device, we call the shutdown method for
* each driver registered for the device - the globals, the auxillaries,
* and the class driver.
* *
* We only decrement the reference count on @root->sysdev * Note: The list is iterated in reverse order, so that we shut down
* and @root->dev. * child devices before we shut down thier parents. The list ordering
* If both are 0, they will be cleaned up by the core. * is guaranteed by virtue of the fact that child devices are registered
* after their parents.
*/ */
void sys_unregister_root(struct sys_root *root)
void sysdev_shutdown(void)
{ {
device_unregister(&root->sysdev); struct sysdev_class * cls;
device_unregister(&root->dev);
pr_debug("Shutting Down System Devices\n");
down_write(&system_subsys.rwsem);
list_for_each_entry_reverse(cls,&system_subsys.kset.list,
kset.kobj.entry) {
struct sys_device * sysdev;
pr_debug("Shutting down type '%s':\n",cls->kset.kobj.name);
list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) {
struct sysdev_driver * drv;
pr_debug(" %s\n",sysdev->kobj.name);
/* Call global drivers first. */
list_for_each_entry(drv,&global_drivers,entry) {
if (drv->shutdown)
drv->shutdown(sysdev);
}
/* Call auxillary drivers next. */
list_for_each_entry(drv,&cls->drivers,entry) {
if (drv->shutdown)
drv->shutdown(sysdev);
}
/* Now call the generic one */
if (cls->shutdown)
cls->shutdown(sysdev);
}
}
up_write(&system_subsys.rwsem);
} }
/** /**
* sys_device_register - add a system device to the tree * sysdev_save - Save system device state
* @sysdev: device in question * @state: Power state we're entering.
* *
* The hardest part about this is getting the ancestry right. * This is called when the system is going to sleep, but before interrupts
* If the device has a parent - super! We do nothing. * have been disabled. This allows system device drivers to allocate and
* If the device doesn't, but @dev->root is set, then we're * save device state, including sleeping during the process..
* dealing with a NUMA like architecture where each root */
* has a system pseudo-bus to foster the device.
* If not, then we fallback to system_bus (at the top of int sysdev_save(u32 state)
* this file). {
struct sysdev_class * cls;
pr_debug("Saving System Device State\n");
down_write(&system_subsys.rwsem);
list_for_each_entry_reverse(cls,&system_subsys.kset.list,
kset.kobj.entry) {
struct sys_device * sysdev;
pr_debug("Saving state for type '%s':\n",cls->kset.kobj.name);
list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) {
struct sysdev_driver * drv;
pr_debug(" %s\n",sysdev->kobj.name);
list_for_each_entry(drv,&global_drivers,entry) {
if (drv->save)
drv->save(sysdev,state);
}
list_for_each_entry(drv,&cls->drivers,entry) {
if (drv->save)
drv->save(sysdev,state);
}
if (cls->save)
cls->save(sysdev,state);
}
}
up_write(&system_subsys.rwsem);
return 0;
}
/**
* sysdev_suspend - Suspend all system devices.
* @state: Power state to enter.
* *
* One way or another, we call device_register() on it and * We perform an almost identical operation as sys_device_shutdown()
* are done. * above, though calling ->suspend() instead.
* *
* The caller is also responsible for initializing the bus_id * Note: Interrupts are disabled when called, so we can't sleep when
* and name fields of @sysdev->dev. * trying to get the subsystem's rwsem. If that happens, print a nasty
* warning and return an error.
*/ */
int sys_device_register(struct sys_device * sysdev)
int sysdev_suspend(u32 state)
{ {
if (!sysdev) struct sysdev_class * cls;
return -EINVAL;
pr_debug("Suspending System Devices\n");
if (!sysdev->dev.parent) { if (!down_write_trylock(&system_subsys.rwsem)) {
if (sysdev->root) printk("%s: Cannot acquire semaphore; Failing\n",__FUNCTION__);
sysdev->dev.parent = &sysdev->root->sysdev; return -EFAULT;
else
sysdev->dev.parent = &system_bus;
} }
/* make sure bus type is set */ list_for_each_entry_reverse(cls,&system_subsys.kset.list,
if (!sysdev->dev.bus) kset.kobj.entry) {
sysdev->dev.bus = &system_bus_type; struct sys_device * sysdev;
pr_debug("Suspending type '%s':\n",cls->kset.kobj.name);
list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) {
struct sysdev_driver * drv;
pr_debug(" %s\n",sysdev->kobj.name);
/* construct bus_id */ /* Call global drivers first. */
snprintf(sysdev->dev.bus_id,BUS_ID_SIZE,"%s%u",sysdev->name,sysdev->id); list_for_each_entry(drv,&global_drivers,entry) {
if (drv->suspend)
drv->suspend(sysdev,state);
}
pr_debug("Registering system device %s\n", sysdev->dev.bus_id); /* Call auxillary drivers next. */
list_for_each_entry(drv,&cls->drivers,entry) {
if (drv->suspend)
drv->suspend(sysdev,state);
}
return device_register(&sysdev->dev); /* Now call the generic one */
if (cls->suspend)
cls->suspend(sysdev,state);
}
}
up_write(&system_subsys.rwsem);
return 0;
} }
void sys_device_unregister(struct sys_device * sysdev)
/**
* sysdev_resume - Bring system devices back to life.
*
* Similar to sys_device_suspend(), but we iterate the list forwards
* to guarantee that parent devices are resumed before their children.
*
* Note: Interrupts are disabled when called.
*/
int sysdev_resume(void)
{ {
if (sysdev) struct sysdev_class * cls;
device_unregister(&sysdev->dev);
pr_debug("Resuming System Devices\n");
if(!down_write_trylock(&system_subsys.rwsem))
return -EFAULT;
list_for_each_entry(cls,&system_subsys.kset.list,kset.kobj.entry) {
struct sys_device * sysdev;
pr_debug("Resuming type '%s':\n",cls->kset.kobj.name);
list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) {
struct sysdev_driver * drv;
pr_debug(" %s\n",sysdev->kobj.name);
/* First, call the class-specific one */
if (cls->resume)
cls->resume(sysdev);
/* Call auxillary drivers next. */
list_for_each_entry(drv,&cls->drivers,entry) {
if (drv->resume)
drv->resume(sysdev);
}
/* Call global drivers. */
list_for_each_entry(drv,&global_drivers,entry) {
if (drv->resume)
drv->resume(sysdev);
}
}
}
up_write(&system_subsys.rwsem);
return 0;
}
/**
* sysdev_restore - Restore system device state
*
* This is called during a suspend/resume cycle last, after interrupts
* have been re-enabled. This is intended for auxillary drivers, etc,
* that may sleep when restoring state.
*/
int sysdev_restore(void)
{
struct sysdev_class * cls;
down_write(&system_subsys.rwsem);
pr_debug("Restoring System Device State\n");
list_for_each_entry(cls,&system_subsys.kset.list,kset.kobj.entry) {
struct sys_device * sysdev;
pr_debug("Restoring state for type '%s':\n",cls->kset.kobj.name);
list_for_each_entry(sysdev,&cls->kset.list,kobj.entry) {
struct sysdev_driver * drv;
pr_debug(" %s\n",sysdev->kobj.name);
if (cls->restore)
cls->restore(sysdev);
list_for_each_entry(drv,&cls->drivers,entry) {
if (drv->restore)
drv->restore(sysdev);
}
list_for_each_entry(drv,&global_drivers,entry) {
if (drv->restore)
drv->restore(sysdev);
}
}
}
up_write(&system_subsys.rwsem);
return 0;
} }
struct bus_type system_bus_type = {
.name = "system",
};
int __init sys_bus_init(void) int __init sys_bus_init(void)
{ {
bus_register(&system_bus_type); system_subsys.kset.kobj.parent = &devices_subsys.kset.kobj;
return device_register(&system_bus); return subsystem_register(&system_subsys);
} }
EXPORT_SYMBOL(system_bus_type);
EXPORT_SYMBOL(sys_device_register); EXPORT_SYMBOL(sys_device_register);
EXPORT_SYMBOL(sys_device_unregister); EXPORT_SYMBOL(sys_device_unregister);
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
#include <linux/blk.h> #include <linux/blk.h>
#include <linux/blkpg.h> #include <linux/blkpg.h>
#include <linux/hdreg.h> /* HDIO_GETGEO */ #include <linux/hdreg.h> /* HDIO_GETGEO */
#include <linux/device.h> #include <linux/sysdev.h>
#include <linux/bio.h> #include <linux/bio.h>
#include <linux/devfs_fs_kernel.h> #include <linux/devfs_fs_kernel.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -48,12 +48,14 @@ ...@@ -48,12 +48,14 @@
#define PRINT_WARN(x...) printk(KERN_WARNING XPRAM_NAME " warning:" x) #define PRINT_WARN(x...) printk(KERN_WARNING XPRAM_NAME " warning:" x)
#define PRINT_ERR(x...) printk(KERN_ERR XPRAM_NAME " error:" x) #define PRINT_ERR(x...) printk(KERN_ERR XPRAM_NAME " error:" x)
static struct sysdev_class xpram_sysclass = {
set_kset_name("xpram"),
};
static struct sys_device xpram_sys_device = { static struct sys_device xpram_sys_device = {
.name = "S/390 expanded memory RAM disk", .id = 0,
.dev = { .cls = &xpram_sysclass,
.name = "S/390 expanded memory RAM disk",
.bus_id = "xpram",
},
}; };
typedef struct { typedef struct {
...@@ -485,6 +487,7 @@ static void __exit xpram_exit(void) ...@@ -485,6 +487,7 @@ static void __exit xpram_exit(void)
unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME);
devfs_remove("slram"); devfs_remove("slram");
sys_device_unregister(&xpram_sys_device); sys_device_unregister(&xpram_sys_device);
sysdev_class_unregister(&xpram_sys_class);
} }
static int __init xpram_init(void) static int __init xpram_init(void)
...@@ -502,9 +505,15 @@ static int __init xpram_init(void) ...@@ -502,9 +505,15 @@ static int __init xpram_init(void)
rc = xpram_setup_sizes(xpram_pages); rc = xpram_setup_sizes(xpram_pages);
if (rc) if (rc)
return rc; return rc;
rc = sys_device_register(&xpram_sys_device); rc = sysdev_class_register(&xpram_sysclass);
if (rc) if (rc)
return rc; return rc;
rc = sys_device_register(&xpram_sys_device);
if (rc) {
sysdev_class_unregister(&xpram_syclass);
return rc;
}
rc = xpram_setup_blkdev(); rc = xpram_setup_blkdev();
if (rc) if (rc)
sys_device_unregister(&xpram_sys_device); sys_device_unregister(&xpram_sys_device);
......
...@@ -444,7 +444,7 @@ static char *usb_dump_string(char *start, char *end, const struct usb_device *de ...@@ -444,7 +444,7 @@ static char *usb_dump_string(char *start, char *end, const struct usb_device *de
* skip_bytes - the number of bytes to skip before writing anything * skip_bytes - the number of bytes to skip before writing anything
* file_offset - the offset into the devices file on completion * file_offset - the offset into the devices file on completion
*/ */
static ssize_t usb_device_dump(char **buffer, size_t *nbytes, loff_t *skip_bytes, loff_t *file_offset, static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *skip_bytes, loff_t *file_offset,
struct usb_device *usbdev, struct usb_bus *bus, int level, int index, int count) struct usb_device *usbdev, struct usb_bus *bus, int level, int index, int count)
{ {
int chix; int chix;
...@@ -554,7 +554,7 @@ static ssize_t usb_device_dump(char **buffer, size_t *nbytes, loff_t *skip_bytes ...@@ -554,7 +554,7 @@ static ssize_t usb_device_dump(char **buffer, size_t *nbytes, loff_t *skip_bytes
return total_written; return total_written;
} }
static ssize_t usb_device_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos) static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{ {
struct list_head *buslist; struct list_head *buslist;
struct usb_bus *bus; struct usb_bus *bus;
......
...@@ -49,14 +49,14 @@ ...@@ -49,14 +49,14 @@
#include "hcd.h" /* for usbcore internals */ #include "hcd.h" /* for usbcore internals */
struct async { struct async {
struct list_head asynclist; struct list_head asynclist;
struct dev_state *ps; struct dev_state *ps;
struct task_struct *task; struct task_struct *task;
unsigned int signr; unsigned int signr;
unsigned int intf; unsigned int intf;
void *userbuffer; void __user *userbuffer;
void *userurb; void __user *userurb;
struct urb *urb; struct urb *urb;
}; };
static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig) static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
...@@ -83,7 +83,7 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig) ...@@ -83,7 +83,7 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
return ret; return ret;
} }
static ssize_t usbdev_read(struct file *file, char * buf, size_t nbytes, loff_t *ppos) static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{ {
struct dev_state *ps = (struct dev_state *)file->private_data; struct dev_state *ps = (struct dev_state *)file->private_data;
ssize_t ret = 0; ssize_t ret = 0;
...@@ -235,7 +235,7 @@ extern __inline__ struct async *async_getcompleted(struct dev_state *ps) ...@@ -235,7 +235,7 @@ extern __inline__ struct async *async_getcompleted(struct dev_state *ps)
return as; return as;
} }
extern __inline__ struct async *async_getpending(struct dev_state *ps, void *userurb) extern __inline__ struct async *async_getpending(struct dev_state *ps, void __user *userurb)
{ {
unsigned long flags; unsigned long flags;
struct async *as; struct async *as;
...@@ -265,7 +265,7 @@ static void async_completed(struct urb *urb, struct pt_regs *regs) ...@@ -265,7 +265,7 @@ static void async_completed(struct urb *urb, struct pt_regs *regs)
sinfo.si_signo = as->signr; sinfo.si_signo = as->signr;
sinfo.si_errno = as->urb->status; sinfo.si_errno = as->urb->status;
sinfo.si_code = SI_ASYNCIO; sinfo.si_code = SI_ASYNCIO;
sinfo.si_addr = as->userurb; sinfo.si_addr = (void *)as->userurb;
send_sig_info(as->signr, &sinfo, as->task); send_sig_info(as->signr, &sinfo, as->task);
} }
} }
...@@ -536,7 +536,7 @@ static int usbdev_release(struct inode *inode, struct file *file) ...@@ -536,7 +536,7 @@ static int usbdev_release(struct inode *inode, struct file *file)
return 0; return 0;
} }
static int proc_control(struct dev_state *ps, void *arg) static int proc_control(struct dev_state *ps, void __user *arg)
{ {
struct usb_device *dev = ps->dev; struct usb_device *dev = ps->dev;
struct usbdevfs_ctrltransfer ctrl; struct usbdevfs_ctrltransfer ctrl;
...@@ -544,7 +544,7 @@ static int proc_control(struct dev_state *ps, void *arg) ...@@ -544,7 +544,7 @@ static int proc_control(struct dev_state *ps, void *arg)
unsigned char *tbuf; unsigned char *tbuf;
int i, ret; int i, ret;
if (copy_from_user(&ctrl, (void *)arg, sizeof(ctrl))) if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
return -EFAULT; return -EFAULT;
if ((ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex))) if ((ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex)))
return ret; return ret;
...@@ -578,13 +578,15 @@ static int proc_control(struct dev_state *ps, void *arg) ...@@ -578,13 +578,15 @@ static int proc_control(struct dev_state *ps, void *arg)
} }
free_page((unsigned long)tbuf); free_page((unsigned long)tbuf);
if (i<0) { if (i<0) {
printk(KERN_DEBUG "usbfs: USBDEVFS_CONTROL failed dev %d rqt %u rq %u len %u ret %d\n", printk(KERN_DEBUG "usbfs: USBDEVFS_CONTROL failed "
"cmd %s dev %d rqt %u rq %u len %u ret %d\n",
current->comm,
dev->devnum, ctrl.bRequestType, ctrl.bRequest, ctrl.wLength, i); dev->devnum, ctrl.bRequestType, ctrl.bRequest, ctrl.wLength, i);
} }
return i; return i;
} }
static int proc_bulk(struct dev_state *ps, void *arg) static int proc_bulk(struct dev_state *ps, void __user *arg)
{ {
struct usb_device *dev = ps->dev; struct usb_device *dev = ps->dev;
struct usbdevfs_bulktransfer bulk; struct usbdevfs_bulktransfer bulk;
...@@ -593,7 +595,7 @@ static int proc_bulk(struct dev_state *ps, void *arg) ...@@ -593,7 +595,7 @@ static int proc_bulk(struct dev_state *ps, void *arg)
unsigned char *tbuf; unsigned char *tbuf;
int i, ret; int i, ret;
if (copy_from_user(&bulk, (void *)arg, sizeof(bulk))) if (copy_from_user(&bulk, arg, sizeof(bulk)))
return -EFAULT; return -EFAULT;
if ((ret = findintfep(ps->dev, bulk.ep)) < 0) if ((ret = findintfep(ps->dev, bulk.ep)) < 0)
return ret; return ret;
...@@ -639,12 +641,12 @@ static int proc_bulk(struct dev_state *ps, void *arg) ...@@ -639,12 +641,12 @@ static int proc_bulk(struct dev_state *ps, void *arg)
return len2; return len2;
} }
static int proc_resetep(struct dev_state *ps, void *arg) static int proc_resetep(struct dev_state *ps, void __user *arg)
{ {
unsigned int ep; unsigned int ep;
int ret; int ret;
if (get_user(ep, (unsigned int *)arg)) if (get_user(ep, (unsigned int __user *)arg))
return -EFAULT; return -EFAULT;
if ((ret = findintfep(ps->dev, ep)) < 0) if ((ret = findintfep(ps->dev, ep)) < 0)
return ret; return ret;
...@@ -654,13 +656,13 @@ static int proc_resetep(struct dev_state *ps, void *arg) ...@@ -654,13 +656,13 @@ static int proc_resetep(struct dev_state *ps, void *arg)
return 0; return 0;
} }
static int proc_clearhalt(struct dev_state *ps, void *arg) static int proc_clearhalt(struct dev_state *ps, void __user *arg)
{ {
unsigned int ep; unsigned int ep;
int pipe; int pipe;
int ret; int ret;
if (get_user(ep, (unsigned int *)arg)) if (get_user(ep, (unsigned int __user *)arg))
return -EFAULT; return -EFAULT;
if ((ret = findintfep(ps->dev, ep)) < 0) if ((ret = findintfep(ps->dev, ep)) < 0)
return ret; return ret;
...@@ -675,7 +677,7 @@ static int proc_clearhalt(struct dev_state *ps, void *arg) ...@@ -675,7 +677,7 @@ static int proc_clearhalt(struct dev_state *ps, void *arg)
} }
static int proc_getdriver(struct dev_state *ps, void *arg) static int proc_getdriver(struct dev_state *ps, void __user *arg)
{ {
struct usbdevfs_getdriver gd; struct usbdevfs_getdriver gd;
struct usb_interface *interface; struct usb_interface *interface;
...@@ -696,7 +698,7 @@ static int proc_getdriver(struct dev_state *ps, void *arg) ...@@ -696,7 +698,7 @@ static int proc_getdriver(struct dev_state *ps, void *arg)
return 0; return 0;
} }
static int proc_connectinfo(struct dev_state *ps, void *arg) static int proc_connectinfo(struct dev_state *ps, void __user *arg)
{ {
struct usbdevfs_connectinfo ci; struct usbdevfs_connectinfo ci;
...@@ -731,7 +733,7 @@ static int proc_resetdevice(struct dev_state *ps) ...@@ -731,7 +733,7 @@ static int proc_resetdevice(struct dev_state *ps)
return 0; return 0;
} }
static int proc_setintf(struct dev_state *ps, void *arg) static int proc_setintf(struct dev_state *ps, void __user *arg)
{ {
struct usbdevfs_setinterface setintf; struct usbdevfs_setinterface setintf;
struct usb_interface *interface; struct usb_interface *interface;
...@@ -753,18 +755,18 @@ static int proc_setintf(struct dev_state *ps, void *arg) ...@@ -753,18 +755,18 @@ static int proc_setintf(struct dev_state *ps, void *arg)
return 0; return 0;
} }
static int proc_setconfig(struct dev_state *ps, void *arg) static int proc_setconfig(struct dev_state *ps, void __user *arg)
{ {
unsigned int u; unsigned int u;
if (get_user(u, (unsigned int *)arg)) if (get_user(u, (unsigned int __user *)arg))
return -EFAULT; return -EFAULT;
if (usb_set_configuration(ps->dev, u) < 0) if (usb_set_configuration(ps->dev, u) < 0)
return -EINVAL; return -EINVAL;
return 0; return 0;
} }
static int proc_submiturb(struct dev_state *ps, void *arg) static int proc_submiturb(struct dev_state *ps, void __user *arg)
{ {
struct usbdevfs_urb uurb; struct usbdevfs_urb uurb;
struct usbdevfs_iso_packet_desc *isopkt = NULL; struct usbdevfs_iso_packet_desc *isopkt = NULL;
...@@ -802,7 +804,7 @@ static int proc_submiturb(struct dev_state *ps, void *arg) ...@@ -802,7 +804,7 @@ static int proc_submiturb(struct dev_state *ps, void *arg)
return -EINVAL; return -EINVAL;
if (!(dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL))) if (!(dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL)))
return -ENOMEM; return -ENOMEM;
if (copy_from_user(dr, (unsigned char*)uurb.buffer, 8)) { if (copy_from_user(dr, uurb.buffer, 8)) {
kfree(dr); kfree(dr);
return -EFAULT; return -EFAULT;
} }
...@@ -928,7 +930,7 @@ static int proc_submiturb(struct dev_state *ps, void *arg) ...@@ -928,7 +930,7 @@ static int proc_submiturb(struct dev_state *ps, void *arg)
return 0; return 0;
} }
static int proc_unlinkurb(struct dev_state *ps, void *arg) static int proc_unlinkurb(struct dev_state *ps, void __user *arg)
{ {
struct async *as; struct async *as;
...@@ -970,11 +972,11 @@ static int processcompl(struct async *as) ...@@ -970,11 +972,11 @@ static int processcompl(struct async *as)
return 0; return 0;
} }
static int proc_reapurb(struct dev_state *ps, void *arg) static int proc_reapurb(struct dev_state *ps, void __user *arg)
{ {
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
struct async *as = NULL; struct async *as = NULL;
void *addr; void __user *addr;
int ret; int ret;
add_wait_queue(&ps->wait, &wait); add_wait_queue(&ps->wait, &wait);
...@@ -1005,10 +1007,10 @@ static int proc_reapurb(struct dev_state *ps, void *arg) ...@@ -1005,10 +1007,10 @@ static int proc_reapurb(struct dev_state *ps, void *arg)
return -EIO; return -EIO;
} }
static int proc_reapurbnonblock(struct dev_state *ps, void *arg) static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg)
{ {
struct async *as; struct async *as;
void *addr; void __user *addr;
int ret; int ret;
if (!(as = async_getcompleted(ps))) if (!(as = async_getcompleted(ps)))
...@@ -1023,7 +1025,7 @@ static int proc_reapurbnonblock(struct dev_state *ps, void *arg) ...@@ -1023,7 +1025,7 @@ static int proc_reapurbnonblock(struct dev_state *ps, void *arg)
return 0; return 0;
} }
static int proc_disconnectsignal(struct dev_state *ps, void *arg) static int proc_disconnectsignal(struct dev_state *ps, void __user *arg)
{ {
struct usbdevfs_disconnectsignal ds; struct usbdevfs_disconnectsignal ds;
...@@ -1036,24 +1038,24 @@ static int proc_disconnectsignal(struct dev_state *ps, void *arg) ...@@ -1036,24 +1038,24 @@ static int proc_disconnectsignal(struct dev_state *ps, void *arg)
return 0; return 0;
} }
static int proc_claiminterface(struct dev_state *ps, void *arg) static int proc_claiminterface(struct dev_state *ps, void __user *arg)
{ {
unsigned int intf; unsigned int intf;
int ret; int ret;
if (get_user(intf, (unsigned int *)arg)) if (get_user(intf, (unsigned int __user *)arg))
return -EFAULT; return -EFAULT;
if ((ret = findintfif(ps->dev, intf)) < 0) if ((ret = findintfif(ps->dev, intf)) < 0)
return ret; return ret;
return claimintf(ps, ret); return claimintf(ps, ret);
} }
static int proc_releaseinterface(struct dev_state *ps, void *arg) static int proc_releaseinterface(struct dev_state *ps, void __user *arg)
{ {
unsigned int intf; unsigned int intf;
int ret; int ret;
if (get_user(intf, (unsigned int *)arg)) if (get_user(intf, (unsigned int __user *)arg))
return -EFAULT; return -EFAULT;
if ((ret = findintfif(ps->dev, intf)) < 0) if ((ret = findintfif(ps->dev, intf)) < 0)
return ret; return ret;
...@@ -1063,7 +1065,7 @@ static int proc_releaseinterface(struct dev_state *ps, void *arg) ...@@ -1063,7 +1065,7 @@ static int proc_releaseinterface(struct dev_state *ps, void *arg)
return 0; return 0;
} }
static int proc_ioctl (struct dev_state *ps, void *arg) static int proc_ioctl (struct dev_state *ps, void __user *arg)
{ {
struct usbdevfs_ioctl ctrl; struct usbdevfs_ioctl ctrl;
int size; int size;
...@@ -1073,7 +1075,7 @@ static int proc_ioctl (struct dev_state *ps, void *arg) ...@@ -1073,7 +1075,7 @@ static int proc_ioctl (struct dev_state *ps, void *arg)
struct usb_driver *driver = 0; struct usb_driver *driver = 0;
/* get input parameters and alloc buffer */ /* get input parameters and alloc buffer */
if (copy_from_user(&ctrl, (void *) arg, sizeof (ctrl))) if (copy_from_user(&ctrl, arg, sizeof (ctrl)))
return -EFAULT; return -EFAULT;
if ((size = _IOC_SIZE (ctrl.ioctl_code)) > 0) { if ((size = _IOC_SIZE (ctrl.ioctl_code)) > 0) {
if ((buf = kmalloc (size, GFP_KERNEL)) == 0) if ((buf = kmalloc (size, GFP_KERNEL)) == 0)
...@@ -1171,19 +1173,19 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd ...@@ -1171,19 +1173,19 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
} }
switch (cmd) { switch (cmd) {
case USBDEVFS_CONTROL: case USBDEVFS_CONTROL:
ret = proc_control(ps, (void *)arg); ret = proc_control(ps, (void __user *)arg);
if (ret >= 0) if (ret >= 0)
inode->i_mtime = CURRENT_TIME; inode->i_mtime = CURRENT_TIME;
break; break;
case USBDEVFS_BULK: case USBDEVFS_BULK:
ret = proc_bulk(ps, (void *)arg); ret = proc_bulk(ps, (void __user *)arg);
if (ret >= 0) if (ret >= 0)
inode->i_mtime = CURRENT_TIME; inode->i_mtime = CURRENT_TIME;
break; break;
case USBDEVFS_RESETEP: case USBDEVFS_RESETEP:
ret = proc_resetep(ps, (void *)arg); ret = proc_resetep(ps, (void __user *)arg);
if (ret >= 0) if (ret >= 0)
inode->i_mtime = CURRENT_TIME; inode->i_mtime = CURRENT_TIME;
break; break;
...@@ -1193,59 +1195,59 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd ...@@ -1193,59 +1195,59 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
break; break;
case USBDEVFS_CLEAR_HALT: case USBDEVFS_CLEAR_HALT:
ret = proc_clearhalt(ps, (void *)arg); ret = proc_clearhalt(ps, (void __user *)arg);
if (ret >= 0) if (ret >= 0)
inode->i_mtime = CURRENT_TIME; inode->i_mtime = CURRENT_TIME;
break; break;
case USBDEVFS_GETDRIVER: case USBDEVFS_GETDRIVER:
ret = proc_getdriver(ps, (void *)arg); ret = proc_getdriver(ps, (void __user *)arg);
break; break;
case USBDEVFS_CONNECTINFO: case USBDEVFS_CONNECTINFO:
ret = proc_connectinfo(ps, (void *)arg); ret = proc_connectinfo(ps, (void __user *)arg);
break; break;
case USBDEVFS_SETINTERFACE: case USBDEVFS_SETINTERFACE:
ret = proc_setintf(ps, (void *)arg); ret = proc_setintf(ps, (void __user *)arg);
break; break;
case USBDEVFS_SETCONFIGURATION: case USBDEVFS_SETCONFIGURATION:
ret = proc_setconfig(ps, (void *)arg); ret = proc_setconfig(ps, (void __user *)arg);
break; break;
case USBDEVFS_SUBMITURB: case USBDEVFS_SUBMITURB:
ret = proc_submiturb(ps, (void *)arg); ret = proc_submiturb(ps, (void __user *)arg);
if (ret >= 0) if (ret >= 0)
inode->i_mtime = CURRENT_TIME; inode->i_mtime = CURRENT_TIME;
break; break;
case USBDEVFS_DISCARDURB: case USBDEVFS_DISCARDURB:
ret = proc_unlinkurb(ps, (void *)arg); ret = proc_unlinkurb(ps, (void __user *)arg);
break; break;
case USBDEVFS_REAPURB: case USBDEVFS_REAPURB:
ret = proc_reapurb(ps, (void *)arg); ret = proc_reapurb(ps, (void __user *)arg);
break; break;
case USBDEVFS_REAPURBNDELAY: case USBDEVFS_REAPURBNDELAY:
ret = proc_reapurbnonblock(ps, (void *)arg); ret = proc_reapurbnonblock(ps, (void __user *)arg);
break; break;
case USBDEVFS_DISCSIGNAL: case USBDEVFS_DISCSIGNAL:
ret = proc_disconnectsignal(ps, (void *)arg); ret = proc_disconnectsignal(ps, (void __user *)arg);
break; break;
case USBDEVFS_CLAIMINTERFACE: case USBDEVFS_CLAIMINTERFACE:
ret = proc_claiminterface(ps, (void *)arg); ret = proc_claiminterface(ps, (void __user *)arg);
break; break;
case USBDEVFS_RELEASEINTERFACE: case USBDEVFS_RELEASEINTERFACE:
ret = proc_releaseinterface(ps, (void *)arg); ret = proc_releaseinterface(ps, (void __user *)arg);
break; break;
case USBDEVFS_IOCTL: case USBDEVFS_IOCTL:
ret = proc_ioctl(ps, (void *) arg); ret = proc_ioctl(ps, (void __user *) arg);
break; break;
} }
up_read(&ps->devsem); up_read(&ps->devsem);
......
...@@ -64,17 +64,17 @@ static inline struct device *hubdev (struct usb_device *dev) ...@@ -64,17 +64,17 @@ static inline struct device *hubdev (struct usb_device *dev)
} }
/* USB 2.0 spec Section 11.24.4.5 */ /* USB 2.0 spec Section 11.24.4.5 */
static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size) static int get_hub_descriptor(struct usb_device *dev, void *data, int size)
{ {
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB, USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
USB_DT_HUB << 8, 0, data, size, HZ); USB_DT_HUB << 8, 0, data, size, HZ * USB_CTRL_GET_TIMEOUT);
} }
/* /*
* USB 2.0 spec Section 11.24.2.1 * USB 2.0 spec Section 11.24.2.1
*/ */
static int usb_clear_hub_feature(struct usb_device *dev, int feature) static int clear_hub_feature(struct usb_device *dev, int feature)
{ {
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0, NULL, 0, HZ); USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0, NULL, 0, HZ);
...@@ -84,7 +84,7 @@ static int usb_clear_hub_feature(struct usb_device *dev, int feature) ...@@ -84,7 +84,7 @@ static int usb_clear_hub_feature(struct usb_device *dev, int feature)
* USB 2.0 spec Section 11.24.2.2 * USB 2.0 spec Section 11.24.2.2
* BUG: doesn't handle port indicator selector in high byte of wIndex * BUG: doesn't handle port indicator selector in high byte of wIndex
*/ */
static int usb_clear_port_feature(struct usb_device *dev, int port, int feature) static int clear_port_feature(struct usb_device *dev, int port, int feature)
{ {
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ); USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ);
...@@ -94,7 +94,7 @@ static int usb_clear_port_feature(struct usb_device *dev, int port, int feature) ...@@ -94,7 +94,7 @@ static int usb_clear_port_feature(struct usb_device *dev, int port, int feature)
* USB 2.0 spec Section 11.24.2.13 * USB 2.0 spec Section 11.24.2.13
* BUG: doesn't handle port indicator selector in high byte of wIndex * BUG: doesn't handle port indicator selector in high byte of wIndex
*/ */
static int usb_set_port_feature(struct usb_device *dev, int port, int feature) static int set_port_feature(struct usb_device *dev, int port, int feature)
{ {
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ); USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ);
...@@ -103,21 +103,23 @@ static int usb_set_port_feature(struct usb_device *dev, int port, int feature) ...@@ -103,21 +103,23 @@ static int usb_set_port_feature(struct usb_device *dev, int port, int feature)
/* /*
* USB 2.0 spec Section 11.24.2.6 * USB 2.0 spec Section 11.24.2.6
*/ */
static int usb_get_hub_status(struct usb_device *dev, void *data) static int get_hub_status(struct usb_device *dev,
struct usb_hub_status *data)
{ {
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0, USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0,
data, sizeof(struct usb_hub_status), HZ); data, sizeof(*data), HZ * USB_CTRL_GET_TIMEOUT);
} }
/* /*
* USB 2.0 spec Section 11.24.2.7 * USB 2.0 spec Section 11.24.2.7
*/ */
static int usb_get_port_status(struct usb_device *dev, int port, void *data) static int get_port_status(struct usb_device *dev, int port,
struct usb_port_status *data)
{ {
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port, USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port,
data, sizeof(struct usb_hub_status), HZ); data, sizeof(*data), HZ * USB_CTRL_GET_TIMEOUT);
} }
/* completion function, fires on port status changes and various faults */ /* completion function, fires on port status changes and various faults */
...@@ -256,7 +258,7 @@ void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe) ...@@ -256,7 +258,7 @@ void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe)
spin_unlock_irqrestore (&tt->lock, flags); spin_unlock_irqrestore (&tt->lock, flags);
} }
static void usb_hub_power_on(struct usb_hub *hub) static void hub_power_on(struct usb_hub *hub)
{ {
struct usb_device *dev; struct usb_device *dev;
int i; int i;
...@@ -266,22 +268,55 @@ static void usb_hub_power_on(struct usb_hub *hub) ...@@ -266,22 +268,55 @@ static void usb_hub_power_on(struct usb_hub *hub)
"enabling power on all ports\n"); "enabling power on all ports\n");
dev = interface_to_usbdev(hub->intf); dev = interface_to_usbdev(hub->intf);
for (i = 0; i < hub->descriptor->bNbrPorts; i++) for (i = 0; i < hub->descriptor->bNbrPorts; i++)
usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER); set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
/* Wait for power to be enabled */ /* Wait for power to be enabled */
wait_ms(hub->descriptor->bPwrOn2PwrGood * 2); wait_ms(hub->descriptor->bPwrOn2PwrGood * 2);
} }
static int usb_hub_configure(struct usb_hub *hub, static int hub_hub_status(struct usb_hub *hub,
u16 *status, u16 *change)
{
struct usb_device *dev = interface_to_usbdev (hub->intf);
int ret;
ret = get_hub_status(dev, &hub->status->hub);
if (ret < 0)
dev_err (hubdev (dev),
"%s failed (err = %d)\n", __FUNCTION__, ret);
else {
*status = le16_to_cpu(hub->status->hub.wHubStatus);
*change = le16_to_cpu(hub->status->hub.wHubChange);
ret = 0;
}
return ret;
}
static int hub_configure(struct usb_hub *hub,
struct usb_endpoint_descriptor *endpoint) struct usb_endpoint_descriptor *endpoint)
{ {
struct usb_device *dev = interface_to_usbdev (hub->intf); struct usb_device *dev = interface_to_usbdev (hub->intf);
struct device *hub_dev; struct device *hub_dev;
struct usb_hub_status hubstatus; u16 hubstatus, hubchange;
unsigned int pipe; unsigned int pipe;
int maxp, ret; int maxp, ret;
char *message; char *message;
hub->buffer = usb_buffer_alloc(dev, sizeof(*hub->buffer), GFP_KERNEL,
&hub->buffer_dma);
if (!hub->buffer) {
message = "can't allocate hub irq buffer";
ret = -ENOMEM;
goto fail;
}
hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL);
if (!hub->status) {
message = "can't kmalloc hub status buffer";
ret = -ENOMEM;
goto fail;
}
hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL); hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
if (!hub->descriptor) { if (!hub->descriptor) {
message = "can't kmalloc hub descriptor"; message = "can't kmalloc hub descriptor";
...@@ -293,7 +328,7 @@ static int usb_hub_configure(struct usb_hub *hub, ...@@ -293,7 +328,7 @@ static int usb_hub_configure(struct usb_hub *hub,
* hub->descriptor can handle USB_MAXCHILDREN ports, * hub->descriptor can handle USB_MAXCHILDREN ports,
* but the hub can/will return fewer bytes here. * but the hub can/will return fewer bytes here.
*/ */
ret = usb_get_hub_descriptor(dev, hub->descriptor, ret = get_hub_descriptor(dev, hub->descriptor,
sizeof(*hub->descriptor)); sizeof(*hub->descriptor));
if (ret < 0) { if (ret < 0) {
message = "can't read hub descriptor"; message = "can't read hub descriptor";
...@@ -396,27 +431,25 @@ static int usb_hub_configure(struct usb_hub *hub, ...@@ -396,27 +431,25 @@ static int usb_hub_configure(struct usb_hub *hub,
dev_dbg(hub_dev, "hub controller current requirement: %dmA\n", dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",
hub->descriptor->bHubContrCurrent); hub->descriptor->bHubContrCurrent);
ret = usb_get_hub_status(dev, &hubstatus); ret = hub_hub_status(hub, &hubstatus, &hubchange);
if (ret < 0) { if (ret < 0) {
message = "can't get hub status"; message = "can't get hub status";
goto fail; goto fail;
} }
le16_to_cpus(&hubstatus.wHubStatus);
dev_dbg(hub_dev, "local power source is %s\n", dev_dbg(hub_dev, "local power source is %s\n",
(hubstatus.wHubStatus & HUB_STATUS_LOCAL_POWER) (hubstatus & HUB_STATUS_LOCAL_POWER)
? "lost (inactive)" : "good"); ? "lost (inactive)" : "good");
dev_dbg(hub_dev, "%sover-current condition exists\n", dev_dbg(hub_dev, "%sover-current condition exists\n",
(hubstatus.wHubStatus & HUB_STATUS_OVERCURRENT) ? "" : "no "); (hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
/* Start the interrupt endpoint */ /* Start the interrupt endpoint */
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
if (maxp > sizeof(hub->buffer)) if (maxp > sizeof(*hub->buffer))
maxp = sizeof(hub->buffer); maxp = sizeof(*hub->buffer);
hub->urb = usb_alloc_urb(0, GFP_KERNEL); hub->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!hub->urb) { if (!hub->urb) {
...@@ -425,8 +458,10 @@ static int usb_hub_configure(struct usb_hub *hub, ...@@ -425,8 +458,10 @@ static int usb_hub_configure(struct usb_hub *hub,
goto fail; goto fail;
} }
usb_fill_int_urb(hub->urb, dev, pipe, hub->buffer, maxp, hub_irq, usb_fill_int_urb(hub->urb, dev, pipe, *hub->buffer, maxp, hub_irq,
hub, endpoint->bInterval); hub, endpoint->bInterval);
hub->urb->transfer_dma = hub->buffer_dma;
hub->urb->transfer_flags |= URB_NO_DMA_MAP;
ret = usb_submit_urb(hub->urb, GFP_KERNEL); ret = usb_submit_urb(hub->urb, GFP_KERNEL);
if (ret) { if (ret) {
message = "couldn't submit status urb"; message = "couldn't submit status urb";
...@@ -436,7 +471,7 @@ static int usb_hub_configure(struct usb_hub *hub, ...@@ -436,7 +471,7 @@ static int usb_hub_configure(struct usb_hub *hub,
/* Wake up khubd */ /* Wake up khubd */
wake_up(&khubd_wait); wake_up(&khubd_wait);
usb_hub_power_on(hub); hub_power_on(hub);
return 0; return 0;
...@@ -484,6 +519,18 @@ static void hub_disconnect(struct usb_interface *intf) ...@@ -484,6 +519,18 @@ static void hub_disconnect(struct usb_interface *intf)
hub->descriptor = NULL; hub->descriptor = NULL;
} }
if (hub->status) {
kfree(hub->status);
hub->status = NULL;
}
if (hub->buffer) {
usb_buffer_free(interface_to_usbdev(intf),
sizeof(*hub->buffer), hub->buffer,
hub->buffer_dma);
hub->buffer = NULL;
}
/* Free the memory */ /* Free the memory */
kfree(hub); kfree(hub);
} }
...@@ -550,7 +597,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) ...@@ -550,7 +597,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
usb_set_intfdata (intf, hub); usb_set_intfdata (intf, hub);
if (usb_hub_configure(hub, endpoint) >= 0) { if (hub_configure(hub, endpoint) >= 0) {
strcpy (intf->dev.name, "Hub"); strcpy (intf->dev.name, "Hub");
return 0; return 0;
} }
...@@ -594,7 +641,7 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data) ...@@ -594,7 +641,7 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
} }
} }
static int usb_hub_reset(struct usb_hub *hub) static int hub_reset(struct usb_hub *hub)
{ {
struct usb_device *dev = interface_to_usbdev(hub->intf); struct usb_device *dev = interface_to_usbdev(hub->intf);
int i; int i;
...@@ -618,12 +665,12 @@ static int usb_hub_reset(struct usb_hub *hub) ...@@ -618,12 +665,12 @@ static int usb_hub_reset(struct usb_hub *hub)
if (usb_submit_urb(hub->urb, GFP_KERNEL)) if (usb_submit_urb(hub->urb, GFP_KERNEL))
return -1; return -1;
usb_hub_power_on(hub); hub_power_on(hub);
return 0; return 0;
} }
static void usb_hub_disconnect(struct usb_device *dev) static void hub_start_disconnect(struct usb_device *dev)
{ {
struct usb_device *parent = dev->parent; struct usb_device *parent = dev->parent;
int i; int i;
...@@ -641,25 +688,20 @@ static void usb_hub_disconnect(struct usb_device *dev) ...@@ -641,25 +688,20 @@ static void usb_hub_disconnect(struct usb_device *dev)
err("cannot disconnect hub %s", dev->devpath); err("cannot disconnect hub %s", dev->devpath);
} }
static int usb_hub_port_status(struct usb_device *hub, int port, static int hub_port_status(struct usb_device *dev, int port,
u16 *status, u16 *change) u16 *status, u16 *change)
{ {
struct usb_port_status *portsts; struct usb_hub *hub = usb_get_intfdata (dev->actconfig->interface);
int ret = -ENOMEM; int ret;
portsts = kmalloc(sizeof(*portsts), GFP_NOIO); ret = get_port_status(dev, port + 1, &hub->status->port);
if (portsts) { if (ret < 0)
ret = usb_get_port_status(hub, port + 1, portsts); dev_err (hubdev (dev),
if (ret < 0) "%s failed (err = %d)\n", __FUNCTION__, ret);
dev_err (hubdev (hub), else {
"%s failed (err = %d)\n", __FUNCTION__, *status = le16_to_cpu(hub->status->port.wPortStatus);
ret); *change = le16_to_cpu(hub->status->port.wPortChange);
else { ret = 0;
*status = le16_to_cpu(portsts->wPortStatus);
*change = le16_to_cpu(portsts->wPortChange);
ret = 0;
}
kfree(portsts);
} }
return ret; return ret;
} }
...@@ -671,7 +713,7 @@ static int usb_hub_port_status(struct usb_device *hub, int port, ...@@ -671,7 +713,7 @@ static int usb_hub_port_status(struct usb_device *hub, int port,
#define HUB_RESET_TIMEOUT 500 #define HUB_RESET_TIMEOUT 500
/* return: -1 on error, 0 on success, 1 on disconnect. */ /* return: -1 on error, 0 on success, 1 on disconnect. */
static int usb_hub_port_wait_reset(struct usb_device *hub, int port, static int hub_port_wait_reset(struct usb_device *hub, int port,
struct usb_device *dev, unsigned int delay) struct usb_device *dev, unsigned int delay)
{ {
int delay_time, ret; int delay_time, ret;
...@@ -685,7 +727,7 @@ static int usb_hub_port_wait_reset(struct usb_device *hub, int port, ...@@ -685,7 +727,7 @@ static int usb_hub_port_wait_reset(struct usb_device *hub, int port,
wait_ms(delay); wait_ms(delay);
/* read and decode port status */ /* read and decode port status */
ret = usb_hub_port_status(hub, port, &portstatus, &portchange); ret = hub_port_status(hub, port, &portstatus, &portchange);
if (ret < 0) { if (ret < 0) {
return -1; return -1;
} }
...@@ -723,19 +765,19 @@ static int usb_hub_port_wait_reset(struct usb_device *hub, int port, ...@@ -723,19 +765,19 @@ static int usb_hub_port_wait_reset(struct usb_device *hub, int port,
} }
/* return: -1 on error, 0 on success, 1 on disconnect. */ /* return: -1 on error, 0 on success, 1 on disconnect. */
static int usb_hub_port_reset(struct usb_device *hub, int port, static int hub_port_reset(struct usb_device *hub, int port,
struct usb_device *dev, unsigned int delay) struct usb_device *dev, unsigned int delay)
{ {
int i, status; int i, status;
/* Reset the port */ /* Reset the port */
for (i = 0; i < HUB_RESET_TRIES; i++) { for (i = 0; i < HUB_RESET_TRIES; i++) {
usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET); set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);
/* return on disconnect or reset */ /* return on disconnect or reset */
status = usb_hub_port_wait_reset(hub, port, dev, delay); status = hub_port_wait_reset(hub, port, dev, delay);
if (status != -1) { if (status != -1) {
usb_clear_port_feature(hub, clear_port_feature(hub,
port + 1, USB_PORT_FEAT_C_RESET); port + 1, USB_PORT_FEAT_C_RESET);
dev->state = status dev->state = status
? USB_STATE_NOTATTACHED ? USB_STATE_NOTATTACHED
...@@ -756,11 +798,11 @@ static int usb_hub_port_reset(struct usb_device *hub, int port, ...@@ -756,11 +798,11 @@ static int usb_hub_port_reset(struct usb_device *hub, int port,
return -1; return -1;
} }
int usb_hub_port_disable(struct usb_device *hub, int port) int hub_port_disable(struct usb_device *hub, int port)
{ {
int ret; int ret;
ret = usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE); ret = clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE);
if (ret) if (ret)
dev_err(hubdev(hub), "cannot disable port %d (err = %d)\n", dev_err(hubdev(hub), "cannot disable port %d (err = %d)\n",
port + 1, ret); port + 1, ret);
...@@ -787,7 +829,7 @@ int usb_hub_port_disable(struct usb_device *hub, int port) ...@@ -787,7 +829,7 @@ int usb_hub_port_disable(struct usb_device *hub, int port)
#define HUB_DEBOUNCE_STABLE 4 #define HUB_DEBOUNCE_STABLE 4
/* return: -1 on error, 0 on success, 1 on disconnect. */ /* return: -1 on error, 0 on success, 1 on disconnect. */
static int usb_hub_port_debounce(struct usb_device *hub, int port) static int hub_port_debounce(struct usb_device *hub, int port)
{ {
int ret; int ret;
int delay_time, stable_count; int delay_time, stable_count;
...@@ -799,7 +841,7 @@ static int usb_hub_port_debounce(struct usb_device *hub, int port) ...@@ -799,7 +841,7 @@ static int usb_hub_port_debounce(struct usb_device *hub, int port)
for (delay_time = 0; delay_time < HUB_DEBOUNCE_TIMEOUT; delay_time += HUB_DEBOUNCE_STEP) { for (delay_time = 0; delay_time < HUB_DEBOUNCE_TIMEOUT; delay_time += HUB_DEBOUNCE_STEP) {
wait_ms(HUB_DEBOUNCE_STEP); wait_ms(HUB_DEBOUNCE_STEP);
ret = usb_hub_port_status(hub, port, &portstatus, &portchange); ret = hub_port_status(hub, port, &portstatus, &portchange);
if (ret < 0) if (ret < 0)
return -1; return -1;
...@@ -814,7 +856,7 @@ static int usb_hub_port_debounce(struct usb_device *hub, int port) ...@@ -814,7 +856,7 @@ static int usb_hub_port_debounce(struct usb_device *hub, int port)
connection = portstatus & USB_PORT_STAT_CONNECTION; connection = portstatus & USB_PORT_STAT_CONNECTION;
if ((portchange & USB_PORT_STAT_C_CONNECTION)) { if ((portchange & USB_PORT_STAT_C_CONNECTION)) {
usb_clear_port_feature(hub, port+1, USB_PORT_FEAT_C_CONNECTION); clear_port_feature(hub, port+1, USB_PORT_FEAT_C_CONNECTION);
} }
} }
...@@ -826,7 +868,7 @@ static int usb_hub_port_debounce(struct usb_device *hub, int port) ...@@ -826,7 +868,7 @@ static int usb_hub_port_debounce(struct usb_device *hub, int port)
return ((portstatus&USB_PORT_STAT_CONNECTION)) ? 0 : 1; return ((portstatus&USB_PORT_STAT_CONNECTION)) ? 0 : 1;
} }
static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port, static void hub_port_connect_change(struct usb_hub *hubstate, int port,
u16 portstatus, u16 portchange) u16 portstatus, u16 portchange)
{ {
struct usb_device *hub = interface_to_usbdev(hubstate->intf); struct usb_device *hub = interface_to_usbdev(hubstate->intf);
...@@ -839,7 +881,7 @@ static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port, ...@@ -839,7 +881,7 @@ static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port,
port + 1, portstatus, portchange, portspeed (portstatus)); port + 1, portstatus, portchange, portspeed (portstatus));
/* Clear the connection change status */ /* Clear the connection change status */
usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION); clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION);
/* Disconnect any existing devices under this port */ /* Disconnect any existing devices under this port */
if (hub->children[port]) if (hub->children[port])
...@@ -848,16 +890,16 @@ static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port, ...@@ -848,16 +890,16 @@ static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port,
/* Return now if nothing is connected */ /* Return now if nothing is connected */
if (!(portstatus & USB_PORT_STAT_CONNECTION)) { if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
if (portstatus & USB_PORT_STAT_ENABLE) if (portstatus & USB_PORT_STAT_ENABLE)
usb_hub_port_disable(hub, port); hub_port_disable(hub, port);
return; return;
} }
if (usb_hub_port_debounce(hub, port)) { if (hub_port_debounce(hub, port)) {
dev_err (&hubstate->intf->dev, dev_err (&hubstate->intf->dev,
"connect-debounce failed, port %d disabled\n", "connect-debounce failed, port %d disabled\n",
port+1); port+1);
usb_hub_port_disable(hub, port); hub_port_disable(hub, port);
return; return;
} }
...@@ -884,7 +926,7 @@ static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port, ...@@ -884,7 +926,7 @@ static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port,
dev->state = USB_STATE_POWERED; dev->state = USB_STATE_POWERED;
/* Reset the device, and detect its speed */ /* Reset the device, and detect its speed */
if (usb_hub_port_reset(hub, port, dev, delay)) { if (hub_port_reset(hub, port, dev, delay)) {
usb_put_dev(dev); usb_put_dev(dev);
break; break;
} }
...@@ -944,18 +986,17 @@ static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port, ...@@ -944,18 +986,17 @@ static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port,
} }
hub->children[port] = NULL; hub->children[port] = NULL;
usb_hub_port_disable(hub, port); hub_port_disable(hub, port);
done: done:
up(&usb_address0_sem); up(&usb_address0_sem);
} }
static void usb_hub_events(void) static void hub_events(void)
{ {
unsigned long flags; unsigned long flags;
struct list_head *tmp; struct list_head *tmp;
struct usb_device *dev; struct usb_device *dev;
struct usb_hub *hub; struct usb_hub *hub;
struct usb_hub_status hubsts;
u16 hubstatus; u16 hubstatus;
u16 hubchange; u16 hubchange;
u16 portstatus; u16 portstatus;
...@@ -991,11 +1032,11 @@ static void usb_hub_events(void) ...@@ -991,11 +1032,11 @@ static void usb_hub_events(void)
dev_dbg (&hub->intf->dev, "resetting for error %d\n", dev_dbg (&hub->intf->dev, "resetting for error %d\n",
hub->error); hub->error);
if (usb_hub_reset(hub)) { if (hub_reset(hub)) {
dev_dbg (&hub->intf->dev, dev_dbg (&hub->intf->dev,
"can't reset; disconnecting\n"); "can't reset; disconnecting\n");
up(&hub->khubd_sem); up(&hub->khubd_sem);
usb_hub_disconnect(dev); hub_start_disconnect(dev);
continue; continue;
} }
...@@ -1004,18 +1045,18 @@ static void usb_hub_events(void) ...@@ -1004,18 +1045,18 @@ static void usb_hub_events(void)
} }
for (i = 0; i < hub->descriptor->bNbrPorts; i++) { for (i = 0; i < hub->descriptor->bNbrPorts; i++) {
ret = usb_hub_port_status(dev, i, &portstatus, &portchange); ret = hub_port_status(dev, i, &portstatus, &portchange);
if (ret < 0) { if (ret < 0) {
continue; continue;
} }
if (portchange & USB_PORT_STAT_C_CONNECTION) { if (portchange & USB_PORT_STAT_C_CONNECTION) {
usb_hub_port_connect_change(hub, i, portstatus, portchange); hub_port_connect_change(hub, i, portstatus, portchange);
} else if (portchange & USB_PORT_STAT_C_ENABLE) { } else if (portchange & USB_PORT_STAT_C_ENABLE) {
dev_dbg (hubdev (dev), dev_dbg (hubdev (dev),
"port %d enable change, status %x\n", "port %d enable change, status %x\n",
i + 1, portstatus); i + 1, portstatus);
usb_clear_port_feature(dev, clear_port_feature(dev,
i + 1, USB_PORT_FEAT_C_ENABLE); i + 1, USB_PORT_FEAT_C_ENABLE);
/* /*
...@@ -1032,7 +1073,7 @@ static void usb_hub_events(void) ...@@ -1032,7 +1073,7 @@ static void usb_hub_events(void)
"disabled by hub (EMI?), " "disabled by hub (EMI?), "
"re-enabling...", "re-enabling...",
i + 1); i + 1);
usb_hub_port_connect_change(hub, hub_port_connect_change(hub,
i, portstatus, portchange); i, portstatus, portchange);
} }
} }
...@@ -1041,7 +1082,7 @@ static void usb_hub_events(void) ...@@ -1041,7 +1082,7 @@ static void usb_hub_events(void)
dev_dbg (&hub->intf->dev, dev_dbg (&hub->intf->dev,
"suspend change on port %d\n", "suspend change on port %d\n",
i + 1); i + 1);
usb_clear_port_feature(dev, clear_port_feature(dev,
i + 1, USB_PORT_FEAT_C_SUSPEND); i + 1, USB_PORT_FEAT_C_SUSPEND);
} }
...@@ -1049,35 +1090,33 @@ static void usb_hub_events(void) ...@@ -1049,35 +1090,33 @@ static void usb_hub_events(void)
dev_err (&hub->intf->dev, dev_err (&hub->intf->dev,
"over-current change on port %d\n", "over-current change on port %d\n",
i + 1); i + 1);
usb_clear_port_feature(dev, clear_port_feature(dev,
i + 1, USB_PORT_FEAT_C_OVER_CURRENT); i + 1, USB_PORT_FEAT_C_OVER_CURRENT);
usb_hub_power_on(hub); hub_power_on(hub);
} }
if (portchange & USB_PORT_STAT_C_RESET) { if (portchange & USB_PORT_STAT_C_RESET) {
dev_dbg (&hub->intf->dev, dev_dbg (&hub->intf->dev,
"reset change on port %d\n", "reset change on port %d\n",
i + 1); i + 1);
usb_clear_port_feature(dev, clear_port_feature(dev,
i + 1, USB_PORT_FEAT_C_RESET); i + 1, USB_PORT_FEAT_C_RESET);
} }
} /* end for i */ } /* end for i */
/* deal with hub status changes */ /* deal with hub status changes */
if (usb_get_hub_status(dev, &hubsts) < 0) if (hub_hub_status(hub, &hubstatus, &hubchange) < 0)
dev_err (&hub->intf->dev, "get_hub_status failed\n"); dev_err (&hub->intf->dev, "get_hub_status failed\n");
else { else {
hubstatus = le16_to_cpup(&hubsts.wHubStatus);
hubchange = le16_to_cpup(&hubsts.wHubChange);
if (hubchange & HUB_CHANGE_LOCAL_POWER) { if (hubchange & HUB_CHANGE_LOCAL_POWER) {
dev_dbg (&hub->intf->dev, "power change\n"); dev_dbg (&hub->intf->dev, "power change\n");
usb_clear_hub_feature(dev, C_HUB_LOCAL_POWER); clear_hub_feature(dev, C_HUB_LOCAL_POWER);
} }
if (hubchange & HUB_CHANGE_OVERCURRENT) { if (hubchange & HUB_CHANGE_OVERCURRENT) {
dev_dbg (&hub->intf->dev, "overcurrent change\n"); dev_dbg (&hub->intf->dev, "overcurrent change\n");
wait_ms(500); /* Cool down */ wait_ms(500); /* Cool down */
usb_clear_hub_feature(dev, C_HUB_OVER_CURRENT); clear_hub_feature(dev, C_HUB_OVER_CURRENT);
usb_hub_power_on(hub); hub_power_on(hub);
} }
} }
up(&hub->khubd_sem); up(&hub->khubd_sem);
...@@ -1086,7 +1125,7 @@ static void usb_hub_events(void) ...@@ -1086,7 +1125,7 @@ static void usb_hub_events(void)
spin_unlock_irqrestore(&hub_event_lock, flags); spin_unlock_irqrestore(&hub_event_lock, flags);
} }
static int usb_hub_thread(void *__hub) static int hub_thread(void *__hub)
{ {
/* /*
* This thread doesn't need any user-level access, * This thread doesn't need any user-level access,
...@@ -1098,13 +1137,13 @@ static int usb_hub_thread(void *__hub) ...@@ -1098,13 +1137,13 @@ static int usb_hub_thread(void *__hub)
/* Send me a signal to get me die (for debugging) */ /* Send me a signal to get me die (for debugging) */
do { do {
usb_hub_events(); hub_events();
wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list)); wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list));
if (current->flags & PF_FREEZE) if (current->flags & PF_FREEZE)
refrigerator(PF_IOTHREAD); refrigerator(PF_IOTHREAD);
} while (!signal_pending(current)); } while (!signal_pending(current));
dbg("usb_hub_thread exiting"); dbg("hub_thread exiting");
complete_and_exit(&khubd_exited, 0); complete_and_exit(&khubd_exited, 0);
} }
...@@ -1139,7 +1178,7 @@ int usb_hub_init(void) ...@@ -1139,7 +1178,7 @@ int usb_hub_init(void)
return -1; return -1;
} }
pid = kernel_thread(usb_hub_thread, NULL, pid = kernel_thread(hub_thread, NULL,
CLONE_FS | CLONE_FILES | CLONE_SIGHAND); CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
if (pid >= 0) { if (pid >= 0) {
khubd_pid = pid; khubd_pid = pid;
...@@ -1149,7 +1188,7 @@ int usb_hub_init(void) ...@@ -1149,7 +1188,7 @@ int usb_hub_init(void)
/* Fall through if kernel_thread failed */ /* Fall through if kernel_thread failed */
usb_deregister(&hub_driver); usb_deregister(&hub_driver);
err("failed to start usb_hub_thread"); err("failed to start hub_thread");
return -1; return -1;
} }
...@@ -1212,8 +1251,8 @@ int usb_physical_reset_device(struct usb_device *dev) ...@@ -1212,8 +1251,8 @@ int usb_physical_reset_device(struct usb_device *dev)
down(&usb_address0_sem); down(&usb_address0_sem);
/* Send a reset to the device */ /* Send a reset to the device */
if (usb_hub_port_reset(parent, port, dev, HUB_SHORT_RESET_TIME)) { if (hub_port_reset(parent, port, dev, HUB_SHORT_RESET_TIME)) {
usb_hub_port_disable(parent, port); hub_port_disable(parent, port);
up(&usb_address0_sem); up(&usb_address0_sem);
kfree(descriptor); kfree(descriptor);
return(-ENODEV); return(-ENODEV);
...@@ -1223,7 +1262,7 @@ int usb_physical_reset_device(struct usb_device *dev) ...@@ -1223,7 +1262,7 @@ int usb_physical_reset_device(struct usb_device *dev)
ret = usb_set_address(dev); ret = usb_set_address(dev);
if (ret < 0) { if (ret < 0) {
err("USB device not accepting new address (error=%d)", ret); err("USB device not accepting new address (error=%d)", ret);
usb_hub_port_disable(parent, port); hub_port_disable(parent, port);
up(&usb_address0_sem); up(&usb_address0_sem);
kfree(descriptor); kfree(descriptor);
return ret; return ret;
......
...@@ -174,7 +174,12 @@ struct usb_hub { ...@@ -174,7 +174,12 @@ struct usb_hub {
struct urb *urb; /* for interrupt polling pipe */ struct urb *urb; /* for interrupt polling pipe */
/* buffer for urb ... 1 bit each for hub and children, rounded up */ /* buffer for urb ... 1 bit each for hub and children, rounded up */
char buffer[(USB_MAXCHILDREN + 1 + 7) / 8]; char (*buffer)[(USB_MAXCHILDREN + 1 + 7) / 8];
dma_addr_t buffer_dma; /* DMA address for buffer */
union {
struct usb_hub_status hub;
struct usb_port_status port;
} *status; /* buffer for status reports */
int error; /* last reported error */ int error; /* last reported error */
int nerrors; /* track consecutive errors */ int nerrors; /* track consecutive errors */
......
...@@ -282,13 +282,13 @@ static int usbfs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -282,13 +282,13 @@ static int usbfs_rmdir(struct inode *dir, struct dentry *dentry)
/* default file operations */ /* default file operations */
static ssize_t default_read_file (struct file *file, char *buf, static ssize_t default_read_file (struct file *file, char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
return 0; return 0;
} }
static ssize_t default_write_file (struct file *file, const char *buf, static ssize_t default_write_file (struct file *file, const char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
return count; return count;
......
...@@ -20,10 +20,12 @@ ...@@ -20,10 +20,12 @@
* short OUT transfers happen.) Drivers can use the req->no_interrupt * short OUT transfers happen.) Drivers can use the req->no_interrupt
* hint to completely eliminate some IRQs, if a later IRQ is guaranteed * hint to completely eliminate some IRQs, if a later IRQ is guaranteed
* and DMA chaining is enabled. * and DMA chaining is enabled.
*
* Note that almost all the errata workarounds here are only needed for
* rev1 chips. Rev1a silicon (0110) fixes almost all of them.
*/ */
// #define NET2280_DMA_OUT_WORKAROUND #define USE_DMA_CHAINING
// #define USE_DMA_CHAINING
/* /*
...@@ -180,6 +182,13 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) ...@@ -180,6 +182,13 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
* kicking in the "toggle-irrelevant" mode. * kicking in the "toggle-irrelevant" mode.
*/ */
tmp = USB_ENDPOINT_XFER_BULK; tmp = USB_ENDPOINT_XFER_BULK;
} else if (tmp == USB_ENDPOINT_XFER_BULK) {
/* catch some particularly blatant driver bugs */
if ((dev->gadget.speed == USB_SPEED_HIGH
&& max != 512)
|| (dev->gadget.speed == USB_SPEED_FULL
&& max > 64))
return -ERANGE;
} }
ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC) ? 1 : 0; ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC) ? 1 : 0;
tmp <<= ENDPOINT_TYPE; tmp <<= ENDPOINT_TYPE;
...@@ -252,9 +261,6 @@ static int handshake (u32 *ptr, u32 mask, u32 done, int usec) ...@@ -252,9 +261,6 @@ static int handshake (u32 *ptr, u32 mask, u32 done, int usec)
udelay (1); udelay (1);
usec--; usec--;
} while (usec > 0); } while (usec > 0);
#ifdef DEBUG
if (done == 0) dump_stack (); /* ignore out_flush timeout */
#endif
return -ETIMEDOUT; return -ETIMEDOUT;
} }
...@@ -917,6 +923,8 @@ net2280_queue (struct usb_ep *_ep, struct usb_request *_req, int gfp_flags) ...@@ -917,6 +923,8 @@ net2280_queue (struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
*/ */
if (read_fifo (ep, req)) { if (read_fifo (ep, req)) {
done (ep, req, 0); done (ep, req, 0);
if (ep->num == 0)
allow_status (ep);
/* don't queue it */ /* don't queue it */
req = 0; req = 0;
} else } else
...@@ -1194,9 +1202,12 @@ net2280_set_halt (struct usb_ep *_ep, int value) ...@@ -1194,9 +1202,12 @@ net2280_set_halt (struct usb_ep *_ep, int value)
VDEBUG (ep->dev, "%s %s halt\n", _ep->name, value ? "set" : "clear"); VDEBUG (ep->dev, "%s %s halt\n", _ep->name, value ? "set" : "clear");
/* set/clear, then synch memory views with the device */ /* set/clear, then synch memory views with the device */
if (value) if (value) {
set_halt (ep); if (ep->num == 0)
else ep->dev->protocol_stall = 1;
else
set_halt (ep);
} else
clear_halt (ep); clear_halt (ep);
(void) readl (&ep->regs->ep_rsp); (void) readl (&ep->regs->ep_rsp);
...@@ -2042,7 +2053,8 @@ static void handle_ep_small (struct net2280_ep *ep) ...@@ -2042,7 +2053,8 @@ static void handle_ep_small (struct net2280_ep *ep)
* can decide to stall ep0 after that done() returns, * can decide to stall ep0 after that done() returns,
* from non-irq context * from non-irq context
*/ */
allow_status (ep); if (!ep->stopped)
allow_status (ep);
req = 0; req = 0;
} else { } else {
if (!list_empty (&ep->queue) && !ep->stopped) if (!list_empty (&ep->queue) && !ep->stopped)
......
...@@ -377,12 +377,8 @@ static struct ed *ed_get ( ...@@ -377,12 +377,8 @@ static struct ed *ed_get (
ed->type = type; ed->type = type;
} }
/* FIXME: Don't do this without knowing it's safe to clobber this /* NOTE: only ep0 currently needs this "re"init logic, during
* state/mode info. Currently the upper layers don't support such * enumeration (after set_address, or if ep0 maxpacket >8).
* guarantees; we're lucky changing config/altsetting is rare.
* The state/mode info also changes during enumeration: set_address
* uses the 'wrong' device address, and ep0 maxpacketsize will often
* improve on the initial value.
*/ */
if (ed->state == ED_IDLE) { if (ed->state == ED_IDLE) {
u32 info; u32 info;
......
...@@ -45,7 +45,7 @@ hpusbscsi_usb_probe(struct usb_interface *intf, ...@@ -45,7 +45,7 @@ hpusbscsi_usb_probe(struct usb_interface *intf,
struct usb_host_interface *altsetting = intf->altsetting; struct usb_host_interface *altsetting = intf->altsetting;
struct hpusbscsi *new; struct hpusbscsi *new;
int error = -ENOMEM; int error = -ENOMEM;
int i, result; int i;
if (altsetting->desc.bNumEndpoints != 3) { if (altsetting->desc.bNumEndpoints != 3) {
printk (KERN_ERR "Wrong number of endpoints\n"); printk (KERN_ERR "Wrong number of endpoints\n");
......
...@@ -1101,6 +1101,52 @@ static int vicam_read_proc_gain(char *page, char **start, off_t off, ...@@ -1101,6 +1101,52 @@ static int vicam_read_proc_gain(char *page, char **start, off_t off,
((struct vicam_camera *)data)->gain); ((struct vicam_camera *)data)->gain);
} }
static int
vicam_write_proc_shutter(struct file *file, const char *buffer,
unsigned long count, void *data)
{
u16 stmp;
char kbuf[8];
struct vicam_camera *cam = (struct vicam_camera *) data;
if (count > 6)
return -EINVAL;
if (copy_from_user(kbuf, buffer, count))
return -EFAULT;
stmp = (u16) simple_strtoul(kbuf, NULL, 10);
if (stmp < 4 || stmp > 32000)
return -EINVAL;
cam->shutter_speed = stmp;
return count;
}
static int
vicam_write_proc_gain(struct file *file, const char *buffer,
unsigned long count, void *data)
{
u16 gtmp;
char kbuf[8];
struct vicam_camera *cam = (struct vicam_camera *) data;
if (count > 4)
return -EINVAL;
if (copy_from_user(kbuf, buffer, count))
return -EFAULT;
gtmp = (u16) simple_strtoul(kbuf, NULL, 10);
if (gtmp > 255)
return -EINVAL;
cam->gain = gtmp;
return count;
}
static void static void
vicam_create_proc_root(void) vicam_create_proc_root(void)
{ {
...@@ -1142,18 +1188,21 @@ vicam_create_proc_entry(struct vicam_camera *cam) ...@@ -1142,18 +1188,21 @@ vicam_create_proc_entry(struct vicam_camera *cam)
if ( !cam->proc_dir ) if ( !cam->proc_dir )
return; // FIXME: We should probably return an error here return; // FIXME: We should probably return an error here
ent = ent = create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR,
create_proc_entry("shutter", S_IFREG | S_IRUGO, cam->proc_dir); cam->proc_dir);
if (ent) { if (ent) {
ent->data = cam; ent->data = cam;
ent->read_proc = vicam_read_proc_shutter; ent->read_proc = vicam_read_proc_shutter;
ent->write_proc = vicam_write_proc_shutter;
ent->size = 64; ent->size = 64;
} }
ent = create_proc_entry("gain", S_IFREG | S_IRUGO , cam->proc_dir); ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR,
if ( ent ) { cam->proc_dir);
if (ent) {
ent->data = cam; ent->data = cam;
ent->read_proc = vicam_read_proc_gain; ent->read_proc = vicam_read_proc_gain;
ent->write_proc = vicam_write_proc_gain;
ent->size = 64; ent->size = 64;
} }
} }
......
...@@ -63,6 +63,8 @@ MODULE_AUTHOR(DRIVER_AUTHOR); ...@@ -63,6 +63,8 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static const char driver_name[] = "catc";
/* /*
* Some defines. * Some defines.
*/ */
...@@ -677,7 +679,7 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) ...@@ -677,7 +679,7 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
/* get driver info */ /* get driver info */
case ETHTOOL_GDRVINFO: { case ETHTOOL_GDRVINFO: {
struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
strncpy(info.driver, SHORT_DRIVER_DESC, ETHTOOL_BUSINFO_LEN); strncpy(info.driver, driver_name, ETHTOOL_BUSINFO_LEN);
strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN); strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
usb_make_path (catc->usbdev, info.bus_info, sizeof info.bus_info); usb_make_path (catc->usbdev, info.bus_info, sizeof info.bus_info);
if (copy_to_user(useraddr, &info, sizeof(info))) if (copy_to_user(useraddr, &info, sizeof(info)))
...@@ -978,7 +980,7 @@ MODULE_DEVICE_TABLE(usb, catc_id_table); ...@@ -978,7 +980,7 @@ MODULE_DEVICE_TABLE(usb, catc_id_table);
static struct usb_driver catc_driver = { static struct usb_driver catc_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "catc", .name = driver_name,
.probe = catc_probe, .probe = catc_probe,
.disconnect = catc_disconnect, .disconnect = catc_disconnect,
.id_table = catc_id_table, .id_table = catc_id_table,
......
...@@ -114,6 +114,8 @@ MODULE_AUTHOR("Michael Zappe <zapman@interlan.net>, Stephane Alnet <stephane@u-p ...@@ -114,6 +114,8 @@ MODULE_AUTHOR("Michael Zappe <zapman@interlan.net>, Stephane Alnet <stephane@u-p
MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver"); MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static const char driver_name[] = "kaweth";
static int kaweth_probe( static int kaweth_probe(
struct usb_interface *intf, struct usb_interface *intf,
const struct usb_device_id *id /* from id_table */ const struct usb_device_id *id /* from id_table */
...@@ -169,7 +171,7 @@ MODULE_DEVICE_TABLE (usb, usb_klsi_table); ...@@ -169,7 +171,7 @@ MODULE_DEVICE_TABLE (usb, usb_klsi_table);
****************************************************************/ ****************************************************************/
static struct usb_driver kaweth_driver = { static struct usb_driver kaweth_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "kaweth", .name = driver_name,
.probe = kaweth_probe, .probe = kaweth_probe,
.disconnect = kaweth_disconnect, .disconnect = kaweth_disconnect,
.id_table = usb_klsi_table, .id_table = usb_klsi_table,
...@@ -670,7 +672,7 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) ...@@ -670,7 +672,7 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
switch (ethcmd) { switch (ethcmd) {
case ETHTOOL_GDRVINFO: { case ETHTOOL_GDRVINFO: {
struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO}; struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
strlcpy(info.driver, "kaweth", sizeof(info.driver)); strlcpy(info.driver, driver_name, sizeof(info.driver));
if (copy_to_user(useraddr, &info, sizeof(info))) if (copy_to_user(useraddr, &info, sizeof(info)))
return -EFAULT; return -EFAULT;
return 0; return 0;
......
/* /*
* Copyright (c) 1999-2002 Petko Manolov (petkan@users.sourceforge.net) * Copyright (c) 1999-2003 Petko Manolov (petkan@users.sourceforge.net)
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
/* /*
* Version Information * Version Information
*/ */
#define DRIVER_VERSION "v0.5.10 (2003/04/01)" #define DRIVER_VERSION "v0.5.12 (2003/06/06)"
#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>" #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
#define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver" #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
...@@ -564,7 +564,14 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs) ...@@ -564,7 +564,14 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs)
dbg("%s: reset MAC", net->name); dbg("%s: reset MAC", net->name);
pegasus->flags &= ~PEGASUS_RX_BUSY; pegasus->flags &= ~PEGASUS_RX_BUSY;
break; break;
case -EPIPE: /* stall, or disconnect from TT */
/* FIXME schedule work to clear the halt */
warn("%s: no rx stall recovery", net->name);
return;
case -ENOENT: case -ENOENT:
case -ECONNRESET:
case -ESHUTDOWN:
dbg("%s: rx unlink, %d", net->name, urb->status);
return; return;
default: default:
dbg("%s: RX status %d", net->name, urb->status); dbg("%s: RX status %d", net->name, urb->status);
...@@ -604,6 +611,9 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs) ...@@ -604,6 +611,9 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs)
pegasus->stats.rx_packets++; pegasus->stats.rx_packets++;
pegasus->stats.rx_bytes += pkt_len; pegasus->stats.rx_bytes += pkt_len;
if (pegasus->flags & PEGASUS_UNPLUG)
return;
spin_lock(&pegasus->rx_pool_lock); spin_lock(&pegasus->rx_pool_lock);
pegasus->rx_skb = pull_skb(pegasus); pegasus->rx_skb = pull_skb(pegasus);
spin_unlock(&pegasus->rx_pool_lock); spin_unlock(&pegasus->rx_pool_lock);
...@@ -631,24 +641,24 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs) ...@@ -631,24 +641,24 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs)
static void rx_fixup(unsigned long data) static void rx_fixup(unsigned long data)
{ {
pegasus_t *pegasus; pegasus_t *pegasus;
unsigned long flags;
pegasus = (pegasus_t *) data; pegasus = (pegasus_t *) data;
if (pegasus->flags & PEGASUS_UNPLUG)
return;
spin_lock_irq(&pegasus->rx_pool_lock); spin_lock_irqsave(&pegasus->rx_pool_lock, flags);
fill_skb_pool(pegasus); fill_skb_pool(pegasus);
spin_unlock_irq(&pegasus->rx_pool_lock);
if (pegasus->flags & PEGASUS_RX_URB_FAIL) if (pegasus->flags & PEGASUS_RX_URB_FAIL)
if (pegasus->rx_skb) if (pegasus->rx_skb)
goto try_again; goto try_again;
if (pegasus->rx_skb == NULL) { if (pegasus->rx_skb == NULL) {
spin_lock_irq(&pegasus->rx_pool_lock);
pegasus->rx_skb = pull_skb(pegasus); pegasus->rx_skb = pull_skb(pegasus);
spin_unlock_irq(&pegasus->rx_pool_lock);
} }
if (pegasus->rx_skb == NULL) { if (pegasus->rx_skb == NULL) {
warn("wow, low on memory"); warn("wow, low on memory");
tasklet_schedule(&pegasus->rx_tl); tasklet_schedule(&pegasus->rx_tl);
return; goto done;
} }
usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb, usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb,
usb_rcvbulkpipe(pegasus->usb, 1), usb_rcvbulkpipe(pegasus->usb, 1),
...@@ -661,23 +671,41 @@ static void rx_fixup(unsigned long data) ...@@ -661,23 +671,41 @@ static void rx_fixup(unsigned long data)
} else { } else {
pegasus->flags &= ~PEGASUS_RX_URB_FAIL; pegasus->flags &= ~PEGASUS_RX_URB_FAIL;
} }
done:
spin_unlock_irqrestore(&pegasus->rx_pool_lock, flags);
} }
static void write_bulk_callback(struct urb *urb, struct pt_regs *regs) static void write_bulk_callback(struct urb *urb, struct pt_regs *regs)
{ {
pegasus_t *pegasus = urb->context; pegasus_t *pegasus = urb->context;
struct net_device *net = pegasus->net;
if (!pegasus || !(pegasus->flags & PEGASUS_RUNNING)) if (!pegasus || !(pegasus->flags & PEGASUS_RUNNING))
return; return;
if (!netif_device_present(pegasus->net)) if (!netif_device_present(net))
return; return;
if (urb->status) switch (urb->status) {
info("%s: TX status %d", pegasus->net->name, urb->status); case -EPIPE:
/* FIXME schedule_work() to clear the tx halt */
netif_stop_queue(net);
warn("%s: no tx stall recovery", net->name);
return;
case -ENOENT:
case -ECONNRESET:
case -ESHUTDOWN:
dbg("%s: tx unlink, %d", net->name, urb->status);
return;
default:
info("%s: TX status %d", net->name, urb->status);
/* FALL THROUGH */
case 0:
break;
}
pegasus->net->trans_start = jiffies; net->trans_start = jiffies;
netif_wake_queue(pegasus->net); netif_wake_queue(net);
} }
static void intr_callback(struct urb *urb, struct pt_regs *regs) static void intr_callback(struct urb *urb, struct pt_regs *regs)
...@@ -754,8 +782,16 @@ static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net) ...@@ -754,8 +782,16 @@ static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net)
write_bulk_callback, pegasus); write_bulk_callback, pegasus);
if ((res = usb_submit_urb(pegasus->tx_urb, GFP_ATOMIC))) { if ((res = usb_submit_urb(pegasus->tx_urb, GFP_ATOMIC))) {
warn("failed tx_urb %d", res); warn("failed tx_urb %d", res);
pegasus->stats.tx_errors++; switch (res) {
netif_start_queue(net); case -EPIPE: /* stall, or disconnect from TT */
/* cleanup should already have been scheduled */
break;
case -ENODEV: /* disconnect() upcoming */
break;
default:
pegasus->stats.tx_errors++;
netif_start_queue(net);
}
} else { } else {
pegasus->stats.tx_packets++; pegasus->stats.tx_packets++;
pegasus->stats.tx_bytes += skb->len; pegasus->stats.tx_bytes += skb->len;
...@@ -903,6 +939,7 @@ static int pegasus_close(struct net_device *net) ...@@ -903,6 +939,7 @@ static int pegasus_close(struct net_device *net)
netif_stop_queue(net); netif_stop_queue(net);
if (!(pegasus->flags & PEGASUS_UNPLUG)) if (!(pegasus->flags & PEGASUS_UNPLUG))
disable_net_traffic(pegasus); disable_net_traffic(pegasus);
tasklet_kill(&pegasus->rx_tl);
unlink_all_urbs(pegasus); unlink_all_urbs(pegasus);
return 0; return 0;
...@@ -920,11 +957,15 @@ static int pegasus_ethtool_ioctl(struct net_device *dev, void *useraddr) ...@@ -920,11 +957,15 @@ static int pegasus_ethtool_ioctl(struct net_device *dev, void *useraddr)
switch (ethcmd) { switch (ethcmd) {
/* get driver-specific version/etc. info */ /* get driver-specific version/etc. info */
case ETHTOOL_GDRVINFO:{ case ETHTOOL_GDRVINFO:{
struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; struct ethtool_drvinfo info;
strlcpy(info.driver, driver_name, memset (&info, 0, sizeof (info));
sizeof (info.driver)); info.cmd = ETHTOOL_GDRVINFO;
strlcpy(info.version, DRIVER_VERSION, strncpy(info.driver, driver_name,
sizeof (info.version)); sizeof (info.driver) - 1);
strncpy(info.version, DRIVER_VERSION,
sizeof (info.version) - 1);
usb_make_path(pegasus->usb, info.bus_info,
sizeof (info.bus_info));
if (copy_to_user(useraddr, &info, sizeof (info))) if (copy_to_user(useraddr, &info, sizeof (info)))
return -EFAULT; return -EFAULT;
return 0; return 0;
...@@ -993,12 +1034,15 @@ static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr) ...@@ -993,12 +1034,15 @@ static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr)
return -EFAULT; return -EFAULT;
switch (cmd) { switch (cmd) {
case ETHTOOL_GDRVINFO:{ case ETHTOOL_GDRVINFO:{
struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; struct ethtool_drvinfo info;
strncpy(info.driver, driver_name, sizeof info.driver); memset (&info, 0, sizeof (info));
info.cmd = ETHTOOL_GDRVINFO;
strncpy(info.driver, driver_name,
sizeof (info.driver) - 1);
strncpy(info.version, DRIVER_VERSION, strncpy(info.version, DRIVER_VERSION,
ETHTOOL_BUSINFO_LEN); sizeof (info.version) - 1);
usb_make_path(pegasus->usb, info.bus_info, usb_make_path(pegasus->usb, info.bus_info,
sizeof info.bus_info); sizeof (info.bus_info));
if (copy_to_user(uaddr, &info, sizeof (info))) if (copy_to_user(uaddr, &info, sizeof (info)))
return -EFAULT; return -EFAULT;
return 0; return 0;
...@@ -1006,15 +1050,20 @@ static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr) ...@@ -1006,15 +1050,20 @@ static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr)
case ETHTOOL_GSET:{ case ETHTOOL_GSET:{
struct ethtool_cmd ecmd; struct ethtool_cmd ecmd;
short lpa, bmcr; short lpa, bmcr;
u8 port;
memset(&ecmd, 0, sizeof ecmd); memset(&ecmd, 0, sizeof (ecmd));
ecmd.supported = (SUPPORTED_10baseT_Half | ecmd.supported = (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full | SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full | SUPPORTED_100baseT_Full |
SUPPORTED_Autoneg | SUPPORTED_Autoneg |
SUPPORTED_TP | SUPPORTED_MII); SUPPORTED_TP | SUPPORTED_MII);
ecmd.port = PORT_TP; get_registers(pegasus, Reg7b, 1, &port);
if (port == 0)
ecmd.port = PORT_MII;
else
ecmd.port = PORT_TP;
ecmd.transceiver = XCVR_INTERNAL; ecmd.transceiver = XCVR_INTERNAL;
ecmd.phy_address = pegasus->phy; ecmd.phy_address = pegasus->phy;
read_mii_word(pegasus, pegasus->phy, MII_BMCR, &bmcr); read_mii_word(pegasus, pegasus->phy, MII_BMCR, &bmcr);
...@@ -1132,7 +1181,10 @@ static inline void setup_pegasus_II(pegasus_t * pegasus) ...@@ -1132,7 +1181,10 @@ static inline void setup_pegasus_II(pegasus_t * pegasus)
set_register(pegasus, Reg1d, 0); set_register(pegasus, Reg1d, 0);
set_register(pegasus, Reg7b, 1); set_register(pegasus, Reg7b, 1);
mdelay(100); mdelay(100);
set_register(pegasus, Reg7b, 2); if ((pegasus->features & HAS_HOME_PNA) && mii_mode)
set_register(pegasus, Reg7b, 0);
else
set_register(pegasus, Reg7b, 2);
set_register(pegasus, 0x83, data); set_register(pegasus, 0x83, data);
get_registers(pegasus, 0x83, 1, &data); get_registers(pegasus, 0x83, 1, &data);
...@@ -1253,7 +1305,6 @@ static void pegasus_disconnect(struct usb_interface *intf) ...@@ -1253,7 +1305,6 @@ static void pegasus_disconnect(struct usb_interface *intf)
pegasus->flags |= PEGASUS_UNPLUG; pegasus->flags |= PEGASUS_UNPLUG;
unregister_netdev(pegasus->net); unregister_netdev(pegasus->net);
usb_put_dev(interface_to_usbdev(intf)); usb_put_dev(interface_to_usbdev(intf));
unlink_all_urbs(pegasus);
free_all_urbs(pegasus); free_all_urbs(pegasus);
free_skb_pool(pegasus); free_skb_pool(pegasus);
if (pegasus->rx_skb) if (pegasus->rx_skb)
...@@ -1263,7 +1314,6 @@ static void pegasus_disconnect(struct usb_interface *intf) ...@@ -1263,7 +1314,6 @@ static void pegasus_disconnect(struct usb_interface *intf)
} }
static struct usb_driver pegasus_driver = { static struct usb_driver pegasus_driver = {
.owner = THIS_MODULE,
.name = driver_name, .name = driver_name,
.probe = pegasus_probe, .probe = pegasus_probe,
.disconnect = pegasus_disconnect, .disconnect = pegasus_disconnect,
......
/* /*
* Copyright (c) 1999-2002 Petko Manolov - Petkan (petkan@users.sourceforge.net) * Copyright (c) 1999-2003 Petko Manolov - Petkan (petkan@users.sourceforge.net)
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published * it under the terms of the GNU General Public License version 2 as published
...@@ -129,6 +129,7 @@ struct usb_eth_dev { ...@@ -129,6 +129,7 @@ struct usb_eth_dev {
#define VENDOR_ELCON 0x0db7 #define VENDOR_ELCON 0x0db7
#define VENDOR_ELSA 0x05cc #define VENDOR_ELSA 0x05cc
#define VENDOR_HAWKING 0x0e66 #define VENDOR_HAWKING 0x0e66
#define VENDOR_HP 0x03f0
#define VENDOR_IODATA 0x04bb #define VENDOR_IODATA 0x04bb
#define VENDOR_KINGSTON 0x0951 #define VENDOR_KINGSTON 0x0951
#define VENDOR_LANEED 0x056e #define VENDOR_LANEED 0x056e
...@@ -223,6 +224,8 @@ PEGASUS_DEV( "Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000, ...@@ -223,6 +224,8 @@ PEGASUS_DEV( "Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000,
DEFAULT_GPIO_RESET ) DEFAULT_GPIO_RESET )
PEGASUS_DEV( "Hawking UF100 10/100 Ethernet", VENDOR_HAWKING, 0x400c, PEGASUS_DEV( "Hawking UF100 10/100 Ethernet", VENDOR_HAWKING, 0x400c,
DEFAULT_GPIO_RESET | PEGASUS_II ) DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "HP hn210c Ethernet USB", VENDOR_HP, 0x811c,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "IO DATA USB ET/TX", VENDOR_IODATA, 0x0904, PEGASUS_DEV( "IO DATA USB ET/TX", VENDOR_IODATA, 0x0904,
DEFAULT_GPIO_RESET ) DEFAULT_GPIO_RESET )
PEGASUS_DEV( "IO DATA USB ET/TX-S", VENDOR_IODATA, 0x0913, PEGASUS_DEV( "IO DATA USB ET/TX-S", VENDOR_IODATA, 0x0913,
......
...@@ -113,9 +113,11 @@ static void rtl8150_disconnect(struct usb_interface *intf); ...@@ -113,9 +113,11 @@ static void rtl8150_disconnect(struct usb_interface *intf);
static int rtl8150_probe(struct usb_interface *intf, static int rtl8150_probe(struct usb_interface *intf,
const struct usb_device_id *id); const struct usb_device_id *id);
static const char driver_name [] = "rtl8150";
static struct usb_driver rtl8150_driver = { static struct usb_driver rtl8150_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = "rtl8150", .name = driver_name,
.probe = rtl8150_probe, .probe = rtl8150_probe,
.disconnect = rtl8150_disconnect, .disconnect = rtl8150_disconnect,
.id_table = rtl8150_table, .id_table = rtl8150_table,
...@@ -684,7 +686,7 @@ static int rtl8150_ethtool_ioctl(struct net_device *netdev, void *uaddr) ...@@ -684,7 +686,7 @@ static int rtl8150_ethtool_ioctl(struct net_device *netdev, void *uaddr)
case ETHTOOL_GDRVINFO:{ case ETHTOOL_GDRVINFO:{
struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
strncpy(info.driver, DRIVER_DESC, ETHTOOL_BUSINFO_LEN); strncpy(info.driver, driver_name, ETHTOOL_BUSINFO_LEN);
strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN); strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
usb_make_path(dev->udev, info.bus_info, sizeof info.bus_info); usb_make_path(dev->udev, info.bus_info, sizeof info.bus_info);
if (copy_to_user(uaddr, &info, sizeof(info))) if (copy_to_user(uaddr, &info, sizeof(info)))
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
#include <linux/config.h> #include <linux/config.h>
#include "transport.h" #include "transport.h"
#include "protocol.h" #include "protocol.h"
#include "scsiglue.h"
#include "usb.h" #include "usb.h"
#include "debug.h" #include "debug.h"
...@@ -303,6 +304,11 @@ static int interpret_urb_result(struct us_data *us, unsigned int pipe, ...@@ -303,6 +304,11 @@ static int interpret_urb_result(struct us_data *us, unsigned int pipe,
US_DEBUGP("-- device NAKed\n"); US_DEBUGP("-- device NAKed\n");
return USB_STOR_XFER_ERROR; return USB_STOR_XFER_ERROR;
/* babble - the device tried to send more than we wanted to read */
case -EOVERFLOW:
US_DEBUGP("-- Babble\n");
return USB_STOR_XFER_LONG;
/* the transfer was cancelled, presumably by an abort */ /* the transfer was cancelled, presumably by an abort */
case -ECONNRESET: case -ECONNRESET:
US_DEBUGP("-- transfer cancelled\n"); US_DEBUGP("-- transfer cancelled\n");
...@@ -525,6 +531,12 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -525,6 +531,12 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
return; return;
} }
/* if the transport provided its own sense data, don't auto-sense */
if (result == USB_STOR_TRANSPORT_NO_SENSE) {
srb->result = SAM_STAT_CHECK_CONDITION;
return;
}
/* Determine if we need to auto-sense /* Determine if we need to auto-sense
* *
* I normally don't use a flag like this, but it's almost impossible * I normally don't use a flag like this, but it's almost impossible
...@@ -764,7 +776,7 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -764,7 +776,7 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
srb->request_buffer, transfer_length, srb->request_buffer, transfer_length,
srb->use_sg, &srb->resid); srb->use_sg, &srb->resid);
US_DEBUGP("CBI data stage result is 0x%x\n", result); US_DEBUGP("CBI data stage result is 0x%x\n", result);
if (result == USB_STOR_XFER_ERROR) if (result > USB_STOR_XFER_STALLED)
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
} }
...@@ -854,7 +866,7 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -854,7 +866,7 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us)
srb->request_buffer, transfer_length, srb->request_buffer, transfer_length,
srb->use_sg, &srb->resid); srb->use_sg, &srb->resid);
US_DEBUGP("CB data stage result is 0x%x\n", result); US_DEBUGP("CB data stage result is 0x%x\n", result);
if (result == USB_STOR_XFER_ERROR) if (result > USB_STOR_XFER_STALLED)
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
} }
...@@ -899,6 +911,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -899,6 +911,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
struct bulk_cs_wrap bcs; struct bulk_cs_wrap bcs;
unsigned int transfer_length = srb->request_bufflen; unsigned int transfer_length = srb->request_bufflen;
int result; int result;
int fake_sense = 0;
/* set up the command wrapper */ /* set up the command wrapper */
bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN);
...@@ -936,6 +949,15 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -936,6 +949,15 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
US_DEBUGP("Bulk data transfer result 0x%x\n", result); US_DEBUGP("Bulk data transfer result 0x%x\n", result);
if (result == USB_STOR_XFER_ERROR) if (result == USB_STOR_XFER_ERROR)
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
/* If the device tried to send back more data than the
* amount requested, the spec requires us to transfer
* the CSW anyway. Since there's no point retrying the
* the command, we'll return fake sense data indicating
* Illegal Request, Invalid Field in CDB.
*/
if (result == USB_STOR_XFER_LONG)
fake_sense = 1;
} }
/* See flow chart on pg 15 of the Bulk Only Transport spec for /* See flow chart on pg 15 of the Bulk Only Transport spec for
...@@ -975,6 +997,14 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -975,6 +997,14 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
/* based on the status code, we report good or bad */ /* based on the status code, we report good or bad */
switch (bcs.Status) { switch (bcs.Status) {
case US_BULK_STAT_OK: case US_BULK_STAT_OK:
/* device babbled -- return fake sense data */
if (fake_sense) {
memcpy(srb->sense_buffer,
usb_stor_sense_invalidCDB,
sizeof(usb_stor_sense_invalidCDB));
return USB_STOR_TRANSPORT_NO_SENSE;
}
/* command good -- note that data could be short */ /* command good -- note that data could be short */
return USB_STOR_TRANSPORT_GOOD; return USB_STOR_TRANSPORT_GOOD;
......
...@@ -122,7 +122,8 @@ struct bulk_cs_wrap { ...@@ -122,7 +122,8 @@ struct bulk_cs_wrap {
#define USB_STOR_XFER_GOOD 0 /* good transfer */ #define USB_STOR_XFER_GOOD 0 /* good transfer */
#define USB_STOR_XFER_SHORT 1 /* transferred less than expected */ #define USB_STOR_XFER_SHORT 1 /* transferred less than expected */
#define USB_STOR_XFER_STALLED 2 /* endpoint stalled */ #define USB_STOR_XFER_STALLED 2 /* endpoint stalled */
#define USB_STOR_XFER_ERROR 3 /* transfer died in the middle */ #define USB_STOR_XFER_LONG 3 /* device tried to send too much */
#define USB_STOR_XFER_ERROR 4 /* transfer died in the middle */
/* /*
* Transport return codes * Transport return codes
...@@ -130,7 +131,8 @@ struct bulk_cs_wrap { ...@@ -130,7 +131,8 @@ struct bulk_cs_wrap {
#define USB_STOR_TRANSPORT_GOOD 0 /* Transport good, command good */ #define USB_STOR_TRANSPORT_GOOD 0 /* Transport good, command good */
#define USB_STOR_TRANSPORT_FAILED 1 /* Transport good, command failed */ #define USB_STOR_TRANSPORT_FAILED 1 /* Transport good, command failed */
#define USB_STOR_TRANSPORT_ERROR 2 /* Transport bad (i.e. device dead) */ #define USB_STOR_TRANSPORT_NO_SENSE 2 /* Command failed, no auto-sense */
#define USB_STOR_TRANSPORT_ERROR 3 /* Transport bad (i.e. device dead) */
/* /*
* We used to have USB_STOR_XFER_ABORTED and USB_STOR_TRANSPORT_ABORTED * We used to have USB_STOR_XFER_ABORTED and USB_STOR_TRANSPORT_ABORTED
......
...@@ -3,10 +3,11 @@ ...@@ -3,10 +3,11 @@
* $Id: usb.c,v 1.75 2002/04/22 03:39:43 mdharm Exp $ * $Id: usb.c,v 1.75 2002/04/22 03:39:43 mdharm Exp $
* *
* Current development and maintenance by: * Current development and maintenance by:
* (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) * (c) 1999-2003 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
* *
* Developed with the assistance of: * Developed with the assistance of:
* (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org) * (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
* (c) 2003 Alan Stern (stern@rowland.harvard.edu)
* *
* Initial work by: * Initial work by:
* (c) 1999 Michael Gee (michael@linuxspecific.com) * (c) 1999 Michael Gee (michael@linuxspecific.com)
...@@ -297,7 +298,7 @@ static int usb_stor_control_thread(void * __us) ...@@ -297,7 +298,7 @@ static int usb_stor_control_thread(void * __us)
/* /*
* This thread doesn't need any user-level access, * This thread doesn't need any user-level access,
* so get rid of all our resources.. * so get rid of all our resources.
*/ */
daemonize("usb-storage"); daemonize("usb-storage");
...@@ -305,9 +306,6 @@ static int usb_stor_control_thread(void * __us) ...@@ -305,9 +306,6 @@ static int usb_stor_control_thread(void * __us)
unlock_kernel(); unlock_kernel();
/* set up for wakeups by new commands */
init_MUTEX_LOCKED(&us->sema);
/* signal that we've started the thread */ /* signal that we've started the thread */
complete(&(us->notify)); complete(&(us->notify));
...@@ -366,17 +364,6 @@ static int usb_stor_control_thread(void * __us) ...@@ -366,17 +364,6 @@ static int usb_stor_control_thread(void * __us)
us->srb->result = DID_BAD_TARGET << 16; us->srb->result = DID_BAD_TARGET << 16;
} }
/* handle requests for EVPD, which most USB devices do
* not support */
else if((us->srb->cmnd[0] == INQUIRY) &&
(us->srb->cmnd[1] & 0x1)) {
US_DEBUGP("Faking INQUIRY command for EVPD\n");
memcpy(us->srb->sense_buffer,
usb_stor_sense_invalidCDB,
sizeof(usb_stor_sense_invalidCDB));
us->srb->result = SAM_STAT_CHECK_CONDITION;
}
/* Handle those devices which need us to fake /* Handle those devices which need us to fake
* their inquiry data */ * their inquiry data */
else if ((us->srb->cmnd[0] == INQUIRY) && else if ((us->srb->cmnd[0] == INQUIRY) &&
...@@ -432,272 +419,60 @@ static int usb_stor_control_thread(void * __us) ...@@ -432,272 +419,60 @@ static int usb_stor_control_thread(void * __us)
return 0; return 0;
} }
/* Set up the URB and the usb_ctrlrequest. /***********************************************************************
* us->dev_semaphore must already be locked. * Device probing and disconnecting
* Note that this function assumes that all the data in the us_data ***********************************************************************/
* structure is current.
* Returns non-zero on failure, zero on success
*/
static int usb_stor_allocate_urbs(struct us_data *us)
{
/* calculate and store the pipe values */
us->send_ctrl_pipe = usb_sndctrlpipe(us->pusb_dev, 0);
us->recv_ctrl_pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
us->send_bulk_pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
us->recv_intr_pipe = usb_rcvintpipe(us->pusb_dev, us->ep_int);
/* allocate the usb_ctrlrequest for control packets */
US_DEBUGP("Allocating usb_ctrlrequest\n");
us->dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
if (!us->dr) {
US_DEBUGP("allocation failed\n");
return 1;
}
/* allocate the URB we're going to use */
US_DEBUGP("Allocating URB\n");
us->current_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!us->current_urb) {
US_DEBUGP("allocation failed\n");
return 2;
}
US_DEBUGP("Allocating scatter-gather request block\n");
us->current_sg = kmalloc(sizeof(*us->current_sg), GFP_KERNEL);
if (!us->current_sg) {
US_DEBUGP("allocation failed\n");
return 5;
}
return 0; /* success */
}
/* Deallocate the URB, the usb_ctrlrequest, and the IRQ pipe.
* us->dev_semaphore must already be locked.
*/
static void usb_stor_deallocate_urbs(struct us_data *us)
{
/* free the scatter-gather request block */
if (us->current_sg) {
kfree(us->current_sg);
us->current_sg = NULL;
}
/* free up the main URB for this device */
if (us->current_urb) {
US_DEBUGP("-- releasing main URB\n");
usb_free_urb(us->current_urb);
us->current_urb = NULL;
}
/* free the usb_ctrlrequest buffer */
if (us->dr) {
kfree(us->dr);
us->dr = NULL;
}
/* mark the device as gone */
usb_put_dev(us->pusb_dev);
us->pusb_dev = NULL;
}
/* Probe to see if a new device is actually a SCSI device */ /* Get the unusual_devs entries and the string descriptors */
static int storage_probe(struct usb_interface *intf, static void get_device_info(struct us_data *us,
const struct usb_device_id *id) struct us_unusual_dev *unusual_dev)
{ {
struct usb_device *dev = interface_to_usbdev(intf); struct usb_device *dev = us->pusb_dev;
int ifnum = intf->altsetting->desc.bInterfaceNumber;
int i;
const int id_index = id - storage_usb_ids;
char mf[USB_STOR_STRING_LEN]; /* manufacturer */
char prod[USB_STOR_STRING_LEN]; /* product */
char serial[USB_STOR_STRING_LEN]; /* serial number */
unsigned int flags;
struct us_unusual_dev *unusual_dev;
struct us_data *us = NULL;
int result;
/* these are temporary copies -- we test on these, then put them
* in the us-data structure
*/
struct usb_endpoint_descriptor *ep_in = NULL;
struct usb_endpoint_descriptor *ep_out = NULL;
struct usb_endpoint_descriptor *ep_int = NULL;
u8 subclass = 0;
u8 protocol = 0;
/* the altsetting on the interface we're probing that matched our
* usb_match_id table
*/
struct usb_host_interface *altsetting =
intf[ifnum].altsetting + intf[ifnum].act_altsetting;
US_DEBUGP("act_altsetting is %d\n", intf[ifnum].act_altsetting);
/* clear the temporary strings */
memset(mf, 0, sizeof(mf));
memset(prod, 0, sizeof(prod));
memset(serial, 0, sizeof(serial));
/*
* Can we support this device, either because we know about it
* from our unusual device list, or because it advertises that it's
* compliant to the specification?
*
* id_index is calculated in the declaration to be the index number
* of the match from the usb_device_id table, so we can find the
* corresponding entry in the private table.
*/
US_DEBUGP("id_index calculated to be: %d\n", id_index);
US_DEBUGP("Array length appears to be: %d\n", sizeof(us_unusual_dev_list) / sizeof(us_unusual_dev_list[0]));
if (id_index <
sizeof(us_unusual_dev_list) / sizeof(us_unusual_dev_list[0])) {
unusual_dev = &us_unusual_dev_list[id_index];
if (unusual_dev->vendorName)
US_DEBUGP("Vendor: %s\n", unusual_dev->vendorName);
if (unusual_dev->productName)
US_DEBUGP("Product: %s\n", unusual_dev->productName);
} else
/* no, we can't support it */
return -EIO;
/* At this point, we know we've got a live one */
US_DEBUGP("USB Mass Storage device detected\n");
/* Determine subclass and protocol, or copy from the interface */
subclass = unusual_dev->useProtocol;
protocol = unusual_dev->useTransport;
flags = unusual_dev->flags;
/*
* Find the endpoints we need
* We are expecting a minimum of 2 endpoints - in and out (bulk).
* An optional interrupt is OK (necessary for CBI protocol).
* We will ignore any others.
*/
for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
struct usb_endpoint_descriptor *ep;
ep = &altsetting->endpoint[i].desc;
/* is it an BULK endpoint? */
if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_BULK) {
/* BULK in or out? */
if (ep->bEndpointAddress & USB_DIR_IN)
ep_in = ep;
else
ep_out = ep;
}
/* is it an interrupt endpoint? */
else if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_INT) {
ep_int = ep;
}
}
US_DEBUGP("Endpoints: In: 0x%p Out: 0x%p Int: 0x%p (Period %d)\n",
ep_in, ep_out, ep_int, ep_int ? ep_int->bInterval : 0);
#ifdef CONFIG_USB_STORAGE_SDDR09
if (protocol == US_PR_EUSB_SDDR09 || protocol == US_PR_DPCM_USB) {
/* set the configuration -- STALL is an acceptable response here */
result = usb_set_configuration(dev, 1);
US_DEBUGP("Result from usb_set_configuration is %d\n", result);
if (result == -EPIPE) {
US_DEBUGP("-- stall on control interface\n");
} else if (result != 0) {
/* it's not a stall, but another error -- time to bail */
US_DEBUGP("-- Unknown error. Rejecting device\n");
return -EIO;
}
}
#endif
/* Do some basic sanity checks, and bail if we find a problem */ if (unusual_dev->vendorName)
if (!ep_in || !ep_out || (protocol == US_PR_CBI && !ep_int)) { US_DEBUGP("Vendor: %s\n", unusual_dev->vendorName);
US_DEBUGP("Endpoint sanity check failed! Rejecting dev.\n"); if (unusual_dev->productName)
return -EIO; US_DEBUGP("Product: %s\n", unusual_dev->productName);
}
/* At this point, we've decided to try to use the device */ /* Store the entries */
usb_get_dev(dev); us->unusual_dev = unusual_dev;
us->subclass = unusual_dev->useProtocol;
us->protocol = unusual_dev->useTransport;
us->flags = unusual_dev->flags;
/* fetch the strings */ /* Read the device's string descriptors */
if (dev->descriptor.iManufacturer) if (dev->descriptor.iManufacturer)
usb_string(dev, dev->descriptor.iManufacturer, usb_string(dev, dev->descriptor.iManufacturer,
mf, sizeof(mf)); us->vendor, sizeof(us->vendor));
if (dev->descriptor.iProduct) if (dev->descriptor.iProduct)
usb_string(dev, dev->descriptor.iProduct, usb_string(dev, dev->descriptor.iProduct,
prod, sizeof(prod)); us->product, sizeof(us->product));
if (dev->descriptor.iSerialNumber && !(flags & US_FL_IGNORE_SER)) if (dev->descriptor.iSerialNumber && !(us->flags & US_FL_IGNORE_SER))
usb_string(dev, dev->descriptor.iSerialNumber, usb_string(dev, dev->descriptor.iSerialNumber,
serial, sizeof(serial)); us->serial, sizeof(us->serial));
/* New device -- allocate memory and initialize */ /* Use the unusual_dev strings if the device didn't provide them */
if ((us = (struct us_data *)kmalloc(sizeof(struct us_data),
GFP_KERNEL)) == NULL) {
printk(KERN_WARNING USB_STORAGE "Out of memory\n");
usb_put_dev(dev);
return -ENOMEM;
}
memset(us, 0, sizeof(struct us_data));
/* Initialize the mutexes only when the struct is new */
init_completion(&(us->notify));
init_MUTEX_LOCKED(&(us->dev_semaphore));
/* copy over the subclass and protocol data */
us->subclass = subclass;
us->protocol = protocol;
us->flags = flags;
us->unusual_dev = unusual_dev;
/* copy over the endpoint data */
us->ep_in = ep_in->bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK;
us->ep_out = ep_out->bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK;
if (ep_int) {
us->ep_int = ep_int->bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK;
us->ep_bInterval = ep_int->bInterval;
}
else
us->ep_int = us->ep_bInterval = 0;
/* establish the connection to the new device */
us->ifnum = ifnum;
us->pusb_dev = dev;
/* copy over the identifiying strings */
strncpy(us->vendor, mf, USB_STOR_STRING_LEN);
strncpy(us->product, prod, USB_STOR_STRING_LEN);
strncpy(us->serial, serial, USB_STOR_STRING_LEN);
if (strlen(us->vendor) == 0) { if (strlen(us->vendor) == 0) {
if (unusual_dev->vendorName) if (unusual_dev->vendorName)
strncpy(us->vendor, unusual_dev->vendorName, strncpy(us->vendor, unusual_dev->vendorName,
USB_STOR_STRING_LEN); sizeof(us->vendor) - 1);
else else
strncpy(us->vendor, "Unknown", strcpy(us->vendor, "Unknown");
USB_STOR_STRING_LEN);
} }
if (strlen(us->product) == 0) { if (strlen(us->product) == 0) {
if (unusual_dev->productName) if (unusual_dev->productName)
strncpy(us->product, unusual_dev->productName, strncpy(us->product, unusual_dev->productName,
USB_STOR_STRING_LEN); sizeof(us->product) - 1);
else else
strncpy(us->product, "Unknown", strcpy(us->product, "Unknown");
USB_STOR_STRING_LEN);
} }
if (strlen(us->serial) == 0) if (strlen(us->serial) == 0)
strncpy(us->serial, "None", USB_STOR_STRING_LEN); strcpy(us->serial, "None");
}
/* /* Get the transport settings */
* Set the handler pointers based on the protocol static int get_transport(struct us_data *us)
* Again, this data is persistent across reattachments {
*/
switch (us->protocol) { switch (us->protocol) {
case US_PR_CB: case US_PR_CB:
us->transport_name = "Control/Bulk"; us->transport_name = "Control/Bulk";
...@@ -783,15 +558,19 @@ static int storage_probe(struct usb_interface *intf, ...@@ -783,15 +558,19 @@ static int storage_probe(struct usb_interface *intf,
#endif #endif
default: default:
/* us->transport_name = "Unknown"; */ return -EIO;
goto BadDevice;
} }
US_DEBUGP("Transport: %s\n", us->transport_name); US_DEBUGP("Transport: %s\n", us->transport_name);
/* fix for single-lun devices */ /* fix for single-lun devices */
if (us->flags & US_FL_SINGLE_LUN) if (us->flags & US_FL_SINGLE_LUN)
us->max_lun = 0; us->max_lun = 0;
return 0;
}
/* Get the protocol settings */
static int get_protocol(struct us_data *us)
{
switch (us->subclass) { switch (us->subclass) {
case US_SC_RBC: case US_SC_RBC:
us->protocol_name = "Reduced Block Commands (RBC)"; us->protocol_name = "Reduced Block Commands (RBC)";
...@@ -834,173 +613,335 @@ static int storage_probe(struct usb_interface *intf, ...@@ -834,173 +613,335 @@ static int storage_probe(struct usb_interface *intf,
#endif #endif
default: default:
/* us->protocol_name = "Unknown"; */ return -EIO;
goto BadDevice;
} }
US_DEBUGP("Protocol: %s\n", us->protocol_name); US_DEBUGP("Protocol: %s\n", us->protocol_name);
return 0;
}
/* allocate the URB, the usb_ctrlrequest, and the IRQ URB */ /* Get the pipe settings */
if (usb_stor_allocate_urbs(us)) static int get_pipes(struct us_data *us)
goto BadDevice; {
struct usb_host_interface *altsetting =
&us->pusb_intf->altsetting[us->pusb_intf->act_altsetting];
int i;
struct usb_endpoint_descriptor *ep;
struct usb_endpoint_descriptor *ep_in = NULL;
struct usb_endpoint_descriptor *ep_out = NULL;
struct usb_endpoint_descriptor *ep_int = NULL;
/*
* Find the endpoints we need.
* We are expecting a minimum of 2 endpoints - in and out (bulk).
* An optional interrupt is OK (necessary for CBI protocol).
* We will ignore any others.
*/
for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
ep = &altsetting->endpoint[i].desc;
/* Is it a BULK endpoint? */
if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_BULK) {
/* BULK in or out? */
if (ep->bEndpointAddress & USB_DIR_IN)
ep_in = ep;
else
ep_out = ep;
}
/* Is it an interrupt endpoint? */
else if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_INT) {
ep_int = ep;
}
}
US_DEBUGP("Endpoints: In: 0x%p Out: 0x%p Int: 0x%p (Period %d)\n",
ep_in, ep_out, ep_int, ep_int ? ep_int->bInterval : 0);
if (!ep_in || !ep_out || (us->protocol == US_PR_CBI && !ep_int)) {
US_DEBUGP("Endpoint sanity check failed! Rejecting dev.\n");
return -EIO;
}
/* Calculate and store the pipe values */
us->send_ctrl_pipe = usb_sndctrlpipe(us->pusb_dev, 0);
us->recv_ctrl_pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
us->send_bulk_pipe = usb_sndbulkpipe(us->pusb_dev,
ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev,
ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
if (ep_int) {
us->recv_intr_pipe = usb_rcvintpipe(us->pusb_dev,
ep_int->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
us->ep_bInterval = ep_int->bInterval;
}
return 0;
}
/* Initialize all the dynamic resources we need */
static int usb_stor_acquire_resources(struct us_data *us)
{
int p;
/* Allocate the USB control blocks */
US_DEBUGP("Allocating usb_ctrlrequest\n");
us->dr = kmalloc(sizeof(*us->dr), GFP_KERNEL);
if (!us->dr) {
US_DEBUGP("allocation failed\n");
return -ENOMEM;
}
US_DEBUGP("Allocating URB\n");
us->current_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!us->current_urb) {
US_DEBUGP("allocation failed\n");
return -ENOMEM;
}
US_DEBUGP("Allocating scatter-gather request block\n");
us->current_sg = kmalloc(sizeof(*us->current_sg), GFP_KERNEL);
if (!us->current_sg) {
US_DEBUGP("allocation failed\n");
return -ENOMEM;
}
/* Lock the device while we carry out the next two operations */
down(&us->dev_semaphore);
/* For bulk-only devices, determine the max LUN value */ /* For bulk-only devices, determine the max LUN value */
if (us->protocol == US_PR_BULK) if (us->protocol == US_PR_BULK)
us->max_lun = usb_stor_Bulk_max_lun(us); us->max_lun = usb_stor_Bulk_max_lun(us);
/*
* Since this is a new device, we need to generate a scsi
* host definition, and register with the higher SCSI layers
*/
/* Just before we start our control thread, initialize /* Just before we start our control thread, initialize
* the device if it needs initialization */ * the device if it needs initialization */
if (unusual_dev && unusual_dev->initFunction) if (us->unusual_dev->initFunction)
unusual_dev->initFunction(us); us->unusual_dev->initFunction(us);
/* start up our control thread */ up(&us->dev_semaphore);
/* Start up our control thread */
atomic_set(&us->sm_state, US_STATE_IDLE); atomic_set(&us->sm_state, US_STATE_IDLE);
us->pid = kernel_thread(usb_stor_control_thread, us, p = kernel_thread(usb_stor_control_thread, us, CLONE_VM);
CLONE_VM); if (p < 0) {
if (us->pid < 0) {
printk(KERN_WARNING USB_STORAGE printk(KERN_WARNING USB_STORAGE
"Unable to start control thread\n"); "Unable to start control thread\n");
goto BadDevice; return p;
} }
us->pid = p;
/* wait for the thread to start */ /* Wait for the thread to start */
wait_for_completion(&(us->notify)); wait_for_completion(&(us->notify));
/* unlock the device pointers */ /*
up(&(us->dev_semaphore)); * Since this is a new device, we need to register a SCSI
* host definition with the higher SCSI layers.
/* now register */ */
us->host = scsi_register(&usb_stor_host_template, sizeof(us)); us->host = scsi_register(&usb_stor_host_template, sizeof(us));
if (!us->host) { if (!us->host) {
printk(KERN_WARNING USB_STORAGE printk(KERN_WARNING USB_STORAGE
"Unable to register the scsi host\n"); "Unable to register the scsi host\n");
return -EBUSY;
}
/* Set the hostdata to prepare for scanning */
us->host->hostdata[0] = (unsigned long) us;
/* tell the control thread to exit */ return 0;
}
/* Dissociate from the USB device */
static void dissociate_dev(struct us_data *us)
{
US_DEBUGP("-- %s\n", __FUNCTION__);
down(&us->dev_semaphore);
usb_set_intfdata(us->pusb_intf, NULL);
usb_put_dev(us->pusb_dev);
us->pusb_dev = NULL;
us->pusb_intf = NULL;
up(&us->dev_semaphore);
}
/* Release all our static and dynamic resources */
void usb_stor_release_resources(struct us_data *us)
{
/*
* The host must already have been removed
* and dissociate_dev() must have been called.
*/
/* Finish the SCSI host removal sequence */
if (us->host) {
(struct us_data *) us->host->hostdata[0] = NULL;
scsi_unregister(us->host);
}
/* Kill the control thread
*
* Enqueue the command, wake up the thread, and wait for
* notification that it has exited.
*/
if (us->pid) {
US_DEBUGP("-- sending exit command to thread\n");
BUG_ON(atomic_read(&us->sm_state) != US_STATE_IDLE);
us->srb = NULL; us->srb = NULL;
up(&us->sema); up(&(us->sema));
wait_for_completion(&us->notify); wait_for_completion(&(us->notify));
}
/* re-lock the device pointers */ /* Call the destructor routine, if it exists */
down(&us->dev_semaphore); if (us->extra_destructor) {
goto BadDevice; US_DEBUGP("-- calling extra_destructor()\n");
us->extra_destructor(us->extra);
}
/* Destroy the extra data */
if (us->extra) {
kfree(us->extra);
}
/* Free the USB control blocks */
if (us->current_sg)
kfree(us->current_sg);
if (us->current_urb)
usb_free_urb(us->current_urb);
if (us->dr)
kfree(us->dr);
/* Free the structure itself */
kfree(us);
US_DEBUGP("-- %s finished\n", __FUNCTION__);
}
/* Probe to see if we can drive a newly-connected USB device */
static int storage_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct us_data *us;
const int id_index = id - storage_usb_ids;
int result;
US_DEBUGP("USB Mass Storage device detected\n");
US_DEBUGP("act_altsetting is %d, id_index is %d\n",
intf->act_altsetting, id_index);
/* Allocate the us_data structure and initialize the mutexes */
us = (struct us_data *) kmalloc(sizeof(*us), GFP_KERNEL);
if (!us) {
printk(KERN_WARNING USB_STORAGE "Out of memory\n");
return -ENOMEM;
} }
memset(us, 0, sizeof(struct us_data));
init_MUTEX(&(us->dev_semaphore));
init_MUTEX_LOCKED(&(us->sema));
init_completion(&(us->notify));
/* Fill in the device-related fields */
us->pusb_dev = interface_to_usbdev(intf);
us->pusb_intf = intf;
us->ifnum = intf->altsetting->desc.bInterfaceNumber;
/* Store our private data in the interface and increment the
* device's reference count */
usb_set_intfdata(intf, us);
usb_get_dev(us->pusb_dev);
/*
* Get the unusual_devs entries and the descriptors
*
* id_index is calculated in the declaration to be the index number
* of the match from the usb_device_id table, so we can find the
* corresponding entry in the private table.
*/
get_device_info(us, &us_unusual_dev_list[id_index]);
/* set the hostdata to prepare for scanning */ #ifdef CONFIG_USB_STORAGE_SDDR09
us->host->hostdata[0] = (unsigned long)us; if (us->protocol == US_PR_EUSB_SDDR09 ||
us->protocol == US_PR_DPCM_USB) {
/* set the configuration -- STALL is an acceptable response here */
result = usb_set_configuration(us->pusb_dev, 1);
/* now add the host */ US_DEBUGP("Result from usb_set_configuration is %d\n", result);
if (result == -EPIPE) {
US_DEBUGP("-- stall on control interface\n");
} else if (result != 0) {
/* it's not a stall, but another error -- time to bail */
US_DEBUGP("-- Unknown error. Rejecting device\n");
goto BadDevice;
}
}
#endif
/* Get the transport, protocol, and pipe settings */
result = get_transport(us);
if (result)
goto BadDevice;
result = get_protocol(us);
if (result)
goto BadDevice;
result = get_pipes(us);
if (result)
goto BadDevice;
/* Acquire all the other resources */
result = usb_stor_acquire_resources(us);
if (result)
goto BadDevice;
/* Finally, add the host (this does SCSI device scanning) */
result = scsi_add_host(us->host, &intf->dev); result = scsi_add_host(us->host, &intf->dev);
if (result) { if (result) {
printk(KERN_WARNING USB_STORAGE printk(KERN_WARNING USB_STORAGE
"Unable to add the scsi host\n"); "Unable to add the scsi host\n");
/* tell the control thread to exit */
us->srb = NULL;
up(&us->sema);
wait_for_completion(&us->notify);
/* re-lock the device pointers */
down(&us->dev_semaphore);
goto BadDevice; goto BadDevice;
} }
printk(KERN_DEBUG printk(KERN_DEBUG
"WARNING: USB Mass Storage data integrity not assured\n"); "WARNING: USB Mass Storage data integrity not assured\n");
printk(KERN_DEBUG printk(KERN_DEBUG
"USB Mass Storage device found at %d\n", dev->devnum); "USB Mass Storage device found at %d\n", us->pusb_dev->devnum);
/* save a pointer to our structure */
usb_set_intfdata(intf, us);
return 0; return 0;
/* we come here if there are any problems */ /* We come here if there are any problems */
/* us->dev_semaphore must be locked */
BadDevice: BadDevice:
US_DEBUGP("storage_probe() failed\n"); US_DEBUGP("storage_probe() failed\n");
usb_stor_deallocate_urbs(us); dissociate_dev(us);
up(&us->dev_semaphore); usb_stor_release_resources(us);
kfree(us); return result;
return -EIO;
} }
/* Handle a disconnect event from the USB core */ /* Handle a disconnect event from the USB core */
static void storage_disconnect(struct usb_interface *intf) static void storage_disconnect(struct usb_interface *intf)
{ {
struct us_data *us; struct us_data *us = usb_get_intfdata(intf);
struct scsi_device *sdev; struct scsi_device *sdev;
US_DEBUGP("storage_disconnect() called\n"); US_DEBUGP("storage_disconnect() called\n");
us = usb_get_intfdata(intf); /* Set devices offline -- need host lock for this */
usb_set_intfdata(intf, NULL);
/* set devices offline -- need host lock for this */
scsi_lock(us->host); scsi_lock(us->host);
list_for_each_entry(sdev, &us->host->my_devices, siblings) list_for_each_entry(sdev, &us->host->my_devices, siblings)
sdev->online = 0; sdev->online = 0;
scsi_unlock(us->host); scsi_unlock(us->host);
/* prevent new USB transfers and stop the current command */ /* Prevent new USB transfers and stop the current command */
set_bit(US_FLIDX_DISCONNECTING, &us->flags); set_bit(US_FLIDX_DISCONNECTING, &us->flags);
usb_stor_stop_transport(us); usb_stor_stop_transport(us);
/* lock device access -- no need to unlock, as we're going away */ /* Dissociate from the USB device */
down(&(us->dev_semaphore)); dissociate_dev(us);
/* TODO: somehow, wait for the device to /* Begin the SCSI host removal sequence */
* be 'idle' (tasklet completion) */ if (scsi_remove_host(us->host)) {
US_DEBUGP("-- SCSI refused to remove the host\n");
/* remove the pointer to the data structure we were using */
(struct us_data*)us->host->hostdata[0] = NULL;
/* begin SCSI host removal sequence */
if(scsi_remove_host(us->host)) {
US_DEBUGP("-- SCSI refused to unregister\n");
BUG(); BUG();
return; return;
};
/* finish SCSI host removal sequence */
scsi_unregister(us->host);
/* Kill the control threads
*
* Enqueue the command, wake up the thread, and wait for
* notification that it has exited.
*/
US_DEBUGP("-- sending exit command to thread\n");
BUG_ON(atomic_read(&us->sm_state) != US_STATE_IDLE);
us->srb = NULL;
up(&(us->sema));
wait_for_completion(&(us->notify));
/* free allocated urbs */
usb_stor_deallocate_urbs(us);
/* If there's extra data in the us_data structure then
* free that first */
if (us->extra) {
/* call the destructor routine, if it exists */
if (us->extra_destructor) {
US_DEBUGP("-- calling extra_destructor()\n");
us->extra_destructor(us->extra);
}
/* destroy the extra data */
US_DEBUGP("-- freeing the data structure\n");
kfree(us->extra);
} }
/* up the semaphore so auto-code-checkers won't complain about /* TODO: somehow, wait for the device to
* the down/up imbalance */ * be 'idle' (tasklet completion) */
up(&(us->dev_semaphore));
/* free the structure itself */ /* Release all our other resources */
kfree (us); usb_stor_release_resources(us);
} }
/*********************************************************************** /***********************************************************************
......
...@@ -107,6 +107,7 @@ struct us_data { ...@@ -107,6 +107,7 @@ struct us_data {
*/ */
struct semaphore dev_semaphore; /* protect pusb_dev */ struct semaphore dev_semaphore; /* protect pusb_dev */
struct usb_device *pusb_dev; /* this usb_device */ struct usb_device *pusb_dev; /* this usb_device */
struct usb_interface *pusb_intf; /* this interface */
unsigned long flags; /* from filter initially */ unsigned long flags; /* from filter initially */
unsigned int send_bulk_pipe; /* cached pipe values */ unsigned int send_bulk_pipe; /* cached pipe values */
unsigned int recv_bulk_pipe; unsigned int recv_bulk_pipe;
...@@ -114,7 +115,7 @@ struct us_data { ...@@ -114,7 +115,7 @@ struct us_data {
unsigned int recv_ctrl_pipe; unsigned int recv_ctrl_pipe;
unsigned int recv_intr_pipe; unsigned int recv_intr_pipe;
/* information about the device -- always good */ /* information about the device */
char vendor[USB_STOR_STRING_LEN]; char vendor[USB_STOR_STRING_LEN];
char product[USB_STOR_STRING_LEN]; char product[USB_STOR_STRING_LEN];
char serial[USB_STOR_STRING_LEN]; char serial[USB_STOR_STRING_LEN];
...@@ -124,11 +125,7 @@ struct us_data { ...@@ -124,11 +125,7 @@ struct us_data {
u8 protocol; u8 protocol;
u8 max_lun; u8 max_lun;
/* information about the device -- only good if device is attached */
u8 ifnum; /* interface number */ u8 ifnum; /* interface number */
u8 ep_in; /* bulk in endpoint */
u8 ep_out; /* bulk out endpoint */
u8 ep_int; /* interrupt endpoint */
u8 ep_bInterval; /* interrupt interval */ u8 ep_bInterval; /* interrupt interval */
/* function pointers for this device */ /* function pointers for this device */
......
...@@ -84,7 +84,7 @@ static int fill_read_buffer(struct file * file, struct sysfs_buffer * buffer) ...@@ -84,7 +84,7 @@ static int fill_read_buffer(struct file * file, struct sysfs_buffer * buffer)
ssize_t count; ssize_t count;
if (!buffer->page) if (!buffer->page)
buffer->page = (char *) __get_free_page(GFP_KERNEL); buffer->page = (char *) get_zeroed_page(GFP_KERNEL);
if (!buffer->page) if (!buffer->page)
return -ENOMEM; return -ENOMEM;
...@@ -174,7 +174,7 @@ fill_write_buffer(struct sysfs_buffer * buffer, const char * buf, size_t count) ...@@ -174,7 +174,7 @@ fill_write_buffer(struct sysfs_buffer * buffer, const char * buf, size_t count)
int error; int error;
if (!buffer->page) if (!buffer->page)
buffer->page = (char *)__get_free_page(GFP_KERNEL); buffer->page = (char *)get_zeroed_page(GFP_KERNEL);
if (!buffer->page) if (!buffer->page)
return -ENOMEM; return -ENOMEM;
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#ifndef _LINUX_CPU_H_ #ifndef _LINUX_CPU_H_
#define _LINUX_CPU_H_ #define _LINUX_CPU_H_
#include <linux/device.h> #include <linux/sysdev.h>
#include <linux/node.h> #include <linux/node.h>
#include <asm/semaphore.h> #include <asm/semaphore.h>
...@@ -29,8 +29,6 @@ struct cpu { ...@@ -29,8 +29,6 @@ struct cpu {
}; };
extern int register_cpu(struct cpu *, int, struct node *); extern int register_cpu(struct cpu *, int, struct node *);
extern struct class cpu_class;
struct notifier_block; struct notifier_block;
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
...@@ -48,6 +46,7 @@ static inline void unregister_cpu_notifier(struct notifier_block *nb) ...@@ -48,6 +46,7 @@ static inline void unregister_cpu_notifier(struct notifier_block *nb)
{ {
} }
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
extern struct sysdev_class cpu_sysdev_class;
/* Stop CPUs going up and down. */ /* Stop CPUs going up and down. */
extern struct semaphore cpucontrol; extern struct semaphore cpucontrol;
......
...@@ -205,10 +205,6 @@ struct freq_attr { ...@@ -205,10 +205,6 @@ struct freq_attr {
int cpufreq_set_policy(struct cpufreq_policy *policy); int cpufreq_set_policy(struct cpufreq_policy *policy);
int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu); int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu);
#ifdef CONFIG_PM
int cpufreq_restore(void);
#endif
/* the proc_intf.c needs this */ /* the proc_intf.c needs this */
int cpufreq_parse_governor (char *str_governor, unsigned int *policy, struct cpufreq_governor **governor); int cpufreq_parse_governor (char *str_governor, unsigned int *policy, struct cpufreq_governor **governor);
......
...@@ -351,30 +351,6 @@ extern int (*platform_notify_remove)(struct device * dev); ...@@ -351,30 +351,6 @@ extern int (*platform_notify_remove)(struct device * dev);
extern struct device * get_device(struct device * dev); extern struct device * get_device(struct device * dev);
extern void put_device(struct device * dev); extern void put_device(struct device * dev);
/* drivers/base/sys.c */
struct sys_root {
u32 id;
struct device dev;
struct device sysdev;
};
extern int sys_register_root(struct sys_root *);
extern void sys_unregister_root(struct sys_root *);
struct sys_device {
char * name;
u32 id;
struct sys_root * root;
struct device dev;
struct class_device class_dev;
};
extern int sys_device_register(struct sys_device *);
extern void sys_device_unregister(struct sys_device *);
extern struct bus_type system_bus_type;
/* drivers/base/platform.c */ /* drivers/base/platform.c */
......
...@@ -118,6 +118,14 @@ static inline struct kobj_type * get_ktype(struct kobject * k) ...@@ -118,6 +118,14 @@ static inline struct kobj_type * get_ktype(struct kobject * k)
extern struct kobject * kset_find_obj(struct kset *, const char *); extern struct kobject * kset_find_obj(struct kset *, const char *);
/**
* Use this when initializing an embedded kset with no other
* fields to initialize.
*/
#define set_kset_name(str) .kset = { .kobj = { .name = str } }
struct subsystem { struct subsystem {
struct kset kset; struct kset kset;
struct rw_semaphore rwsem; struct rw_semaphore rwsem;
......
...@@ -309,6 +309,20 @@ static inline void list_splice_init(struct list_head *list, ...@@ -309,6 +309,20 @@ static inline void list_splice_init(struct list_head *list,
pos = list_entry(pos->member.next, typeof(*pos), member), \ pos = list_entry(pos->member.next, typeof(*pos), member), \
prefetch(pos->member.next)) prefetch(pos->member.next))
/**
* list_for_each_entry_reverse - iterate backwards over list of given type.
* @pos: the type * to use as a loop counter.
* @head: the head for your list.
* @member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_reverse(pos, head, member) \
for (pos = list_entry((head)->prev, typeof(*pos), member), \
prefetch(pos->member.prev); \
&pos->member != (head); \
pos = list_entry(pos->member.prev, typeof(*pos), member), \
prefetch(pos->member.prev))
/** /**
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @pos: the type * to use as a loop counter. * @pos: the type * to use as a loop counter.
......
...@@ -19,11 +19,11 @@ ...@@ -19,11 +19,11 @@
#ifndef _LINUX_NODE_H_ #ifndef _LINUX_NODE_H_
#define _LINUX_NODE_H_ #define _LINUX_NODE_H_
#include <linux/device.h> #include <linux/sysdev.h>
struct node { struct node {
unsigned long cpumap; /* Bitmap of CPUs on the Node */ unsigned long cpumap; /* Bitmap of CPUs on the Node */
struct sys_root sysroot; struct sys_device sysdev;
}; };
extern int register_node(struct node *, int, struct node *); extern int register_node(struct node *, int, struct node *);
......
/**
* System devices follow a slightly different driver model.
* They don't need to do dynammic driver binding, can't be probed,
* and don't reside on any type of peripheral bus.
* So, we represent and treat them a little differently.
*
* We still have a notion of a driver for a system device, because we still
* want to perform basic operations on these devices.
*
* We also support auxillary drivers binding to devices of a certain class.
*
* This allows configurable drivers to register themselves for devices of
* a certain type. And, it allows class definitions to reside in generic
* code while arch-specific code can register specific drivers.
*
* Auxillary drivers registered with a NULL cls are registered as drivers
* for all system devices, and get notification calls for each device.
*/
#ifndef _SYSDEV_H_
#define _SYSDEV_H_
#include <linux/kobject.h>
struct sys_device;
struct sysdev_class {
struct list_head drivers;
/* Default operations for these types of devices */
int (*shutdown)(struct sys_device *);
int (*save)(struct sys_device *, u32 state);
int (*suspend)(struct sys_device *, u32 state);
int (*resume)(struct sys_device *);
int (*restore)(struct sys_device *);
struct kset kset;
};
extern int sysdev_class_register(struct sysdev_class *);
extern void sysdev_class_unregister(struct sysdev_class *);
/**
* Auxillary system device drivers.
*/
struct sysdev_driver {
struct list_head entry;
int (*add)(struct sys_device *);
int (*remove)(struct sys_device *);
int (*shutdown)(struct sys_device *);
int (*save)(struct sys_device *, u32 state);
int (*suspend)(struct sys_device *, u32 state);
int (*resume)(struct sys_device *);
int (*restore)(struct sys_device *);
};
extern int sysdev_driver_register(struct sysdev_class *, struct sysdev_driver *);
extern void sysdev_driver_unregister(struct sysdev_class *, struct sysdev_driver *);
/**
* sys_devices can be simplified a lot from regular devices, because they're
* simply not as versatile.
*/
struct sys_device {
u32 id;
struct sysdev_class * cls;
struct kobject kobj;
};
extern int sys_device_register(struct sys_device *);
extern void sys_device_unregister(struct sys_device *);
struct sysdev_attribute {
struct attribute attr;
ssize_t (*show)(struct sys_device *, char *);
ssize_t (*store)(struct sys_device *, const char *, size_t);
};
#define SYSDEV_ATTR(_name,_mode,_show,_store) \
struct sysdev_attribute attr_##_name = { \
.attr = {.name = __stringify(_name), .mode = _mode }, \
.show = _show, \
.store = _store, \
};
extern int sysdev_create_file(struct sys_device *, struct sysdev_attribute *);
extern void sysdev_remove_file(struct sys_device *, struct sysdev_attribute *);
#endif /* _SYSDEV_H_ */
...@@ -136,7 +136,7 @@ static inline void *usb_get_intfdata (struct usb_interface *intf) ...@@ -136,7 +136,7 @@ static inline void *usb_get_intfdata (struct usb_interface *intf)
static inline void usb_set_intfdata (struct usb_interface *intf, void *data) static inline void usb_set_intfdata (struct usb_interface *intf, void *data)
{ {
return dev_set_drvdata (&intf->dev, data); dev_set_drvdata(&intf->dev, data);
} }
/* USB_DT_CONFIG: Configuration descriptor information. /* USB_DT_CONFIG: Configuration descriptor information.
......
...@@ -46,14 +46,14 @@ struct usbdevfs_ctrltransfer { ...@@ -46,14 +46,14 @@ struct usbdevfs_ctrltransfer {
__u16 wIndex; __u16 wIndex;
__u16 wLength; __u16 wLength;
__u32 timeout; /* in milliseconds */ __u32 timeout; /* in milliseconds */
void *data; void __user *data;
}; };
struct usbdevfs_bulktransfer { struct usbdevfs_bulktransfer {
unsigned int ep; unsigned int ep;
unsigned int len; unsigned int len;
unsigned int timeout; /* in milliseconds */ unsigned int timeout; /* in milliseconds */
void *data; void __user *data;
}; };
struct usbdevfs_setinterface { struct usbdevfs_setinterface {
...@@ -97,7 +97,7 @@ struct usbdevfs_urb { ...@@ -97,7 +97,7 @@ struct usbdevfs_urb {
unsigned char endpoint; unsigned char endpoint;
int status; int status;
unsigned int flags; unsigned int flags;
void *buffer; void __user *buffer;
int buffer_length; int buffer_length;
int actual_length; int actual_length;
int start_frame; int start_frame;
...@@ -113,7 +113,7 @@ struct usbdevfs_ioctl { ...@@ -113,7 +113,7 @@ struct usbdevfs_ioctl {
int ifno; /* interface 0..N ; negative numbers reserved */ int ifno; /* interface 0..N ; negative numbers reserved */
int ioctl_code; /* MUST encode size + direction of data so the int ioctl_code; /* MUST encode size + direction of data so the
* macros in <asm/ioctl.h> give correct values */ * macros in <asm/ioctl.h> give correct values */
void *data; /* param buffer (in, or out) */ void __user *data; /* param buffer (in, or out) */
}; };
/* You can do most things with hubs just through control messages, /* You can do most things with hubs just through control messages,
......
...@@ -49,8 +49,6 @@ static DECLARE_RWSEM (cpufreq_notifier_rwsem); ...@@ -49,8 +49,6 @@ static DECLARE_RWSEM (cpufreq_notifier_rwsem);
static LIST_HEAD(cpufreq_governor_list); static LIST_HEAD(cpufreq_governor_list);
static DECLARE_MUTEX (cpufreq_governor_sem); static DECLARE_MUTEX (cpufreq_governor_sem);
static struct class_interface cpufreq_interface;
static int cpufreq_cpu_get(unsigned int cpu) static int cpufreq_cpu_get(unsigned int cpu)
{ {
if (cpu >= NR_CPUS) if (cpu >= NR_CPUS)
...@@ -113,24 +111,8 @@ int cpufreq_parse_governor (char *str_governor, unsigned int *policy, ...@@ -113,24 +111,8 @@ int cpufreq_parse_governor (char *str_governor, unsigned int *policy,
EXPORT_SYMBOL_GPL(cpufreq_parse_governor); EXPORT_SYMBOL_GPL(cpufreq_parse_governor);
/* forward declarations */
static int cpufreq_add_dev (struct class_device * dev);
static void cpufreq_remove_dev (struct class_device * dev);
/* drivers/base/cpu.c */ /* drivers/base/cpu.c */
extern struct device_class cpu_devclass; extern struct sysdev_class cpu_sysdev_class;
static struct class_interface cpufreq_interface = {
.class = &cpu_class,
.add = &cpufreq_add_dev,
.remove = &cpufreq_remove_dev,
};
static inline int to_cpu_nr (struct class_device *dev)
{
struct sys_device * cpu_sys_dev = container_of(dev->dev, struct sys_device, dev);
return (cpu_sys_dev->id);
}
/** /**
...@@ -331,9 +313,9 @@ static struct kobj_type ktype_cpufreq = { ...@@ -331,9 +313,9 @@ static struct kobj_type ktype_cpufreq = {
* *
* Adds the cpufreq interface for a CPU device. * Adds the cpufreq interface for a CPU device.
*/ */
static int cpufreq_add_dev (struct class_device * class_dev) static int cpufreq_add_dev (struct sys_device * sys_dev)
{ {
unsigned int cpu = to_cpu_nr(class_dev); unsigned int cpu = sys_dev->id;
int ret = 0; int ret = 0;
struct cpufreq_policy new_policy; struct cpufreq_policy new_policy;
struct cpufreq_policy *policy; struct cpufreq_policy *policy;
...@@ -358,14 +340,12 @@ static int cpufreq_add_dev (struct class_device * class_dev) ...@@ -358,14 +340,12 @@ static int cpufreq_add_dev (struct class_device * class_dev)
memcpy(&new_policy, memcpy(&new_policy,
policy, policy,
sizeof(struct cpufreq_policy)); sizeof(struct cpufreq_policy));
class_set_devdata(class_dev, policy);
up(&cpufreq_driver_sem); up(&cpufreq_driver_sem);
init_MUTEX(&policy->lock); init_MUTEX(&policy->lock);
/* prepare interface data */ /* prepare interface data */
policy->kobj.parent = &class_dev->kobj; policy->kobj.parent = &sys_dev->kobj;
policy->kobj.ktype = &ktype_cpufreq; policy->kobj.ktype = &ktype_cpufreq;
// policy->dev = dev->dev;
strlcpy(policy->kobj.name, "cpufreq", KOBJ_NAME_LEN); strlcpy(policy->kobj.name, "cpufreq", KOBJ_NAME_LEN);
ret = kobject_register(&policy->kobj); ret = kobject_register(&policy->kobj);
...@@ -396,12 +376,12 @@ static int cpufreq_add_dev (struct class_device * class_dev) ...@@ -396,12 +376,12 @@ static int cpufreq_add_dev (struct class_device * class_dev)
* *
* Removes the cpufreq interface for a CPU device. * Removes the cpufreq interface for a CPU device.
*/ */
static void cpufreq_remove_dev (struct class_device * class_dev) static int cpufreq_remove_dev (struct sys_device * sys_dev)
{ {
unsigned int cpu = to_cpu_nr(class_dev); unsigned int cpu = sys_dev->id;
if (!kobject_get(&cpufreq_driver->policy[cpu].kobj)) if (!kobject_get(&cpufreq_driver->policy[cpu].kobj))
return; return -EFAULT;
down(&cpufreq_driver_sem); down(&cpufreq_driver_sem);
if ((cpufreq_driver->target) && if ((cpufreq_driver->target) &&
...@@ -421,9 +401,17 @@ static void cpufreq_remove_dev (struct class_device * class_dev) ...@@ -421,9 +401,17 @@ static void cpufreq_remove_dev (struct class_device * class_dev)
up(&cpufreq_driver_sem); up(&cpufreq_driver_sem);
kobject_put(&cpufreq_driver->policy[cpu].kobj); kobject_put(&cpufreq_driver->policy[cpu].kobj);
return; return 0;
} }
static int cpufreq_restore(struct sys_device *);
static struct sysdev_driver cpufreq_sysdev_driver = {
.add = cpufreq_add_dev,
.remove = cpufreq_remove_dev,
.restore = cpufreq_restore,
};
/********************************************************************* /*********************************************************************
* NOTIFIER LISTS INTERFACE * * NOTIFIER LISTS INTERFACE *
...@@ -843,7 +831,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) ...@@ -843,7 +831,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
memset(cpufreq_driver->policy, 0, NR_CPUS * sizeof(struct cpufreq_policy)); memset(cpufreq_driver->policy, 0, NR_CPUS * sizeof(struct cpufreq_policy));
return class_interface_register(&cpufreq_interface); return sysdev_driver_register(&cpu_sysdev_class,&cpufreq_sysdev_driver);
} }
EXPORT_SYMBOL_GPL(cpufreq_register_driver); EXPORT_SYMBOL_GPL(cpufreq_register_driver);
...@@ -861,7 +849,7 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver) ...@@ -861,7 +849,7 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
if (!cpufreq_driver || (driver != cpufreq_driver)) if (!cpufreq_driver || (driver != cpufreq_driver))
return -EINVAL; return -EINVAL;
class_interface_unregister(&cpufreq_interface); sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver);
down(&cpufreq_driver_sem); down(&cpufreq_driver_sem);
kfree(cpufreq_driver->policy); kfree(cpufreq_driver->policy);
...@@ -874,41 +862,34 @@ EXPORT_SYMBOL_GPL(cpufreq_unregister_driver); ...@@ -874,41 +862,34 @@ EXPORT_SYMBOL_GPL(cpufreq_unregister_driver);
#ifdef CONFIG_PM #ifdef CONFIG_PM
/** /**
* cpufreq_restore - restore the CPU clock frequency after resume * cpufreq_restore - restore the CPU clock frequency after resume
* *
* Restore the CPU clock frequency so that our idea of the current * Restore the CPU clock frequency so that our idea of the current
* frequency reflects the actual hardware. * frequency reflects the actual hardware.
*/ */
int cpufreq_restore(void) static int cpufreq_restore(struct sys_device * sysdev)
{ {
struct cpufreq_policy policy; int cpu = sysdev->id;
unsigned int i;
unsigned int ret = 0; unsigned int ret = 0;
struct cpufreq_policy policy;
if (in_interrupt()) if (cpu_online(cpu) && cpufreq_cpu_get(cpu)) {
panic("cpufreq_restore() called from interrupt context!");
if (!try_module_get(cpufreq_driver->owner))
goto error_out;
for (i=0;i<NR_CPUS;i++) {
if (!cpu_online(i) || !cpufreq_cpu_get(i))
continue;
down(&cpufreq_driver_sem); down(&cpufreq_driver_sem);
memcpy(&policy, &cpufreq_driver->policy[i], sizeof(struct cpufreq_policy)); memcpy(&policy, &cpufreq_driver->policy[cpu],
sizeof(struct cpufreq_policy));
up(&cpufreq_driver_sem); up(&cpufreq_driver_sem);
ret += cpufreq_set_policy(&policy); ret = cpufreq_set_policy(&policy);
cpufreq_cpu_put(cpu);
cpufreq_cpu_put(i);
} }
module_put(cpufreq_driver->owner);
error_out:
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(cpufreq_restore);
#else #else
#define cpufreq_restore() do {} while (0) static int cpufreq_restore(struct sys_device * sysdev)
{
return 0;
}
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
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