diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-07-15 03:32:22 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-07-15 03:32:22 +0000 |
commit | f1da2c3860e301527d56a1ef0b56c649ee7c4b1b (patch) | |
tree | 562b5d2e8b9cb62eb983d78ff6bcf9789e08fcf6 /drivers | |
parent | 00f11569ac8ca73cbcdef8822de1583e79aee571 (diff) |
Merge with Linux 2.4.0-test5-pre1. This works again on Origin UP.
The IP22 cache bugs which are plaguing some machines are still unfixed.
Diffstat (limited to 'drivers')
155 files changed, 4697 insertions, 2930 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index c8b888ff1..2c9606663 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -11,7 +11,7 @@ O_TARGET := acpi.o O_OBJS := M_OBJS := -ACPI_OBJS := osd.o +ACPI_OBJS := driver.o ec.o cpu.o os.o sys.o tables.o ACPI_OBJS += $(patsubst %.c,%.o,$(wildcard */*.c)) EXTRA_CFLAGS += -I./include -D_LINUX diff --git a/drivers/acpi/cpu.c b/drivers/acpi/cpu.c new file mode 100644 index 000000000..f1feeb12b --- /dev/null +++ b/drivers/acpi/cpu.c @@ -0,0 +1,307 @@ +/* + * cpu.c - Processor handling + * + * Copyright (C) 2000 Andrew Henroid + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/pm.h> +#include <linux/acpi.h> +#include "acpi.h" +#include "driver.h" + +unsigned long acpi_c2_exit_latency = ACPI_INFINITE; +unsigned long acpi_c3_exit_latency = ACPI_INFINITE; +unsigned long acpi_c2_enter_latency = ACPI_INFINITE; +unsigned long acpi_c3_enter_latency = ACPI_INFINITE; + +static unsigned long acpi_pblk = ACPI_INVALID; +static int acpi_c2_tested = 0; +static int acpi_c3_tested = 0; + +/* + * Clear busmaster activity flag + */ +static inline void +acpi_clear_bm_activity(struct acpi_facp *facp) +{ + acpi_write_pm1_status(facp, ACPI_BM); +} + +/* + * Returns 1 if there has been busmaster activity + */ +static inline int +acpi_bm_activity(struct acpi_facp *facp) +{ + return acpi_read_pm1_status(facp) & ACPI_BM; +} + +/* + * Set system to sleep through busmaster requests + */ +static void +acpi_sleep_on_busmaster(struct acpi_facp *facp) +{ + u32 pm1_cntr = acpi_read_pm1_control(facp); + if (pm1_cntr & ACPI_BM_RLD) { + pm1_cntr &= ~ACPI_BM_RLD; + acpi_write_pm1_control(facp, pm1_cntr); + } +} + +/* + * Set system to wake on busmaster requests + */ +static void +acpi_wake_on_busmaster(struct acpi_facp *facp) +{ + u32 pm1_cntr = acpi_read_pm1_control(facp); + if (!(pm1_cntr & ACPI_BM_RLD)) { + pm1_cntr |= ACPI_BM_RLD; + acpi_write_pm1_control(facp, pm1_cntr); + } + acpi_clear_bm_activity(facp); +} + +/* The ACPI timer is just the low 24 bits */ +#define TIME_BEGIN(tmr) inl(tmr) +#define TIME_END(tmr, begin) ((inl(tmr) - (begin)) & 0x00ffffff) + +/* + * Idle loop (uniprocessor only) + */ +static void +acpi_idle(void) +{ + static int sleep_level = 1; + struct acpi_facp *facp = &acpi_facp; + + if (!facp + || facp->hdr.signature != ACPI_FACP_SIG + || !facp->pm_tmr + || !acpi_pblk) + goto not_initialized; + + /* + * start from the previous sleep level.. + */ + if (sleep_level == 1) + goto sleep1; + if (sleep_level == 2) + goto sleep2; + sleep3: + sleep_level = 3; + if (!acpi_c3_tested) { + printk(KERN_DEBUG "ACPI C3 works\n"); + acpi_c3_tested = 1; + } + acpi_wake_on_busmaster(facp); + if (facp->pm2_cnt) + goto sleep3_with_arbiter; + + for (;;) { + unsigned long time; + unsigned int pm_tmr = facp->pm_tmr; + + __cli(); + if (current->need_resched) + goto out; + if (acpi_bm_activity(facp)) + goto sleep2; + + time = TIME_BEGIN(pm_tmr); + inb(acpi_pblk + ACPI_P_LVL3); + /* Dummy read, force synchronization with the PMU */ + inl(pm_tmr); + time = TIME_END(pm_tmr, time); + + __sti(); + if (time < acpi_c3_exit_latency) + goto sleep2; + } + + sleep3_with_arbiter: + for (;;) { + unsigned long time; + u8 arbiter; + unsigned int pm2_cntr = facp->pm2_cnt; + unsigned int pm_tmr = facp->pm_tmr; + + __cli(); + if (current->need_resched) + goto out; + if (acpi_bm_activity(facp)) + goto sleep2; + + time = TIME_BEGIN(pm_tmr); + arbiter = inb(pm2_cntr) & ~ACPI_ARB_DIS; + /* Disable arbiter, park on CPU */ + outb(arbiter | ACPI_ARB_DIS, pm2_cntr); + inb(acpi_pblk + ACPI_P_LVL3); + /* Dummy read, force synchronization with the PMU */ + inl(pm_tmr); + time = TIME_END(pm_tmr, time); + /* Enable arbiter again.. */ + outb(arbiter, pm2_cntr); + + __sti(); + if (time < acpi_c3_exit_latency) + goto sleep2; + } + + sleep2: + sleep_level = 2; + if (!acpi_c2_tested) { + printk(KERN_DEBUG "ACPI C2 works\n"); + acpi_c2_tested = 1; + } + acpi_wake_on_busmaster(facp); /* Required to track BM activity.. */ + for (;;) { + unsigned long time; + unsigned int pm_tmr = facp->pm_tmr; + + __cli(); + if (current->need_resched) + goto out; + + time = TIME_BEGIN(pm_tmr); + inb(acpi_pblk + ACPI_P_LVL2); + /* Dummy read, force synchronization with the PMU */ + inl(pm_tmr); + time = TIME_END(pm_tmr, time); + + __sti(); + if (time < acpi_c2_exit_latency) + goto sleep1; + if (acpi_bm_activity(facp)) { + acpi_clear_bm_activity(facp); + continue; + } + if (time > acpi_c3_enter_latency) + goto sleep3; + } + + sleep1: + sleep_level = 1; + acpi_sleep_on_busmaster(facp); + for (;;) { + unsigned long time; + unsigned int pm_tmr = facp->pm_tmr; + + __cli(); + if (current->need_resched) + goto out; + time = TIME_BEGIN(pm_tmr); + safe_halt(); + time = TIME_END(pm_tmr, time); + if (time > acpi_c2_enter_latency) + goto sleep2; + } + + not_initialized: + for (;;) { + __cli(); + if (current->need_resched) + goto out; + safe_halt(); + } + + out: + __sti(); +} + +/* + * Get processor information + */ +static ACPI_STATUS +acpi_find_cpu(ACPI_HANDLE handle, u32 level, void *ctx, void **value) +{ + ACPI_OBJECT obj; + ACPI_CX_STATE lat[4]; + ACPI_CPU_THROTTLING_STATE throttle[ACPI_MAX_THROTTLE]; + ACPI_BUFFER buf; + int i, count; + + buf.length = sizeof(obj); + buf.pointer = &obj; + if (!ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buf))) + return AE_OK; + + printk(KERN_INFO "ACPI: PBLK %d @ 0x%04x:%d\n", + obj.processor.proc_id, + obj.processor.pblk_address, + obj.processor.pblk_length); + if (acpi_pblk != ACPI_INVALID + || !obj.processor.pblk_address + || obj.processor.pblk_length != 6) + return AE_OK; + + acpi_pblk = obj.processor.pblk_address; + + buf.length = sizeof(lat); + buf.pointer = lat; + if (!ACPI_SUCCESS(acpi_get_processor_cx_info(handle, &buf))) + return AE_OK; + + if (lat[2].latency < MAX_CX_STATE_LATENCY) { + printk(KERN_INFO "ACPI: C2 supported\n"); + acpi_c2_exit_latency = lat[2].latency; + } + if (lat[3].latency < MAX_CX_STATE_LATENCY) { + printk(KERN_INFO "ACPI: C3 supported\n"); + acpi_c3_exit_latency = lat[3].latency; + } + + memset(throttle, 0, sizeof(throttle)); + buf.length = sizeof(throttle); + buf.pointer = throttle; + + if (!ACPI_SUCCESS(acpi_get_processor_throttling_info(handle, &buf))) + return AE_OK; + + for (i = 0, count = 0; i < ACPI_MAX_THROTTLE; i++) { + if (throttle[i].percent_of_clock) + count++; + } + count--; + if (count > 0) + printk(KERN_INFO "ACPI: %d throttling states\n", count); + + return AE_OK; +} + +int +acpi_cpu_init(void) +{ + acpi_walk_namespace(ACPI_TYPE_PROCESSOR, + ACPI_ROOT_OBJECT, + ACPI_INT32_MAX, + acpi_find_cpu, + NULL, + NULL); + +#ifdef CONFIG_SMP + if (smp_num_cpus == 1) + pm_idle = acpi_idle; +#else + pm_idle = acpi_idle; +#endif + + return 0; +} diff --git a/drivers/acpi/driver.c b/drivers/acpi/driver.c new file mode 100644 index 000000000..0c668f59b --- /dev/null +++ b/drivers/acpi/driver.c @@ -0,0 +1,388 @@ +/* + * driver.c - ACPI driver + * + * Copyright (C) 2000 Andrew Henroid + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/proc_fs.h> +#include <linux/sysctl.h> +#include <linux/pm.h> +#include <linux/acpi.h> +#include <asm/uaccess.h> +#include "acpi.h" +#include "driver.h" + +struct acpi_run_entry +{ + void (*callback)(void*); + void *context; + struct tq_struct task; +}; + +static spinlock_t acpi_event_lock = SPIN_LOCK_UNLOCKED; +static volatile u32 acpi_event_status = 0; +static volatile acpi_sstate_t acpi_event_state = ACPI_S0; +static DECLARE_WAIT_QUEUE_HEAD(acpi_event_wait); + +static volatile int acpi_thread_pid = -1; +static DECLARE_TASK_QUEUE(acpi_thread_run); +static DECLARE_WAIT_QUEUE_HEAD(acpi_thread_wait); + +static struct ctl_table_header *acpi_sysctl = NULL; + +/* + * Examine/modify value + */ +static int +acpi_do_ulong(ctl_table * ctl, + int write, + struct file *file, + void *buffer, + size_t * len) +{ + char str[2 * sizeof(unsigned long) + 4], *strend; + unsigned long val; + int size; + + if (!write) { + if (file->f_pos) { + *len = 0; + return 0; + } + + val = *(unsigned long *) ctl->data; + size = sprintf(str, "0x%08lx\n", val); + if (*len >= size) { + copy_to_user(buffer, str, size); + *len = size; + } + else + *len = 0; + } + else { + size = sizeof(str) - 1; + if (size > *len) + size = *len; + copy_from_user(str, buffer, size); + str[size] = '\0'; + val = simple_strtoul(str, &strend, 0); + if (strend == str) + return -EINVAL; + *(unsigned long *) ctl->data = val; + } + + file->f_pos += *len; + return 0; +} + +/* + * Handle ACPI event + */ +static u32 +acpi_event(void *context) +{ + unsigned long flags; + int event = (int) context; + int mask = 0; + + switch (event) { + case ACPI_EVENT_POWER_BUTTON: mask = ACPI_PWRBTN; break; + case ACPI_EVENT_SLEEP_BUTTON: mask = ACPI_SLPBTN; break; + default: return AE_ERROR; + } + + if (mask) { + // notify process waiting on /dev/acpi + spin_lock_irqsave(&acpi_event_lock, flags); + acpi_event_status |= mask; + spin_unlock_irqrestore(&acpi_event_lock, flags); + acpi_event_state = acpi_sleep_state; + wake_up_interruptible(&acpi_event_wait); + } + + return AE_OK; +} + +/* + * Wait for next event + */ +static int +acpi_do_event(ctl_table * ctl, + int write, + struct file *file, + void *buffer, + size_t * len) +{ + u32 event_status = 0; + acpi_sstate_t event_state = 0; + char str[27]; + int size; + + if (write) + return -EPERM; + if (*len < sizeof(str)) { + *len = 0; + return 0; + } + + for (;;) { + unsigned long flags; + + // we need an atomic exchange here + spin_lock_irqsave(&acpi_event_lock, flags); + event_status = acpi_event_status; + acpi_event_status = 0; + spin_unlock_irqrestore(&acpi_event_lock, flags); + event_state = acpi_event_state; + + if (event_status) + break; + + // wait for an event to arrive + interruptible_sleep_on(&acpi_event_wait); + if (signal_pending(current)) + return -ERESTARTSYS; + } + + size = sprintf(str, + "0x%08x 0x%08x 0x%01x\n", + event_status, + 0, + event_state); + copy_to_user(buffer, str, size); + *len = size; + file->f_pos += size; + + return 0; +} + +/* + * Enter system sleep state + */ +static int +acpi_do_sleep(ctl_table * ctl, + int write, + struct file *file, + void *buffer, + size_t * len) +{ + if (!write) { + if (file->f_pos) { + *len = 0; + return 0; + } + } + else { +#ifdef CONFIG_ACPI_S1_SLEEP + int status = acpi_enter_sx(ACPI_S1); + if (status) + return status; +#endif + } + file->f_pos += *len; + return 0; +} + +/* + * Run queued callback + */ +static void +acpi_run_exec(void *context) +{ + struct acpi_run_entry *entry + = (struct acpi_run_entry*) context; + (*entry->callback)(entry->context); + kfree(entry); +} + +/* + * Queue for execution by the ACPI thread + */ +int +acpi_run(void (*callback)(void*), void *context) +{ + struct acpi_run_entry *entry; + + entry = kmalloc(sizeof(*entry), GFP_ATOMIC); + if (!entry) + return -1; + + memset(entry, 0, sizeof(entry)); + entry->callback = callback; + entry->context = context; + entry->task.routine = acpi_run_exec; + entry->task.data = entry; + + queue_task(&entry->task, &acpi_thread_run); + + if (waitqueue_active(&acpi_thread_wait)) + wake_up(&acpi_thread_wait); + + return 0; +} + +static struct ctl_table acpi_table[] = +{ + {ACPI_P_LVL2_LAT, "c2_exit_latency", + &acpi_c2_exit_latency, sizeof(acpi_c2_exit_latency), + 0644, NULL, &acpi_do_ulong}, + + {ACPI_ENTER_LVL2_LAT, "c2_enter_latency", + &acpi_c2_enter_latency, sizeof(acpi_c2_enter_latency), + 0644, NULL, &acpi_do_ulong}, + + {ACPI_P_LVL3_LAT, "c3_exit_latency", + &acpi_c3_exit_latency, sizeof(acpi_c3_exit_latency), + 0644, NULL, &acpi_do_ulong}, + + {ACPI_ENTER_LVL3_LAT, "c3_enter_latency", + &acpi_c3_enter_latency, sizeof(acpi_c3_enter_latency), + 0644, NULL, &acpi_do_ulong}, + + {ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &acpi_do_sleep}, + + {ACPI_EVENT, "event", NULL, 0, 0400, NULL, &acpi_do_event}, + + {0} +}; + +static struct ctl_table acpi_dir_table[] = +{ + {CTL_ACPI, "acpi", NULL, 0, 0555, acpi_table}, + {0} +}; + +/* + * Initialize and run interpreter within a kernel thread + */ +static int +acpi_thread(void *context) +{ + /* + * initialize + */ + exit_files(current); + daemonize(); + strcpy(current->comm, "acpi"); + + if (!ACPI_SUCCESS(acpi_initialize(NULL))) { + printk(KERN_ERR "ACPI: initialize failed\n"); + return -ENODEV; + } + + if (acpi_load_tables()) + return -ENODEV; + + if (PM_IS_ACTIVE()) { + printk(KERN_NOTICE "ACPI: APM is already active.\n"); + acpi_terminate(); + return -ENODEV; + } + + pm_active = 1; + + if (!ACPI_SUCCESS(acpi_enable())) { + printk(KERN_ERR "ACPI: enable failed\n"); + acpi_terminate(); + return -ENODEV; + } + + acpi_cpu_init(); + acpi_sys_init(); + acpi_ec_init(); + + if (!ACPI_SUCCESS(acpi_install_fixed_event_handler( + ACPI_EVENT_POWER_BUTTON, + acpi_event, + (void *) ACPI_EVENT_POWER_BUTTON))) { + printk(KERN_ERR "ACPI: power button enable failed\n"); + } + if (!ACPI_SUCCESS(acpi_install_fixed_event_handler( + ACPI_EVENT_SLEEP_BUTTON, + acpi_event, + (void *) ACPI_EVENT_SLEEP_BUTTON))) { + printk(KERN_ERR "ACPI: sleep button enable failed\n"); + } + + acpi_sysctl = register_sysctl_table(acpi_dir_table, 1); + + /* + * run + */ + for (;;) { + interruptible_sleep_on(&acpi_thread_wait); + if (signal_pending(current)) + break; + do { + run_task_queue(&acpi_thread_run); + } while (acpi_thread_run); + } + + /* + * terminate + */ + unregister_sysctl_table(acpi_sysctl); + acpi_terminate(); + + acpi_thread_pid = -1; + + return 0; +} + +/* + * Start the interpreter + */ +int __init +acpi_init(void) +{ + acpi_thread_pid = kernel_thread(acpi_thread, + NULL, + (CLONE_FS | CLONE_FILES + | CLONE_SIGHAND | SIGCHLD)); + return ((acpi_thread_pid >= 0) ? 0:-ENODEV); +} + +/* + * Terminate the interpreter + */ +void __exit +acpi_exit(void) +{ + int count; + + if (!kill_proc(acpi_thread_pid, SIGTERM, 1)) { + // wait until thread terminates (at most 5 seconds) + count = 5 * HZ; + while (acpi_thread_pid >= 0 && --count) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } + } + + pm_idle = NULL; + pm_power_off = NULL; + pm_active = 0; +} + +module_init(acpi_init); +module_exit(acpi_exit); diff --git a/drivers/acpi/driver.h b/drivers/acpi/driver.h new file mode 100644 index 000000000..a26402b40 --- /dev/null +++ b/drivers/acpi/driver.h @@ -0,0 +1,115 @@ +/* + * driver.h - ACPI driver + * + * Copyright (C) 2000 Andrew Henroid + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __DRIVER_H +#define __DRIVER_H + +#include <linux/tqueue.h> +#include <linux/wait.h> +#include <linux/pm.h> +#include <linux/acpi.h> +#include <asm/io.h> + +#define ACPI_MAX_THROTTLE 10 +#define ACPI_INVALID ~0UL +#define ACPI_INFINITE ~0UL + +/* + * cpu.c + */ +int acpi_cpu_init(void); + +extern unsigned long acpi_c2_exit_latency; +extern unsigned long acpi_c3_exit_latency; +extern unsigned long acpi_c2_enter_latency; +extern unsigned long acpi_c3_enter_latency; + +/* + * driver.c + */ +int acpi_run(void (*callback)(void*), void *context); + +/* + * ec.c + */ +int acpi_ec_init(void); +int acpi_ec_read(int addr, int *value); +int acpi_ec_write(int addr, int value); + +/* + * sys.c + */ +int acpi_sys_init(void); +int acpi_enter_sx(acpi_sstate_t state); + +extern volatile acpi_sstate_t acpi_sleep_state; + +/* + * tables.c + */ +extern struct acpi_facp acpi_facp; + +int acpi_load_tables(void); + +/* + * access ACPI registers + */ + +extern inline u32 +acpi_read_pm1_control(struct acpi_facp *facp) +{ + u32 value = 0; + if (facp->pm1a_cnt) + value = inw(facp->pm1a_cnt); + if (facp->pm1b_cnt) + value |= inw(facp->pm1b_cnt); + return value; +} + +extern inline void +acpi_write_pm1_control(struct acpi_facp *facp, u32 value) +{ + if (facp->pm1a_cnt) + outw(value, facp->pm1a_cnt); + if (facp->pm1b_cnt) + outw(value, facp->pm1b_cnt); +} + +extern inline u32 +acpi_read_pm1_status(struct acpi_facp *facp) +{ + u32 value = 0; + if (facp->pm1a_evt) + value = inw(facp->pm1a_evt); + if (facp->pm1b_evt) + value |= inw(facp->pm1b_evt); + return value; +} + +extern inline void +acpi_write_pm1_status(struct acpi_facp *facp, u32 value) +{ + if (facp->pm1a_evt) + outw(value, facp->pm1a_evt); + if (facp->pm1b_evt) + outw(value, facp->pm1b_evt); +} + +#endif /* __DRIVER_H */ diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c new file mode 100644 index 000000000..3e5fe753f --- /dev/null +++ b/drivers/acpi/ec.c @@ -0,0 +1,191 @@ +/* + * ec.c - Embedded controller support + * + * Copyright (C) 2000 Andrew Henroid + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/pm.h> +#include <linux/acpi.h> +#include <linux/delay.h> +#include <asm/io.h> +#include "acpi.h" +#include "driver.h" + +enum +{ + ACPI_EC_HID = 0x090cd041, +}; + +enum +{ + ACPI_EC_SMI = 0x40, + ACPI_EC_SCI = 0x20, + ACPI_EC_BURST = 0x10, + ACPI_EC_CMD = 0x08, + ACPI_EC_IBF = 0x02, + ACPI_EC_OBF = 0x01 +}; + +enum +{ + ACPI_EC_READ = 0x80, + ACPI_EC_WRITE = 0x81, + ACPI_EC_BURST_ENABLE = 0x82, + ACPI_EC_BURST_DISABLE = 0x83, + ACPI_EC_QUERY = 0x84, +}; + + +static int acpi_ec_data = 0; +static int acpi_ec_status = 0; +static DECLARE_WAIT_QUEUE_HEAD(acpi_ec_wait); + +/* + * handle GPE + */ +static void +acpi_ec_gpe(void *context) +{ + printk(KERN_INFO "ACPI: EC GPE\n"); + if (waitqueue_active(&acpi_ec_wait)) + wake_up_interruptible(&acpi_ec_wait); +} + +/* + * wait for read/write status to clear + */ +static void +acpi_ec_wait_control(void) +{ + udelay(1); + while(inb(acpi_ec_status) & ACPI_EC_IBF) + udelay(10); +} + +/* + * read a byte from the EC + */ +int +acpi_ec_read(int addr, int *value) +{ + if (!acpi_ec_data || !acpi_ec_status) + return -1; + + outb(ACPI_EC_READ, acpi_ec_status); + acpi_ec_wait_control(); + outb(addr, acpi_ec_data); + acpi_ec_wait_control(); + interruptible_sleep_on(&acpi_ec_wait); + *value = inb(acpi_ec_data); + + return 0; +} + +/* + * write a byte to the EC + */ +int +acpi_ec_write(int addr, int value) +{ + if (!acpi_ec_data || !acpi_ec_status) + return -1; + + outb(ACPI_EC_WRITE, acpi_ec_status); + acpi_ec_wait_control(); + outb(addr, acpi_ec_data); + acpi_ec_wait_control(); + outb(value, acpi_ec_data); + acpi_ec_wait_control(); + interruptible_sleep_on(&acpi_ec_wait); + + return 0; +} + +/* + * Get processor information + */ +static ACPI_STATUS +acpi_find_ec(ACPI_HANDLE handle, u32 level, void *ctx, void **value) +{ + ACPI_BUFFER buf; + ACPI_OBJECT obj; + RESOURCE *res; + int gpe; + + buf.length = sizeof(obj); + buf.pointer = &obj; + if (!ACPI_SUCCESS(acpi_evaluate_object(handle, "_HID", NULL, &buf)) + || obj.type != ACPI_TYPE_NUMBER + || obj.number.value != ACPI_EC_HID) + return AE_OK; + + buf.length = 0; + buf.pointer = NULL; + if (acpi_get_current_resources(handle, &buf) != AE_BUFFER_OVERFLOW) + return AE_OK; + + buf.pointer = kmalloc(buf.length, GFP_KERNEL); + if (!buf.pointer) + return AE_OK; + + if (!ACPI_SUCCESS(acpi_get_current_resources(handle, &buf))) { + kfree(buf.pointer); + return AE_OK; + } + + res = (RESOURCE*) buf.pointer; + acpi_ec_data = (int) res->data.io.min_base_address; + res = (RESOURCE*)((u8*) buf.pointer + res->length); + acpi_ec_status = (int) res->data.io.min_base_address; + + kfree(buf.pointer); + + buf.length = sizeof(obj); + buf.pointer = &obj; + if (!ACPI_SUCCESS(acpi_evaluate_object(handle, "_GPE", NULL, &buf)) + || obj.type != ACPI_TYPE_NUMBER) + return AE_OK; + gpe = (int) obj.number.value; + + printk(KERN_INFO "ACPI: found EC @ (0x%02x,0x%02x,%d)\n", + acpi_ec_data, acpi_ec_status, gpe); + + if (!ACPI_SUCCESS(acpi_install_gpe_handler( + gpe, + (ACPI_EVENT_LEVEL_TRIGGERED + | ACPI_EVENT_EDGE_TRIGGERED), + acpi_ec_gpe, + NULL))) + return AE_OK; + + return AE_OK; +} + +int +acpi_ec_init(void) +{ + acpi_walk_namespace(ACPI_TYPE_DEVICE, + ACPI_ROOT_OBJECT, + ACPI_INT32_MAX, + acpi_find_ec, + NULL, + NULL); + return 0; +} diff --git a/drivers/acpi/os.c b/drivers/acpi/os.c new file mode 100644 index 000000000..7398534ad --- /dev/null +++ b/drivers/acpi/os.c @@ -0,0 +1,379 @@ +/* + * os.c - OS-dependent functions + * + * Copyright (C) 2000 Andrew Henroid + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/mm.h> +#include <linux/pci.h> +#include <linux/acpi.h> +#include <asm/io.h> +#include <asm/delay.h> +#include "acpi.h" +#include "driver.h" + +static int acpi_irq_irq = 0; +static OSD_HANDLER acpi_irq_handler = NULL; +static void *acpi_irq_context = NULL; + +char * +strupr(char *str) +{ + char *s = str; + while (*s) { + *s = TOUPPER(*s); + s++; + } + return str; +} + +ACPI_STATUS +acpi_os_initialize(void) +{ + return AE_OK; +} + +ACPI_STATUS +acpi_os_terminate(void) +{ + if (acpi_irq_handler) { + acpi_os_remove_interrupt_handler(acpi_irq_irq, + acpi_irq_handler); + } + return AE_OK; +} + +s32 +acpi_os_printf(const char *fmt,...) +{ + s32 size; + va_list args; + va_start(args, fmt); + size = acpi_os_vprintf(fmt, args); + va_end(args); + return size; +} + +s32 +acpi_os_vprintf(const char *fmt, va_list args) +{ + static char buffer[512]; + int size = vsprintf(buffer, fmt, args); + printk(KERN_DEBUG "ACPI: %s", buffer); + return size; +} + +void * +acpi_os_allocate(u32 size) +{ + return kmalloc(size, GFP_KERNEL); +} + +void * +acpi_os_callocate(u32 size) +{ + void *ptr = acpi_os_allocate(size); + if (ptr) + memset(ptr, 0, size); + return ptr; +} + +void +acpi_os_free(void *ptr) +{ + kfree(ptr); +} + +ACPI_STATUS +acpi_os_map_memory(void *phys, u32 size, void **virt) +{ + if ((unsigned long) phys < virt_to_phys(high_memory)) { + *virt = phys_to_virt((unsigned long) phys); + return AE_OK; + } + + *virt = ioremap((unsigned long) phys, size); + if (!*virt) + return AE_ERROR; + + return AE_OK; +} + +void +acpi_os_unmap_memory(void *virt, u32 size) +{ + if (virt >= high_memory) + iounmap(virt); +} + +static void +acpi_irq(int irq, void *dev_id, struct pt_regs *regs) +{ + (*acpi_irq_handler)(acpi_irq_context); +} + +ACPI_STATUS +acpi_os_install_interrupt_handler(u32 irq, OSD_HANDLER handler, void *context) +{ + acpi_irq_irq = irq; + acpi_irq_handler = handler; + acpi_irq_context = context; + if (request_irq(irq, + acpi_irq, + SA_INTERRUPT | SA_SHIRQ, + "acpi", + acpi_irq)) { + printk(KERN_ERR "ACPI: SCI (IRQ%d) allocation failed\n", irq); + return AE_ERROR; + } + return AE_OK; +} + +ACPI_STATUS +acpi_os_remove_interrupt_handler(u32 irq, OSD_HANDLER handler) +{ + if (acpi_irq_handler) { + free_irq(irq, acpi_irq); + acpi_irq_handler = NULL; + } + return AE_OK; +} + +/* + * Running in interpreter thread context, safe to sleep + */ + +void +acpi_os_sleep(u32 sec, u32 ms) +{ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(HZ * sec + (ms * HZ) / 1000); +} + +void +acpi_os_sleep_usec(u32 us) +{ + udelay(us); +} + +u8 +acpi_os_in8(ACPI_IO_ADDRESS port) +{ + return inb(port); +} + +u16 +acpi_os_in16(ACPI_IO_ADDRESS port) +{ + return inw(port); +} + +u32 +acpi_os_in32(ACPI_IO_ADDRESS port) +{ + return inl(port); +} + +void +acpi_os_out8(ACPI_IO_ADDRESS port, u8 val) +{ + outb(val, port); +} + +void +acpi_os_out16(ACPI_IO_ADDRESS port, u16 val) +{ + outw(val, port); +} + +void +acpi_os_out32(ACPI_IO_ADDRESS port, u32 val) +{ + outl(val, port); +} + +ACPI_STATUS +acpi_os_read_pci_cfg_byte( + u32 bus, + u32 func, + u32 addr, + u8 * val) +{ + int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff); + struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn); + if (!val || !dev || pci_read_config_byte(dev, addr, val)) + return AE_ERROR; + return AE_OK; +} + +ACPI_STATUS +acpi_os_read_pci_cfg_word( + u32 bus, + u32 func, + u32 addr, + u16 * val) +{ + int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff); + struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn); + if (!val || !dev || pci_read_config_word(dev, addr, val)) + return AE_ERROR; + return AE_OK; +} + +ACPI_STATUS +acpi_os_read_pci_cfg_dword( + u32 bus, + u32 func, + u32 addr, + u32 * val) +{ + int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff); + struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn); + if (!val || !dev || pci_read_config_dword(dev, addr, val)) + return AE_ERROR; + return AE_OK; +} + +ACPI_STATUS +acpi_os_write_pci_cfg_byte( + u32 bus, + u32 func, + u32 addr, + u8 val) +{ + int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff); + struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn); + if (!dev || pci_write_config_byte(dev, addr, val)) + return AE_ERROR; + return AE_OK; +} + +ACPI_STATUS +acpi_os_write_pci_cfg_word( + u32 bus, + u32 func, + u32 addr, + u16 val) +{ + int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff); + struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn); + if (!dev || pci_write_config_word(dev, addr, val)) + return AE_ERROR; + return AE_OK; +} + +ACPI_STATUS +acpi_os_write_pci_cfg_dword( + u32 bus, + u32 func, + u32 addr, + u32 val) +{ + int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff); + struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn); + if (!dev || pci_write_config_dword(dev, addr, val)) + return AE_ERROR; + return AE_OK; +} + +/* + * Queue for interpreter thread + */ + +ACPI_STATUS +acpi_os_queue_for_execution( + u32 priority, + OSD_EXECUTION_CALLBACK callback, + void *context) +{ + if (acpi_run(callback, context)) + return AE_ERROR; + return AE_OK; +} + +/* + * Semaphores are unused, interpreter access is single threaded + */ + +ACPI_STATUS +acpi_os_create_semaphore(u32 max_units, u32 init, ACPI_HANDLE * handle) +{ + *handle = (ACPI_HANDLE) 0; + return AE_OK; +} + +ACPI_STATUS +acpi_os_delete_semaphore(ACPI_HANDLE handle) +{ + return AE_OK; +} + +ACPI_STATUS +acpi_os_wait_semaphore(ACPI_HANDLE handle, u32 units, u32 timeout) +{ + return AE_OK; +} + +ACPI_STATUS +acpi_os_signal_semaphore(ACPI_HANDLE handle, u32 units) +{ + return AE_OK; +} + +ACPI_STATUS +acpi_os_breakpoint(char *msg) +{ + acpi_os_printf("breakpoint: %s", msg); + return AE_OK; +} + +void +acpi_os_dbg_trap(char *msg) +{ + acpi_os_printf("trap: %s", msg); +} + +void +acpi_os_dbg_assert(void *failure, void *file, u32 line, char *msg) +{ + acpi_os_printf("assert: %s", msg); +} + +u32 +acpi_os_get_line(char *buffer) +{ + return 0; +} + +/* + * We just have to assume we're dealing with valid memory + */ + +BOOLEAN +acpi_os_readable(void *ptr, u32 len) +{ + return 1; +} + +BOOLEAN +acpi_os_writable(void *ptr, u32 len) +{ + return 1; +} diff --git a/drivers/acpi/osd.c b/drivers/acpi/osd.c deleted file mode 100644 index 402df75d7..000000000 --- a/drivers/acpi/osd.c +++ /dev/null @@ -1,1319 +0,0 @@ -/* - * osd.c - Linux specific code - * - * Copyright (C) 2000 Andrew Henroid - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/proc_fs.h> -#include <linux/sysctl.h> -#include <linux/interrupt.h> -#include <linux/slab.h> -#include <linux/wait.h> -#include <linux/pm.h> -#include <linux/mm.h> -#include <linux/pci.h> -#include <linux/acpi.h> -#include <asm/io.h> -#include <asm/delay.h> -#include <asm/uaccess.h> -#include "acpi.h" - -#define ACPI_MAX_THROTTLE 10 -#define ACPI_INVALID ~0UL -#define ACPI_INFINITE ~0UL - -static struct acpi_facp *acpi_facp = NULL; - -static spinlock_t acpi_event_lock = SPIN_LOCK_UNLOCKED; -static volatile u32 acpi_event_status = 0; -static volatile acpi_sstate_t acpi_event_state = ACPI_S0; -static DECLARE_WAIT_QUEUE_HEAD(acpi_event_wait); -static int acpi_irq_irq = 0; -static OSD_HANDLER acpi_irq_handler = NULL; -static void *acpi_irq_context = NULL; - -static unsigned long acpi_pblk = ACPI_INVALID; -static unsigned long acpi_c2_exit_latency = ACPI_INFINITE; -static unsigned long acpi_c3_exit_latency = ACPI_INFINITE; -static unsigned long acpi_c2_enter_latency = ACPI_INFINITE; -static unsigned long acpi_c3_enter_latency = ACPI_INFINITE; -static int acpi_c2_tested = 0; -static int acpi_c3_tested = 0; - -struct acpi_intrp_entry -{ - int priority; - OSD_EXECUTION_CALLBACK callback; - void *context; - struct list_head list; -}; - -struct acpi_enter_sx_ctx -{ - wait_queue_head_t wait; - int state; -}; - -static volatile int acpi_intrp_pid = -1; -static DECLARE_WAIT_QUEUE_HEAD(acpi_intrp_wait); -static LIST_HEAD(acpi_intrp_exec); -static spinlock_t acpi_intrp_exec_lock = SPIN_LOCK_UNLOCKED; - -#define ACPI_SLP_TYP(typa, typb) (((int)(typa) << 8) | (int)(typb)) -#define ACPI_SLP_TYPA(value) \ - ((((value) >> 8) << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK) -#define ACPI_SLP_TYPB(value) \ - ((((value) & 0xff) << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK) - -static volatile acpi_sstate_t acpi_sleep_state = ACPI_S0; -static unsigned long acpi_slptyp[ACPI_S5 + 1] = {ACPI_INVALID,}; - -static struct ctl_table_header *acpi_sysctl = NULL; - -static int acpi_do_ulong(ctl_table * ctl, - int write, - struct file *file, - void *buffer, - size_t * len); -static int acpi_do_sleep(ctl_table * ctl, - int write, - struct file *file, - void *buffer, - size_t * len); -static int acpi_do_event(ctl_table * ctl, - int write, - struct file *file, - void *buffer, - size_t * len); - -static struct ctl_table acpi_table[] = -{ - {ACPI_P_LVL2_LAT, "c2_exit_latency", - &acpi_c2_exit_latency, sizeof(acpi_c2_exit_latency), - 0644, NULL, &acpi_do_ulong}, - - {ACPI_ENTER_LVL2_LAT, "c2_enter_latency", - &acpi_c2_enter_latency, sizeof(acpi_c2_enter_latency), - 0644, NULL, &acpi_do_ulong}, - - {ACPI_P_LVL3_LAT, "c3_exit_latency", - &acpi_c3_exit_latency, sizeof(acpi_c3_exit_latency), - 0644, NULL, &acpi_do_ulong}, - - {ACPI_ENTER_LVL3_LAT, "c3_enter_latency", - &acpi_c3_enter_latency, sizeof(acpi_c3_enter_latency), - 0644, NULL, &acpi_do_ulong}, - - {ACPI_SLEEP, "sleep", NULL, 0, 0600, NULL, &acpi_do_sleep}, - - {ACPI_EVENT, "event", NULL, 0, 0400, NULL, &acpi_do_event}, - - {0} -}; - -static struct ctl_table acpi_dir_table[] = -{ - {CTL_ACPI, "acpi", NULL, 0, 0555, acpi_table}, - {0} -}; - -static u32 FASTCALL(acpi_read_pm1_control(struct acpi_facp *)); -static u32 FASTCALL(acpi_read_pm1_status(struct acpi_facp *)); -static void FASTCALL(acpi_write_pm1_control(struct acpi_facp *, u32)); -static void FASTCALL(acpi_write_pm1_status(struct acpi_facp *, u32)); - -/* - * Get the value of the PM1 control register (ACPI_SCI_EN, ...) - */ -static u32 -acpi_read_pm1_control(struct acpi_facp *facp) -{ - u32 value = 0; - if (facp->pm1a_cnt) - value = inw(facp->pm1a_cnt); - if (facp->pm1b_cnt) - value |= inw(facp->pm1b_cnt); - return value; -} - -/* - * Set the value of the PM1 control register (ACPI_BM_RLD, ...) - */ -static void -acpi_write_pm1_control(struct acpi_facp *facp, u32 value) -{ - if (facp->pm1a_cnt) - outw(value, facp->pm1a_cnt); - if (facp->pm1b_cnt) - outw(value, facp->pm1b_cnt); -} - -/* - * Get the value of the fixed event status register - */ -static u32 -acpi_read_pm1_status(struct acpi_facp *facp) -{ - u32 value = 0; - if (facp->pm1a_evt) - value = inw(facp->pm1a_evt); - if (facp->pm1b_evt) - value |= inw(facp->pm1b_evt); - return value; -} - -/* - * Set the value of the fixed event status register (clear events) - */ -static void -acpi_write_pm1_status(struct acpi_facp *facp, u32 value) -{ - if (facp->pm1a_evt) - outw(value, facp->pm1a_evt); - if (facp->pm1b_evt) - outw(value, facp->pm1b_evt); -} - -/* - * Examine/modify value - */ -static int -acpi_do_ulong(ctl_table * ctl, - int write, - struct file *file, - void *buffer, - size_t * len) -{ - char str[2 * sizeof(unsigned long) + 4], *strend; - unsigned long val; - int size; - - if (!write) { - if (file->f_pos) { - *len = 0; - return 0; - } - - val = *(unsigned long *) ctl->data; - size = sprintf(str, "0x%08lx\n", val); - if (*len >= size) { - copy_to_user(buffer, str, size); - *len = size; - } - else - *len = 0; - } - else { - size = sizeof(str) - 1; - if (size > *len) - size = *len; - copy_from_user(str, buffer, size); - str[size] = '\0'; - val = simple_strtoul(str, &strend, 0); - if (strend == str) - return -EINVAL; - *(unsigned long *) ctl->data = val; - } - - file->f_pos += *len; - return 0; -} - -/* - * Handle ACPI event - */ -u32 -acpi_event(void *context) -{ - unsigned long flags; - int event = (int) context; - int mask = 0; - - switch (event) { - case ACPI_EVENT_POWER_BUTTON: - mask = ACPI_PWRBTN; - break; - case ACPI_EVENT_SLEEP_BUTTON: - mask = ACPI_SLPBTN; - break; - } - - if (mask) { - // notify process waiting on /dev/acpi - spin_lock_irqsave(&acpi_event_lock, flags); - acpi_event_status |= mask; - spin_unlock_irqrestore(&acpi_event_lock, flags); - acpi_event_state = acpi_sleep_state; - wake_up_interruptible(&acpi_event_wait); - } - - return AE_OK; -} - -/* - * Wait for next event - */ -int -acpi_do_event(ctl_table * ctl, - int write, - struct file *file, - void *buffer, - size_t * len) -{ - u32 event_status = 0; - acpi_sstate_t event_state = 0; - char str[27]; - int size; - - if (write) - return -EPERM; - if (*len < sizeof(str)) { - *len = 0; - return 0; - } - - for (;;) { - unsigned long flags; - - // we need an atomic exchange here - spin_lock_irqsave(&acpi_event_lock, flags); - event_status = acpi_event_status; - acpi_event_status = 0; - spin_unlock_irqrestore(&acpi_event_lock, flags); - event_state = acpi_event_state; - - if (event_status) - break; - - // wait for an event to arrive - interruptible_sleep_on(&acpi_event_wait); - if (signal_pending(current)) - return -ERESTARTSYS; - } - - size = sprintf(str, - "0x%08x 0x%08x 0x%01x\n", - event_status, - 0, - event_state); - copy_to_user(buffer, str, size); - *len = size; - file->f_pos += size; - - return 0; -} - -/* - * Enter system sleep state - */ -static void -acpi_enter_sx(void *context) -{ - struct acpi_enter_sx_ctx *ctx = (struct acpi_enter_sx_ctx*) context; - struct acpi_facp *facp = acpi_facp; - ACPI_OBJECT_LIST arg_list; - ACPI_OBJECT arg; - u16 value; - - /* - * _PSW methods could be run here to enable wake-on keyboard, LAN, etc. - */ - - // run the _PTS method - memset(&arg_list, 0, sizeof(arg_list)); - arg_list.count = 1; - arg_list.pointer = &arg; - - memset(&arg, 0, sizeof(arg)); - arg.type = ACPI_TYPE_NUMBER; - arg.number.value = ctx->state; - - acpi_evaluate_object(NULL, "\\_PTS", &arg_list, NULL); - - // clear wake status - acpi_write_pm1_status(facp, ACPI_WAK); - - acpi_sleep_state = ctx->state; - - // set ACPI_SLP_TYPA/b and ACPI_SLP_EN - __cli(); - if (facp->pm1a_cnt) { - value = inw(facp->pm1a_cnt) & ~ACPI_SLP_TYP_MASK; - value |= (ACPI_SLP_TYPA(acpi_slptyp[ctx->state]) - | ACPI_SLP_EN); - outw(value, facp->pm1a_cnt); - } - if (facp->pm1b_cnt) { - value = inw(facp->pm1b_cnt) & ~ACPI_SLP_TYP_MASK; - value |= (ACPI_SLP_TYPB(acpi_slptyp[ctx->state]) - | ACPI_SLP_EN); - outw(value, facp->pm1b_cnt); - } - __sti(); - - if (ctx->state != ACPI_S1) { - printk(KERN_ERR "ACPI: S%d failed\n", ctx->state); - goto out; - } - - // wait until S1 is entered - while (!(acpi_read_pm1_status(facp) & ACPI_WAK)) - safe_halt(); - - // run the _WAK method - memset(&arg_list, 0, sizeof(arg_list)); - arg_list.count = 1; - arg_list.pointer = &arg; - - memset(&arg, 0, sizeof(arg)); - arg.type = ACPI_TYPE_NUMBER; - arg.number.value = ctx->state; - - acpi_evaluate_object(NULL, "\\_WAK", &arg_list, NULL); - - out: - acpi_sleep_state = ACPI_S0; - - if (waitqueue_active(&ctx->wait)) - wake_up_interruptible(&ctx->wait); -} - -/* - * Enter system sleep state and wait for completion - */ -static int -acpi_enter_sx_and_wait(acpi_sstate_t state) -{ - struct acpi_enter_sx_ctx ctx; - - if (!acpi_facp - || acpi_facp->hdr.signature != ACPI_FACP_SIG - || acpi_slptyp[state] == ACPI_INVALID) - return -EINVAL; - - init_waitqueue_head(&ctx.wait); - ctx.state = state; - - if (acpi_os_queue_for_execution(0, acpi_enter_sx, &ctx)) - return -1; - - interruptible_sleep_on(&ctx.wait); - if (signal_pending(current)) - return -ERESTARTSYS; - - return 0; -} - -/* - * Enter system sleep state - */ -static int -acpi_do_sleep(ctl_table * ctl, - int write, - struct file *file, - void *buffer, - size_t * len) -{ - if (!write) { - if (file->f_pos) { - *len = 0; - return 0; - } - } - else { -#ifdef CONFIG_ACPI_S1_SLEEP - int status = acpi_enter_sx_and_wait(ACPI_S1); - if (status) - return status; -#endif - } - file->f_pos += *len; - return 0; -} - -/* - * Clear busmaster activity flag - */ -static inline void -acpi_clear_bm_activity(struct acpi_facp *facp) -{ - acpi_write_pm1_status(facp, ACPI_BM); -} - -/* - * Returns 1 if there has been busmaster activity - */ -static inline int -acpi_bm_activity(struct acpi_facp *facp) -{ - return acpi_read_pm1_status(facp) & ACPI_BM; -} - -/* - * Set system to sleep through busmaster requests - */ -static void -acpi_sleep_on_busmaster(struct acpi_facp *facp) -{ - u32 pm1_cntr = acpi_read_pm1_control(facp); - if (pm1_cntr & ACPI_BM_RLD) { - pm1_cntr &= ~ACPI_BM_RLD; - acpi_write_pm1_control(facp, pm1_cntr); - } -} - -/* - * Set system to wake on busmaster requests - */ -static void -acpi_wake_on_busmaster(struct acpi_facp *facp) -{ - u32 pm1_cntr = acpi_read_pm1_control(facp); - if (!(pm1_cntr & ACPI_BM_RLD)) { - pm1_cntr |= ACPI_BM_RLD; - acpi_write_pm1_control(facp, pm1_cntr); - } - acpi_clear_bm_activity(facp); -} - -/* The ACPI timer is just the low 24 bits */ -#define TIME_BEGIN(tmr) inl(tmr) -#define TIME_END(tmr, begin) ((inl(tmr) - (begin)) & 0x00ffffff) - -/* - * Idle loop (uniprocessor only) - */ -void -acpi_idle(void) -{ - static int sleep_level = 1; - struct acpi_facp *facp = acpi_facp; - - if (!facp - || facp->hdr.signature != ACPI_FACP_SIG - || !facp->pm_tmr - || !acpi_pblk) - goto not_initialized; - - /* - * start from the previous sleep level.. - */ - if (sleep_level == 1) - goto sleep1; - if (sleep_level == 2) - goto sleep2; - sleep3: - sleep_level = 3; - if (!acpi_c3_tested) { - printk(KERN_DEBUG "ACPI C3 works\n"); - acpi_c3_tested = 1; - } - acpi_wake_on_busmaster(facp); - if (facp->pm2_cnt) - goto sleep3_with_arbiter; - - for (;;) { - unsigned long time; - unsigned int pm_tmr = facp->pm_tmr; - - __cli(); - if (current->need_resched) - goto out; - if (acpi_bm_activity(facp)) - goto sleep2; - - time = TIME_BEGIN(pm_tmr); - inb(acpi_pblk + ACPI_P_LVL3); - /* Dummy read, force synchronization with the PMU */ - inl(pm_tmr); - time = TIME_END(pm_tmr, time); - - __sti(); - if (time < acpi_c3_exit_latency) - goto sleep2; - } - - sleep3_with_arbiter: - for (;;) { - unsigned long time; - u8 arbiter; - unsigned int pm2_cntr = facp->pm2_cnt; - unsigned int pm_tmr = facp->pm_tmr; - - __cli(); - if (current->need_resched) - goto out; - if (acpi_bm_activity(facp)) - goto sleep2; - - time = TIME_BEGIN(pm_tmr); - arbiter = inb(pm2_cntr) & ~ACPI_ARB_DIS; - /* Disable arbiter, park on CPU */ - outb(arbiter | ACPI_ARB_DIS, pm2_cntr); - inb(acpi_pblk + ACPI_P_LVL3); - /* Dummy read, force synchronization with the PMU */ - inl(pm_tmr); - time = TIME_END(pm_tmr, time); - /* Enable arbiter again.. */ - outb(arbiter, pm2_cntr); - - __sti(); - if (time < acpi_c3_exit_latency) - goto sleep2; - } - - sleep2: - sleep_level = 2; - if (!acpi_c2_tested) { - printk(KERN_DEBUG "ACPI C2 works\n"); - acpi_c2_tested = 1; - } - acpi_wake_on_busmaster(facp); /* Required to track BM activity.. */ - for (;;) { - unsigned long time; - unsigned int pm_tmr = facp->pm_tmr; - - __cli(); - if (current->need_resched) - goto out; - - time = TIME_BEGIN(pm_tmr); - inb(acpi_pblk + ACPI_P_LVL2); - /* Dummy read, force synchronization with the PMU */ - inl(pm_tmr); - time = TIME_END(pm_tmr, time); - - __sti(); - if (time < acpi_c2_exit_latency) - goto sleep1; - if (acpi_bm_activity(facp)) { - acpi_clear_bm_activity(facp); - continue; - } - if (time > acpi_c3_enter_latency) - goto sleep3; - } - - sleep1: - sleep_level = 1; - acpi_sleep_on_busmaster(facp); - for (;;) { - unsigned long time; - unsigned int pm_tmr = facp->pm_tmr; - - __cli(); - if (current->need_resched) - goto out; - time = TIME_BEGIN(pm_tmr); - safe_halt(); - time = TIME_END(pm_tmr, time); - if (time > acpi_c2_enter_latency) - goto sleep2; - } - - not_initialized: - for (;;) { - __cli(); - if (current->need_resched) - goto out; - safe_halt(); - } - - out: - __sti(); -} - -/* - * Enter soft-off (S5) - */ -static void -acpi_power_off(void) -{ - struct acpi_enter_sx_ctx ctx; - - if (!acpi_facp - || acpi_facp->hdr.signature != ACPI_FACP_SIG - || acpi_slptyp[ACPI_S5] == ACPI_INVALID) - return; - - init_waitqueue_head(&ctx.wait); - ctx.state = ACPI_S5; - acpi_enter_sx(&ctx); -} - -/* - * Get processor information - */ -static ACPI_STATUS -acpi_get_cpu_info(ACPI_HANDLE handle, u32 level, void *ctx, void **value) -{ - ACPI_OBJECT obj; - ACPI_CX_STATE lat[4]; - ACPI_CPU_THROTTLING_STATE throttle[ACPI_MAX_THROTTLE]; - ACPI_BUFFER buf; - int i, count; - - buf.length = sizeof(obj); - buf.pointer = &obj; - if (!ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buf))) - return AE_OK; - - printk(KERN_INFO "ACPI: PBLK %d @ 0x%04x:%d\n", - obj.processor.proc_id, - obj.processor.pblk_address, - obj.processor.pblk_length); - if (acpi_pblk != ACPI_INVALID - || !obj.processor.pblk_address - || obj.processor.pblk_length != 6) - return AE_OK; - - acpi_pblk = obj.processor.pblk_address; - - buf.length = sizeof(lat); - buf.pointer = lat; - if (!ACPI_SUCCESS(acpi_get_processor_cx_info(handle, &buf))) - return AE_OK; - - if (lat[2].latency < MAX_CX_STATE_LATENCY) { - printk(KERN_INFO "ACPI: C2 supported\n"); - acpi_c2_exit_latency = lat[2].latency; - } - if (lat[3].latency < MAX_CX_STATE_LATENCY) { - printk(KERN_INFO "ACPI: C3 supported\n"); - acpi_c3_exit_latency = lat[3].latency; - } - - memset(throttle, 0, sizeof(throttle)); - buf.length = sizeof(throttle); - buf.pointer = throttle; - - if (!ACPI_SUCCESS(acpi_get_processor_throttling_info(handle, &buf))) - return AE_OK; - - for (i = 0, count = 0; i < ACPI_MAX_THROTTLE; i++) { - if (throttle[i].percent_of_clock) - count++; - } - count--; - if (count > 0) - printk(KERN_INFO "ACPI: %d throttling states\n", count); - - return AE_OK; -} - -/* - * Fetch the FACP information - */ -static int -acpi_fetch_facp(void) -{ - ACPI_BUFFER buffer; - - buffer.pointer = acpi_facp; - buffer.length = sizeof(*acpi_facp); - if (!ACPI_SUCCESS(acpi_get_table(ACPI_TABLE_FACP, 1, &buffer))) { - printk(KERN_ERR "ACPI: no FACP\n"); - kfree(acpi_facp); - return -ENODEV; - } - - if (acpi_facp->p_lvl2_lat - && acpi_facp->p_lvl2_lat <= ACPI_MAX_P_LVL2_LAT) { - acpi_c2_exit_latency - = ACPI_uS_TO_TMR_TICKS(acpi_facp->p_lvl2_lat); - acpi_c2_enter_latency - = ACPI_uS_TO_TMR_TICKS(ACPI_TMR_HZ / 1000); - } - if (acpi_facp->p_lvl3_lat - && acpi_facp->p_lvl3_lat <= ACPI_MAX_P_LVL3_LAT) { - acpi_c3_exit_latency - = ACPI_uS_TO_TMR_TICKS(acpi_facp->p_lvl3_lat); - acpi_c3_enter_latency - = ACPI_uS_TO_TMR_TICKS(acpi_facp->p_lvl3_lat * 5); - } - - return 0; -} - -/* - * Execute callbacks (interpret methods) - */ -static void -acpi_intrp_run(void) -{ - for (;;) { - struct acpi_intrp_entry *entry; - unsigned long flags; - - interruptible_sleep_on(&acpi_intrp_wait); - if (signal_pending(current)) - return; - - for (;;) { - entry = NULL; - - spin_lock_irqsave(&acpi_intrp_exec_lock, flags); - if (!list_empty(&acpi_intrp_exec)) { - entry = list_entry(acpi_intrp_exec.next, - struct acpi_intrp_entry, - list); - list_del(&entry->list); - } - spin_unlock_irqrestore(&acpi_intrp_exec_lock, flags); - - if (!entry) - break; - - (*entry->callback)(entry->context); - - kfree(entry); - } - } -} - -/* - * Initialize and run interpreter within a kernel thread - */ -static int -acpi_intrp_thread(void *context) -{ - ACPI_STATUS status; - u8 sx, typa, typb; - - /* - * initialize interpreter - */ - exit_files(current); - daemonize(); - strcpy(current->comm, "acpi"); - - if (!ACPI_SUCCESS(acpi_initialize(NULL))) { - printk(KERN_ERR "ACPI: initialize failed\n"); - return -ENODEV; - } - - if (!ACPI_SUCCESS(acpi_load_firmware_tables())) { - printk(KERN_ERR "ACPI: table load failed\n"); - acpi_terminate(); - return -ENODEV; - } - - if (acpi_fetch_facp()) { - acpi_terminate(); - return -ENODEV; - } - - status = acpi_load_namespace(); - if (!ACPI_SUCCESS(status) && status != AE_CTRL_PENDING) { - printk(KERN_ERR "ACPI: namespace load failed\n"); - acpi_terminate(); - return -ENODEV; - } - - printk(KERN_INFO "ACPI: ACPI support found\n"); - - acpi_walk_namespace(ACPI_TYPE_PROCESSOR, - ACPI_ROOT_OBJECT, - ACPI_INT32_MAX, - acpi_get_cpu_info, - NULL, - NULL); - - for (sx = ACPI_S0; sx <= ACPI_S5; sx++) { - int ca_sx = (sx <= ACPI_S4) ? sx : (sx + 1); - if (ACPI_SUCCESS( - acpi_hw_obtain_sleep_type_register_data(ca_sx, - &typa, - &typb))) - acpi_slptyp[sx] = ACPI_SLP_TYP(typa, typb); - else - acpi_slptyp[sx] = ACPI_INVALID; - } - if (acpi_slptyp[ACPI_S1] != ACPI_INVALID) - printk(KERN_INFO "ACPI: S1 supported\n"); - if (acpi_slptyp[ACPI_S5] != ACPI_INVALID) - printk(KERN_INFO "ACPI: S5 supported\n"); - - if (!ACPI_SUCCESS(acpi_enable())) { - printk(KERN_ERR "ACPI: enable failed\n"); - acpi_terminate(); - return -ENODEV; - } - - if (!ACPI_SUCCESS(acpi_install_fixed_event_handler( - ACPI_EVENT_POWER_BUTTON, - acpi_event, - (void *) ACPI_EVENT_POWER_BUTTON))) { - printk(KERN_ERR "ACPI: power button enable failed\n"); - } - if (!ACPI_SUCCESS(acpi_install_fixed_event_handler( - ACPI_EVENT_SLEEP_BUTTON, - acpi_event, - (void *) ACPI_EVENT_SLEEP_BUTTON))) { - printk(KERN_ERR "ACPI: sleep button enable failed\n"); - } - -#ifdef CONFIG_SMP - if (smp_num_cpus == 1) - pm_idle = acpi_idle; -#else - pm_idle = acpi_idle; -#endif - pm_power_off = acpi_power_off; - - acpi_sysctl = register_sysctl_table(acpi_dir_table, 1); - - /* - * run interpreter - */ - acpi_intrp_run(); - - /* - * terminate interpreter - */ - unregister_sysctl_table(acpi_sysctl); - acpi_terminate(); - - acpi_intrp_pid = -1; - - return 0; -} - -/* - * Start the interpreter - */ -int __init -acpi_init(void) -{ - acpi_facp = kmalloc(sizeof(*acpi_facp), GFP_KERNEL); - if (!acpi_facp) - return -ENOMEM; - memset(acpi_facp, 0, sizeof(*acpi_facp)); - - acpi_intrp_pid = kernel_thread(acpi_intrp_thread, - NULL, - (CLONE_FS | CLONE_FILES - | CLONE_SIGHAND | SIGCHLD)); - return ((acpi_intrp_pid >= 0) ? 0:-ENODEV); -} - -/* - * Terminate the interpreter - */ -void __exit -acpi_exit(void) -{ - int count; - - if (!kill_proc(acpi_intrp_pid, SIGTERM, 1)) { - // wait until interpreter thread terminates (at most 5 seconds) - count = 5 * HZ; - while (acpi_intrp_pid >= 0 && --count) { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(1); - } - } - - // clean up after the interpreter - - if (acpi_irq_handler) { - acpi_os_remove_interrupt_handler(acpi_irq_irq, - acpi_irq_handler); - } - - if (pm_power_off == acpi_power_off) - pm_power_off = NULL; - if (pm_idle == acpi_idle) - pm_idle = NULL; - - kfree(acpi_facp); -} - -module_init(acpi_init); -module_exit(acpi_exit); - -/* - * OS-dependent functions - * - */ - -char * -strupr(char *str) -{ - char *s = str; - while (*s) { - *s = TOUPPER(*s); - s++; - } - return str; -} - -ACPI_STATUS -acpi_os_initialize(void) -{ - return AE_OK; -} - -ACPI_STATUS -acpi_os_terminate(void) -{ - return AE_OK; -} - -s32 -acpi_os_printf(const char *fmt,...) -{ - s32 size; - va_list args; - va_start(args, fmt); - size = acpi_os_vprintf(fmt, args); - va_end(args); - return size; -} - -s32 -acpi_os_vprintf(const char *fmt, va_list args) -{ - static char buffer[512]; - int size = vsprintf(buffer, fmt, args); - printk(KERN_DEBUG "%s", buffer); - return size; -} - -void * -acpi_os_allocate(u32 size) -{ - return kmalloc(size, GFP_KERNEL); -} - -void * -acpi_os_callocate(u32 size) -{ - void *ptr = acpi_os_allocate(size); - if (ptr) - memset(ptr, 0, size); - return ptr; -} - -void -acpi_os_free(void *ptr) -{ - kfree(ptr); -} - -ACPI_STATUS -acpi_os_map_memory(void *phys, u32 size, void **virt) -{ - if ((unsigned long) phys < virt_to_phys(high_memory)) { - *virt = phys_to_virt((unsigned long) phys); - return AE_OK; - } - - *virt = ioremap((unsigned long) phys, size); - if (!*virt) - return AE_ERROR; - - return AE_OK; -} - -void -acpi_os_unmap_memory(void *virt, u32 size) -{ - if (virt >= high_memory) - iounmap(virt); -} - -static void -acpi_irq(int irq, void *dev_id, struct pt_regs *regs) -{ - (*acpi_irq_handler)(acpi_irq_context); -} - -ACPI_STATUS -acpi_os_install_interrupt_handler(u32 irq, OSD_HANDLER handler, void *context) -{ - acpi_irq_irq = irq; - acpi_irq_handler = handler; - acpi_irq_context = context; - if (request_irq(irq, - acpi_irq, - SA_INTERRUPT | SA_SHIRQ, - "acpi", - acpi_irq)) { - printk(KERN_ERR "ACPI: SCI (IRQ%d) allocation failed\n", irq); - return AE_ERROR; - } - return AE_OK; -} - -ACPI_STATUS -acpi_os_remove_interrupt_handler(u32 irq, OSD_HANDLER handler) -{ - if (acpi_irq_handler) { - free_irq(irq, acpi_irq); - acpi_irq_handler = NULL; - } - return AE_OK; -} - -/* - * Running in interpreter thread context, safe to sleep - */ - -void -acpi_os_sleep(u32 sec, u32 ms) -{ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ * sec + (ms * HZ) / 1000); -} - -void -acpi_os_sleep_usec(u32 us) -{ - udelay(us); -} - -u8 -acpi_os_in8(ACPI_IO_ADDRESS port) -{ - return inb(port); -} - -u16 -acpi_os_in16(ACPI_IO_ADDRESS port) -{ - return inw(port); -} - -u32 -acpi_os_in32(ACPI_IO_ADDRESS port) -{ - return inl(port); -} - -void -acpi_os_out8(ACPI_IO_ADDRESS port, u8 val) -{ - outb(val, port); -} - -void -acpi_os_out16(ACPI_IO_ADDRESS port, u16 val) -{ - outw(val, port); -} - -void -acpi_os_out32(ACPI_IO_ADDRESS port, u32 val) -{ - outl(val, port); -} - -ACPI_STATUS -acpi_os_read_pci_cfg_byte( - u32 bus, - u32 func, - u32 addr, - u8 * val) -{ - int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff); - struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn); - if (!val || !dev || pci_read_config_byte(dev, addr, val)) - return AE_ERROR; - return AE_OK; -} - -ACPI_STATUS -acpi_os_read_pci_cfg_word( - u32 bus, - u32 func, - u32 addr, - u16 * val) -{ - int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff); - struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn); - if (!val || !dev || pci_read_config_word(dev, addr, val)) - return AE_ERROR; - return AE_OK; -} - -ACPI_STATUS -acpi_os_read_pci_cfg_dword( - u32 bus, - u32 func, - u32 addr, - u32 * val) -{ - int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff); - struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn); - if (!val || !dev || pci_read_config_dword(dev, addr, val)) - return AE_ERROR; - return AE_OK; -} - -ACPI_STATUS -acpi_os_write_pci_cfg_byte( - u32 bus, - u32 func, - u32 addr, - u8 val) -{ - int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff); - struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn); - if (!dev || pci_write_config_byte(dev, addr, val)) - return AE_ERROR; - return AE_OK; -} - -ACPI_STATUS -acpi_os_write_pci_cfg_word( - u32 bus, - u32 func, - u32 addr, - u16 val) -{ - int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff); - struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn); - if (!dev || pci_write_config_word(dev, addr, val)) - return AE_ERROR; - return AE_OK; -} - -ACPI_STATUS -acpi_os_write_pci_cfg_dword( - u32 bus, - u32 func, - u32 addr, - u32 val) -{ - int devfn = PCI_DEVFN((func >> 16) & 0xffff, func & 0xffff); - struct pci_dev *dev = pci_find_slot(bus & 0xffff, devfn); - if (!dev || pci_write_config_dword(dev, addr, val)) - return AE_ERROR; - return AE_OK; -} - -/* - * Queue for interpreter thread - */ - -ACPI_STATUS -acpi_os_queue_for_execution( - u32 priority, - OSD_EXECUTION_CALLBACK callback, - void *context) -{ - struct acpi_intrp_entry *entry; - unsigned long flags; - - entry = kmalloc(sizeof(*entry), GFP_ATOMIC); - if (!entry) - return AE_ERROR; - - memset(entry, 0, sizeof(entry)); - entry->priority = priority; - entry->callback = callback; - entry->context = context; - INIT_LIST_HEAD(&entry->list); - - if (!waitqueue_active(&acpi_intrp_wait)) { - kfree(entry); - return AE_ERROR; - } - - spin_lock_irqsave(&acpi_intrp_exec_lock, flags); - list_add(&entry->list, &acpi_intrp_exec); - wake_up(&acpi_intrp_wait); - spin_unlock_irqrestore(&acpi_intrp_exec_lock, flags); - - return AE_OK; -} - -/* - * Semaphores are unused, interpreter access is single threaded - */ - -ACPI_STATUS -acpi_os_create_semaphore(u32 max_units, u32 init, ACPI_HANDLE * handle) -{ - *handle = (ACPI_HANDLE) 0; - return AE_OK; -} - -ACPI_STATUS -acpi_os_delete_semaphore(ACPI_HANDLE handle) -{ - return AE_OK; -} - -ACPI_STATUS -acpi_os_wait_semaphore(ACPI_HANDLE handle, u32 units, u32 timeout) -{ - return AE_OK; -} - -ACPI_STATUS -acpi_os_signal_semaphore(ACPI_HANDLE handle, u32 units) -{ - return AE_OK; -} - -ACPI_STATUS -acpi_os_breakpoint(char *msg) -{ - acpi_os_printf("breakpoint: %s", msg); - return AE_OK; -} - -void -acpi_os_dbg_trap(char *msg) -{ - acpi_os_printf("trap: %s", msg); -} - -void -acpi_os_dbg_assert(void *failure, void *file, u32 line, char *msg) -{ - acpi_os_printf("assert: %s", msg); -} - -u32 -acpi_os_get_line(char *buffer) -{ - return 0; -} - -/* - * We just have to assume we're dealing with valid memory - */ - -BOOLEAN -acpi_os_readable(void *ptr, u32 len) -{ - return 1; -} - -BOOLEAN -acpi_os_writable(void *ptr, u32 len) -{ - return 1; -} diff --git a/drivers/acpi/sys.c b/drivers/acpi/sys.c new file mode 100644 index 000000000..1a403f86f --- /dev/null +++ b/drivers/acpi/sys.c @@ -0,0 +1,182 @@ +/* + * sys.c - System management (suspend, ...) + * + * Copyright (C) 2000 Andrew Henroid + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/kernel.h> +#include <linux/pm.h> +#include <linux/acpi.h> +#include "acpi.h" +#include "driver.h" + +#define ACPI_SLP_TYP(typa, typb) (((int)(typa) << 8) | (int)(typb)) +#define ACPI_SLP_TYPA(value) \ + ((((value) >> 8) << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK) +#define ACPI_SLP_TYPB(value) \ + ((((value) & 0xff) << ACPI_SLP_TYP_SHIFT) & ACPI_SLP_TYP_MASK) + +struct acpi_enter_sx_ctx +{ + wait_queue_head_t wait; + int state; +}; + +volatile acpi_sstate_t acpi_sleep_state = ACPI_S0; +static unsigned long acpi_slptyp[ACPI_S5 + 1] = {ACPI_INVALID,}; + +/* + * Enter system sleep state + */ +static void +acpi_enter_sx_async(void *context) +{ + struct acpi_enter_sx_ctx *ctx = (struct acpi_enter_sx_ctx*) context; + struct acpi_facp *facp = &acpi_facp; + ACPI_OBJECT_LIST arg_list; + ACPI_OBJECT arg; + u16 value; + + /* + * _PSW methods could be run here to enable wake-on keyboard, LAN, etc. + */ + + // run the _PTS method + memset(&arg_list, 0, sizeof(arg_list)); + arg_list.count = 1; + arg_list.pointer = &arg; + + memset(&arg, 0, sizeof(arg)); + arg.type = ACPI_TYPE_NUMBER; + arg.number.value = ctx->state; + + acpi_evaluate_object(NULL, "\\_PTS", &arg_list, NULL); + + // clear wake status + acpi_write_pm1_status(facp, ACPI_WAK); + + acpi_sleep_state = ctx->state; + + // set ACPI_SLP_TYPA/b and ACPI_SLP_EN + __cli(); + if (facp->pm1a_cnt) { + value = inw(facp->pm1a_cnt) & ~ACPI_SLP_TYP_MASK; + value |= (ACPI_SLP_TYPA(acpi_slptyp[ctx->state]) + | ACPI_SLP_EN); + outw(value, facp->pm1a_cnt); + } + if (facp->pm1b_cnt) { + value = inw(facp->pm1b_cnt) & ~ACPI_SLP_TYP_MASK; + value |= (ACPI_SLP_TYPB(acpi_slptyp[ctx->state]) + | ACPI_SLP_EN); + outw(value, facp->pm1b_cnt); + } + __sti(); + + if (ctx->state != ACPI_S1) { + printk(KERN_ERR "ACPI: S%d failed\n", ctx->state); + goto out; + } + + // wait until S1 is entered + while (!(acpi_read_pm1_status(facp) & ACPI_WAK)) + safe_halt(); + + // run the _WAK method + memset(&arg_list, 0, sizeof(arg_list)); + arg_list.count = 1; + arg_list.pointer = &arg; + + memset(&arg, 0, sizeof(arg)); + arg.type = ACPI_TYPE_NUMBER; + arg.number.value = ctx->state; + + acpi_evaluate_object(NULL, "\\_WAK", &arg_list, NULL); + + out: + acpi_sleep_state = ACPI_S0; + + if (waitqueue_active(&ctx->wait)) + wake_up_interruptible(&ctx->wait); +} + +/* + * Enter soft-off (S5) + */ +static void +acpi_power_off(void) +{ + struct acpi_enter_sx_ctx ctx; + + if (acpi_facp.hdr.signature != ACPI_FACP_SIG + || acpi_slptyp[ACPI_S5] == ACPI_INVALID) + return; + + init_waitqueue_head(&ctx.wait); + ctx.state = ACPI_S5; + acpi_enter_sx_async(&ctx); +} + +/* + * Enter system sleep state and wait for completion + */ +int +acpi_enter_sx(acpi_sstate_t state) +{ + struct acpi_enter_sx_ctx ctx; + + if (acpi_facp.hdr.signature != ACPI_FACP_SIG + || acpi_slptyp[state] == ACPI_INVALID) + return -EINVAL; + + init_waitqueue_head(&ctx.wait); + ctx.state = state; + + if (acpi_os_queue_for_execution(0, acpi_enter_sx_async, &ctx)) + return -1; + + interruptible_sleep_on(&ctx.wait); + if (signal_pending(current)) + return -ERESTARTSYS; + + return 0; +} + +int +acpi_sys_init(void) +{ + u8 sx, typa, typb; + + for (sx = ACPI_S0; sx <= ACPI_S5; sx++) { + int ca_sx = (sx <= ACPI_S4) ? sx : (sx + 1); + if (ACPI_SUCCESS( + acpi_hw_obtain_sleep_type_register_data(ca_sx, + &typa, + &typb))) + acpi_slptyp[sx] = ACPI_SLP_TYP(typa, typb); + else + acpi_slptyp[sx] = ACPI_INVALID; + } + if (acpi_slptyp[ACPI_S1] != ACPI_INVALID) + printk(KERN_INFO "ACPI: S1 supported\n"); + if (acpi_slptyp[ACPI_S5] != ACPI_INVALID) + printk(KERN_INFO "ACPI: S5 supported\n"); + + pm_power_off = acpi_power_off; + + return 0; +} diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c new file mode 100644 index 000000000..9ec6c58f4 --- /dev/null +++ b/drivers/acpi/tables.c @@ -0,0 +1,303 @@ +/* + * tables.c - ACPI tables, chipset, and errata handling + * + * Copyright (C) 2000 Andrew Henroid + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/pci.h> +#include <linux/pm.h> +#include <linux/acpi.h> +#include "acpi.h" +#include "driver.h" + +struct acpi_facp acpi_facp; + +#define ACPI_DUMMY_CHECKSUM 9 +#define ACPI_DUMMY_PBLK 51 + +static u8 acpi_dummy_dsdt[] = +{ + 0x44, 0x53, 0x44, 0x54, // "DSDT" + 0x38, 0x00, 0x00, 0x00, // length + 0x01, // revision + 0x00, // checksum + 0x4c, 0x49, 0x4e, 0x55, 0x58, 0x00, // "LINUX" + 0x44, 0x55, 0x4d, 0x4d, 0x59, 0x00, 0x00, 0x00, // "DUMMY" + 0x01, 0x00, 0x00, 0x00, // OEM rev + 0x4c, 0x4e, 0x55, 0x58, // "LNUX" + 0x01, 0x00, 0x00, 0x00, // creator rev + 0x10, // Scope + 0x13, // PkgLength + 0x5c, 0x5f, 0x50, 0x52, 0x5f, // \_PR_ + 0x5b, 0x83, // Processor + 0x0b, // PkgLength + 0x43, 0x50, 0x55, 0x30, // CPU0 + 0x00, // ID + 0x00, 0x00, 0x00, 0x00, // PBLK + 0x06 // PBLK size +}; + +/* + * Calculate and set ACPI table checksum + */ +static void +acpi_set_checksum(u8 *table, int size) +{ + int i, sum = 0; + for (i = 0; i < size; i++) + sum += (int) table[i]; + sum = (0x100 - ((sum - table[ACPI_DUMMY_CHECKSUM]) & 0xff)); + table[ACPI_DUMMY_CHECKSUM] = sum; +} + +/* + * Init PIIX4 device, create a fake FACP + */ +static int +acpi_init_piix4(struct pci_dev *dev) +{ + u32 base, pblk; + u16 cmd; + u8 pmregmisc; + + pci_read_config_word(dev, PCI_COMMAND, &cmd); + if (!(cmd & PCI_COMMAND_IO)) + return -ENODEV; + + pci_read_config_byte(dev, ACPI_PIIX4_PMREGMISC, &pmregmisc); + if (!(pmregmisc & ACPI_PIIX4_PMIOSE)) + return -ENODEV; + + base = pci_resource_start (dev, PCI_BRIDGE_RESOURCES); + if (!base) + return -ENODEV; + + printk(KERN_INFO "ACPI: found \"%s\" at 0x%04x\n", dev->name, base); + + memset(&acpi_facp, 0, sizeof(acpi_facp)); + acpi_facp.hdr.signature = ACPI_FACP_SIG; + acpi_facp.hdr.length = sizeof(acpi_facp); + acpi_facp.int_model = ACPI_PIIX4_INT_MODEL; + acpi_facp.sci_int = ACPI_PIIX4_SCI_INT; + acpi_facp.smi_cmd = ACPI_PIIX4_SMI_CMD; + acpi_facp.acpi_enable = ACPI_PIIX4_ACPI_ENABLE; + acpi_facp.acpi_disable = ACPI_PIIX4_ACPI_DISABLE; + acpi_facp.s4bios_req = ACPI_PIIX4_S4BIOS_REQ; + acpi_facp.pm1a_evt = base + ACPI_PIIX4_PM1_EVT; + acpi_facp.pm1a_cnt = base + ACPI_PIIX4_PM1_CNT; + acpi_facp.pm2_cnt = ACPI_PIIX4_PM2_CNT; + acpi_facp.pm_tmr = base + ACPI_PIIX4_PM_TMR; + acpi_facp.gpe0 = base + ACPI_PIIX4_GPE0; + acpi_facp.pm1_evt_len = ACPI_PIIX4_PM1_EVT_LEN; + acpi_facp.pm1_cnt_len = ACPI_PIIX4_PM1_CNT_LEN; + acpi_facp.pm2_cnt_len = ACPI_PIIX4_PM2_CNT_LEN; + acpi_facp.pm_tm_len = ACPI_PIIX4_PM_TM_LEN; + acpi_facp.gpe0_len = ACPI_PIIX4_GPE0_LEN; + acpi_facp.p_lvl2_lat = (__u16) ACPI_INFINITE_LAT; + acpi_facp.p_lvl3_lat = (__u16) ACPI_INFINITE_LAT; + + acpi_set_checksum((u8*) &acpi_facp, sizeof(acpi_facp)); + acpi_load_table((ACPI_TABLE_HEADER*) &acpi_facp); + + pblk = base + ACPI_PIIX4_P_BLK; + memcpy(acpi_dummy_dsdt + ACPI_DUMMY_PBLK, &pblk, sizeof(pblk)); + acpi_set_checksum(acpi_dummy_dsdt, sizeof(acpi_dummy_dsdt)); + acpi_load_table((ACPI_TABLE_HEADER*) acpi_dummy_dsdt); + + return 0; +} + +/* + * Init VIA ACPI device and create a fake FACP + */ +static int +acpi_init_via(struct pci_dev *dev) +{ + u32 base, pblk; + u8 tmp, irq; + + pci_read_config_byte(dev, 0x41, &tmp); + if (!(tmp & 0x80)) + return -ENODEV; + + base = pci_resource_start(dev, PCI_BRIDGE_RESOURCES); + if (!base) { + base = pci_resource_start(dev, PCI_BASE_ADDRESS_4); + if (!base) + return -ENODEV; + } + + pci_read_config_byte(dev, 0x42, &irq); + + printk(KERN_INFO "ACPI: found \"%s\" at 0x%04x\n", dev->name, base); + + memset(&acpi_facp, 0, sizeof(acpi_facp)); + acpi_facp.hdr.signature = ACPI_FACP_SIG; + acpi_facp.hdr.length = sizeof(acpi_facp); + acpi_facp.int_model = ACPI_VIA_INT_MODEL; + acpi_facp.sci_int = irq; + acpi_facp.smi_cmd = base + ACPI_VIA_SMI_CMD; + acpi_facp.acpi_enable = ACPI_VIA_ACPI_ENABLE; + acpi_facp.acpi_disable = ACPI_VIA_ACPI_DISABLE; + acpi_facp.pm1a_evt = base + ACPI_VIA_PM1_EVT; + acpi_facp.pm1a_cnt = base + ACPI_VIA_PM1_CNT; + acpi_facp.pm_tmr = base + ACPI_VIA_PM_TMR; + acpi_facp.gpe0 = base + ACPI_VIA_GPE0; + + acpi_facp.pm1_evt_len = ACPI_VIA_PM1_EVT_LEN; + acpi_facp.pm1_cnt_len = ACPI_VIA_PM1_CNT_LEN; + acpi_facp.pm_tm_len = ACPI_VIA_PM_TM_LEN; + acpi_facp.gpe0_len = ACPI_VIA_GPE0_LEN; + acpi_facp.p_lvl2_lat = (__u16) ACPI_INFINITE_LAT; + acpi_facp.p_lvl3_lat = (__u16) ACPI_INFINITE_LAT; + + acpi_facp.duty_offset = ACPI_VIA_DUTY_OFFSET; + acpi_facp.duty_width = ACPI_VIA_DUTY_WIDTH; + + acpi_facp.day_alarm = ACPI_VIA_DAY_ALARM; + acpi_facp.mon_alarm = ACPI_VIA_MON_ALARM; + acpi_facp.century = ACPI_VIA_CENTURY; + + acpi_set_checksum((u8*) &acpi_facp, sizeof(acpi_facp)); + acpi_load_table((ACPI_TABLE_HEADER*) &acpi_facp); + + pblk = base + ACPI_VIA_P_BLK; + memcpy(acpi_dummy_dsdt + ACPI_DUMMY_PBLK, &pblk, sizeof(pblk)); + acpi_set_checksum(acpi_dummy_dsdt, sizeof(acpi_dummy_dsdt)); + acpi_load_table((ACPI_TABLE_HEADER*) acpi_dummy_dsdt); + + return 0; +} + +typedef enum +{ + CH_UNKNOWN = 0, + CH_INTEL_PIIX4, + CH_VIA_586, + CH_VIA_686A, +} acpi_chip_t; + +/* indexed by value of each enum in acpi_chip_t */ +const static struct +{ + int (*chip_init)(struct pci_dev *dev); +} acpi_chip_info[] = +{ + {NULL,}, + {acpi_init_piix4}, + {acpi_init_via}, + {acpi_init_via}, +}; + +static struct pci_device_id acpi_pci_tbl[] = +{ + {0x8086, 0x7113, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_INTEL_PIIX4}, + {0x1106, 0x3040, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VIA_586}, + {0x1106, 0x3057, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_VIA_686A}, + {0,} /* terminate list */ +}; + +static int +acpi_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + return acpi_chip_info[id->driver_data].chip_init(dev); +} + +static struct pci_driver acpi_driver = +{ + name: "acpi", + id_table: acpi_pci_tbl, + probe: acpi_probe, +}; +static int acpi_driver_registered = 0; + +/* + * Locate a known ACPI chipset + */ +static int +acpi_find_chipset(void) +{ + if (pci_register_driver(&acpi_driver) < 1) + return -ENODEV; + acpi_driver_registered = 1; + return 0; +} + +/* + * Fetch the FACP information + */ +static int +acpi_fetch_facp(void) +{ + ACPI_BUFFER buffer; + + memset(&acpi_facp, 0, sizeof(acpi_facp)); + buffer.pointer = &acpi_facp; + buffer.length = sizeof(acpi_facp); + if (!ACPI_SUCCESS(acpi_get_table(ACPI_TABLE_FACP, 1, &buffer))) { + printk(KERN_ERR "ACPI: missing FACP\n"); + return -ENODEV; + } + + if (acpi_facp.p_lvl2_lat + && acpi_facp.p_lvl2_lat <= ACPI_MAX_P_LVL2_LAT) { + acpi_c2_exit_latency + = ACPI_uS_TO_TMR_TICKS(acpi_facp.p_lvl2_lat); + acpi_c2_enter_latency + = ACPI_uS_TO_TMR_TICKS(ACPI_TMR_HZ / 1000); + } + if (acpi_facp.p_lvl3_lat + && acpi_facp.p_lvl3_lat <= ACPI_MAX_P_LVL3_LAT) { + acpi_c3_exit_latency + = ACPI_uS_TO_TMR_TICKS(acpi_facp.p_lvl3_lat); + acpi_c3_enter_latency + = ACPI_uS_TO_TMR_TICKS(acpi_facp.p_lvl3_lat * 5); + } + + return 0; +} + +/* + * Find and load ACPI tables + */ +int +acpi_load_tables(void) +{ + if (ACPI_SUCCESS(acpi_load_firmware_tables())) + { + printk(KERN_INFO "ACPI: support found\n"); + } + else if (acpi_find_chipset()) { + acpi_terminate(); + return -1; + } + + if (acpi_fetch_facp()) { + acpi_terminate(); + return -1; + } + + if (!ACPI_SUCCESS(acpi_load_namespace())) { + printk(KERN_ERR "ACPI: namespace load failed\n"); + acpi_terminate(); + return -1; + } + + return 0; +} diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c index 785a0e551..b8f1c693e 100644 --- a/drivers/block/acsi_slm.c +++ b/drivers/block/acsi_slm.c @@ -66,6 +66,7 @@ not be guaranteed. There are several ways to assure this: #include <linux/mm.h> #include <linux/malloc.h> #include <linux/devfs_fs_kernel.h> +#include <linux/smp_lock.h> #include <asm/pgtable.h> #include <asm/system.h> @@ -269,7 +270,7 @@ static int slm_get_pagesize( int device, int *w, int *h ); /************************* End of Prototypes **************************/ -static struct timer_list slm_timer = { NULL, NULL, 0, 0, slm_test_ready }; +static struct timer_list slm_timer = { function: slm_test_ready }; static struct file_operations slm_fops = { owner: THIS_MODULE, @@ -799,10 +800,12 @@ static int slm_release( struct inode *inode, struct file *file ) device = MINOR(inode->i_rdev); sip = &slm_info[device]; + lock_kernel(); if (file->f_mode & 2) sip->wbusy = 0; if (file->f_mode & 1) sip->rbusy = 0; + unlock_kernel(); return( 0 ); } diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 37e50dbcd..6e094e4d8 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -578,7 +578,6 @@ static inline void attempt_front_merge(request_queue_t * q, static inline void __make_request(request_queue_t * q, int rw, struct buffer_head * bh) { - int major = MAJOR(bh->b_rdev); unsigned int sector, count; int max_segments = MAX_SEGMENTS; struct request * req = NULL; @@ -590,26 +589,6 @@ static inline void __make_request(request_queue_t * q, int rw, count = bh->b_size >> 9; sector = bh->b_rsector; - if (blk_size[major]) { - unsigned long maxsector = (blk_size[major][MINOR(bh->b_rdev)] << 1) + 1; - - if (maxsector < count || maxsector - count < sector) { - bh->b_state &= (1 << BH_Lock) | (1 << BH_Mapped); - if (!blk_size[major][MINOR(bh->b_rdev)]) - goto end_io; - /* This may well happen - the kernel calls bread() - without checking the size of the device, e.g., - when mounting a device. */ - printk(KERN_INFO - "attempt to access beyond end of device\n"); - printk(KERN_INFO "%s: rw=%d, want=%d, limit=%d\n", - kdevname(bh->b_rdev), rw, - (sector + count)>>1, - blk_size[major][MINOR(bh->b_rdev)]); - goto end_io; - } - } - rw_ahead = 0; /* normal case; gets changed below for READA */ switch (rw) { case READA: @@ -758,9 +737,35 @@ end_io: bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); } -int generic_make_request (request_queue_t *q, int rw, struct buffer_head * bh) +void generic_make_request (request_queue_t *q, int rw, struct buffer_head * bh) { - int ret; + int major = MAJOR(bh->b_rdev); + + if (blk_size[major]) { + unsigned long maxsector = (blk_size[major][MINOR(bh->b_rdev)] << 1) + 1; + unsigned int sector, count; + + count = bh->b_size >> 9; + sector = bh->b_rsector; + + if (maxsector < count || maxsector - count < sector) { + bh->b_state &= (1 << BH_Lock) | (1 << BH_Mapped); + if (blk_size[major][MINOR(bh->b_rdev)]) { + + /* This may well happen - the kernel calls bread() + without checking the size of the device, e.g., + when mounting a device. */ + printk(KERN_INFO + "attempt to access beyond end of device\n"); + printk(KERN_INFO "%s: rw=%d, want=%d, limit=%d\n", + kdevname(bh->b_rdev), rw, + (sector + count)>>1, + blk_size[major][MINOR(bh->b_rdev)]); + } + bh->b_end_io(bh, 0); + return; + } + } /* * Resolve the mapping until finished. (drivers are @@ -768,12 +773,9 @@ int generic_make_request (request_queue_t *q, int rw, struct buffer_head * bh) * by explicitly returning 0) */ while (q->make_request_fn) { - ret = q->make_request_fn(q, rw, bh); - if (ret > 0) { - q = blk_get_queue(bh->b_rdev); - continue; - } - return ret; + if (q->make_request_fn(q, rw, bh) == 0) + return; + q = blk_get_queue(bh->b_rdev); } /* * Does the block device want us to queue @@ -784,16 +786,13 @@ int generic_make_request (request_queue_t *q, int rw, struct buffer_head * bh) if (q && !q->plugged) (q->request_fn)(q); spin_unlock_irq(&io_request_lock); - - return 0; } /* This function can be used to request a number of buffers from a block device. Currently the only restriction is that all buffers must belong to the same device */ -static void __ll_rw_block(int rw, int nr, struct buffer_head * bhs[], - int haslock) +void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]) { struct buffer_head *bh; request_queue_t *q; @@ -840,13 +839,9 @@ static void __ll_rw_block(int rw, int nr, struct buffer_head * bhs[], bh = bhs[i]; /* Only one thread can actually submit the I/O. */ - if (haslock) { - if (!buffer_locked(bh)) - BUG(); - } else { - if (test_and_set_bit(BH_Lock, &bh->b_state)) - continue; - } + if (test_and_set_bit(BH_Lock, &bh->b_state)) + continue; + set_bit(BH_Req, &bh->b_state); /* @@ -865,15 +860,6 @@ sorry: buffer_IO_error(bhs[i]); } -void ll_rw_block(int rw, int nr, struct buffer_head * bh[]) -{ - __ll_rw_block(rw, nr, bh, 0); -} - -void ll_rw_block_locked(int rw, int nr, struct buffer_head * bh[]) -{ - __ll_rw_block(rw, nr, bh, 1); -} #ifdef CONFIG_STRAM_SWAP extern int stram_device_init (void); diff --git a/drivers/block/lvm.c b/drivers/block/lvm.c index 1e2a21cf1..d8cf20d79 100644 --- a/drivers/block/lvm.c +++ b/drivers/block/lvm.c @@ -301,6 +301,7 @@ static spinlock_t lvm_lock = SPIN_LOCK_UNLOCKED; static struct file_operations lvm_chr_fops = { + owner: THIS_MODULE, open: lvm_chr_open, release: lvm_chr_close, ioctl: lvm_chr_ioctl, @@ -517,8 +518,6 @@ static int lvm_chr_open(struct inode *inode, /* Group special file open */ if (VG_CHR(minor) > MAX_VG) return -ENXIO; - MOD_INC_USE_COUNT; - lvm_chr_open_count++; return 0; } /* lvm_chr_open() */ @@ -743,6 +742,7 @@ static int lvm_chr_close(struct inode *inode, struct file *file) "%s -- lvm_chr_close VG#: %d\n", lvm_name, VG_CHR(minor)); #endif + lock_kernel(); #ifdef LVM_TOTAL_RESET if (lvm_reset_spindown > 0) { lvm_reset_spindown = 0; @@ -755,10 +755,7 @@ static int lvm_chr_close(struct inode *inode, struct file *file) lock = 0; /* release lock */ wake_up_interruptible(&lvm_wait); } - -#ifdef MODULE - if (GET_USE_COUNT(&__this_module) > 0) MOD_DEC_USE_COUNT; -#endif + unlock_kernel(); return 0; } /* lvm_chr_close() */ diff --git a/drivers/block/md.c b/drivers/block/md.c index 651c3dd6d..087b5aee1 100644 --- a/drivers/block/md.c +++ b/drivers/block/md.c @@ -3412,7 +3412,7 @@ repeat: currspeed = (j-mddev->resync_mark_cnt)/((jiffies-mddev->resync_mark)/HZ +1) +1; if (currspeed > sysctl_speed_limit_min) { - current->priority = 19; + current->nice = 19; if ((currspeed > sysctl_speed_limit_max) || !is_mddev_idle(mddev)) { @@ -3422,7 +3422,7 @@ repeat: goto repeat; } } else - current->priority = -20; + current->nice = -20; } fsync_dev(read_disk); printk(KERN_INFO "md: md%d: sync done.\n",mdidx(mddev)); diff --git a/drivers/block/paride/paride.c b/drivers/block/paride/paride.c index 2315e1d30..b36fdab11 100644 --- a/drivers/block/paride/paride.c +++ b/drivers/block/paride/paride.c @@ -13,10 +13,11 @@ 1.02 GRG 1998.05.05 init_proto, release_proto, ktti 1.03 GRG 1998.08.15 eliminate compiler warning 1.04 GRG 1998.11.28 added support for FRIQ - + 1.05 TMW 2000.06.06 use parport_find_number instead of + parport_enumerate */ -#define PI_VERSION "1.04" +#define PI_VERSION "1.05" #include <linux/module.h> #include <linux/config.h> @@ -238,22 +239,25 @@ static void pi_register_parport( PIA *pi, int verbose) { #ifdef CONFIG_PARPORT - struct parport *pp; - - pp = parport_enumerate(); + struct parport *port; - while((pp)&&(pp->base != pi->port)) pp = pp->next; + port = parport_find_base (pi->port); + if (!port) return; - if (!pp) return; + pi->pardev = parport_register_device(port, + pi->device,NULL, + pi_wake_up,NULL, + 0,(void *)pi); + parport_put_port (port); + if (!pi->pardev) return; - pi->pardev = (void *) parport_register_device( - pp,pi->device,NULL,pi_wake_up,NULL,0,(void *)pi); init_waitqueue_head(&pi->parq); - if (verbose) printk("%s: 0x%x is %s\n",pi->device,pi->port,pp->name); + if (verbose) printk("%s: 0x%x is %s\n",pi->device,pi->port, + port->name); - pi->parname = (char *)pp->name; + pi->parname = (char *)port->name; #endif } @@ -406,6 +410,7 @@ int init_module(void) { int k; for (k=0;k<MAX_PROTOS;k++) protocols[k] = 0; + printk("paride: version %s installed\n",PI_VERSION); return 0; } diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c index c282d82a1..e2709ce97 100644 --- a/drivers/block/paride/pg.c +++ b/drivers/block/paride/pg.c @@ -171,6 +171,7 @@ static int pg_drive_count; #include <linux/mtio.h> #include <linux/pg.h> #include <linux/wait.h> +#include <linux/smp_lock.h> #include <asm/uaccess.h> @@ -604,10 +605,12 @@ static int pg_release (struct inode *inode, struct file *file) if ((unit >= PG_UNITS) || (PG.access <= 0)) return -EINVAL; + lock_kernel(); PG.access--; kfree(PG.bufptr); PG.bufptr = NULL; + unlock_kernel(); return 0; diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c index 0d3e81838..5cb91ae0a 100644 --- a/drivers/block/paride/pt.c +++ b/drivers/block/paride/pt.c @@ -149,6 +149,7 @@ static int pt_drive_count; #include <linux/malloc.h> #include <linux/mtio.h> #include <linux/wait.h> +#include <linux/smp_lock.h> #include <asm/uaccess.h> @@ -773,6 +774,7 @@ static int pt_release (struct inode *inode, struct file *file) if ((unit >= PT_UNITS) || (PT.access <= 0)) return -EINVAL; + lock_kernel(); if (PT.flags & PT_WRITING) pt_write_fm(unit); if (PT.flags & PT_REWIND) pt_rewind(unit); @@ -781,6 +783,7 @@ static int pt_release (struct inode *inode, struct file *file) kfree(PT.bufptr); PT.bufptr = NULL; + unlock_kernel(); return 0; diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c index 61cb27ec7..8ff56a70a 100644 --- a/drivers/block/ps2esdi.c +++ b/drivers/block/ps2esdi.c @@ -114,14 +114,14 @@ static DECLARE_WAIT_QUEUE_HEAD(ps2esdi_int); static DECLARE_WAIT_QUEUE_HEAD(ps2esdi_wait_open); int no_int_yet; -static int access_count[MAX_HD] = {0,}; -static char ps2esdi_valid[MAX_HD] = {0,}; -static int ps2esdi_sizes[MAX_HD << 6] = {0,}; -static int ps2esdi_blocksizes[MAX_HD << 6] = {0,}; -static int ps2esdi_drives = 0; +static int access_count[MAX_HD]; +static char ps2esdi_valid[MAX_HD]; +static int ps2esdi_sizes[MAX_HD << 6]; +static int ps2esdi_blocksizes[MAX_HD << 6]; +static int ps2esdi_drives; static struct hd_struct ps2esdi[MAX_HD << 6]; static u_short io_base; -static struct timer_list esdi_timer = {{NULL, NULL}, 0, 0L, ps2esdi_reset_timer}; +static struct timer_list esdi_timer = { function: ps2esdi_reset_timer }; static int reset_status; static int ps2esdi_slot = -1; int tp720esdi = 0; /* Is it Integrated ESDI of ThinkPad-720? */ diff --git a/drivers/block/rd.c b/drivers/block/rd.c index 727c1c543..2db08531a 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -59,6 +59,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/devfs_fs_kernel.h> +#include <linux/smp_lock.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -298,11 +299,14 @@ static int initrd_release(struct inode *inode,struct file *file) { extern void free_initrd_mem(unsigned long, unsigned long); - if (--initrd_users) return 0; - blkdev_put(inode->i_bdev, BDEV_FILE); - iput(inode); - free_initrd_mem(initrd_start, initrd_end); - initrd_start = 0; + lock_kernel(); + if (!--initrd_users) { + blkdev_put(inode->i_bdev, BDEV_FILE); + iput(inode); + free_initrd_mem(initrd_start, initrd_end); + initrd_start = 0; + } + unlock_kernel(); return 0; } diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c index 8b551a99d..b71f023aa 100644 --- a/drivers/cdrom/aztcd.c +++ b/drivers/cdrom/aztcd.c @@ -310,7 +310,7 @@ static char azt_auto_eject = AZT_AUTO_EJECT; static int AztTimeout, AztTries; static DECLARE_WAIT_QUEUE_HEAD(azt_waitq); -static struct timer_list delay_timer = { {NULL, NULL}, 0, 0, NULL }; +static struct timer_list delay_timer; static struct azt_DiskInfo DiskInfo; static struct azt_Toc Toc[MAX_TRACKS]; diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c index b793bac4b..eb102a4a7 100644 --- a/drivers/cdrom/sjcd.c +++ b/drivers/cdrom/sjcd.c @@ -150,7 +150,7 @@ static struct sjcd_stat statistic; /* * Timer. */ -static struct timer_list sjcd_delay_timer = { function: NULL }; +static struct timer_list sjcd_delay_timer; #define SJCD_SET_TIMER( func, tmout ) \ ( sjcd_delay_timer.expires = jiffies+tmout, \ diff --git a/drivers/char/acquirewdt.c b/drivers/char/acquirewdt.c index eaa9e6bae..b28df7e34 100644 --- a/drivers/char/acquirewdt.c +++ b/drivers/char/acquirewdt.c @@ -38,6 +38,7 @@ #include <linux/reboot.h> #include <linux/init.h> #include <linux/spinlock.h> +#include <linux/smp_lock.h> static int acq_is_open=0; static spinlock_t acq_lock; @@ -140,6 +141,7 @@ static int acq_open(struct inode *inode, struct file *file) static int acq_close(struct inode *inode, struct file *file) { + lock_kernel(); if(MINOR(inode->i_rdev)==WATCHDOG_MINOR) { spin_lock(&acq_lock); @@ -149,6 +151,7 @@ static int acq_close(struct inode *inode, struct file *file) acq_is_open=0; spin_unlock(&acq_lock); } + unlock_kernel(); return 0; } diff --git a/drivers/char/agp/agpgart_fe.c b/drivers/char/agp/agpgart_fe.c index e67beef38..d16c62a22 100644 --- a/drivers/char/agp/agpgart_fe.c +++ b/drivers/char/agp/agpgart_fe.c @@ -41,6 +41,7 @@ #include <linux/miscdevice.h> #include <linux/agp_backend.h> #include <linux/agpgart.h> +#include <linux/smp_lock.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -605,14 +606,17 @@ static int agp_mmap(struct file *file, struct vm_area_struct *vma) agp_file_private *priv = (agp_file_private *) file->private_data; agp_kern_info kerninfo; + lock_kernel(); AGP_LOCK(); if (agp_fe.backend_acquired != TRUE) { AGP_UNLOCK(); + unlock_kernel(); return -EPERM; } if (!(test_bit(AGP_FF_IS_VALID, &priv->access_flags))) { AGP_UNLOCK(); + unlock_kernel(); return -EPERM; } agp_copy_info(&kerninfo); @@ -624,42 +628,51 @@ static int agp_mmap(struct file *file, struct vm_area_struct *vma) if (test_bit(AGP_FF_IS_CLIENT, &priv->access_flags)) { if ((size + offset) > current_size) { AGP_UNLOCK(); + unlock_kernel(); return -EINVAL; } client = agp_find_client_by_pid(current->pid); if (client == NULL) { AGP_UNLOCK(); + unlock_kernel(); return -EPERM; } if (!agp_find_seg_in_client(client, offset, size, vma->vm_page_prot)) { AGP_UNLOCK(); + unlock_kernel(); return -EINVAL; } if (remap_page_range(vma->vm_start, (kerninfo.aper_base + offset), size, vma->vm_page_prot)) { AGP_UNLOCK(); + unlock_kernel(); return -EAGAIN; } AGP_UNLOCK(); + unlock_kernel(); return 0; } if (test_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags)) { if (size != current_size) { AGP_UNLOCK(); + unlock_kernel(); return -EINVAL; } if (remap_page_range(vma->vm_start, kerninfo.aper_base, size, vma->vm_page_prot)) { AGP_UNLOCK(); + unlock_kernel(); return -EAGAIN; } AGP_UNLOCK(); + unlock_kernel(); return 0; } AGP_UNLOCK(); + unlock_kernel(); return -EPERM; } @@ -667,6 +680,7 @@ static int agp_release(struct inode *inode, struct file *file) { agp_file_private *priv = (agp_file_private *) file->private_data; + lock_kernel(); AGP_LOCK(); if (test_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags)) { @@ -688,6 +702,7 @@ static int agp_release(struct inode *inode, struct file *file) agp_remove_file_private(priv); kfree(priv); AGP_UNLOCK(); + unlock_kernel(); return 0; } diff --git a/drivers/char/amikeyb.c b/drivers/char/amikeyb.c index 15e21be68..73b8fecd2 100644 --- a/drivers/char/amikeyb.c +++ b/drivers/char/amikeyb.c @@ -176,7 +176,7 @@ static unsigned int key_repeat_rate = DEFAULT_KEYB_REP_RATE; static unsigned char rep_scancode; static void amikeyb_rep(unsigned long ignore); -static struct timer_list amikeyb_rep_timer = {NULL, NULL, 0, 0, amikeyb_rep}; +static struct timer_list amikeyb_rep_timer = {function: amikeyb_rep}; static void amikeyb_rep(unsigned long ignore) { diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c index d5091ff4d..c109c5965 100644 --- a/drivers/char/applicom.c +++ b/drivers/char/applicom.c @@ -101,21 +101,18 @@ static unsigned int ReadErrorCount; /* number of read error */ static unsigned int DeviceErrorCount; /* number of device error */ static loff_t ac_llseek(struct file *, loff_t, int); -static int ac_open(struct inode *, struct file *); static ssize_t ac_read (struct file *, char *, size_t, loff_t *); static ssize_t ac_write (struct file *, const char *, size_t, loff_t *); static int ac_ioctl(struct inode *, struct file *, unsigned int, unsigned long); -static int ac_release(struct inode *, struct file *); static void ac_interrupt(int, void *, struct pt_regs *); struct file_operations ac_fops = { + owner:THIS_MODULE, llseek:ac_llseek, read:ac_read, write:ac_write, ioctl:ac_ioctl, - open:ac_open, - release:ac_release, }; struct miscdevice ac_miscdev = { @@ -124,6 +121,8 @@ struct miscdevice ac_miscdev = { &ac_fops }; +static int dummy; /* dev_id for request_irq() */ + int ac_register_board(unsigned long physloc, unsigned long loc, unsigned char boardno) { @@ -180,7 +179,7 @@ void cleanup_module(void) iounmap((void *) apbs[i].RamIO); if (apbs[i].irq) - free_irq(apbs[i].irq, &ac_open); + free_irq(apbs[i].irq, &dummy); } } @@ -226,7 +225,7 @@ int __init applicom_init(void) continue; } - if (request_irq(dev->irq, &ac_interrupt, SA_SHIRQ, "Applicom PCI", &ac_open)) { + if (request_irq(dev->irq, &ac_interrupt, SA_SHIRQ, "Applicom PCI", &dummy)) { printk(KERN_INFO "Could not allocate IRQ %d for PCI Applicom device.\n", dev->irq); iounmap(RamIO); apbs[boardno - 1].RamIO = 0; @@ -277,7 +276,7 @@ int __init applicom_init(void) printk(KERN_NOTICE "Applicom ISA card found at mem 0x%lx, irq %d\n", mem + (LEN_RAM_IO*i), irq); if (!numisa) { - if (request_irq(irq, &ac_interrupt, SA_SHIRQ, "Applicom ISA", &ac_open)) { + if (request_irq(irq, &ac_interrupt, SA_SHIRQ, "Applicom ISA", &dummy)) { printk(KERN_WARNING "Could not allocate IRQ %d for ISA Applicom device.\n", irq); iounmap((void *) RamIO); apbs[boardno - 1].RamIO = 0; @@ -346,19 +345,6 @@ static loff_t ac_llseek(struct file *file, loff_t offset, int origin) return -ESPIPE; } -static int ac_open(struct inode *inode, struct file *filp) -{ - MOD_INC_USE_COUNT; - return 0; -} - -static int ac_release(struct inode *inode, struct file *file) -{ - MOD_DEC_USE_COUNT; - return 0; -} - - static ssize_t ac_write(struct file *file, const char *buf, size_t count, loff_t * ppos) { unsigned int NumCard; /* Board number 1 -> 8 */ diff --git a/drivers/char/busmouse.c b/drivers/char/busmouse.c index bc8345cff..9bfe4b2b3 100644 --- a/drivers/char/busmouse.c +++ b/drivers/char/busmouse.c @@ -19,6 +19,7 @@ #include <linux/miscdevice.h> #include <linux/random.h> #include <linux/init.h> +#include <linux/smp_lock.h> #include <asm/uaccess.h> #include <asm/system.h> @@ -167,6 +168,7 @@ static int busmouse_release(struct inode *inode, struct file *file) struct busmouse_data *mse = (struct busmouse_data *)file->private_data; int ret = 0; + lock_kernel(); busmouse_fasync(-1, file, 0); if (--mse->active == 0) { @@ -178,6 +180,7 @@ static int busmouse_release(struct inode *inode, struct file *file) } mse->ready = 0; } + unlock_kernel(); return ret; } diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index cf4bb1f83..d0e801180 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -2,7 +2,7 @@ #define Z_WAKE #undef Z_EXT_CHARS_IN_BUFFER static char rcsid[] = -"$Revision: 2.3.2.7 $$Date: 2000/06/01 18:26:34 $"; +"$Revision: 2.3.2.8 $$Date: 2000/07/06 18:14:16 $"; /* * linux/drivers/char/cyclades.c @@ -25,6 +25,11 @@ static char rcsid[] = * This version supports shared IRQ's (only for PCI boards). * * $Log: cyclades.c,v $ + * Revision 2.3.2.8 2000/07/06 18:14:16 ivan + * Fixed the PCI detection function to work properly on Alpha systems. + * Implemented support for TIOCSERGETLSR ioctl. + * Implemented full support for non-standard baud rates. + * * Revision 2.3.2.7 2000/06/01 18:26:34 ivan * Request PLX I/O region, although driver doesn't use it, to avoid * problems with other drivers accessing it. @@ -1363,9 +1368,16 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs) while (char_count-- > 0){ if (!info->xmit_cnt){ - cy_writeb((u_long)base_addr+(CySRER<<index), - cy_readb(base_addr+(CySRER<<index)) & - ~CyTxRdy); + if (cy_readb(base_addr+(CySRER<<index))&CyTxMpty) { + cy_writeb((u_long)base_addr+(CySRER<<index), + cy_readb(base_addr+(CySRER<<index)) & + ~CyTxMpty); + } else { + cy_writeb((u_long)base_addr+(CySRER<<index), + ((cy_readb(base_addr+(CySRER<<index)) + & ~CyTxRdy) + | CyTxMpty)); + } goto txdone; } if (info->xmit_buf == 0){ @@ -3176,6 +3188,30 @@ cy_chars_in_buffer(struct tty_struct *tty) * ------------------------------------------------------------ */ +static void +cyy_baud_calc(struct cyclades_port *info, uclong baud) +{ + int co, co_val, bpr; + uclong cy_clock = ((info->chip_rev >= CD1400_REV_J) ? 60000000 : 25000000); + + if (baud == 0) { + info->tbpr = info->tco = info->rbpr = info->rco = 0; + return; + } + + /* determine which prescaler to use */ + for (co = 4, co_val = 2048; co; co--, co_val >>= 2) { + if (cy_clock / co_val / baud > 63) + break; + } + + bpr = (cy_clock / co_val * 2 / baud + 1) / 2; + if (bpr > 255) + bpr = 255; + + info->tbpr = info->rbpr = bpr; + info->tco = info->rco = co; +} /* * This routine finds or computes the various line characteristics. @@ -3189,7 +3225,7 @@ set_line_char(struct cyclades_port * info) int card,chip,channel,index; unsigned cflag, iflag; unsigned short chip_number; - int baud; + int baud, baud_rate = 0; int i; @@ -3225,12 +3261,14 @@ set_line_char(struct cyclades_port * info) index = cy_card[card].bus_index; /* baud rate */ - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) { - baud = info->baud; - } else { - baud = tty_get_baud_rate(info->tty); - } - if (baud > CD1400_MAX_SPEED) { + baud = tty_get_baud_rate(info->tty); + if ((baud == 38400) && + ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) { + if (info->custom_divisor) + baud_rate = info->baud / info->custom_divisor; + else + baud_rate = info->baud; + } else if (baud > CD1400_MAX_SPEED) { baud = CD1400_MAX_SPEED; } /* find the baud index */ @@ -3243,22 +3281,29 @@ set_line_char(struct cyclades_port * info) i = 19; /* CD1400_MAX_SPEED */ } - - if(info->chip_rev >= CD1400_REV_J) { - /* It is a CD1400 rev. J or later */ - info->tbpr = baud_bpr_60[i]; /* Tx BPR */ - info->tco = baud_co_60[i]; /* Tx CO */ - info->rbpr = baud_bpr_60[i]; /* Rx BPR */ - info->rco = baud_co_60[i]; /* Rx CO */ + if ((baud == 38400) && + ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) { + cyy_baud_calc(info, baud_rate); } else { - info->tbpr = baud_bpr_25[i]; /* Tx BPR */ - info->tco = baud_co_25[i]; /* Tx CO */ - info->rbpr = baud_bpr_25[i]; /* Rx BPR */ - info->rco = baud_co_25[i]; /* Rx CO */ + if(info->chip_rev >= CD1400_REV_J) { + /* It is a CD1400 rev. J or later */ + info->tbpr = baud_bpr_60[i]; /* Tx BPR */ + info->tco = baud_co_60[i]; /* Tx CO */ + info->rbpr = baud_bpr_60[i]; /* Rx BPR */ + info->rco = baud_co_60[i]; /* Rx CO */ + } else { + info->tbpr = baud_bpr_25[i]; /* Tx BPR */ + info->tco = baud_co_25[i]; /* Tx CO */ + info->rbpr = baud_bpr_25[i]; /* Rx BPR */ + info->rco = baud_co_25[i]; /* Rx CO */ + } } if (baud_table[i] == 134) { - info->timeout = (info->xmit_fifo_size*HZ*15/269) + 2; /* get it right for 134.5 baud */ + info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2; + } else if ((baud == 38400) && + ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) { + info->timeout = (info->xmit_fifo_size*HZ*15/baud_rate) + 2; } else if (baud_table[i]) { info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2; /* this needs to be propagated into the card info */ @@ -3447,19 +3492,24 @@ set_line_char(struct cyclades_port * info) buf_ctrl = &zfw_ctrl->buf_ctrl[channel]; /* baud rate */ - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) { - baud = info->baud; - } else { - baud = tty_get_baud_rate(info->tty); - } - if (baud > CYZ_MAX_SPEED) { + baud = tty_get_baud_rate(info->tty); + if ((baud == 38400) && + ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) { + if (info->custom_divisor) + baud_rate = info->baud / info->custom_divisor; + else + baud_rate = info->baud; + } else if (baud > CYZ_MAX_SPEED) { baud = CYZ_MAX_SPEED; } cy_writel(&ch_ctrl->comm_baud , baud); if (baud == 134) { - info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2; /* get it right for 134.5 baud */ + info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2; + } else if ((baud == 38400) && + ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) { + info->timeout = (info->xmit_fifo_size*HZ*15/baud_rate) + 2; } else if (baud) { info->timeout = (info->xmit_fifo_size*HZ*15/baud) + 2; /* this needs to be propagated into the card info */ @@ -3549,8 +3599,6 @@ set_line_char(struct cyclades_port * info) clear_bit(TTY_IO_ERROR, &info->tty->flags); } } - - } /* set_line_char */ @@ -3571,7 +3619,7 @@ get_serial_info(struct cyclades_port * info, tmp.flags = info->flags; tmp.close_delay = info->close_delay; tmp.baud_base = info->baud; - tmp.custom_divisor = 0; /*!!!*/ + tmp.custom_divisor = info->custom_divisor; tmp.hub6 = 0; /*!!!*/ return copy_to_user(retinfo,&tmp,sizeof(*retinfo))?-EFAULT:0; } /* get_serial_info */ @@ -3597,6 +3645,7 @@ set_serial_info(struct cyclades_port * info, info->flags = ((info->flags & ~ASYNC_USR_MASK) | (new_serial.flags & ASYNC_USR_MASK)); info->baud = new_serial.baud_base; + info->custom_divisor = new_serial.custom_divisor; goto check_and_exit; } @@ -3607,6 +3656,7 @@ set_serial_info(struct cyclades_port * info, */ info->baud = new_serial.baud_base; + info->custom_divisor = new_serial.custom_divisor; info->flags = ((info->flags & ~ASYNC_FLAGS) | (new_serial.flags & ASYNC_FLAGS)); info->close_delay = new_serial.close_delay * HZ/100; @@ -3621,6 +3671,43 @@ check_and_exit: } } /* set_serial_info */ +/* + * get_lsr_info - get line status register info + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows an RS485 driver to be written in user space. + */ +static int get_lsr_info(struct cyclades_port *info, unsigned int *value) +{ + int card, chip, channel, index; + unsigned char status; + unsigned int result; + unsigned long flags; + unsigned char *base_addr; + + card = info->card; + channel = (info->line) - (cy_card[card].first_line); + if (!IS_CYC_Z(cy_card[card])) { + chip = channel>>2; + channel &= 0x03; + index = cy_card[card].bus_index; + base_addr = (unsigned char *) + (cy_card[card].base_addr + (cy_chip_offset[chip]<<index)); + + CY_LOCK(info, flags); + status = cy_readb(base_addr+(CySRER<<index)) & (CyTxRdy|CyTxMpty); + CY_UNLOCK(info, flags); + result = (status ? 0 : TIOCSER_TEMT); + } else { + /* Not supported yet */ + return -EINVAL; + } + return cy_put_user(result, (unsigned long *) value); +} static int get_modem_info(struct cyclades_port * info, unsigned int *value) @@ -4247,6 +4334,9 @@ cy_ioctl(struct tty_struct *tty, struct file * file, case TIOCSSERIAL: ret_val = set_serial_info(info, (struct serial_struct *) arg); break; + case TIOCSERGETLSR: /* Get line status register */ + ret_val = get_lsr_info(info, (unsigned int *) arg); + break; /* * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change * - mask passed in arg for lines of interest @@ -4937,10 +5027,9 @@ cy_detect_pci(void) i--; continue; } -#else +#endif cy_pci_addr0 = (ulong)ioremap(cy_pci_phys0, CyPCI_Yctl); cy_pci_addr2 = (ulong)ioremap(cy_pci_phys2, CyPCI_Ywin); -#endif #ifdef CY_PCI_DEBUG printk("Cyclom-Y/PCI: relocate winaddr=0x%lx ctladdr=0x%lx\n", @@ -5048,9 +5137,7 @@ cy_detect_pci(void) printk("Cyclades-Z/PCI: found winaddr=0x%lx ctladdr=0x%lx\n", (ulong)cy_pci_phys2, (ulong)cy_pci_phys0); #endif -#if !defined(__alpha__) - cy_pci_addr0 = (ulong)ioremap(cy_pci_phys0, CyPCI_Zctl); -#endif + cy_pci_addr0 = (ulong)ioremap(cy_pci_phys0, CyPCI_Zctl); /* Disable interrupts on the PLX before resetting it */ cy_writew(cy_pci_addr0+0x68, @@ -5078,9 +5165,7 @@ cy_detect_pci(void) request_region(cy_pci_phys1, CyPCI_Zctl, "Cyclades-Z"); if (mailbox == ZE_V1) { -#if !defined(__alpha__) - cy_pci_addr2 = (ulong)ioremap(cy_pci_phys2, CyPCI_Ze_win); -#endif + cy_pci_addr2 = (ulong)ioremap(cy_pci_phys2, CyPCI_Ze_win); if (ZeIndex == NR_CARDS) { printk("Cyclades-Ze/PCI found at 0x%lx ", (ulong)cy_pci_phys2); @@ -5097,9 +5182,7 @@ cy_detect_pci(void) i--; continue; } else { -#if !defined(__alpha__) - cy_pci_addr2 = (ulong)ioremap(cy_pci_phys2, CyPCI_Zwin); -#endif + cy_pci_addr2 = (ulong)ioremap(cy_pci_phys2, CyPCI_Zwin); } #ifdef CY_PCI_DEBUG @@ -5538,6 +5621,7 @@ cy_init(void) info->tco = 0; info->rbpr = 0; info->rco = 0; + info->custom_divisor = 0; info->close_delay = 5*HZ/10; info->closing_wait = CLOSING_WAIT_DELAY; info->icount.cts = info->icount.dsr = @@ -5596,6 +5680,7 @@ cy_init(void) info->cor3 = 0x08; /* _very_ small rcv threshold */ info->cor4 = 0; info->cor5 = 0; + info->custom_divisor = 0; info->close_delay = 5*HZ/10; info->closing_wait = CLOSING_WAIT_DELAY; info->icount.cts = info->icount.dsr = diff --git a/drivers/char/dn_keyb.c b/drivers/char/dn_keyb.c index 8d8766b85..980ee13ba 100644 --- a/drivers/char/dn_keyb.c +++ b/drivers/char/dn_keyb.c @@ -51,8 +51,7 @@ static u_char *shadow_buf=&debug_buf2[0]; static short debug_buf_count=0; static int debug_buf_overrun=0,debug_timer_running=0; static unsigned long debug_buffer_updated=0; -static struct timer_list debug_keyb_timer = { NULL, NULL, 0, 0, - debug_keyb_timer_handler }; +static struct timer_list debug_keyb_timer = { function: debug_keyb_timer_handler }; #endif static u_short dnplain_map[NR_KEYS] __initdata = { diff --git a/drivers/char/drm/ffb_drv.c b/drivers/char/drm/ffb_drv.c index a1ab1f279..5ad4885bf 100644 --- a/drivers/char/drm/ffb_drv.c +++ b/drivers/char/drm/ffb_drv.c @@ -6,6 +6,8 @@ #include "drmP.h" +#include <linux/sched.h> +#include <linux/smp_lock.h> #include <asm/oplib.h> #include <asm/upa.h> @@ -44,6 +46,7 @@ extern int ffb_rmctx(struct inode *, struct file *, unsigned int, unsigned long) extern int ffb_context_switch(drm_device_t *, int, int); static struct file_operations ffb_fops = { + owner: THIS_MODULE, open: ffb_open, flush: drm_flush, release: ffb_release, @@ -501,7 +504,6 @@ static int ffb_open(struct inode *inode, struct file *filp) DRM_DEBUG("open_count = %d\n", dev->open_count); ret = drm_open_helper(inode, filp, dev); if (!ret) { - MOD_INC_USE_COUNT; atomic_inc(&dev->total_open); spin_lock(&dev->count_lock); if (!dev->open_count++) { @@ -517,9 +519,11 @@ static int ffb_open(struct inode *inode, struct file *filp) static int ffb_release(struct inode *inode, struct file *filp) { drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + drm_device_t *dev; int ret = 0; + lock_kernel(); + dev = priv->dev; DRM_DEBUG("open_count = %d\n", dev->open_count); if (dev->lock.hw_lock != NULL && _DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) @@ -541,7 +545,6 @@ static int ffb_release(struct inode *inode, struct file *filp) ret = drm_release(inode, filp); if (!ret) { - MOD_DEC_USE_COUNT; atomic_inc(&dev->total_close); spin_lock(&dev->count_lock); if (!--dev->open_count) { @@ -550,14 +553,18 @@ static int ffb_release(struct inode *inode, struct file *filp) atomic_read(&dev->ioctl_count), dev->blocked); spin_unlock(&dev->count_lock); + unlock_kernel(); return -EBUSY; } spin_unlock(&dev->count_lock); - return ffb_takedown(dev); + ret = ffb_takedown(dev); + unlock_kernel(); + return ret; } spin_unlock(&dev->count_lock); } + unlock_kernel(); return ret; } @@ -756,6 +763,7 @@ static int ffb_mmap(struct file *filp, struct vm_area_struct *vma) DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n", vma->vm_start, vma->vm_end, VM_OFFSET(vma)); + lock_kernel(); minor = MINOR(filp->f_dentry->d_inode->i_rdev); ffb_priv = NULL; for (i = 0; i < ffb_dev_table_size; i++) { @@ -763,13 +771,15 @@ static int ffb_mmap(struct file *filp, struct vm_area_struct *vma) if (ffb_priv->miscdev.minor == minor) break; } - if (i >= ffb_dev_table_size) + if (i >= ffb_dev_table_size) { + unlock_kernel(); return -EINVAL; - + } /* We don't support/need dma mappings, so... */ - if (!VM_OFFSET(vma)) + if (!VM_OFFSET(vma)) { + unlock_kernel(); return -EINVAL; - + } for (i = 0; i < dev->map_count; i++) { unsigned long off; @@ -781,16 +791,19 @@ static int ffb_mmap(struct file *filp, struct vm_area_struct *vma) break; } - if (i >= dev->map_count) + if (i >= dev->map_count) { + unlock_kernel(); return -EINVAL; - + } if (!map || - ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) + ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) { + unlock_kernel(); return -EPERM; - - if (map->size != (vma->vm_end - vma->vm_start)) + } + if (map->size != (vma->vm_end - vma->vm_start)) { + unlock_kernel(); return -EINVAL; - + } /* Set read-only attribute before mappings are created * so it works for fb/reg maps too. */ @@ -813,9 +826,10 @@ static int ffb_mmap(struct file *filp, struct vm_area_struct *vma) if (io_remap_page_range(vma->vm_start, ffb_priv->card_phys_base + VM_OFFSET(vma), vma->vm_end - vma->vm_start, - vma->vm_page_prot, 0)) + vma->vm_page_prot, 0)) { + unlock_kernel(); return -EAGAIN; - + } vma->vm_ops = &drm_vm_ops; break; case _DRM_SHM: @@ -828,8 +842,10 @@ static int ffb_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_flags |= VM_LOCKED; break; default: + unlock_kernel(); return -EINVAL; /* This should never happen. */ }; + unlock_kernel(); vma->vm_flags |= VM_LOCKED | VM_SHM; /* Don't swap */ diff --git a/drivers/char/drm/gamma_drv.c b/drivers/char/drm/gamma_drv.c index 7e0d6e53e..8809d1810 100644 --- a/drivers/char/drm/gamma_drv.c +++ b/drivers/char/drm/gamma_drv.c @@ -29,6 +29,8 @@ */ #include <linux/config.h> +#include <linux/sched.h> +#include <linux/smp_lock.h> #include "drmP.h" #include "gamma_drv.h" EXPORT_SYMBOL(gamma_init); @@ -44,14 +46,15 @@ EXPORT_SYMBOL(gamma_cleanup); static drm_device_t gamma_device; static struct file_operations gamma_fops = { - open: gamma_open, - flush: drm_flush, - release: gamma_release, - ioctl: gamma_ioctl, - mmap: drm_mmap, - read: drm_read, - fasync: drm_fasync, - poll: drm_poll, + owner: THIS_MODULE, + open: gamma_open, + flush: drm_flush, + release: gamma_release, + ioctl: gamma_ioctl, + mmap: drm_mmap, + read: drm_read, + fasync: drm_fasync, + poll: drm_poll, }; static struct miscdevice gamma_misc = { @@ -407,7 +410,6 @@ int gamma_open(struct inode *inode, struct file *filp) DRM_DEBUG("open_count = %d\n", dev->open_count); if (!(retcode = drm_open_helper(inode, filp, dev))) { - MOD_INC_USE_COUNT; atomic_inc(&dev->total_open); spin_lock(&dev->count_lock); if (!dev->open_count++) { @@ -422,12 +424,13 @@ int gamma_open(struct inode *inode, struct file *filp) int gamma_release(struct inode *inode, struct file *filp) { drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + drm_device_t *dev; int retcode = 0; + lock_kernel(); + dev = priv->dev; DRM_DEBUG("open_count = %d\n", dev->open_count); if (!(retcode = drm_release(inode, filp))) { - MOD_DEC_USE_COUNT; atomic_inc(&dev->total_close); spin_lock(&dev->count_lock); if (!--dev->open_count) { @@ -436,13 +439,17 @@ int gamma_release(struct inode *inode, struct file *filp) atomic_read(&dev->ioctl_count), dev->blocked); spin_unlock(&dev->count_lock); + unlock_kernel(); return -EBUSY; } spin_unlock(&dev->count_lock); - return gamma_takedown(dev); + retcode = gamma_takedown(dev); + unlock_kernel(); + return retcode; } spin_unlock(&dev->count_lock); } + unlock_kernel(); return retcode; } diff --git a/drivers/char/drm/tdfx_drv.c b/drivers/char/drm/tdfx_drv.c index 23c9c55bf..b0c41c93c 100644 --- a/drivers/char/drm/tdfx_drv.c +++ b/drivers/char/drm/tdfx_drv.c @@ -30,6 +30,8 @@ */ #include <linux/config.h> +#include <linux/sched.h> +#include <linux/smp_lock.h> #include "drmP.h" #include "tdfx_drv.h" @@ -44,6 +46,7 @@ static drm_device_t tdfx_device; drm_ctx_t tdfx_res_ctx; static struct file_operations tdfx_fops = { + owner: THIS_MODULE, open: tdfx_open, flush: drm_flush, release: tdfx_release, @@ -343,7 +346,6 @@ int tdfx_open(struct inode *inode, struct file *filp) DRM_DEBUG("open_count = %d\n", dev->open_count); if (!(retcode = drm_open_helper(inode, filp, dev))) { - MOD_INC_USE_COUNT; atomic_inc(&dev->total_open); spin_lock(&dev->count_lock); if (!dev->open_count++) { @@ -358,12 +360,13 @@ int tdfx_open(struct inode *inode, struct file *filp) int tdfx_release(struct inode *inode, struct file *filp) { drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; + drm_device_t *dev; int retcode = 0; + lock_kernel(); + dev = priv->dev; DRM_DEBUG("open_count = %d\n", dev->open_count); if (!(retcode = drm_release(inode, filp))) { - MOD_DEC_USE_COUNT; atomic_inc(&dev->total_close); spin_lock(&dev->count_lock); if (!--dev->open_count) { @@ -372,13 +375,17 @@ int tdfx_release(struct inode *inode, struct file *filp) atomic_read(&dev->ioctl_count), dev->blocked); spin_unlock(&dev->count_lock); + unlock_kernel(); return -EBUSY; } spin_unlock(&dev->count_lock); - return tdfx_takedown(dev); + retcode = tdfx_takedown(dev); + unlock_kernel(); + return retcode; } spin_unlock(&dev->count_lock); } + unlock_kernel(); return retcode; } diff --git a/drivers/char/drm/vm.c b/drivers/char/drm/vm.c index b4c4c5bbf..b6595c88c 100644 --- a/drivers/char/drm/vm.c +++ b/drivers/char/drm/vm.c @@ -144,7 +144,6 @@ void drm_vm_open(struct vm_area_struct *vma) DRM_DEBUG("0x%08lx,0x%08lx\n", vma->vm_start, vma->vm_end - vma->vm_start); atomic_inc(&dev->vma_count); - MOD_INC_USE_COUNT; #if DRM_DEBUG_CODE vma_entry = drm_alloc(sizeof(*vma_entry), DRM_MEM_VMAS); @@ -169,7 +168,6 @@ void drm_vm_close(struct vm_area_struct *vma) DRM_DEBUG("0x%08lx,0x%08lx\n", vma->vm_start, vma->vm_end - vma->vm_start); - MOD_DEC_USE_COUNT; atomic_dec(&dev->vma_count); #if DRM_DEBUG_CODE diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c index 6fe41e118..0ada290ac 100644 --- a/drivers/char/dsp56k.c +++ b/drivers/char/dsp56k.c @@ -35,6 +35,7 @@ #include <linux/mm.h> #include <linux/init.h> #include <linux/devfs_fs_kernel.h> +#include <linux/smp_lock.h> #include <asm/segment.h> #include <asm/atarihw.h> @@ -483,7 +484,9 @@ static int dsp56k_release(struct inode *inode, struct file *file) { case DSP56K_DEV_56001: + lock_kernel(); dsp56k.in_use = 0; + unlock_kernel(); break; default: diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c index 475e1d052..867a7fcec 100644 --- a/drivers/char/dtlk.c +++ b/drivers/char/dtlk.c @@ -69,6 +69,7 @@ #include <linux/poll.h> /* for POLLIN, etc. */ #include <linux/dtlk.h> /* local header file for DoubleTalk values */ #include <linux/devfs_fs_kernel.h> +#include <linux/smp_lock.h> #ifdef TRACING #define TRACE_TEXT(str) printk(str); @@ -333,7 +334,9 @@ static int dtlk_release(struct inode *inode, struct file *file) } TRACE_RET; + lock_kernel(); del_timer(&dtlk_timer); + unlock_kernel(); return 0; } diff --git a/drivers/char/ftape/zftape/zftape-init.c b/drivers/char/ftape/zftape/zftape-init.c index fd81f24ca..a57e3abc1 100644 --- a/drivers/char/ftape/zftape/zftape-init.c +++ b/drivers/char/ftape/zftape/zftape-init.c @@ -35,15 +35,11 @@ #endif #include <linux/fcntl.h> #include <linux/wrapper.h> +#include <linux/smp_lock.h> #include <linux/devfs_fs_kernel.h> #include <linux/zftape.h> -#if LINUX_VERSION_CODE >=KERNEL_VER(2,1,16) #include <linux/init.h> -#else -#define __initdata -#define __initfunc(__arg) __arg -#endif #include "../zftape/zftape-init.h" #include "../zftape/zftape-read.h" @@ -56,7 +52,6 @@ char zft_src[] __initdata = "$Source: /homes/cvs/ftape-stacked/ftape/zftape/zfta char zft_rev[] __initdata = "$Revision: 1.8 $"; char zft_dat[] __initdata = "$Date: 1997/11/06 00:48:56 $"; -#if LINUX_VERSION_CODE >= KERNEL_VER(2,1,18) MODULE_AUTHOR("(c) 1996, 1997 Claus-Justus Heine " "(claus@momo.math.rwth-aachen.de)"); MODULE_DESCRIPTION(ZFTAPE_VERSION " - " @@ -64,7 +59,6 @@ MODULE_DESCRIPTION(ZFTAPE_VERSION " - " "Support for QIC-113 compatible volume table " "and builtin compression (lzrw3 algorithm)"); MODULE_SUPPORTED_DEVICE("char-major-27"); -#endif /* Global vars. */ @@ -90,38 +84,18 @@ static sigset_t orig_sigmask; */ static int zft_open (struct inode *ino, struct file *filep); -#if LINUX_VERSION_CODE >= KERNEL_VER(2,1,31) static int zft_close(struct inode *ino, struct file *filep); -#else -static void zft_close(struct inode *ino, struct file *filep); -#endif static int zft_ioctl(struct inode *ino, struct file *filep, unsigned int command, unsigned long arg); -#if LINUX_VERSION_CODE >= KERNEL_VER(2,1,56) static int zft_mmap(struct file *filep, struct vm_area_struct *vma); -#else -static int zft_mmap(struct inode *ino, struct file *filep, - struct vm_area_struct *vma); -#endif -#if LINUX_VERSION_CODE >= KERNEL_VER(2,1,60) static ssize_t zft_read (struct file *fp, char *buff, size_t req_len, loff_t *ppos); static ssize_t zft_write(struct file *fp, const char *buff, size_t req_len, loff_t *ppos); -#elif LINUX_VERSION_CODE >= KERNEL_VER(2,1,0) -static long zft_read (struct inode *ino, struct file *fp, char *buff, - unsigned long req_len); -static long zft_write(struct inode *ino, struct file *fp, const char *buff, - unsigned long req_len); -#else -static int zft_read (struct inode *ino, struct file *fp, char *buff, - int req_len); -static int zft_write(struct inode *ino, struct file *fp, const char *buff, - int req_len); -#endif static struct file_operations zft_cdev = { + owner: THIS_MODULE, read: zft_read, write: zft_write, ioctl: zft_ioctl, @@ -137,15 +111,6 @@ static int zft_open(struct inode *ino, struct file *filep) int result; TRACE_FUN(ft_t_flow); -#if LINUX_VERSION_CODE < KERNEL_VER(2,1,18) - if (!MOD_IN_USE) { - MOD_INC_USE_COUNT; /* lock module in memory */ - } -#else - MOD_INC_USE_COUNT; /* sets MOD_VISITED and MOD_USED_ONCE, - * locking is done with can_unload() - */ -#endif TRACE(ft_t_flow, "called for minor %d", MINOR(ino->i_rdev)); if (busy_flag) { TRACE_ABORT(-EBUSY, ft_t_warn, "failed: already busy"); @@ -155,11 +120,6 @@ static int zft_open(struct inode *ino, struct file *filep) > FTAPE_SEL_D) { busy_flag = 0; -#if defined(MODULE) && LINUX_VERSION_CODE < KERNEL_VER(2,1,18) - if (!zft_dirty()) { - MOD_DEC_USE_COUNT; /* unlock module in memory */ - } -#endif TRACE_ABORT(-ENXIO, ft_t_err, "failed: illegal unit nr"); } orig_sigmask = current->blocked; @@ -168,11 +128,6 @@ static int zft_open(struct inode *ino, struct file *filep) if (result < 0) { current->blocked = orig_sigmask; /* restore mask */ busy_flag = 0; -#if defined(MODULE) && LINUX_VERSION_CODE < KERNEL_VER(2,1,18) - if (!zft_dirty()) { - MOD_DEC_USE_COUNT; /* unlock module in memory */ - } -#endif TRACE_ABORT(result, ft_t_err, "_ftape_open failed"); } else { /* Mask signals that will disturb proper operation of the @@ -191,13 +146,11 @@ static int zft_close(struct inode *ino, struct file *filep) int result; TRACE_FUN(ft_t_flow); + lock_kernel(); if (!busy_flag || MINOR(ino->i_rdev) != zft_unit) { TRACE(ft_t_err, "failed: not busy or wrong unit"); -#if LINUX_VERSION_CODE >= KERNEL_VER(2,1,31) + unlock_kernel(); TRACE_EXIT 0; -#else - TRACE_EXIT; /* keep busy_flag !(?) */ -#endif } sigfillset(¤t->blocked); result = _zft_close(); @@ -206,16 +159,8 @@ static int zft_close(struct inode *ino, struct file *filep) } current->blocked = orig_sigmask; /* restore before open state */ busy_flag = 0; -#if defined(MODULE) && LINUX_VERSION_CODE < KERNEL_VER(2,1,18) - if (!zft_dirty()) { - MOD_DEC_USE_COUNT; /* unlock module in memory */ - } -#endif -#if LINUX_VERSION_CODE >= KERNEL_VER(2,1,31) + unlock_kernel(); TRACE_EXIT 0; -#else - TRACE_EXIT; -#endif } /* Ioctl for floppy tape device @@ -241,24 +186,14 @@ static int zft_ioctl(struct inode *ino, struct file *filep, /* Ioctl for floppy tape device */ -#if LINUX_VERSION_CODE >= KERNEL_VER(2,1,56) static int zft_mmap(struct file *filep, struct vm_area_struct *vma) -#else -static int zft_mmap(struct inode *ino, - struct file *filep, - struct vm_area_struct *vma) -#endif { int result = -EIO; sigset_t old_sigmask; TRACE_FUN(ft_t_flow); if (!busy_flag || -#if LINUX_VERSION_CODE >= KERNEL_VER(2,1,56) MINOR(filep->f_dentry->d_inode->i_rdev) != zft_unit || -#else - MINOR(ino->i_rdev) != zft_unit || -#endif ft_failure) { TRACE_ABORT(-EIO, ft_t_err, @@ -266,34 +201,26 @@ static int zft_mmap(struct inode *ino, } old_sigmask = current->blocked; /* save mask */ sigfillset(¤t->blocked); + lock_kernel(); if ((result = ftape_mmap(vma)) >= 0) { #ifndef MSYNC_BUG_WAS_FIXED static struct vm_operations_struct dummy = { NULL, }; vma->vm_ops = &dummy; #endif } + unlock_kernel(); current->blocked = old_sigmask; /* restore mask */ TRACE_EXIT result; } /* Read from floppy tape device */ -#if LINUX_VERSION_CODE >= KERNEL_VER(2,1,60) static ssize_t zft_read(struct file *fp, char *buff, size_t req_len, loff_t *ppos) -#elif LINUX_VERSION_CODE >= KERNEL_VER(2,1,0) -static long zft_read(struct inode *ino, struct file *fp, char *buff, - unsigned long req_len) -#else -static int zft_read(struct inode *ino, struct file *fp, char *buff, - int req_len) -#endif { int result = -EIO; sigset_t old_sigmask; -#if LINUX_VERSION_CODE >= KERNEL_VER(2,1,60) struct inode *ino = fp->f_dentry->d_inode; -#endif TRACE_FUN(ft_t_flow); TRACE(ft_t_data_flow, "called with count: %ld", (unsigned long)req_len); @@ -311,22 +238,12 @@ static int zft_read(struct inode *ino, struct file *fp, char *buff, /* Write to tape device */ -#if LINUX_VERSION_CODE >= KERNEL_VER(2,1,60) static ssize_t zft_write(struct file *fp, const char *buff, size_t req_len, loff_t *ppos) -#elif LINUX_VERSION_CODE >= KERNEL_VER(2,1,0) -static long zft_write(struct inode *ino, struct file *fp, const char *buff, - unsigned long req_len) -#else -static int zft_write(struct inode *ino, struct file *fp, const char *buff, - int req_len) -#endif { int result = -EIO; sigset_t old_sigmask; -#if LINUX_VERSION_CODE >= KERNEL_VER(2,1,60) struct inode *ino = fp->f_dentry->d_inode; -#endif TRACE_FUN(ft_t_flow); TRACE(ft_t_flow, "called with count: %ld", (unsigned long)req_len); @@ -470,9 +387,6 @@ KERN_INFO &zft_cdev, NULL); } -#if LINUX_VERSION_CODE < KERNEL_VER(2,1,18) - register_symtab(&zft_symbol_table); /* add global zftape symbols */ -#endif #ifdef CONFIG_ZFT_COMPRESSOR (void)zft_compressor_init(); #endif @@ -484,24 +398,20 @@ KERN_INFO #ifdef MODULE -#if LINUX_VERSION_CODE >= KERNEL_VER(2,1,18) /* Called by modules package before trying to unload the module */ static int can_unload(void) { - return (zft_dirty() || busy_flag) ? -EBUSY : 0; + return (GET_USE_COUNT(THIS_MODULE)||zft_dirty()||busy_flag)?-EBUSY:0; } -#endif /* Called by modules package when installing the driver */ int init_module(void) { -#if LINUX_VERSION_CODE >= KERNEL_VER(2,1,18) if (!mod_member_present(&__this_module, can_unload)) { return -EBUSY; } __this_module.can_unload = can_unload; -#endif return zft_init(); } diff --git a/drivers/char/h8.c b/drivers/char/h8.c index acc898cb8..8a4b4de51 100644 --- a/drivers/char/h8.c +++ b/drivers/char/h8.c @@ -106,16 +106,6 @@ static int h8_monitor_timer_active = 0; static char driver_version[] = "X0.0";/* no spaces */ -static struct file_operations h8_fops = { - /* twelve lines of crap^WNULLs were here */ -}; - -static struct miscdevice h8_device = { - H8_MINOR_DEV, - "h8", - &h8_fops -}; - union intr_buf intrbuf; int intr_buf_ptr; union intr_buf xx; @@ -297,7 +287,6 @@ static void h8_intr(int irq, void *dev_id, struct pt_regs *regs) static void __exit h8_cleanup (void) { remove_proc_entry("driver/h8", NULL); - misc_deregister(&h8_device); release_region(h8_base, 8); free_irq(h8_irq, NULL); } @@ -313,7 +302,6 @@ static int __init h8_init(void) create_proc_info_entry("driver/h8", 0, NULL, h8_get_info); - misc_register(&h8_device); request_region(h8_base, 8, "h8"); h8_alloc_queues(); diff --git a/drivers/char/i2c-parport.c b/drivers/char/i2c-parport.c index 8304a6ab5..00b574f60 100644 --- a/drivers/char/i2c-parport.c +++ b/drivers/char/i2c-parport.c @@ -75,7 +75,7 @@ static void i2c_parport_attach(struct parport *port) struct parport_i2c_bus *b = kmalloc(sizeof(struct parport_i2c_bus), GFP_KERNEL); b->i2c = parport_i2c_bus_template; - b->i2c.data = port; + b->i2c.data = parport_get_port (port); strncpy(b->i2c.name, port->name, 32); spin_lock(&bus_list_lock); b->next = bus_list; diff --git a/drivers/char/i810_rng.c b/drivers/char/i810_rng.c index 905d8e8cd..7a6718c02 100644 --- a/drivers/char/i810_rng.c +++ b/drivers/char/i810_rng.c @@ -165,6 +165,7 @@ #include <linux/random.h> #include <linux/sysctl.h> #include <linux/miscdevice.h> +#include <linux/smp_lock.h> #include <asm/io.h> #include <asm/uaccess.h> @@ -626,12 +627,16 @@ err_out: static int rng_dev_release (struct inode *inode, struct file *filp) { - if (rng_enable(0) != 0) + lock_kernel(); + if (rng_enable(0) != 0) { + unlock_kernel(); return -EIO; + } spin_lock_bh (&rng_lock); rng_open = 0; spin_unlock_bh (&rng_lock); + unlock_kernel(); return 0; } diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c index 449bd2f76..6fbfe22df 100644 --- a/drivers/char/ip2main.c +++ b/drivers/char/ip2main.c @@ -329,8 +329,7 @@ static long bh_counter = 0; * selected, the board is serviced periodically to see if anything needs doing. */ #define POLL_TIMEOUT (jiffies + 1) -static struct timer_list PollTimer = { {NULL, NULL}, 0, 0, ip2_poll }; -// next, prev, expires,data, func() +static struct timer_list PollTimer = { function: ip2_poll }; static char TimerOn = 0; #ifdef IP2DEBUG_TRACE diff --git a/drivers/char/joystick/Config.in b/drivers/char/joystick/Config.in index 1547e5f38..b020f1728 100644 --- a/drivers/char/joystick/Config.in +++ b/drivers/char/joystick/Config.in @@ -7,9 +7,7 @@ comment 'Joysticks' tristate 'Joystick support' CONFIG_JOYSTICK if [ "$CONFIG_JOYSTICK" != "n" ]; then - - define_tristate CONFIG_USB $CONFIG_JOYSTICK - define_tristate CONFIG_INPUT_JOYDEV $CONFIG_JOYSTICK + define_tristate CONFIG_INPUT_JOYDEV $CONFIG_JOYSTICK comment 'Game port support' dep_tristate ' ns558 gameports' CONFIG_INPUT_NS558 $CONFIG_JOYSTICK diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 5e212af34..a602e3b3b 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -119,6 +119,7 @@ #include <linux/kernel.h> #include <linux/major.h> #include <linux/sched.h> +#include <linux/smp_lock.h> #include <linux/devfs_fs_kernel.h> #include <linux/malloc.h> #include <linux/fcntl.h> @@ -407,9 +408,11 @@ static int lp_release(struct inode * inode, struct file * file) { unsigned int minor = MINOR(inode->i_rdev); + lock_kernel(); kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE); lp_table[minor].lp_buffer = NULL; LP_F(minor) &= ~LP_BUSY; + unlock_kernel(); return 0; } diff --git a/drivers/char/mixcomwd.c b/drivers/char/mixcomwd.c index 6352d6f73..1daff0de7 100644 --- a/drivers/char/mixcomwd.c +++ b/drivers/char/mixcomwd.c @@ -43,6 +43,7 @@ #include <linux/watchdog.h> #include <linux/reboot.h> #include <linux/init.h> +#include <linux/smp_lock.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -100,9 +101,11 @@ static int mixcomwd_open(struct inode *inode, struct file *file) static int mixcomwd_release(struct inode *inode, struct file *file) { + lock_kernel(); #ifndef CONFIG_WATCHDOG_NOWAYOUT if(mixcomwd_timer_alive) { printk(KERN_ERR "mixcomwd: release called while internal timer alive"); + unlock_kernel(); return -EBUSY; } init_timer(&mixcomwd_timer); @@ -114,6 +117,7 @@ static int mixcomwd_release(struct inode *inode, struct file *file) #endif clear_bit(0,&mixcomwd_opened); + unlock_kernel(); return 0; } diff --git a/drivers/char/msp3400.c b/drivers/char/msp3400.c index dce40c671..5c30ca2f0 100644 --- a/drivers/char/msp3400.c +++ b/drivers/char/msp3400.c @@ -1265,8 +1265,10 @@ msp3400c_mixer_release(struct inode *inode, struct file *file) { struct i2c_client *client = file->private_data; + lock_kernel(); if (client->adapter->dec_use) client->adapter->dec_use(client->adapter); + unlock_kernel(); return 0; } diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index a32cd18df..6fa72fc8e 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -34,6 +34,8 @@ #include <linux/module.h> #include <linux/config.h> +#include <linux/sched.h> +#include <linux/smp_lock.h> #define PC 1 #define ATARI 2 @@ -341,11 +343,13 @@ static int nvram_open( struct inode *inode, struct file *file ) static int nvram_release( struct inode *inode, struct file *file ) { + lock_kernel(); nvram_open_cnt--; if (file->f_flags & O_EXCL) nvram_open_mode &= ~NVRAM_EXCL; if (file->f_mode & 2) nvram_open_mode &= ~NVRAM_WRITE; + unlock_kernel(); return( 0 ); } diff --git a/drivers/char/pc110pad.c b/drivers/char/pc110pad.c index dfef66e39..556d8630e 100644 --- a/drivers/char/pc110pad.c +++ b/drivers/char/pc110pad.c @@ -41,6 +41,7 @@ #include <linux/poll.h> #include <linux/ioport.h> #include <linux/interrupt.h> +#include <linux/smp_lock.h> #include <asm/signal.h> #include <asm/io.h> @@ -583,10 +584,11 @@ static int fasync_pad(int fd, struct file *filp, int on) static int close_pad(struct inode * inode, struct file * file) { + lock_kernel(); fasync_pad(-1, file, 0); - if (--active) - return 0; - outb(0x30, current_params.io+2); /* switch off digitiser */ + if (!--active) + outb(0x30, current_params.io+2); /* switch off digitiser */ + unlock_kernel(); return 0; } diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c index c265b927f..34e13c97f 100644 --- a/drivers/char/pc_keyb.c +++ b/drivers/char/pc_keyb.c @@ -31,6 +31,7 @@ #include <linux/miscdevice.h> #include <linux/malloc.h> #include <linux/kbd_kern.h> +#include <linux/smp_lock.h> #include <asm/keyboard.h> #include <asm/bitops.h> @@ -872,12 +873,16 @@ static int fasync_aux(int fd, struct file *filp, int on) static int release_aux(struct inode * inode, struct file * file) { + lock_kernel(); fasync_aux(-1, file, 0); - if (--aux_count) + if (--aux_count) { + unlock_kernel(); return 0; + } kbd_write_cmd(AUX_INTS_OFF); /* Disable controller ints */ kbd_write_command_w(KBD_CCMD_MOUSE_DISABLE); aux_free_irq(AUX_DEV); + unlock_kernel(); return 0; } diff --git a/drivers/char/pcmcia/Config.in b/drivers/char/pcmcia/Config.in index 766fdd1d0..8baf1932e 100644 --- a/drivers/char/pcmcia/Config.in +++ b/drivers/char/pcmcia/Config.in @@ -3,12 +3,12 @@ # if [ "$CONFIG_SERIAL" = "n" ]; then - define_bool CONFIG_PCMCIA_SERIAL n + define_tristate CONFIG_PCMCIA_SERIAL n else if [ "$CONFIG_SERIAL" = "m" -o "$CONFIG_PCMCIA" = "m" ]; then - define_bool CONFIG_PCMCIA_SERIAL m + define_tristate CONFIG_PCMCIA_SERIAL m else - define_bool CONFIG_PCMCIA_SERIAL y + define_tristate CONFIG_PCMCIA_SERIAL y fi fi diff --git a/drivers/char/pcwd.c b/drivers/char/pcwd.c index b85a168de..cb197afc5 100644 --- a/drivers/char/pcwd.c +++ b/drivers/char/pcwd.c @@ -63,6 +63,7 @@ #include <linux/init.h> #include <linux/proc_fs.h> #include <linux/spinlock.h> +#include <linux/smp_lock.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -451,6 +452,7 @@ static int pcwd_close(struct inode *ino, struct file *filep) { if (MINOR(ino->i_rdev)==WATCHDOG_MINOR) { + lock_kernel(); is_open = 0; #ifndef CONFIG_WATCHDOG_NOWAYOUT /* Disable the board */ @@ -460,6 +462,7 @@ static int pcwd_close(struct inode *ino, struct file *filep) outb_p(0xA5, current_readport + 3); spin_unlock(&io_lock); } + unlock_kernel(); #endif } return 0; diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index 4e2be3c8b..07877c1a7 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -52,6 +52,7 @@ #include <linux/poll.h> #include <asm/uaccess.h> #include <linux/ppdev.h> +#include <linux/smp_lock.h> #define PP_VERSION "ppdev: user-space parallel port driver" #define CHRDEV "ppdev" @@ -83,64 +84,6 @@ struct pp_struct { /* ROUND_UP macro from fs/select.c */ #define ROUND_UP(x,y) (((x)+(y)-1)/(y)) -struct pp_port_list_struct { - struct parport *port; - struct pp_port_list_struct *next; -}; -static struct pp_port_list_struct *pp_port_list; -static DECLARE_MUTEX(pp_port_list_lock); - -/* pp_attach and pp_detach are for keeping a list of currently - * available ports, held under a mutex. We do this rather than - * using parport_enumerate because it stops a load of races. - */ - -static void pp_attach (struct parport *port) -{ - struct pp_port_list_struct *add; - - add = kmalloc (sizeof (struct pp_port_list_struct), GFP_KERNEL); - if (!add) { - printk (KERN_WARNING CHRDEV ": memory squeeze\n"); - return; - } - - add->port = port; - down (&pp_port_list_lock); - add->next = pp_port_list; - pp_port_list = add; - up (&pp_port_list_lock); -} - -static void pp_detach (struct parport *port) -{ - struct pp_port_list_struct *del; - - down (&pp_port_list_lock); - del = pp_port_list; - if (del->port == port) - pp_port_list = del->next; - else { - struct pp_port_list_struct *prev; - do { - prev = del; - del = del->next; - } while (del && del->port != port); - if (del) - prev->next = del->next; - } - up (&pp_port_list_lock); - - if (del) - kfree (del); -} - -static struct parport_driver ppdev_driver = { - name: CHRDEV, - attach: pp_attach, - detach: pp_detach -}; - static inline void pp_enable_irq (struct pp_struct *pp) { struct parport *port = pp->pdev->port; @@ -274,7 +217,7 @@ static void pp_irq (int irq, void * private, struct pt_regs * unused) static int register_device (int minor, struct pp_struct *pp) { - struct pp_port_list_struct *ports; + struct parport *port; struct pardevice * pdev = NULL; char *name; int fl; @@ -285,23 +228,17 @@ static int register_device (int minor, struct pp_struct *pp) sprintf (name, CHRDEV "%x", minor); - down (&pp_port_list_lock); - ports = pp_port_list; - while (ports && ports->port->number != minor) - ports = ports->next; - if (ports->port) { - fl = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0; - pdev = parport_register_device (ports->port, name, NULL, - NULL, pp_irq, fl, pp); - } - up (&pp_port_list_lock); - - if (!ports->port) { + port = parport_find_number (minor); + if (!port) { printk (KERN_WARNING "%s: no associated port!\n", name); kfree (name); return -ENXIO; } + fl = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0; + pdev = parport_register_device (port, name, NULL, + NULL, pp_irq, fl, pp); + parport_put_port (port); if (!pdev) { printk (KERN_WARNING "%s: failed to register device!\n", name); @@ -595,6 +532,7 @@ static int pp_release (struct inode * inode, struct file * file) unsigned int minor = MINOR (inode->i_rdev); struct pp_struct *pp = file->private_data; + lock_kernel(); if (pp->pdev && pp->pdev->port->ieee1284.mode != IEEE1284_MODE_COMPAT) { if (!(pp->flags & PP_CLAIMED)) { parport_claim_or_block (pp->pdev); @@ -620,6 +558,7 @@ static int pp_release (struct inode * inode, struct file * file) printk (KERN_DEBUG CHRDEV "%x: unregistered pardevice\n", minor); } + unlock_kernel(); kfree (pp); @@ -654,10 +593,6 @@ static devfs_handle_t devfs_handle = NULL; static int __init ppdev_init (void) { - if (parport_register_driver (&ppdev_driver)) { - printk (KERN_WARNING CHRDEV ": unable to register driver\n"); - return -EIO; - } if (devfs_register_chrdev (PP_MAJOR, CHRDEV, &pp_fops)) { printk (KERN_WARNING CHRDEV ": unable to get major %d\n", PP_MAJOR); @@ -678,7 +613,6 @@ static void __exit ppdev_cleanup (void) /* Clean up all parport stuff */ devfs_unregister (devfs_handle); devfs_unregister_chrdev (PP_MAJOR, CHRDEV); - parport_unregister_driver (&ppdev_driver); } module_init(ppdev_init); diff --git a/drivers/char/qpmouse.c b/drivers/char/qpmouse.c index 6fd5a3d65..4db93b1fb 100644 --- a/drivers/char/qpmouse.c +++ b/drivers/char/qpmouse.c @@ -36,6 +36,7 @@ #include <linux/random.h> #include <linux/poll.h> #include <linux/init.h> +#include <linux/smp_lock.h> #include <asm/io.h> #include <asm/uaccess.h> @@ -141,6 +142,7 @@ static int release_qp(struct inode * inode, struct file * file) { unsigned char status; + lock_kernel(); fasync_qp(-1, file, 0); if (!--qp_count) { if (!poll_qp_status()) @@ -151,6 +153,7 @@ static int release_qp(struct inode * inode, struct file * file) printk("Warning: Mouse device busy in release_qp()\n"); free_irq(QP_IRQ, NULL); } + unlock_kernel(); return 0; } diff --git a/drivers/char/raw.c b/drivers/char/raw.c index a3159c836..4b1281b50 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -14,6 +14,7 @@ #include <linux/blkdev.h> #include <linux/raw.h> #include <linux/capability.h> +#include <linux/smp_lock.h> #include <asm/uaccess.h> #define dprintk(x...) @@ -126,9 +127,11 @@ int raw_release(struct inode *inode, struct file *filp) struct block_device *bdev; minor = MINOR(inode->i_rdev); + lock_kernel(); bdev = raw_device_bindings[minor]; blkdev_put(bdev, BDEV_RAW); raw_device_inuse[minor]--; + unlock_kernel(); return 0; } diff --git a/drivers/char/sbc60xxwdt.c b/drivers/char/sbc60xxwdt.c index a0bea62c0..813594244 100644 --- a/drivers/char/sbc60xxwdt.c +++ b/drivers/char/sbc60xxwdt.c @@ -66,6 +66,7 @@ #include <linux/malloc.h> #include <linux/ioport.h> #include <linux/fcntl.h> +#include <linux/smp_lock.h> #include <asm/io.h> #include <asm/uaccess.h> #include <asm/system.h> @@ -207,6 +208,7 @@ static int fop_open(struct inode * inode, struct file * file) static int fop_close(struct inode * inode, struct file * file) { + lock_kernel(); if(MINOR(inode->i_rdev) == WATCHDOG_MINOR) { if(wdt_expect_close) @@ -217,6 +219,7 @@ static int fop_close(struct inode * inode, struct file * file) } } wdt_is_open = 0; + unlock_kernel(); return 0; } diff --git a/drivers/char/softdog.c b/drivers/char/softdog.c index a7620dda0..3d1c57907 100644 --- a/drivers/char/softdog.c +++ b/drivers/char/softdog.c @@ -37,6 +37,7 @@ #include <linux/miscdevice.h> #include <linux/watchdog.h> #include <linux/reboot.h> +#include <linux/smp_lock.h> #include <linux/init.h> #include <asm/uaccess.h> @@ -79,7 +80,9 @@ static int softdog_open(struct inode *inode, struct file *file) { if(timer_alive) return -EBUSY; +#ifdef CONFIG_WATCHDOG_NOWAYOUT MOD_INC_USE_COUNT; +#endif /* * Activate timer */ @@ -94,11 +97,12 @@ static int softdog_release(struct inode *inode, struct file *file) * Shut off the timer. * Lock it in if it's a module and we defined ...NOWAYOUT */ + lock_kernel(); #ifndef CONFIG_WATCHDOG_NOWAYOUT del_timer(&watchdog_ticktock); - MOD_DEC_USE_COUNT; #endif timer_alive=0; + unlock_kernel(); return 0; } @@ -146,6 +150,7 @@ static int softdog_ioctl(struct inode *inode, struct file *file, static struct file_operations softdog_fops= { + owner: THIS_MODULE, write: softdog_write, ioctl: softdog_ioctl, open: softdog_open, diff --git a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c index 3ca976b6e..14a42682d 100644 --- a/drivers/char/tpqic02.c +++ b/drivers/char/tpqic02.c @@ -89,6 +89,7 @@ #include <linux/mm.h> #include <linux/malloc.h> #include <linux/init.h> +#include <linux/smp_lock.h> #include <linux/devfs_fs_kernel.h> #include <asm/dma.h> @@ -2411,6 +2412,7 @@ static int qic02_tape_release(struct inode * inode, struct file * filp) { kdev_t dev = inode->i_rdev; + lock_kernel(); if (TP_DIAGS(dev)) { printk("qic02_tape_release: dev=%s\n", kdevname(dev)); @@ -2437,6 +2439,7 @@ static int qic02_tape_release(struct inode * inode, struct file * filp) (void) do_qic_cmd(QCMD_REWIND, TIM_R); } } + unlock_kernel(); return 0; } /* qic02_tape_release */ diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 60a5c41f5..816f385e1 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -1430,7 +1430,9 @@ init_dev_done: static int tty_release(struct inode * inode, struct file * filp) { + lock_kernel(); release_dev(filp); + unlock_kernel(); return 0; } diff --git a/drivers/char/tvmixer.c b/drivers/char/tvmixer.c index 0ef5bbd03..c3db65bae 100644 --- a/drivers/char/tvmixer.c +++ b/drivers/char/tvmixer.c @@ -7,6 +7,7 @@ #include <linux/errno.h> #include <linux/malloc.h> #include <linux/i2c.h> +#include <linux/smp_lock.h> #include <linux/videodev.h> #include <asm/semaphore.h> #include <linux/init.h> @@ -220,13 +221,18 @@ static int tvmixer_open(struct inode *inode, struct file *file) static int tvmixer_release(struct inode *inode, struct file *file) { struct TVMIXER *mix = file->private_data; - struct i2c_client *client = mix->dev; + struct i2c_client *client; - if (NULL == client) + lock_kernel(); + client = mix->dev; + if (NULL == client) { + unlock_kernel(); return -ENODEV; + } if (client->adapter->dec_use) client->adapter->dec_use(client->adapter); + unlock_kernel(); return 0; } diff --git a/drivers/char/videodev.c b/drivers/char/videodev.c index 5103433e1..3657cb518 100644 --- a/drivers/char/videodev.c +++ b/drivers/char/videodev.c @@ -21,6 +21,7 @@ #include <linux/types.h> #include <linux/kernel.h> #include <linux/sched.h> +#include <linux/smp_lock.h> #include <linux/mm.h> #include <linux/string.h> #include <linux/errno.h> @@ -158,11 +159,9 @@ static int video_open(struct inode *inode, struct file *file) if(vfl==NULL) { char modname[20]; - MOD_INC_USE_COUNT; sprintf (modname, "char-major-%d-%d", VIDEO_MAJOR, minor); request_module(modname); vfl=video_device[minor]; - MOD_DEC_USE_COUNT; if (vfl==NULL) return -ENODEV; } @@ -188,10 +187,13 @@ static int video_open(struct inode *inode, struct file *file) static int video_release(struct inode *inode, struct file *file) { - struct video_device *vfl=video_device[MINOR(inode->i_rdev)]; + struct video_device *vfl; + lock_kernel(); + vfl=video_device[MINOR(inode->i_rdev)]; if(vfl->close) vfl->close(vfl); vfl->busy=0; + unlock_kernel(); return 0; } @@ -229,11 +231,15 @@ static int video_ioctl(struct inode *inode, struct file *file, int video_mmap(struct file *file, struct vm_area_struct *vma) { + int ret = -EINVAL; struct video_device *vfl=video_device[MINOR(file->f_dentry->d_inode->i_rdev)]; - if(vfl->mmap) - return vfl->mmap(vfl, (char *)vma->vm_start, + if(vfl->mmap) { + lock_kernel(); + ret = vfl->mmap(vfl, (char *)vma->vm_start, (unsigned long)(vma->vm_end-vma->vm_start)); - return -EINVAL; + unlock_kernel(); + } + return ret; } /* @@ -515,6 +521,7 @@ void video_unregister_device(struct video_device *vfd) static struct file_operations video_fops= { + owner: THIS_MODULE, llseek: video_lseek, read: video_read, write: video_write, diff --git a/drivers/char/wdt.c b/drivers/char/wdt.c index 3ac86bf3a..bde40c589 100644 --- a/drivers/char/wdt.c +++ b/drivers/char/wdt.c @@ -35,6 +35,7 @@ #include <linux/errno.h> #include <linux/kernel.h> #include <linux/sched.h> +#include <linux/smp_lock.h> #include <linux/miscdevice.h> #include <linux/watchdog.h> #include "wd501p.h" @@ -372,6 +373,7 @@ static int wdt_open(struct inode *inode, struct file *file) static int wdt_release(struct inode *inode, struct file *file) { + lock_kernel(); if(MINOR(inode->i_rdev)==WATCHDOG_MINOR) { #ifndef CONFIG_WATCHDOG_NOWAYOUT @@ -380,6 +382,7 @@ static int wdt_release(struct inode *inode, struct file *file) #endif wdt_is_open=0; } + unlock_kernel(); return 0; } diff --git a/drivers/char/wdt285.c b/drivers/char/wdt285.c index 6efdd7f76..66633fd20 100644 --- a/drivers/char/wdt285.c +++ b/drivers/char/wdt285.c @@ -26,6 +26,7 @@ #include <linux/reboot.h> #include <linux/init.h> #include <linux/interrupt.h> +#include <linux/smp_lock.h> #include <asm/irq.h> #include <asm/uaccess.h> @@ -74,7 +75,6 @@ static int watchdog_open(struct inode *inode, struct file *file) { if(timer_alive) return -EBUSY; - MOD_INC_USE_COUNT; /* * Ahead watchdog factor ten, Mr Sulu */ @@ -86,6 +86,7 @@ static int watchdog_open(struct inode *inode, struct file *file) request_irq(IRQ_TIMER4, watchdog_fire, 0, "watchdog", NULL); #else *CSR_SA110_CNTL |= 1 << 13; + MOD_INC_USE_COUNT; #endif timer_alive = 1; return 0; @@ -94,9 +95,10 @@ static int watchdog_open(struct inode *inode, struct file *file) static int watchdog_release(struct inode *inode, struct file *file) { #ifdef ONLY_TESTING + lock_kernel(); free_irq(IRQ_TIMER4, NULL); timer_alive = 0; - MOD_DEC_USE_COUNT; + unlock_kernel(); #else /* * It's irreversible! @@ -153,6 +155,7 @@ static int watchdog_ioctl(struct inode *inode, struct file *file, static struct file_operations watchdog_fops= { + owner: THIS_MODULE, write: watchdog_write, ioctl: watchdog_ioctl, open: watchdog_open, diff --git a/drivers/char/wdt977.c b/drivers/char/wdt977.c index 9bfbf0cc6..fef6bc7fc 100644 --- a/drivers/char/wdt977.c +++ b/drivers/char/wdt977.c @@ -20,6 +20,7 @@ #include <linux/fs.h> #include <linux/miscdevice.h> #include <linux/init.h> +#include <linux/smp_lock.h> #include <asm/io.h> #include <asm/system.h> @@ -38,7 +39,9 @@ static int wdt977_open(struct inode *inode, struct file *file) { if(timer_alive) return -EBUSY; +#ifdef CONFIG_WATCHDOG_NOWAYOUT MOD_INC_USE_COUNT; +#endif timer_alive++; //max timeout value = 255 minutes (0xFF). Write 0 to disable WatchDog. @@ -88,6 +91,7 @@ static int wdt977_release(struct inode *inode, struct file *file) * Lock it in if it's a module and we defined ...NOWAYOUT */ #ifndef CONFIG_WATCHDOG_NOWAYOUT + lock_kernel(); // unlock the SuperIO chip outb(0x87,0x370); @@ -118,8 +122,8 @@ static int wdt977_release(struct inode *inode, struct file *file) // lock the SuperIO chip outb(0xAA,0x370); - MOD_DEC_USE_COUNT; timer_alive=0; + unlock_kernel(); printk(KERN_INFO "Watchdog: shutdown.\n"); #endif @@ -162,6 +166,7 @@ static ssize_t wdt977_write(struct file *file, const char *data, size_t len, lof static struct file_operations wdt977_fops= { + owner: THIS_MODULE, write: wdt977_write, open: wdt977_open, release: wdt977_release, diff --git a/drivers/char/wdt_pci.c b/drivers/char/wdt_pci.c index 2bd09930a..8e960841b 100644 --- a/drivers/char/wdt_pci.c +++ b/drivers/char/wdt_pci.c @@ -51,6 +51,7 @@ #include <linux/notifier.h> #include <linux/reboot.h> #include <linux/init.h> +#include <linux/smp_lock.h> #include <linux/pci.h> @@ -358,7 +359,9 @@ static int wdtpci_open(struct inode *inode, struct file *file) case WATCHDOG_MINOR: if(wdt_is_open) return -EBUSY; +#ifdef CONFIG_WATCHDOG_NOWAYOUT MOD_INC_USE_COUNT; +#endif /* * Activate */ @@ -391,7 +394,6 @@ static int wdtpci_open(struct inode *inode, struct file *file) outb_p(0, WDT_DC); /* Enable */ return 0; case TEMP_MINOR: - MOD_INC_USE_COUNT; return 0; default: return -ENODEV; @@ -414,13 +416,14 @@ static int wdtpci_release(struct inode *inode, struct file *file) { if(MINOR(inode->i_rdev)==WATCHDOG_MINOR) { + lock_kernel(); #ifndef CONFIG_WATCHDOG_NOWAYOUT inb_p(WDT_DC); /* Disable counters */ wdtpci_ctr_load(2,0); /* 0 length reset pulses now */ #endif wdt_is_open=0; + unlock_kernel(); } - MOD_DEC_USE_COUNT; return 0; } @@ -454,6 +457,7 @@ static int wdtpci_notify_sys(struct notifier_block *this, unsigned long code, static struct file_operations wdtpci_fops = { + owner: THIS_MODULE, llseek: wdtpci_llseek, read: wdtpci_read, write: wdtpci_write, diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index e373ce2f3..47a6292d1 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -32,6 +32,7 @@ #include <linux/fs.h> #include <linux/malloc.h> #include <linux/version.h> +#include <linux/smp_lock.h> /* If you want debugging uncomment: */ /* #define DEBUG */ @@ -76,6 +77,7 @@ extern static int i2cdev_cleanup(void); static struct file_operations i2cdev_fops = { + owner: THIS_MODULE, llseek: i2cdev_lseek, read: i2cdev_read, write: i2cdev_write, @@ -374,7 +376,6 @@ int i2cdev_open (struct inode *inode, struct file *file) if (i2cdev_adaps[minor]->inc_use) i2cdev_adaps[minor]->inc_use(i2cdev_adaps[minor]); - MOD_INC_USE_COUNT; #ifdef DEBUG printk("i2c-dev.o: opened i2c-%d\n",minor); @@ -390,9 +391,10 @@ static int i2cdev_release (struct inode *inode, struct file *file) #ifdef DEBUG printk("i2c-dev.o: Closed: i2c-%d\n", minor); #endif - MOD_DEC_USE_COUNT; + lock_kernel(); if (i2cdev_adaps[minor]->dec_use) i2cdev_adaps[minor]->dec_use(i2cdev_adaps[minor]); + unlock_kernel(); return 0; } diff --git a/drivers/i2o/i2o_config.c b/drivers/i2o/i2o_config.c index 7a50f64e9..9a9cfec6e 100644 --- a/drivers/i2o/i2o_config.c +++ b/drivers/i2o/i2o_config.c @@ -35,6 +35,7 @@ #include <linux/miscdevice.h> #include <linux/mm.h> #include <linux/spinlock.h> +#include <linux/smp_lock.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -848,6 +849,7 @@ static int cfg_release(struct inode *inode, struct file *file) struct i2o_cfg_info *p1, *p2; unsigned int flags; + lock_kernel(); p1 = p2 = NULL; spin_lock_irqsave(&i2o_config_lock, flags); @@ -870,6 +872,7 @@ static int cfg_release(struct inode *inode, struct file *file) p1 = p1->next; } spin_unlock_irqrestore(&i2o_config_lock, flags); + unlock_kernel(); return 0; } diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 911234014..bd89fcc61 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -402,6 +402,7 @@ #include <linux/malloc.h> #include <linux/pci.h> #include <linux/ide.h> +#include <linux/smp_lock.h> #include <asm/byteorder.h> #include <asm/irq.h> @@ -5235,11 +5236,6 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp) if (test_and_set_bit (IDETAPE_BUSY, &tape->flags)) return -EBUSY; - MOD_INC_USE_COUNT; -#if ONSTREAM_DEBUG - if (tape->debug_level >= 6) - printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_chrdev_open-1\n"); -#endif if (!tape->onstream) { idetape_read_position(drive); if (!test_bit (IDETAPE_ADDRESS_VALID, &tape->flags)) @@ -5255,28 +5251,13 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp) } if (idetape_wait_ready(drive, 60 * HZ)) { clear_bit(IDETAPE_BUSY, &tape->flags); - MOD_DEC_USE_COUNT; -#if ONSTREAM_DEBUG - if (tape->debug_level >= 6) - printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_chrdev_open-1\n"); -#endif printk(KERN_ERR "ide-tape: %s: drive not ready\n", tape->name); return -EBUSY; } idetape_read_position(drive); - MOD_DEC_USE_COUNT; -#if ONSTREAM_DEBUG - if (tape->debug_level >= 6) - printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_chrdev_open-2\n"); -#endif clear_bit (IDETAPE_PIPELINE_ERROR, &tape->flags); if (tape->chrdev_direction == idetape_direction_none) { - MOD_INC_USE_COUNT; -#if ONSTREAM_DEBUG - if (tape->debug_level >= 6) - printk(KERN_INFO "ide-tape: MOD_INC_USE_COUNT in idetape_chrdev_open-2\n"); -#endif idetape_create_prevent_cmd(drive, &pc, 1); if (!idetape_queue_pc_tail (drive,&pc)) { if (tape->door_locked != DOOR_EXPLICITLY_LOCKED) @@ -5296,10 +5277,12 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp) static int idetape_chrdev_release (struct inode *inode, struct file *filp) { ide_drive_t *drive = get_drive_ptr (inode->i_rdev); - idetape_tape_t *tape = drive->driver_data; + idetape_tape_t *tape; idetape_pc_t pc; unsigned int minor=MINOR (inode->i_rdev); - + + lock_kernel(); + tape = drive->driver_data; #if IDETAPE_DEBUG_LOG if (tape->debug_level >= 3) printk (KERN_INFO "ide-tape: Reached idetape_chrdev_release\n"); @@ -5337,13 +5320,9 @@ static int idetape_chrdev_release (struct inode *inode, struct file *filp) if (!idetape_queue_pc_tail (drive,&pc)) tape->door_locked = DOOR_UNLOCKED; } - MOD_DEC_USE_COUNT; -#if ONSTREAM_DEBUG - if (tape->debug_level >= 6) - printk(KERN_INFO "ide-tape: MOD_DEC_USE_COUNT in idetape_chrdev_release\n"); -#endif } clear_bit (IDETAPE_BUSY, &tape->flags); + unlock_kernel(); return 0; } @@ -5919,6 +5898,7 @@ static ide_module_t idetape_module = { * Our character device supporting functions, passed to register_chrdev. */ static struct file_operations idetape_fops = { + owner: THIS_MODULE, read: idetape_chrdev_read, write: idetape_chrdev_write, ioctl: idetape_chrdev_ioctl, diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c index 83c1169fe..3c23c45a5 100644 --- a/drivers/ieee1394/raw1394.c +++ b/drivers/ieee1394/raw1394.c @@ -17,6 +17,7 @@ #include <linux/poll.h> #include <linux/module.h> #include <linux/version.h> +#include <linux/smp_lock.h> #include <asm/uaccess.h> #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) @@ -869,6 +870,7 @@ static int dev_release(struct inode *inode, struct file *file) struct pending_request *req; int done = 0, i; + lock_kernel(); for (i = 0; i < 64; i++) { if (fi->listen_channels & (1ULL << i)) { hpsb_unlisten_channel(hl_handle, fi->host, i); @@ -913,6 +915,7 @@ static int dev_release(struct inode *inode, struct file *file) kfree(fi); V22_COMPAT_MOD_DEC_USE_COUNT; + unlock_kernel(); return 0; } diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c index 9f00fd3f0..9afbb58ec 100644 --- a/drivers/ieee1394/video1394.c +++ b/drivers/ieee1394/video1394.c @@ -27,6 +27,7 @@ #include <linux/pci.h> #include <linux/fs.h> #include <linux/poll.h> +#include <linux/smp_lock.h> #include <asm/byteorder.h> #include <asm/atomic.h> #include <asm/io.h> @@ -1043,18 +1044,20 @@ int video1394_mmap(struct file *file, struct vm_area_struct *vma) { struct video_card *video = &video_cards[MINOR(file->f_dentry->d_inode->i_rdev)]; - struct ti_ohci *ohci= video->ohci; + struct ti_ohci *ohci; + int res = -EINVAL; + lock_kernel(); + ohci = video->ohci; PRINT(KERN_INFO, ohci->id, "mmap"); if (video->current_ctx == NULL) { PRINT(KERN_ERR, ohci->id, "current iso context not set"); - return -EINVAL; - } - - return do_iso_mmap(ohci, video->current_ctx, + } else + res = do_iso_mmap(ohci, video->current_ctx, (char *)vma->vm_start, (unsigned long)(vma->vm_end-vma->vm_start)); - return 0; + unlock_kernel(); + return res; } static int video1394_open(struct inode *inode, struct file *file) @@ -1079,6 +1082,7 @@ static int video1394_release(struct inode *inode, struct file *file) struct ti_ohci *ohci= video->ohci; int i; + lock_kernel(); for (i=0;i<ohci->nb_iso_rcv_ctx-1;i++) if (video->ir_context[i]) { if (!test_and_clear_bit( @@ -1115,6 +1119,7 @@ static int video1394_release(struct inode *inode, struct file *file) V22_COMPAT_MOD_DEC_USE_COUNT; PRINT(KERN_INFO, ohci->id, "release"); + unlock_kernel(); return 0; } diff --git a/drivers/isdn/avmb1/capi.c b/drivers/isdn/avmb1/capi.c index 06ddc8199..4c7e68266 100644 --- a/drivers/isdn/avmb1/capi.c +++ b/drivers/isdn/avmb1/capi.c @@ -182,6 +182,7 @@ #include <linux/fs.h> #include <linux/signal.h> #include <linux/mm.h> +#include <linux/smp_lock.h> #include <linux/timer.h> #include <linux/wait.h> #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE @@ -379,10 +380,8 @@ struct capiminor *capiminor_alloc(__u16 applid, __u32 ncci) struct capiminor *mp, **pp; unsigned int minor = 0; - MOD_INC_USE_COUNT; mp = (struct capiminor *)kmem_cache_alloc(capiminor_cachep, GFP_ATOMIC); if (!mp) { - MOD_DEC_USE_COUNT; printk(KERN_ERR "capi: can't alloc capiminor\n"); return 0; } @@ -434,7 +433,6 @@ void capiminor_free(struct capiminor *mp) kfree_skb(skb); capiminor_del_all_ack(mp); kmem_cache_free(capiminor_cachep, mp); - MOD_DEC_USE_COUNT; #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capiminor_free %d\n", GET_USE_COUNT(THIS_MODULE)); #endif @@ -1212,7 +1210,6 @@ capi_open(struct inode *inode, struct file *file) if ((file->private_data = capidev_alloc(file)) == 0) return -ENOMEM; - MOD_INC_USE_COUNT; #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capi_open %d\n", GET_USE_COUNT(THIS_MODULE)); #endif @@ -1224,14 +1221,15 @@ capi_release(struct inode *inode, struct file *file) { struct capidev *cdev = (struct capidev *)file->private_data; + lock_kernel(); capincci_free(cdev, 0xffffffff); capidev_free(cdev); file->private_data = NULL; - MOD_DEC_USE_COUNT; #ifdef _DEBUG_REFCOUNT printk(KERN_DEBUG "capi_release %d\n", GET_USE_COUNT(THIS_MODULE)); #endif + unlock_kernel(); return 0; } @@ -1414,11 +1412,13 @@ capinc_raw_release(struct inode *inode, struct file *file) struct capiminor *mp = (struct capiminor *)file->private_data; if (mp) { + lock_kernel(); mp->file = 0; if (mp->nccip == 0) { capiminor_free(mp); file->private_data = NULL; } + unlock_kernel(); } #ifdef _DEBUG_REFCOUNT @@ -2050,8 +2050,6 @@ int capi_init(void) { char *p; - MOD_INC_USE_COUNT; - if ((p = strchr(revision, ':'))) { strcpy(rev, p + 2); p = strchr(rev, '$'); @@ -2061,7 +2059,6 @@ int capi_init(void) if (devfs_register_chrdev(capi_major, "capi20", &capi_fops)) { printk(KERN_ERR "capi20: unable to get major %d\n", capi_major); - MOD_DEC_USE_COUNT; return -EIO; } @@ -2069,7 +2066,6 @@ int capi_init(void) if (devfs_register_chrdev(capi_rawmajor, "capi/r%d", &capinc_raw_fops)) { devfs_unregister_chrdev(capi_major, "capi20"); printk(KERN_ERR "capi20: unable to get major %d\n", capi_rawmajor); - MOD_DEC_USE_COUNT; return -EIO; } devfs_register_series (NULL, "capi/r%u", CAPINC_NR_PORTS, @@ -2085,7 +2081,6 @@ int capi_init(void) if ((capifuncs = attach_capi_interface(&cuser)) == 0) { - MOD_DEC_USE_COUNT; devfs_unregister_chrdev(capi_major, "capi20"); #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE devfs_unregister_chrdev(capi_rawmajor, "capi/r%d"); @@ -2101,7 +2096,6 @@ int capi_init(void) (void) detach_capi_interface(&cuser); devfs_unregister_chrdev(capi_major, "capi20"); devfs_unregister_chrdev(capi_rawmajor, "capi/r%d"); - MOD_DEC_USE_COUNT; return -ENOMEM; } #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */ @@ -2122,7 +2116,6 @@ int capi_init(void) devfs_unregister(devfs_find_handle(NULL, "capi20", capi_major, 0, DEVFS_SPECIAL_CHR, 0)); - MOD_DEC_USE_COUNT; return -ENOMEM; } @@ -2131,7 +2124,6 @@ int capi_init(void) printk(KERN_NOTICE "capi20: Rev%s: started up with major %d\n", rev, capi_major); - MOD_DEC_USE_COUNT; return 0; } diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c index f7d7ee8d5..bd065a48d 100644 --- a/drivers/isdn/divert/divert_procfs.c +++ b/drivers/isdn/divert/divert_procfs.c @@ -199,6 +199,7 @@ isdn_divert_close(struct inode *ino, struct file *filep) struct divert_info *inf; int flags; + lock_kernel(); save_flags(flags); cli(); if_used--; @@ -214,6 +215,7 @@ isdn_divert_close(struct inode *ino, struct file *filep) divert_info_head = divert_info_head->next; kfree(inf); } + unlock_kernel(); return (0); } /* isdn_divert_close */ diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c index c27c926a1..c28aedc1f 100644 --- a/drivers/isdn/hysdn/hysdn_procconf.c +++ b/drivers/isdn/hysdn/hysdn_procconf.c @@ -372,6 +372,7 @@ hysdn_conf_close(struct inode *ino, struct file *filep) int retval = 0; struct proc_dir_entry *pd; + lock_kernel(); /* search the addressed card */ card = card_root; while (card) { @@ -381,6 +382,7 @@ hysdn_conf_close(struct inode *ino, struct file *filep) card = card->next; /* search next entry */ } if (!card) { + unlock_kernel(); return (-ENODEV); /* device is unknown/invalid */ } if (card->debug_flags & (LOG_PROC_OPEN | LOG_PROC_ALL)) @@ -403,6 +405,7 @@ hysdn_conf_close(struct inode *ino, struct file *filep) if (filep->private_data) kfree(filep->private_data); /* release memory */ } + unlock_kernel(); return (retval); } /* hysdn_conf_close */ diff --git a/drivers/isdn/hysdn/hysdn_procfs.c b/drivers/isdn/hysdn/hysdn_procfs.c index ae07f6597..864935625 100644 --- a/drivers/isdn/hysdn/hysdn_procfs.c +++ b/drivers/isdn/hysdn/hysdn_procfs.c @@ -254,7 +254,7 @@ hysdn_log_close(struct inode *ino, struct file *filep) hysdn_card *card; int flags, retval = 0; - + lock_kernel(); if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { /* write only access -> write debug completely written */ retval = 0; /* success */ @@ -297,6 +297,7 @@ hysdn_log_close(struct inode *ino, struct file *filep) } } /* read access */ + unlock_kernel(); return (retval); } /* hysdn_log_close */ diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c index 1a2980f02..ba454b9dc 100644 --- a/drivers/isdn/hysdn/hysdn_proclog.c +++ b/drivers/isdn/hysdn/hysdn_proclog.c @@ -345,6 +345,7 @@ hysdn_log_close(struct inode *ino, struct file *filep) int flags, retval = 0; + lock_kernel(); if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) { /* write only access -> write debug level written */ retval = 0; /* success */ @@ -386,6 +387,7 @@ hysdn_log_close(struct inode *ino, struct file *filep) kfree(inf); } } /* read access */ + unlock_kernel(); return (retval); } /* hysdn_log_close */ diff --git a/drivers/isdn/isdn_common.c b/drivers/isdn/isdn_common.c index f6c326301..b543d8690 100644 --- a/drivers/isdn/isdn_common.c +++ b/drivers/isdn/isdn_common.c @@ -439,6 +439,7 @@ #include <linux/poll.h> #include <linux/vmalloc.h> #include <linux/isdn.h> +#include <linux/smp_lock.h> #include "isdn_common.h" #include "isdn_tty.h" #include "isdn_net.h" @@ -485,11 +486,10 @@ static void isdn_register_devfs(int); static void isdn_unregister_devfs(int); void -isdn_MOD_INC_USE_COUNT(void) +isdn_lock_drivers(void) { int i; - MOD_INC_USE_COUNT; for (i = 0; i < dev->drivers; i++) { isdn_ctrl cmd; @@ -502,11 +502,17 @@ isdn_MOD_INC_USE_COUNT(void) } void -isdn_MOD_DEC_USE_COUNT(void) +isdn_MOD_INC_USE_COUNT(void) +{ + MOD_INC_USE_COUNT; + isdn_lock_drivers(); +} + +void +isdn_unlock_drivers(void) { int i; - MOD_DEC_USE_COUNT; for (i = 0; i < dev->drivers; i++) if (dev->drv[i]->locks > 0) { isdn_ctrl cmd; @@ -519,6 +525,13 @@ isdn_MOD_DEC_USE_COUNT(void) } } +void +isdn_MOD_DEC_USE_COUNT(void) +{ + MOD_DEC_USE_COUNT; + isdn_unlock_drivers(); +} + #if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP) void isdn_dumppkt(char *s, u_char * p, int len, int dumplen) @@ -1976,8 +1989,6 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) /* * Open the device code. - * MOD_INC_USE_COUNT make sure that the driver memory is not freed - * while the device is in use. */ static int isdn_open(struct inode *ino, struct file *filep) @@ -1990,7 +2001,6 @@ isdn_open(struct inode *ino, struct file *filep) infostruct *p; if ((p = (infostruct *) kmalloc(sizeof(infostruct), GFP_KERNEL))) { - MOD_INC_USE_COUNT; p->next = (char *) dev->infochain; p->private = (char *) &(filep->private_data); dev->infochain = p; @@ -2011,21 +2021,21 @@ isdn_open(struct inode *ino, struct file *filep) return -ENODEV; if (!(dev->drv[drvidx]->online & (1 << chidx))) return -ENODEV; - isdn_MOD_INC_USE_COUNT(); + isdn_lock_drivers(); return 0; } if (minor <= ISDN_MINOR_CTRLMAX) { drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL); if (drvidx < 0) return -ENODEV; - isdn_MOD_INC_USE_COUNT(); + isdn_lock_drivers(); return 0; } #ifdef CONFIG_ISDN_PPP if (minor <= ISDN_MINOR_PPPMAX) { int ret; if (!(ret = isdn_ppp_open(minor - ISDN_MINOR_PPP, filep))) - isdn_MOD_INC_USE_COUNT(); + isdn_lock_drivers(); return ret; } #endif @@ -2037,11 +2047,11 @@ isdn_close(struct inode *ino, struct file *filep) { uint minor = MINOR(ino->i_rdev); + lock_kernel(); if (minor == ISDN_MINOR_STATUS) { infostruct *p = dev->infochain; infostruct *q = NULL; - MOD_DEC_USE_COUNT; while (p) { if (p->private == (char *) &(filep->private_data)) { if (q) @@ -2049,31 +2059,38 @@ isdn_close(struct inode *ino, struct file *filep) else dev->infochain = (infostruct *) (p->next); kfree(p); + unlock_kernel(); return 0; } q = p; p = (infostruct *) (p->next); } printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n"); + unlock_kernel(); return 0; } - isdn_MOD_DEC_USE_COUNT(); - if (minor < ISDN_MINOR_CTRL) + isdn_unlock_drivers(); + if (minor < ISDN_MINOR_CTRL) { + unlock_kernel(); return 0; + } if (minor <= ISDN_MINOR_CTRLMAX) { if (dev->profd == current) dev->profd = NULL; + unlock_kernel(); return 0; } #ifdef CONFIG_ISDN_PPP if (minor <= ISDN_MINOR_PPPMAX) isdn_ppp_release(minor - ISDN_MINOR_PPP, filep); #endif + unlock_kernel(); return 0; } static struct file_operations isdn_fops = { + owner: THIS_MODULE, llseek: isdn_lseek, read: isdn_read, write: isdn_write, diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index ff6f18ee1..10421b00d 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -25,6 +25,7 @@ #include <linux/devfs_fs_kernel.h> #include <linux/mm.h> #include <linux/sched.h> +#include <linux/smp_lock.h> #include <linux/adb.h> #include <linux/cuda.h> #include <linux/pmu.h> @@ -516,6 +517,7 @@ static int adb_release(struct inode *inode, struct file *file) struct adbdev_state *state = file->private_data; unsigned long flags; + lock_kernel(); if (state) { file->private_data = NULL; spin_lock_irqsave(&state->lock, flags); @@ -528,6 +530,7 @@ static int adb_release(struct inode *inode, struct file *file) spin_unlock_irqrestore(&state->lock, flags); } } + unlock_kernel(); return 0; } diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 9ca4a9ae8..efec54db0 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -31,6 +31,7 @@ #include <linux/adb.h> #include <linux/pmu.h> #include <linux/cuda.h> +#include <linux/smp_lock.h> #include <asm/prom.h> #include <asm/machdep.h> #include <asm/io.h> @@ -1539,6 +1540,7 @@ static int pmu_release(struct inode *inode, struct file *file) struct pmu_private *pp = file->private_data; unsigned long flags; + lock_kernel(); if (pp != 0) { file->private_data = 0; spin_lock_irqsave(&all_pvt_lock, flags); @@ -1546,6 +1548,7 @@ static int pmu_release(struct inode *inode, struct file *file) spin_unlock_irqrestore(&all_pvt_lock, flags); kfree(pp); } + unlock_kernel(); return 0; } diff --git a/drivers/mtd/Config.in b/drivers/mtd/Config.in index e2af3489a..5f7622572 100644 --- a/drivers/mtd/Config.in +++ b/drivers/mtd/Config.in @@ -1,59 +1,67 @@ + +# $Id: Config.in,v 1.20 2000/07/13 12:40:46 scote1 Exp $ + mainmenu_option next_comment comment 'Memory Technology Devices (MTD)' tristate 'Memory Technology Device (MTD) support' CONFIG_MTD if [ "$CONFIG_MTD" != "n" ]; then - dep_tristate 'M-Systems Disk-On-Chip 1000 support' CONFIG_MTD_DOC1000 $CONFIG_MTD - dep_tristate 'M-Systems Disk-On-Chip 2000' CONFIG_MTD_DOC2000 $CONFIG_MTD - dep_tristate 'M-Systems Disk-On-Chip Millennium' CONFIG_MTD_DOC2001 $CONFIG_MTD - if [ "$CONFIG_MTD_DOC2001" = "y" -o "$CONFIG_MTD_DOC2000" = "y" ]; then - define_bool CONFIG_MTD_DOCPROBE y - else - if [ "$CONFIG_MTD_DOC2001" = "m" -o "$CONFIG_MTD_DOC2000" = "m" ]; then - define_bool CONFIG_MTD_DOCPROBE m - else - define_bool CONFIG_MTD_DOCPROBE n - fi - fi - dep_tristate 'Use extra onboard system memory as MTD device' CONFIG_MTD_SLRAM $CONFIG_MTD - dep_tristate 'Ramix PMC551 PCI Mezzanine ram card support' CONFIG_MTD_PMC551 $CONFIG_MTD - if [ "$CONFIG_MTD_PMC551" != "n" ]; then - bool 'PMC551 256M DRAM Bugfix' CONFIG_MTD_PMC551_BUGFIX - fi - dep_tristate 'Debugging RAM test driver' CONFIG_MTD_MTDRAM $CONFIG_MTD + dep_tristate ' M-Systems Disk-On-Chip 1000 support' CONFIG_MTD_DOC1000 $CONFIG_MTD + dep_tristate ' M-Systems Disk-On-Chip 2000' CONFIG_MTD_DOC2000 $CONFIG_MTD + dep_tristate ' M-Systems Disk-On-Chip Millennium' CONFIG_MTD_DOC2001 $CONFIG_MTD + if [ "$CONFIG_MTD_DOC2001" = "y" -o "$CONFIG_MTD_DOC2000" = "y" ]; then + define_tristate CONFIG_MTD_DOCPROBE y + else + if [ "$CONFIG_MTD_DOC2001" = "m" -o "$CONFIG_MTD_DOC2000" = "m" ]; then + define_tristate CONFIG_MTD_DOCPROBE m + else + define_tristate CONFIG_MTD_DOCPROBE n + fi + fi + dep_tristate ' Use extra onboard system memory as MTD device' CONFIG_MTD_SLRAM $CONFIG_MTD + dep_tristate ' Ramix PMC551 PCI Mezzanine ram card support' CONFIG_MTD_PMC551 $CONFIG_MTD + if [ "$CONFIG_MTD_PMC551" != "n" ]; then + bool ' PMC551 256M DRAM Bugfix' CONFIG_MTD_PMC551_BUGFIX + fi + dep_tristate ' Debugging RAM test driver' CONFIG_MTD_MTDRAM $CONFIG_MTD + if [ "$CONFIG_MTD_MTDRAM" != "n" ]; then + int 'Device size in kB' CONFIG_MTDRAM_TOTAL_SIZE 4096 + int 'Size of the erase sectors in kB' CONFIG_MTDRAM_ERASE_SIZE 128 + fi -mainmenu_option next_comment comment 'MTD drivers for mapped chips' + dep_tristate ' Common Flash Interface (CFI) support' CONFIG_MTD_CFI $CONFIG_MTD + dep_tristate ' CFI support for Intel/Sharp Extended Command Set chips' CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_CFI + dep_tristate ' CFI support for AMD/Fujitsu Standard Command Set chips' CONFIG_MTD_CFI_AMDSTD $CONFIG_MTD_CFI - dep_tristate 'Common Flash Interface (CFI) support' CONFIG_MTD_CFI $CONFIG_MTD - dep_tristate 'CFI support for Intel/Sharp Extended Command Set chips' CONFIG_MTD_CFI_INTELEXT $CONFIG_CFI - define_bool CONFIG_MTD_JEDEC n - define_bool CONFIG_MTD_RAM n - define_bool CONFIG_MTD_ROM n -mainmenu_option next_comment -comment 'Drivers for chip mappings' +# These will later become config-options +define_bool CONFIG_MTD_JEDEC n +define_bool CONFIG_MTD_RAM n +define_bool CONFIG_MTD_ROM n - dep_tristate 'Flash chip mapping in physical memory' CONFIG_MTD_PHYSMAP $CONFIG_MTD_CFI - if [ "$CONFIG_MTD_PHYSMAP" != "n" ]; then - hex ' Physical start location of flash chip mapping (0x8000000)' CONFIG_MTD_PHYSMAP_START 0x8000000 - hex ' Physical length of flash chip mapping (0x4000000)' CONFIG_MTD_PHYSMAP_LEN 0x4000000 - fi - dep_tristate 'Flash chip mapping on Mixcom piggyback card' CONFIG_MTD_MIXMEM $CONFIG_MTD_JEDEC - dep_tristate 'Flash chip mapping on Nora' CONFIG_MTD_NORA $CONFIG_MTD_CFI - dep_tristate 'Flash chip mapping on Octagon 5066 SBC' CONFIG_MTD_OCTAGON $CONFIG_MTD_JEDEC - dep_tristate 'Flash chip mapping on RPXLite PPC board' CONFIG_MTD_RPXLITE $CONFIG_MTD_CFI - dep_tristate 'Flash chip mapping on Tempustech VMAX SBC301' CONFIG_MTD_VMAX $CONFIG_MTD_JEDEC + dep_tristate ' Flash chip mapping in physical memory' CONFIG_MTD_PHYSMAP $CONFIG_MTD_CFI + if [ "$CONFIG_MTD_PHYSMAP" != "n" ]; then + hex 'Physical start location of flash chip mapping' CONFIG_MTD_PHYSMAP_START 0x8000000 + hex 'Physical length of flash chip mapping' CONFIG_MTD_PHYSMAP_LEN 0x4000000 + fi + +comment 'Drivers for chip mappings' + dep_tristate ' Flash chip mapping on Mixcom piggyback card' CONFIG_MTD_MIXMEM $CONFIG_MTD_JEDEC + dep_tristate ' Flash chip mapping on Nora' CONFIG_MTD_NORA $CONFIG_MTD_CFI + dep_tristate ' Flash chip mapping on Octagon 5066 SBC' CONFIG_MTD_OCTAGON $CONFIG_MTD_JEDEC + dep_tristate ' Flash chip mapping on Photron PNC-2000' CONFIG_MTD_PNC2000 $CONFIG_MTD_CFI + dep_tristate ' Flash chip mapping on RPXLite PPC board' CONFIG_MTD_RPXLITE $CONFIG_MTD_CFI + dep_tristate ' Flash chip mapping on Tempustech VMAX SBC301' CONFIG_MTD_VMAX $CONFIG_MTD_JEDEC -mainmenu_option next_comment comment 'User modules and translation layers for MTD devices' - dep_tristate 'Direct chardevice access to MTD devices' CONFIG_MTD_CHAR $CONFIG_MTD - dep_tristate 'Pseudo-blockdevice access to MTD devices' CONFIG_MTD_BLOCK $CONFIG_MTD - dep_tristate 'FTL (Flash Translation Layer) support' CONFIG_FTL $CONFIG_MTD - dep_tristate 'NFTL (NAND Flash Translation Layer) support' CONFIG_NFTL $CONFIG_MTD - if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_NFTL" != "n" ]; then - bool 'Write support for NFTL (EXPERIMENTAL)' CONFIG_NFTL_RW - fi + dep_tristate ' Direct chardevice access to MTD devices' CONFIG_MTD_CHAR $CONFIG_MTD + dep_tristate ' Pseudo-blockdevice access to MTD devices' CONFIG_MTD_BLOCK $CONFIG_MTD + dep_tristate ' FTL (Flash Translation Layer) support' CONFIG_FTL $CONFIG_MTD + dep_tristate ' NFTL (NAND Flash Translation Layer) support' CONFIG_NFTL $CONFIG_MTD + if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_NFTL" != "n" ]; then + bool ' Write support for NFTL (EXPERIMENTAL)' CONFIG_NFTL_RW + fi fi endmenu diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 53a3906f8..6030b63b3 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -1,189 +1,110 @@ -# $Id: Makefile,v 1.20 2000/07/04 08:58:10 dwmw2 Exp $ - -# Uncomment this to enable the DBG macro (see mtd.h) -#CFLAGS+= -DZDBG +# +# Makefile for the memory technology device drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now inherited from the +# parent makes.. +# +# $Id: Makefile,v 1.22 2000/07/14 08:10:52 dwmw2 Exp $ ifndef CONFIG_MTD + # We're being invoked outside a normal kernel build. Fake it EXTRA_CFLAGS= -I$(shell pwd)/../include -HWDRIVERS = slram.o docprobe.o doc1000.o nora.o physmap.o rpxlite.o vmax301.o octagon-5066.o pmc551.o mtdram.o -USERDRIVERS = ftl.o nftl.o mtdblock.o mtdchar.o -MIX_OBJS = mtdcore.o mapped.o doc2000.o doc2001.o cfi_probe.o cfi_cmdset_0001.o -MI_OBJS = $(HWDRIVERS) $(USERDRIVERS) -CFLAGS_nftl.o := -DCONFIG_NFTL_RW -else - -O_TARGET := mtdlink.o -SUB_DIRS := -ALL_SUB_DIRS := -MOD_LIST_NAME := MTD_MODULES - - -ifeq ($(CONFIG_MTD),y) - OX_OBJS += mtdcore.o mapped.o -else - ifeq ($(CONFIG_MTD),m) - MX_OBJS += mtdcore.o mapped.o - endif -endif - -ifeq ($(CONFIG_MTD_NORA),y) - O_OBJS += nora.o -else - ifeq ($(CONFIG_MTD_NORA),m) - M_OBJS += nora.o - endif -endif - -ifeq ($(CONFIG_MTD_RPXLITE),y) - O_OBJS += rpxlite.o -else - ifeq ($(CONFIG_MTD_RPXLITE),m) - M_OBJS += rpxlite.o - endif -endif - -ifeq ($(CONFIG_MTD_PHYSMAP),y) - O_OBJS += physmap.o -else - ifeq ($(CONFIG_MTD_PHYSMAP),m) - M_OBJS += physmap.o - endif -endif - -ifeq ($(CONFIG_MTD_CFI),y) - OX_OBJS += cfi_probe.o -else - ifeq ($(CONFIG_MTD_CFI),m) - MX_OBJS += cfi_probe.o - endif -endif - -ifeq ($(CONFIG_MTD_CFI_INTELEXT),y) - OX_OBJS += cfi_cmdset_0001.o -else - ifeq ($(CONFIG_MTD_CFI_INTELEXT),m) - MX_OBJS += cfi_cmdset_0001.o - endif -endif - -ifeq ($(CONFIG_MTD_DOC1000),y) - O_OBJS += doc1000.o -else - ifeq ($(CONFIG_MTD_DOC1000),m) - M_OBJS += doc1000.o - endif -endif - -ifeq ($(CONFIG_MTD_DOC2000),y) - OX_OBJS += doc2000.o -else - ifeq ($(CONFIG_MTD_DOC2000),m) - MX_OBJS += doc2000.o - endif -endif +MIX_OBJS = mtdcore.o doc2000.o doc2001.o cfi_probe.o cfi_cmdset_0001.o \ + map_ram.o map_rom.o cfi_cmdset_0002.o +MI_OBJS = doc1000.o docprobe.o slram.o pmc551.o mtdram.o physmap.o \ + nora.o octagon-5066.o pnc2000.o rpxlite.o vmax301.o mtdchar.o \ + mtdblock.o ftl.o nftl.o -ifeq ($(CONFIG_MTD_DOC2001),y) - OX_OBJS += doc2001.o -else - ifeq ($(CONFIG_MTD_DOC2001),m) - MX_OBJS += doc2001.o - endif -endif - -ifeq ($(CONFIG_MTD_DOCPROBE),y) - O_OBJS += docprobe.o -else - ifeq ($(CONFIG_MTD_DOCPROBE),m) - M_OBJS += docprobe.o - endif -endif - -ifeq ($(CONFIG_MTD_SLRAM),y) - O_OBJS += slram.o -else - ifeq ($(CONFIG_MTD_SLRAM),m) - M_OBJS += slram.o - endif -endif - -ifeq ($(CONFIG_MTD_OCTAGON),y) - O_OBJS += octagon-5066.o -else - ifeq ($(CONFIG_MTD_OCTAGON),m) - M_OBJS += octagon-5066.o - endif -endif - -ifeq ($(CONFIG_MTD_PMC551),y) - O_OBJS += pmc551.o -else - ifeq ($(CONFIG_MTD_PMC551),m) - M_OBJS += pmc551.o - endif -endif - -ifeq ($(CONFIG_MTD_PMC551_BUGFIX),y) - CFLAGS_pmc551.o += -DPMC551_DRAM_BUG -endif - -ifeq ($(CONFIG_MTD_VMAX),y) - O_OBJS += vmax301.o -else - ifeq ($(CONFIG_MTD_VMAX),m) - M_OBJS += vmax301.o - endif -endif +CFLAGS_nftl.o := -DCONFIG_NFTL_RW +CFLAGS_mtdram.o := -DCONFIG_MTDRAM_TOTAL_SIZE=4096 -DCONFIG_MTDRAM_ERASE_SIZE=128 +CFLAGS_physmap.o := -DCONFIG_MTD_PHYSMAP_START=0x8000000 -DCONFIG_MTD_PHYSMAP_LEN=0x4000000 -ifeq ($(CONFIG_MTD_MIXMEM),y) - O_OBJS += mixmem.o -else - ifeq ($(CONFIG_MTD_MIXMEM),m) - M_OBJS += mixmem.o - endif -endif +else -ifeq ($(CONFIG_MTD_MTDRAM),y) - O_OBJS += mtdram.o -else - ifeq ($(CONFIG_MTD_MTDRAM),m) - M_OBJS += mtdram.o - endif -endif +O_OBJS := +OX_OBJS := +M_OBJS := +MX_OBJS := -ifeq ($(CONFIG_FTL),y) - O_OBJS += ftl.o -else - ifeq ($(CONFIG_FTL),m) - M_OBJS += ftl.o - endif -endif +# Object file lists. -ifeq ($(CONFIG_NFTL),y) - O_OBJS += nftl.o -else - ifeq ($(CONFIG_NFTL),m) - M_OBJS += nftl.o - endif -endif +obj-y := +obj-m := +obj-n := +obj- := -ifeq ($(CONFIG_MTD_BLOCK),y) - O_OBJS += mtdblock.o -else - ifeq ($(CONFIG_MTD_BLOCK),m) - M_OBJS += mtdblock.o - endif -endif +O_TARGET := mtdlink.o +SUB_DIRS := +ALL_SUB_DIRS := +MOD_SUB_DIRS := +MOD_LIST_NAME := MTD_MODULES +export-objs := mtdcore.o doc2000.o doc2001.o cfi_probe.o cfi_cmdset_0001.o cfi_cmdset_0002.o +list-multi := + +# MTD devices +obj-$(CONFIG_MTD) += mtdcore.o +obj-$(CONFIG_MTD_DOC1000) += doc1000.o +obj-$(CONFIG_MTD_DOC2000) += doc2000.o +obj-$(CONFIG_MTD_DOC2001) += doc2001.o +obj-$(CONFIG_MTD_DOCPROBE) += docprobe.o +obj-$(CONFIG_MTD_SLRAM) += slram.o +obj-$(CONFIG_MTD_PMC551) += pmc551.o +obj-$(CONFIG_MTD_MTDRAM) += mtdram.o + +# Chip drivers +obj-$(CONFIG_MTD_JEDEC) += jedec.o +obj-$(CONFIG_MTD_RAM) += map_ram.o +obj-$(CONFIG_MTD_ROM) += map_rom.o +obj-$(CONFIG_MTD_CFI) += cfi_probe.o +obj-$(CONFIG_MTD_CFI_INTELEXT) += cfi_cmdset_0001.o +obj-$(CONFIG_MTD_CFI_AMDSTD) += cfi_cmdset_0002.o + +# Chip mappings +obj-$(CONFIG_MTD_PHYSMAP) += physmap.o +obj-$(CONFIG_MTD_MIXMEM) += mixmem.o +obj-$(CONFIG_MTD_NORA) += nora.o +obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o +obj-$(CONFIG_MTD_PNC2000) += pnc2000.o +obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o +obj-$(CONFIG_MTD_VMAX) += vmax301.o + +# Users +obj-$(CONFIG_MTD_CHAR) += mtdchar.o +obj-$(CONFIG_MTD_BLOCK) += mtdblock.o +obj-$(CONFIG_FTL) += ftl.o +obj-$(CONFIG_NFTL) += nftl.o + +# Extract lists of the multi-part drivers. +# The 'int-*' lists are the intermediate files used to build the multi's. + +multi-y := $(filter $(list-multi), $(obj-y)) +multi-m := $(filter $(list-multi), $(obj-m)) +int-y := $(sort $(foreach m, $(multi-y), $($(basename $(m))-objs))) +int-m := $(sort $(foreach m, $(multi-m), $($(basename $(m))-objs))) + +# Files that are both resident and modular: remove from modular. + +obj-m := $(filter-out $(obj-y), $(obj-m)) +int-m := $(filter-out $(int-y), $(int-m)) + +# Take multi-part drivers out of obj-y and put components in. + +obj-y := $(filter-out $(list-multi), $(obj-y)) $(int-y) + +# Translate to Rules.make lists. + +O_OBJS := $(filter-out $(export-objs), $(obj-y)) +OX_OBJS := $(filter $(export-objs), $(obj-y)) +M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m))) +MX_OBJS := $(sort $(filter $(export-objs), $(obj-m))) -ifeq ($(CONFIG_MTD_CHAR),y) - O_OBJS += mtdchar.o -else - ifeq ($(CONFIG_MTD_CHAR),m) - M_OBJS += mtdchar.o - endif -endif endif diff --git a/drivers/mtd/cfi_cmdset_0001.c b/drivers/mtd/cfi_cmdset_0001.c index 713d8ab05..8c26d43b4 100644 --- a/drivers/mtd/cfi_cmdset_0001.c +++ b/drivers/mtd/cfi_cmdset_0001.c @@ -4,7 +4,7 @@ * * (C) 2000 Red Hat. GPL'd * - * $Id: cfi_cmdset_0001.c,v 1.20 2000/07/04 07:36:43 dwmw2 Exp $ + * $Id: cfi_cmdset_0001.c,v 1.21 2000/07/13 10:36:14 dwmw2 Exp $ */ #include <linux/module.h> @@ -455,13 +455,9 @@ static inline int do_write_1_by_16_oneword(struct map_info *map, struct flchip * chip->word_write_time--; if (!chip->word_write_time) chip->word_write_time++; - else - printk("decreasing word_write_time to %d µs\n", chip->word_write_time); } - if (z > 100) { + if (z > 1) chip->word_write_time++; - printk("increasing word_write_time to %d µs\n", chip->word_write_time); - } /* Done and happy. */ chip->state = FL_STATUS; diff --git a/drivers/mtd/cfi_cmdset_0002.c b/drivers/mtd/cfi_cmdset_0002.c new file mode 100644 index 000000000..d2736c024 --- /dev/null +++ b/drivers/mtd/cfi_cmdset_0002.c @@ -0,0 +1,610 @@ +/* + * Common Flash Interface support: + * AMD & Fujitsu Extended Vendor Command Set (ID 0x0002) + * + * Copyright (C) 2000 Crossnet Co. <info@crossnet.co.jp> + * + * This code is GPL + * + * $Id: cfi_cmdset_0002.c,v 1.1 2000/07/11 12:32:09 dwmw2 Exp $ + * + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <asm/io.h> +#include <asm/byteorder.h> + +#include <linux/errno.h> +#include <linux/malloc.h> +#include <linux/delay.h> +#include <linux/mtd/map.h> +#include <linux/mtd/cfi.h> + +#if LINUX_VERSION_CODE < 0x20300 +#define set_current_state(x) current->state = (x); +#endif + +static int cfi_amdext_read_2_by_16 (struct mtd_info *, loff_t, size_t, size_t *, u_char *); +static int cfi_amdext_write_2_by_16(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); +static int cfi_amdext_erase_2_by_16 (struct mtd_info *, struct erase_info *); +static void cfi_amdext_sync (struct mtd_info *); +static int cfi_amdext_suspend (struct mtd_info *); +static void cfi_amdext_resume (struct mtd_info *); + +static void cfi_amdext_destroy(struct mtd_info *); + +void cfi_cmdset_0002(struct map_info *, int, unsigned long); +EXPORT_SYMBOL(cfi_cmdset_0002); + +struct mtd_info *cfi_amdext_setup (struct map_info *); + +void cfi_cmdset_0002(struct map_info *map, int primary, unsigned long base) +{ + struct cfi_private *cfi = map->fldrv_priv; + int i; +// struct cfi_pri_intelext *extp; + + __u16 adr = primary?cfi->cfiq.P_ADR:cfi->cfiq.A_ADR; + + printk(" Amd/Fujitsu Extended Query Table at 0x%4.4X\n", adr); + + + /* If there was an old setup function, decrease its use count */ + if (cfi->cmdset_setup) + put_module_symbol((unsigned long)cfi->cmdset_setup); + if (cfi->cmdset_priv) + kfree(cfi->cmdset_priv); + + for (i=0; i< cfi->numchips; i++) { + cfi->chips[i].word_write_time = 128; + cfi->chips[i].buffer_write_time = 128; + cfi->chips[i].erase_time = 1024; + } + + + cfi->cmdset_setup = cfi_amdext_setup; +// cfi->cmdset_priv = extp; + MOD_INC_USE_COUNT; /* So the setup function is still there + * by the time it's called */ + + return; +} + +struct mtd_info *cfi_amdext_setup(struct map_info *map) +{ + struct cfi_private *cfi = map->fldrv_priv; + struct mtd_info *mtd; + + mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); + printk("number of CFI chips: %d\n", cfi->numchips); + + if (!mtd) { + printk("Failed to allocate memory for MTD device\n"); + kfree(cfi->cmdset_priv); + return NULL; + } + + memset(mtd, 0, sizeof(*mtd)); + mtd->priv = map; + mtd->type = MTD_NORFLASH; + mtd->erasesize = 0x20000; /* FIXME */ + /* Also select the correct geometry setup too */ + mtd->size = (1 << cfi->cfiq.DevSize) * cfi->numchips * cfi->interleave; + mtd->erase = cfi_amdext_erase_2_by_16; + mtd->read = cfi_amdext_read_2_by_16; + mtd->write = cfi_amdext_write_2_by_16; + mtd->sync = cfi_amdext_sync; + mtd->suspend = cfi_amdext_suspend; + mtd->resume = cfi_amdext_resume; + mtd->flags = MTD_CAP_NORFLASH; + map->fldrv_destroy = cfi_amdext_destroy; + mtd->name = map->name; + return mtd; +} + +static inline int do_read_2_by_16_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf) +{ + DECLARE_WAITQUEUE(wait, current); + unsigned long timeo = jiffies + HZ; + + retry: + spin_lock_bh(chip->mutex); + + if (chip->state != FL_READY){ +printk("Waiting for chip to read, status = %d\n", chip->state); + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); + + spin_unlock_bh(chip->mutex); + + schedule(); + remove_wait_queue(&chip->wq, &wait); + + if(signal_pending(current)) + return -EINTR; + + timeo = jiffies + HZ; + + goto retry; + } + + adr += chip->start; + +// map->write32(map, cpu_to_le32(0x00F000F0), adr); + + chip->state = FL_READY; + + map->copy_from(map, buf, adr, len); + + wake_up(&chip->wq); + spin_unlock_bh(chip->mutex); + + return 0; +} + +static int cfi_amdext_read_2_by_16 (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + unsigned long ofs; + int chipnum; + int ret = 0; + + /* ofs: offset within the first chip that the first read should start */ + + chipnum = (from >> cfi->chipshift); + chipnum /= (cfi->interleave); + ofs = from - (chipnum << cfi->chipshift) * (cfi->interleave); + + *retlen = 0; + + while (len) { + unsigned long thislen; + + if (chipnum >= cfi->numchips) + break; + + if (((len + ofs -1) >> cfi->chipshift) / (cfi->interleave)) + thislen = (1<<cfi->chipshift) * (cfi->interleave) - ofs; + else + thislen = len; + + ret = do_read_2_by_16_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf); + if (ret) + break; + + *retlen += thislen; + len -= thislen; + buf += thislen; + + ofs = 0; + chipnum++; + } + return ret; +} + +static inline int do_write_2_by_16_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, __u32 datum) +{ + unsigned long timeo = jiffies + HZ; + unsigned int Last[4]; + unsigned long Count = 0; + DECLARE_WAITQUEUE(wait, current); + int ret = 0; + + retry: + spin_lock_bh(chip->mutex); + + if (chip->state != FL_READY){ +printk("Waiting for chip to write, status = %d\n", chip->state); + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); + + spin_unlock_bh(chip->mutex); + + schedule(); + remove_wait_queue(&chip->wq, &wait); +printk("Wake up to write:\n"); + if(signal_pending(current)) + return -EINTR; + + timeo = jiffies + HZ; + + goto retry; + } + + chip->state = FL_WRITING; + + adr += chip->start; + + map->write32(map, cpu_to_le32(0x00AA00AA), 0x555 *4); + map->write32(map, cpu_to_le32(0x00550055), 0x2AA *4); + map->write32(map, cpu_to_le32(0x00A000A0), 0x555 *4); + map->write32(map, cpu_to_le32(datum), adr); + + spin_unlock_bh(chip->mutex); + udelay(chip->word_write_time); + spin_lock_bh(chip->mutex); + + Last[0] = map->read32(map, adr); + Last[1] = map->read32(map, adr); + Last[2] = map->read32(map, adr); + + for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] && Count < 10000; Count++){ + udelay(10); + + Last[Count % 4] = map->read32(map, adr); + } + + if (Last[(Count - 1) % 4] != datum){ + map->write32(map, cpu_to_le32(0x00F000F0), adr); + ret = -EIO; + } + + chip->state = FL_READY; + wake_up(&chip->wq); + spin_unlock_bh(chip->mutex); + + return ret; +} + + +static int cfi_amdext_write_2_by_16 (struct mtd_info *mtd, loff_t to , size_t len, size_t *retlen, const u_char *buf) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + int ret = 0; + int chipnum; + unsigned long ofs; + + *retlen = 0; + + chipnum = (to >> cfi->chipshift); + chipnum /= cfi->interleave; + ofs = to - (chipnum << cfi->chipshift) * cfi->interleave; + + while(len > 3) { + + ret = do_write_2_by_16_oneword(map, &cfi->chips[chipnum], + ofs, *(__u32 *)buf); + if (ret) + return ret; + + ofs += 4; + buf += 4; + (*retlen) += 4; + len -= 4; + + if ((ofs >> cfi->chipshift) / cfi->interleave) { + chipnum ++; + ofs = 0; + if (chipnum == cfi->numchips) + return 0; + } + } + + if (len) { + unsigned int tmp; + + /* Final byte to write */ +#if defined(__LITTLE_ENDIAN) + tmp = map->read32(map, ofs); + + tmp = 0xffffffff >> (len*8); + tmp = tmp << (len*8); + + tmp |= *(__u32 *)(buf); + + ret = do_write_2_by_16_oneword(map, &cfi->chips[chipnum], + ofs, tmp); + +#elif defined(__BIG_ENDIAN) +#error not support big endian yet +#else +#error define a sensible endianness +#endif + + if (ret) + return ret; + + (*retlen)+=len; + } + + return 0; +} + + +static inline int do_erase_2_by_16_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr) +{ + unsigned int status; + unsigned long timeo = jiffies + HZ; + DECLARE_WAITQUEUE(wait, current); + + retry: + spin_lock_bh(chip->mutex); + + if (chip->state != FL_READY){ + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); + + spin_unlock_bh(chip->mutex); + + schedule(); + remove_wait_queue(&chip->wq, &wait); + + if(signal_pending(current)) + return -EINTR; + + timeo = jiffies + HZ; + + goto retry; + } + + chip->state = FL_ERASING; + + adr += chip->start; + + map->write32(map, cpu_to_le32(0x00AA00AA), 0x555 *4); + map->write32(map, cpu_to_le32(0x00550055), 0x2AA *4); + map->write32(map, cpu_to_le32(0x00800080), 0x555 *4); + map->write32(map, cpu_to_le32(0x00AA00AA), 0x555 *4); + map->write32(map, cpu_to_le32(0x00550055), 0x2AA *4); + map->write32(map, cpu_to_le32(0x00300030), adr); + + + timeo = jiffies + (HZ*20); + + spin_unlock_bh(chip->mutex); + schedule_timeout(HZ); + spin_lock_bh(chip->mutex); + + /* FIXME. Use a timer to check this, and return immediately. */ + /* Once the state machine's known to be working I'll do that */ + + while ( ( (status = le32_to_cpu(map->read32(map, 0x00))) & 0x80808080 ) != 0x80808080 ) { + static int z=0; + + if (chip->state != FL_ERASING) { + /* Someone's suspended the erase. Sleep */ + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); + + spin_unlock_bh(chip->mutex); + printk("erase suspended. Sleeping\n"); + + schedule(); + remove_wait_queue(&chip->wq, &wait); + + if (signal_pending(current)) + return -EINTR; + + timeo = jiffies + (HZ*2); /* FIXME */ + spin_lock_bh(chip->mutex); + continue; + } + + /* OK Still waiting */ + if (time_after(jiffies, timeo)) { + chip->state = FL_READY; + spin_unlock_bh(chip->mutex); + printk("waiting for erase to complete timed out."); + return -EIO; + } + + /* Latency issues. Drop the lock, wait a while and retry */ + spin_unlock_bh(chip->mutex); + + z++; + if ( 0 && !(z % 100 )) + printk("chip not ready yet after erase. looping\n"); + + udelay(1); + + spin_lock_bh(chip->mutex); + continue; + } + + /* Done and happy. */ + chip->state = FL_READY; + wake_up(&chip->wq); + spin_unlock_bh(chip->mutex); + printk("erase ret OK\n"); + return 0; +} + +static int cfi_amdext_erase_2_by_16 (struct mtd_info *mtd, struct erase_info *instr) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + unsigned long adr, len; + int chipnum, ret = 0; + +//printk("erase : 0x%x 0x%x 0x%x\n", instr->addr, instr->len, mtd->size); + + if (instr->addr & (mtd->erasesize - 1)) + return -EINVAL; + + if (instr->len & (mtd->erasesize -1)) + return -EINVAL; + + if ((instr->len + instr->addr) > mtd->size) + return -EINVAL; + + chipnum = instr->addr >> cfi->chipshift; + chipnum /= cfi->interleave; + adr = instr->addr - (chipnum << cfi->chipshift) * (cfi->interleave); + len = instr->len; + +printk("erase : 0x%x 0x%x 0x%x\n", adr, len, chipnum, mtd->size); + + while(len) { +//printk("erase : 0x%x 0x%x 0x%x 0x%x\n", chipnum, adr, len, cfi->chipshift); + ret = do_erase_2_by_16_oneblock(map, &cfi->chips[chipnum], adr); + + if (ret) + return ret; + + adr += mtd->erasesize; + len -= mtd->erasesize; + + if ((adr >> cfi->chipshift) / (cfi->interleave)) { + adr = 0; + chipnum++; + + if (chipnum >= cfi->numchips) + break; + } + } + + if (instr->callback) + instr->callback(instr); + + return 0; +} + + + +static void cfi_amdext_sync (struct mtd_info *mtd) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + int i; + struct flchip *chip; + int ret = 0; + DECLARE_WAITQUEUE(wait, current); +printk("sync\n"); + + for (i=0; !ret && i<cfi->numchips; i++) { + chip = &cfi->chips[i]; + + retry: + spin_lock_bh(chip->mutex); + + switch(chip->state) { + case FL_READY: + case FL_STATUS: + case FL_CFI_QUERY: + case FL_JEDEC_QUERY: + chip->oldstate = chip->state; + chip->state = FL_SYNCING; + /* No need to wake_up() on this state change - + * as the whole point is that nobody can do anything + * with the chip now anyway. + */ + spin_unlock_bh(chip->mutex); + break; + + default: + /* Not an idle state */ + add_wait_queue(&chip->wq, &wait); + + spin_unlock_bh(chip->mutex); + schedule(); + + goto retry; + } + } + + /* Unlock the chips again */ + + for (i--; i >=0; i--) { + chip = &cfi->chips[i]; + + spin_lock_bh(chip->mutex); + + if (chip->state == FL_SYNCING) { + chip->state = chip->oldstate; + wake_up(&chip->wq); + } + spin_unlock_bh(chip->mutex); + } +printk("sync end\n"); +} + + +static int cfi_amdext_suspend(struct mtd_info *mtd) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + int i; + struct flchip *chip; + int ret = 0; +//printk("suspend\n"); + + for (i=0; !ret && i<cfi->numchips; i++) { + chip = &cfi->chips[i]; + + spin_lock_bh(chip->mutex); + + switch(chip->state) { + case FL_READY: + case FL_STATUS: + case FL_CFI_QUERY: + case FL_JEDEC_QUERY: + chip->oldstate = chip->state; + chip->state = FL_PM_SUSPENDED; + /* No need to wake_up() on this state change - + * as the whole point is that nobody can do anything + * with the chip now anyway. + */ + spin_unlock_bh(chip->mutex); + break; + + default: + ret = -EAGAIN; + break; + } + } + + /* Unlock the chips again */ + + for (i--; i >=0; i--) { + chip = &cfi->chips[i]; + + spin_lock_bh(chip->mutex); + + if (chip->state == FL_PM_SUSPENDED) { + chip->state = chip->oldstate; + wake_up(&chip->wq); + } + spin_unlock_bh(chip->mutex); + } + + return ret; +} + +static void cfi_amdext_resume(struct mtd_info *mtd) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + int i; + struct flchip *chip; +//printk("resume\n"); + + for (i=0; i<cfi->numchips; i++) { + + chip = &cfi->chips[i]; + + spin_lock_bh(chip->mutex); + + if (chip->state == FL_PM_SUSPENDED) { + chip->state = chip->oldstate; + wake_up(&chip->wq); + } + else + printk("Argh. Chip not in PM_SUSPENDED state upon resume()\n"); + + spin_unlock_bh(chip->mutex); + } +} + +static void cfi_amdext_destroy(struct mtd_info *mtd) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + kfree(cfi->cmdset_priv); + kfree(cfi); +} + diff --git a/drivers/mtd/doc2000.c b/drivers/mtd/doc2000.c index 8385648d1..eeb49a4eb 100644 --- a/drivers/mtd/doc2000.c +++ b/drivers/mtd/doc2000.c @@ -2,7 +2,7 @@ /* Linux driver for Disk-On-Chip 2000 */ /* (c) 1999 Machine Vision Holdings, Inc. */ /* Author: David Woodhouse <dwmw2@mvhi.com> */ -/* $Id: doc2000.c,v 1.23 2000/07/03 10:01:38 dwmw2 Exp $ */ +/* $Id: doc2000.c,v 1.24 2000/07/13 10:03:31 dwmw2 Exp $ */ #include <linux/kernel.h> #include <linux/module.h> @@ -36,7 +36,7 @@ static struct mtd_info *doc2klist = NULL; /* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */ -int _DoC_WaitReady (unsigned long docptr) +static int _DoC_WaitReady (unsigned long docptr) { //long c=-1; short c=-1; @@ -148,7 +148,7 @@ static inline int DoC_SelectFloor(unsigned long docptr, int floor) /* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */ -int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) +static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) { int mfr, id, chipshift=0; char *mfrname=NULL, *idname=NULL; @@ -302,7 +302,7 @@ int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) /* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */ -void DoC_ScanChips(struct DiskOnChip *this) +static void DoC_ScanChips(struct DiskOnChip *this) { int floor, chip; int numchips[MAX_FLOORS]; diff --git a/drivers/mtd/doc2001.c b/drivers/mtd/doc2001.c index 9f63b0b22..26a107722 100644 --- a/drivers/mtd/doc2001.c +++ b/drivers/mtd/doc2001.c @@ -1,8 +1,7 @@ - /* Linux driver for Disk-On-Chip Millennium */ /* (c) 1999 Machine Vision Holdings, Inc. */ /* Author: David Woodhouse <dwmw2@mvhi.com> */ -/* $Id: doc2001.c,v 1.4 2000/07/03 10:01:38 dwmw2 Exp $ */ +/* $Id: doc2001.c,v 1.7 2000/07/13 10:41:39 dwmw2 Exp $ */ #include <linux/kernel.h> #include <linux/module.h> @@ -21,305 +20,238 @@ #include <linux/mtd/nand.h> #include <linux/mtd/doc2000.h> - - -//#define PRERELEASE -#if 0 -static int doc_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); -static int doc_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); -static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eecbuf); -static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf); -static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t *retlen, u_char *buf); -static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t *retlen, const u_char *buf); +static struct { + char * name; + int manufacture_id; + int model_id; + int chipshift; +} nand_flash_ids[] = { + {"Toshiba TC5816BDC", NAND_MFR_TOSHIBA, 0x64, 21}, + {"Toshiba TC5832DC", NAND_MFR_TOSHIBA, 0x6b, 22}, + {"Toshiba TH58V128DC", NAND_MFR_TOSHIBA, 0x73, 24}, + {"Toshiba TC58256FT/DC", NAND_MFR_TOSHIBA, 0x75, 25}, + {"Toshiba TC58V32DC", NAND_MFR_TOSHIBA, 0xe5, 22}, + {"Toshiba TC58V64DC", NAND_MFR_TOSHIBA, 0xe6, 23}, + {"Toshiba TC58V16BDC", NAND_MFR_TOSHIBA, 0xea, 21}, + {"Samsung KM29N16000", NAND_MFR_SAMSUNG, 0x64, 21}, + {"Samsung KM29U128T", NAND_MFR_SAMSUNG, 0x73, 24}, + {"Samsung KM29U256T", NAND_MFR_SAMSUNG, 0x75, 25}, + {"Samsung KM29W32000", NAND_MFR_SAMSUNG, 0xe3, 22}, + {"Samsung KM29U64000", NAND_MFR_SAMSUNG, 0xe6, 23}, + {"Samsung KM29W16000", NAND_MFR_SAMSUNG, 0xea, 21}, + {NULL,} +}; + +static int doc_read (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf); +static int doc_write (struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf); +static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf, u_char *eecbuf); +static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf, u_char *eccbuf); +static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, + size_t *retlen, u_char *buf); +static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, + size_t *retlen, const u_char *buf); static int doc_erase (struct mtd_info *mtd, struct erase_info *instr); -#endif static struct mtd_info *docmillist = NULL; -/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */ - -int _DoC_WaitReady (unsigned long docptr) +static void DoC_Delay(unsigned long docptr, unsigned short cycles) { - //long c=-1; - short c=-1; + volatile char dummy; + int i; - DEBUG(2,"_DoC_WaitReady called for out-of-line wait\n"); + for (i = 0; i < cycles; i++) + dummy = ReadDOC(docptr, NOP); +} + +/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */ +static int _DoC_WaitReady(unsigned long docptr) +{ + unsigned short c = 0xffff; /* Out-of-line routine to wait for chip response */ while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B) && --c) ; - if (c == 0) - DEBUG(2, "_DoC_WaitReady timed out.\n"); - - return (c==0); + return (c == 0); } -static inline int DoC_WaitReady(unsigned long docptr) +static __inline__ int DoC_WaitReady(unsigned long docptr) { /* This is inline, to optimise the common case, where it's ready instantly */ - volatile char dummy; int ret = 0; - /* Out-of-line routine to wait for chip response */ - /* TPW: Add 4 reads - see Software Requirement 2.3.2 */ - dummy = ReadDOC(docptr, CDSNControl); - dummy = ReadDOC(docptr, CDSNControl); - dummy = ReadDOC(docptr, CDSNControl); - dummy = ReadDOC(docptr, CDSNControl); - + /* 4 read form NOP register should be issued in prior to the read from CDSNControl + see Software Requirement 11.4 item 2. */ + DoC_Delay(docptr, 4); + if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) - ret = _DoC_WaitReady(docptr); /* Call the out-of-line routine to wait */ - - /* TPW: Add 2 reads - see Software Requirement 2.3.2 */ - dummy = ReadDOC(docptr, CDSNControl); - dummy = ReadDOC(docptr, CDSNControl); + /* Call the out-of-line routine to wait */ + ret = _DoC_WaitReady(docptr); + + /* issue 2 read from NOP register after reading from CDSNControl register + see Software Requirement 11.4 item 2. */ + DoC_Delay(docptr, 2); return ret; } - -/* DoC_Command: Send a flash command to the flash chip */ - -static inline int DoC_Command(unsigned long docptr, unsigned char command, unsigned char xtraflags) +/* DoC_Command: Send a flash command to the flash chip through the CDSN Slow IO register to bypass + the internal pipeline. Each of 4 delay cycles (read from the NOP register) is required after + writing to CDSN Control register, see Software Requirement 11.4 item 3. */ +static __inline__ void DoC_Command(unsigned long docptr, unsigned char command, + unsigned char xtraflags) { /* Assert the CLE (Command Latch Enable) line to the flash chip */ - WriteDOC( CDSN_CTRL_FLASH_IO | xtraflags | CDSN_CTRL_CLE | CDSN_CTRL_CE, - docptr, CDSNControl); + WriteDOC(xtraflags | CDSN_CTRL_CLE | CDSN_CTRL_CE, docptr, CDSNControl); + DoC_Delay(docptr, 4); /* Send the command */ - WriteDOC(command, docptr, 2k_CDSN_IO); + WriteDOC(command, docptr, CDSNSlowIO); + WriteDOC(command, docptr, Mil_CDSN_IO); /* Lower the CLE line */ - WriteDOC( CDSN_CTRL_FLASH_IO | xtraflags | CDSN_CTRL_CE, docptr, CDSNControl); - - /* Wait for the chip to respond */ - return DoC_WaitReady(docptr); + WriteDOC(xtraflags | CDSN_CTRL_CE, docptr, CDSNControl); + DoC_Delay(docptr, 4); } -/* DoC_Address: Set the current address for the flash chip */ - -static inline int DoC_Address (unsigned long docptr, int numbytes, unsigned long ofs, +/* DoC_Address: Set the current address for the flash chip through the CDSN Slow IO register to bypass + the internal pipeline. Each of 4 delay cycles (read from the NOP register) is required after + writing to CDSN Control register, see Software Requirement 11.4 item 3. */ +static __inline__ void DoC_Address (unsigned long docptr, int numbytes, unsigned long ofs, unsigned char xtraflags1, unsigned char xtraflags2) { /* Assert the ALE (Address Latch Enable line to the flash chip */ - WriteDOC( CDSN_CTRL_FLASH_IO | xtraflags1 | CDSN_CTRL_ALE | CDSN_CTRL_CE, - docptr, CDSNControl); + WriteDOC(xtraflags1 | CDSN_CTRL_ALE | CDSN_CTRL_CE, docptr, CDSNControl); + DoC_Delay(docptr, 4); /* Send the address */ - /* Three cases: - numbytes == 1: Send single byte, bits 0-7. - numbytes == 2: Send bits 9-16 followed by 17-23 - numbytes == 3: Send 0-7, 9-16, then 17-23 - */ - if (numbytes != 2) - WriteDOC(ofs & 0xff, docptr, 2k_CDSN_IO); - - if (numbytes != 1) { - WriteDOC((ofs >> 9) & 0xff, docptr, 2k_CDSN_IO); - WriteDOC((ofs >> 17) & 0xff, docptr, 2k_CDSN_IO); - } + switch (numbytes) + { + case 1: + /* Send single byte, bits 0-7. */ + WriteDOC(ofs & 0xff, docptr, CDSNSlowIO); + WriteDOC(ofs & 0xff, docptr, Mil_CDSN_IO); + break; + case 2: + /* Send bits 9-16 followed by 17-23 */ + WriteDOC((ofs >> 9) & 0xff, docptr, CDSNSlowIO); + WriteDOC((ofs >> 9) & 0xff, docptr, Mil_CDSN_IO); + WriteDOC((ofs >> 17) & 0xff, docptr, CDSNSlowIO); + WriteDOC((ofs >> 17) & 0xff, docptr, Mil_CDSN_IO); + break; + case 3: + /* Send 0-7, 9-16, then 17-23 */ + WriteDOC(ofs & 0xff, docptr, CDSNSlowIO); + WriteDOC(ofs & 0xff, docptr, Mil_CDSN_IO); + WriteDOC((ofs >> 9) & 0xff, docptr, CDSNSlowIO); + WriteDOC((ofs >> 9) & 0xff, docptr, Mil_CDSN_IO); + WriteDOC((ofs >> 17) & 0xff, docptr, CDSNSlowIO); + WriteDOC((ofs >> 17) & 0xff, docptr, Mil_CDSN_IO); + break; + default: + return; + } + /* Lower the ALE line */ - WriteDOC( CDSN_CTRL_FLASH_IO | xtraflags1 | xtraflags2 | CDSN_CTRL_CE, docptr, CDSNControl); - - /* Wait for the chip to respond */ - return DoC_WaitReady(docptr); + WriteDOC(xtraflags1 | xtraflags2 | CDSN_CTRL_CE, docptr, CDSNControl); + DoC_Delay(docptr, 4); } /* DoC_SelectChip: Select a given flash chip within the current floor */ - -static inline int DoC_SelectChip(unsigned long docptr, int chip) +static int DoC_SelectChip(unsigned long docptr, int chip) { /* Select the individual flash chip requested */ - WriteDOC( chip, docptr, CDSNDeviceSelect); - + WriteDOC(chip, docptr, CDSNDeviceSelect); + DoC_Delay(docptr, 4); + /* Wait for it to be ready */ return DoC_WaitReady(docptr); } /* DoC_SelectFloor: Select a given floor (bank of flash chips) */ - -static inline int DoC_SelectFloor(unsigned long docptr, int floor) +static int DoC_SelectFloor(unsigned long docptr, int floor) { /* Select the floor (bank) of chips required */ - WriteDOC( floor, docptr, FloorSelect); + WriteDOC(floor, docptr, FloorSelect); /* Wait for the chip to be ready */ return DoC_WaitReady(docptr); } - -/* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */ -int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) +/* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */ +static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) { - int mfr, id, chipshift=0; - char *mfrname=NULL, *idname=NULL; + int mfr, id, i; + volatile char dummy; - /* Page in the required floor/chip */ + /* Page in the required floor/chip + FIXME: is this supported by Millennium ?? */ DoC_SelectFloor(doc->virtadr, floor); DoC_SelectChip(doc->virtadr, chip); - /* Reset the chip */ - if (DoC_Command(doc->virtadr, NAND_CMD_RESET, CDSN_CTRL_WP)) { - DEBUG(2, "DoC_Command (reset) for %d,%d returned true\n", floor,chip); - return 0; - } - + /* Reset the chip, see Software Requirement 11.4 item 1. */ + DoC_Command(doc->virtadr, NAND_CMD_RESET, CDSN_CTRL_WP); + DoC_WaitReady(doc->virtadr); + /* Read the NAND chip ID: 1. Send ReadID command */ - if(DoC_Command(doc->virtadr, NAND_CMD_READID, CDSN_CTRL_WP)) { - DEBUG(2,"DoC_Command (ReadID) for %d,%d returned true\n", floor,chip); - return 0; - } + DoC_Command(doc->virtadr, NAND_CMD_READID, CDSN_CTRL_WP); + + /* Read the NAND chip ID: 2. Send address byte zero */ + DoC_Address(doc->virtadr, 1, 0x00, CDSN_CTRL_WP, 0x00); + + /* Read the manufacturer and device id codes of the flash device through + CDSN Slow IO register see Software Requirement 11.4 item 5.*/ + dummy = ReadDOC(doc->virtadr, CDSNSlowIO); + DoC_Delay(doc->virtadr, 2); + mfr = ReadDOC(doc->virtadr, Mil_CDSN_IO); + + dummy = ReadDOC(doc->virtadr, CDSNSlowIO); + DoC_Delay(doc->virtadr, 2); + id = ReadDOC(doc->virtadr, Mil_CDSN_IO); - /* Read the NAND chip ID: 2. Send address byte zero - */ - DoC_Address(doc->virtadr, 1, 0, CDSN_CTRL_WP, 0); - - /* Read the manufacturer and device id codes from the device */ - mfr = ReadDOC(doc->virtadr, 2k_CDSN_IO); - id = ReadDOC(doc->virtadr, 2k_CDSN_IO); - /* No response - return failure */ if (mfr == 0xff || mfr == 0) return 0; - - /* Check it's the same as the first chip we identified. - * M-Systems say that any given DiskOnChip device should only - * contain _one_ type of flash part, although that's not a - * hardware restriction. */ - if (doc->mfr) { - if (doc->mfr == mfr && doc->id == id) - return 1; /* This is another the same the first */ - else - printk(KERN_WARNING "Flash chip at floor %d, chip %d is different:\n", - floor, chip); - } - - /* Print (and store if first time) the manufacturer and ID codes. */ - - switch(mfr) { - case NAND_MFR_TOSHIBA: /* Toshiba */ - mfrname = "Toshiba"; - - switch(id) { - case 0x64: - idname = "TC5816BDC"; - chipshift = 21; - break; - - case 0x6b: - idname = "TC5832DC"; - chipshift = 22; - break; - - case 0x73: - idname = "TH58V128DC"; - chipshift = 24; - break; - - case 0x75: - idname = "TC58256FT/DC"; - chipshift = 25; - break; - - case 0xe5: - idname = "TC58V32DC"; - chipshift = 22; - break; - - case 0xe6: - idname = "TC58V64DC"; - chipshift = 23; - break; - - case 0xea: - idname = "TC58V16BDC"; - chipshift = 21; - break; - } - break; /* End of Toshiba parts */ - - case NAND_MFR_SAMSUNG: /* Samsung */ - mfrname = "Samsung"; - - switch(id) { - case 0x64: - idname = "KM29N16000"; - chipshift = 21; - - case 0x73: - idname = "KM29U128T"; - chipshift = 24; - break; - - case 0x75: - idname = "KM29U256T"; - chipshift = 25; - break; - case 0xe3: - idname = "KM29W32000"; - chipshift = 22; - break; - - case 0xe6: - idname = "KM29U64000"; - chipshift = 23; - break; - - case 0xea: - idname = "KM29W16000"; - chipshift = 21; - break; - } - break; /* End of Samsung parts */ - } - - /* If we've identified it fully, print the full names */ - if (idname) { -#ifdef PRERELEASE - DEBUG(1, "Flash chip found: %2.2X %2.2X (%s %s)\n", - mfr,id,mfrname,idname); -#endif - /* If this is the first chip, store the id codes */ - if (!doc->mfr) { + /* FIXME: to deal with mulit-flash on multi-Millennium case more carefully */ + for (i = 0; nand_flash_ids[i].name != NULL; i++) { + if (mfr == nand_flash_ids[i].manufacture_id && + id == nand_flash_ids[i].model_id) { + printk(KERN_INFO "Flash chip found: Manufacture ID: %2.2X, " + "Chip ID: %2.2X (%s)\n", + mfr, id, nand_flash_ids[i].name); doc->mfr = mfr; doc->id = id; - doc->chipshift = chipshift; - return 1; + doc->chipshift = nand_flash_ids[i].chipshift; + break; } - return 0; } - /* We haven't fully identified the chip. Print as much as we know. */ - if (mfrname) - printk(KERN_WARNING "Unknown %s flash chip found: %2.2X %2.2X\n", mfrname, - id, mfr); + if (nand_flash_ids[i].name == NULL) + return 0; else - printk(KERN_WARNING "Unknown flash chip found: %2.2X %2.2X\n", id, mfr); - - printk(KERN_WARNING "Please report to David.Woodhouse@mvhi.com\n"); - return 0; + return 1; } /* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */ - -void DoC_ScanChips(struct DiskOnChip *this) +static void DoC_ScanChips(struct DiskOnChip *this) { int floor, chip; - int numchips[MAX_FLOORS]; - int ret = 1; + int numchips[MAX_FLOORS_MIL]; + int ret; this->numchips = 0; this->mfr = 0; this->id = 0; /* For each floor, find the number of valid chips it contains */ - for (floor = 0 ; floor < MAX_FLOORS ; floor++) { - ret = 1; - numchips[floor]=0; - for (chip = 0 ; chip < MAX_CHIPS && ret != 0; chip++ ) { - + for (floor = 0,ret = 1; floor < MAX_FLOORS_MIL; floor++) { + numchips[floor] = 0; + for (chip = 0; chip < MAX_CHIPS_MIL && ret != 0; chip++) { ret = DoC_IdentChip(this, floor, chip); if (ret) { numchips[floor]++; @@ -327,7 +259,6 @@ void DoC_ScanChips(struct DiskOnChip *this) } } } - /* If there are none at all that we recognise, bail */ if (!this->numchips) { printk("No flash chips recognised.\n"); @@ -341,11 +272,9 @@ void DoC_ScanChips(struct DiskOnChip *this) return; } - ret = 0; - /* Fill out the chip array with {floor, chipno} for each * detected chip in the device. */ - for (floor = 0; floor < MAX_FLOORS; floor++) { + for (floor = 0, ret = 0; floor < MAX_FLOORS_MIL; floor++) { for (chip = 0 ; chip < numchips[floor] ; chip++) { this->chips[ret].floor = floor; this->chips[ret].chip = chip; @@ -357,14 +286,14 @@ void DoC_ScanChips(struct DiskOnChip *this) /* Calculate and print the total size of the device */ this->totlen = this->numchips * (1 << this->chipshift); - - printk(KERN_INFO "%d flash chips found. Total DiskOnChip size: %ld Mb\n", this->numchips , - this->totlen >> 20); + printk(KERN_INFO "%d flash chips found. Total DiskOnChip size: %ld Mbytes\n", + this->numchips ,this->totlen >> 20); } static int DoCMil_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2) { int tmp1, tmp2, retval; + if (doc1->physadr == doc2->physadr) return 1; @@ -392,21 +321,19 @@ static int DoCMil_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2) return retval; } - void DoCMil_init(struct mtd_info *mtd) { struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; struct DiskOnChip *old = NULL; /* We must avoid being called twice for the same device. */ - if (docmillist) old = (struct DiskOnChip *)docmillist->priv; while (old) { if (DoCMil_is_alias(this, old)) { - printk(KERN_NOTICE "Ignoring DiskOnChip Millennium at 0x%lX - already configured\n", - this->physadr); + printk(KERN_NOTICE "Ignoring DiskOnChip Millennium at " + "0x%lX - already configured\n", this->physadr); iounmap((void *)this->virtadr); kfree(mtd); return; @@ -418,14 +345,9 @@ void DoCMil_init(struct mtd_info *mtd) } mtd->name = "DiskOnChip Millennium"; - printk(KERN_NOTICE "DiskOnChip Millennium found at address 0x%lX\n",this->physadr); + printk(KERN_NOTICE "DiskOnChip Millennium found at address 0x%lX\n", + this->physadr); -#if 1 - printk("Unfortunately, we don't have support for the DiskOnChip Millennium yet.\n"); - iounmap((void *)this->virtadr); - kfree(mtd); - return; -#else mtd->type = MTD_NANDFLASH; mtd->flags = MTD_CAP_NANDFLASH; mtd->size = 0; @@ -445,8 +367,7 @@ void DoCMil_init(struct mtd_info *mtd) mtd->sync = NULL; this->totlen = 0; - this->numchips = 0; - + this->numchips = 0; this->curfloor = -1; this->curchip = -1; @@ -463,78 +384,90 @@ void DoCMil_init(struct mtd_info *mtd) add_mtd_device(mtd); return; } -#endif } - EXPORT_SYMBOL(DoCMil_init); -#if 0 -static int doc_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) + +static int doc_read (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) { /* Just a special case of doc_read_ecc */ return doc_read_ecc(mtd, from, len, retlen, buf, NULL); } -static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf) +static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf, u_char *eccbuf) { + int i; + volatile char dummy; struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; - int di=0; /* Yes, DI is a hangover from when I was disassembling the binary driver */ - unsigned long docptr; - struct Nand *mychip; - - docptr = this->virtadr; + unsigned long docptr = this->virtadr; + struct Nand *mychip = &this->chips[from >> (this->chipshift)]; /* Don't allow read past end of device */ if (from >= this->totlen) return -EINVAL; - + /* Don't allow a single read to cross a 512-byte block boundary */ - if (from + len > ( (from | 0x1ff) + 1)) + if (from + len > ((from | 0x1ff) + 1)) len = ((from | 0x1ff) + 1) - from; /* Find the chip which is to be used and select it */ - mychip = &this->chips[from >> (this->chipshift)]; - if (this->curfloor != mychip->floor) { DoC_SelectFloor(docptr, mychip->floor); DoC_SelectChip(docptr, mychip->chip); - } - else if (this->curchip != mychip->chip) { + } else if (this->curchip != mychip->chip) { DoC_SelectChip(docptr, mychip->chip); } - this->curfloor = mychip->floor; this->curchip = mychip->chip; - if (eccbuf) { - /* Prime the ECC engine */ - WriteDOC ( DOC_ECC_RESET, docptr, ECCConf); - WriteDOC ( DOC_ECC_EN, docptr, ECCConf); + /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/ + WriteDOC (DOC_ECC_RESET, docptr, ECCConf); + WriteDOC (DOC_ECC_EN, docptr, ECCConf); + } else { + /* disable the ECC engine, FIXME: is this correct ?? */ + WriteDOC (DOC_ECC_RESET, docptr, ECCConf); + WriteDOC (DOC_ECC_DIS, docptr, ECCConf); } + /* issue the Read0 or Read1 command depend on which half of the page + we are accessing. Polling the Flash Ready bit after issue 3 bytes + address in Sequence Read Mode, see Software Requirement 11.4 item 1.*/ DoC_Command(docptr, (from >> 8) & 1, CDSN_CTRL_WP); - DoC_Address(docptr, 3, from, CDSN_CTRL_WP , CDSN_CTRL_ECC_IO); + DoC_Address(docptr, 3, from, CDSN_CTRL_WP, 0x00); + DoC_WaitReady(docptr); - for (di=0; di < len ; di++) { - buf[di] = ReadDOC(docptr, 2k_CDSN_IO); + /* Read the data via the internal pipeline through CDSN IO register, + see Pipelined Read Operations 11.3 */ + dummy = ReadDOC(docptr, ReadPipeInit); + for (i = 0; i < len-1; i++) { + buf[i] = ReadDOC(docptr, Mil_CDSN_IO); } + buf[i] = ReadDOC(docptr, LastDataRead); /* Let the caller know we completed it */ *retlen = len; if (eccbuf) { - /* Read the ECC data through the DiskOnChip ECC logic */ - for (di=0; di<6; di++) { - eccbuf[di] = ReadDOC(docptr, 2k_CDSN_IO); + /* FIXME: are we reading the ECC from the ECC logic of DOC or + the spare data space on the flash chip i.e. How do we + control the Spare Area Enable bit of the flash ?? */ + /* Read the ECC data through the DiskOnChip ECC logic + see Reed-Solomon EDC/ECC 11.1 */ + dummy = ReadDOC(docptr, ReadPipeInit); + for (i = 0; i < 5; i++) { + eccbuf[i] = ReadDOC(docptr, Mil_CDSN_IO); } - + eccbuf[i] = ReadDOC(docptr, LastDataRead); + /* Flush the pipeline */ - (void) ReadDOC(docptr, 2k_ECCStatus); - (void) ReadDOC(docptr, 2k_ECCStatus); - + dummy = ReadDOC(docptr, ECCConf); + dummy = ReadDOC(docptr, ECCConf); + /* Check the ECC Status */ - if (ReadDOC(docptr, 2k_ECCStatus) & 0x80) { + if (ReadDOC(docptr, ECCConf) & 0x80) { /* There was an ECC error */ printk("DiskOnChip ECC Error: Read at %lx\n", (long)from); @@ -548,41 +481,40 @@ static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, size_t * #ifdef PSYCHO_DEBUG else printk("ECC OK at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", - (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], eccbuf[4], - eccbuf[5]); + (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], + eccbuf[4], eccbuf[5]); #endif - /* Reset the ECC engine */ WriteDOC(DOC_ECC_RESV, docptr , ECCConf); - } return 0; } -static int doc_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) +static int doc_write (struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) { static char as[6]; return doc_write_ecc(mtd, to, len, retlen, buf, as); } -static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf) +static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf, u_char *eccbuf) { + int i; + volatile char dummy; struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; - int di=0; - unsigned long docptr; - struct Nand *mychip; - - docptr = this->virtadr; + unsigned long docptr = this->virtadr; + struct Nand *mychip = &this->chips[to >> (this->chipshift)]; /* Don't allow write past end of device */ if (to >= this->totlen) return -EINVAL; -#if 0 + +#if 0 /* Don't allow a single write to cross a 512-byte block boundary */ if (to + len > ( (to | 0x1ff) + 1)) len = ((to | 0x1ff) + 1) - to; - #else /* Don't allow writes which aren't exactly one block */ if (to & 0x1ff || len != 0x200) @@ -590,8 +522,6 @@ static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, size_t *r #endif /* Find the chip which is to be used and select it */ - mychip = &this->chips[to >> (this->chipshift)]; - if (this->curfloor != mychip->floor) { DoC_SelectFloor(docptr, mychip->floor); DoC_SelectChip(docptr, mychip->chip); @@ -599,61 +529,75 @@ static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, size_t *r else if (this->curchip != mychip->chip) { DoC_SelectChip(docptr, mychip->chip); } - this->curfloor = mychip->floor; this->curchip = mychip->chip; - - /* Set device to main plane of flash */ + + /* Reset the chip, see Software Requirement 11.4 item 1. */ DoC_Command(docptr, NAND_CMD_RESET, CDSN_CTRL_WP); + DoC_WaitReady(docptr); + /* Set device to main plane of flash */ DoC_Command(docptr, NAND_CMD_READ0, CDSN_CTRL_WP); if (eccbuf) { - /* Prime the ECC engine */ - WriteDOC ( DOC_ECC_RESET, docptr, ECCConf); - WriteDOC ( DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf); + /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/ + WriteDOC (DOC_ECC_RESET, docptr, ECCConf); + WriteDOC (DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf); + } else { + /* disable the ECC engine, FIXME: is this correct ?? */ + WriteDOC (DOC_ECC_RESET, docptr, ECCConf); + WriteDOC (DOC_ECC_DIS, docptr, ECCConf); } - DoC_Command(docptr, NAND_CMD_SEQIN, 0); - DoC_Address(docptr, 3, to, 0, CDSN_CTRL_ECC_IO); + /* issue the Serial Data In command to initial the Page Program process */ + DoC_Command(docptr, NAND_CMD_SEQIN, 0x00); + DoC_Address(docptr, 3, to, 0x00, 0x00); - for (di=0; di < len ; di++) { - WriteDOC(buf[di], docptr, 2k_CDSN_IO); + /* Write the data via the internal pipeline through CDSN IO register, + see Pipelined Write Operations 11.2 */ + for (i = 0; i < len; i++) { + WriteDOC(buf[i], docptr, Mil_CDSN_IO); } - + WriteDOC(0x00, docptr, WritePipeTerm); if (eccbuf) { - WriteDOC( CDSN_CTRL_ECC_IO | CDSN_CTRL_CE , docptr, CDSNControl ); - -#if 1 - /* eduardp@m-sys.com says this shouldn't be necessary, - * but it doesn't actually work without it, so I've - * left it in for now. dwmw2. - */ - - WriteDOC( 0, docptr, 2k_CDSN_IO); - WriteDOC( 0, docptr, 2k_CDSN_IO); - WriteDOC( 0, docptr, 2k_CDSN_IO); -#endif + /* Write ECC data to flash, the ECC info is generated by the DiskOnChip DECC logic + see Reed-Solomon EDC/ECC 11.1 */ + WriteDOC(0, docptr, NOP); + WriteDOC(0, docptr, NOP); + WriteDOC(0, docptr, NOP); + /* Read the ECC data through the DiskOnChip ECC logic */ - for (di=0; di<6; di++) { - eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di); + for (i = 0; i < 6; i++) { + eccbuf[i] = ReadDOC(docptr, ECCSyndrome0 + i); } + + /* Write the ECC data to flash */ + for (i = 0; i < 6; i++) { + WriteDOC(eccbuf[i], docptr, Mil_CDSN_IO); + } + WriteDOC(0x00, docptr, WritePipeTerm); + #ifdef PSYCHO_DEBUG printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", - (long) to, eccbuf[0], eccbuf[1], eccbuf[2], - eccbuf[3], eccbuf[4], eccbuf[5] ); + (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], + eccbuf[4], eccbuf[5]); #endif + /* Reset the ECC engine */ WriteDOC(DOC_ECC_RESV, docptr , ECCConf); - } - DoC_Command(docptr, NAND_CMD_PAGEPROG, 0); - - DoC_Command(docptr, NAND_CMD_STATUS, CDSN_CTRL_WP); - /* There's an implicit DoC_WaitReady() in DoC_Command */ + /* Commit the Page Program command and wait for ready + see Software Requirement 11.4 item 1.*/ + DoC_Command(docptr, NAND_CMD_PAGEPROG, 0x00); + DoC_WaitReady(docptr); - if (ReadDOC(docptr, 2k_CDSN_IO) & 1) { + /* Read the status of the flash device through CDSN Slow IO register + see Software Requirement 11.4 item 5.*/ + DoC_Command(docptr, NAND_CMD_STATUS, 0x00); + dummy = ReadDOC(docptr, CDSNSlowIO); + DoC_Delay(docptr, 2); + if (ReadDOC(docptr, Mil_CDSN_IO) & 1) { printk("Error programming flash\n"); /* Error in programming */ *retlen = 0; @@ -666,19 +610,18 @@ static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, size_t *r return 0; } - - -static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t *retlen, u_char *buf) +static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, + size_t *retlen, u_char *buf) { - struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; + volatile char dummy; int i; - unsigned long docptr; - struct Nand *mychip; - - docptr = this->virtadr; - - mychip = &this->chips[ofs >> this->chipshift]; - + struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; + unsigned long docptr = this->virtadr; + struct Nand *mychip = &this->chips[ofs >> this->chipshift]; + + /* FIXME: should we restrict the access between 512 to 527 ?? */ + + /* Find the chip which is to be used and select it */ if (this->curfloor != mychip->floor) { DoC_SelectFloor(docptr, mychip->floor); DoC_SelectChip(docptr, mychip->chip); @@ -688,35 +631,43 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t *re } this->curfloor = mychip->floor; this->curchip = mychip->chip; - - - + + /* FIXME: should we disable ECC engine in this way ?? */ + /* disable the ECC engine, FIXME: is this correct ?? */ + WriteDOC (DOC_ECC_RESET, docptr, ECCConf); + WriteDOC (DOC_ECC_DIS, docptr, ECCConf); + + /* issue the Read2 command to read the Spare Data Area. + Polling the Flash Ready bit after issue 3 bytes address in + Sequence Read Mode, see Software Requirement 11.4 item 1.*/ DoC_Command(docptr, NAND_CMD_READOOB, CDSN_CTRL_WP); - DoC_Address(docptr, 3, ofs, CDSN_CTRL_WP, 0); - - for (i=0; i<len; i++) - buf[i] = ReadDOC(docptr, 2k_CDSN_IO); - + DoC_Address(docptr, 3, ofs, CDSN_CTRL_WP, 0x00); + DoC_WaitReady(docptr); + + /* Read the data out via the internal pipeline through CDSN IO register, + see Pipelined Read Operations 11.3 */ + dummy = ReadDOC(docptr, ReadPipeInit); + for (i = 0; i < len-1; i++) { + buf[i] = ReadDOC(docptr, Mil_CDSN_IO); + } + buf[i] = ReadDOC(docptr, LastDataRead); + *retlen = len; - return 0; + return 0; } -static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t *retlen, const u_char *buf) +static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, + size_t *retlen, const u_char *buf) { - struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; int i; - unsigned long docptr; - struct Nand *mychip; - - // printk("doc_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n",(long)ofs, len, - // buf[0], buf[1], buf[2], buf[3], buf[8], buf[9], buf[14],buf[15]); + volatile char dummy; + struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; + unsigned long docptr = this->virtadr; + struct Nand *mychip = &this->chips[ofs >> this->chipshift]; - docptr = this->virtadr; - - mychip = &this->chips[ofs >> this->chipshift]; - - if (this->curfloor != mychip->floor) { + /* Find the chip which is to be used and select it */ + if (this->curfloor != mychip->floor) { DoC_SelectFloor(docptr, mychip->floor); DoC_SelectChip(docptr, mychip->chip); } @@ -725,49 +676,63 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t *r } this->curfloor = mychip->floor; this->curchip = mychip->chip; - - DoC_Command(docptr, NAND_CMD_RESET, CDSN_CTRL_WP); - DoC_Command(docptr, NAND_CMD_READOOB, CDSN_CTRL_WP); - DoC_Command(docptr, NAND_CMD_SEQIN, 0); - DoC_Address(docptr, 3, ofs, 0, 0); - - for (i=0; i<len; i++) - WriteDOC(buf[i], docptr, 2k_CDSN_IO); + /* FIXME: should we disable ECC engine in this way ?? */ + /* disable the ECC engine, FIXME: is this correct ?? */ + WriteDOC (DOC_ECC_RESET, docptr, ECCConf); + WriteDOC (DOC_ECC_DIS, docptr, ECCConf); - DoC_Command(docptr, NAND_CMD_PAGEPROG, 0); - DoC_Command(docptr, NAND_CMD_STATUS, 0); - /* DoC_WaitReady() is implicit in DoC_Command */ + /* Reset the chip, see Software Requirement 11.4 item 1. */ + DoC_Command(docptr, NAND_CMD_RESET, CDSN_CTRL_WP); + DoC_WaitReady(docptr); + /* issue the Read2 command to read the Spare Data Area. */ + DoC_Command(docptr, NAND_CMD_READOOB, CDSN_CTRL_WP); - if (ReadDOC(docptr, 2k_CDSN_IO) & 1) { + /* issue the Serial Data In command to initial the Page Program process */ + DoC_Command(docptr, NAND_CMD_SEQIN, 0x00); + DoC_Address(docptr, 3, ofs, 0x00, 0x00); + + /* Write the data via the internal pipeline through CDSN IO register, + see Pipelined Write Operations 11.2 */ + for (i = 0; i < len; i++) + WriteDOC(buf[i], docptr, Mil_CDSN_IO); + WriteDOC(0x00, docptr, WritePipeTerm); + + /* Commit the Page Program command and wait for ready + see Software Requirement 11.4 item 1.*/ + DoC_Command(docptr, NAND_CMD_PAGEPROG, 0x00); + DoC_WaitReady(docptr); + + /* Read the status of the flash device through CDSN Slow IO register + see Software Requirement 11.4 item 5.*/ + DoC_Command(docptr, NAND_CMD_STATUS, 0x00); + dummy = ReadDOC(docptr, CDSNSlowIO); + DoC_Delay(docptr, 2); + if (ReadDOC(docptr, Mil_CDSN_IO) & 1) { printk("Error programming oob data\n"); - /* There was an error */ *retlen = 0; return -EIO; } *retlen = len; - return 0; + return 0; } - int doc_erase (struct mtd_info *mtd, struct erase_info *instr) { + volatile char dummy; struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; unsigned long ofs = instr->addr; unsigned long len = instr->len; - unsigned long docptr; - struct Nand *mychip; - - if(len != mtd->erasesize) - printk(KERN_WARNING "Erase not right size (%lx != %lx)n", len, mtd->erasesize); - + unsigned long docptr = this->virtadr; + struct Nand *mychip = &this->chips[ofs >> this->chipshift]; - docptr = this->virtadr; - - mychip = &this->chips[ofs >> this->chipshift]; - + if (len != mtd->erasesize) + printk(KERN_WARNING "Erase not right size (%lx != %lx)n", + len, mtd->erasesize); + + /* Find the chip which is to be used and select it */ if (this->curfloor != mychip->floor) { DoC_SelectFloor(docptr, mychip->floor); DoC_SelectChip(docptr, mychip->chip); @@ -780,32 +745,35 @@ int doc_erase (struct mtd_info *mtd, struct erase_info *instr) instr->state = MTD_ERASE_PENDING; - DoC_Command(docptr, NAND_CMD_ERASE1, 0); - DoC_Address(docptr, 2, ofs, 0, 0); - DoC_Command(docptr, NAND_CMD_ERASE2, 0); + /* issue the Erase Setup command */ + DoC_Command(docptr, NAND_CMD_ERASE1, 0x00); + DoC_Address(docptr, 2, ofs, 0x00, 0x00); + + /* Commit the Erase Start command and wait for ready + see Software Requirement 11.4 item 1.*/ + DoC_Command(docptr, NAND_CMD_ERASE2, 0x00); + DoC_WaitReady(docptr); instr->state = MTD_ERASING; + /* Read the status of the flash device through CDSN Slow IO register + see Software Requirement 11.4 item 5.*/ DoC_Command(docptr, NAND_CMD_STATUS, CDSN_CTRL_WP); - - if (ReadDOC(docptr, 2k_CDSN_IO) & 1) { - printk("Error writing\n"); + dummy = ReadDOC(docptr, CDSNSlowIO); + DoC_Delay(docptr, 2); + if (ReadDOC(docptr, Mil_CDSN_IO) & 1) { + printk("Error Erasing\n"); /* There was an error */ instr->state = MTD_ERASE_FAILED; - } - else + } else instr->state = MTD_ERASE_DONE; if (instr->callback) instr->callback(instr); - + return 0; } - - -#endif - /**************************************************************************** * * Module stuff diff --git a/drivers/mtd/docprobe.c b/drivers/mtd/docprobe.c index 5feb64901..7ab0a2d74 100644 --- a/drivers/mtd/docprobe.c +++ b/drivers/mtd/docprobe.c @@ -3,7 +3,7 @@ /* Probe routines common to all DoC devices */ /* (c) 1999 Machine Vision Holdings, Inc. */ /* Author: David Woodhouse <dwmw2@mvhi.com> */ -/* $Id: docprobe.c,v 1.8 2000/06/26 20:40:53 dwmw2 Exp $ */ +/* $Id: docprobe.c,v 1.10 2000/07/13 14:23:20 dwmw2 Exp $ */ @@ -206,7 +206,7 @@ static void DoC_Probe(unsigned long physadr) case DOC_ChipID_DocMil: name="Millennium"; #ifdef CONFIG_MTD_DOC2001 - initroutine = &DocMil_init; + initroutine = &DoCMil_init; #elif CONFIG_MODULES initroutinedynamic=1; initroutine = (void *)get_module_symbol(NULL, "DoCMil_init"); @@ -252,7 +252,7 @@ int __init init_doc(void) printk(KERN_NOTICE "M-Systems DiskOnChip driver. (C) 1999 Machine Vision Holdings, Inc.\n"); #ifdef PRERELEASE - printk(KERN_INFO "$Id: docprobe.c,v 1.8 2000/06/26 20:40:53 dwmw2 Exp $\n"); + printk(KERN_INFO "$Id: docprobe.c,v 1.10 2000/07/13 14:23:20 dwmw2 Exp $\n"); #endif for (i=0; doc_locations[i]; i++) { diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index a69ec9e65..d94d86ff7 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c @@ -1,7 +1,7 @@ /* * Direct MTD block device access * - * $Id: mtdblock.c,v 1.16 2000/06/23 09:34:58 dwmw2 Exp $ + * $Id: mtdblock.c,v 1.17 2000/07/13 14:25:54 dwmw2 Exp $ */ #ifdef MTDBLOCK_DEBUG diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index d0e79a431..11413556f 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -63,21 +63,16 @@ static int mtd_open(struct inode *inode, struct file *file) if ((file->f_mode & 2) && (minor & 1)) return -EACCES; - MOD_INC_USE_COUNT; - mtd = get_mtd_device(NULL, devnum); - if (!mtd) { - MOD_DEC_USE_COUNT; + if (!mtd) return -ENODEV; - } file->private_data = mtd; /* You can't open it RW if it's not a writeable device */ if ((file->f_mode & 2) && !(mtd->flags & MTD_WRITEABLE)) { put_mtd_device(mtd); - MOD_DEC_USE_COUNT; return -EACCES; } @@ -100,7 +95,6 @@ static release_t mtd_close(struct inode *inode, put_mtd_device(mtd); - MOD_DEC_USE_COUNT; release_return(0); } /* mtd_close */ @@ -362,7 +356,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file, } /* memory_ioctl */ static struct file_operations mtd_fops = { - + owner: THIS_MODULE, llseek: mtd_lseek, /* lseek */ read: mtd_read, /* read */ write: mtd_write, /* write */ diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 7403b6b94..b3f0157eb 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -1,5 +1,5 @@ /* - * $Id: mtdcore.c,v 1.8 2000/06/27 13:40:05 dwmw2 Exp $ + * $Id: mtdcore.c,v 1.13 2000/07/13 14:27:37 dwmw2 Exp $ * * Core registration and callback routines for MTD * drivers and users. @@ -44,9 +44,18 @@ extern int init_doc1000(void); #ifdef CONFIG_MTD_DOCPROBE extern int init_doc(void); #endif +#ifdef CONFIG_MTD_PHYSMAP +extern int init_physmap(void); +#endif +#ifdef CONFIG_MTD_RPXLITE +extern int init_rpxlite(void); +#endif #ifdef CONFIG_MTD_OCTAGON extern int init_octagon5066(void); #endif +#ifdef CONFIG_MTD_PNC2000 +extern int init_pnc2000(void); +#endif #ifdef CONFIG_MTD_VMAX extern int init_vmax301(void); #endif @@ -76,11 +85,18 @@ extern int init_mtdchar(void); static DECLARE_MUTEX(mtd_table_mutex); - static struct mtd_info *mtd_table[MAX_MTD_DEVICES]; - static struct mtd_notifier *mtd_notifiers = NULL; +/** + * add_mtd_device - register an MTD device + * @mtd: pointer to new MTD device info structure + * + * Add a device to the list of MTD devices present in the system, and + * notify each currently active MTD 'user' of its arrival. Returns + * zero on success or 1 on failure, which currently will only happen + * if the number of present devices exceeds MAX_MTD_DEVICES (i.e. 16) + */ int add_mtd_device(struct mtd_info *mtd) { @@ -109,6 +125,15 @@ int add_mtd_device(struct mtd_info *mtd) return 1; } +/** + * del_mtd_device - unregister an MTD device + * @mtd: pointer to MTD device info structure + * + * Remove a device from the list of MTD devices present in the system, + * and notify each currently active MTD 'user' of its departure. + * Returns zero on success or 1 on failure, which currently will happen + * if the requested device does not appear to be present in the list. + */ int del_mtd_device (struct mtd_info *mtd) { @@ -137,7 +162,14 @@ int del_mtd_device (struct mtd_info *mtd) return 1; } - +/** + * register_mtd_user - register a 'user' of MTD devices. + * @new: pointer to notifier info structure + * + * Registers a pair of callbacks function to be called upon addition + * or removal of MTD devices. Causes the 'add' callback to be immediately + * invoked for each MTD device currently present in the system. + */ void register_mtd_user (struct mtd_notifier *new) { @@ -157,7 +189,15 @@ void register_mtd_user (struct mtd_notifier *new) up(&mtd_table_mutex); } - +/** + * register_mtd_user - unregister a 'user' of MTD devices. + * @new: pointer to notifier info structure + * + * Removes a callback function pair from the list of 'users' to be + * notified upon addition or removal of MTD devices. Causes the + * 'remove' callback to be immediately invoked for each MTD device + * currently present in the system. + */ int unregister_mtd_user (struct mtd_notifier *old) { @@ -187,13 +227,17 @@ int unregister_mtd_user (struct mtd_notifier *old) } -/* get_mtd_device(): - * Prepare to use an MTD device referenced either by number or address. +/** + * __get_mtd_device - obtain a validated handle for an MTD device + * @mtd: last known address of the required MTD device + * @num: internal device number of the required MTD device * - * If <num> == -1, search the table for an MTD device located at <mtd>. - * If <mtd> == NULL, return the MTD device with number <num>. - * If both are set, return the MTD device with number <num> _only_ if it - * is located at <mtd>. + * Given a number and NULL address, return the num'th entry in the device + * table, if any. Given an address and num == -1, search the device table + * for a device with that address and return if it's still present. Given + * both, return the num'th driver only if its address matches. Return NULL + * if not. get_mtd_device() increases the use count, but + * __get_mtd_device() doesn't - you should generally use get_mtd_device(). */ struct mtd_info *__get_mtd_device(struct mtd_info *mtd, int num) @@ -224,12 +268,45 @@ EXPORT_SYMBOL(register_mtd_user); EXPORT_SYMBOL(unregister_mtd_user); /*====================================================================*/ -/* /proc/mtd support */ +/* Power management code */ + +#ifdef CONFIG_PM + +#include <linux/pm.h> + +static struct pm_dev *mtd_pm_dev = NULL; + +static int mtd_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) +{ + int ret = 0, i; + + if (down_trylock(&mtd_table_mutex)) + return -EAGAIN; + if (rqst == PM_SUSPEND) { + for (i = 0; ret == 0 && i < MAX_MTD_DEVICES; i++) { + if (mtd_table[i] && mtd_table[i]->suspend) + ret = mtd_table[i]->suspend(mtd_table[i]); + } + } else i = MAX_MTD_DEVICES-1; + + if (rqst == PM_RESUME || ret) { + for ( ; i >= 0; i--) { + if (mtd_table[i] && mtd_table[i]->resume) + mtd_table[i]->resume(mtd_table[i]); + } + } + up(&mtd_table_mutex); + return ret; +} +#endif + +/*====================================================================*/ +/* Support for /proc/mtd */ #ifdef CONFIG_PROC_FS #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) -struct proc_dir_entry *proc_mtd; +static struct proc_dir_entry *proc_mtd; #endif static inline int mtd_proc_info (char *buf, int i) @@ -292,10 +369,10 @@ struct proc_dir_entry mtd_proc_entry = { }; #endif -#endif +#endif /* CONFIG_PROC_FS */ /*====================================================================*/ - +/* Init code */ #if LINUX_VERSION_CODE < 0x20300 @@ -315,9 +392,18 @@ static inline void init_others(void) * Theoretically all other DiskOnChip * devices too. */ #endif +#ifdef CONFIG_MTD_PHYSMAP + init_physmap(); +#endif +#ifdef CONFIG_MTD_RPXLITE + init_rpxlite(); +#endif #ifdef CONFIG_MTD_OCTAGON init_octagon5066(); #endif +#ifdef CONFIG_MTD_PNC2000 + init_pnc2000(); +#endif #ifdef CONFIG_MTD_VMAX init_vmax301(); #endif @@ -374,13 +460,21 @@ mod_init_t init_mtd(void) #if LINUX_VERSION_CODE < 0x20300 init_others(); #endif - +#ifdef CONFIG_PM + mtd_pm_dev = pm_register(PM_UNKNOWN_DEV, 0, mtd_pm_callback); +#endif return 0; } mod_exit_t cleanup_mtd(void) { unregister_chrdev(MTD_CHAR_MAJOR, "mtd"); +#ifdef CONFIG_PM + if (mtd_pm_dev) { + pm_unregister(mtd_pm_dev); + mtd_pm_dev = NULL; + } +#endif #ifdef CONFIG_PROC_FS #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) if (proc_mtd) diff --git a/drivers/mtd/mtdram.c b/drivers/mtd/mtdram.c index 674435272..33f3a8116 100644 --- a/drivers/mtd/mtdram.c +++ b/drivers/mtd/mtdram.c @@ -1,6 +1,6 @@ /* * mtdram - a test mtd device - * $Id: mtdram.c,v 1.13 2000/07/03 10:01:38 dwmw2 Exp $ + * $Id: mtdram.c,v 1.15 2000/07/13 12:40:46 scote1 Exp $ * Author: Alexander Larsson <alex@cendio.se> * * Copyright (c) 1999 Alexander Larsson <alex@cendio.se> @@ -17,8 +17,8 @@ #include <linux/mtd/mtd.h> -#define MTDRAM_TOTAL_SIZE 1024*1024*8 -#define MTDRAM_ERASE_SIZE 4*1024 +#define MTDRAM_TOTAL_SIZE (CONFIG_MTDRAM_TOTAL_SIZE * 1024) +#define MTDRAM_ERASE_SIZE (CONFIG_MTDRAM_ERASE_SIZE * 1024) // We could store these in the mtd structure, but we only support 1 device.. diff --git a/drivers/mtd/nftl.c b/drivers/mtd/nftl.c index 182ec5a96..e7040863f 100644 --- a/drivers/mtd/nftl.c +++ b/drivers/mtd/nftl.c @@ -2,7 +2,7 @@ /* Linux driver for NAND Flash Translation Layer */ /* (c) 1999 Machine Vision Holdings, Inc. */ /* Author: David Woodhouse <dwmw2@infradead.org> */ -/* $Id: nftl.c,v 1.35 2000/07/06 14:35:01 dwmw2 Exp $ */ +/* $Id: nftl.c,v 1.36 2000/07/13 14:14:20 dwmw2 Exp $ */ /* The contents of this file are distributed under the GNU Public @@ -1293,7 +1293,7 @@ int __init init_nftl(void) printk(KERN_NOTICE "M-Systems NAND Flash Translation Layer driver. (C) 1999 MVHI\n"); #ifdef PRERELEASE - printk(KERN_INFO"$Id: nftl.c,v 1.35 2000/07/06 14:35:01 dwmw2 Exp $\n"); + printk(KERN_INFO"$Id: nftl.c,v 1.36 2000/07/13 14:14:20 dwmw2 Exp $\n"); #endif if (register_blkdev(NFTL_MAJOR, "nftl", &nftl_fops)){ diff --git a/drivers/mtd/nora.c b/drivers/mtd/nora.c index a92e47734..9304d7e62 100644 --- a/drivers/mtd/nora.c +++ b/drivers/mtd/nora.c @@ -1,5 +1,5 @@ /* - * $Id: nora.c,v 1.11 2000/07/04 16:42:50 dwmw2 Exp $ + * $Id: nora.c,v 1.12 2000/07/13 10:32:33 dwmw2 Exp $ * * This is so simple I love it. */ @@ -125,7 +125,7 @@ static struct mtd_info nora_mtds[4] = { /* boot, kernel, ramdisk, fs */ { type: MTD_NORFLASH, flags: MTD_CAP_NORFLASH, - size: 0x1a0000, + size: 0x0a0000, erasesize: 0x20000, name: "NORA kernel", module: THIS_MODULE, @@ -140,9 +140,9 @@ static struct mtd_info nora_mtds[4] = { /* boot, kernel, ramdisk, fs */ { type: MTD_NORFLASH, flags: MTD_CAP_NORFLASH, - size: 0xe00000, + size: 0xf00000, erasesize: 0x20000, - name: "NORA ramdisk", + name: "NORA root filesystem", module: THIS_MODULE, erase: nora_mtd_erase, read: nora_mtd_read, @@ -150,14 +150,14 @@ static struct mtd_info nora_mtds[4] = { /* boot, kernel, ramdisk, fs */ suspend: nora_mtd_suspend, resume: nora_mtd_resume, sync: nora_mtd_sync, - priv: (void *)0x200000 + priv: (void *)0x100000 }, { type: MTD_NORFLASH, flags: MTD_CAP_NORFLASH, size: 0x1000000, erasesize: 0x20000, - name: "NORA filesystem", + name: "NORA main filesystem", module: THIS_MODULE, erase: nora_mtd_erase, read: nora_mtd_read, diff --git a/drivers/mtd/octagon-5066.c b/drivers/mtd/octagon-5066.c index 167e0da13..b184cd0e7 100644 --- a/drivers/mtd/octagon-5066.c +++ b/drivers/mtd/octagon-5066.c @@ -1,4 +1,4 @@ -// $Id: octagon-5066.c,v 1.9 2000/07/03 10:01:38 dwmw2 Exp $ +// $Id: octagon-5066.c,v 1.10 2000/07/13 14:04:23 dwmw2 Exp $ /* ###################################################################### Octagon 5066 MTD Driver. @@ -56,8 +56,8 @@ static inline void oct5066_page(struct map_info *map, unsigned long ofs) { __u8 byte = map->map_priv_1 | (ofs >> WINDOW_SHIFT); - if (page_n_dev != byte); - __oct5066_page(map, byte); + if (page_n_dev != byte) + __oct5066_page(map, byte); } diff --git a/drivers/mtd/pmc551.c b/drivers/mtd/pmc551.c index 98d5c3069..fdc80cbcf 100644 --- a/drivers/mtd/pmc551.c +++ b/drivers/mtd/pmc551.c @@ -1,5 +1,5 @@ /* - * $Id: pmc551.c,v 1.7 2000/07/03 10:01:38 dwmw2 Exp $ + * $Id: pmc551.c,v 1.8 2000/07/14 07:53:31 dwmw2 Exp $ * * PMC551 PCI Mezzanine Ram Device * @@ -53,6 +53,7 @@ * hang w/ a reboot beeing the only chance at recover. */ +#include <linux/config.h> #include <linux/kernel.h> #include <linux/module.h> #include <asm/uaccess.h> @@ -343,7 +344,7 @@ out: */ static u32 fixup_pmc551 (struct pci_dev *dev) { -#ifdef PMC551_DRAM_BUG +#ifdef CONFIG_MTD_PMC551_BUGFIX u32 dram_data; #endif u32 size, dcmd; @@ -362,7 +363,7 @@ static u32 fixup_pmc551 (struct pci_dev *dev) * row mux values. We fix them here, but this will break other * memory configurations. */ -#ifdef PMC551_DRAM_BUG +#ifdef CONFIG_MTD_PMC551_BUGFIX pci_read_config_dword(dev, PMC551_DRAM_BLK0, &dram_data); size = PMC551_DRAM_BLK_GET_SIZE(dram_data); dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5); @@ -386,7 +387,7 @@ static u32 fixup_pmc551 (struct pci_dev *dev) dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5); dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9); pci_write_config_dword(dev, PMC551_DRAM_BLK3, dram_data); -#endif /* PMC551_DRAM_BUG */ +#endif /* CONFIG_MTD_PMC551_BUGFIX */ /* * Oops .. something went wrong @@ -550,7 +551,7 @@ int __init init_pmc551(void) printk(KERN_NOTICE "Ramix PMC551 PCI Mezzanine Ram Driver. (C) 1999,2000 Nortel Networks.\n"); - printk(KERN_INFO "$Id: pmc551.c,v 1.7 2000/07/03 10:01:38 dwmw2 Exp $\n"); + printk(KERN_INFO "$Id: pmc551.c,v 1.8 2000/07/14 07:53:31 dwmw2 Exp $\n"); if(!pci_present()) { printk(KERN_NOTICE "pmc551: PCI not enabled.\n"); diff --git a/drivers/mtd/pnc2000.c b/drivers/mtd/pnc2000.c new file mode 100644 index 000000000..4e4b052a7 --- /dev/null +++ b/drivers/mtd/pnc2000.c @@ -0,0 +1,210 @@ +/* + * pnc2000.c - mapper for Photron PNC-2000 board. + * + * Copyright (C) 2000 Crossnet Co. <info@crossnet.co.jp> + * + * This code is GPL + * + * $Id: pnc2000.c,v 1.1 2000/07/12 09:34:32 dwmw2 Exp $ + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> + + +#define WINDOW_ADDR 0xbf000000 +#define WINDOW_SIZE 0x00400000 + +/* + * MAP DRIVER STUFF + */ + +__u8 pnc_read8(struct map_info *map, unsigned long ofs) +{ + return *(__u8 *)(WINDOW_ADDR + ofs); +} + +__u16 pnc_read16(struct map_info *map, unsigned long ofs) +{ + return *(__u16 *)(WINDOW_ADDR + ofs); +} + +__u32 pnc_read32(struct map_info *map, unsigned long ofs) +{ + return *(volatile unsigned int *)(WINDOW_ADDR + ofs); +} + +void pnc_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy(to, (void *)(WINDOW_ADDR + from), len); +} + +void pnc_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + *(__u8 *)(WINDOW_ADDR + adr) = d; +} + +void pnc_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + *(__u16 *)(WINDOW_ADDR + adr) = d; +} + +void pnc_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + *(__u32 *)(WINDOW_ADDR + adr) = d; +} + +void pnc_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy((void *)(WINDOW_ADDR + to), from, len); +} + +struct map_info pnc_map = { + "PNC-2000", + WINDOW_SIZE, + 4, + pnc_read8, + pnc_read16, + pnc_read32, + pnc_copy_from, + pnc_write8, + pnc_write16, + pnc_write32, + pnc_copy_to, + 0, + 0 +}; + + +/* + * MTD 'PARTITIONING' STUFF + */ + +/* + * This is the _real_ MTD device for which all the others are just + * auto-relocating aliases. + */ +static struct mtd_info *mymtd; + +/* + * MTD methods which simply translate the effective address and pass through + * to the _real_ device. + */ + +static int pnc_mtd_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) +{ + return mymtd->read(mymtd, from + (unsigned long)mtd->priv, len, retlen, buf); +} + +static int pnc_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) +{ + return mymtd->write(mymtd, to + (unsigned long)mtd->priv, len, retlen, buf); +} + +static int pnc_mtd_erase (struct mtd_info *mtd, struct erase_info *instr) +{ + instr->addr += (unsigned long)mtd->priv; + return mymtd->erase(mymtd, instr); +} + +static void pnc_mtd_sync (struct mtd_info *mtd) +{ + mymtd->sync(mymtd); +} + +static int pnc_mtd_suspend (struct mtd_info *mtd) +{ + return mymtd->suspend(mymtd); +} + +static void pnc_mtd_resume (struct mtd_info *mtd) +{ + mymtd->resume(mymtd); +} + + +static struct mtd_info pnc_mtds[3] = { /* boot, kernel, fs */ + { + type: MTD_NORFLASH, + flags: MTD_CAP_NORFLASH, + size: 0x20000, + erasesize: 0x20000, + name: "PNC-2000 boot firmware", + module: THIS_MODULE, + erase: pnc_mtd_erase, + read: pnc_mtd_read, + write: pnc_mtd_write, + suspend: pnc_mtd_suspend, + resume: pnc_mtd_resume, + sync: pnc_mtd_sync, + priv: (void *)0 + }, + { + type: MTD_NORFLASH, + flags: MTD_CAP_NORFLASH, + size: 0x1a0000, + erasesize: 0x20000, + name: "PNC-2000 kernel", + module: THIS_MODULE, + erase: pnc_mtd_erase, + read: pnc_mtd_read, + write: pnc_mtd_write, + suspend: pnc_mtd_suspend, + resume: pnc_mtd_resume, + sync: pnc_mtd_sync, + priv: (void *)0x20000 + }, + { + type: MTD_NORFLASH, + flags: MTD_CAP_NORFLASH, + size: 0x240000, + erasesize: 0x20000, + name: "PNC-2000 filesystem", + module: THIS_MODULE, + erase: pnc_mtd_erase, + read: pnc_mtd_read, + write: pnc_mtd_write, + suspend: pnc_mtd_suspend, + resume: pnc_mtd_resume, + sync: pnc_mtd_sync, + priv: (void *)0x1c0000 + } +}; + +#if LINUX_VERSION_CODE < 0x20300 +#ifdef MODULE +#define init_pnc init_module +#define cleanup_pnc cleanup_module +#endif +#endif + +int __init init_pnc(void) +{ + printk(KERN_NOTICE "Photron PNC-2000 flash mapping: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR); + + mymtd = do_cfi_probe(&pnc_map); + if (mymtd) { + mymtd->module = THIS_MODULE; + + add_mtd_device(&pnc_mtds[0]); /* boot */ + add_mtd_device(&pnc_mtds[1]); /* kernel */ + add_mtd_device(&pnc_mtds[2]); /* file system */ + return 0; + } + + return -ENXIO; +} + +static void __exit cleanup_pnc(void) +{ + if (mymtd) { + del_mtd_device(&pnc_mtds[2]); + del_mtd_device(&pnc_mtds[1]); + del_mtd_device(&pnc_mtds[0]); + map_destroy(mymtd); + } +} diff --git a/drivers/net/atari_bionet.c b/drivers/net/atari_bionet.c index b0d8e73d4..275ef3296 100644 --- a/drivers/net/atari_bionet.c +++ b/drivers/net/atari_bionet.c @@ -158,7 +158,7 @@ static int bionet_close(struct net_device *dev); static struct net_device_stats *net_get_stats(struct net_device *dev); static void bionet_tick(unsigned long); -static struct timer_list bionet_timer = { NULL, NULL, 0, 0, bionet_tick }; +static struct timer_list bionet_timer = { function: bionet_tick }; #define STRAM_ADDR(a) (((a) & 0xff000000) == 0) diff --git a/drivers/net/atari_pamsnet.c b/drivers/net/atari_pamsnet.c index f9b1eef79..6aeb737d5 100644 --- a/drivers/net/atari_pamsnet.c +++ b/drivers/net/atari_pamsnet.c @@ -168,7 +168,7 @@ static void pamsnet_tick(unsigned long); static void pamsnet_intr(int irq, void *data, struct pt_regs *fp); -static struct timer_list pamsnet_timer = { NULL, NULL, 0, 0, pamsnet_tick }; +static struct timer_list pamsnet_timer = { function: amsnet_tick }; #define STRAM_ADDR(a) (((a) & 0xff000000) == 0) diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c index e136e0132..b749908bd 100644 --- a/drivers/net/de4x5.c +++ b/drivers/net/de4x5.c @@ -3271,6 +3271,7 @@ srom_map_media(struct net_device *dev) case ANS: lp->media = ANS; + lp->fdx = lp->params.fdx; break; default: diff --git a/drivers/net/pcmcia/xircom_tulip_cb.c b/drivers/net/pcmcia/xircom_tulip_cb.c index f8075373e..46f37e946 100644 --- a/drivers/net/pcmcia/xircom_tulip_cb.c +++ b/drivers/net/pcmcia/xircom_tulip_cb.c @@ -3010,7 +3010,8 @@ static void set_rx_mode(struct net_device *dev) /* Same setup recently queued, we need not add it. */ } else { unsigned long flags; - unsigned int entry, dummy = -1; + unsigned int entry; + int dummy = -1; save_flags(flags); cli(); entry = tp->cur_tx++ % TX_RING_SIZE; diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index e43e3b394..f59653eef 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -41,6 +41,7 @@ #include <linux/ip.h> #include <linux/tcp.h> #include <linux/spinlock.h> +#include <linux/smp_lock.h> #include <net/slhc_vj.h> #include <asm/atomic.h> @@ -319,6 +320,7 @@ static int ppp_release(struct inode *inode, struct file *file) { struct ppp_file *pf = (struct ppp_file *) file->private_data; + lock_kernel(); if (pf != 0) { file->private_data = 0; if (atomic_dec_and_test(&pf->refcnt)) { @@ -332,6 +334,7 @@ static int ppp_release(struct inode *inode, struct file *file) } } } + unlock_kernel(); return 0; } diff --git a/drivers/net/sk_g16.c b/drivers/net/sk_g16.c index 1a6da6e79..8ecc46db2 100644 --- a/drivers/net/sk_g16.c +++ b/drivers/net/sk_g16.c @@ -632,6 +632,8 @@ static int __init SK_init_module (void) if (!SK_dev) return -ENOMEM; + SK_dev->base_addr = io; + rc = SK_init (SK_dev); if (rc) { unregister_netdev (SK_dev); diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 9079f8113..4f6252383 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -19,8 +19,6 @@ */ -static const char version[] = "Linux Tulip driver version 0.9.7 (June 17, 2000)\n"; - #include <linux/module.h> #include "tulip.h" #include <linux/pci.h> @@ -29,6 +27,9 @@ static const char version[] = "Linux Tulip driver version 0.9.7 (June 17, 2000)\ #include <linux/delay.h> #include <asm/unaligned.h> +static char version[] __devinitdata = + "Linux Tulip driver version 0.9.8 (July 13, 2000)\n"; + /* A few user-configurable values. */ @@ -948,7 +949,8 @@ static void set_rx_mode(struct net_device *dev) if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) { /* Same setup recently queued, we need not add it. */ } else { - unsigned int entry, dummy = -1; + unsigned int entry; + int dummy = -1; /* Now add this frame to the Tx list. */ diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile index d45f0ccfd..371153a47 100644 --- a/drivers/net/wan/Makefile +++ b/drivers/net/wan/Makefile @@ -175,6 +175,7 @@ ifeq ($(CONFIG_SDLA),y) else ifeq ($(CONFIG_SDLA),m) M_OBJS += sdla.o + endif endif ifeq ($(CONFIG_VENDOR_SANGOMA),y) @@ -194,8 +195,6 @@ ifeq ($(CONFIG_VENDOR_SANGOMA),y) endif endif -endif - ifeq ($(CONFIG_VENDOR_SANGOMA),m) MX_OBJS += sdladrv.o M_OBJS += wanpipe.o diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index dc0b212f5..be015f195 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -93,6 +93,7 @@ #include <linux/ioport.h> #include <linux/netdevice.h> #include <linux/spinlock.h> +#include <linux/smp_lock.h> #undef COSA_SLOW_IO /* for testing purposes only */ #undef REALLY_SLOW_IO @@ -977,13 +978,16 @@ static int cosa_open(struct inode *inode, struct file *file) static int cosa_release(struct inode *inode, struct file *file) { struct channel_data *channel = (struct channel_data *)file->private_data; - struct cosa_data *cosa = channel->cosa; + struct cosa_data *cosa; unsigned long flags; + lock_kernel(); + cosa = channel->cosa; spin_lock_irqsave(&cosa->lock, flags); cosa->usage--; channel->usage--; spin_unlock_irqrestore(&cosa->lock, flags); + unlock_kernel(); return 0; } diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c index eff2559d0..207c9e21c 100644 --- a/drivers/net/wan/cycx_main.c +++ b/drivers/net/wan/cycx_main.c @@ -13,6 +13,8 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* 2000/07/13 acme remove useless #ifdef MODULE and crap +* #if KERNEL_VERSION > blah * 2000/07/06 acme __exit at cyclomx_cleanup * 2000/04/02 acme dprintk and cycx_debug * module_init/module_exit @@ -50,22 +52,18 @@ unsigned int cycx_debug = 0; -#ifdef MODULE MODULE_AUTHOR("Arnaldo Carvalho de Melo"); MODULE_DESCRIPTION("Cyclom 2X Sync Card Driver."); MODULE_PARM(debug, "i"); MODULE_PARM_DESC(debug, "cyclomx debug level"); -#endif /* Defines & Macros */ #define DRV_VERSION 0 /* version number */ -#define DRV_RELEASE 8 /* release (minor version) number */ +#define DRV_RELEASE 9 /* release (minor version) number */ #define MAX_CARDS 1 /* max number of adapters */ -#ifndef CONFIG_CYCLOMX_CARDS /* configurable option */ #define CONFIG_CYCLOMX_CARDS 1 -#endif /* Function Prototypes */ @@ -225,11 +223,7 @@ static int setup (wan_device_t *wandev, wandev_conf_t *conf) card->hw.dpmsize = CYCX_WINDOWSIZE; card->hw.fwid = CFID_X25_2X; card->lock = SPIN_LOCK_UNLOCKED; -#if LINUX_VERSION_CODE >= 0x020300 init_waitqueue_head(&card->wait_stats); -#else - card->wait_stats = NULL; -#endif err = cycx_setup(&card->hw, conf->data, conf->data_size); if (err) { diff --git a/drivers/parport/ChangeLog b/drivers/parport/ChangeLog index d408c8796..34446db01 100644 --- a/drivers/parport/ChangeLog +++ b/drivers/parport/ChangeLog @@ -1,4 +1,40 @@ -2000-06-30 Gunther Mayer <gunther.mayer@braunschweig.okersurf.de> +2000-07-12 Tim Waugh <twaugh@redhat.com> + + * share.c: Documentation for parport_{get,port}_port, + parport_find_{number,base}. + +2000-07-12 Tim Waugh <twaugh@redhat.com> + + * share.c (parport_unregister_device): Remove unneeded locking + (test cad==dev). + (parport_claim): Likewise. + (parport_find_number): New function. + +2000-07-12 Tim Waugh <twaugh@redhat.com> + + * share.c (parport_register_port): Hold the parportlist_lock while + looking for a free parport number. + (parport_register_driver): Make sure that attach can block. + (attach_driver_chain): Likewise. + +2000-07-12 Tim Waugh <twaugh@redhat.com> + + * share.c (call_driver_chain): Do reference counting things. + (parport_get_port): New function. + (parport_put_port): New function. + (parport_register_port): Initialise reference count to zero. + (parport_unregister_port): Check reference count rather than + driver list to see if we can free the port. + +2000-07-12 Tim Waugh <twaugh@redhat.com> + + * share.c: Clarifications in doc comments. + +2000-07-12 Tim Waugh <twaugh@redhat.com> + + * share.c (parport_unregister_port): Fix typo in comment. + +2000-07-11 Gunther Mayer <gunther.mayer@braunschweig.okersurf.de> * parport_pc.c: Support for the full range of Timedia cards. diff --git a/drivers/parport/init.c b/drivers/parport/init.c index 416ca51cb..90280e371 100644 --- a/drivers/parport/init.c +++ b/drivers/parport/init.c @@ -180,6 +180,10 @@ EXPORT_SYMBOL(parport_unregister_driver); EXPORT_SYMBOL(parport_register_device); EXPORT_SYMBOL(parport_unregister_device); EXPORT_SYMBOL(parport_enumerate); +EXPORT_SYMBOL(parport_get_port); +EXPORT_SYMBOL(parport_put_port); +EXPORT_SYMBOL(parport_find_number); +EXPORT_SYMBOL(parport_find_base); EXPORT_SYMBOL(parport_negotiate); EXPORT_SYMBOL(parport_write); EXPORT_SYMBOL(parport_read); diff --git a/drivers/parport/share.c b/drivers/parport/share.c index 9fe0bb4be..92618e7b4 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -88,17 +88,57 @@ static struct parport_operations dead_ops = { dead_read /* byte */ }; -static void call_driver_chain(int attach, struct parport *port) +/* Call attach(port) for each registered driver. */ +static void attach_driver_chain(struct parport *port) { struct parport_driver *drv; + void (**attach) (struct parport *); + int count = 0, i; + + /* This is complicated because attach() must be able to block, + * but we can't let it do that while we're holding a + * spinlock. */ spin_lock (&driverlist_lock); - for (drv = driver_chain; drv; drv = drv->next) { - if (attach) - drv->attach (port); - else - drv->detach (port); + for (drv = driver_chain; drv; drv = drv->next) + count++; + spin_unlock (&driverlist_lock); + + /* Drivers can unregister here; that's okay. If they register + * they'll be given an attach during parport_register_driver, + * so that's okay too. The only worry is that someone might + * get given an attach twice if they registered just before + * this function gets called. */ + + /* Hmm, this could be fixed with a generation number.. + * FIXME */ + + attach = kmalloc (sizeof (void(*)(struct parport *)) * count, + GFP_KERNEL); + if (!attach) { + printk (KERN_WARNING "parport: not enough memory to attach\n"); + return; } + + spin_lock (&driverlist_lock); + for (i = 0, drv = driver_chain; drv && i < count; drv = drv->next) + attach[i++] = drv->attach; + spin_unlock (&driverlist_lock); + + for (count = 0; count < i; count++) + (*attach[i]) (port); + + kfree (attach); +} + +/* Call detach(port) for each registered driver. */ +static void detach_driver_chain(struct parport *port) +{ + struct parport_driver *drv; + + spin_lock (&driverlist_lock); + for (drv = driver_chain; drv; drv = drv->next) + drv->detach (port); spin_unlock (&driverlist_lock); } @@ -121,27 +161,62 @@ static void get_lowlevel_driver (void) * The @drv structure is allocated by the caller and must not be * deallocated until after calling parport_unregister_driver(). * + * The driver's attach() function may block. The port that + * attach() is given will be valid for the duration of the + * callback, but if the driver wants to take a copy of the + * pointer it must call parport_get_port() to do so. Calling + * parport_register_device() on that port will do this for you. + * + * The driver's detach() function may not block. The port that + * detach() is given will be valid for the duration of the + * callback, but if the driver wants to take a copy of the + * pointer it must call parport_get_port() to do so. + * * Returns 0 on success. Currently it always succeeds. **/ int parport_register_driver (struct parport_driver *drv) { struct parport *port; + struct parport **ports; + int count = 0, i; - spin_lock (&driverlist_lock); - drv->next = driver_chain; - driver_chain = drv; - spin_unlock (&driverlist_lock); + if (!portlist) + get_lowlevel_driver (); /* We have to take the portlist lock for this to be sure * that port is valid for the duration of the callback. */ + + /* This is complicated by the fact that attach must be allowed + * to block, so we can't be holding any spinlocks when we call + * it. But we need to hold a spinlock to iterate over the + * list of ports.. */ + spin_lock (&parportlist_lock); for (port = portlist; port; port = port->next) - drv->attach (port); + count++; spin_unlock (&parportlist_lock); - if (!portlist) - get_lowlevel_driver (); + ports = kmalloc (sizeof (struct parport *) * count, GFP_KERNEL); + if (!ports) + printk (KERN_WARNING "parport: not enough memory to attach\n"); + else { + spin_lock (&parportlist_lock); + for (i = 0, port = portlist; port && i < count; + port = port->next) + ports[i++] = port; + spin_unlock (&parportlist_lock); + + for (count = 0; count < i; count++) + drv->attach (ports[count]); + + kfree (ports); + } + + spin_lock (&driverlist_lock); + drv->next = driver_chain; + driver_chain = drv; + spin_unlock (&driverlist_lock); return 0; } @@ -162,6 +237,11 @@ int parport_register_driver (struct parport_driver *drv) * If the caller's attach() function can block, it is their * responsibility to make sure to wait for it to exit before * unloading. + * + * All the driver's detach() calls are guaranteed to have + * finished by the time this function returns. + * + * The driver's detach() call is not allowed to block. **/ void parport_unregister_driver (struct parport_driver *arg) @@ -194,6 +274,57 @@ void parport_unregister_driver (struct parport_driver *arg) } } +static void free_port (struct parport *port) +{ + int d; + for (d = 0; d < 5; d++) { + if (port->probe_info[d].class_name) + kfree (port->probe_info[d].class_name); + if (port->probe_info[d].mfr) + kfree (port->probe_info[d].mfr); + if (port->probe_info[d].model) + kfree (port->probe_info[d].model); + if (port->probe_info[d].cmdset) + kfree (port->probe_info[d].cmdset); + if (port->probe_info[d].description) + kfree (port->probe_info[d].description); + } + + kfree(port->name); + kfree(port); +} + +/** + * parport_get_port - increment a port's reference count + * @port: the port + * + * This ensure's that a struct parport pointer remains valid + * until the matching parport_put_port() call. + **/ + +struct parport *parport_get_port (struct parport *port) +{ + atomic_inc (&port->ref_count); + return port; +} + +/** + * parport_put_port - decrement a port's reference count + * @port: the port + * + * This should be called once for each call to parport_get_port(), + * once the port is no longer needed. + **/ + +void parport_put_port (struct parport *port) +{ + if (atomic_dec_and_test (&port->ref_count)) + /* Can destroy it now. */ + free_port (port); + + return; +} + /** * parport_enumerate - return a list of the system's parallel ports * @@ -260,6 +391,8 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, } /* Search for the lowest free parport number. */ + + spin_lock_irq (&parportlist_lock); for (portnum = 0; ; portnum++) { struct parport *itr = portlist; while (itr) { @@ -274,6 +407,7 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, /* Got to the end of the list. */ break; } + spin_unlock_irq (&parportlist_lock); /* Init our structure */ memset(tmp, 0, sizeof(struct parport)); @@ -296,6 +430,7 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, tmp->ieee1284.phase = IEEE1284_PH_FWD_IDLE; init_MUTEX_LOCKED (&tmp->ieee1284.irq); /* actually a semaphore at 0 */ tmp->spintime = parport_default_spintime; + atomic_set (&tmp->ref_count, 1); name = kmalloc(15, GFP_KERNEL); if (!name) { @@ -372,27 +507,7 @@ void parport_announce_port (struct parport *port) #endif /* Let drivers know that a new port has arrived. */ - call_driver_chain (1, port); -} - -static void free_port (struct parport *port) -{ - int d; - for (d = 0; d < 5; d++) { - if (port->probe_info[d].class_name) - kfree (port->probe_info[d].class_name); - if (port->probe_info[d].mfr) - kfree (port->probe_info[d].mfr); - if (port->probe_info[d].model) - kfree (port->probe_info[d].model); - if (port->probe_info[d].cmdset) - kfree (port->probe_info[d].cmdset); - if (port->probe_info[d].description) - kfree (port->probe_info[d].description); - } - - kfree(port->name); - kfree(port); + attach_driver_chain (port); } /** @@ -421,7 +536,7 @@ void parport_unregister_port(struct parport *port) port->ops = &dead_ops; /* Spread the word. */ - call_driver_chain (0, port); + detach_driver_chain (port); #ifdef CONFIG_PARPORT_1284 /* Forget the IEEE1284.3 topology of the port. */ @@ -431,7 +546,7 @@ void parport_unregister_port(struct parport *port) spin_lock(&parportlist_lock); /* We are protected from other people changing the list, but - * they can see see it (using parport_enumerate). So be + * they can still see it (using parport_enumerate). So be * careful about the order of writes.. */ if (portlist == port) { if ((portlist = port->next) == NULL) @@ -449,8 +564,7 @@ void parport_unregister_port(struct parport *port) spin_unlock(&parportlist_lock); /* Yes, parport_enumerate _is_ unsafe. Don't use it. */ - if (!port->devices) - free_port (port); + parport_put_port (port); } /** @@ -552,6 +666,7 @@ parport_register_device(struct parport *port, const char *name, parport_register_device.. */ inc_parport_count(); port->ops->inc_use_count(); + parport_get_port (port); tmp = kmalloc(sizeof(struct pardevice), GFP_KERNEL); if (tmp == NULL) { @@ -623,6 +738,7 @@ parport_register_device(struct parport *port, const char *name, out: dec_parport_count(); port->ops->dec_use_count(); + parport_put_port (port); return NULL; } @@ -636,7 +752,6 @@ parport_register_device(struct parport *port, const char *name, void parport_unregister_device(struct pardevice *dev) { struct parport *port; - unsigned long flags; #ifdef PARPORT_PARANOID if (dev == NULL) { @@ -649,14 +764,11 @@ void parport_unregister_device(struct pardevice *dev) port = dev->port->physport; - read_lock_irqsave (&port->cad_lock, flags); if (port->cad == dev) { - read_unlock_irqrestore (&port->cad_lock, flags); printk(KERN_DEBUG "%s: %s forgot to release port\n", port->name, dev->name); parport_release (dev); } - read_unlock_irqrestore (&port->cad_lock, flags); spin_lock(&port->pardevice_lock); if (dev->next) @@ -676,11 +788,7 @@ void parport_unregister_device(struct pardevice *dev) dec_parport_count(); port->ops->dec_use_count(); - - /* If this was the last device on a port that's already gone away, - * free up the resources. */ - if (port->ops == &dead_ops && !port->devices) - free_port (port); + parport_put_port (port); /* Yes, that's right, someone _could_ still have a pointer to * port, if they used parport_enumerate. That's why they @@ -689,6 +797,56 @@ void parport_unregister_device(struct pardevice *dev) } /** + * parport_find_number - find a parallel port by number + * @number: parallel port number + * + * This returns the parallel port with the specified number, or + * %NULL if there is none. + * + * There is an implicit parport_get_port() done already; to throw + * away the reference to the port that parport_find_number() + * gives you, use parport_put_port(). + */ + +struct parport *parport_find_number (int number) +{ + struct parport *port, *result = NULL; + spin_lock (&parportlist_lock); + for (port = portlist; port; port = port->next) + if (port->number == number) { + result = parport_get_port (port); + break; + } + spin_unlock (&parportlist_lock); + return result; +} + +/** + * parport_find_base - find a parallel port by base address + * @base: base I/O address + * + * This returns the parallel port with the specified base + * address, or %NULL if there is none. + * + * There is an implicit parport_get_port() done already; to throw + * away the reference to the port that parport_find_base() + * gives you, use parport_put_port(). + */ + +struct parport *parport_find_base (unsigned long base) +{ + struct parport *port, *result = NULL; + spin_lock (&parportlist_lock); + for (port = portlist; port; port = port->next) + if (port->base == base) { + result = parport_get_port (port); + break; + } + spin_unlock (&parportlist_lock); + return result; +} + +/** * parport_claim - claim access to a parallel port device * @dev: pointer to structure representing a device on the port * @@ -706,14 +864,11 @@ int parport_claim(struct pardevice *dev) struct parport *port = dev->port->physport; unsigned long flags; - read_lock_irqsave (&port->cad_lock, flags); if (port->cad == dev) { - read_unlock_irqrestore (&port->cad_lock, flags); printk(KERN_INFO "%s: %s already owner\n", dev->port->name,dev->name); return 0; } - read_unlock_irqrestore (&port->cad_lock, flags); /* Preempt any current device */ write_lock_irqsave (&port->cad_lock, flags); diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 11e4330c5..f536e42cb 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -42,6 +42,7 @@ #include <linux/mm.h> #include <linux/fcntl.h> #include <linux/sched.h> +#include <linux/smp_lock.h> #include <linux/timer.h> #include <linux/ioctl.h> #include <linux/proc_fs.h> @@ -561,7 +562,6 @@ static int ds_open(struct inode *inode, struct file *file) user = kmalloc(sizeof(user_info_t), GFP_KERNEL); if (!user) return -ENOMEM; - MOD_INC_USE_COUNT; user->event_tail = user->event_head = 0; user->next = s->user; user->user_magic = USER_MAGIC; @@ -584,10 +584,11 @@ static int ds_release(struct inode *inode, struct file *file) DEBUG(0, "ds_release(socket %d)\n", i); if ((i >= sockets) || (sockets == 0)) return 0; + lock_kernel(); s = &socket_table[i]; user = file->private_data; if (CHECK_USER(user)) - return 0; + goto out; /* Unlink user data structure */ if ((file->f_flags & O_ACCMODE) != O_RDONLY) @@ -596,12 +597,12 @@ static int ds_release(struct inode *inode, struct file *file) for (link = &s->user; *link; link = &(*link)->next) if (*link == user) break; if (link == NULL) - return 0; + goto out; *link = user->next; user->user_magic = 0; kfree(user); - - MOD_DEC_USE_COUNT; +out: + unlock_kernel(); return 0; } /* ds_release */ @@ -854,12 +855,13 @@ static int ds_ioctl(struct inode * inode, struct file * file, /*====================================================================*/ static struct file_operations ds_fops = { - open: ds_open, - release: ds_release, - ioctl: ds_ioctl, - read: ds_read, - write: ds_write, - poll: ds_poll, + owner: THIS_MODULE, + open: ds_open, + release: ds_release, + ioctl: ds_ioctl, + read: ds_read, + write: ds_write, + poll: ds_poll, }; EXPORT_SYMBOL(register_pccard_driver); diff --git a/drivers/pnp/isapnp_proc.c b/drivers/pnp/isapnp_proc.c index 3472225b8..ee4c2aee3 100644 --- a/drivers/pnp/isapnp_proc.c +++ b/drivers/pnp/isapnp_proc.c @@ -187,10 +187,12 @@ static int isapnp_info_entry_release(struct inode *inode, struct file *file) if ((buffer = (isapnp_info_buffer_t *) file->private_data) == NULL) return -EINVAL; mode = file->f_flags & O_ACCMODE; + lock_kernel(); if (mode == O_WRONLY) isapnp_info_write(buffer); vfree(buffer->buffer); kfree(buffer); + unlock_kernel(); return 0; } diff --git a/drivers/sbus/audio/audio.c b/drivers/sbus/audio/audio.c index be7e9de06..6ee5c6d3c 100644 --- a/drivers/sbus/audio/audio.c +++ b/drivers/sbus/audio/audio.c @@ -24,6 +24,7 @@ #include <linux/fs.h> #include <linux/kernel.h> #include <linux/sched.h> +#include <linux/smp_lock.h> #include <linux/mm.h> #include <linux/tqueue.h> #include <linux/major.h> @@ -1910,6 +1911,7 @@ static int sparcaudio_release(struct inode * inode, struct file * file) struct sparcaudio_driver *drv = drivers[(MINOR(inode->i_rdev) >> SPARCAUDIO_DEVICE_SHIFT)]; + lock_kernel(); if (file->f_mode & FMODE_READ) { /* Stop input */ drv->ops->stop_input(drv); @@ -1951,11 +1953,13 @@ static int sparcaudio_release(struct inode * inode, struct file * file) kill_procs(drv->sd_siglist,SIGPOLL,S_MSG); wake_up_interruptible(&drv->open_wait); + unlock_kernel(); return 0; } static struct file_operations sparcaudio_fops = { + owner: THIS_MODULE, llseek: sparcaudio_lseek, read: sparcaudio_read, write: sparcaudio_write, diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c index ebe9928c2..56f9d38af 100644 --- a/drivers/sbus/char/bpp.c +++ b/drivers/sbus/char/bpp.c @@ -16,6 +16,7 @@ #include <linux/fs.h> #include <linux/errno.h> #include <linux/sched.h> +#include <linux/smp_lock.h> #include <linux/timer.h> #include <linux/ioport.h> #include <linux/major.h> @@ -456,10 +457,13 @@ static int bpp_open(struct inode *inode, struct file *f) static int bpp_release(struct inode *inode, struct file *f) { unsigned minor = MINOR(inode->i_rdev); + + lock_kernel(); instances[minor].opened = 0; if (instances[minor].mode != COMPATIBILITY) terminate(minor); + unlock_kernel(); return 0; } diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c index 8bdee5e04..7a03036b6 100644 --- a/drivers/sbus/char/flash.c +++ b/drivers/sbus/char/flash.c @@ -13,6 +13,7 @@ #include <linux/fcntl.h> #include <linux/poll.h> #include <linux/init.h> +#include <linux/smp_lock.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -37,23 +38,28 @@ flash_mmap(struct file *file, struct vm_area_struct *vma) unsigned long addr; unsigned long size; + lock_kernel(); if (flash.read_base == flash.write_base) { addr = flash.read_base; size = flash.read_size; } else { if ((vma->vm_flags & VM_READ) && - (vma->vm_flags & VM_WRITE)) + (vma->vm_flags & VM_WRITE)) { + unlock_kernel(); return -EINVAL; - + } if (vma->vm_flags & VM_READ) { addr = flash.read_base; size = flash.read_size; } else if (vma->vm_flags & VM_WRITE) { addr = flash.write_base; size = flash.write_size; - } else + } else { + unlock_kernel(); return -ENXIO; + } } + unlock_kernel(); if ((vma->vm_pgoff << PAGE_SHIFT) > size) return -ENXIO; @@ -121,7 +127,9 @@ flash_open(struct inode *inode, struct file *file) static int flash_release(struct inode *inode, struct file *file) { + lock_kernel(); flash.busy = 0; + unlock_kernel(); return 0; } diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c index b01f26969..f87850b2c 100644 --- a/drivers/sbus/char/jsflash.c +++ b/drivers/sbus/char/jsflash.c @@ -35,6 +35,7 @@ #include <linux/poll.h> #include <linux/init.h> #include <linux/string.h> +#include <linux/smp_lock.h> /* * <linux/blk.h> is controlled from the outside with these definitions. @@ -504,7 +505,9 @@ static int jsfd_open(struct inode *inode, struct file *file) static int jsf_release(struct inode *inode, struct file *file) { + lock_kernel(); jsf0.busy = 0; + unlock_kernel(); return 0; } diff --git a/drivers/sbus/char/pcikbd.c b/drivers/sbus/char/pcikbd.c index 93673e3b8..ecce4db4b 100644 --- a/drivers/sbus/char/pcikbd.c +++ b/drivers/sbus/char/pcikbd.c @@ -24,6 +24,7 @@ #include <linux/kbd_kern.h> #include <linux/delay.h> #include <linux/spinlock.h> +#include <linux/smp_lock.h> #include <linux/init.h> #include <asm/ebus.h> @@ -745,9 +746,10 @@ static int aux_release(struct inode * inode, struct file * file) { unsigned long flags; + lock_kernel(); aux_fasync(-1, file, 0); if (--aux_count) - return 0; + goto out; spin_lock_irqsave(&pcikbd_lock, flags); @@ -760,6 +762,8 @@ static int aux_release(struct inode * inode, struct file * file) poll_aux_status(); spin_unlock_irqrestore(&pcikbd_lock, flags); +out: + unlock_kernel(); return 0; } diff --git a/drivers/sbus/char/rtc.c b/drivers/sbus/char/rtc.c index bda9e3a26..7a02f543f 100644 --- a/drivers/sbus/char/rtc.c +++ b/drivers/sbus/char/rtc.c @@ -19,6 +19,7 @@ #include <linux/fcntl.h> #include <linux/poll.h> #include <linux/init.h> +#include <linux/smp_lock.h> #include <asm/mostek.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -129,7 +130,9 @@ static int rtc_open(struct inode *inode, struct file *file) static int rtc_release(struct inode *inode, struct file *file) { + lock_kernel(); rtc_busy = 0; + unlock_kernel(); return 0; } diff --git a/drivers/sbus/char/sunkbd.c b/drivers/sbus/char/sunkbd.c index 8004569ab..191194287 100644 --- a/drivers/sbus/char/sunkbd.c +++ b/drivers/sbus/char/sunkbd.c @@ -25,6 +25,7 @@ #include <linux/init.h> #include <linux/sysrq.h> #include <linux/spinlock.h> +#include <linux/smp_lock.h> #include <linux/devfs_fs_kernel.h> #include <asm/kbio.h> @@ -1527,16 +1528,15 @@ kbd_open (struct inode *i, struct file *f) static int kbd_close (struct inode *i, struct file *f) { - if (--kbd_active) - return 0; - - if (kbd_redirected) - kbd_table [kbd_redirected-1].kbdmode = VC_XLATE; - - kbd_redirected = 0; - kbd_opened = 0; - - kbd_fasync (-1, f, 0); + lock_kernel(); + if (!--kbd_active) { + if (kbd_redirected) + kbd_table [kbd_redirected-1].kbdmode = VC_XLATE; + kbd_redirected = 0; + kbd_opened = 0; + kbd_fasync (-1, f, 0); + } + unlock_kernel(); return 0; } diff --git a/drivers/sbus/char/sunmouse.c b/drivers/sbus/char/sunmouse.c index 46d335c2a..b9dd25653 100644 --- a/drivers/sbus/char/sunmouse.c +++ b/drivers/sbus/char/sunmouse.c @@ -49,6 +49,7 @@ #include <linux/mm.h> #include <linux/poll.h> #include <linux/spinlock.h> +#include <linux/smp_lock.h> #include <linux/init.h> #include <asm/uaccess.h> #include <asm/system.h> @@ -411,8 +412,10 @@ static int sun_mouse_fasync (int fd, struct file *filp, int on) static int sun_mouse_close(struct inode *inode, struct file *file) { + lock_kernel(); sun_mouse_fasync (-1, file, 0); sunmouse.active--; + unlock_kernel(); return 0; } diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c index eed298c6e..7b7a59ea2 100644 --- a/drivers/sbus/char/vfc_dev.c +++ b/drivers/sbus/char/vfc_dev.c @@ -21,6 +21,7 @@ #include <linux/errno.h> #include <linux/sched.h> #include <linux/fs.h> +#include <linux/smp_lock.h> #include <asm/openprom.h> #include <asm/oplib.h> @@ -203,16 +204,19 @@ static int vfc_open(struct inode *inode, struct file *file) return 0; } -static void vfc_release(struct inode *inode,struct file *file) +static int vfc_release(struct inode *inode,struct file *file) { struct vfc_dev *dev; + lock_kernel(); dev = vfc_get_dev_ptr(MINOR(inode->i_rdev)); - if (dev == NULL) - return; - if (!dev->busy) - return; + if (!dev || !dev->busy) { + unlock_kernel(); + return -EINVAL; + } dev->busy = 0; + unlock_kernel(); + return 0; } static int vfc_debug(struct vfc_dev *dev, int cmd, unsigned long arg) @@ -606,10 +610,12 @@ static int vfc_mmap(struct inode *inode, struct file *file, unsigned int map_size, ret, map_offset; struct vfc_dev *dev; + lock_kernel(); dev = vfc_get_dev_ptr(MINOR(inode->i_rdev)); - if(dev == NULL) + if(dev == NULL) { + unlock_kernel(); return -ENODEV; - + } map_size = vma->vm_end - vma->vm_start; if(map_size > sizeof(struct vfc_regs)) map_size = sizeof(struct vfc_regs); @@ -619,6 +625,7 @@ static int vfc_mmap(struct inode *inode, struct file *file, map_offset = (unsigned int) (long)dev->phys_regs; ret = io_remap_page_range(vma->vm_start, map_offset, map_size, vma->vm_page_prot, dev->which_io); + unlock_kernel(); if(ret) return -EAGAIN; diff --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c index 518f1e26e..b4ebd88f3 100644 --- a/drivers/scsi/pluto.c +++ b/drivers/scsi/pluto.c @@ -48,7 +48,6 @@ static struct ctrl_inquiry { } *fcs __initdata = { 0 }; static int fcscount __initdata = 0; static atomic_t fcss __initdata = ATOMIC_INIT(0); -static struct timer_list fc_timer __initdata = { function: NULL }; DECLARE_MUTEX_LOCKED(fc_sem); static int pluto_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd); @@ -92,6 +91,7 @@ int __init pluto_detect(Scsi_Host_Template *tpnt) int i, retry, nplutos; fc_channel *fc; Scsi_Device dev; + struct timer_list fc_timer = { function: pluto_detect_timeout }; tpnt->proc_name = "pluto"; fcscount = 0; @@ -121,7 +121,6 @@ int __init pluto_detect(Scsi_Host_Template *tpnt) memset (fcs, 0, sizeof (struct ctrl_inquiry) * fcscount); memset (&dev, 0, sizeof(dev)); atomic_set (&fcss, fcscount); - fc_timer.function = pluto_detect_timeout; i = 0; for_each_online_fc_channel(fc) { @@ -192,7 +191,7 @@ int __init pluto_detect(Scsi_Host_Template *tpnt) if (!atomic_read(&fcss)) break; /* All fc channels have answered us */ } - del_timer(&fc_timer); + del_timer_sync(&fc_timer); PLND(("Finished search\n")) for (i = 0, nplutos = 0; i < fcscount; i++) { diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 056b2f1b5..fd705d425 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -138,6 +138,10 @@ static struct dev_info device_list[] = {"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN}, {"TOSHIBA","CDROM","*", BLIST_ISROM}, {"MegaRAID", "LD", "*", BLIST_FORCELUN}, + {"DGC", "RAID", "*", BLIST_SPARSELUN}, // Dell PV 650F (tgt @ LUN 0) + {"DGC", "DISK", "*", BLIST_SPARSELUN}, // Dell PV 650F (no tgt @ LUN 0) + {"DELL", "PV530F", "*", BLIST_SPARSELUN}, // Dell PV 530F + {"SONY", "TSL", "*", BLIST_FORCELUN}, // DDS3 & DDS4 autoloaders /* * Must be at end of list... diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 4bfdc59f4..4ac3dbcfb 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -52,6 +52,7 @@ #include <linux/fcntl.h> #include <linux/init.h> #include <linux/poll.h> +#include <linux/smp_lock.h> #include <asm/io.h> #include <asm/uaccess.h> @@ -304,8 +305,6 @@ static int sg_open(struct inode * inode, struct file * filp) if (sdp->device->host->hostt->module) __MOD_INC_USE_COUNT(sdp->device->host->hostt->module); - if (sg_template.module) - __MOD_INC_USE_COUNT(sg_template.module); return 0; } @@ -315,8 +314,11 @@ static int sg_release(struct inode * inode, struct file * filp) Sg_device * sdp; Sg_fd * sfp; - if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) + lock_kernel(); + if ((! (sfp = (Sg_fd *)filp->private_data)) || (! (sdp = sfp->parentdp))) { + unlock_kernel(); return -ENXIO; + } SCSI_LOG_TIMEOUT(3, printk("sg_release: dev=%d\n", MINOR(sdp->i_rdev))); sg_fasync(-1, filp, 0); /* remove filp from async notification list */ sg_remove_sfp(sdp, sfp); @@ -325,10 +327,9 @@ static int sg_release(struct inode * inode, struct file * filp) if (sdp->device->host->hostt->module) __MOD_DEC_USE_COUNT(sdp->device->host->hostt->module); - if(sg_template.module) - __MOD_DEC_USE_COUNT(sg_template.module); sdp->exclude = 0; wake_up_interruptible(&sdp->o_excl_wait); + unlock_kernel(); return 0; } @@ -1094,13 +1095,14 @@ static void sg_cmd_done_bh(Scsi_Cmnd * SCpnt) } static struct file_operations sg_fops = { - read: sg_read, - write: sg_write, - poll: sg_poll, - ioctl: sg_ioctl, - open: sg_open, - release: sg_release, - fasync: sg_fasync, + owner: THIS_MODULE, + read: sg_read, + write: sg_write, + poll: sg_poll, + ioctl: sg_ioctl, + open: sg_open, + release: sg_release, + fasync: sg_fasync, }; diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index a605233c0..2ac10c832 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -31,6 +31,7 @@ #include <linux/ioctl.h> #include <linux/fcntl.h> #include <linux/spinlock.h> +#include <linux/smp_lock.h> #include <asm/uaccess.h> #include <asm/dma.h> #include <asm/system.h> @@ -620,8 +621,6 @@ static int scsi_tape_open(struct inode *inode, struct file *filp) if (STp->device->host->hostt->module) __MOD_INC_USE_COUNT(STp->device->host->hostt->module); - if (st_template.module) - __MOD_INC_USE_COUNT(st_template.module); if (mode != STp->current_mode) { DEBC(printk(ST_DEB_MSG "st%d: Mode change from %d to %d.\n", @@ -859,8 +858,6 @@ static int scsi_tape_open(struct inode *inode, struct file *filp) STp->in_use = 0; if (STp->device->host->hostt->module) __MOD_DEC_USE_COUNT(STp->device->host->hostt->module); - if (st_template.module) - __MOD_DEC_USE_COUNT(st_template.module); return retval; } @@ -995,6 +992,7 @@ static int scsi_tape_close(struct inode *inode, struct file *filp) int dev; dev = TAPE_NR(devt); + lock_kernel(); read_lock(&st_dev_arr_lock); STp = scsi_tapes[dev]; read_unlock(&st_dev_arr_lock); @@ -1010,8 +1008,7 @@ static int scsi_tape_close(struct inode *inode, struct file *filp) STp->in_use = 0; if (STp->device->host->hostt->module) __MOD_DEC_USE_COUNT(STp->device->host->hostt->module); - if (st_template.module) - __MOD_DEC_USE_COUNT(st_template.module); + unlock_kernel(); return result; } @@ -3428,6 +3425,7 @@ __setup("st=", st_setup); static struct file_operations st_fops = { + owner: THIS_MODULE, read: st_read, write: st_write, ioctl: st_ioctl, diff --git a/drivers/sgi/char/graphics.c b/drivers/sgi/char/graphics.c index a060e9895..62ca3c5e6 100644 --- a/drivers/sgi/char/graphics.c +++ b/drivers/sgi/char/graphics.c @@ -33,6 +33,7 @@ #include <linux/mman.h> #include <linux/malloc.h> #include <linux/module.h> +#include <linux/smp_lock.h> #include <asm/uaccess.h> #include "gconsole.h" #include "graphics.h" @@ -194,6 +195,7 @@ sgi_graphics_close (struct inode *inode, struct file *file) int board = GRAPHICS_CARD (inode->i_rdev); /* Tell the rendering manager that one client is going away */ + lock_kernel(); rrm_close (inode, file); /* Was this file handle from the board owner?, clear it */ @@ -203,6 +205,7 @@ sgi_graphics_close (struct inode *inode, struct file *file) (*cards [board].g_reset_console)(); enable_gconsole (); } + unlock_kernel(); return 0; } diff --git a/drivers/sgi/char/shmiq.c b/drivers/sgi/char/shmiq.c index 03eab91e2..1438030b3 100644 --- a/drivers/sgi/char/shmiq.c +++ b/drivers/sgi/char/shmiq.c @@ -329,9 +329,12 @@ shmiq_qcntl_mmap (struct file *file, struct vm_area_struct *vma) size = vma->vm_end - vma->vm_start; start = vma->vm_start; + lock_kernel(); mem = (unsigned long) shmiqs [minor].shmiq_vaddr = vmalloc_uncached (size); - if (!mem) + if (!mem) { + unlock_kernel(); return -EINVAL; + } /* Prevent the swapper from considering these pages for swap and touching them */ vma->vm_flags |= (VM_SHM | VM_LOCKED | VM_IO); @@ -345,6 +348,7 @@ shmiq_qcntl_mmap (struct file *file, struct vm_area_struct *vma) shmiqs [minor].tail = 0; /* Init the shared memory input queue */ memset (shmiqs [minor].shmiq_vaddr, 0, size); + unlock_kernel(); return error; } diff --git a/drivers/sgi/char/streamable.c b/drivers/sgi/char/streamable.c index 1f354d80f..1d2a65c2a 100644 --- a/drivers/sgi/char/streamable.c +++ b/drivers/sgi/char/streamable.c @@ -13,6 +13,7 @@ #include <linux/sched.h> #include <linux/kbd_kern.h> #include <linux/vt_kern.h> +#include <linux/smp_lock.h> #include <asm/uaccess.h> #include <asm/shmiq.h> #include <asm/keyboard.h> @@ -50,20 +51,6 @@ get_sioc (struct strioctl *sioc, unsigned long arg) /* /dev/gfx device */ static int -sgi_gfx_open (struct inode *inode, struct file *file) -{ - printk ("GFX: Opened by %d\n", current->pid); - return 0; -} - -static int -sgi_gfx_close (struct inode *inode, struct file *file) -{ - printk ("GFX: Closed by %d\n", current->pid); - return 0; -} - -static int sgi_gfx_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { printk ("GFX: ioctl 0x%x %ld called\n", cmd, arg); @@ -73,8 +60,6 @@ sgi_gfx_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigne struct file_operations sgi_gfx_fops = { ioctl: sgi_gfx_ioctl, - open: sgi_gfx_open, - release: sgi_gfx_close, }; static struct miscdevice dev_gfx = { @@ -236,7 +221,9 @@ sgi_mouse_open (struct inode *inode, struct file *file) static int sgi_mouse_close (struct inode *inode, struct file *filp) { + lock_kernel(); mouse_opened = 0; + unlock_kernel(); return 0; } diff --git a/drivers/sgi/char/usema.c b/drivers/sgi/char/usema.c index c9fbe87d4..4ae9d2e2b 100644 --- a/drivers/sgi/char/usema.c +++ b/drivers/sgi/char/usema.c @@ -163,17 +163,10 @@ sgi_usemaclone_open(struct inode *inode, struct file *filp) return 0; } -static int -sgi_usemaclone_release(struct inode *inode, struct file *filp) -{ - return 0; -} - struct file_operations sgi_usemaclone_fops = { poll: sgi_usemaclone_poll, ioctl: sgi_usemaclone_ioctl, open: sgi_usemaclone_open, - release: sgi_usemaclone_release, }; static struct miscdevice dev_usemaclone = { diff --git a/drivers/sound/cmpci.c b/drivers/sound/cmpci.c index 3b5639054..cc55d508e 100644 --- a/drivers/sound/cmpci.c +++ b/drivers/sound/cmpci.c @@ -114,6 +114,7 @@ #include <linux/init.h> #include <linux/poll.h> #include <linux/spinlock.h> +#include <linux/smp_lock.h> #include <asm/uaccess.h> #include <asm/hardirq.h> @@ -1397,29 +1398,35 @@ static int cm_mmap(struct file *file, struct vm_area_struct *vma) { struct cm_state *s = (struct cm_state *)file->private_data; struct dmabuf *db; - int ret; + int ret = -EINVAL; unsigned long size; VALIDATE_STATE(s); + lock_kernel(); if (vma->vm_flags & VM_WRITE) { if ((ret = prog_dmabuf(s, 1)) != 0) - return ret; + goto out; db = &s->dma_dac; } else if (vma->vm_flags & VM_READ) { if ((ret = prog_dmabuf(s, 0)) != 0) - return ret; + goto out; db = &s->dma_adc; } else - return -EINVAL; + goto out; + ret = -EINVAL; if (vma->vm_pgoff != 0) - return -EINVAL; + goto out; size = vma->vm_end - vma->vm_start; if (size > (PAGE_SIZE << db->buforder)) - return -EINVAL; + goto out; + ret = -EAGAIN; if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) - return -EAGAIN; + goto out; db->mapped = 1; - return 0; + ret = 0; +out: + unlock_kernel(); + return ret; } static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) @@ -1771,6 +1778,7 @@ static int cm_release(struct inode *inode, struct file *file) struct cm_state *s = (struct cm_state *)file->private_data; VALIDATE_STATE(s); + lock_kernel(); if (file->f_mode & FMODE_WRITE) drain_dac(s, file->f_flags & O_NONBLOCK); down(&s->open_sem); @@ -1785,6 +1793,7 @@ static int cm_release(struct inode *inode, struct file *file) s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); up(&s->open_sem); wake_up(&s->open_wait); + unlock_kernel(); return 0; } @@ -2021,6 +2030,7 @@ static int cm_midi_release(struct inode *inode, struct file *file) VALIDATE_STATE(s); + lock_kernel(); if (file->f_mode & FMODE_WRITE) { __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&s->midi.owait, &wait); @@ -2058,6 +2068,7 @@ static int cm_midi_release(struct inode *inode, struct file *file) spin_unlock_irqrestore(&s->lock, flags); up(&s->open_sem); wake_up(&s->open_wait); + unlock_kernel(); return 0; } @@ -2212,6 +2223,7 @@ static int cm_dmfm_release(struct inode *inode, struct file *file) unsigned int regb; VALIDATE_STATE(s); + lock_kernel(); down(&s->open_sem); s->open_mode &= ~FMODE_DMFM; for (regb = 0xb0; regb < 0xb9; regb++) { @@ -2222,6 +2234,7 @@ static int cm_dmfm_release(struct inode *inode, struct file *file) } up(&s->open_sem); wake_up(&s->open_wait); + unlock_kernel(); return 0; } diff --git a/drivers/sound/dmasound/dmasound_core.c b/drivers/sound/dmasound/dmasound_core.c index da60c783b..1d8804b36 100644 --- a/drivers/sound/dmasound/dmasound_core.c +++ b/drivers/sound/dmasound/dmasound_core.c @@ -111,6 +111,7 @@ #include <linux/sound.h> #include <linux/init.h> #include <linux/soundcard.h> +#include <linux/smp_lock.h> #include <asm/uaccess.h> @@ -501,8 +502,10 @@ static int mixer_open(struct inode *inode, struct file *file) static int mixer_release(struct inode *inode, struct file *file) { + lock_kernel(); mixer.busy = 0; dmasound.mach.release(); + unlock_kernel(); return 0; } static int mixer_ioctl(struct inode *inode, struct file *file, u_int cmd, @@ -905,6 +908,7 @@ static int sq_release(struct inode *inode, struct file *file) { int rc = 0; + lock_kernel(); if (write_sq.busy) rc = sq_fsync(file, file->f_dentry); dmasound.soft = dmasound.dsp; @@ -923,6 +927,7 @@ static int sq_release(struct inode *inode, struct file *file) /* Wake up a process waiting for the queue being released. * Note: There may be several processes waiting for a call * to open() returning. */ + unlock_kernel(); return rc; } @@ -1141,8 +1146,10 @@ static int state_open(struct inode *inode, struct file *file) static int state_release(struct inode *inode, struct file *file) { + lock_kernel(); state.busy = 0; dmasound.mach.release(); + unlock_kernel(); return 0; } diff --git a/drivers/sound/emu10k1/audio.c b/drivers/sound/emu10k1/audio.c index 06f84dfc3..9e2ee24d1 100644 --- a/drivers/sound/emu10k1/audio.c +++ b/drivers/sound/emu10k1/audio.c @@ -36,6 +36,8 @@ #include "cardwi.h" #include "recmgr.h" #include "audio.h" +#include <linux/sched.h> +#include <linux/smp_lock.h> static void calculate_ofrag(struct woinst *); static void calculate_ifrag(struct wiinst *); @@ -890,6 +892,7 @@ static int emu10k1_audio_mmap(struct file *file, struct vm_area_struct *vma) if (vma_get_pgoff(vma) != 0) return -ENXIO; + lock_kernel(); if (vma->vm_flags & VM_WRITE) { struct woinst *woinst = wave_dev->woinst; struct wave_out *wave_out; @@ -907,6 +910,7 @@ static int emu10k1_audio_mmap(struct file *file, struct vm_area_struct *vma) if (emu10k1_waveout_open(wave_dev) != CTSTATUS_SUCCESS) { spin_unlock_irqrestore(&woinst->lock, flags); ERROR(); + unlock_kernel(); return -EINVAL; } @@ -921,12 +925,14 @@ static int emu10k1_audio_mmap(struct file *file, struct vm_area_struct *vma) if (size > (PAGE_SIZE * wave_out->wavexferbuf->numpages)) { spin_unlock_irqrestore(&woinst->lock, flags); + unlock_kernel(); return -EINVAL; } for (i = 0; i < wave_out->wavexferbuf->numpages; i++) { if (remap_page_range(vma->vm_start + (i * PAGE_SIZE), virt_to_phys(wave_out->pagetable[i]), PAGE_SIZE, vma->vm_page_prot)) { spin_unlock_irqrestore(&woinst->lock, flags); + unlock_kernel(); return -EAGAIN; } } @@ -944,6 +950,7 @@ static int emu10k1_audio_mmap(struct file *file, struct vm_area_struct *vma) wiinst->mapped = 1; spin_unlock_irqrestore(&wiinst->lock, flags); } + unlock_kernel(); return 0; } @@ -1098,9 +1105,11 @@ static int emu10k1_audio_open(struct inode *inode, struct file *file) static int emu10k1_audio_release(struct inode *inode, struct file *file) { struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data; - struct emu10k1_card *card = wave_dev->card; + struct emu10k1_card *card; unsigned long flags; + lock_kernel(); + card = wave_dev->card; DPF(2, "emu10k1_audio_release()\n"); if (file->f_mode & FMODE_WRITE) { @@ -1171,6 +1180,7 @@ static int emu10k1_audio_release(struct inode *inode, struct file *file) kfree(wave_dev); wake_up_interruptible(&card->open_wait); + unlock_kernel(); return 0; } diff --git a/drivers/sound/emu10k1/midi.c b/drivers/sound/emu10k1/midi.c index 04b1424a8..d7e0a4a87 100644 --- a/drivers/sound/emu10k1/midi.c +++ b/drivers/sound/emu10k1/midi.c @@ -32,6 +32,8 @@ #define __NO_VERSION__ #include <linux/module.h> +#include <linux/sched.h> +#include <linux/smp_lock.h> #include <asm/uaccess.h> #include "hwaccess.h" @@ -183,8 +185,10 @@ static int emu10k1_midi_open(struct inode *inode, struct file *file) static int emu10k1_midi_release(struct inode *inode, struct file *file) { struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data; - struct emu10k1_card *card = midi_dev->card; + struct emu10k1_card *card; + lock_kernel(); + card = midi_dev->card; DPF(2, "emu10k1_midi_release()\n"); if (file->f_mode & FMODE_WRITE) { @@ -227,6 +231,7 @@ static int emu10k1_midi_release(struct inode *inode, struct file *file) card->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE)); up(&card->open_sem); wake_up_interruptible(&card->open_wait); + unlock_kernel(); return 0; } diff --git a/drivers/sound/es1370.c b/drivers/sound/es1370.c index 47d1d875f..ae004f10f 100644 --- a/drivers/sound/es1370.c +++ b/drivers/sound/es1370.c @@ -149,6 +149,7 @@ #include <linux/malloc.h> #include <linux/soundcard.h> #include <linux/pci.h> +#include <linux/smp_lock.h> #include <asm/io.h> #include <asm/dma.h> #include <linux/init.h> @@ -1306,24 +1307,38 @@ static int es1370_mmap(struct file *file, struct vm_area_struct *vma) unsigned long size; VALIDATE_STATE(s); + lock_kernel(); if (vma->vm_flags & VM_WRITE) { - if ((ret = prog_dmabuf_dac2(s)) != 0) + if ((ret = prog_dmabuf_dac2(s)) != 0) { + unlock_kernel(); return ret; + } db = &s->dma_dac2; } else if (vma->vm_flags & VM_READ) { - if ((ret = prog_dmabuf_adc(s)) != 0) + if ((ret = prog_dmabuf_adc(s)) != 0) { + unlock_kernel(); return ret; + } db = &s->dma_adc; - } else + } else { + unlock_kernel(); return -EINVAL; - if (vma->vm_pgoff != 0) + } + if (vma->vm_pgoff != 0) { + unlock_kernel(); return -EINVAL; + } size = vma->vm_end - vma->vm_start; - if (size > (PAGE_SIZE << db->buforder)) + if (size > (PAGE_SIZE << db->buforder)) { + unlock_kernel(); return -EINVAL; - if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) + } + if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) { + unlock_kernel(); return -EAGAIN; + } db->mapped = 1; + unlock_kernel(); return 0; } @@ -1717,6 +1732,7 @@ static int es1370_release(struct inode *inode, struct file *file) struct es1370_state *s = (struct es1370_state *)file->private_data; VALIDATE_STATE(s); + lock_kernel(); if (file->f_mode & FMODE_WRITE) drain_dac2(s, file->f_flags & O_NONBLOCK); down(&s->open_sem); @@ -1733,6 +1749,7 @@ static int es1370_release(struct inode *inode, struct file *file) wake_up(&s->open_wait); up(&s->open_sem); return 0; + unlock_kernel(); } static /*const*/ struct file_operations es1370_audio_fops = { @@ -1850,17 +1867,23 @@ static int es1370_mmap_dac(struct file *file, struct vm_area_struct *vma) VALIDATE_STATE(s); if (!(vma->vm_flags & VM_WRITE)) return -EINVAL; + lock_kernel(); if ((ret = prog_dmabuf_dac1(s)) != 0) - return ret; + goto out; + ret = -EINVAL; if (vma->vm_pgoff != 0) - return -EINVAL; + goto out; size = vma->vm_end - vma->vm_start; if (size > (PAGE_SIZE << s->dma_dac1.buforder)) - return -EINVAL; + goto out; + ret = -EAGAIN; if (remap_page_range(vma->vm_start, virt_to_phys(s->dma_dac1.rawbuf), size, vma->vm_page_prot)) - return -EAGAIN; + goto out; s->dma_dac1.mapped = 1; - return 0; + ret = 0; +out: + unlock_kernel(); + return ret; } static int es1370_ioctl_dac(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) @@ -2122,6 +2145,7 @@ static int es1370_release_dac(struct inode *inode, struct file *file) struct es1370_state *s = (struct es1370_state *)file->private_data; VALIDATE_STATE(s); + lock_kernel(); drain_dac1(s, file->f_flags & O_NONBLOCK); down(&s->open_sem); stop_dac1(s); @@ -2129,6 +2153,7 @@ static int es1370_release_dac(struct inode *inode, struct file *file) s->open_mode &= ~FMODE_DAC; wake_up(&s->open_wait); up(&s->open_sem); + unlock_kernel(); return 0; } @@ -2366,6 +2391,7 @@ static int es1370_midi_release(struct inode *inode, struct file *file) VALIDATE_STATE(s); + lock_kernel(); if (file->f_mode & FMODE_WRITE) { add_wait_queue(&s->midi.owait, &wait); for (;;) { @@ -2399,6 +2425,7 @@ static int es1370_midi_release(struct inode *inode, struct file *file) spin_unlock_irqrestore(&s->lock, flags); wake_up(&s->open_wait); up(&s->open_sem); + unlock_kernel(); return 0; } diff --git a/drivers/sound/es1371.c b/drivers/sound/es1371.c index 109ac71c0..58d7923ab 100644 --- a/drivers/sound/es1371.c +++ b/drivers/sound/es1371.c @@ -121,6 +121,7 @@ #include <linux/bitops.h> #include <linux/proc_fs.h> #include <linux/spinlock.h> +#include <linux/smp_lock.h> #include <linux/ac97_codec.h> #include <asm/io.h> #include <asm/dma.h> @@ -1494,24 +1495,38 @@ static int es1371_mmap(struct file *file, struct vm_area_struct *vma) unsigned long size; VALIDATE_STATE(s); + lock_kernel(); if (vma->vm_flags & VM_WRITE) { - if ((ret = prog_dmabuf_dac2(s)) != 0) + if ((ret = prog_dmabuf_dac2(s)) != 0) { + unlock_kernel(); return ret; + } db = &s->dma_dac2; } else if (vma->vm_flags & VM_READ) { - if ((ret = prog_dmabuf_adc(s)) != 0) + if ((ret = prog_dmabuf_adc(s)) != 0) { + unlock_kernel(); return ret; + } db = &s->dma_adc; - } else + } else { + unlock_kernel(); return -EINVAL; - if (vma->vm_pgoff != 0) + } + if (vma->vm_pgoff != 0) { + unlock_kernel(); return -EINVAL; + } size = vma->vm_end - vma->vm_start; - if (size > (PAGE_SIZE << db->buforder)) + if (size > (PAGE_SIZE << db->buforder)) { + unlock_kernel(); return -EINVAL; - if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) + } + if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) { + unlock_kernel(); return -EAGAIN; + } db->mapped = 1; + unlock_kernel(); return 0; } @@ -1903,6 +1918,7 @@ static int es1371_release(struct inode *inode, struct file *file) struct es1371_state *s = (struct es1371_state *)file->private_data; VALIDATE_STATE(s); + lock_kernel(); if (file->f_mode & FMODE_WRITE) drain_dac2(s, file->f_flags & O_NONBLOCK); down(&s->open_sem); @@ -1917,6 +1933,7 @@ static int es1371_release(struct inode *inode, struct file *file) s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); up(&s->open_sem); wake_up(&s->open_wait); + unlock_kernel(); return 0; } @@ -2035,17 +2052,23 @@ static int es1371_mmap_dac(struct file *file, struct vm_area_struct *vma) VALIDATE_STATE(s); if (!(vma->vm_flags & VM_WRITE)) return -EINVAL; + lock_kernel(); if ((ret = prog_dmabuf_dac1(s)) != 0) - return ret; + goto out; + ret = -EINVAL; if (vma->vm_pgoff != 0) - return -EINVAL; + goto out; size = vma->vm_end - vma->vm_start; if (size > (PAGE_SIZE << s->dma_dac1.buforder)) - return -EINVAL; + goto out; + ret = -EAGAIN; if (remap_page_range(vma->vm_start, virt_to_phys(s->dma_dac1.rawbuf), size, vma->vm_page_prot)) - return -EAGAIN; + goto out; s->dma_dac1.mapped = 1; - return 0; + ret = 0; +out: + unlock_kernel(); + return ret; } static int es1371_ioctl_dac(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) @@ -2297,6 +2320,7 @@ static int es1371_release_dac(struct inode *inode, struct file *file) struct es1371_state *s = (struct es1371_state *)file->private_data; VALIDATE_STATE(s); + lock_kernel(); drain_dac1(s, file->f_flags & O_NONBLOCK); down(&s->open_sem); stop_dac1(s); @@ -2304,6 +2328,7 @@ static int es1371_release_dac(struct inode *inode, struct file *file) s->open_mode &= ~FMODE_DAC; up(&s->open_sem); wake_up(&s->open_wait); + unlock_kernel(); return 0; } @@ -2540,6 +2565,7 @@ static int es1371_midi_release(struct inode *inode, struct file *file) unsigned count, tmo; VALIDATE_STATE(s); + lock_kernel(); if (file->f_mode & FMODE_WRITE) { add_wait_queue(&s->midi.owait, &wait); for (;;) { @@ -2573,6 +2599,7 @@ static int es1371_midi_release(struct inode *inode, struct file *file) spin_unlock_irqrestore(&s->lock, flags); up(&s->open_sem); wake_up(&s->open_wait); + unlock_kernel(); return 0; } diff --git a/drivers/sound/esssolo1.c b/drivers/sound/esssolo1.c index cfc89d3ee..e2e0c3b12 100644 --- a/drivers/sound/esssolo1.c +++ b/drivers/sound/esssolo1.c @@ -90,6 +90,7 @@ #include <linux/init.h> #include <linux/poll.h> #include <linux/spinlock.h> +#include <linux/smp_lock.h> #include <asm/uaccess.h> #include <asm/hardirq.h> @@ -1192,29 +1193,35 @@ static int solo1_mmap(struct file *file, struct vm_area_struct *vma) { struct solo1_state *s = (struct solo1_state *)file->private_data; struct dmabuf *db; - int ret; + int ret = -EINVAL; unsigned long size; VALIDATE_STATE(s); + lock_kernel(); if (vma->vm_flags & VM_WRITE) { if ((ret = prog_dmabuf_dac(s)) != 0) - return ret; + goto out; db = &s->dma_dac; } else if (vma->vm_flags & VM_READ) { if ((ret = prog_dmabuf_adc(s)) != 0) - return ret; + goto out; db = &s->dma_adc; } else - return -EINVAL; + goto out; + ret = -EINVAL; if (vma->vm_pgoff != 0) - return -EINVAL; + goto out; size = vma->vm_end - vma->vm_start; if (size > (PAGE_SIZE << db->buforder)) - return -EINVAL; + goto out; + ret = -EAGAIN; if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) - return -EAGAIN; + goto out; db->mapped = 1; - return 0; + ret = 0; +out: + unlock_kernel(); + return ret; } static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) @@ -1510,6 +1517,7 @@ static int solo1_release(struct inode *inode, struct file *file) struct solo1_state *s = (struct solo1_state *)file->private_data; VALIDATE_STATE(s); + lock_kernel(); if (file->f_mode & FMODE_WRITE) drain_dac(s, file->f_flags & O_NONBLOCK); down(&s->open_sem); @@ -1527,6 +1535,7 @@ static int solo1_release(struct inode *inode, struct file *file) s->open_mode &= ~(FMODE_READ | FMODE_WRITE); wake_up(&s->open_wait); up(&s->open_sem); + unlock_kernel(); return 0; } @@ -1881,6 +1890,7 @@ static int solo1_midi_release(struct inode *inode, struct file *file) VALIDATE_STATE(s); + lock_kernel(); if (file->f_mode & FMODE_WRITE) { add_wait_queue(&s->midi.owait, &wait); for (;;) { @@ -1914,6 +1924,7 @@ static int solo1_midi_release(struct inode *inode, struct file *file) spin_unlock_irqrestore(&s->lock, flags); wake_up(&s->open_wait); up(&s->open_sem); + unlock_kernel(); return 0; } @@ -2083,6 +2094,7 @@ static int solo1_dmfm_release(struct inode *inode, struct file *file) unsigned int regb; VALIDATE_STATE(s); + lock_kernel(); down(&s->open_sem); s->open_mode &= ~FMODE_DMFM; for (regb = 0xb0; regb < 0xb9; regb++) { @@ -2094,6 +2106,7 @@ static int solo1_dmfm_release(struct inode *inode, struct file *file) release_region(s->sbbase, FMSYNTH_EXTENT); wake_up(&s->open_wait); up(&s->open_sem); + unlock_kernel(); return 0; } diff --git a/drivers/sound/i810_audio.c b/drivers/sound/i810_audio.c index f04636a65..792f670af 100644 --- a/drivers/sound/i810_audio.c +++ b/drivers/sound/i810_audio.c @@ -76,6 +76,7 @@ #include <linux/init.h> #include <linux/poll.h> #include <linux/spinlock.h> +#include <linux/smp_lock.h> #include <linux/ac97_codec.h> #include <asm/uaccess.h> #include <asm/hardirq.h> @@ -1227,29 +1228,34 @@ static int i810_mmap(struct file *file, struct vm_area_struct *vma) { struct i810_state *state = (struct i810_state *)file->private_data; struct dmabuf *dmabuf = &state->dmabuf; - int ret; + int ret = -EINVAL; unsigned long size; + lock_kernel(); if (vma->vm_flags & VM_WRITE) { if ((ret = prog_dmabuf(state, 0)) != 0) - return ret; + goto out; } else if (vma->vm_flags & VM_READ) { if ((ret = prog_dmabuf(state, 1)) != 0) - return ret; + goto out; } else - return -EINVAL; + goto out; + ret = -EINVAL; if (vma->vm_pgoff != 0) - return -EINVAL; + goto out; size = vma->vm_end - vma->vm_start; if (size > (PAGE_SIZE << dmabuf->buforder)) - return -EINVAL; + goto out; + ret = -EAGAIN; if (remap_page_range(vma->vm_start, virt_to_phys(dmabuf->rawbuf), size, vma->vm_page_prot)) - return -EAGAIN; + goto out; dmabuf->mapped = 1; - - return 0; + ret = 0; +out: + unlock_kernel(); + return ret; } static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) @@ -1608,6 +1614,7 @@ static int i810_release(struct inode *inode, struct file *file) struct i810_state *state = (struct i810_state *)file->private_data; struct dmabuf *dmabuf = &state->dmabuf; + lock_kernel(); if (file->f_mode & FMODE_WRITE) { i810_clear_tail(state); drain_dac(state, file->f_flags & O_NONBLOCK); @@ -1632,6 +1639,7 @@ static int i810_release(struct inode *inode, struct file *file) kfree(state->card->states[state->virt]); state->card->states[state->virt] = NULL; + unlock_kernel(); return 0; } diff --git a/drivers/sound/maestro.c b/drivers/sound/maestro.c index cd5a2bc27..cc54f784c 100644 --- a/drivers/sound/maestro.c +++ b/drivers/sound/maestro.c @@ -197,6 +197,8 @@ #include <linux/version.h> #include <linux/module.h> +#include <linux/sched.h> +#include <linux/smp_lock.h> #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) @@ -2422,13 +2424,14 @@ static int ess_mmap(struct file *file, struct vm_area_struct *vma) { struct ess_state *s = (struct ess_state *)file->private_data; struct dmabuf *db; - int ret; + int ret = -EINVAL; unsigned long size; VALIDATE_STATE(s); + lock_kernel(); if (vma->vm_flags & VM_WRITE) { if ((ret = prog_dmabuf(s, 1)) != 0) - return ret; + goto out; db = &s->dma_dac; } else #if 0 @@ -2436,20 +2439,25 @@ static int ess_mmap(struct file *file, struct vm_area_struct *vma) we can turn this back on. */ if (vma->vm_flags & VM_READ) { if ((ret = prog_dmabuf(s, 0)) != 0) - return ret; + goto out; db = &s->dma_adc; } else #endif - return -EINVAL; + goto out; + ret = -EINVAL; if (SILLY_OFFSET(vma) != 0) - return -EINVAL; + goto out; size = vma->vm_end - vma->vm_start; if (size > (PAGE_SIZE << db->buforder)) - return -EINVAL; + goto out; + ret = -EAGAIN; if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) - return -EAGAIN; + goto out; db->mapped = 1; - return 0; + ret = 0; +out: + unlock_kernel(); + return ret; } static int ess_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) @@ -2985,6 +2993,7 @@ ess_release(struct inode *inode, struct file *file) struct ess_state *s = (struct ess_state *)file->private_data; VALIDATE_STATE(s); + lock_kernel(); if (file->f_mode & FMODE_WRITE) drain_dac(s, file->f_flags & O_NONBLOCK); down(&s->open_sem); @@ -3006,6 +3015,7 @@ ess_release(struct inode *inode, struct file *file) } up(&s->open_sem); wake_up(&s->open_wait); + unlock_kernel(); return 0; } diff --git a/drivers/sound/msnd.h b/drivers/sound/msnd.h index 219a6bfe0..7b361921e 100644 --- a/drivers/sound/msnd.h +++ b/drivers/sound/msnd.h @@ -160,13 +160,6 @@ # define inb inb_p #endif -#ifdef LINUX20 -# define __initfunc(f) f -# define __initdata /* nothing */ -# define spin_lock_irqsave(junk,flags) do { save_flags(flags); cli(); } while (0) -# define spin_unlock_irqrestore(junk,flags) do { restore_flags(flags); } while (0) -#endif - /* JobQueueStruct */ #define JQS_wStart 0x00 #define JQS_wSize 0x02 @@ -236,9 +229,7 @@ typedef struct multisound_dev { wait_queue_head_t writeblock; wait_queue_head_t readblock; wait_queue_head_t writeflush; -#ifndef LINUX20 spinlock_t lock; -#endif int nresets; unsigned long recsrc; int left_levels[16]; @@ -250,8 +241,6 @@ typedef struct multisound_dev { int rec_sample_size, rec_sample_rate, rec_channels; int rec_ndelay; BYTE bCurrentMidiPatch; - void (*inc_ref)(void); - void (*dec_ref)(void); /* Digital audio FIFOs */ msnd_fifo DAPF, DARF; diff --git a/drivers/sound/msnd_pinnacle.c b/drivers/sound/msnd_pinnacle.c index b220433ce..91c7d2306 100644 --- a/drivers/sound/msnd_pinnacle.c +++ b/drivers/sound/msnd_pinnacle.c @@ -35,16 +35,12 @@ #include <linux/config.h> #include <linux/version.h> -#if LINUX_VERSION_CODE < 0x020101 -# define LINUX20 -#endif #include <linux/module.h> #include <linux/malloc.h> #include <linux/types.h> #include <linux/delay.h> -#ifndef LINUX20 -# include <linux/init.h> -#endif +#include <linux/init.h> +#include <linux/smp_lock.h> #include <asm/irq.h> #include <asm/io.h> #include "sound_config.h" @@ -747,16 +743,6 @@ static void set_default_audio_parameters(void) set_default_rec_audio_parameters(); } -static void mod_inc_ref(void) -{ - MOD_INC_USE_COUNT; -} - -static void mod_dec_ref(void) -{ - MOD_DEC_USE_COUNT; -} - static int dev_open(struct inode *inode, struct file *file) { int minor = MINOR(inode->i_rdev); @@ -789,43 +775,23 @@ static int dev_open(struct inode *inode, struct file *file) } else err = -EINVAL; - if (err >= 0) - mod_inc_ref(); - return err; } -#ifdef LINUX20 -static void dev_release(struct inode *inode, struct file *file) -#else static int dev_release(struct inode *inode, struct file *file) -#endif { int minor = MINOR(inode->i_rdev); -#ifndef LINUX20 int err = 0; -#endif - if (minor == dev.dsp_minor) { -#ifndef LINUX20 - err = -#endif - dsp_release(file); - } + lock_kernel(); + if (minor == dev.dsp_minor) + err = dsp_release(file); else if (minor == dev.mixer_minor) { /* nothing */ - } -#ifndef LINUX20 - else + } else err = -EINVAL; - - if (err >= 0) -#endif - mod_dec_ref(); - -#ifndef LINUX20 + unlock_kernel(); return err; -#endif } static __inline__ int pack_DARQ_to_DARF(register int bank) @@ -1002,30 +968,18 @@ static int dsp_write(const char *buf, size_t len) return len - count; } -#ifdef LINUX20 -static int dev_read(struct inode *inode, struct file *file, char *buf, int count) -{ - int minor = MINOR(inode->i_rdev); -#else static ssize_t dev_read(struct file *file, char *buf, size_t count, loff_t *off) { int minor = MINOR(file->f_dentry->d_inode->i_rdev); -#endif if (minor == dev.dsp_minor) return dsp_read(buf, count); else return -EINVAL; } -#ifdef LINUX20 -static int dev_write(struct inode *inode, struct file *file, const char *buf, int count) -{ - int minor = MINOR(inode->i_rdev); -#else static ssize_t dev_write(struct file *file, const char *buf, size_t count, loff_t *off) { int minor = MINOR(file->f_dentry->d_inode->i_rdev); -#endif if (minor == dev.dsp_minor) return dsp_write(buf, count); else @@ -1042,15 +996,8 @@ static __inline__ void eval_dsp_msg(register WORD wMessage) if (pack_DAPF_to_DAPQ(0) <= 0) { if (!test_bit(F_WRITEBLOCK, &dev.flags)) { -#ifdef LINUX20 - if (test_bit(F_WRITEFLUSH, &dev.flags)) { - clear_bit(F_WRITEFLUSH, &dev.flags); - wake_up_interruptible(&dev.writeflush); - } -#else if (test_and_clear_bit(F_WRITEFLUSH, &dev.flags)) wake_up_interruptible(&dev.writeflush); -#endif } clear_bit(F_WRITING, &dev.flags); } @@ -1122,6 +1069,7 @@ static void intr(int irq, void *dev_id, struct pt_regs *regs) } static struct file_operations dev_fileops = { + owner: THIS_MODULE, read: dev_read, write: dev_write, ioctl: dev_ioctl, @@ -1881,8 +1829,6 @@ int __init msnd_pinnacle_init(void) dev.recsrc = 0; dev.dspq_data_buff = DSPQ_DATA_BUFF; dev.dspq_buff_size = DSPQ_BUFF_SIZE; - dev.inc_ref = mod_inc_ref; - dev.dec_ref = mod_dec_ref; if (write_ndelay == -1) write_ndelay = CONFIG_MSND_WRITE_NDELAY; if (write_ndelay) @@ -1898,9 +1844,7 @@ int __init msnd_pinnacle_init(void) init_waitqueue_head(&dev.writeflush); msnd_fifo_init(&dev.DAPF); msnd_fifo_init(&dev.DARF); -#ifndef LINUX20 spin_lock_init(&dev.lock); -#endif printk(KERN_INFO LOGNAME ": %u byte audio FIFOs (x2)\n", dev.fifosize); if ((err = msnd_fifo_alloc(&dev.DAPF, dev.fifosize)) < 0) { printk(KERN_ERR LOGNAME ": Couldn't allocate write FIFO\n"); diff --git a/drivers/sound/sonicvibes.c b/drivers/sound/sonicvibes.c index c9c66a73f..8a082552a 100644 --- a/drivers/sound/sonicvibes.c +++ b/drivers/sound/sonicvibes.c @@ -108,6 +108,7 @@ #include <linux/init.h> #include <linux/poll.h> #include <linux/spinlock.h> +#include <linux/smp_lock.h> #include <asm/uaccess.h> #include <asm/hardirq.h> @@ -1509,29 +1510,35 @@ static int sv_mmap(struct file *file, struct vm_area_struct *vma) { struct sv_state *s = (struct sv_state *)file->private_data; struct dmabuf *db; - int ret; + int ret = -EINVAL; unsigned long size; VALIDATE_STATE(s); + lock_kernel(); if (vma->vm_flags & VM_WRITE) { if ((ret = prog_dmabuf(s, 1)) != 0) - return ret; + goto out; db = &s->dma_dac; } else if (vma->vm_flags & VM_READ) { if ((ret = prog_dmabuf(s, 0)) != 0) - return ret; + goto out; db = &s->dma_adc; } else - return -EINVAL; + goto out; + ret = -EINVAL; if (vma->vm_pgoff != 0) - return -EINVAL; + goto out; size = vma->vm_end - vma->vm_start; if (size > (PAGE_SIZE << db->buforder)) - return -EINVAL; + goto out; + ret = -EAGAIN; if (remap_page_range(vma->vm_start, virt_to_phys(db->rawbuf), size, vma->vm_page_prot)) - return -EAGAIN; + goto out; db->mapped = 1; - return 0; + ret = 0; +out: + unlock_kernel(); + return ret; } static int sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) @@ -1907,6 +1914,7 @@ static int sv_release(struct inode *inode, struct file *file) struct sv_state *s = (struct sv_state *)file->private_data; VALIDATE_STATE(s); + lock_kernel(); if (file->f_mode & FMODE_WRITE) drain_dac(s, file->f_flags & O_NONBLOCK); down(&s->open_sem); @@ -1921,6 +1929,7 @@ static int sv_release(struct inode *inode, struct file *file) s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); wake_up(&s->open_wait); up(&s->open_sem); + unlock_kernel(); return 0; } @@ -2167,6 +2176,7 @@ static int sv_midi_release(struct inode *inode, struct file *file) VALIDATE_STATE(s); + lock_kernel(); if (file->f_mode & FMODE_WRITE) { add_wait_queue(&s->midi.owait, &wait); for (;;) { @@ -2200,6 +2210,7 @@ static int sv_midi_release(struct inode *inode, struct file *file) spin_unlock_irqrestore(&s->lock, flags); wake_up(&s->open_wait); up(&s->open_sem); + unlock_kernel(); return 0; } @@ -2363,6 +2374,7 @@ static int sv_dmfm_release(struct inode *inode, struct file *file) unsigned int regb; VALIDATE_STATE(s); + lock_kernel(); down(&s->open_sem); s->open_mode &= ~FMODE_DMFM; for (regb = 0xb0; regb < 0xb9; regb++) { @@ -2373,6 +2385,7 @@ static int sv_dmfm_release(struct inode *inode, struct file *file) } wake_up(&s->open_wait); up(&s->open_sem); + unlock_kernel(); return 0; } diff --git a/drivers/sound/soundcard.c b/drivers/sound/soundcard.c index 0351fe7ce..d56b8f77f 100644 --- a/drivers/sound/soundcard.c +++ b/drivers/sound/soundcard.c @@ -270,6 +270,7 @@ static int sound_release(struct inode *inode, struct file *file) { int dev = MINOR(inode->i_rdev); + lock_kernel(); DEB(printk("sound_release(dev=%d)\n", dev)); switch (dev & 0x0f) { case SND_DEV_CTL: @@ -297,6 +298,7 @@ static int sound_release(struct inode *inode, struct file *file) notifier_call_chain(&sound_locker, 0, 0); lock_depth--; + unlock_kernel(); return 0; } @@ -449,29 +451,35 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma) printk(KERN_ERR "Sound: mmap() not supported for other than audio devices\n"); return -EINVAL; } + lock_kernel(); if (vma->vm_flags & VM_WRITE) /* Map write and read/write to the output buf */ dmap = audio_devs[dev]->dmap_out; else if (vma->vm_flags & VM_READ) dmap = audio_devs[dev]->dmap_in; else { printk(KERN_ERR "Sound: Undefined mmap() access\n"); + unlock_kernel(); return -EINVAL; } if (dmap == NULL) { printk(KERN_ERR "Sound: mmap() error. dmap == NULL\n"); + unlock_kernel(); return -EIO; } if (dmap->raw_buf == NULL) { printk(KERN_ERR "Sound: mmap() called when raw_buf == NULL\n"); + unlock_kernel(); return -EIO; } if (dmap->mapping_flags) { printk(KERN_ERR "Sound: mmap() called twice for the same DMA buffer\n"); + unlock_kernel(); return -EIO; } if (vma->vm_pgoff != 0) { printk(KERN_ERR "Sound: mmap() offset must be 0.\n"); + unlock_kernel(); return -EINVAL; } size = vma->vm_end - vma->vm_start; @@ -481,8 +489,10 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma) } if (remap_page_range(vma->vm_start, virt_to_phys(dmap->raw_buf), vma->vm_end - vma->vm_start, - vma->vm_page_prot)) + vma->vm_page_prot)) { + unlock_kernel(); return -EAGAIN; + } dmap->mapping_flags |= DMA_MAP_MAPPED; @@ -492,6 +502,7 @@ static int sound_mmap(struct file *file, struct vm_area_struct *vma) memset(dmap->raw_buf, dmap->neutral_byte, dmap->bytes_in_use); + unlock_kernel(); return 0; } diff --git a/drivers/sound/trident.c b/drivers/sound/trident.c index 6e2b70791..f19cb1740 100644 --- a/drivers/sound/trident.c +++ b/drivers/sound/trident.c @@ -107,6 +107,7 @@ #include <linux/init.h> #include <linux/poll.h> #include <linux/spinlock.h> +#include <linux/smp_lock.h> #include <linux/ac97_codec.h> #include <asm/uaccess.h> #include <asm/hardirq.h> @@ -1560,30 +1561,35 @@ static int trident_mmap(struct file *file, struct vm_area_struct *vma) { struct trident_state *state = (struct trident_state *)file->private_data; struct dmabuf *dmabuf = &state->dmabuf; - int ret; + int ret = -EINVAL; unsigned long size; VALIDATE_STATE(state); + lock_kernel(); if (vma->vm_flags & VM_WRITE) { if ((ret = prog_dmabuf(state, 0)) != 0) - return ret; + goto out; } else if (vma->vm_flags & VM_READ) { if ((ret = prog_dmabuf(state, 1)) != 0) - return ret; - } else - return -EINVAL; + goto out; + } else + goto out; + ret = -EINVAL; if (vma->vm_pgoff != 0) - return -EINVAL; + goto out; size = vma->vm_end - vma->vm_start; if (size > (PAGE_SIZE << dmabuf->buforder)) - return -EINVAL; + goto out; + ret = -EAGAIN; if (remap_page_range(vma->vm_start, virt_to_phys(dmabuf->rawbuf), size, vma->vm_page_prot)) - return -EAGAIN; + goto out; dmabuf->mapped = 1; - - return 0; + ret = 0; +out: + unlock_kernel(); + return ret; } static int trident_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) @@ -2009,9 +2015,12 @@ static int trident_open(struct inode *inode, struct file *file) static int trident_release(struct inode *inode, struct file *file) { struct trident_state *state = (struct trident_state *)file->private_data; - struct trident_card *card = state->card; - struct dmabuf *dmabuf = &state->dmabuf; + struct trident_card *card; + struct dmabuf *dmabuf; + lock_kernel(); + card = state->card; + dmabuf = &state->dmabuf; VALIDATE_STATE(state); if (file->f_mode & FMODE_WRITE) { @@ -2038,6 +2047,7 @@ static int trident_release(struct inode *inode, struct file *file) /* we're covered by the open_sem */ up(&card->open_sem); + unlock_kernel(); return 0; } diff --git a/drivers/sound/via82cxxx_audio.c b/drivers/sound/via82cxxx_audio.c index ab14427d6..be3b1c9ca 100644 --- a/drivers/sound/via82cxxx_audio.c +++ b/drivers/sound/via82cxxx_audio.c @@ -30,6 +30,7 @@ #include <linux/poll.h> #include <linux/soundcard.h> #include <linux/ac97_codec.h> +#include <linux/smp_lock.h> #include <asm/io.h> #include <asm/delay.h> #include <asm/uaccess.h> @@ -2207,6 +2208,7 @@ static int via_dsp_release(struct inode *inode, struct file *file) card = file->private_data; assert (card != NULL); + lock_kernel(); if (file->f_mode & FMODE_READ) via_chan_free (card, &card->ch_in); @@ -2220,6 +2222,7 @@ static int via_dsp_release(struct inode *inode, struct file *file) spin_unlock_irqrestore (&card->lock, flags); wake_up (&card->open_wait); + unlock_kernel(); DPRINTK("EXIT, returning 0\n"); return 0; diff --git a/drivers/sound/vwsnd.c b/drivers/sound/vwsnd.c index 19cca5ee0..d46abd569 100644 --- a/drivers/sound/vwsnd.c +++ b/drivers/sound/vwsnd.c @@ -84,10 +84,9 @@ * Locking Notes * * INC_USE_COUNT and DEC_USE_COUNT keep track of the number of - * open descriptors to this driver. When the driver is compiled - * as a module, they call MOD_{INC,DEC}_USE_COUNT; otherwise they - * bump vwsnd_use_count. The global device list, vwsnd_dev_list, - * is immutable when the IN_USE is true. + * open descriptors to this driver. They store it in vwsnd_use_count. + * The global device list, vwsnd_dev_list, is immutable when the IN_USE + * is true. * * devc->open_lock is a semaphore that is used to enforce the * single reader/single writer rule for /dev/audio. The rule is @@ -141,6 +140,7 @@ #include <linux/module.h> #include <linux/stddef.h> #include <linux/spinlock.h> +#include <linux/smp_lock.h> #include <asm/fixmap.h> #include <asm/cobalt.h> #include <asm/semaphore.h> @@ -1517,22 +1517,12 @@ typedef struct vwsnd_dev { static vwsnd_dev_t *vwsnd_dev_list; /* linked list of all devices */ -#ifdef MODULE - -# define INC_USE_COUNT MOD_INC_USE_COUNT -# define DEC_USE_COUNT MOD_DEC_USE_COUNT -# define IN_USE MOD_IN_USE - -#else - static atomic_t vwsnd_use_count = ATOMIC_INIT(0); # define INC_USE_COUNT (atomic_inc(&vwsnd_use_count)) # define DEC_USE_COUNT (atomic_dec(&vwsnd_use_count)) # define IN_USE (atomic_read(&vwsnd_use_count) != 0) -#endif - /* * Lithium can only DMA multiples of 32 bytes. Its DMA buffer may * be up to 8 Kb. This driver always uses 8 Kb. @@ -2998,6 +2988,7 @@ static int vwsnd_audio_release(struct inode *inode, struct file *file) vwsnd_port_t *wport = NULL, *rport = NULL; int err = 0; + lock_kernel(); down(&devc->io_sema); { DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); @@ -3023,13 +3014,14 @@ static int vwsnd_audio_release(struct inode *inode, struct file *file) } up(&devc->open_sema); wake_up(&devc->open_wait); - DBGDO(if (IN_USE)) /* see hack in vwsnd_mixer_release() */ - DEC_USE_COUNT; + DEC_USE_COUNT; DBGR(); + unlock_kernel(); return err; } static struct file_operations vwsnd_audio_fops = { + owner: THIS_MODULE, llseek: vwsnd_audio_llseek, read: vwsnd_audio_read, write: vwsnd_audio_write, @@ -3069,15 +3061,7 @@ static int vwsnd_mixer_open(struct inode *inode, struct file *file) static int vwsnd_mixer_release(struct inode *inode, struct file *file) { DBGEV("(inode=0x%p, file=0x%p)\n", inode, file); - - /* - * hack -- opening/closing the mixer device zeroes use count - * so driver can be unloaded. - * Use only while debugging module, and then use it carefully. - */ - - DBGDO(while (IN_USE)) - DEC_USE_COUNT; + DEC_USE_COUNT; return 0; } @@ -3234,6 +3218,7 @@ static int vwsnd_mixer_ioctl(struct inode *ioctl, } static struct file_operations vwsnd_mixer_fops = { + owner: THIS_MODULE, llseek: vwsnd_mixer_llseek, ioctl: vwsnd_mixer_ioctl, open: vwsnd_mixer_open, @@ -3429,8 +3414,6 @@ static int unload_vwsnd(struct address_info *hw_config) DBGE("()\n"); - if (IN_USE) - return -EBUSY; devcp = &vwsnd_dev_list; while ((devc = *devcp)) { if (devc->audio_minor == hw_config->slots[0]) { diff --git a/drivers/sound/wavfront.c b/drivers/sound/wavfront.c index a8f826031..3fb7cce2e 100644 --- a/drivers/sound/wavfront.c +++ b/drivers/sound/wavfront.c @@ -67,6 +67,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/sched.h> +#include <linux/smp_lock.h> #include <linux/ptrace.h> #include <linux/fcntl.h> #include <linux/ioport.h> @@ -1959,8 +1960,10 @@ wavefront_open (struct inode *inode, struct file *file) static int wavefront_release(struct inode *inode, struct file *file) { + lock_kernel(); dev.opened = 0; dev.debug = 0; + unlock_kernel(); return 0; } diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c index 043d57bbc..47485dbde 100644 --- a/drivers/telephony/ixj.c +++ b/drivers/telephony/ixj.c @@ -50,6 +50,7 @@ static char ixj_c_rcsid[] = "$Id: ixj.c,v 3.4 1999/12/16 22:18:36 root Exp root #include <linux/timer.h> #include <linux/delay.h> #include <linux/pci.h> +#include <linux/smp_lock.h> #include <asm/io.h> #include <asm/segment.h> @@ -1056,6 +1057,7 @@ int ixj_release(struct inode *inode, struct file *file_p) if (ixjdebug > 0) printk(KERN_INFO "Closing board %d\n", NUM(inode->i_rdev)); + lock_kernel(); daa_set_mode(board, SOP_PU_SLEEP); ixj_set_port(board, PORT_POTS); aec_stop(board); @@ -1189,6 +1191,7 @@ int ixj_release(struct inode *inode, struct file *file_p) j->rec_frame_size = j->play_frame_size = 0; ixj_fasync(-1, file_p, 0); // remove from list of async notification + unlock_kernel(); return 0; } diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in index 55b8b1df5..7e29c7807 100644 --- a/drivers/usb/Config.in +++ b/drivers/usb/Config.in @@ -28,6 +28,9 @@ comment 'USB Controllers' comment 'USB Devices' dep_tristate ' USB Printer support' CONFIG_USB_PRINTER $CONFIG_USB dep_tristate ' USB Scanner support' CONFIG_USB_SCANNER $CONFIG_USB + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + dep_tristate ' Microtek X6USB scanner support (EXPERIMENTAL)' CONFIG_USB_MICROTEK $CONFIG_USB $CONFIG_SCSI + fi dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND dep_tristate ' USB Modem (CDC ACM) support' CONFIG_USB_ACM $CONFIG_USB dep_tristate ' USB Serial Converter support' CONFIG_USB_SERIAL $CONFIG_USB @@ -68,7 +71,6 @@ comment 'USB Devices' dep_tristate ' USB ADMtek Pegasus-based device support (EXPERIMENTAL)' CONFIG_USB_PEGASUS $CONFIG_USB $CONFIG_NET dep_tristate ' USB Diamond Rio500 support (EXPERIMENTAL)' CONFIG_USB_RIO500 $CONFIG_USB dep_tristate ' D-Link USB FM radio support (EXPERIMENTAL)' CONFIG_USB_DSBR $CONFIG_USB $CONFIG_VIDEO_DEV - dep_tristate ' Microtek X6USB scanner support (EXPERIMENTAL)' CONFIG_USB_MICROTEK $CONFIG_USB $CONFIG_SCSI dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB fi diff --git a/drivers/usb/audio.c b/drivers/usb/audio.c index 67f1635a6..4560ad602 100644 --- a/drivers/usb/audio.c +++ b/drivers/usb/audio.c @@ -171,6 +171,7 @@ #include <linux/string.h> #include <linux/timer.h> #include <linux/sched.h> +#include <linux/smp_lock.h> #include <linux/module.h> #include <linux/sound.h> #include <linux/soundcard.h> @@ -1944,10 +1945,13 @@ static int usb_audio_open_mixdev(struct inode *inode, struct file *file) static int usb_audio_release_mixdev(struct inode *inode, struct file *file) { struct usb_mixerdev *ms = (struct usb_mixerdev *)file->private_data; - struct usb_audio_state *s = ms->state; + struct usb_audio_state *s; + lock_kernel(); + s = ms->state; down(&open_sem); release(s); + unlock_kernel(); return 0; } @@ -2283,23 +2287,28 @@ static int usb_audio_mmap(struct file *file, struct vm_area_struct *vma) { struct usb_audiodev *as = (struct usb_audiodev *)file->private_data; struct dmabuf *db; - int ret; + int ret = -EINVAL; + lock_kernel(); if (vma->vm_flags & VM_WRITE) { if ((ret = prog_dmabuf_out(as)) != 0) - return ret; + goto out; db = &as->usbout.dma; } else if (vma->vm_flags & VM_READ) { if ((ret = prog_dmabuf_in(as)) != 0) - return ret; + goto out; db = &as->usbin.dma; } else - return -EINVAL; + goto out; + ret = -EINVAL; if (vma->vm_pgoff != 0) - return -EINVAL; + goto out; - return dmabuf_mmap(db, vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot); + ret = dmabuf_mmap(db, vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_page_prot); +out: + unlock_kernel(); + return ret; } static int usb_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) @@ -2615,10 +2624,13 @@ static int usb_audio_open(struct inode *inode, struct file *file) static int usb_audio_release(struct inode *inode, struct file *file) { struct usb_audiodev *as = (struct usb_audiodev *)file->private_data; - struct usb_audio_state *s = as->state; - struct usb_device *dev = s->usbdev; + struct usb_audio_state *s; + struct usb_device *dev; struct usb_interface *iface; + lock_kernel(); + s = as->state; + dev = s->usbdev; if (file->f_mode & FMODE_WRITE) drain_out(as, file->f_flags & O_NONBLOCK); down(&open_sem); @@ -2643,6 +2655,7 @@ static int usb_audio_release(struct inode *inode, struct file *file) as->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE); release(s); wake_up(&open_wait); + unlock_kernel(); return 0; } diff --git a/drivers/usb/bluetooth.c b/drivers/usb/bluetooth.c index aaea67a4c..bd7be69e8 100644 --- a/drivers/usb/bluetooth.c +++ b/drivers/usb/bluetooth.c @@ -1,11 +1,15 @@ /* - * bluetooth.c Version 0.1 + * bluetooth.c Version 0.2 * * Copyright (c) 2000 Greg Kroah-Hartman <greg@kroah.com> * * USB Bluetooth driver, based on the Bluetooth Spec version 1.0B * * + * (07/11/2000) Version 0.2 gkh + * Fixed a small bug found by Nils Faerber in the usb_bluetooth_probe + * function. + * * (07/09/2000) Version 0.1 gkh * Initial release. Has support for sending ACL data (which is really just * a HCI frame.) Raw HCI commands and HCI events are not supported. @@ -619,6 +623,7 @@ static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum) memset(bluetooth, 0, sizeof(struct usb_bluetooth)); + bluetooth->magic = USB_BLUETOOTH_MAGIC; bluetooth->dev = dev; bluetooth->minor = minor; bluetooth->tqueue.routine = bluetooth_softint; @@ -676,6 +681,8 @@ static void * usb_bluetooth_probe(struct usb_device *dev, unsigned int ifnum) tty_register_devfs (&bluetooth_tty_driver, 0, minor); info("Bluetooth converter now attached to ttyBLUE%d (or usb/ttblue/%d for devfs)", minor, minor); + bluetooth_table[minor] = bluetooth; + return bluetooth; /* success */ probe_error: diff --git a/drivers/usb/dabusb.c b/drivers/usb/dabusb.c index 8b1df4edf..9b3bc24fa 100644 --- a/drivers/usb/dabusb.c +++ b/drivers/usb/dabusb.c @@ -38,6 +38,7 @@ #include <asm/atomic.h> #include <linux/delay.h> #include <linux/usb.h> +#include <linux/smp_lock.h> #include "dabusb.h" #include "dabfirmware.h" @@ -613,6 +614,7 @@ static int dabusb_release (struct inode *inode, struct file *file) dbg("dabusb_release"); + lock_kernel(); down (&s->mutex); dabusb_stop (s); dabusb_free_buffers (s); @@ -626,6 +628,7 @@ static int dabusb_release (struct inode *inode, struct file *file) wake_up (&s->remove_ok); s->opened = 0; + unlock_kernel(); return 0; } diff --git a/drivers/usb/dc2xx.c b/drivers/usb/dc2xx.c index 4fcfa640c..bb960a4af 100644 --- a/drivers/usb/dc2xx.c +++ b/drivers/usb/dc2xx.c @@ -60,6 +60,7 @@ #include <linux/module.h> #undef DEBUG #include <linux/usb.h> +#include <linux/smp_lock.h> @@ -298,10 +299,12 @@ static int camera_release (struct inode *inode, struct file *file) kfree (camera->buf); /* If camera was unplugged with open file ... */ + lock_kernel(); if (!camera->dev) { minor_data [camera->subminor] = NULL; kfree (camera); } + unlock_kernel(); dbg ("close"); diff --git a/drivers/usb/devices.c b/drivers/usb/devices.c index c99f86973..df02bcf2a 100644 --- a/drivers/usb/devices.c +++ b/drivers/usb/devices.c @@ -45,6 +45,9 @@ * up an eventual usbd * 2000-01-04: Thomas Sailer <sailer@ife.ee.ethz.ch> * Turned into its own filesystem + * 2000-07-05: Ashley Montanaro <ashley@compsoc.man.ac.uk> + * Converted file reading routine to dump to buffer once + * per device, not per bus * * $Id: devices.c,v 1.5 2000/01/11 13:58:21 tom Exp $ */ @@ -367,23 +370,40 @@ static char *usb_dump_string(char *start, char *end, const struct usb_device *de /*****************************************************************/ -static char *usb_device_dump(char *start, char *end, struct usb_device *usbdev, - struct usb_bus *bus, int level, int index, int count) +/* This is a recursive function. Parameters: + * buffer - the user-space buffer to write data into + * nbytes - the maximum number of bytes to write + * skip_bytes - the number of bytes to skip before writing anything + * 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, + struct usb_device *usbdev, struct usb_bus *bus, int level, int index, int count) { int chix; - int cnt = 0; + int ret, cnt = 0; int parent_devnum = 0; - + char *pages_start, *data_end; + unsigned int length; + ssize_t total_written = 0; + + /* don't bother with anything else if we're not writing any data */ + if (*nbytes <= 0) + return 0; + if (level > MAX_TOPO_LEVEL) - return start; + return total_written; + /* allocate 2^1 pages = 8K (on i386); should be more than enough for one device */ + if (!(pages_start = (char*) __get_free_pages(GFP_KERNEL,1))) + return -ENOMEM; + if (usbdev->parent && usbdev->parent->devnum != -1) parent_devnum = usbdev->parent->devnum; /* * So the root hub's parent is 0 and any device that is * plugged into the root hub has a parent of 0. */ - start += sprintf(start, format_topo, bus->busnum, level, parent_devnum, index, count, - usbdev->devnum, usbdev->slow ? "1.5" : "12 ", usbdev->maxchild); + data_end = pages_start + sprintf(pages_start, format_topo, bus->busnum, level, parent_devnum, index, count, + usbdev->devnum, usbdev->slow ? "1.5" : "12 ", usbdev->maxchild); /* * level = topology-tier level; * parent_devnum = parent device number; @@ -392,30 +412,58 @@ static char *usb_device_dump(char *start, char *end, struct usb_device *usbdev, */ /* If this is the root hub, display the bandwidth information */ if (level == 0) - start += sprintf(start, format_bandwidth, bus->bandwidth_allocated, + data_end += sprintf(data_end, format_bandwidth, bus->bandwidth_allocated, FRAME_TIME_MAX_USECS_ALLOC, (100 * bus->bandwidth_allocated + FRAME_TIME_MAX_USECS_ALLOC / 2) / FRAME_TIME_MAX_USECS_ALLOC, bus->bandwidth_int_reqs, bus->bandwidth_isoc_reqs); - start = usb_dump_desc(start, end, usbdev); - if (start > end) - return start + sprintf(start, "(truncated)\n"); + + data_end = usb_dump_desc(data_end, pages_start + (2 * PAGE_SIZE) - 256, usbdev); + + if (data_end > (pages_start + (2 * PAGE_SIZE) - 256)) + data_end += sprintf(data_end, "(truncated)\n"); + + length = data_end - pages_start; + /* if we can start copying some data to the user */ + if (length > *skip_bytes) { + length -= *skip_bytes; + if (length > *nbytes) + length = *nbytes; + if (copy_to_user(*buffer, pages_start + *skip_bytes, length)) { + free_pages((unsigned long)pages_start, 1); + + if (total_written == 0) + return -EFAULT; + return total_written; + } + *nbytes -= length; + *file_offset += length; + total_written += length; + *buffer += length; + *skip_bytes = 0; + } else + *skip_bytes -= length; + + free_pages((unsigned long)pages_start, 1); + /* Now look at all of this device's children. */ for (chix = 0; chix < usbdev->maxchild; chix++) { - if (start > end) - return start; - if (usbdev->children[chix]) - start = usb_device_dump(start, end, usbdev->children[chix], bus, level + 1, chix, ++cnt); + if (usbdev->children[chix]) { + ret = usb_device_dump(buffer, nbytes, skip_bytes, file_offset, usbdev->children[chix], + bus, level + 1, chix, ++cnt); + if (ret == -EFAULT) + return total_written; + total_written += ret; + } } - return start; + return total_written; } static ssize_t usb_device_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos) { struct list_head *buslist; struct usb_bus *bus; - char *page, *end; - ssize_t ret = 0; - unsigned int pos, len; + ssize_t ret, total_written = 0; + loff_t skip_bytes = *ppos; if (*ppos < 0) return -EINVAL; @@ -423,34 +471,18 @@ static ssize_t usb_device_read(struct file *file, char *buf, size_t nbytes, loff return 0; if (!access_ok(VERIFY_WRITE, buf, nbytes)) return -EFAULT; - if (!(page = (char*) __get_free_pages(GFP_KERNEL,1))) - return -ENOMEM; - pos = *ppos; + /* enumerate busses */ for (buslist = usb_bus_list.next; buslist != &usb_bus_list; buslist = buslist->next) { /* print devices for this bus */ bus = list_entry(buslist, struct usb_bus, bus_list); - end = usb_device_dump(page, page + (2*PAGE_SIZE - 256), bus->root_hub, bus, 0, 0, 0); - len = end - page; - if (len > pos) { - len -= pos; - if (len > nbytes) - len = nbytes; - if (copy_to_user(buf, page + pos, len)) { - if (!ret) - ret = -EFAULT; - break; - } - nbytes -= len; - buf += len; - ret += len; - pos = 0; - *ppos += len; - } else - pos -= len; + /* recurse through all children of the root hub */ + ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, bus->root_hub, bus, 0, 0, 0); + if (ret < 0) + return ret; + total_written += ret; } - free_pages((unsigned long)page, 1); - return ret; + return total_written; } /* Kernel lock for "lastev" protection */ diff --git a/drivers/usb/evdev.c b/drivers/usb/evdev.c index 7eca5e304..e11327cef 100644 --- a/drivers/usb/evdev.c +++ b/drivers/usb/evdev.c @@ -37,6 +37,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/input.h> +#include <linux/smp_lock.h> struct evdev { int exist; @@ -91,8 +92,10 @@ static int evdev_fasync(int fd, struct file *file, int on) static int evdev_release(struct inode * inode, struct file * file) { struct evdev_list *list = file->private_data; - struct evdev_list **listptr = &list->evdev->list; + struct evdev_list **listptr; + lock_kernel(); + listptr = &list->evdev->list; evdev_fasync(-1, file, 0); while (*listptr && (*listptr != list)) @@ -110,6 +113,7 @@ static int evdev_release(struct inode * inode, struct file * file) } kfree(list); + unlock_kernel(); return 0; } diff --git a/drivers/usb/joydev.c b/drivers/usb/joydev.c index 5349d515c..2210ad0d1 100644 --- a/drivers/usb/joydev.c +++ b/drivers/usb/joydev.c @@ -44,6 +44,7 @@ #include <linux/module.h> #include <linux/poll.h> #include <linux/init.h> +#include <linux/smp_lock.h> #define JOYDEV_MINOR_BASE 0 #define JOYDEV_MINORS 32 @@ -160,8 +161,10 @@ static int joydev_fasync(int fd, struct file *file, int on) static int joydev_release(struct inode * inode, struct file * file) { struct joydev_list *list = file->private_data; - struct joydev_list **listptr = &list->joydev->list; + struct joydev_list **listptr; + lock_kernel(); + listptr = &list->joydev->list; joydev_fasync(-1, file, 0); while (*listptr && (*listptr != list)) @@ -179,6 +182,7 @@ static int joydev_release(struct inode * inode, struct file * file) } kfree(list); + unlock_kernel(); return 0; } diff --git a/drivers/usb/mdc800.c b/drivers/usb/mdc800.c index dc578df33..80a1ebbf4 100644 --- a/drivers/usb/mdc800.c +++ b/drivers/usb/mdc800.c @@ -76,6 +76,7 @@ #include <linux/init.h> #include <linux/malloc.h> #include <linux/module.h> +#include <linux/smp_lock.h> #include <linux/usb.h> @@ -582,6 +583,7 @@ static int mdc800_device_release (struct inode* inode, struct file *file) int retval=0; dbg ("Mustek MDC800 device closed."); + lock_kernel(); if (mdc800->open && (mdc800->state != NOT_CONNECTED)) { mdc800->open=0; @@ -593,6 +595,7 @@ static int mdc800_device_release (struct inode* inode, struct file *file) { retval=-EIO; } + unlock_kernel(); return retval; } diff --git a/drivers/usb/mousedev.c b/drivers/usb/mousedev.c index 5c871a88d..ea5ad301b 100644 --- a/drivers/usb/mousedev.c +++ b/drivers/usb/mousedev.c @@ -38,6 +38,7 @@ #include <linux/init.h> #include <linux/input.h> #include <linux/config.h> +#include <linux/smp_lock.h> #ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_X #define CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024 @@ -159,8 +160,10 @@ static int mousedev_fasync(int fd, struct file *file, int on) static int mousedev_release(struct inode * inode, struct file * file) { struct mousedev_list *list = file->private_data; - struct mousedev_list **listptr = &list->mousedev->list; + struct mousedev_list **listptr; + lock_kernel(); + listptr = &list->mousedev->list; mousedev_fasync(-1, file, 0); while (*listptr && (*listptr != list)) @@ -197,6 +200,7 @@ static int mousedev_release(struct inode * inode, struct file * file) } kfree(list); + unlock_kernel(); return 0; } diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c index 4dc11aee0..987f1a8b5 100644 --- a/drivers/usb/printer.c +++ b/drivers/usb/printer.c @@ -37,6 +37,7 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/sched.h> +#include <linux/smp_lock.h> #include <linux/signal.h> #include <linux/poll.h> #include <linux/init.h> @@ -167,17 +168,19 @@ static int usblp_open(struct inode *inode, struct file *file) if (minor < 0 || minor >= USBLP_MINORS) return -ENODEV; + lock_kernel(); usblp = usblp_table[minor]; + retval = -ENODEV; if (!usblp || !usblp->dev) - return -ENODEV; + goto out; + retval = -EBUSY; if (usblp->used) - return -EBUSY; + goto out; - if ((retval = usblp_check_status(usblp))) { - return retval; - } + if ((retval = usblp_check_status(usblp))) + goto out; usblp->used = 1; file->private_data = usblp; @@ -189,8 +192,9 @@ static int usblp_open(struct inode *inode, struct file *file) usblp->readcount = 0; usb_submit_urb(&usblp->readurb); } - - return 0; +out: + unlock_kernel(); + return retval; } static int usblp_release(struct inode *inode, struct file *file) diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c index 3fba783e0..9c650cfdc 100644 --- a/drivers/usb/usb.c +++ b/drivers/usb/usb.c @@ -58,8 +58,6 @@ static struct usb_driver *usb_minors[16]; int usb_register(struct usb_driver *new_driver) { - struct list_head *tmp; - if (new_driver->fops != NULL) { if (usb_minors[new_driver->minor/16]) { err("error registering %s driver", new_driver->name); @@ -75,13 +73,22 @@ int usb_register(struct usb_driver *new_driver) /* Add it to the list of known drivers */ list_add(&new_driver->driver_list, &usb_driver_list); - /* - * We go through all existing devices, and see if any of them would - * be acceptable to the new driver.. This is done using a depth-first - * search for devices without a registered driver already, then - * running 'probe' with each of the drivers registered on every one - * of these. - */ + usb_scan_devices(); + + return 0; +} + +/* + * We go through all existing devices, and see if any of them would + * be acceptable to the new driver.. This is done using a depth-first + * search for devices without a registered driver already, then + * running 'probe' with each of the drivers registered on every one + * of these. + */ +void usb_scan_devices(void) +{ + struct list_head *tmp; + tmp = usb_bus_list.next; while (tmp != &usb_bus_list) { struct usb_bus *bus = list_entry(tmp,struct usb_bus, bus_list); @@ -89,7 +96,6 @@ int usb_register(struct usb_driver *new_driver) tmp = tmp->next; usb_check_support(bus->root_hub); } - return 0; } /* @@ -1772,6 +1778,7 @@ EXPORT_SYMBOL(usb_ifnum_to_if); EXPORT_SYMBOL(usb_register); EXPORT_SYMBOL(usb_deregister); +EXPORT_SYMBOL(usb_scan_devices); EXPORT_SYMBOL(usb_alloc_bus); EXPORT_SYMBOL(usb_free_bus); EXPORT_SYMBOL(usb_register_bus); diff --git a/drivers/video/fbcon-mac.c b/drivers/video/fbcon-mac.c index 0b3e816e7..2d021dd87 100644 --- a/drivers/video/fbcon-mac.c +++ b/drivers/video/fbcon-mac.c @@ -100,8 +100,8 @@ void fbcon_mac_bmove(struct display *p, int sy, int sx, int dy, int dx, err_buf[cnt] = 0x700 | err_str[cnt]; fbcon_mac_putcs(p->conp, p, err_buf, len, 0, 0); /* pause for the user */ - for(cnt = 0; cnt < 50000; cnt++) - udelay(100); + printk( "ERROR: shift algorithm...\n" ); + mdelay(5000); return; } } @@ -318,12 +318,25 @@ void fbcon_mac_revc(struct display *p, int xx, int yy) } } +static inline void plot_helper(u8 *dest, u8 bit, int bw) +{ + switch (bw) { + case PIXEL_BLACK_MAC: + fb_writeb( fb_readb(dest) | bit, dest ); + break; + case PIXEL_WHITE_MAC: + fb_writeb( fb_readb(dest) & (~bit), dest ); + break; + case PIXEL_INVERT_MAC: + fb_writeb( fb_readb(dest) ^ bit, dest ); + break; + default: + printk( "ERROR: Unknown pixel value in plot_pixel_mac\n"); + } +} + /* * plot_pixel_mac - * - * bw == 0 = black - * 1 = white - * 2 = invert */ static void plot_pixel_mac(struct display *p, int bw, int pixel_x, int pixel_y) { @@ -333,10 +346,8 @@ static void plot_pixel_mac(struct display *p, int bw, int pixel_x, int pixel_y) /* There *are* 68k Macs that support more than 832x624, you know :-) */ if (pixel_x < 0 || pixel_y < 0 || pixel_x >= p->var.xres || pixel_y >= p->var.yres) { - int cnt; printk ("ERROR: pixel_x == %d, pixel_y == %d", pixel_x, pixel_y); - for(cnt = 0; cnt < 100000; cnt++) - udelay(100); + mdelay(1000); return; } @@ -344,90 +355,36 @@ static void plot_pixel_mac(struct display *p, int bw, int pixel_x, int pixel_y) case 1: dest = (u8 *) ((pixel_x >> 3) + p->screen_base + pixel_y * p->next_line); bit = 0x80 >> (pixel_x & 7); - switch (bw) { - case PIXEL_BLACK_MAC: - *dest |= bit; - break; - case PIXEL_WHITE_MAC: - *dest &= ~bit; - break; - case PIXEL_INVERT_MAC: - *dest ^= bit; - break; - default: - printk( "ERROR: Unknown pixel value in plot_pixel_mac\n"); - } + plot_helper(dest, bit, bw); break; case 2: dest = (u8 *) ((pixel_x >> 2) + p->screen_base + pixel_y * p->next_line); bit = 0xC0 >> ((pixel_x & 3) << 1); - switch (bw) { - case PIXEL_BLACK_MAC: - *dest |= bit; - break; - case PIXEL_WHITE_MAC: - *dest &= ~bit; - break; - case PIXEL_INVERT_MAC: - *dest ^= bit; - break; - default: - printk( "ERROR: Unknown pixel value in plot_pixel_mac\n"); - } + plot_helper(dest, bit, bw); break; case 4: - dest = (u8 *) ((pixel_x / 2) + p->screen_base + pixel_y * p->next_line); + dest = (u8 *) ((pixel_x >> 1) + p->screen_base + pixel_y * p->next_line); bit = 0xF0 >> ((pixel_x & 1) << 2); - switch (bw) { - case PIXEL_BLACK_MAC: - *dest |= bit; - break; - case PIXEL_WHITE_MAC: - *dest &= ~bit; - break; - case PIXEL_INVERT_MAC: - *dest ^= bit; - break; - default: - printk( "ERROR: Unknown pixel value in plot_pixel_mac\n"); - } + plot_helper(dest, bit, bw); break; case 8: dest = (u8 *) (pixel_x + p->screen_base + pixel_y * p->next_line); bit = 0xFF; - switch (bw) { - case PIXEL_BLACK_MAC: - *dest |= bit; - break; - case PIXEL_WHITE_MAC: - *dest &= ~bit; - break; - case PIXEL_INVERT_MAC: - *dest ^= bit; - break; - default: - printk( "ERROR: Unknown pixel value in plot_pixel_mac\n"); - } + plot_helper(dest, bit, bw); break; +/* FIXME: You can't access framebuffer directly like this! */ case 16: dest16 = (u16 *) ((pixel_x *2) + p->screen_base + pixel_y * p->next_line); pix16 = 0xFFFF; switch (bw) { - case PIXEL_BLACK_MAC: - *dest16 = ~pix16; - break; - case PIXEL_WHITE_MAC: - *dest16 = pix16; - break; - case PIXEL_INVERT_MAC: - *dest16 ^= pix16; - break; - default: - printk( "ERROR: Unknown pixel value in plot_pixel_mac\n"); + case PIXEL_BLACK_MAC: *dest16 = ~pix16; break; + case PIXEL_WHITE_MAC: *dest16 = pix16; break; + case PIXEL_INVERT_MAC: *dest16 ^= pix16; break; + default: printk( "ERROR: Unknown pixel value in plot_pixel_mac\n"); } break; @@ -435,17 +392,10 @@ static void plot_pixel_mac(struct display *p, int bw, int pixel_x, int pixel_y) dest32 = (u32 *) ((pixel_x *4) + p->screen_base + pixel_y * p->next_line); pix32 = 0xFFFFFFFF; switch (bw) { - case PIXEL_BLACK_MAC: - *dest32 = ~pix32; - break; - case PIXEL_WHITE_MAC: - *dest32 = pix32; - break; - case PIXEL_INVERT_MAC: - *dest32 ^= pix32; - break; - default: - printk( "ERROR: Unknown pixel value in plot_pixel_mac\n"); + case PIXEL_BLACK_MAC: *dest32 = ~pix32; break; + case PIXEL_WHITE_MAC: *dest32 = pix32; break; + case PIXEL_INVERT_MAC: *dest32 ^= pix32; break; + default: printk( "ERROR: Unknown pixel value in plot_pixel_mac\n"); } break; } @@ -497,7 +447,7 @@ static int get_pixel_mac(struct display *p, int pixel_x, int pixel_y) */ struct display_switch fbcon_mac = { - fbcon_mac_setup, fbcon_mac_bmove, fbcon_mac_clear, fbcon_mac_putc, + fbcon_mac_setup, fbcon_redraw_bmove, fbcon_redraw_clear, fbcon_mac_putc, fbcon_mac_putcs, fbcon_mac_revc, NULL, NULL, NULL, FONTWIDTHRANGE(1,8) }; diff --git a/drivers/video/fbcon.c b/drivers/video/fbcon.c index c2611d0a6..bf74fa162 100644 --- a/drivers/video/fbcon.c +++ b/drivers/video/fbcon.c @@ -1124,6 +1124,15 @@ static void fbcon_redraw(struct vc_data *conp, struct display *p, } } +void fbcon_redraw_clear(struct vc_data *conp, struct display *p, int sy, int sx, + int height, int width) +{ + int x, y; + for (y=0; y<height; y++) + for (x=0; x<width; x++) + fbcon_putc(conp, ' ', sy+y, sx+x); +} + /* This cannot be used together with ypan or ywrap */ void fbcon_redraw_bmove(struct display *p, int sy, int sx, int dy, int dx, int h, int w) { @@ -2422,5 +2431,6 @@ struct display_switch fbcon_dummy = { EXPORT_SYMBOL(fb_display); EXPORT_SYMBOL(fbcon_redraw_bmove); +EXPORT_SYMBOL(fbcon_redraw_clear); EXPORT_SYMBOL(fbcon_dummy); EXPORT_SYMBOL(fb_con); diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 2ab527f02..30bd06d32 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -14,6 +14,7 @@ #include <linux/types.h> #include <linux/errno.h> #include <linux/sched.h> +#include <linux/smp_lock.h> #include <linux/kernel.h> #include <linux/major.h> #include <linux/malloc.h> @@ -473,8 +474,13 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) off = vma->vm_pgoff << PAGE_SHIFT; if (!fb) return -ENODEV; - if (fb->fb_mmap) - return fb->fb_mmap(info, file, vma); + if (fb->fb_mmap) { + int res; + lock_kernel(); + res = fb->fb_mmap(info, file, vma); + unlock_kernel(); + return res; + } #if defined(__sparc__) && !defined(__sparc_v9__) /* Should never get here, all fb drivers should have their own @@ -483,6 +489,7 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) #else /* !sparc32... */ + lock_kernel(); fb->fb_get_fix(&fix, PROC_CONSOLE(info), info); /* frame buffer memory */ @@ -497,6 +504,7 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) start = fix.mmio_start; len = PAGE_ALIGN((start & ~PAGE_MASK)+fix.mmio_len); } + unlock_kernel(); start &= PAGE_MASK; if ((vma->vm_end - vma->vm_start + off) > len) return -EINVAL; @@ -612,12 +620,15 @@ static int fb_release(struct inode *inode, struct file *file) { int fbidx = GET_FB_IDX(inode->i_rdev); - struct fb_info *info = registered_fb[fbidx]; + struct fb_info *info; + lock_kernel(); + info = registered_fb[fbidx]; if (info->fbops->fb_release) info->fbops->fb_release(info,1); if (info->fbops->owner) __MOD_DEC_USE_COUNT(info->fbops->owner); + unlock_kernel(); return 0; } diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c index 261ce3d3c..c465bafc7 100644 --- a/drivers/video/vesafb.c +++ b/drivers/video/vesafb.c @@ -30,6 +30,7 @@ #include <video/fbcon-cfb16.h> #include <video/fbcon-cfb24.h> #include <video/fbcon-cfb32.h> +#include <video/fbcon-mac.h> #define dac_reg (0x3c8) #define dac_val (0x3c9) @@ -220,8 +221,13 @@ static void vesafb_set_disp(int con) break; #endif default: +#ifdef FBCON_HAS_MAC + sw = &fbcon_mac; + break; +#else sw = &fbcon_dummy; return; +#endif } memcpy(&vesafb_sw, sw, sizeof(*sw)); display->dispsw = &vesafb_sw; |