diff options
Diffstat (limited to 'drivers')
590 files changed, 23434 insertions, 11079 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index 80f0ec91e2cf..59f33fa6af3e 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -84,6 +84,8 @@ source "drivers/memstick/Kconfig" source "drivers/leds/Kconfig" +source "drivers/accessibility/Kconfig" + source "drivers/infiniband/Kconfig" source "drivers/edac/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index e5e394a7e6c0..f65deda72d61 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -70,6 +70,7 @@ obj-$(CONFIG_WATCHDOG) += watchdog/ obj-$(CONFIG_PHONE) += telephony/ obj-$(CONFIG_MD) += md/ obj-$(CONFIG_BT) += bluetooth/ +obj-$(CONFIG_ACCESSIBILITY) += accessibility/ obj-$(CONFIG_ISDN) += isdn/ obj-$(CONFIG_EDAC) += edac/ obj-$(CONFIG_MCA) += mca/ diff --git a/drivers/accessibility/Kconfig b/drivers/accessibility/Kconfig new file mode 100644 index 000000000000..1264c4b98094 --- /dev/null +++ b/drivers/accessibility/Kconfig @@ -0,0 +1,23 @@ +menuconfig ACCESSIBILITY + bool "Accessibility support" + ---help--- + Enable a submenu where accessibility items may be enabled. + + If unsure, say N. + +if ACCESSIBILITY +config A11Y_BRAILLE_CONSOLE + bool "Console on braille device" + depends on VT + depends on SERIAL_CORE_CONSOLE + ---help--- + Enables console output on a braille device connected to a 8250 + serial port. For now only the VisioBraille device is supported. + + To actually enable it, you need to pass option + console=brl,ttyS0 + to the kernel. Options are the same as for serial console. + + If unsure, say N. + +endif # ACCESSIBILITY diff --git a/drivers/accessibility/Makefile b/drivers/accessibility/Makefile new file mode 100644 index 000000000000..72b01a46546f --- /dev/null +++ b/drivers/accessibility/Makefile @@ -0,0 +1 @@ +obj-y += braille/ diff --git a/drivers/accessibility/braille/Makefile b/drivers/accessibility/braille/Makefile new file mode 100644 index 000000000000..2e9f16c91347 --- /dev/null +++ b/drivers/accessibility/braille/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille_console.o diff --git a/drivers/accessibility/braille/braille_console.c b/drivers/accessibility/braille/braille_console.c new file mode 100644 index 000000000000..0a5f6b2114c5 --- /dev/null +++ b/drivers/accessibility/braille/braille_console.c @@ -0,0 +1,397 @@ +/* + * Minimalistic braille device kernel support. + * + * By default, shows console messages on the braille device. + * Pressing Insert switches to VC browsing. + * + * Copyright (C) Samuel Thibault <samuel.thibault@ens-lyon.org> + * + * 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 the program ; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/autoconf.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/console.h> +#include <linux/notifier.h> + +#include <linux/selection.h> +#include <linux/vt_kern.h> +#include <linux/consolemap.h> + +#include <linux/keyboard.h> +#include <linux/kbd_kern.h> +#include <linux/input.h> + +MODULE_AUTHOR("samuel.thibault@ens-lyon.org"); +MODULE_DESCRIPTION("braille device"); +MODULE_LICENSE("GPL"); + +/* + * Braille device support part. + */ + +/* Emit various sounds */ +static int sound; +module_param(sound, bool, 0); +MODULE_PARM_DESC(sound, "emit sounds"); + +static void beep(unsigned int freq) +{ + if (sound) + kd_mksound(freq, HZ/10); +} + +/* mini console */ +#define WIDTH 40 +#define BRAILLE_KEY KEY_INSERT +static u16 console_buf[WIDTH]; +static int console_cursor; + +/* mini view of VC */ +static int vc_x, vc_y, lastvc_x, lastvc_y; + +/* show console ? (or show VC) */ +static int console_show = 1; +/* pending newline ? */ +static int console_newline = 1; +static int lastVC = -1; + +static struct console *braille_co; + +/* Very VisioBraille-specific */ +static void braille_write(u16 *buf) +{ + static u16 lastwrite[WIDTH]; + unsigned char data[1 + 1 + 2*WIDTH + 2 + 1], csum = 0, *c; + u16 out; + int i; + + if (!braille_co) + return; + + if (!memcmp(lastwrite, buf, WIDTH * sizeof(*buf))) + return; + memcpy(lastwrite, buf, WIDTH * sizeof(*buf)); + +#define SOH 1 +#define STX 2 +#define ETX 2 +#define EOT 4 +#define ENQ 5 + data[0] = STX; + data[1] = '>'; + csum ^= '>'; + c = &data[2]; + for (i = 0; i < WIDTH; i++) { + out = buf[i]; + if (out >= 0x100) + out = '?'; + else if (out == 0x00) + out = ' '; + csum ^= out; + if (out <= 0x05) { + *c++ = SOH; + out |= 0x40; + } + *c++ = out; + } + + if (csum <= 0x05) { + *c++ = SOH; + csum |= 0x40; + } + *c++ = csum; + *c++ = ETX; + + braille_co->write(braille_co, data, c - data); +} + +/* Follow the VC cursor*/ +static void vc_follow_cursor(struct vc_data *vc) +{ + vc_x = vc->vc_x - (vc->vc_x % WIDTH); + vc_y = vc->vc_y; + lastvc_x = vc->vc_x; + lastvc_y = vc->vc_y; +} + +/* Maybe the VC cursor moved, if so follow it */ +static void vc_maybe_cursor_moved(struct vc_data *vc) +{ + if (vc->vc_x != lastvc_x || vc->vc_y != lastvc_y) + vc_follow_cursor(vc); +} + +/* Show portion of VC at vc_x, vc_y */ +static void vc_refresh(struct vc_data *vc) +{ + u16 buf[WIDTH]; + int i; + + for (i = 0; i < WIDTH; i++) { + u16 glyph = screen_glyph(vc, + 2 * (vc_x + i) + vc_y * vc->vc_size_row); + buf[i] = inverse_translate(vc, glyph, 1); + } + braille_write(buf); +} + +/* + * Link to keyboard + */ + +static int keyboard_notifier_call(struct notifier_block *blk, + unsigned long code, void *_param) +{ + struct keyboard_notifier_param *param = _param; + struct vc_data *vc = param->vc; + int ret = NOTIFY_OK; + + if (!param->down) + return ret; + + switch (code) { + case KBD_KEYCODE: + if (console_show) { + if (param->value == BRAILLE_KEY) { + console_show = 0; + beep(880); + vc_maybe_cursor_moved(vc); + vc_refresh(vc); + ret = NOTIFY_STOP; + } + } else { + ret = NOTIFY_STOP; + switch (param->value) { + case KEY_INSERT: + beep(440); + console_show = 1; + lastVC = -1; + braille_write(console_buf); + break; + case KEY_LEFT: + if (vc_x > 0) { + vc_x -= WIDTH; + if (vc_x < 0) + vc_x = 0; + } else if (vc_y >= 1) { + beep(880); + vc_y--; + vc_x = vc->vc_cols-WIDTH; + } else + beep(220); + break; + case KEY_RIGHT: + if (vc_x + WIDTH < vc->vc_cols) { + vc_x += WIDTH; + } else if (vc_y + 1 < vc->vc_rows) { + beep(880); + vc_y++; + vc_x = 0; + } else + beep(220); + break; + case KEY_DOWN: + if (vc_y + 1 < vc->vc_rows) + vc_y++; + else + beep(220); + break; + case KEY_UP: + if (vc_y >= 1) + vc_y--; + else + beep(220); + break; + case KEY_HOME: + vc_follow_cursor(vc); + break; + case KEY_PAGEUP: + vc_x = 0; + vc_y = 0; + break; + case KEY_PAGEDOWN: + vc_x = 0; + vc_y = vc->vc_rows-1; + break; + default: + ret = NOTIFY_OK; + break; + } + if (ret == NOTIFY_STOP) + vc_refresh(vc); + } + break; + case KBD_POST_KEYSYM: + { + unsigned char type = KTYP(param->value) - 0xf0; + if (type == KT_SPEC) { + unsigned char val = KVAL(param->value); + int on_off = -1; + + switch (val) { + case KVAL(K_CAPS): + on_off = vc_kbd_led(kbd_table + fg_console, + VC_CAPSLOCK); + break; + case KVAL(K_NUM): + on_off = vc_kbd_led(kbd_table + fg_console, + VC_NUMLOCK); + break; + case KVAL(K_HOLD): + on_off = vc_kbd_led(kbd_table + fg_console, + VC_SCROLLOCK); + break; + } + if (on_off == 1) + beep(880); + else if (on_off == 0) + beep(440); + } + } + case KBD_UNBOUND_KEYCODE: + case KBD_UNICODE: + case KBD_KEYSYM: + /* Unused */ + break; + } + return ret; +} + +static struct notifier_block keyboard_notifier_block = { + .notifier_call = keyboard_notifier_call, +}; + +static int vt_notifier_call(struct notifier_block *blk, + unsigned long code, void *_param) +{ + struct vt_notifier_param *param = _param; + struct vc_data *vc = param->vc; + switch (code) { + case VT_ALLOCATE: + break; + case VT_DEALLOCATE: + break; + case VT_WRITE: + { + unsigned char c = param->c; + if (vc->vc_num != fg_console) + break; + switch (c) { + case '\b': + case 127: + if (console_cursor > 0) { + console_cursor--; + console_buf[console_cursor] = ' '; + } + break; + case '\n': + case '\v': + case '\f': + case '\r': + console_newline = 1; + break; + case '\t': + c = ' '; + /* Fallthrough */ + default: + if (c < 32) + /* Ignore other control sequences */ + break; + if (console_newline) { + memset(console_buf, 0, sizeof(console_buf)); + console_cursor = 0; + console_newline = 0; + } + if (console_cursor == WIDTH) + memmove(console_buf, &console_buf[1], + (WIDTH-1) * sizeof(*console_buf)); + else + console_cursor++; + console_buf[console_cursor-1] = c; + break; + } + if (console_show) + braille_write(console_buf); + else { + vc_maybe_cursor_moved(vc); + vc_refresh(vc); + } + break; + } + case VT_UPDATE: + /* Maybe a VT switch, flush */ + if (console_show) { + if (vc->vc_num != lastVC) { + lastVC = vc->vc_num; + memset(console_buf, 0, sizeof(console_buf)); + console_cursor = 0; + braille_write(console_buf); + } + } else { + vc_maybe_cursor_moved(vc); + vc_refresh(vc); + } + break; + } + return NOTIFY_OK; +} + +static struct notifier_block vt_notifier_block = { + .notifier_call = vt_notifier_call, +}; + +/* + * Called from printk.c when console=brl is given + */ + +int braille_register_console(struct console *console, int index, + char *console_options, char *braille_options) +{ + int ret; + if (!console_options) + /* Only support VisioBraille for now */ + console_options = "57600o8"; + if (braille_co) + return -ENODEV; + if (console->setup) { + ret = console->setup(console, console_options); + if (ret != 0) + return ret; + } + console->flags |= CON_ENABLED; + console->index = index; + braille_co = console; + return 0; +} + +int braille_unregister_console(struct console *console) +{ + if (braille_co != console) + return -EINVAL; + braille_co = NULL; + return 0; +} + +static int __init braille_init(void) +{ + register_keyboard_notifier(&keyboard_notifier_block); + register_vt_notifier(&vt_notifier_block); + return 0; +} + +console_initcall(braille_init); diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 43a95e5640de..5b73f6a2cd86 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -92,6 +92,7 @@ struct acpi_ac { #ifdef CONFIG_ACPI_PROCFS_POWER static const struct file_operations acpi_ac_fops = { + .owner = THIS_MODULE, .open = acpi_ac_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -195,16 +196,11 @@ static int acpi_ac_add_fs(struct acpi_device *device) } /* 'state' [R] */ - entry = create_proc_entry(ACPI_AC_FILE_STATE, - S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data(ACPI_AC_FILE_STATE, + S_IRUGO, acpi_device_dir(device), + &acpi_ac_fops, acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_ac_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } - return 0; } diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index d5729d5dc190..b1c723f9f58d 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -741,15 +741,13 @@ static int acpi_battery_add_fs(struct acpi_device *device) } for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) { - entry = create_proc_entry(acpi_battery_file[i].name, - acpi_battery_file[i].mode, acpi_device_dir(device)); + entry = proc_create_data(acpi_battery_file[i].name, + acpi_battery_file[i].mode, + acpi_device_dir(device), + &acpi_battery_file[i].ops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_battery_file[i].ops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } } return 0; } diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 2d1955c11833..a6dbcf4d9ef5 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -35,6 +35,7 @@ #ifdef CONFIG_X86 #include <asm/mpspec.h> #endif +#include <linux/pci.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> @@ -784,6 +785,7 @@ static int __init acpi_init(void) result = acpi_bus_init(); if (!result) { + pci_mmcfg_late_init(); if (!(pm_flags & PM_APM)) pm_flags |= PM_ACPI; else { diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 6c5da83cdb68..1dfec413588c 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -102,6 +102,7 @@ struct acpi_button { }; static const struct file_operations acpi_button_info_fops = { + .owner = THIS_MODULE, .open = acpi_button_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -109,6 +110,7 @@ static const struct file_operations acpi_button_info_fops = { }; static const struct file_operations acpi_button_state_fops = { + .owner = THIS_MODULE, .open = acpi_button_state_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -207,27 +209,21 @@ static int acpi_button_add_fs(struct acpi_device *device) acpi_device_dir(device)->owner = THIS_MODULE; /* 'info' [R] */ - entry = create_proc_entry(ACPI_BUTTON_FILE_INFO, - S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data(ACPI_BUTTON_FILE_INFO, + S_IRUGO, acpi_device_dir(device), + &acpi_button_info_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_button_info_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* show lid state [R] */ if (button->type == ACPI_BUTTON_TYPE_LID) { - entry = create_proc_entry(ACPI_BUTTON_FILE_STATE, - S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data(ACPI_BUTTON_FILE_STATE, + S_IRUGO, acpi_device_dir(device), + &acpi_button_state_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_button_state_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } } return 0; diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 7222a18a0319..e3f04b272f3f 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -669,16 +669,11 @@ static int acpi_ec_add_fs(struct acpi_device *device) return -ENODEV; } - entry = create_proc_entry(ACPI_EC_FILE_INFO, S_IRUGO, - acpi_device_dir(device)); + entry = proc_create_data(ACPI_EC_FILE_INFO, S_IRUGO, + acpi_device_dir(device), + &acpi_ec_info_ops, acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_ec_info_ops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } - return 0; } diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index abec1ca94cf4..0c24bd4d6562 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -102,6 +102,7 @@ static unsigned int acpi_system_poll_event(struct file *file, poll_table * wait) } static const struct file_operations acpi_system_event_ops = { + .owner = THIS_MODULE, .open = acpi_system_open_event, .read = acpi_system_read_event, .release = acpi_system_close_event, @@ -294,10 +295,9 @@ static int __init acpi_event_init(void) #ifdef CONFIG_ACPI_PROC_EVENT /* 'event' [R] */ - entry = create_proc_entry("event", S_IRUSR, acpi_root_dir); - if (entry) - entry->proc_fops = &acpi_system_event_ops; - else + entry = proc_create("event", S_IRUSR, acpi_root_dir, + &acpi_system_event_ops); + if (!entry) return -ENODEV; #endif diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index c8e3cba423ef..194077ab9b85 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -192,17 +192,13 @@ static int acpi_fan_add_fs(struct acpi_device *device) } /* 'status' [R/W] */ - entry = create_proc_entry(ACPI_FAN_FILE_STATE, - S_IFREG | S_IRUGO | S_IWUSR, - acpi_device_dir(device)); + entry = proc_create_data(ACPI_FAN_FILE_STATE, + S_IFREG | S_IRUGO | S_IWUSR, + acpi_device_dir(device), + &acpi_fan_state_ops, + device); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_fan_state_ops; - entry->data = device; - entry->owner = THIS_MODULE; - } - return 0; } diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 76bf6d90c700..21fc8bf0d31f 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -93,6 +93,7 @@ struct acpi_power_resource { static struct list_head acpi_power_resource_list; static const struct file_operations acpi_power_fops = { + .owner = THIS_MODULE, .open = acpi_power_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -543,15 +544,11 @@ static int acpi_power_add_fs(struct acpi_device *device) } /* 'status' [R] */ - entry = create_proc_entry(ACPI_POWER_FILE_STATUS, - S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data(ACPI_POWER_FILE_STATUS, + S_IRUGO, acpi_device_dir(device), + &acpi_power_fops, acpi_driver_data(device)); if (!entry) return -EIO; - else { - entry->proc_fops = &acpi_power_fops; - entry->data = acpi_driver_data(device); - } - return 0; } diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index a825b431b64f..5241e3ff5080 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -112,6 +112,7 @@ static struct acpi_driver acpi_processor_driver = { #define UNINSTALL_NOTIFY_HANDLER 2 static const struct file_operations acpi_processor_info_fops = { + .owner = THIS_MODULE, .open = acpi_processor_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -326,40 +327,30 @@ static int acpi_processor_add_fs(struct acpi_device *device) acpi_device_dir(device)->owner = THIS_MODULE; /* 'info' [R] */ - entry = create_proc_entry(ACPI_PROCESSOR_FILE_INFO, - S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data(ACPI_PROCESSOR_FILE_INFO, + S_IRUGO, acpi_device_dir(device), + &acpi_processor_info_fops, + acpi_driver_data(device)); if (!entry) return -EIO; - else { - entry->proc_fops = &acpi_processor_info_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'throttling' [R/W] */ - entry = create_proc_entry(ACPI_PROCESSOR_FILE_THROTTLING, - S_IFREG | S_IRUGO | S_IWUSR, - acpi_device_dir(device)); + entry = proc_create_data(ACPI_PROCESSOR_FILE_THROTTLING, + S_IFREG | S_IRUGO | S_IWUSR, + acpi_device_dir(device), + &acpi_processor_throttling_fops, + acpi_driver_data(device)); if (!entry) return -EIO; - else { - entry->proc_fops = &acpi_processor_throttling_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'limit' [R/W] */ - entry = create_proc_entry(ACPI_PROCESSOR_FILE_LIMIT, - S_IFREG | S_IRUGO | S_IWUSR, - acpi_device_dir(device)); + entry = proc_create_data(ACPI_PROCESSOR_FILE_LIMIT, + S_IFREG | S_IRUGO | S_IWUSR, + acpi_device_dir(device), + &acpi_processor_limit_fops, + acpi_driver_data(device)); if (!entry) return -EIO; - else { - entry->proc_fops = &acpi_processor_limit_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } - return 0; } @@ -612,6 +603,15 @@ static int acpi_processor_get_info(struct acpi_processor *pr, unsigned has_uid) request_region(pr->throttling.address, 6, "ACPI CPU throttle"); } + /* + * If ACPI describes a slot number for this CPU, we can use it + * ensure we get the right value in the "physical id" field + * of /proc/cpuinfo + */ + status = acpi_evaluate_object(pr->handle, "_SUN", NULL, &buffer); + if (ACPI_SUCCESS(status)) + arch_fix_phys_package_id(pr->id, object.integer.value); + return 0; } diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 0d90ff5fd117..789d4947ed31 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1282,6 +1282,7 @@ static int acpi_processor_power_open_fs(struct inode *inode, struct file *file) } static const struct file_operations acpi_processor_power_fops = { + .owner = THIS_MODULE, .open = acpi_processor_power_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -1822,16 +1823,12 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, } /* 'power' [R] */ - entry = create_proc_entry(ACPI_PROCESSOR_FILE_POWER, - S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data(ACPI_PROCESSOR_FILE_POWER, + S_IRUGO, acpi_device_dir(device), + &acpi_processor_power_fops, + acpi_driver_data(device)); if (!entry) return -EIO; - else { - entry->proc_fops = &acpi_processor_power_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } - return 0; } diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index b477a4be8a69..d80b2d1441af 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -411,6 +411,7 @@ EXPORT_SYMBOL(acpi_processor_notify_smm); static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_processor_perf_fops = { + .owner = THIS_MODULE, .open = acpi_processor_perf_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -456,7 +457,6 @@ static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file) static void acpi_cpufreq_add_file(struct acpi_processor *pr) { - struct proc_dir_entry *entry = NULL; struct acpi_device *device = NULL; @@ -464,14 +464,9 @@ static void acpi_cpufreq_add_file(struct acpi_processor *pr) return; /* add file 'performance' [R/W] */ - entry = create_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE, - S_IFREG | S_IRUGO, - acpi_device_dir(device)); - if (entry){ - entry->proc_fops = &acpi_processor_perf_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } + proc_create_data(ACPI_PROCESSOR_FILE_PERFORMANCE, S_IFREG | S_IRUGO, + acpi_device_dir(device), + &acpi_processor_perf_fops, acpi_driver_data(device)); return; } diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index 649ae99b9216..ef34b18f95ca 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -509,6 +509,7 @@ static ssize_t acpi_processor_write_limit(struct file * file, } struct file_operations acpi_processor_limit_fops = { + .owner = THIS_MODULE, .open = acpi_processor_limit_open_fs, .read = seq_read, .write = acpi_processor_write_limit, diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 0bba3a914e86..bb06738860c4 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -1252,6 +1252,7 @@ static ssize_t acpi_processor_write_throttling(struct file *file, } struct file_operations acpi_processor_throttling_fops = { + .owner = THIS_MODULE, .open = acpi_processor_throttling_open_fs, .read = seq_read, .write = acpi_processor_write_throttling, diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index 585ae3c9c8ea..10a36512647c 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -483,8 +483,6 @@ acpi_sbs_add_fs(struct proc_dir_entry **dir, struct file_operations *state_fops, struct file_operations *alarm_fops, void *data) { - struct proc_dir_entry *entry = NULL; - if (!*dir) { *dir = proc_mkdir(dir_name, parent_dir); if (!*dir) { @@ -494,34 +492,19 @@ acpi_sbs_add_fs(struct proc_dir_entry **dir, } /* 'info' [R] */ - if (info_fops) { - entry = create_proc_entry(ACPI_SBS_FILE_INFO, S_IRUGO, *dir); - if (entry) { - entry->proc_fops = info_fops; - entry->data = data; - entry->owner = THIS_MODULE; - } - } + if (info_fops) + proc_create_data(ACPI_SBS_FILE_INFO, S_IRUGO, *dir, + info_fops, data); /* 'state' [R] */ - if (state_fops) { - entry = create_proc_entry(ACPI_SBS_FILE_STATE, S_IRUGO, *dir); - if (entry) { - entry->proc_fops = state_fops; - entry->data = data; - entry->owner = THIS_MODULE; - } - } + if (state_fops) + proc_create_data(ACPI_SBS_FILE_STATE, S_IRUGO, *dir, + state_fops, data); /* 'alarm' [R/W] */ - if (alarm_fops) { - entry = create_proc_entry(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir); - if (entry) { - entry->proc_fops = alarm_fops; - entry->data = data; - entry->owner = THIS_MODULE; - } - } + if (alarm_fops) + proc_create_data(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir, + alarm_fops, data); return 0; } diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c index f8df5217d477..8a5fe8710513 100644 --- a/drivers/acpi/sleep/proc.c +++ b/drivers/acpi/sleep/proc.c @@ -440,6 +440,7 @@ acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file) } static const struct file_operations acpi_system_wakeup_device_fops = { + .owner = THIS_MODULE, .open = acpi_system_wakeup_device_open_fs, .read = seq_read, .write = acpi_system_write_wakeup_device, @@ -449,6 +450,7 @@ static const struct file_operations acpi_system_wakeup_device_fops = { #ifdef CONFIG_ACPI_PROCFS static const struct file_operations acpi_system_sleep_fops = { + .owner = THIS_MODULE, .open = acpi_system_sleep_open_fs, .read = seq_read, .write = acpi_system_write_sleep, @@ -459,6 +461,7 @@ static const struct file_operations acpi_system_sleep_fops = { #ifdef HAVE_ACPI_LEGACY_ALARM static const struct file_operations acpi_system_alarm_fops = { + .owner = THIS_MODULE, .open = acpi_system_alarm_open_fs, .read = seq_read, .write = acpi_system_write_alarm, @@ -477,37 +480,26 @@ static u32 rtc_handler(void *context) static int __init acpi_sleep_proc_init(void) { - struct proc_dir_entry *entry = NULL; - if (acpi_disabled) return 0; #ifdef CONFIG_ACPI_PROCFS /* 'sleep' [R/W] */ - entry = - create_proc_entry("sleep", S_IFREG | S_IRUGO | S_IWUSR, - acpi_root_dir); - if (entry) - entry->proc_fops = &acpi_system_sleep_fops; + proc_create("sleep", S_IFREG | S_IRUGO | S_IWUSR, + acpi_root_dir, &acpi_system_sleep_fops); #endif /* CONFIG_ACPI_PROCFS */ #ifdef HAVE_ACPI_LEGACY_ALARM /* 'alarm' [R/W] */ - entry = - create_proc_entry("alarm", S_IFREG | S_IRUGO | S_IWUSR, - acpi_root_dir); - if (entry) - entry->proc_fops = &acpi_system_alarm_fops; + proc_create("alarm", S_IFREG | S_IRUGO | S_IWUSR, + acpi_root_dir, &acpi_system_alarm_fops); acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL); #endif /* HAVE_ACPI_LEGACY_ALARM */ /* 'wakeup device' [R/W] */ - entry = - create_proc_entry("wakeup", S_IFREG | S_IRUGO | S_IWUSR, - acpi_root_dir); - if (entry) - entry->proc_fops = &acpi_system_wakeup_device_fops; + proc_create("wakeup", S_IFREG | S_IRUGO | S_IWUSR, + acpi_root_dir, &acpi_system_wakeup_device_fops); return 0; } diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c index 4749f379a915..769f24855eb6 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c @@ -396,6 +396,7 @@ static int acpi_system_info_open_fs(struct inode *inode, struct file *file) } static const struct file_operations acpi_system_info_ops = { + .owner = THIS_MODULE, .open = acpi_system_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -406,6 +407,7 @@ static ssize_t acpi_system_read_dsdt(struct file *, char __user *, size_t, loff_t *); static const struct file_operations acpi_system_dsdt_ops = { + .owner = THIS_MODULE, .read = acpi_system_read_dsdt, }; @@ -430,6 +432,7 @@ static ssize_t acpi_system_read_fadt(struct file *, char __user *, size_t, loff_t *); static const struct file_operations acpi_system_fadt_ops = { + .owner = THIS_MODULE, .read = acpi_system_read_fadt, }; @@ -454,31 +457,23 @@ static int acpi_system_procfs_init(void) { struct proc_dir_entry *entry; int error = 0; - char *name; /* 'info' [R] */ - name = ACPI_SYSTEM_FILE_INFO; - entry = create_proc_entry(name, S_IRUGO, acpi_root_dir); + entry = proc_create(ACPI_SYSTEM_FILE_INFO, S_IRUGO, acpi_root_dir, + &acpi_system_info_ops); if (!entry) goto Error; - else { - entry->proc_fops = &acpi_system_info_ops; - } /* 'dsdt' [R] */ - name = ACPI_SYSTEM_FILE_DSDT; - entry = create_proc_entry(name, S_IRUSR, acpi_root_dir); - if (entry) - entry->proc_fops = &acpi_system_dsdt_ops; - else + entry = proc_create(ACPI_SYSTEM_FILE_DSDT, S_IRUSR, acpi_root_dir, + &acpi_system_dsdt_ops); + if (!entry) goto Error; /* 'fadt' [R] */ - name = ACPI_SYSTEM_FILE_FADT; - entry = create_proc_entry(name, S_IRUSR, acpi_root_dir); - if (entry) - entry->proc_fops = &acpi_system_fadt_ops; - else + entry = proc_create(ACPI_SYSTEM_FILE_FADT, S_IRUSR, acpi_root_dir, + &acpi_system_fadt_ops); + if (!entry) goto Error; Done: diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 766bd25d3376..0815ac3ae3d6 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -198,6 +198,7 @@ struct acpi_thermal { }; static const struct file_operations acpi_thermal_state_fops = { + .owner = THIS_MODULE, .open = acpi_thermal_state_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -205,6 +206,7 @@ static const struct file_operations acpi_thermal_state_fops = { }; static const struct file_operations acpi_thermal_temp_fops = { + .owner = THIS_MODULE, .open = acpi_thermal_temp_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -212,6 +214,7 @@ static const struct file_operations acpi_thermal_temp_fops = { }; static const struct file_operations acpi_thermal_trip_fops = { + .owner = THIS_MODULE, .open = acpi_thermal_trip_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -219,6 +222,7 @@ static const struct file_operations acpi_thermal_trip_fops = { }; static const struct file_operations acpi_thermal_cooling_fops = { + .owner = THIS_MODULE, .open = acpi_thermal_cooling_open_fs, .read = seq_read, .write = acpi_thermal_write_cooling_mode, @@ -227,6 +231,7 @@ static const struct file_operations acpi_thermal_cooling_fops = { }; static const struct file_operations acpi_thermal_polling_fops = { + .owner = THIS_MODULE, .open = acpi_thermal_polling_open_fs, .read = seq_read, .write = acpi_thermal_write_polling, @@ -1419,63 +1424,47 @@ static int acpi_thermal_add_fs(struct acpi_device *device) } /* 'state' [R] */ - entry = create_proc_entry(ACPI_THERMAL_FILE_STATE, - S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data(ACPI_THERMAL_FILE_STATE, + S_IRUGO, acpi_device_dir(device), + &acpi_thermal_state_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_thermal_state_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'temperature' [R] */ - entry = create_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE, - S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data(ACPI_THERMAL_FILE_TEMPERATURE, + S_IRUGO, acpi_device_dir(device), + &acpi_thermal_temp_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_thermal_temp_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'trip_points' [R] */ - entry = create_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS, - S_IRUGO, - acpi_device_dir(device)); + entry = proc_create_data(ACPI_THERMAL_FILE_TRIP_POINTS, + S_IRUGO, + acpi_device_dir(device), + &acpi_thermal_trip_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_thermal_trip_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'cooling_mode' [R/W] */ - entry = create_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE, - S_IFREG | S_IRUGO | S_IWUSR, - acpi_device_dir(device)); + entry = proc_create_data(ACPI_THERMAL_FILE_COOLING_MODE, + S_IFREG | S_IRUGO | S_IWUSR, + acpi_device_dir(device), + &acpi_thermal_cooling_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_thermal_cooling_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'polling_frequency' [R/W] */ - entry = create_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ, - S_IFREG | S_IRUGO | S_IWUSR, - acpi_device_dir(device)); + entry = proc_create_data(ACPI_THERMAL_FILE_POLLING_FREQ, + S_IFREG | S_IRUGO | S_IWUSR, + acpi_device_dir(device), + &acpi_thermal_polling_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_thermal_polling_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } - return 0; } diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 980a74188781..43b228314a86 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -192,6 +192,7 @@ struct acpi_video_device { /* bus */ static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_bus_info_fops = { + .owner = THIS_MODULE, .open = acpi_video_bus_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -200,6 +201,7 @@ static struct file_operations acpi_video_bus_info_fops = { static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_bus_ROM_fops = { + .owner = THIS_MODULE, .open = acpi_video_bus_ROM_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -209,6 +211,7 @@ static struct file_operations acpi_video_bus_ROM_fops = { static int acpi_video_bus_POST_info_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_bus_POST_info_fops = { + .owner = THIS_MODULE, .open = acpi_video_bus_POST_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -217,6 +220,7 @@ static struct file_operations acpi_video_bus_POST_info_fops = { static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_bus_POST_fops = { + .owner = THIS_MODULE, .open = acpi_video_bus_POST_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -225,6 +229,7 @@ static struct file_operations acpi_video_bus_POST_fops = { static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_bus_DOS_fops = { + .owner = THIS_MODULE, .open = acpi_video_bus_DOS_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -235,6 +240,7 @@ static struct file_operations acpi_video_bus_DOS_fops = { static int acpi_video_device_info_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_device_info_fops = { + .owner = THIS_MODULE, .open = acpi_video_device_info_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -244,6 +250,7 @@ static struct file_operations acpi_video_device_info_fops = { static int acpi_video_device_state_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_device_state_fops = { + .owner = THIS_MODULE, .open = acpi_video_device_state_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -253,6 +260,7 @@ static struct file_operations acpi_video_device_state_fops = { static int acpi_video_device_brightness_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_device_brightness_fops = { + .owner = THIS_MODULE, .open = acpi_video_device_brightness_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -262,6 +270,7 @@ static struct file_operations acpi_video_device_brightness_fops = { static int acpi_video_device_EDID_open_fs(struct inode *inode, struct file *file); static struct file_operations acpi_video_device_EDID_fops = { + .owner = THIS_MODULE, .open = acpi_video_device_EDID_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -1070,51 +1079,36 @@ static int acpi_video_device_add_fs(struct acpi_device *device) } /* 'info' [R] */ - entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data("info", S_IRUGO, acpi_device_dir(device), + &acpi_video_device_info_fops, acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_video_device_info_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'state' [R/W] */ - entry = - create_proc_entry("state", S_IFREG | S_IRUGO | S_IWUSR, - acpi_device_dir(device)); + acpi_video_device_state_fops.write = acpi_video_device_write_state; + entry = proc_create_data("state", S_IFREG | S_IRUGO | S_IWUSR, + acpi_device_dir(device), + &acpi_video_device_state_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - acpi_video_device_state_fops.write = acpi_video_device_write_state; - entry->proc_fops = &acpi_video_device_state_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'brightness' [R/W] */ - entry = - create_proc_entry("brightness", S_IFREG | S_IRUGO | S_IWUSR, - acpi_device_dir(device)); + acpi_video_device_brightness_fops.write = + acpi_video_device_write_brightness; + entry = proc_create_data("brightness", S_IFREG | S_IRUGO | S_IWUSR, + acpi_device_dir(device), + &acpi_video_device_brightness_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - acpi_video_device_brightness_fops.write = acpi_video_device_write_brightness; - entry->proc_fops = &acpi_video_device_brightness_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'EDID' [R] */ - entry = create_proc_entry("EDID", S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data("EDID", S_IRUGO, acpi_device_dir(device), + &acpi_video_device_EDID_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_video_device_EDID_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } - return 0; } @@ -1353,61 +1347,43 @@ static int acpi_video_bus_add_fs(struct acpi_device *device) } /* 'info' [R] */ - entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data("info", S_IRUGO, acpi_device_dir(device), + &acpi_video_bus_info_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_video_bus_info_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'ROM' [R] */ - entry = create_proc_entry("ROM", S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data("ROM", S_IRUGO, acpi_device_dir(device), + &acpi_video_bus_ROM_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_video_bus_ROM_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'POST_info' [R] */ - entry = - create_proc_entry("POST_info", S_IRUGO, acpi_device_dir(device)); + entry = proc_create_data("POST_info", S_IRUGO, acpi_device_dir(device), + &acpi_video_bus_POST_info_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - entry->proc_fops = &acpi_video_bus_POST_info_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'POST' [R/W] */ - entry = - create_proc_entry("POST", S_IFREG | S_IRUGO | S_IRUSR, - acpi_device_dir(device)); + acpi_video_bus_POST_fops.write = acpi_video_bus_write_POST; + entry = proc_create_data("POST", S_IFREG | S_IRUGO | S_IRUSR, + acpi_device_dir(device), + &acpi_video_bus_POST_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - acpi_video_bus_POST_fops.write = acpi_video_bus_write_POST; - entry->proc_fops = &acpi_video_bus_POST_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } /* 'DOS' [R/W] */ - entry = - create_proc_entry("DOS", S_IFREG | S_IRUGO | S_IRUSR, - acpi_device_dir(device)); + acpi_video_bus_DOS_fops.write = acpi_video_bus_write_DOS; + entry = proc_create_data("DOS", S_IFREG | S_IRUGO | S_IRUSR, + acpi_device_dir(device), + &acpi_video_bus_DOS_fops, + acpi_driver_data(device)); if (!entry) return -ENODEV; - else { - acpi_video_bus_DOS_fops.write = acpi_video_bus_write_DOS; - entry->proc_fops = &acpi_video_bus_DOS_fops; - entry->data = acpi_driver_data(device); - entry->owner = THIS_MODULE; - } return 0; } diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 292aa9a0f02f..1c11df9a5f32 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -566,11 +566,11 @@ config PATA_RADISYS If unsure, say N. -config PATA_RB500 - tristate "RouterBoard 500 PATA CompactFlash support" - depends on MIKROTIK_RB500 +config PATA_RB532 + tristate "RouterBoard 532 PATA CompactFlash support" + depends on MIKROTIK_RB532 help - This option enables support for the RouterBoard 500 + This option enables support for the RouterBoard 532 PATA CompactFlash controller. If unsure, say N. diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 1fbc2aa648b7..b693d829383a 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -55,7 +55,7 @@ obj-$(CONFIG_PATA_PDC2027X) += pata_pdc2027x.o obj-$(CONFIG_PATA_PDC_OLD) += pata_pdc202xx_old.o obj-$(CONFIG_PATA_QDI) += pata_qdi.o obj-$(CONFIG_PATA_RADISYS) += pata_radisys.o -obj-$(CONFIG_PATA_RB500) += pata_rb500_cf.o +obj-$(CONFIG_PATA_RB532) += pata_rb532_cf.o obj-$(CONFIG_PATA_RZ1000) += pata_rz1000.o obj-$(CONFIG_PATA_SC1200) += pata_sc1200.o obj-$(CONFIG_PATA_SERVERWORKS) += pata_serverworks.o diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 7c4f886f1f16..8cace9aa9c03 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -358,7 +358,7 @@ static const struct ata_port_info ahci_port_info[] = { /* board_ahci_sb600 */ { AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL | - AHCI_HFLAG_32BIT_ONLY | + AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255 | AHCI_HFLAG_NO_PMP), .flags = AHCI_FLAG_COMMON, .pio_mask = 0x1f, /* pio0-4 */ diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 51b7d2fad36a..3bc488538204 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3933,6 +3933,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { /* Devices which get the IVB wrong */ { "QUANTUM FIREBALLlct10 05", "A03.0900", ATA_HORKAGE_IVB, }, + /* Maybe we should just blacklist TSSTcorp... */ + { "TSSTcorp CDDVDW SH-S202H", "SB00", ATA_HORKAGE_IVB, }, + { "TSSTcorp CDDVDW SH-S202H", "SB01", ATA_HORKAGE_IVB, }, { "TSSTcorp CDDVDW SH-S202J", "SB00", ATA_HORKAGE_IVB, }, { "TSSTcorp CDDVDW SH-S202J", "SB01", ATA_HORKAGE_IVB, }, { "TSSTcorp CDDVDW SH-S202N", "SB00", ATA_HORKAGE_IVB, }, diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index a34f32442edf..3ce43920e459 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -49,7 +49,11 @@ #include "libata.h" -#define SECTOR_SIZE 512 +#define SECTOR_SIZE 512 +#define ATA_SCSI_RBUF_SIZE 4096 + +static DEFINE_SPINLOCK(ata_scsi_rbuf_lock); +static u8 ata_scsi_rbuf[ATA_SCSI_RBUF_SIZE]; typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc); @@ -179,6 +183,13 @@ DEVICE_ATTR(link_power_management_policy, S_IRUGO | S_IWUSR, ata_scsi_lpm_show, ata_scsi_lpm_put); EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy); +static void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq) +{ + cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; + + scsi_build_sense_buffer(0, cmd->sense_buffer, sk, asc, ascq); +} + static void ata_scsi_invalid_field(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) { @@ -1632,53 +1643,48 @@ defer: /** * ata_scsi_rbuf_get - Map response buffer. - * @cmd: SCSI command containing buffer to be mapped. - * @buf_out: Pointer to mapped area. + * @flags: unsigned long variable to store irq enable status + * @copy_in: copy in from user buffer * - * Maps buffer contained within SCSI command @cmd. + * Prepare buffer for simulated SCSI commands. * * LOCKING: - * spin_lock_irqsave(host lock) + * spin_lock_irqsave(ata_scsi_rbuf_lock) on success * * RETURNS: - * Length of response buffer. + * Pointer to response buffer. */ - -static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out) +static void *ata_scsi_rbuf_get(struct scsi_cmnd *cmd, bool copy_in, + unsigned long *flags) { - u8 *buf; - unsigned int buflen; - - struct scatterlist *sg = scsi_sglist(cmd); + spin_lock_irqsave(&ata_scsi_rbuf_lock, *flags); - if (sg) { - buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset; - buflen = sg->length; - } else { - buf = NULL; - buflen = 0; - } - - *buf_out = buf; - return buflen; + memset(ata_scsi_rbuf, 0, ATA_SCSI_RBUF_SIZE); + if (copy_in) + sg_copy_to_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), + ata_scsi_rbuf, ATA_SCSI_RBUF_SIZE); + return ata_scsi_rbuf; } /** * ata_scsi_rbuf_put - Unmap response buffer. * @cmd: SCSI command containing buffer to be unmapped. - * @buf: buffer to unmap + * @copy_out: copy out result + * @flags: @flags passed to ata_scsi_rbuf_get() * - * Unmaps response buffer contained within @cmd. + * Returns rbuf buffer. The result is copied to @cmd's buffer if + * @copy_back is true. * * LOCKING: - * spin_lock_irqsave(host lock) + * Unlocks ata_scsi_rbuf_lock. */ - -static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf) +static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, bool copy_out, + unsigned long *flags) { - struct scatterlist *sg = scsi_sglist(cmd); - if (sg) - kunmap_atomic(buf - sg->offset, KM_IRQ0); + if (copy_out) + sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), + ata_scsi_rbuf, ATA_SCSI_RBUF_SIZE); + spin_unlock_irqrestore(&ata_scsi_rbuf_lock, *flags); } /** @@ -1696,24 +1702,17 @@ static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf) * LOCKING: * spin_lock_irqsave(host lock) */ - -void ata_scsi_rbuf_fill(struct ata_scsi_args *args, - unsigned int (*actor) (struct ata_scsi_args *args, - u8 *rbuf, unsigned int buflen)) +static void ata_scsi_rbuf_fill(struct ata_scsi_args *args, + unsigned int (*actor)(struct ata_scsi_args *args, u8 *rbuf)) { u8 *rbuf; - unsigned int buflen, rc; + unsigned int rc; struct scsi_cmnd *cmd = args->cmd; unsigned long flags; - local_irq_save(flags); - - buflen = ata_scsi_rbuf_get(cmd, &rbuf); - memset(rbuf, 0, buflen); - rc = actor(args, rbuf, buflen); - ata_scsi_rbuf_put(cmd, rbuf); - - local_irq_restore(flags); + rbuf = ata_scsi_rbuf_get(cmd, false, &flags); + rc = actor(args, rbuf); + ata_scsi_rbuf_put(cmd, rc == 0, &flags); if (rc == 0) cmd->result = SAM_STAT_GOOD; @@ -1721,26 +1720,9 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args, } /** - * ATA_SCSI_RBUF_SET - helper to set values in SCSI response buffer - * @idx: byte index into SCSI response buffer - * @val: value to set - * - * To be used by SCSI command simulator functions. This macros - * expects two local variables, u8 *rbuf and unsigned int buflen, - * are in scope. - * - * LOCKING: - * None. - */ -#define ATA_SCSI_RBUF_SET(idx, val) do { \ - if ((idx) < buflen) rbuf[(idx)] = (u8)(val); \ - } while (0) - -/** * ata_scsiop_inq_std - Simulate INQUIRY command * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * Returns standard device identification data associated * with non-VPD INQUIRY command output. @@ -1748,10 +1730,17 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args, * LOCKING: * spin_lock_irqsave(host lock) */ - -unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf) { + const u8 versions[] = { + 0x60, /* SAM-3 (no version claimed) */ + + 0x03, + 0x20, /* SBC-2 (no version claimed) */ + + 0x02, + 0x60 /* SPC-3 (no version claimed) */ + }; u8 hdr[] = { TYPE_DISK, 0, @@ -1760,35 +1749,21 @@ unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, 95 - 4 }; + VPRINTK("ENTER\n"); + /* set scsi removeable (RMB) bit per ata bit */ if (ata_id_removeable(args->id)) hdr[1] |= (1 << 7); - VPRINTK("ENTER\n"); - memcpy(rbuf, hdr, sizeof(hdr)); + memcpy(&rbuf[8], "ATA ", 8); + ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16); + ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4); - if (buflen > 35) { - memcpy(&rbuf[8], "ATA ", 8); - ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16); - ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4); - if (rbuf[32] == 0 || rbuf[32] == ' ') - memcpy(&rbuf[32], "n/a ", 4); - } - - if (buflen > 63) { - const u8 versions[] = { - 0x60, /* SAM-3 (no version claimed) */ - - 0x03, - 0x20, /* SBC-2 (no version claimed) */ + if (rbuf[32] == 0 || rbuf[32] == ' ') + memcpy(&rbuf[32], "n/a ", 4); - 0x02, - 0x60 /* SPC-3 (no version claimed) */ - }; - - memcpy(rbuf + 59, versions, sizeof(versions)); - } + memcpy(rbuf + 59, versions, sizeof(versions)); return 0; } @@ -1797,27 +1772,22 @@ unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, * ata_scsiop_inq_00 - Simulate INQUIRY VPD page 0, list of pages * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * Returns list of inquiry VPD pages available. * * LOCKING: * spin_lock_irqsave(host lock) */ - -unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf) { const u8 pages[] = { 0x00, /* page 0x00, this page */ 0x80, /* page 0x80, unit serial no page */ 0x83 /* page 0x83, device ident page */ }; - rbuf[3] = sizeof(pages); /* number of supported VPD pages */ - - if (buflen > 6) - memcpy(rbuf + 4, pages, sizeof(pages)); + rbuf[3] = sizeof(pages); /* number of supported VPD pages */ + memcpy(rbuf + 4, pages, sizeof(pages)); return 0; } @@ -1825,16 +1795,13 @@ unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf, * ata_scsiop_inq_80 - Simulate INQUIRY VPD page 80, device serial number * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * Returns ATA device serial number. * * LOCKING: * spin_lock_irqsave(host lock) */ - -unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf) { const u8 hdr[] = { 0, @@ -1842,12 +1809,10 @@ unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf, 0, ATA_ID_SERNO_LEN, /* page len */ }; - memcpy(rbuf, hdr, sizeof(hdr)); - - if (buflen > (ATA_ID_SERNO_LEN + 4 - 1)) - ata_id_string(args->id, (unsigned char *) &rbuf[4], - ATA_ID_SERNO, ATA_ID_SERNO_LEN); + memcpy(rbuf, hdr, sizeof(hdr)); + ata_id_string(args->id, (unsigned char *) &rbuf[4], + ATA_ID_SERNO, ATA_ID_SERNO_LEN); return 0; } @@ -1855,7 +1820,6 @@ unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf, * ata_scsiop_inq_83 - Simulate INQUIRY VPD page 83, device identity * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * Yields two logical unit device identification designators: * - vendor specific ASCII containing the ATA serial number @@ -1865,41 +1829,37 @@ unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf, * LOCKING: * spin_lock_irqsave(host lock) */ - -unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf) { - int num; const int sat_model_serial_desc_len = 68; + int num; rbuf[1] = 0x83; /* this page code */ num = 4; - if (buflen > (ATA_ID_SERNO_LEN + num + 3)) { - /* piv=0, assoc=lu, code_set=ACSII, designator=vendor */ - rbuf[num + 0] = 2; - rbuf[num + 3] = ATA_ID_SERNO_LEN; - num += 4; - ata_id_string(args->id, (unsigned char *) rbuf + num, - ATA_ID_SERNO, ATA_ID_SERNO_LEN); - num += ATA_ID_SERNO_LEN; - } - if (buflen > (sat_model_serial_desc_len + num + 3)) { - /* SAT defined lu model and serial numbers descriptor */ - /* piv=0, assoc=lu, code_set=ACSII, designator=t10 vendor id */ - rbuf[num + 0] = 2; - rbuf[num + 1] = 1; - rbuf[num + 3] = sat_model_serial_desc_len; - num += 4; - memcpy(rbuf + num, "ATA ", 8); - num += 8; - ata_id_string(args->id, (unsigned char *) rbuf + num, - ATA_ID_PROD, ATA_ID_PROD_LEN); - num += ATA_ID_PROD_LEN; - ata_id_string(args->id, (unsigned char *) rbuf + num, - ATA_ID_SERNO, ATA_ID_SERNO_LEN); - num += ATA_ID_SERNO_LEN; - } + /* piv=0, assoc=lu, code_set=ACSII, designator=vendor */ + rbuf[num + 0] = 2; + rbuf[num + 3] = ATA_ID_SERNO_LEN; + num += 4; + ata_id_string(args->id, (unsigned char *) rbuf + num, + ATA_ID_SERNO, ATA_ID_SERNO_LEN); + num += ATA_ID_SERNO_LEN; + + /* SAT defined lu model and serial numbers descriptor */ + /* piv=0, assoc=lu, code_set=ACSII, designator=t10 vendor id */ + rbuf[num + 0] = 2; + rbuf[num + 1] = 1; + rbuf[num + 3] = sat_model_serial_desc_len; + num += 4; + memcpy(rbuf + num, "ATA ", 8); + num += 8; + ata_id_string(args->id, (unsigned char *) rbuf + num, ATA_ID_PROD, + ATA_ID_PROD_LEN); + num += ATA_ID_PROD_LEN; + ata_id_string(args->id, (unsigned char *) rbuf + num, ATA_ID_SERNO, + ATA_ID_SERNO_LEN); + num += ATA_ID_SERNO_LEN; + rbuf[3] = num - 4; /* page len (assume less than 256 bytes) */ return 0; } @@ -1908,35 +1868,26 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf, * ata_scsiop_inq_89 - Simulate INQUIRY VPD page 89, ATA info * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * Yields SAT-specified ATA VPD page. * * LOCKING: * spin_lock_irqsave(host lock) */ - -static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf) { - u8 pbuf[60]; struct ata_taskfile tf; - unsigned int i; - if (!buflen) - return 0; - - memset(&pbuf, 0, sizeof(pbuf)); memset(&tf, 0, sizeof(tf)); - pbuf[1] = 0x89; /* our page code */ - pbuf[2] = (0x238 >> 8); /* page size fixed at 238h */ - pbuf[3] = (0x238 & 0xff); + rbuf[1] = 0x89; /* our page code */ + rbuf[2] = (0x238 >> 8); /* page size fixed at 238h */ + rbuf[3] = (0x238 & 0xff); - memcpy(&pbuf[8], "linux ", 8); - memcpy(&pbuf[16], "libata ", 16); - memcpy(&pbuf[32], DRV_VERSION, 4); - ata_id_string(args->id, &pbuf[32], ATA_ID_FW_REV, 4); + memcpy(&rbuf[8], "linux ", 8); + memcpy(&rbuf[16], "libata ", 16); + memcpy(&rbuf[32], DRV_VERSION, 4); + ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4); /* we don't store the ATA device signature, so we fake it */ @@ -1944,19 +1895,12 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf, tf.lbal = 0x1; tf.nsect = 0x1; - ata_tf_to_fis(&tf, 0, 1, &pbuf[36]); /* TODO: PMP? */ - pbuf[36] = 0x34; /* force D2H Reg FIS (34h) */ + ata_tf_to_fis(&tf, 0, 1, &rbuf[36]); /* TODO: PMP? */ + rbuf[36] = 0x34; /* force D2H Reg FIS (34h) */ - pbuf[56] = ATA_CMD_ID_ATA; + rbuf[56] = ATA_CMD_ID_ATA; - i = min(buflen, 60U); - memcpy(rbuf, &pbuf[0], i); - buflen -= i; - - if (!buflen) - return 0; - - memcpy(&rbuf[60], &args->id[0], min(buflen, 512U)); + memcpy(&rbuf[60], &args->id[0], 512); return 0; } @@ -1964,7 +1908,6 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf, * ata_scsiop_noop - Command handler that simply returns success. * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * No operation. Simply returns success to caller, to indicate * that the caller should successfully complete this SCSI command. @@ -1972,47 +1915,16 @@ static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf, * LOCKING: * spin_lock_irqsave(host lock) */ - -unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf) { VPRINTK("ENTER\n"); return 0; } /** - * ata_msense_push - Push data onto MODE SENSE data output buffer - * @ptr_io: (input/output) Location to store more output data - * @last: End of output data buffer - * @buf: Pointer to BLOB being added to output buffer - * @buflen: Length of BLOB - * - * Store MODE SENSE data on an output buffer. - * - * LOCKING: - * None. - */ - -static void ata_msense_push(u8 **ptr_io, const u8 *last, - const u8 *buf, unsigned int buflen) -{ - u8 *ptr = *ptr_io; - - if ((ptr + buflen - 1) > last) - return; - - memcpy(ptr, buf, buflen); - - ptr += buflen; - - *ptr_io = ptr; -} - -/** * ata_msense_caching - Simulate MODE SENSE caching info page * @id: device IDENTIFY data - * @ptr_io: (input/output) Location to store more output data - * @last: End of output data buffer + * @buf: output buffer * * Generate a caching info page, which conditionally indicates * write caching to the SCSI layer, depending on device @@ -2021,58 +1933,43 @@ static void ata_msense_push(u8 **ptr_io, const u8 *last, * LOCKING: * None. */ - -static unsigned int ata_msense_caching(u16 *id, u8 **ptr_io, - const u8 *last) +static unsigned int ata_msense_caching(u16 *id, u8 *buf) { - u8 page[CACHE_MPAGE_LEN]; - - memcpy(page, def_cache_mpage, sizeof(page)); + memcpy(buf, def_cache_mpage, sizeof(def_cache_mpage)); if (ata_id_wcache_enabled(id)) - page[2] |= (1 << 2); /* write cache enable */ + buf[2] |= (1 << 2); /* write cache enable */ if (!ata_id_rahead_enabled(id)) - page[12] |= (1 << 5); /* disable read ahead */ - - ata_msense_push(ptr_io, last, page, sizeof(page)); - return sizeof(page); + buf[12] |= (1 << 5); /* disable read ahead */ + return sizeof(def_cache_mpage); } /** * ata_msense_ctl_mode - Simulate MODE SENSE control mode page - * @dev: Device associated with this MODE SENSE command - * @ptr_io: (input/output) Location to store more output data - * @last: End of output data buffer + * @buf: output buffer * * Generate a generic MODE SENSE control mode page. * * LOCKING: * None. */ - -static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last) +static unsigned int ata_msense_ctl_mode(u8 *buf) { - ata_msense_push(ptr_io, last, def_control_mpage, - sizeof(def_control_mpage)); + memcpy(buf, def_control_mpage, sizeof(def_control_mpage)); return sizeof(def_control_mpage); } /** * ata_msense_rw_recovery - Simulate MODE SENSE r/w error recovery page - * @dev: Device associated with this MODE SENSE command - * @ptr_io: (input/output) Location to store more output data - * @last: End of output data buffer + * @bufp: output buffer * * Generate a generic MODE SENSE r/w error recovery page. * * LOCKING: * None. */ - -static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last) +static unsigned int ata_msense_rw_recovery(u8 *buf) { - - ata_msense_push(ptr_io, last, def_rw_recovery_mpage, - sizeof(def_rw_recovery_mpage)); + memcpy(buf, def_rw_recovery_mpage, sizeof(def_rw_recovery_mpage)); return sizeof(def_rw_recovery_mpage); } @@ -2104,7 +2001,6 @@ static int ata_dev_supports_fua(u16 *id) * ata_scsiop_mode_sense - Simulate MODE SENSE 6, 10 commands * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * Simulate MODE SENSE commands. Assume this is invoked for direct * access devices (e.g. disks) only. There should be no block @@ -2113,19 +2009,17 @@ static int ata_dev_supports_fua(u16 *id) * LOCKING: * spin_lock_irqsave(host lock) */ - -unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf) { struct ata_device *dev = args->dev; - u8 *scsicmd = args->cmd->cmnd, *p, *last; + u8 *scsicmd = args->cmd->cmnd, *p = rbuf; const u8 sat_blk_desc[] = { 0, 0, 0, 0, /* number of blocks: sat unspecified */ 0, 0, 0x2, 0x0 /* block length: 512 bytes */ }; u8 pg, spg; - unsigned int ebd, page_control, six_byte, output_len, alloc_len, minlen; + unsigned int ebd, page_control, six_byte; u8 dpofua; VPRINTK("ENTER\n"); @@ -2148,17 +2042,10 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, goto invalid_fld; } - if (six_byte) { - output_len = 4 + (ebd ? 8 : 0); - alloc_len = scsicmd[4]; - } else { - output_len = 8 + (ebd ? 8 : 0); - alloc_len = (scsicmd[7] << 8) + scsicmd[8]; - } - minlen = (alloc_len < buflen) ? alloc_len : buflen; - - p = rbuf + output_len; - last = rbuf + minlen - 1; + if (six_byte) + p += 4 + (ebd ? 8 : 0); + else + p += 8 + (ebd ? 8 : 0); pg = scsicmd[2] & 0x3f; spg = scsicmd[3]; @@ -2171,61 +2058,48 @@ unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, switch(pg) { case RW_RECOVERY_MPAGE: - output_len += ata_msense_rw_recovery(&p, last); + p += ata_msense_rw_recovery(p); break; case CACHE_MPAGE: - output_len += ata_msense_caching(args->id, &p, last); + p += ata_msense_caching(args->id, p); break; - case CONTROL_MPAGE: { - output_len += ata_msense_ctl_mode(&p, last); + case CONTROL_MPAGE: + p += ata_msense_ctl_mode(p); break; - } case ALL_MPAGES: - output_len += ata_msense_rw_recovery(&p, last); - output_len += ata_msense_caching(args->id, &p, last); - output_len += ata_msense_ctl_mode(&p, last); + p += ata_msense_rw_recovery(p); + p += ata_msense_caching(args->id, p); + p += ata_msense_ctl_mode(p); break; default: /* invalid page code */ goto invalid_fld; } - if (minlen < 1) - return 0; - dpofua = 0; if (ata_dev_supports_fua(args->id) && (dev->flags & ATA_DFLAG_LBA48) && (!(dev->flags & ATA_DFLAG_PIO) || dev->multi_count)) dpofua = 1 << 4; if (six_byte) { - output_len--; - rbuf[0] = output_len; - if (minlen > 2) - rbuf[2] |= dpofua; + rbuf[0] = p - rbuf - 1; + rbuf[2] |= dpofua; if (ebd) { - if (minlen > 3) - rbuf[3] = sizeof(sat_blk_desc); - if (minlen > 11) - memcpy(rbuf + 4, sat_blk_desc, - sizeof(sat_blk_desc)); + rbuf[3] = sizeof(sat_blk_desc); + memcpy(rbuf + 4, sat_blk_desc, sizeof(sat_blk_desc)); } } else { - output_len -= 2; + unsigned int output_len = p - rbuf - 2; + rbuf[0] = output_len >> 8; - if (minlen > 1) - rbuf[1] = output_len; - if (minlen > 3) - rbuf[3] |= dpofua; + rbuf[1] = output_len; + rbuf[3] |= dpofua; if (ebd) { - if (minlen > 7) - rbuf[7] = sizeof(sat_blk_desc); - if (minlen > 15) - memcpy(rbuf + 8, sat_blk_desc, - sizeof(sat_blk_desc)); + rbuf[7] = sizeof(sat_blk_desc); + memcpy(rbuf + 8, sat_blk_desc, sizeof(sat_blk_desc)); } } return 0; @@ -2245,15 +2119,13 @@ saving_not_supp: * ata_scsiop_read_cap - Simulate READ CAPACITY[ 16] commands * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * Simulate READ CAPACITY commands. * * LOCKING: * None. */ -unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf) { u64 last_lba = args->dev->n_sectors - 1; /* LBA of the last block */ @@ -2264,28 +2136,28 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, last_lba = 0xffffffff; /* sector count, 32-bit */ - ATA_SCSI_RBUF_SET(0, last_lba >> (8 * 3)); - ATA_SCSI_RBUF_SET(1, last_lba >> (8 * 2)); - ATA_SCSI_RBUF_SET(2, last_lba >> (8 * 1)); - ATA_SCSI_RBUF_SET(3, last_lba); + rbuf[0] = last_lba >> (8 * 3); + rbuf[1] = last_lba >> (8 * 2); + rbuf[2] = last_lba >> (8 * 1); + rbuf[3] = last_lba; /* sector size */ - ATA_SCSI_RBUF_SET(6, ATA_SECT_SIZE >> 8); - ATA_SCSI_RBUF_SET(7, ATA_SECT_SIZE & 0xff); + rbuf[6] = ATA_SECT_SIZE >> 8; + rbuf[7] = ATA_SECT_SIZE & 0xff; } else { /* sector count, 64-bit */ - ATA_SCSI_RBUF_SET(0, last_lba >> (8 * 7)); - ATA_SCSI_RBUF_SET(1, last_lba >> (8 * 6)); - ATA_SCSI_RBUF_SET(2, last_lba >> (8 * 5)); - ATA_SCSI_RBUF_SET(3, last_lba >> (8 * 4)); - ATA_SCSI_RBUF_SET(4, last_lba >> (8 * 3)); - ATA_SCSI_RBUF_SET(5, last_lba >> (8 * 2)); - ATA_SCSI_RBUF_SET(6, last_lba >> (8 * 1)); - ATA_SCSI_RBUF_SET(7, last_lba); + rbuf[0] = last_lba >> (8 * 7); + rbuf[1] = last_lba >> (8 * 6); + rbuf[2] = last_lba >> (8 * 5); + rbuf[3] = last_lba >> (8 * 4); + rbuf[4] = last_lba >> (8 * 3); + rbuf[5] = last_lba >> (8 * 2); + rbuf[6] = last_lba >> (8 * 1); + rbuf[7] = last_lba; /* sector size */ - ATA_SCSI_RBUF_SET(10, ATA_SECT_SIZE >> 8); - ATA_SCSI_RBUF_SET(11, ATA_SECT_SIZE & 0xff); + rbuf[10] = ATA_SECT_SIZE >> 8; + rbuf[11] = ATA_SECT_SIZE & 0xff; } return 0; @@ -2295,16 +2167,13 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, * ata_scsiop_report_luns - Simulate REPORT LUNS command * @args: device IDENTIFY data / SCSI command of interest. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. - * @buflen: Response buffer length. * * Simulate REPORT LUNS command. * * LOCKING: * spin_lock_irqsave(host lock) */ - -unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen) +static unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf) { VPRINTK("ENTER\n"); rbuf[3] = 8; /* just one lun, LUN 0, size 8 bytes */ @@ -2312,53 +2181,6 @@ unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf, return 0; } -/** - * ata_scsi_set_sense - Set SCSI sense data and status - * @cmd: SCSI request to be handled - * @sk: SCSI-defined sense key - * @asc: SCSI-defined additional sense code - * @ascq: SCSI-defined additional sense code qualifier - * - * Helper function that builds a valid fixed format, current - * response code and the given sense key (sk), additional sense - * code (asc) and additional sense code qualifier (ascq) with - * a SCSI command status of %SAM_STAT_CHECK_CONDITION and - * DRIVER_SENSE set in the upper bits of scsi_cmnd::result . - * - * LOCKING: - * Not required - */ - -void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq) -{ - cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; - - scsi_build_sense_buffer(0, cmd->sense_buffer, sk, asc, ascq); -} - -/** - * ata_scsi_badcmd - End a SCSI request with an error - * @cmd: SCSI request to be handled - * @done: SCSI command completion function - * @asc: SCSI-defined additional sense code - * @ascq: SCSI-defined additional sense code qualifier - * - * Helper function that completes a SCSI command with - * %SAM_STAT_CHECK_CONDITION, with a sense key %ILLEGAL_REQUEST - * and the specified additional sense codes. - * - * LOCKING: - * spin_lock_irqsave(host lock) - */ - -void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq) -{ - DPRINTK("ENTER\n"); - ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, asc, ascq); - - done(cmd); -} - static void atapi_sense_complete(struct ata_queued_cmd *qc) { if (qc->err_mask && ((qc->err_mask & AC_ERR_DEV) == 0)) { @@ -2485,13 +2307,10 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc) u8 *scsicmd = cmd->cmnd; if ((scsicmd[0] == INQUIRY) && ((scsicmd[1] & 0x03) == 0)) { - u8 *buf = NULL; - unsigned int buflen; unsigned long flags; + u8 *buf; - local_irq_save(flags); - - buflen = ata_scsi_rbuf_get(cmd, &buf); + buf = ata_scsi_rbuf_get(cmd, true, &flags); /* ATAPI devices typically report zero for their SCSI version, * and sometimes deviate from the spec WRT response data @@ -2506,9 +2325,7 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc) buf[3] = 0x32; } - ata_scsi_rbuf_put(cmd, buf); - - local_irq_restore(flags); + ata_scsi_rbuf_put(cmd, true, &flags); } cmd->result = SAM_STAT_GOOD; diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index ae2cfd95d43e..4514283937ea 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -146,34 +146,6 @@ extern void ata_scsi_scan_host(struct ata_port *ap, int sync); extern int ata_scsi_offline_dev(struct ata_device *dev); extern void ata_scsi_media_change_notify(struct ata_device *dev); extern void ata_scsi_hotplug(struct work_struct *work); -extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); - -extern unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); - -extern unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); -extern unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); -extern unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); -extern unsigned int ata_scsiop_sync_cache(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); -extern unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); -extern unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); -extern unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf, - unsigned int buflen); -extern void ata_scsi_badcmd(struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *), - u8 asc, u8 ascq); -extern void ata_scsi_set_sense(struct scsi_cmnd *cmd, - u8 sk, u8 asc, u8 ascq); -extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, - unsigned int (*actor) (struct ata_scsi_args *args, - u8 *rbuf, unsigned int buflen)); extern void ata_schedule_scsi_eh(struct Scsi_Host *shost); extern void ata_scsi_dev_rescan(struct work_struct *work); extern int ata_bus_probe(struct ata_port *ap); diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c index 78738fb4223b..d7de7baf58a8 100644 --- a/drivers/ata/pata_atiixp.c +++ b/drivers/ata/pata_atiixp.c @@ -88,8 +88,8 @@ static void atiixp_set_pio_timing(struct ata_port *ap, struct ata_device *adev, pci_write_config_word(pdev, ATIIXP_IDE_PIO_MODE, pio_mode_data); pci_read_config_word(pdev, ATIIXP_IDE_PIO_TIMING, &pio_timing_data); - pio_mode_data &= ~(0xFF << timing_shift); - pio_mode_data |= (pio_timings[pio] << timing_shift); + pio_timing_data &= ~(0xFF << timing_shift); + pio_timing_data |= (pio_timings[pio] << timing_shift); pci_write_config_word(pdev, ATIIXP_IDE_PIO_TIMING, pio_timing_data); } diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c index a75de0684c15..9ab89732cf94 100644 --- a/drivers/ata/pata_bf54x.c +++ b/drivers/ata/pata_bf54x.c @@ -1272,8 +1272,8 @@ static void bfin_freeze(struct ata_port *ap) void bfin_thaw(struct ata_port *ap) { + dev_dbg(ap->dev, "in atapi dma thaw\n"); bfin_check_status(ap); - bfin_irq_clear(ap); bfin_irq_on(ap); } @@ -1339,13 +1339,130 @@ static int bfin_port_start(struct ata_port *ap) return 0; } +static unsigned int bfin_ata_host_intr(struct ata_port *ap, + struct ata_queued_cmd *qc) +{ + struct ata_eh_info *ehi = &ap->link.eh_info; + u8 status, host_stat = 0; + + VPRINTK("ata%u: protocol %d task_state %d\n", + ap->print_id, qc->tf.protocol, ap->hsm_task_state); + + /* Check whether we are expecting interrupt in this state */ + switch (ap->hsm_task_state) { + case HSM_ST_FIRST: + /* Some pre-ATAPI-4 devices assert INTRQ + * at this state when ready to receive CDB. + */ + + /* Check the ATA_DFLAG_CDB_INTR flag is enough here. + * The flag was turned on only for atapi devices. + * No need to check is_atapi_taskfile(&qc->tf) again. + */ + if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) + goto idle_irq; + break; + case HSM_ST_LAST: + if (qc->tf.protocol == ATA_PROT_DMA || + qc->tf.protocol == ATAPI_PROT_DMA) { + /* check status of DMA engine */ + host_stat = ap->ops->bmdma_status(ap); + VPRINTK("ata%u: host_stat 0x%X\n", + ap->print_id, host_stat); + + /* if it's not our irq... */ + if (!(host_stat & ATA_DMA_INTR)) + goto idle_irq; + + /* before we do anything else, clear DMA-Start bit */ + ap->ops->bmdma_stop(qc); + + if (unlikely(host_stat & ATA_DMA_ERR)) { + /* error when transfering data to/from memory */ + qc->err_mask |= AC_ERR_HOST_BUS; + ap->hsm_task_state = HSM_ST_ERR; + } + } + break; + case HSM_ST: + break; + default: + goto idle_irq; + } + + /* check altstatus */ + status = ap->ops->sff_check_altstatus(ap); + if (status & ATA_BUSY) + goto busy_ata; + + /* check main status, clearing INTRQ */ + status = ap->ops->sff_check_status(ap); + if (unlikely(status & ATA_BUSY)) + goto busy_ata; + + /* ack bmdma irq events */ + ap->ops->sff_irq_clear(ap); + + ata_sff_hsm_move(ap, qc, status, 0); + + if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA || + qc->tf.protocol == ATAPI_PROT_DMA)) + ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat); + +busy_ata: + return 1; /* irq handled */ + +idle_irq: + ap->stats.idle_irq++; + +#ifdef ATA_IRQ_TRAP + if ((ap->stats.idle_irq % 1000) == 0) { + ap->ops->irq_ack(ap, 0); /* debug trap */ + ata_port_printk(ap, KERN_WARNING, "irq trap\n"); + return 1; + } +#endif + return 0; /* irq not handled */ +} + +static irqreturn_t bfin_ata_interrupt(int irq, void *dev_instance) +{ + struct ata_host *host = dev_instance; + unsigned int i; + unsigned int handled = 0; + unsigned long flags; + + /* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */ + spin_lock_irqsave(&host->lock, flags); + + for (i = 0; i < host->n_ports; i++) { + struct ata_port *ap; + + ap = host->ports[i]; + if (ap && + !(ap->flags & ATA_FLAG_DISABLED)) { + struct ata_queued_cmd *qc; + + qc = ata_qc_from_tag(ap, ap->link.active_tag); + if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) && + (qc->flags & ATA_QCFLAG_ACTIVE)) + handled |= bfin_ata_host_intr(ap, qc); + } + } + + spin_unlock_irqrestore(&host->lock, flags); + + return IRQ_RETVAL(handled); +} + + static struct scsi_host_template bfin_sht = { ATA_BASE_SHT(DRV_NAME), .sg_tablesize = SG_NONE, .dma_boundary = ATA_DMA_BOUNDARY, }; -static const struct ata_port_operations bfin_pata_ops = { +static struct ata_port_operations bfin_pata_ops = { .inherits = &ata_sff_port_ops, .set_piomode = bfin_set_piomode, @@ -1370,7 +1487,6 @@ static const struct ata_port_operations bfin_pata_ops = { .thaw = bfin_thaw, .softreset = bfin_softreset, .postreset = bfin_postreset, - .post_internal_cmd = bfin_bmdma_stop, .sff_irq_clear = bfin_irq_clear, .sff_irq_on = bfin_irq_on, @@ -1507,7 +1623,7 @@ static int __devinit bfin_atapi_probe(struct platform_device *pdev) } if (ata_host_activate(host, platform_get_irq(pdev, 0), - ata_sff_interrupt, IRQF_SHARED, &bfin_sht) != 0) { + bfin_ata_interrupt, IRQF_SHARED, &bfin_sht) != 0) { peripheral_free_list(atapi_io_port); dev_err(&pdev->dev, "Fail to attach ATAPI device\n"); return -ENODEV; diff --git a/drivers/ata/pata_rb500_cf.c b/drivers/ata/pata_rb532_cf.c index 4345174aaeec..a108d259f19d 100644 --- a/drivers/ata/pata_rb500_cf.c +++ b/drivers/ata/pata_rb532_cf.c @@ -32,7 +32,7 @@ #include <asm/gpio.h> -#define DRV_NAME "pata-rb500-cf" +#define DRV_NAME "pata-rb532-cf" #define DRV_VERSION "0.1.0" #define DRV_DESC "PATA driver for RouterBOARD 532 Compact Flash" @@ -43,7 +43,7 @@ #define RB500_CF_REG_CTRL 0x080E #define RB500_CF_REG_DATA 0x0C00 -struct rb500_cf_info { +struct rb532_cf_info { void __iomem *iobase; unsigned int gpio_line; int frozen; @@ -52,10 +52,10 @@ struct rb500_cf_info { /* ------------------------------------------------------------------------ */ -static inline void rb500_pata_finish_io(struct ata_port *ap) +static inline void rb532_pata_finish_io(struct ata_port *ap) { struct ata_host *ah = ap->host; - struct rb500_cf_info *info = ah->private_data; + struct rb532_cf_info *info = ah->private_data; ata_sff_altstatus(ap); ndelay(RB500_CF_IO_DELAY); @@ -63,14 +63,14 @@ static inline void rb500_pata_finish_io(struct ata_port *ap) set_irq_type(info->irq, IRQ_TYPE_LEVEL_HIGH); } -static void rb500_pata_exec_command(struct ata_port *ap, +static void rb532_pata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) { writeb(tf->command, ap->ioaddr.command_addr); - rb500_pata_finish_io(ap); + rb532_pata_finish_io(ap); } -static void rb500_pata_data_xfer(struct ata_device *adev, unsigned char *buf, +static void rb532_pata_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data) { struct ata_port *ap = adev->link->ap; @@ -84,27 +84,27 @@ static void rb500_pata_data_xfer(struct ata_device *adev, unsigned char *buf, *buf = readb(ioaddr); } - rb500_pata_finish_io(adev->link->ap); + rb532_pata_finish_io(adev->link->ap); } -static void rb500_pata_freeze(struct ata_port *ap) +static void rb532_pata_freeze(struct ata_port *ap) { - struct rb500_cf_info *info = ap->host->private_data; + struct rb532_cf_info *info = ap->host->private_data; info->frozen = 1; } -static void rb500_pata_thaw(struct ata_port *ap) +static void rb532_pata_thaw(struct ata_port *ap) { - struct rb500_cf_info *info = ap->host->private_data; + struct rb532_cf_info *info = ap->host->private_data; info->frozen = 0; } -static irqreturn_t rb500_pata_irq_handler(int irq, void *dev_instance) +static irqreturn_t rb532_pata_irq_handler(int irq, void *dev_instance) { struct ata_host *ah = dev_instance; - struct rb500_cf_info *info = ah->private_data; + struct rb532_cf_info *info = ah->private_data; if (gpio_get_value(info->gpio_line)) { set_irq_type(info->irq, IRQ_TYPE_LEVEL_LOW); @@ -117,30 +117,30 @@ static irqreturn_t rb500_pata_irq_handler(int irq, void *dev_instance) return IRQ_HANDLED; } -static struct ata_port_operations rb500_pata_port_ops = { +static struct ata_port_operations rb532_pata_port_ops = { .inherits = &ata_sff_port_ops, - .sff_exec_command = rb500_pata_exec_command, - .sff_data_xfer = rb500_pata_data_xfer, - .freeze = rb500_pata_freeze, - .thaw = rb500_pata_thaw, + .sff_exec_command = rb532_pata_exec_command, + .sff_data_xfer = rb532_pata_data_xfer, + .freeze = rb532_pata_freeze, + .thaw = rb532_pata_thaw, }; /* ------------------------------------------------------------------------ */ -static struct scsi_host_template rb500_pata_sht = { +static struct scsi_host_template rb532_pata_sht = { ATA_PIO_SHT(DRV_NAME), }; /* ------------------------------------------------------------------------ */ -static void rb500_pata_setup_ports(struct ata_host *ah) +static void rb532_pata_setup_ports(struct ata_host *ah) { - struct rb500_cf_info *info = ah->private_data; + struct rb532_cf_info *info = ah->private_data; struct ata_port *ap; ap = ah->ports[0]; - ap->ops = &rb500_pata_port_ops; + ap->ops = &rb532_pata_port_ops; ap->pio_mask = 0x1f; /* PIO4 */ ap->flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO; @@ -153,13 +153,13 @@ static void rb500_pata_setup_ports(struct ata_host *ah) ap->ioaddr.data_addr = info->iobase + RB500_CF_REG_DATA; } -static __devinit int rb500_pata_driver_probe(struct platform_device *pdev) +static __devinit int rb532_pata_driver_probe(struct platform_device *pdev) { unsigned int irq; int gpio; struct resource *res; struct ata_host *ah; - struct rb500_cf_info *info; + struct rb532_cf_info *info; int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -213,10 +213,10 @@ static __devinit int rb500_pata_driver_probe(struct platform_device *pdev) goto err_free_gpio; } - rb500_pata_setup_ports(ah); + rb532_pata_setup_ports(ah); - ret = ata_host_activate(ah, irq, rb500_pata_irq_handler, - IRQF_TRIGGER_LOW, &rb500_pata_sht); + ret = ata_host_activate(ah, irq, rb532_pata_irq_handler, + IRQF_TRIGGER_LOW, &rb532_pata_sht); if (ret) goto err_free_gpio; @@ -228,10 +228,10 @@ err_free_gpio: return ret; } -static __devexit int rb500_pata_driver_remove(struct platform_device *pdev) +static __devexit int rb532_pata_driver_remove(struct platform_device *pdev) { struct ata_host *ah = platform_get_drvdata(pdev); - struct rb500_cf_info *info = ah->private_data; + struct rb532_cf_info *info = ah->private_data; ata_host_detach(ah); gpio_free(info->gpio_line); @@ -242,9 +242,9 @@ static __devexit int rb500_pata_driver_remove(struct platform_device *pdev) /* work with hotplug and coldplug */ MODULE_ALIAS("platform:" DRV_NAME); -static struct platform_driver rb500_pata_platform_driver = { - .probe = rb500_pata_driver_probe, - .remove = __devexit_p(rb500_pata_driver_remove), +static struct platform_driver rb532_pata_platform_driver = { + .probe = rb532_pata_driver_probe, + .remove = __devexit_p(rb532_pata_driver_remove), .driver = { .name = DRV_NAME, .owner = THIS_MODULE, @@ -255,16 +255,16 @@ static struct platform_driver rb500_pata_platform_driver = { #define DRV_INFO DRV_DESC " version " DRV_VERSION -static int __init rb500_pata_module_init(void) +static int __init rb532_pata_module_init(void) { printk(KERN_INFO DRV_INFO "\n"); - return platform_driver_register(&rb500_pata_platform_driver); + return platform_driver_register(&rb532_pata_platform_driver); } -static void __exit rb500_pata_module_exit(void) +static void __exit rb532_pata_module_exit(void) { - platform_driver_unregister(&rb500_pata_platform_driver); + platform_driver_unregister(&rb532_pata_platform_driver); } MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>"); @@ -273,5 +273,5 @@ MODULE_DESCRIPTION(DRV_DESC); MODULE_VERSION(DRV_VERSION); MODULE_LICENSE("GPL"); -module_init(rb500_pata_module_init); -module_exit(rb500_pata_module_exit); +module_init(rb532_pata_module_init); +module_exit(rb532_pata_module_exit); diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index d4840748fb5c..2fea6cbe7755 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -464,11 +464,12 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id) } pci_dev_put(isa); - /* 0x40 low bits indicate enabled channels */ - pci_read_config_byte(pdev, 0x40 , &enable); - enable &= 3; - if (enable == 0) { - return -ENODEV; + if (!(config->flags & VIA_NO_ENABLES)) { + /* 0x40 low bits indicate enabled channels */ + pci_read_config_byte(pdev, 0x40 , &enable); + enable &= 3; + if (enable == 0) + return -ENODEV; } /* Initialise the FIFO for the enabled channels. */ diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 26a6337195b3..842b1a15b78c 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -172,10 +172,11 @@ enum { PCIE_IRQ_MASK_OFS = 0x1910, PCIE_UNMASK_ALL_IRQS = 0x40a, /* assorted bits */ - HC_MAIN_IRQ_CAUSE_OFS = 0x1d60, - HC_MAIN_IRQ_MASK_OFS = 0x1d64, - HC_SOC_MAIN_IRQ_CAUSE_OFS = 0x20020, - HC_SOC_MAIN_IRQ_MASK_OFS = 0x20024, + /* Host Controller Main Interrupt Cause/Mask registers (1 per-chip) */ + PCI_HC_MAIN_IRQ_CAUSE_OFS = 0x1d60, + PCI_HC_MAIN_IRQ_MASK_OFS = 0x1d64, + SOC_HC_MAIN_IRQ_CAUSE_OFS = 0x20020, + SOC_HC_MAIN_IRQ_MASK_OFS = 0x20024, ERR_IRQ = (1 << 0), /* shift by port # */ DONE_IRQ = (1 << 1), /* shift by port # */ HC0_IRQ_PEND = 0x1ff, /* bits 0-8 = HC0's ports */ @@ -445,8 +446,8 @@ struct mv_host_priv { const struct mv_hw_ops *ops; int n_ports; void __iomem *base; - void __iomem *main_cause_reg_addr; - void __iomem *main_mask_reg_addr; + void __iomem *main_irq_cause_addr; + void __iomem *main_irq_mask_addr; u32 irq_cause_ofs; u32 irq_mask_ofs; u32 unmask_all_irqs; @@ -727,8 +728,8 @@ static inline unsigned int mv_hardport_from_port(unsigned int port) * Simple code, with two return values, so macro rather than inline. * * port is the sole input, in range 0..7. - * shift is one output, for use with the main_cause and main_mask registers. - * hardport is the other output, in range 0..3 + * shift is one output, for use with main_irq_cause / main_irq_mask registers. + * hardport is the other output, in range 0..3. * * Note that port and hardport may be the same variable in some cases. */ @@ -1679,12 +1680,12 @@ static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp /** * mv_host_intr - Handle all interrupts on the given host controller * @host: host specific structure - * @main_cause: Main interrupt cause register for the chip. + * @main_irq_cause: Main interrupt cause register for the chip. * * LOCKING: * Inherited from caller. */ -static int mv_host_intr(struct ata_host *host, u32 main_cause) +static int mv_host_intr(struct ata_host *host, u32 main_irq_cause) { struct mv_host_priv *hpriv = host->private_data; void __iomem *mmio = hpriv->base, *hc_mmio = NULL; @@ -1705,7 +1706,7 @@ static int mv_host_intr(struct ata_host *host, u32 main_cause) * Do nothing if port is not interrupting or is disabled: */ MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport); - port_cause = (main_cause >> shift) & (DONE_IRQ | ERR_IRQ); + port_cause = (main_irq_cause >> shift) & (DONE_IRQ | ERR_IRQ); if (!port_cause || !ap || (ap->flags & ATA_FLAG_DISABLED)) continue; /* @@ -1811,20 +1812,20 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance) struct ata_host *host = dev_instance; struct mv_host_priv *hpriv = host->private_data; unsigned int handled = 0; - u32 main_cause, main_mask; + u32 main_irq_cause, main_irq_mask; spin_lock(&host->lock); - main_cause = readl(hpriv->main_cause_reg_addr); - main_mask = readl(hpriv->main_mask_reg_addr); + main_irq_cause = readl(hpriv->main_irq_cause_addr); + main_irq_mask = readl(hpriv->main_irq_mask_addr); /* * Deal with cases where we either have nothing pending, or have read * a bogus register value which can indicate HW removal or PCI fault. */ - if ((main_cause & main_mask) && (main_cause != 0xffffffffU)) { - if (unlikely((main_cause & PCI_ERR) && HAS_PCI(host))) + if ((main_irq_cause & main_irq_mask) && (main_irq_cause != 0xffffffffU)) { + if (unlikely((main_irq_cause & PCI_ERR) && HAS_PCI(host))) handled = mv_pci_error(host, hpriv->base); else - handled = mv_host_intr(host, main_cause); + handled = mv_host_intr(host, main_irq_cause); } spin_unlock(&host->lock); return IRQ_RETVAL(handled); @@ -2027,7 +2028,7 @@ static void mv_reset_pci_bus(struct ata_host *host, void __iomem *mmio) ZERO(MV_PCI_DISC_TIMER); ZERO(MV_PCI_MSI_TRIGGER); writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT); - ZERO(HC_MAIN_IRQ_MASK_OFS); + ZERO(PCI_HC_MAIN_IRQ_MASK_OFS); ZERO(MV_PCI_SERR_MASK); ZERO(hpriv->irq_cause_ofs); ZERO(hpriv->irq_mask_ofs); @@ -2404,7 +2405,7 @@ static void mv_eh_freeze(struct ata_port *ap) { struct mv_host_priv *hpriv = ap->host->private_data; unsigned int shift, hardport, port = ap->port_no; - u32 main_mask; + u32 main_irq_mask; /* FIXME: handle coalescing completion events properly */ @@ -2412,9 +2413,9 @@ static void mv_eh_freeze(struct ata_port *ap) MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport); /* disable assertion of portN err, done events */ - main_mask = readl(hpriv->main_mask_reg_addr); - main_mask &= ~((DONE_IRQ | ERR_IRQ) << shift); - writelfl(main_mask, hpriv->main_mask_reg_addr); + main_irq_mask = readl(hpriv->main_irq_mask_addr); + main_irq_mask &= ~((DONE_IRQ | ERR_IRQ) << shift); + writelfl(main_irq_mask, hpriv->main_irq_mask_addr); } static void mv_eh_thaw(struct ata_port *ap) @@ -2423,7 +2424,7 @@ static void mv_eh_thaw(struct ata_port *ap) unsigned int shift, hardport, port = ap->port_no; void __iomem *hc_mmio = mv_hc_base_from_port(hpriv->base, port); void __iomem *port_mmio = mv_ap_base(ap); - u32 main_mask, hc_irq_cause; + u32 main_irq_mask, hc_irq_cause; /* FIXME: handle coalescing completion events properly */ @@ -2438,9 +2439,9 @@ static void mv_eh_thaw(struct ata_port *ap) writelfl(hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS); /* enable assertion of portN err, done events */ - main_mask = readl(hpriv->main_mask_reg_addr); - main_mask |= ((DONE_IRQ | ERR_IRQ) << shift); - writelfl(main_mask, hpriv->main_mask_reg_addr); + main_irq_mask = readl(hpriv->main_irq_mask_addr); + main_irq_mask |= ((DONE_IRQ | ERR_IRQ) << shift); + writelfl(main_irq_mask, hpriv->main_irq_mask_addr); } /** @@ -2654,15 +2655,15 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx) goto done; if (HAS_PCI(host)) { - hpriv->main_cause_reg_addr = mmio + HC_MAIN_IRQ_CAUSE_OFS; - hpriv->main_mask_reg_addr = mmio + HC_MAIN_IRQ_MASK_OFS; + hpriv->main_irq_cause_addr = mmio + PCI_HC_MAIN_IRQ_CAUSE_OFS; + hpriv->main_irq_mask_addr = mmio + PCI_HC_MAIN_IRQ_MASK_OFS; } else { - hpriv->main_cause_reg_addr = mmio + HC_SOC_MAIN_IRQ_CAUSE_OFS; - hpriv->main_mask_reg_addr = mmio + HC_SOC_MAIN_IRQ_MASK_OFS; + hpriv->main_irq_cause_addr = mmio + SOC_HC_MAIN_IRQ_CAUSE_OFS; + hpriv->main_irq_mask_addr = mmio + SOC_HC_MAIN_IRQ_MASK_OFS; } /* global interrupt mask: 0 == mask everything */ - writel(0, hpriv->main_mask_reg_addr); + writel(0, hpriv->main_irq_mask_addr); n_hc = mv_get_hc_count(host->ports[0]->flags); @@ -2712,23 +2713,23 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx) writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs); if (IS_GEN_I(hpriv)) writelfl(~HC_MAIN_MASKED_IRQS_5, - hpriv->main_mask_reg_addr); + hpriv->main_irq_mask_addr); else writelfl(~HC_MAIN_MASKED_IRQS, - hpriv->main_mask_reg_addr); + hpriv->main_irq_mask_addr); VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x " "PCI int cause/mask=0x%08x/0x%08x\n", - readl(hpriv->main_cause_reg_addr), - readl(hpriv->main_mask_reg_addr), + readl(hpriv->main_irq_cause_addr), + readl(hpriv->main_irq_mask_addr), readl(mmio + hpriv->irq_cause_ofs), readl(mmio + hpriv->irq_mask_ofs)); } else { writelfl(~HC_MAIN_MASKED_IRQS_SOC, - hpriv->main_mask_reg_addr); + hpriv->main_irq_mask_addr); VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x\n", - readl(hpriv->main_cause_reg_addr), - readl(hpriv->main_mask_reg_addr)); + readl(hpriv->main_irq_cause_addr), + readl(hpriv->main_irq_mask_addr)); } done: return rc; diff --git a/drivers/base/core.c b/drivers/base/core.c index 9248e0927d08..be288b5e4180 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -787,6 +787,10 @@ int device_add(struct device *dev) parent = get_device(dev->parent); setup_parent(dev, parent); + /* use parent numa_node */ + if (parent) + set_dev_node(dev, dev_to_node(parent)); + /* first, register with generic layer. */ error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id); if (error) @@ -1306,8 +1310,11 @@ int device_move(struct device *dev, struct device *new_parent) dev->parent = new_parent; if (old_parent) klist_remove(&dev->knode_parent); - if (new_parent) + if (new_parent) { klist_add_tail(&dev->knode_parent, &new_parent->klist_children); + set_dev_node(dev, dev_to_node(new_parent)); + } + if (!dev->class) goto out_put; error = device_move_class_links(dev, old_parent, new_parent); @@ -1317,9 +1324,12 @@ int device_move(struct device *dev, struct device *new_parent) if (!kobject_move(&dev->kobj, &old_parent->kobj)) { if (new_parent) klist_remove(&dev->knode_parent); - if (old_parent) + dev->parent = old_parent; + if (old_parent) { klist_add_tail(&dev->knode_parent, &old_parent->klist_children); + set_dev_node(dev, dev_to_node(old_parent)); + } } cleanup_glue_dir(dev, new_parent_kobj); put_device(new_parent); diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 1fef7df8c9d6..9fd4a8534146 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -396,6 +396,8 @@ _request_firmware(const struct firmware **firmware_p, const char *name, if (!firmware_p) return -EINVAL; + printk(KERN_INFO "firmware: requesting %s\n", name); + *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL); if (!firmware) { printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n", diff --git a/drivers/base/node.c b/drivers/base/node.c index 12fde2d03d69..39f3d1b3a213 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -77,6 +77,7 @@ static ssize_t node_read_meminfo(struct sys_device * dev, char * buf) "Node %d PageTables: %8lu kB\n" "Node %d NFS_Unstable: %8lu kB\n" "Node %d Bounce: %8lu kB\n" + "Node %d WritebackTmp: %8lu kB\n" "Node %d Slab: %8lu kB\n" "Node %d SReclaimable: %8lu kB\n" "Node %d SUnreclaim: %8lu kB\n", @@ -99,6 +100,7 @@ static ssize_t node_read_meminfo(struct sys_device * dev, char * buf) nid, K(node_page_state(nid, NR_PAGETABLE)), nid, K(node_page_state(nid, NR_UNSTABLE_NFS)), nid, K(node_page_state(nid, NR_BOUNCE)), + nid, K(node_page_state(nid, NR_WRITEBACK_TEMP)), nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE) + node_page_state(nid, NR_SLAB_UNRECLAIMABLE)), nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE)), diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index 280e71ee744c..5b4c6e649c11 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -195,7 +195,6 @@ void aoedev_exit(void); struct aoedev *aoedev_by_aoeaddr(int maj, int min); struct aoedev *aoedev_by_sysminor_m(ulong sysminor); void aoedev_downdev(struct aoedev *d); -int aoedev_isbusy(struct aoedev *d); int aoedev_flush(const char __user *str, size_t size); int aoenet_init(void); diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index d00293ba3b45..8fc429cf82b6 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -668,16 +668,16 @@ ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id) u16 n; /* word 83: command set supported */ - n = le16_to_cpu(get_unaligned((__le16 *) &id[83<<1])); + n = get_unaligned_le16(&id[83 << 1]); /* word 86: command set/feature enabled */ - n |= le16_to_cpu(get_unaligned((__le16 *) &id[86<<1])); + n |= get_unaligned_le16(&id[86 << 1]); if (n & (1<<10)) { /* bit 10: LBA 48 */ d->flags |= DEVFL_EXT; /* word 100: number lba48 sectors */ - ssize = le64_to_cpu(get_unaligned((__le64 *) &id[100<<1])); + ssize = get_unaligned_le64(&id[100 << 1]); /* set as in ide-disk.c:init_idedisk_capacity */ d->geo.cylinders = ssize; @@ -688,12 +688,12 @@ ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id) d->flags &= ~DEVFL_EXT; /* number lba28 sectors */ - ssize = le32_to_cpu(get_unaligned((__le32 *) &id[60<<1])); + ssize = get_unaligned_le32(&id[60 << 1]); /* NOTE: obsolete in ATA 6 */ - d->geo.cylinders = le16_to_cpu(get_unaligned((__le16 *) &id[54<<1])); - d->geo.heads = le16_to_cpu(get_unaligned((__le16 *) &id[55<<1])); - d->geo.sectors = le16_to_cpu(get_unaligned((__le16 *) &id[56<<1])); + d->geo.cylinders = get_unaligned_le16(&id[54 << 1]); + d->geo.heads = get_unaligned_le16(&id[55 << 1]); + d->geo.sectors = get_unaligned_le16(&id[56 << 1]); } if (d->ssize != ssize) @@ -779,7 +779,7 @@ aoecmd_ata_rsp(struct sk_buff *skb) u16 aoemajor; hin = (struct aoe_hdr *) skb_mac_header(skb); - aoemajor = be16_to_cpu(get_unaligned(&hin->major)); + aoemajor = get_unaligned_be16(&hin->major); d = aoedev_by_aoeaddr(aoemajor, hin->minor); if (d == NULL) { snprintf(ebuf, sizeof ebuf, "aoecmd_ata_rsp: ata response " @@ -791,7 +791,7 @@ aoecmd_ata_rsp(struct sk_buff *skb) spin_lock_irqsave(&d->lock, flags); - n = be32_to_cpu(get_unaligned(&hin->tag)); + n = get_unaligned_be32(&hin->tag); t = gettgt(d, hin->src); if (t == NULL) { printk(KERN_INFO "aoe: can't find target e%ld.%d:%012llx\n", @@ -806,9 +806,9 @@ aoecmd_ata_rsp(struct sk_buff *skb) snprintf(ebuf, sizeof ebuf, "%15s e%d.%d tag=%08x@%08lx\n", "unexpected rsp", - be16_to_cpu(get_unaligned(&hin->major)), + get_unaligned_be16(&hin->major), hin->minor, - be32_to_cpu(get_unaligned(&hin->tag)), + get_unaligned_be32(&hin->tag), jiffies); aoechr_error(ebuf); return; @@ -873,7 +873,7 @@ aoecmd_ata_rsp(struct sk_buff *skb) printk(KERN_INFO "aoe: unrecognized ata command %2.2Xh for %d.%d\n", ahout->cmdstat, - be16_to_cpu(get_unaligned(&hin->major)), + get_unaligned_be16(&hin->major), hin->minor); } } diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c index f9a1cd9edb77..a1d813ab0d6b 100644 --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c @@ -18,24 +18,6 @@ static void skbpoolfree(struct aoedev *d); static struct aoedev *devlist; static DEFINE_SPINLOCK(devlist_lock); -int -aoedev_isbusy(struct aoedev *d) -{ - struct aoetgt **t, **te; - struct frame *f, *e; - - t = d->targets; - te = t + NTARGETS; - for (; t < te && *t; t++) { - f = (*t)->frames; - e = f + (*t)->nframes; - for (; f < e; f++) - if (f->tag != FREETAG) - return 1; - } - return 0; -} - struct aoedev * aoedev_by_aoeaddr(int maj, int min) { diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c index 18d243c73eee..d625169c8e48 100644 --- a/drivers/block/aoe/aoenet.c +++ b/drivers/block/aoe/aoenet.c @@ -128,7 +128,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, skb_push(skb, ETH_HLEN); /* (1) */ h = (struct aoe_hdr *) skb_mac_header(skb); - n = be32_to_cpu(get_unaligned(&h->tag)); + n = get_unaligned_be32(&h->tag); if ((h->verfl & AOEFL_RSP) == 0 || (n & 1<<31)) goto exit; @@ -140,7 +140,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, printk(KERN_ERR "%s%d.%d@%s; ecode=%d '%s'\n", "aoe: error packet from ", - be16_to_cpu(get_unaligned(&h->major)), + get_unaligned_be16(&h->major), h->minor, skb->dev->name, h->err, aoe_errlist[n]); goto exit; diff --git a/drivers/block/brd.c b/drivers/block/brd.c index e8e38faeafd8..a196ef7f147f 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -387,10 +387,14 @@ static struct block_device_operations brd_fops = { */ static int rd_nr; int rd_size = CONFIG_BLK_DEV_RAM_SIZE; +static int max_part; +static int part_shift; module_param(rd_nr, int, 0); MODULE_PARM_DESC(rd_nr, "Maximum number of brd devices"); module_param(rd_size, int, 0); MODULE_PARM_DESC(rd_size, "Size of each RAM disk in kbytes."); +module_param(max_part, int, 0); +MODULE_PARM_DESC(max_part, "Maximum number of partitions per RAM disk"); MODULE_LICENSE("GPL"); MODULE_ALIAS_BLOCKDEV_MAJOR(RAMDISK_MAJOR); @@ -435,11 +439,11 @@ static struct brd_device *brd_alloc(int i) blk_queue_max_sectors(brd->brd_queue, 1024); blk_queue_bounce_limit(brd->brd_queue, BLK_BOUNCE_ANY); - disk = brd->brd_disk = alloc_disk(1); + disk = brd->brd_disk = alloc_disk(1 << part_shift); if (!disk) goto out_free_queue; disk->major = RAMDISK_MAJOR; - disk->first_minor = i; + disk->first_minor = i << part_shift; disk->fops = &brd_fops; disk->private_data = brd; disk->queue = brd->brd_queue; @@ -523,7 +527,12 @@ static int __init brd_init(void) * themselves and have kernel automatically instantiate actual * device on-demand. */ - if (rd_nr > 1UL << MINORBITS) + + part_shift = 0; + if (max_part > 0) + part_shift = fls(max_part); + + if (rd_nr > 1UL << (MINORBITS - part_shift)) return -EINVAL; if (rd_nr) { @@ -531,7 +540,7 @@ static int __init brd_init(void) range = rd_nr; } else { nr = CONFIG_BLK_DEV_RAM_COUNT; - range = 1UL << MINORBITS; + range = 1UL << (MINORBITS - part_shift); } if (register_blkdev(RAMDISK_MAJOR, "ramdisk")) @@ -570,7 +579,7 @@ static void __exit brd_exit(void) unsigned long range; struct brd_device *brd, *next; - range = rd_nr ? rd_nr : 1UL << MINORBITS; + range = rd_nr ? rd_nr : 1UL << (MINORBITS - part_shift); list_for_each_entry_safe(brd, next, &brd_devices, brd_list) brd_del_one(brd); diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index cf6083a1f928..e539be5750dc 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -425,7 +425,7 @@ static void __devinit cciss_procinit(int i) struct proc_dir_entry *pde; if (proc_cciss == NULL) - proc_cciss = proc_mkdir("cciss", proc_root_driver); + proc_cciss = proc_mkdir("driver/cciss", NULL); if (!proc_cciss) return; pde = proc_create(hba[i]->devname, S_IWUSR | S_IRUSR | S_IRGRP | @@ -3700,7 +3700,7 @@ static void __exit cciss_cleanup(void) cciss_remove_one(hba[i]->pdev); } } - remove_proc_entry("cciss", proc_root_driver); + remove_proc_entry("driver/cciss", NULL); } static void fail_all_cmds(unsigned long ctlr) diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index 69199185ff4b..09c14341e6e3 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -214,7 +214,7 @@ static struct proc_dir_entry *proc_array; static void __init ida_procinit(int i) { if (proc_array == NULL) { - proc_array = proc_mkdir("cpqarray", proc_root_driver); + proc_array = proc_mkdir("driver/cpqarray", NULL); if (!proc_array) return; } @@ -1796,7 +1796,7 @@ static void __exit cpqarray_exit(void) } } - remove_proc_entry("cpqarray", proc_root_driver); + remove_proc_entry("driver/cpqarray", NULL); } module_init(cpqarray_init) diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 7652e87d60c5..395f8ea7981c 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -4526,14 +4526,15 @@ static void __init parse_floppy_cfg_string(char *cfg) } } -int __init init_module(void) +static int __init floppy_module_init(void) { if (floppy) parse_floppy_cfg_string(floppy); return floppy_init(); } +module_init(floppy_module_init); -void cleanup_module(void) +static void __exit floppy_module_exit(void) { int drive; @@ -4562,6 +4563,7 @@ void cleanup_module(void) /* eject disk, if any */ fd_eject(0); } +module_exit(floppy_module_exit); module_param(floppy, charp, 0); module_param(FLOPPY_IRQ, int, 0); diff --git a/drivers/block/loop.c b/drivers/block/loop.c index f7f163557aa0..d3a25b027ff9 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -546,7 +546,7 @@ static void loop_unplug(struct request_queue *q) { struct loop_device *lo = q->queuedata; - clear_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags); + queue_flag_clear_unlocked(QUEUE_FLAG_PLUGGED, q); blk_run_address_space(lo->lo_backing_file->f_mapping); } diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 60cc54368b66..ad98dda6037d 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -29,6 +29,7 @@ #include <linux/kernel.h> #include <net/sock.h> #include <linux/net.h> +#include <linux/kthread.h> #include <asm/uaccess.h> #include <asm/system.h> @@ -55,6 +56,7 @@ static unsigned int debugflags; static unsigned int nbds_max = 16; static struct nbd_device *nbd_dev; +static int max_part; /* * Use just one lock (or at most 1 per NIC). Two arguments for this: @@ -337,7 +339,7 @@ static struct request *nbd_read_stat(struct nbd_device *lo) } req = nbd_find_request(lo, *(struct request **)reply.handle); - if (unlikely(IS_ERR(req))) { + if (IS_ERR(req)) { result = PTR_ERR(req); if (result != -ENOENT) goto harderror; @@ -441,6 +443,85 @@ static void nbd_clear_que(struct nbd_device *lo) } +static void nbd_handle_req(struct nbd_device *lo, struct request *req) +{ + if (!blk_fs_request(req)) + goto error_out; + + nbd_cmd(req) = NBD_CMD_READ; + if (rq_data_dir(req) == WRITE) { + nbd_cmd(req) = NBD_CMD_WRITE; + if (lo->flags & NBD_READ_ONLY) { + printk(KERN_ERR "%s: Write on read-only\n", + lo->disk->disk_name); + goto error_out; + } + } + + req->errors = 0; + + mutex_lock(&lo->tx_lock); + if (unlikely(!lo->sock)) { + mutex_unlock(&lo->tx_lock); + printk(KERN_ERR "%s: Attempted send on closed socket\n", + lo->disk->disk_name); + req->errors++; + nbd_end_request(req); + return; + } + + lo->active_req = req; + + if (nbd_send_req(lo, req) != 0) { + printk(KERN_ERR "%s: Request send failed\n", + lo->disk->disk_name); + req->errors++; + nbd_end_request(req); + } else { + spin_lock(&lo->queue_lock); + list_add(&req->queuelist, &lo->queue_head); + spin_unlock(&lo->queue_lock); + } + + lo->active_req = NULL; + mutex_unlock(&lo->tx_lock); + wake_up_all(&lo->active_wq); + + return; + +error_out: + req->errors++; + nbd_end_request(req); +} + +static int nbd_thread(void *data) +{ + struct nbd_device *lo = data; + struct request *req; + + set_user_nice(current, -20); + while (!kthread_should_stop() || !list_empty(&lo->waiting_queue)) { + /* wait for something to do */ + wait_event_interruptible(lo->waiting_wq, + kthread_should_stop() || + !list_empty(&lo->waiting_queue)); + + /* extract request */ + if (list_empty(&lo->waiting_queue)) + continue; + + spin_lock_irq(&lo->queue_lock); + req = list_entry(lo->waiting_queue.next, struct request, + queuelist); + list_del_init(&req->queuelist); + spin_unlock_irq(&lo->queue_lock); + + /* handle request */ + nbd_handle_req(lo, req); + } + return 0; +} + /* * We always wait for result of write, for now. It would be nice to make it optional * in future @@ -456,65 +537,23 @@ static void do_nbd_request(struct request_queue * q) struct nbd_device *lo; blkdev_dequeue_request(req); + + spin_unlock_irq(q->queue_lock); + dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%x)\n", req->rq_disk->disk_name, req, req->cmd_type); - if (!blk_fs_request(req)) - goto error_out; - lo = req->rq_disk->private_data; BUG_ON(lo->magic != LO_MAGIC); - nbd_cmd(req) = NBD_CMD_READ; - if (rq_data_dir(req) == WRITE) { - nbd_cmd(req) = NBD_CMD_WRITE; - if (lo->flags & NBD_READ_ONLY) { - printk(KERN_ERR "%s: Write on read-only\n", - lo->disk->disk_name); - goto error_out; - } - } - - req->errors = 0; - spin_unlock_irq(q->queue_lock); - - mutex_lock(&lo->tx_lock); - if (unlikely(!lo->sock)) { - mutex_unlock(&lo->tx_lock); - printk(KERN_ERR "%s: Attempted send on closed socket\n", - lo->disk->disk_name); - req->errors++; - nbd_end_request(req); - spin_lock_irq(q->queue_lock); - continue; - } - - lo->active_req = req; + spin_lock_irq(&lo->queue_lock); + list_add_tail(&req->queuelist, &lo->waiting_queue); + spin_unlock_irq(&lo->queue_lock); - if (nbd_send_req(lo, req) != 0) { - printk(KERN_ERR "%s: Request send failed\n", - lo->disk->disk_name); - req->errors++; - nbd_end_request(req); - } else { - spin_lock(&lo->queue_lock); - list_add(&req->queuelist, &lo->queue_head); - spin_unlock(&lo->queue_lock); - } - - lo->active_req = NULL; - mutex_unlock(&lo->tx_lock); - wake_up_all(&lo->active_wq); + wake_up(&lo->waiting_wq); spin_lock_irq(q->queue_lock); - continue; - -error_out: - req->errors++; - spin_unlock(q->queue_lock); - nbd_end_request(req); - spin_lock(q->queue_lock); } } @@ -524,6 +563,7 @@ static int nbd_ioctl(struct inode *inode, struct file *file, struct nbd_device *lo = inode->i_bdev->bd_disk->private_data; int error; struct request sreq ; + struct task_struct *thread; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -537,6 +577,7 @@ static int nbd_ioctl(struct inode *inode, struct file *file, switch (cmd) { case NBD_DISCONNECT: printk(KERN_INFO "%s: NBD_DISCONNECT\n", lo->disk->disk_name); + blk_rq_init(NULL, &sreq); sreq.cmd_type = REQ_TYPE_SPECIAL; nbd_cmd(&sreq) = NBD_CMD_DISC; /* @@ -571,10 +612,13 @@ static int nbd_ioctl(struct inode *inode, struct file *file, error = -EINVAL; file = fget(arg); if (file) { + struct block_device *bdev = inode->i_bdev; inode = file->f_path.dentry->d_inode; if (S_ISSOCK(inode->i_mode)) { lo->file = file; lo->sock = SOCKET_I(inode); + if (max_part > 0) + bdev->bd_invalidated = 1; error = 0; } else { fput(file); @@ -606,7 +650,12 @@ static int nbd_ioctl(struct inode *inode, struct file *file, case NBD_DO_IT: if (!lo->file) return -EINVAL; + thread = kthread_create(nbd_thread, lo, lo->disk->disk_name); + if (IS_ERR(thread)) + return PTR_ERR(thread); + wake_up_process(thread); error = nbd_do_it(lo); + kthread_stop(thread); if (error) return error; sock_shutdown(lo, 1); @@ -619,6 +668,8 @@ static int nbd_ioctl(struct inode *inode, struct file *file, lo->bytesize = 0; inode->i_bdev->bd_inode->i_size = 0; set_capacity(lo->disk, 0); + if (max_part > 0) + ioctl_by_bdev(inode->i_bdev, BLKRRPART, 0); return lo->harderror; case NBD_CLEAR_QUE: /* @@ -652,6 +703,7 @@ static int __init nbd_init(void) { int err = -ENOMEM; int i; + int part_shift; BUILD_BUG_ON(sizeof(struct nbd_request) != 28); @@ -659,8 +711,17 @@ static int __init nbd_init(void) if (!nbd_dev) return -ENOMEM; + if (max_part < 0) { + printk(KERN_CRIT "nbd: max_part must be >= 0\n"); + return -EINVAL; + } + + part_shift = 0; + if (max_part > 0) + part_shift = fls(max_part); + for (i = 0; i < nbds_max; i++) { - struct gendisk *disk = alloc_disk(1); + struct gendisk *disk = alloc_disk(1 << part_shift); elevator_t *old_e; if (!disk) goto out; @@ -695,17 +756,18 @@ static int __init nbd_init(void) nbd_dev[i].file = NULL; nbd_dev[i].magic = LO_MAGIC; nbd_dev[i].flags = 0; + INIT_LIST_HEAD(&nbd_dev[i].waiting_queue); spin_lock_init(&nbd_dev[i].queue_lock); INIT_LIST_HEAD(&nbd_dev[i].queue_head); mutex_init(&nbd_dev[i].tx_lock); init_waitqueue_head(&nbd_dev[i].active_wq); + init_waitqueue_head(&nbd_dev[i].waiting_wq); nbd_dev[i].blksize = 1024; nbd_dev[i].bytesize = 0; disk->major = NBD_MAJOR; - disk->first_minor = i; + disk->first_minor = i << part_shift; disk->fops = &nbd_fops; disk->private_data = &nbd_dev[i]; - disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO; sprintf(disk->disk_name, "nbd%d", i); set_capacity(disk, 0); add_disk(disk); @@ -743,7 +805,9 @@ MODULE_DESCRIPTION("Network Block Device"); MODULE_LICENSE("GPL"); module_param(nbds_max, int, 0444); -MODULE_PARM_DESC(nbds_max, "How many network block devices to initialize."); +MODULE_PARM_DESC(nbds_max, "number of network block devices to initialize (default: 16)"); +module_param(max_part, int, 0444); +MODULE_PARM_DESC(max_part, "number of partitions per device (default: 0)"); #ifndef NDEBUG module_param(debugflags, int, 0644); MODULE_PARM_DESC(debugflags, "flags for controlling debug output"); diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index df819f8a95a6..570f3b70dce7 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -716,10 +716,8 @@ static int pd_special_command(struct pd_unit *disk, struct request rq; int err = 0; - memset(&rq, 0, sizeof(rq)); - rq.errors = 0; + blk_rq_init(NULL, &rq); rq.rq_disk = disk->gd; - rq.ref_count = 1; rq.end_io_data = &wait; rq.end_io = blk_end_sync_rq; blk_insert_request(disk->gd->queue, &rq, 0, func); diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 18feb1c7c33b..3ba1df93e9e3 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -776,8 +776,6 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command * rq->cmd_len = COMMAND_SIZE(cgc->cmd[0]); memcpy(rq->cmd, cgc->cmd, CDROM_PACKET_SIZE); - if (sizeof(rq->cmd) > CDROM_PACKET_SIZE) - memset(rq->cmd + CDROM_PACKET_SIZE, 0, sizeof(rq->cmd) - CDROM_PACKET_SIZE); rq->timeout = 60*HZ; rq->cmd_type = REQ_TYPE_BLOCK_PC; @@ -2744,7 +2742,6 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) int i; int ret = 0; char b[BDEVNAME_SIZE]; - struct proc_dir_entry *proc; struct block_device *bdev; if (pd->pkt_dev == dev) { @@ -2788,11 +2785,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) goto out_mem; } - proc = create_proc_entry(pd->name, 0, pkt_proc); - if (proc) { - proc->data = pd; - proc->proc_fops = &pkt_proc_fops; - } + proc_create_data(pd->name, 0, pkt_proc, &pkt_proc_fops, pd); DPRINTK(DRIVER_NAME": writer %s mapped to %s\n", pd->name, bdevname(bdev, b)); return 0; @@ -3101,7 +3094,7 @@ static int __init pkt_init(void) goto out_misc; } - pkt_proc = proc_mkdir(DRIVER_NAME, proc_root_driver); + pkt_proc = proc_mkdir("driver/"DRIVER_NAME, NULL); return 0; @@ -3117,7 +3110,7 @@ out2: static void __exit pkt_exit(void) { - remove_proc_entry(DRIVER_NAME, proc_root_driver); + remove_proc_entry("driver/"DRIVER_NAME, NULL); misc_deregister(&pkt_misc); pkt_debugfs_cleanup(); diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index 7483f947f0e9..d797e209951d 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -102,8 +102,7 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev, dev_dbg(&dev->sbd.core, "%s:%u: bio %u: %u segs %u sectors from %lu\n", __func__, __LINE__, i, bio_segments(iter.bio), - bio_sectors(iter.bio), - (unsigned long)iter.bio->bi_sector); + bio_sectors(iter.bio), iter.bio->bi_sector); size = bvec->bv_len; buf = bvec_kmap_irq(bvec, &flags); @@ -406,7 +405,6 @@ static void ps3disk_prepare_flush(struct request_queue *q, struct request *req) dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__); - memset(req->cmd, 0, sizeof(req->cmd)); req->cmd_type = REQ_TYPE_FLUSH; } diff --git a/drivers/block/ub.c b/drivers/block/ub.c index 27bfe72aab59..e322cce8c12d 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -2399,7 +2399,7 @@ static void ub_disconnect(struct usb_interface *intf) del_gendisk(lun->disk); /* * I wish I could do: - * set_bit(QUEUE_FLAG_DEAD, &q->queue_flags); + * queue_flag_set(QUEUE_FLAG_DEAD, q); * As it is, we rely on our internal poisoning and let * the upper levels to spin furiously failing all the I/O. */ diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index d771da816d95..f2fff5799ddf 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -137,7 +137,7 @@ static void blkif_restart_queue_callback(void *arg) schedule_work(&info->work); } -int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg) +static int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg) { /* We don't have real geometry info, but let's at least return values consistent with the size of the device */ diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 7e31d5f1bc8a..e5cd856a2fea 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -143,7 +143,7 @@ restart: int len; set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - len = tty->driver->write(tty, skb->data, skb->len); + len = tty->ops->write(tty, skb->data, skb->len); hdev->stat.byte_tx += len; skb_pull(skb, len); @@ -190,8 +190,7 @@ static int hci_uart_flush(struct hci_dev *hdev) /* Flush any pending characters in the driver and discipline. */ tty_ldisc_flush(tty); - if (tty->driver && tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + tty_driver_flush_buffer(tty); if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) hu->proto->flush(hu); @@ -285,9 +284,7 @@ static int hci_uart_tty_open(struct tty_struct *tty) if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); - - if (tty->driver && tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + tty_driver_flush_buffer(tty); return 0; } @@ -373,9 +370,7 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *f hu->hdev->stat.byte_rx += count; spin_unlock(&hu->rx_lock); - if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) && - tty->driver->unthrottle) - tty->driver->unthrottle(tty); + tty_unthrottle(tty); } static int hci_uart_register_dev(struct hci_uart *hu) diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index ac3829030ac5..69f26eb6415b 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2194,7 +2194,6 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, if (ret) break; - memset(rq->cmd, 0, sizeof(rq->cmd)); rq->cmd[0] = GPCMD_READ_CD; rq->cmd[1] = 1 << 2; rq->cmd[2] = (lba >> 24) & 0xff; diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c index b74b6c2768a8..5245a4a0ba74 100644 --- a/drivers/cdrom/viocd.c +++ b/drivers/cdrom/viocd.c @@ -144,6 +144,7 @@ static int proc_viocd_open(struct inode *inode, struct file *file) } static const struct file_operations proc_viocd_operations = { + .owner = THIS_MODULE, .open = proc_viocd_open, .read = seq_read, .llseek = seq_lseek, @@ -679,7 +680,6 @@ static struct vio_driver viocd_driver = { static int __init viocd_init(void) { - struct proc_dir_entry *e; int ret = 0; if (!firmware_has_feature(FW_FEATURE_ISERIES)) @@ -719,12 +719,8 @@ static int __init viocd_init(void) if (ret) goto out_free_info; - e = create_proc_entry("iSeries/viocd", S_IFREG|S_IRUGO, NULL); - if (e) { - e->owner = THIS_MODULE; - e->proc_fops = &proc_viocd_operations; - } - + proc_create("iSeries/viocd", S_IFREG|S_IRUGO, NULL, + &proc_viocd_operations); return 0; out_free_info: diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 929d4fa73fd9..5dce3877eee5 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -80,6 +80,15 @@ config VT_HW_CONSOLE_BINDING information. For framebuffer console users, please refer to <file:Documentation/fb/fbcon.txt>. +config DEVKMEM + bool "/dev/kmem virtual device support" + default y + help + Say Y here if you want to support the /dev/kmem device. The + /dev/kmem device is rarely used, but can be used for certain + kind of kernel debugging operations. + When in doubt, say "N". + config SERIAL_NONSTANDARD bool "Non-standard serial port support" depends on HAS_IOMEM diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index c69f79598e47..99e6a406efb4 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -35,7 +35,7 @@ //#define AGP_DEBUG 1 #ifdef AGP_DEBUG -#define DBG(x,y...) printk (KERN_DEBUG PFX "%s: " x "\n", __FUNCTION__ , ## y) +#define DBG(x,y...) printk (KERN_DEBUG PFX "%s: " x "\n", __func__ , ## y) #else #define DBG(x,y...) do { } while (0) #endif diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 3d468f502d2d..37457e5a4f2b 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -832,33 +832,34 @@ static void change_speed(struct async_struct *info, local_irq_restore(flags); } -static void rs_put_char(struct tty_struct *tty, unsigned char ch) +static int rs_put_char(struct tty_struct *tty, unsigned char ch) { struct async_struct *info; unsigned long flags; if (!tty) - return; + return 0; info = tty->driver_data; if (serial_paranoia_check(info, tty->name, "rs_put_char")) - return; + return 0; if (!info->xmit.buf) - return; + return 0; local_irq_save(flags); if (CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) == 0) { local_irq_restore(flags); - return; + return 0; } info->xmit.buf[info->xmit.head++] = ch; info->xmit.head &= SERIAL_XMIT_SIZE-1; local_irq_restore(flags); + return 1; } static void rs_flush_chars(struct tty_struct *tty) @@ -1074,6 +1075,7 @@ static int get_serial_info(struct async_struct * info, if (!retinfo) return -EFAULT; memset(&tmp, 0, sizeof(tmp)); + lock_kernel(); tmp.type = state->type; tmp.line = state->line; tmp.port = state->port; @@ -1084,6 +1086,7 @@ static int get_serial_info(struct async_struct * info, tmp.close_delay = state->close_delay; tmp.closing_wait = state->closing_wait; tmp.custom_divisor = state->custom_divisor; + unlock_kernel(); if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) return -EFAULT; return 0; @@ -1099,13 +1102,17 @@ static int set_serial_info(struct async_struct * info, if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) return -EFAULT; + + lock_kernel(); state = info->state; old_state = *state; change_irq = new_serial.irq != state->irq; change_port = (new_serial.port != state->port); - if(change_irq || change_port || (new_serial.xmit_fifo_size != state->xmit_fifo_size)) + if(change_irq || change_port || (new_serial.xmit_fifo_size != state->xmit_fifo_size)) { + unlock_kernel(); return -EINVAL; + } if (!serial_isroot()) { if ((new_serial.baud_base != state->baud_base) || @@ -1122,8 +1129,10 @@ static int set_serial_info(struct async_struct * info, goto check_and_exit; } - if (new_serial.baud_base < 9600) + if (new_serial.baud_base < 9600) { + unlock_kernel(); return -EINVAL; + } /* * OK, past this point, all the error checking has been done. @@ -1157,6 +1166,7 @@ check_and_exit: } } else retval = startup(info); + unlock_kernel(); return retval; } @@ -1496,8 +1506,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) rs_wait_until_sent(tty, info->timeout); } shutdown(info); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + rs_flush_buffer(tty); tty_ldisc_flush(tty); tty->closing = 0; @@ -1530,6 +1539,8 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) return; /* Just in case.... */ orig_jiffies = jiffies; + + lock_kernel(); /* * Set the check interval to be 1/5 of the estimated time to * send a single character, and make it at least 1. The check @@ -1570,6 +1581,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) break; } __set_current_state(TASK_RUNNING); + unlock_kernel(); #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); #endif diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c index 17d54315e146..cdd876dbb2b0 100644 --- a/drivers/char/apm-emulation.c +++ b/drivers/char/apm-emulation.c @@ -14,6 +14,7 @@ #include <linux/poll.h> #include <linux/slab.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <linux/miscdevice.h> #include <linux/apm_bios.h> #include <linux/capability.h> @@ -493,11 +494,10 @@ static struct miscdevice apm_device = { * -1: Unknown * 8) min = minutes; sec = seconds */ -static int apm_get_info(char *buf, char **start, off_t fpos, int length) +static int proc_apm_show(struct seq_file *m, void *v) { struct apm_power_info info; char *units; - int ret; info.ac_line_status = 0xff; info.battery_status = 0xff; @@ -515,14 +515,27 @@ static int apm_get_info(char *buf, char **start, off_t fpos, int length) case 1: units = "sec"; break; } - ret = sprintf(buf, "%s 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n", + seq_printf(m, "%s 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n", driver_version, APM_32_BIT_SUPPORT, info.ac_line_status, info.battery_status, info.battery_flag, info.battery_life, info.time, units); - return ret; + return 0; } + +static int proc_apm_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_apm_show, NULL); +} + +static const struct file_operations apm_proc_fops = { + .owner = THIS_MODULE, + .open = proc_apm_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; #endif static int kapmd(void *arg) @@ -593,7 +606,7 @@ static int __init apm_init(void) wake_up_process(kapmd_tsk); #ifdef CONFIG_PROC_FS - create_proc_info_entry("apm", 0, NULL, apm_get_info); + proc_create("apm", 0, NULL, &apm_proc_fops); #endif ret = misc_register(&apm_device); diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c index a7c4990b5b6b..31d08b641f5b 100644 --- a/drivers/char/applicom.c +++ b/drivers/char/applicom.c @@ -199,7 +199,7 @@ static int __init applicom_init(void) if (pci_enable_device(dev)) return -EIO; - RamIO = ioremap(pci_resource_start(dev, 0), LEN_RAM_IO); + RamIO = ioremap_nocache(pci_resource_start(dev, 0), LEN_RAM_IO); if (!RamIO) { printk(KERN_INFO "ac.o: Failed to ioremap PCI memory " @@ -254,7 +254,7 @@ static int __init applicom_init(void) /* Now try the specified ISA cards */ for (i = 0; i < MAX_ISA_BOARD; i++) { - RamIO = ioremap(mem + (LEN_RAM_IO * i), LEN_RAM_IO); + RamIO = ioremap_nocache(mem + (LEN_RAM_IO * i), LEN_RAM_IO); if (!RamIO) { printk(KERN_INFO "ac.o: Failed to ioremap the ISA card's memory space (slot #%d)\n", i + 1); diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c index 6b104e45a322..4246b8e36cb3 100644 --- a/drivers/char/consolemap.c +++ b/drivers/char/consolemap.c @@ -277,6 +277,7 @@ u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode) return p->inverse_translations[m][glyph]; } } +EXPORT_SYMBOL_GPL(inverse_translate); static void update_user_maps(void) { diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index e4f579c3e245..ef73e72daedc 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -21,7 +21,6 @@ * * This version supports shared IRQ's (only for PCI boards). * - * $Log: cyclades.c,v $ * Prevent users from opening non-existing Z ports. * * Revision 2.3.2.8 2000/07/06 18:14:16 ivan @@ -62,7 +61,7 @@ * Driver now makes sure that the constant SERIAL_XMIT_SIZE is defined; * * Revision 2.3.2.2 1999/10/01 11:27:43 ivan - * Fixed bug in cyz_poll that would make all ports but port 0 + * Fixed bug in cyz_poll that would make all ports but port 0 * unable to transmit/receive data (Cyclades-Z only); * Implemented logic to prevent the RX buffer from being stuck with data * due to a driver / firmware race condition in interrupt op mode @@ -83,25 +82,25 @@ * Revision 2.3.1.1 1999/07/15 16:45:53 ivan * Removed CY_PROC conditional compilation; * Implemented SMP-awareness for the driver; - * Implemented a new ISA IRQ autoprobe that uses the irq_probe_[on|off] + * Implemented a new ISA IRQ autoprobe that uses the irq_probe_[on|off] * functions; * The driver now accepts memory addresses (maddr=0xMMMMM) and IRQs * (irq=NN) as parameters (only for ISA boards); - * Fixed bug in set_line_char that would prevent the Cyclades-Z + * Fixed bug in set_line_char that would prevent the Cyclades-Z * ports from being configured at speeds above 115.2Kbps; * Fixed bug in cy_set_termios that would prevent XON/XOFF flow control * switching from working properly; - * The driver now only prints IRQ info for the Cyclades-Z if it's + * The driver now only prints IRQ info for the Cyclades-Z if it's * configured to work in interrupt mode; * * Revision 2.2.2.3 1999/06/28 11:13:29 ivan * Added support for interrupt mode operation for the Z cards; * Removed the driver inactivity control for the Z; - * Added a missing MOD_DEC_USE_COUNT in the cy_open function for when + * Added a missing MOD_DEC_USE_COUNT in the cy_open function for when * the Z firmware is not loaded yet; - * Replaced the "manual" Z Tx flush buffer by a call to a FW command of + * Replaced the "manual" Z Tx flush buffer by a call to a FW command of * same functionality; - * Implemented workaround for IRQ setting loss on the PCI configuration + * Implemented workaround for IRQ setting loss on the PCI configuration * registers after a PCI bridge EEPROM reload (affects PLX9060 only); * * Revision 2.2.2.2 1999/05/14 17:18:15 ivan @@ -112,22 +111,22 @@ * BREAK implementation changed in order to make use of the 'break_ctl' * TTY facility; * Fixed typo in TTY structure field 'driver_name'; - * Included a PCI bridge reset and EEPROM reload in the board + * Included a PCI bridge reset and EEPROM reload in the board * initialization code (for both Y and Z series). * * Revision 2.2.2.1 1999/04/08 16:17:43 ivan - * Fixed a bug in cy_wait_until_sent that was preventing the port to be + * Fixed a bug in cy_wait_until_sent that was preventing the port to be * closed properly after a SIGINT; * Module usage counter scheme revisited; * Added support to the upcoming Y PCI boards (i.e., support to additional * PCI Device ID's). - * + * * Revision 2.2.1.10 1999/01/20 16:14:29 ivan * Removed all unnecessary page-alignement operations in ioremap calls * (ioremap is currently safe for these operations). * * Revision 2.2.1.9 1998/12/30 18:18:30 ivan - * Changed access to PLX PCI bridge registers from I/O to MMIO, in + * Changed access to PLX PCI bridge registers from I/O to MMIO, in * order to make PLX9050-based boards work with certain motherboards. * * Revision 2.2.1.8 1998/11/13 12:46:20 ivan @@ -148,7 +147,7 @@ * Fixed Cyclom-4Yo hardware detection bug. * * Revision 2.2.1.4 1998/08/04 11:02:50 ivan - * /proc/cyclades implementation with great collaboration of + * /proc/cyclades implementation with great collaboration of * Marc Lewis <marc@blarg.net>; * cyy_interrupt was changed to avoid occurrence of kernel oopses * during PPP operation. @@ -157,7 +156,7 @@ * General code review in order to comply with 2.1 kernel standards; * data loss prevention for slow devices revisited (cy_wait_until_sent * was created); - * removed conditional compilation for new/old PCI structure support + * removed conditional compilation for new/old PCI structure support * (now the driver only supports the new PCI structure). * * Revision 2.2.1.1 1998/03/19 16:43:12 ivan @@ -168,7 +167,7 @@ * cleaned up the data loss fix; * fixed XON/XOFF handling once more (Cyclades-Z); * general review of the driver routines; - * introduction of a mechanism to prevent data loss with slow + * introduction of a mechanism to prevent data loss with slow * printers, by forcing a delay before closing the port. * * Revision 2.1.1.2 1998/02/17 16:50:00 ivan @@ -182,12 +181,12 @@ * Code review for the module cleanup routine; * fixed RTS and DTR status report for new CD1400's in get_modem_info; * includes anonymous changes regarding signal_pending. - * + * * Revision 2.1 1997/11/01 17:42:41 ivan * Changes in the driver to support Alpha systems (except 8Zo V_1); * BREAK fix for the Cyclades-Z boards; * driver inactivity control by FW implemented; - * introduction of flag that allows driver to take advantage of + * introduction of flag that allows driver to take advantage of * a special CD1400 feature related to HW flow control; * added support for the CD1400 rev. J (Cyclom-Y boards); * introduction of ioctls to: @@ -196,17 +195,17 @@ * - adjust the polling interval (Cyclades-Z); * * Revision 1.36.4.33 1997/06/27 19:00:00 ivan - * Fixes related to kernel version conditional + * Fixes related to kernel version conditional * compilation. - * + * * Revision 1.36.4.32 1997/06/14 19:30:00 ivan - * Compatibility issues between kernels 2.0.x and + * Compatibility issues between kernels 2.0.x and * 2.1.x (mainly related to clear_bit function). - * + * * Revision 1.36.4.31 1997/06/03 15:30:00 ivan - * Changes to define the memory window according to the + * Changes to define the memory window according to the * board type. - * + * * Revision 1.36.4.30 1997/05/16 15:30:00 daniel * Changes to support new cycladesZ boards. * @@ -624,7 +623,7 @@ #undef CY_PCI_DEBUG /* - * Include section + * Include section */ #include <linux/module.h> #include <linux/errno.h> @@ -649,9 +648,9 @@ #include <linux/firmware.h> #include <asm/system.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/irq.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <linux/kernel.h> #include <linux/pci.h> @@ -668,10 +667,10 @@ static void cy_send_xchar(struct tty_struct *tty, char ch); ((readl(&((struct RUNTIME_9060 __iomem *) \ ((card).ctl_addr))->init_ctrl) & (1<<17)) != 0) -#define ISZLOADED(card) (((ZO_V1==readl(&((struct RUNTIME_9060 __iomem *) \ +#define ISZLOADED(card) (((ZO_V1 == readl(&((struct RUNTIME_9060 __iomem *) \ ((card).ctl_addr))->mail_box_0)) || \ Z_FPGA_CHECK(card)) && \ - (ZFIRM_ID==readl(&((struct FIRM_ID __iomem *) \ + (ZFIRM_ID == readl(&((struct FIRM_ID __iomem *) \ ((card).base_addr+ID_ADDRESS))->signature))) #ifndef SERIAL_XMIT_SIZE @@ -809,12 +808,12 @@ static char baud_cor3[] = { /* receive threshold */ /* * The Cyclades driver implements HW flow control as any serial driver. - * The cyclades_port structure member rflow and the vector rflow_thr - * allows us to take advantage of a special feature in the CD1400 to avoid - * data loss even when the system interrupt latency is too high. These flags - * are to be used only with very special applications. Setting these flags - * requires the use of a special cable (DTR and RTS reversed). In the new - * CD1400-based boards (rev. 6.00 or later), there is no need for special + * The cyclades_port structure member rflow and the vector rflow_thr + * allows us to take advantage of a special feature in the CD1400 to avoid + * data loss even when the system interrupt latency is too high. These flags + * are to be used only with very special applications. Setting these flags + * requires the use of a special cable (DTR and RTS reversed). In the new + * CD1400-based boards (rev. 6.00 or later), there is no need for special * cables. */ @@ -841,14 +840,22 @@ static int cy_chip_offset[] = { 0x0000, #ifdef CONFIG_PCI static struct pci_device_id cy_pci_dev_id[] __devinitdata = { - { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) }, /* PCI < 1Mb */ - { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Hi) }, /* PCI > 1Mb */ - { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Lo) }, /* 4Y PCI < 1Mb */ - { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Hi) }, /* 4Y PCI > 1Mb */ - { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Lo) }, /* 8Y PCI < 1Mb */ - { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Hi) }, /* 8Y PCI > 1Mb */ - { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Lo) }, /* Z PCI < 1Mb */ - { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Hi) }, /* Z PCI > 1Mb */ + /* PCI < 1Mb */ + { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) }, + /* PCI > 1Mb */ + { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Hi) }, + /* 4Y PCI < 1Mb */ + { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Lo) }, + /* 4Y PCI > 1Mb */ + { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Hi) }, + /* 8Y PCI < 1Mb */ + { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Lo) }, + /* 8Y PCI > 1Mb */ + { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Hi) }, + /* Z PCI < 1Mb */ + { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Lo) }, + /* Z PCI > 1Mb */ + { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Hi) }, { } /* end of table */ }; MODULE_DEVICE_TABLE(pci, cy_pci_dev_id); @@ -905,15 +912,14 @@ static inline int serial_paranoia_check(struct cyclades_port *info, This function is only called from inside spinlock-protected code. */ -static int cyy_issue_cmd(void __iomem * base_addr, u_char cmd, int index) +static int cyy_issue_cmd(void __iomem *base_addr, u_char cmd, int index) { unsigned int i; /* Check to see that the previous command has completed */ for (i = 0; i < 100; i++) { - if (readb(base_addr + (CyCCR << index)) == 0) { + if (readb(base_addr + (CyCCR << index)) == 0) break; - } udelay(10L); } /* if the CCR never cleared, the previous command @@ -929,7 +935,7 @@ static int cyy_issue_cmd(void __iomem * base_addr, u_char cmd, int index) #ifdef CONFIG_ISA /* ISA interrupt detection code */ -static unsigned detect_isa_irq(void __iomem * address) +static unsigned detect_isa_irq(void __iomem *address) { int irq; unsigned long irqs, flags; @@ -1038,7 +1044,7 @@ static void cyy_chip_rx(struct cyclades_card *cinfo, int chip, if (info->flags & ASYNC_SAK) do_SAK(tty); } else if (data & CyFRAME) { - tty_insert_flip_char( tty, + tty_insert_flip_char(tty, readb(base_addr + (CyRDSR << index)), TTY_FRAME); info->icount.rx++; @@ -1320,7 +1326,8 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id) if (unlikely(cinfo == NULL)) { #ifdef CY_DEBUG_INTERRUPTS - printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",irq); + printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n", + irq); #endif return IRQ_NONE; /* spurious interrupt */ } @@ -1375,12 +1382,12 @@ static irqreturn_t cyy_interrupt(int irq, void *dev_id) /***********************************************************/ /********* End of block of Cyclom-Y specific code **********/ -/******** Start of block of Cyclades-Z specific code *********/ +/******** Start of block of Cyclades-Z specific code *******/ /***********************************************************/ static int cyz_fetch_msg(struct cyclades_card *cinfo, - __u32 * channel, __u8 * cmd, __u32 * param) + __u32 *channel, __u8 *cmd, __u32 *param) { struct FIRM_ID __iomem *firm_id; struct ZFW_CTRL __iomem *zfw_ctrl; @@ -1388,9 +1395,8 @@ cyz_fetch_msg(struct cyclades_card *cinfo, unsigned long loc_doorbell; firm_id = cinfo->base_addr + ID_ADDRESS; - if (!ISZLOADED(*cinfo)) { + if (!ISZLOADED(*cinfo)) return -1; - } zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; @@ -1418,9 +1424,9 @@ cyz_issue_cmd(struct cyclades_card *cinfo, unsigned int index; firm_id = cinfo->base_addr + ID_ADDRESS; - if (!ISZLOADED(*cinfo)) { + if (!ISZLOADED(*cinfo)) return -1; - } + zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; @@ -1428,9 +1434,8 @@ cyz_issue_cmd(struct cyclades_card *cinfo, pci_doorbell = &((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->pci_doorbell; while ((readl(pci_doorbell) & 0xff) != 0) { - if (index++ == 1000) { + if (index++ == 1000) return (int)(readl(pci_doorbell) & 0xff); - } udelay(50L); } cy_writel(&board_ctrl->hcmd_channel, channel); @@ -1504,7 +1509,8 @@ static void cyz_handle_rx(struct cyclades_port *info, while (len--) { data = readb(cinfo->base_addr + rx_bufaddr + new_rx_get); - new_rx_get = (new_rx_get + 1)& (rx_bufsize - 1); + new_rx_get = (new_rx_get + 1) & + (rx_bufsize - 1); tty_insert_flip_char(tty, data, TTY_NORMAL); info->idle_stats.recv_bytes++; info->icount.rx++; @@ -1636,7 +1642,8 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) special_count = 0; delta_count = 0; info = &cinfo->ports[channel]; - if ((tty = info->tty) == NULL) + tty = info->tty; + if (tty == NULL) continue; ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]); @@ -1732,7 +1739,8 @@ static irqreturn_t cyz_interrupt(int irq, void *dev_id) if (unlikely(cinfo == NULL)) { #ifdef CY_DEBUG_INTERRUPTS - printk(KERN_DEBUG "cyz_interrupt: spurious interrupt %d\n",irq); + printk(KERN_DEBUG "cyz_interrupt: spurious interrupt %d\n", + irq); #endif return IRQ_NONE; /* spurious interrupt */ } @@ -1851,9 +1859,8 @@ static int startup(struct cyclades_port *info) } if (!info->type) { - if (info->tty) { + if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); - } free_page(page); goto errout; } @@ -1904,9 +1911,8 @@ static int startup(struct cyclades_port *info) readb(base_addr + (CySRER << index)) | CyRxData); info->flags |= ASYNC_INITIALIZED; - if (info->tty) { + if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); - } info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; info->breakon = info->breakoff = 0; memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats)); @@ -1925,9 +1931,8 @@ static int startup(struct cyclades_port *info) base_addr = card->base_addr; firm_id = base_addr + ID_ADDRESS; - if (!ISZLOADED(*card)) { + if (!ISZLOADED(*card)) return -ENODEV; - } zfw_ctrl = card->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); @@ -1990,9 +1995,8 @@ static int startup(struct cyclades_port *info) /* enable send, recv, modem !!! */ info->flags |= ASYNC_INITIALIZED; - if (info->tty) { + if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); - } info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; info->breakon = info->breakoff = 0; memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats)); @@ -2061,9 +2065,8 @@ static void shutdown(struct cyclades_port *info) void __iomem *base_addr; int chip, channel, index; - if (!(info->flags & ASYNC_INITIALIZED)) { + if (!(info->flags & ASYNC_INITIALIZED)) return; - } card = info->card; channel = info->line - card->first_line; @@ -2105,9 +2108,8 @@ static void shutdown(struct cyclades_port *info) /* it may be appropriate to clear _XMIT at some later date (after testing)!!! */ - if (info->tty) { + if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); - } info->flags &= ~ASYNC_INITIALIZED; spin_unlock_irqrestore(&card->card_lock, flags); } else { @@ -2124,9 +2126,8 @@ static void shutdown(struct cyclades_port *info) #endif firm_id = base_addr + ID_ADDRESS; - if (!ISZLOADED(*card)) { + if (!ISZLOADED(*card)) return; - } zfw_ctrl = card->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); @@ -2157,9 +2158,8 @@ static void shutdown(struct cyclades_port *info) #endif } - if (info->tty) { + if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); - } info->flags &= ~ASYNC_INITIALIZED; spin_unlock_irqrestore(&card->card_lock, flags); @@ -2204,7 +2204,8 @@ block_til_ready(struct tty_struct *tty, struct file *filp, * If non-blocking mode is set, then make the check up front * and then exit. */ - if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { info->flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -2301,7 +2302,8 @@ block_til_ready(struct tty_struct *tty, struct file *filp, return -EINVAL; } - zfw_ctrl = base_addr + (readl(&firm_id->zfwctrl_addr)& 0xfffff); + zfw_ctrl = base_addr + (readl(&firm_id->zfwctrl_addr) + & 0xfffff); board_ctrl = &zfw_ctrl->board_ctrl; ch_ctrl = zfw_ctrl->ch_ctrl; @@ -2378,9 +2380,9 @@ static int cy_open(struct tty_struct *tty, struct file *filp) int retval; line = tty->index; - if ((tty->index < 0) || (NR_PORTS <= line)) { + if (tty->index < 0 || NR_PORTS <= line) return -ENODEV; - } + for (i = 0; i < NR_CARDS; i++) if (line < cy_card[i].first_line + cy_card[i].nports && line >= cy_card[i].first_line) @@ -2388,9 +2390,8 @@ static int cy_open(struct tty_struct *tty, struct file *filp) if (i >= NR_CARDS) return -ENODEV; info = &cy_card[i].ports[line - cy_card[i].first_line]; - if (info->line < 0) { + if (info->line < 0) return -ENODEV; - } /* If the card's firmware hasn't been loaded, treat it as absent from the system. This @@ -2456,9 +2457,9 @@ static int cy_open(struct tty_struct *tty, struct file *filp) #endif tty->driver_data = info; info->tty = tty; - if (serial_paranoia_check(info, tty->name, "cy_open")) { + if (serial_paranoia_check(info, tty->name, "cy_open")) return -ENODEV; - } + #ifdef CY_DEBUG_OPEN printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line, info->count); @@ -2482,9 +2483,8 @@ static int cy_open(struct tty_struct *tty, struct file *filp) * Start up serial port */ retval = startup(info); - if (retval) { + if (retval) return retval; - } retval = block_til_ready(tty, filp, info); if (retval) { @@ -2522,6 +2522,7 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout) return; /* Just in case.... */ orig_jiffies = jiffies; + lock_kernel(); /* * Set the check interval to be 1/5 of the estimated time to * send a single character, and make it at least 1. The check @@ -2573,11 +2574,47 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout) } /* Run one more char cycle */ msleep_interruptible(jiffies_to_msecs(char_time * 5)); + unlock_kernel(); #ifdef CY_DEBUG_WAIT_UNTIL_SENT printk(KERN_DEBUG "Clean (jiff=%lu)...done\n", jiffies); #endif } +static void cy_flush_buffer(struct tty_struct *tty) +{ + struct cyclades_port *info = tty->driver_data; + struct cyclades_card *card; + int channel, retval; + unsigned long flags; + +#ifdef CY_DEBUG_IO + printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line); +#endif + + if (serial_paranoia_check(info, tty->name, "cy_flush_buffer")) + return; + + card = info->card; + channel = info->line - card->first_line; + + spin_lock_irqsave(&card->card_lock, flags); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + spin_unlock_irqrestore(&card->card_lock, flags); + + if (IS_CYC_Z(*card)) { /* If it is a Z card, flush the on-board + buffers as well */ + spin_lock_irqsave(&card->card_lock, flags); + retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L); + if (retval != 0) { + printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d " + "was %x\n", info->line, retval); + } + spin_unlock_irqrestore(&card->card_lock, flags); + } + tty_wakeup(tty); +} /* cy_flush_buffer */ + + /* * This routine is called when a particular tty device is closed. */ @@ -2591,9 +2628,8 @@ static void cy_close(struct tty_struct *tty, struct file *filp) printk(KERN_DEBUG "cyc:cy_close ttyC%d\n", info->line); #endif - if (!info || serial_paranoia_check(info, tty->name, "cy_close")) { + if (!info || serial_paranoia_check(info, tty->name, "cy_close")) return; - } card = info->card; @@ -2641,9 +2677,9 @@ static void cy_close(struct tty_struct *tty, struct file *filp) */ tty->closing = 1; spin_unlock_irqrestore(&card->card_lock, flags); - if (info->closing_wait != CY_CLOSING_WAIT_NONE) { + if (info->closing_wait != CY_CLOSING_WAIT_NONE) tty_wait_until_sent(tty, info->closing_wait); - } + spin_lock_irqsave(&card->card_lock, flags); if (!IS_CYC_Z(*card)) { @@ -2657,15 +2693,16 @@ static void cy_close(struct tty_struct *tty, struct file *filp) cy_writeb(base_addr + (CySRER << index), readb(base_addr + (CySRER << index)) & ~CyRxData); if (info->flags & ASYNC_INITIALIZED) { - /* Waiting for on-board buffers to be empty before closing - the port */ + /* Waiting for on-board buffers to be empty before + closing the port */ spin_unlock_irqrestore(&card->card_lock, flags); cy_wait_until_sent(tty, info->timeout); spin_lock_irqsave(&card->card_lock, flags); } } else { #ifdef Z_WAKE - /* Waiting for on-board buffers to be empty before closing the port */ + /* Waiting for on-board buffers to be empty before closing + the port */ void __iomem *base_addr = card->base_addr; struct FIRM_ID __iomem *firm_id = base_addr + ID_ADDRESS; struct ZFW_CTRL __iomem *zfw_ctrl = @@ -2689,8 +2726,7 @@ static void cy_close(struct tty_struct *tty, struct file *filp) spin_unlock_irqrestore(&card->card_lock, flags); shutdown(info); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + cy_flush_buffer(tty); tty_ldisc_flush(tty); spin_lock_irqsave(&card->card_lock, flags); @@ -2738,17 +2774,16 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count) printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line); #endif - if (serial_paranoia_check(info, tty->name, "cy_write")) { + if (serial_paranoia_check(info, tty->name, "cy_write")) return 0; - } if (!info->xmit_buf) return 0; spin_lock_irqsave(&info->card->card_lock, flags); while (1) { - c = min(count, min((int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1), - (int)(SERIAL_XMIT_SIZE - info->xmit_head))); + c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1)); + c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head)); if (c <= 0) break; @@ -2766,9 +2801,9 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count) info->idle_stats.xmit_bytes += ret; info->idle_stats.xmit_idle = jiffies; - if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) { + if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) start_xmit(info); - } + return ret; } /* cy_write */ @@ -2779,7 +2814,7 @@ static int cy_write(struct tty_struct *tty, const unsigned char *buf, int count) * done stuffing characters into the driver. If there is no room * in the queue, the character is ignored. */ -static void cy_put_char(struct tty_struct *tty, unsigned char ch) +static int cy_put_char(struct tty_struct *tty, unsigned char ch) { struct cyclades_port *info = tty->driver_data; unsigned long flags; @@ -2789,15 +2824,15 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch) #endif if (serial_paranoia_check(info, tty->name, "cy_put_char")) - return; + return 0; if (!info->xmit_buf) - return; + return 0; spin_lock_irqsave(&info->card->card_lock, flags); if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) { spin_unlock_irqrestore(&info->card->card_lock, flags); - return; + return 0; } info->xmit_buf[info->xmit_head++] = ch; @@ -2806,11 +2841,12 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch) info->idle_stats.xmit_bytes++; info->idle_stats.xmit_idle = jiffies; spin_unlock_irqrestore(&info->card->card_lock, flags); + return 1; } /* cy_put_char */ /* * This routine is called by the kernel after it has written a - * series of characters to the tty device using put_char(). + * series of characters to the tty device using put_char(). */ static void cy_flush_chars(struct tty_struct *tty) { @@ -2882,6 +2918,7 @@ static int cy_chars_in_buffer(struct tty_struct *tty) int char_count; __u32 tx_put, tx_get, tx_bufsize; + lock_kernel(); firm_id = card->base_addr + ID_ADDRESS; zfw_ctrl = card->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); @@ -2899,6 +2936,7 @@ static int cy_chars_in_buffer(struct tty_struct *tty) printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt + char_count); #endif + unlock_kernel(); return info->xmit_cnt + char_count; } #endif /* Z_EXT_CHARS_IN_BUFFER */ @@ -2950,12 +2988,12 @@ static void set_line_char(struct cyclades_port *info) int baud, baud_rate = 0; int i; - if (!info->tty || !info->tty->termios) { + if (!info->tty || !info->tty->termios) return; - } - if (info->line == -1) { + + if (info->line == -1) return; - } + cflag = info->tty->termios->c_cflag; iflag = info->tty->termios->c_iflag; @@ -2994,13 +3032,11 @@ static void set_line_char(struct cyclades_port *info) } /* find the baud index */ for (i = 0; i < 20; i++) { - if (baud == baud_table[i]) { + if (baud == baud_table[i]) break; - } } - if (i == 20) { + if (i == 20) i = 19; /* CD1400_MAX_SPEED */ - } if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) { @@ -3059,18 +3095,16 @@ static void set_line_char(struct cyclades_port *info) info->cor1 = Cy_8_BITS; break; } - if (cflag & CSTOPB) { + if (cflag & CSTOPB) info->cor1 |= Cy_2_STOP; - } + if (cflag & PARENB) { - if (cflag & PARODD) { + if (cflag & PARODD) info->cor1 |= CyPARITY_O; - } else { + else info->cor1 |= CyPARITY_E; - } - } else { + } else info->cor1 |= CyPARITY_NONE; - } /* CTS flow control flag */ if (cflag & CRTSCTS) { @@ -3123,7 +3157,8 @@ static void set_line_char(struct cyclades_port *info) cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch | CyCOR3ch, index); - cy_writeb(base_addr + (CyCAR << index), (u_char) channel); /* !!! Is this needed? */ + /* !!! Is this needed? */ + cy_writeb(base_addr + (CyCAR << index), (u_char) channel); cy_writeb(base_addr + (CyRTPR << index), (info->default_timeout ? info->default_timeout : 0x02)); /* 10ms rx timeout */ @@ -3191,9 +3226,8 @@ static void set_line_char(struct cyclades_port *info) #endif } - if (info->tty) { + if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); - } spin_unlock_irqrestore(&card->card_lock, flags); } else { @@ -3206,9 +3240,8 @@ static void set_line_char(struct cyclades_port *info) int retval; firm_id = card->base_addr + ID_ADDRESS; - if (!ISZLOADED(*card)) { + if (!ISZLOADED(*card)) return; - } zfw_ctrl = card->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff); @@ -3268,14 +3301,12 @@ static void set_line_char(struct cyclades_port *info) readl(&ch_ctrl->comm_data_l) | C_DL_1STOP); } if (cflag & PARENB) { - if (cflag & PARODD) { + if (cflag & PARODD) cy_writel(&ch_ctrl->comm_parity, C_PR_ODD); - } else { + else cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN); - } - } else { + } else cy_writel(&ch_ctrl->comm_parity, C_PR_NONE); - } /* CTS flow control flag */ if (cflag & CRTSCTS) { @@ -3305,11 +3336,10 @@ static void set_line_char(struct cyclades_port *info) } /* CD sensitivity */ - if (cflag & CLOCAL) { + if (cflag & CLOCAL) info->flags &= ~ASYNC_CHECK_CD; - } else { + else info->flags |= ASYNC_CHECK_CD; - } if (baud == 0) { /* baud rate is zero, turn off line */ cy_writel(&ch_ctrl->rs_control, @@ -3325,21 +3355,20 @@ static void set_line_char(struct cyclades_port *info) #endif } - retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM,0L); + retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L); if (retval != 0) { printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d " "was %x\n", info->line, retval); } - if (info->tty) { + if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); - } } } /* set_line_char */ static int get_serial_info(struct cyclades_port *info, - struct serial_struct __user * retinfo) + struct serial_struct __user *retinfo) { struct serial_struct tmp; struct cyclades_card *cinfo = info->card; @@ -3363,7 +3392,7 @@ get_serial_info(struct cyclades_port *info, static int set_serial_info(struct cyclades_port *info, - struct serial_struct __user * new_info) + struct serial_struct __user *new_info) { struct serial_struct new_serial; struct cyclades_port old_info; @@ -3417,7 +3446,7 @@ check_and_exit: * 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 __user * value) +static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value) { struct cyclades_card *card; int chip, channel, index; @@ -3461,9 +3490,11 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file) struct BOARD_CTRL __iomem *board_ctrl; struct CH_CTRL __iomem *ch_ctrl; - if (serial_paranoia_check(info, tty->name, __FUNCTION__)) + if (serial_paranoia_check(info, tty->name, __func__)) return -ENODEV; + lock_kernel(); + card = info->card; channel = info->line - card->first_line; if (!IS_CYC_Z(*card)) { @@ -3506,10 +3537,12 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file) ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0); } else { result = 0; + unlock_kernel(); return -ENODEV; } } + unlock_kernel(); return result; } /* cy_tiomget */ @@ -3528,7 +3561,7 @@ cy_tiocmset(struct tty_struct *tty, struct file *file, struct CH_CTRL __iomem *ch_ctrl; int retval; - if (serial_paranoia_check(info, tty->name, __FUNCTION__)) + if (serial_paranoia_check(info, tty->name, __func__)) return -ENODEV; card = info->card; @@ -3727,8 +3760,8 @@ static void cy_break(struct tty_struct *tty, int break_state) spin_unlock_irqrestore(&card->card_lock, flags); } /* cy_break */ -static int -get_mon_info(struct cyclades_port *info, struct cyclades_monitor __user * mon) +static int get_mon_info(struct cyclades_port *info, + struct cyclades_monitor __user *mon) { if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor))) @@ -3767,8 +3800,8 @@ static int set_threshold(struct cyclades_port *info, unsigned long value) return 0; } /* set_threshold */ -static int -get_threshold(struct cyclades_port *info, unsigned long __user * value) +static int get_threshold(struct cyclades_port *info, + unsigned long __user *value) { struct cyclades_card *card; void __iomem *base_addr; @@ -3789,15 +3822,15 @@ get_threshold(struct cyclades_port *info, unsigned long __user * value) return 0; } /* get_threshold */ -static int -set_default_threshold(struct cyclades_port *info, unsigned long value) +static int set_default_threshold(struct cyclades_port *info, + unsigned long value) { info->default_threshold = value & 0x0f; return 0; } /* set_default_threshold */ -static int -get_default_threshold(struct cyclades_port *info, unsigned long __user * value) +static int get_default_threshold(struct cyclades_port *info, + unsigned long __user *value) { return put_user(info->default_threshold, value); } /* get_default_threshold */ @@ -3824,7 +3857,8 @@ static int set_timeout(struct cyclades_port *info, unsigned long value) return 0; } /* set_timeout */ -static int get_timeout(struct cyclades_port *info, unsigned long __user * value) +static int get_timeout(struct cyclades_port *info, + unsigned long __user *value) { struct cyclades_card *card; void __iomem *base_addr; @@ -3851,8 +3885,8 @@ static int set_default_timeout(struct cyclades_port *info, unsigned long value) return 0; } /* set_default_timeout */ -static int -get_default_timeout(struct cyclades_port *info, unsigned long __user * value) +static int get_default_timeout(struct cyclades_port *info, + unsigned long __user *value) { return put_user(info->default_timeout, value); } /* get_default_timeout */ @@ -3880,6 +3914,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file, printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n", info->line, cmd, arg); #endif + lock_kernel(); switch (cmd) { case CYGETMON: @@ -3936,7 +3971,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file, break; #endif /* CONFIG_CYZ_INTR */ case CYSETWAIT: - info->closing_wait = (unsigned short)arg *HZ / 100; + info->closing_wait = (unsigned short)arg * HZ / 100; ret_val = 0; break; case CYGETWAIT: @@ -3988,47 +4023,47 @@ cy_ioctl(struct tty_struct *tty, struct file *file, p_cuser = argp; ret_val = put_user(cnow.cts, &p_cuser->cts); if (ret_val) - return ret_val; + break; ret_val = put_user(cnow.dsr, &p_cuser->dsr); if (ret_val) - return ret_val; + break; ret_val = put_user(cnow.rng, &p_cuser->rng); if (ret_val) - return ret_val; + break; ret_val = put_user(cnow.dcd, &p_cuser->dcd); if (ret_val) - return ret_val; + break; ret_val = put_user(cnow.rx, &p_cuser->rx); if (ret_val) - return ret_val; + break; ret_val = put_user(cnow.tx, &p_cuser->tx); if (ret_val) - return ret_val; + break; ret_val = put_user(cnow.frame, &p_cuser->frame); if (ret_val) - return ret_val; + break; ret_val = put_user(cnow.overrun, &p_cuser->overrun); if (ret_val) - return ret_val; + break; ret_val = put_user(cnow.parity, &p_cuser->parity); if (ret_val) - return ret_val; + break; ret_val = put_user(cnow.brk, &p_cuser->brk); if (ret_val) - return ret_val; + break; ret_val = put_user(cnow.buf_overrun, &p_cuser->buf_overrun); if (ret_val) - return ret_val; + break; ret_val = 0; break; default: ret_val = -ENOIOCTLCMD; } + unlock_kernel(); #ifdef CY_DEBUG_OTHER printk(KERN_DEBUG "cyc:cy_ioctl done\n"); #endif - return ret_val; } /* cy_ioctl */ @@ -4113,9 +4148,8 @@ static void cy_throttle(struct tty_struct *tty) tty->ldisc.chars_in_buffer(tty), info->line); #endif - if (serial_paranoia_check(info, tty->name, "cy_throttle")) { + if (serial_paranoia_check(info, tty->name, "cy_throttle")) return; - } card = info->card; @@ -4169,12 +4203,11 @@ static void cy_unthrottle(struct tty_struct *tty) char buf[64]; printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n", - tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty),info->line); + tty_name(tty, buf), tty_chars_in_buffer(tty), info->line); #endif - if (serial_paranoia_check(info, tty->name, "cy_unthrottle")) { + if (serial_paranoia_check(info, tty->name, "cy_unthrottle")) return; - } if (I_IXOFF(tty)) { if (info->x_char) @@ -4269,47 +4302,14 @@ static void cy_start(struct tty_struct *tty) base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index); spin_lock_irqsave(&cinfo->card_lock, flags); - cy_writeb(base_addr + (CyCAR << index), (u_char) (channel & 0x0003)); /* index channel */ + cy_writeb(base_addr + (CyCAR << index), + (u_char) (channel & 0x0003)); /* index channel */ cy_writeb(base_addr + (CySRER << index), readb(base_addr + (CySRER << index)) | CyTxRdy); spin_unlock_irqrestore(&cinfo->card_lock, flags); } } /* cy_start */ -static void cy_flush_buffer(struct tty_struct *tty) -{ - struct cyclades_port *info = tty->driver_data; - struct cyclades_card *card; - int channel, retval; - unsigned long flags; - -#ifdef CY_DEBUG_IO - printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line); -#endif - - if (serial_paranoia_check(info, tty->name, "cy_flush_buffer")) - return; - - card = info->card; - channel = info->line - card->first_line; - - spin_lock_irqsave(&card->card_lock, flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - spin_unlock_irqrestore(&card->card_lock, flags); - - if (IS_CYC_Z(*card)) { /* If it is a Z card, flush the on-board - buffers as well */ - spin_lock_irqsave(&card->card_lock, flags); - retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L); - if (retval != 0) { - printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d " - "was %x\n", info->line, retval); - } - spin_unlock_irqrestore(&card->card_lock, flags); - } - tty_wakeup(tty); -} /* cy_flush_buffer */ - /* * cy_hangup() --- called by tty_hangup() when a hangup is signaled. */ @@ -4406,10 +4406,11 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo) info->cor3 = 0x08; /* _very_ small rcv threshold */ chip_number = (port - cinfo->first_line) / 4; - if ((info->chip_rev = readb(cinfo->base_addr + - (cy_chip_offset[chip_number] << - index) + (CyGFRCR << index))) >= - CD1400_REV_J) { + info->chip_rev = readb(cinfo->base_addr + + (cy_chip_offset[chip_number] << index) + + (CyGFRCR << index)); + + if (info->chip_rev >= CD1400_REV_J) { /* It is a CD1400 rev. J or later */ info->tbpr = baud_bpr_60[13]; /* Tx BPR */ info->tco = baud_co_60[13]; /* Tx CO */ @@ -4454,7 +4455,8 @@ static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr, /* Cy_ClrIntr is 0x1800 */ udelay(500L); - for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD; chip_number++) { + for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD; + chip_number++) { base_addr = true_base_addr + (cy_chip_offset[chip_number] << index); mdelay(1); @@ -4555,12 +4557,11 @@ static int __init cy_detect_isa(void) /* scan the address table probing for Cyclom-Y/ISA boards */ for (i = 0; i < NR_ISA_ADDRS; i++) { unsigned int isa_address = cy_isa_addresses[i]; - if (isa_address == 0x0000) { + if (isa_address == 0x0000) return nboard; - } /* probe for CD1400... */ - cy_isa_address = ioremap(isa_address, CyISA_Ywin); + cy_isa_address = ioremap_nocache(isa_address, CyISA_Ywin); if (cy_isa_address == NULL) { printk(KERN_ERR "Cyclom-Y/ISA: can't remap base " "address\n"); @@ -4847,12 +4848,10 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr, if (mailbox != 0) { /* set window to last 512K of RAM */ cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE); - //sleep(1); for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++) cy_writeb(tmp, 255); /* set window to beginning of RAM */ cy_writel(&ctl_addr->loc_addr_base, WIN_RAM); - //sleep(1); } retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, base_addr, NULL); @@ -5382,7 +5381,8 @@ static void __exit cy_cleanup_module(void) del_timer_sync(&cyz_timerlist); #endif /* CONFIG_CYZ_INTR */ - if ((e1 = tty_unregister_driver(cy_serial_driver))) + e1 = tty_unregister_driver(cy_serial_driver); + if (e1) printk(KERN_ERR "failed to unregister Cyclades serial " "driver(%d)\n", e1); diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h index ecee3547a13f..213b3ca3468e 100644 --- a/drivers/char/drm/drmP.h +++ b/drivers/char/drm/drmP.h @@ -160,7 +160,7 @@ struct drm_device; * \param arg arguments */ #define DRM_ERROR(fmt, arg...) \ - printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* " fmt , __FUNCTION__ , ##arg) + printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* " fmt , __func__ , ##arg) /** * Memory error output. @@ -170,7 +170,7 @@ struct drm_device; * \param arg arguments */ #define DRM_MEM_ERROR(area, fmt, arg...) \ - printk(KERN_ERR "[" DRM_NAME ":%s:%s] *ERROR* " fmt , __FUNCTION__, \ + printk(KERN_ERR "[" DRM_NAME ":%s:%s] *ERROR* " fmt , __func__, \ drm_mem_stats[area].name , ##arg) #define DRM_INFO(fmt, arg...) printk(KERN_INFO "[" DRM_NAME "] " fmt , ##arg) @@ -187,7 +187,7 @@ struct drm_device; if ( drm_debug ) \ printk(KERN_DEBUG \ "[" DRM_NAME ":%s] " fmt , \ - __FUNCTION__ , ##arg); \ + __func__ , ##arg); \ } while (0) #else #define DRM_DEBUG(fmt, arg...) do { } while (0) @@ -238,7 +238,7 @@ do { \ if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \ dev->lock.file_priv != file_priv ) { \ DRM_ERROR( "%s called without lock held, held %d owner %p %p\n",\ - __FUNCTION__, _DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ),\ + __func__, _DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ),\ dev->lock.file_priv, file_priv ); \ return -EINVAL; \ } \ diff --git a/drivers/char/drm/drm_sysfs.c b/drivers/char/drm/drm_sysfs.c index 7a1d9a782ddb..9a32169e88fb 100644 --- a/drivers/char/drm/drm_sysfs.c +++ b/drivers/char/drm/drm_sysfs.c @@ -34,7 +34,7 @@ static int drm_sysfs_suspend(struct device *dev, pm_message_t state) struct drm_minor *drm_minor = to_drm_minor(dev); struct drm_device *drm_dev = drm_minor->dev; - printk(KERN_ERR "%s\n", __FUNCTION__); + printk(KERN_ERR "%s\n", __func__); if (drm_dev->driver->suspend) return drm_dev->driver->suspend(drm_dev, state); diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c index 60c9376be486..a86ab30b4620 100644 --- a/drivers/char/drm/i830_dma.c +++ b/drivers/char/drm/i830_dma.c @@ -692,7 +692,7 @@ static void i830EmitState(struct drm_device * dev) drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv; unsigned int dirty = sarea_priv->dirty; - DRM_DEBUG("%s %x\n", __FUNCTION__, dirty); + DRM_DEBUG("%s %x\n", __func__, dirty); if (dirty & I830_UPLOAD_BUFFERS) { i830EmitDestVerified(dev, sarea_priv->BufferState); @@ -1043,7 +1043,7 @@ static void i830_dma_dispatch_flip(struct drm_device * dev) RING_LOCALS; DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n", - __FUNCTION__, + __func__, dev_priv->current_page, dev_priv->sarea_priv->pf_current_page); @@ -1206,7 +1206,7 @@ static void i830_dma_quiescent(struct drm_device * dev) OUT_RING(0); ADVANCE_LP_RING(); - i830_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__); + i830_wait_ring(dev, dev_priv->ring.Size - 8, __func__); } static int i830_flush_queue(struct drm_device * dev) @@ -1223,7 +1223,7 @@ static int i830_flush_queue(struct drm_device * dev) OUT_RING(0); ADVANCE_LP_RING(); - i830_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__); + i830_wait_ring(dev, dev_priv->ring.Size - 8, __func__); for (i = 0; i < dma->buf_count; i++) { struct drm_buf *buf = dma->buflist[i]; @@ -1344,7 +1344,7 @@ static void i830_do_init_pageflip(struct drm_device * dev) { drm_i830_private_t *dev_priv = dev->dev_private; - DRM_DEBUG("%s\n", __FUNCTION__); + DRM_DEBUG("%s\n", __func__); dev_priv->page_flipping = 1; dev_priv->current_page = 0; dev_priv->sarea_priv->pf_current_page = dev_priv->current_page; @@ -1354,7 +1354,7 @@ static int i830_do_cleanup_pageflip(struct drm_device * dev) { drm_i830_private_t *dev_priv = dev->dev_private; - DRM_DEBUG("%s\n", __FUNCTION__); + DRM_DEBUG("%s\n", __func__); if (dev_priv->current_page != 0) i830_dma_dispatch_flip(dev); @@ -1367,7 +1367,7 @@ static int i830_flip_bufs(struct drm_device *dev, void *data, { drm_i830_private_t *dev_priv = dev->dev_private; - DRM_DEBUG("%s\n", __FUNCTION__); + DRM_DEBUG("%s\n", __func__); LOCK_TEST_WITH_RETURN(dev, file_priv); @@ -1437,7 +1437,7 @@ static int i830_getparam(struct drm_device *dev, void *data, int value; if (!dev_priv) { - DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + DRM_ERROR("%s called with no initialization\n", __func__); return -EINVAL; } @@ -1464,7 +1464,7 @@ static int i830_setparam(struct drm_device *dev, void *data, drm_i830_setparam_t *param = data; if (!dev_priv) { - DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + DRM_ERROR("%s called with no initialization\n", __func__); return -EINVAL; } diff --git a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h index 4caba8c54455..b5bf8cc0fdaa 100644 --- a/drivers/char/drm/i830_drv.h +++ b/drivers/char/drm/i830_drv.h @@ -158,7 +158,7 @@ extern int i830_driver_device_is_agp(struct drm_device * dev); if (I830_VERBOSE) \ printk("BEGIN_LP_RING(%d)\n", (n)); \ if (dev_priv->ring.space < n*4) \ - i830_wait_ring(dev, n*4, __FUNCTION__); \ + i830_wait_ring(dev, n*4, __func__); \ outcount = 0; \ outring = dev_priv->ring.tail; \ ringmask = dev_priv->ring.tail_mask; \ diff --git a/drivers/char/drm/i830_irq.c b/drivers/char/drm/i830_irq.c index a33db5f0967f..91ec2bb497e9 100644 --- a/drivers/char/drm/i830_irq.c +++ b/drivers/char/drm/i830_irq.c @@ -58,7 +58,7 @@ static int i830_emit_irq(struct drm_device * dev) drm_i830_private_t *dev_priv = dev->dev_private; RING_LOCALS; - DRM_DEBUG("%s\n", __FUNCTION__); + DRM_DEBUG("%s\n", __func__); atomic_inc(&dev_priv->irq_emitted); @@ -77,7 +77,7 @@ static int i830_wait_irq(struct drm_device * dev, int irq_nr) unsigned long end = jiffies + HZ * 3; int ret = 0; - DRM_DEBUG("%s\n", __FUNCTION__); + DRM_DEBUG("%s\n", __func__); if (atomic_read(&dev_priv->irq_received) >= irq_nr) return 0; @@ -124,7 +124,7 @@ int i830_irq_emit(struct drm_device *dev, void *data, LOCK_TEST_WITH_RETURN(dev, file_priv); if (!dev_priv) { - DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + DRM_ERROR("%s called with no initialization\n", __func__); return -EINVAL; } @@ -147,7 +147,7 @@ int i830_irq_wait(struct drm_device *dev, void *data, drm_i830_irq_wait_t *irqwait = data; if (!dev_priv) { - DRM_ERROR("%s called with no initialization\n", __FUNCTION__); + DRM_ERROR("%s called with no initialization\n", __func__); return -EINVAL; } diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c index ef7bf143a80c..f47e46e3529f 100644 --- a/drivers/char/drm/i915_dma.c +++ b/drivers/char/drm/i915_dma.c @@ -194,7 +194,7 @@ static int i915_dma_resume(struct drm_device * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - DRM_DEBUG("%s\n", __FUNCTION__); + DRM_DEBUG("%s\n", __func__); if (!dev_priv->sarea) { DRM_ERROR("can not find sarea!\n"); @@ -609,7 +609,7 @@ static int i915_quiescent(struct drm_device * dev) drm_i915_private_t *dev_priv = dev->dev_private; i915_kernel_lost_context(dev); - return i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__); + return i915_wait_ring(dev, dev_priv->ring.Size - 8, __func__); } static int i915_flush_ioctl(struct drm_device *dev, void *data, diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h index c614d78b3dfd..db7001f22561 100644 --- a/drivers/char/drm/i915_drv.h +++ b/drivers/char/drm/i915_drv.h @@ -272,7 +272,7 @@ extern void i915_mem_release(struct drm_device * dev, if (I915_VERBOSE) \ DRM_DEBUG("BEGIN_LP_RING(%d)\n", (n)); \ if (dev_priv->ring.space < (n)*4) \ - i915_wait_ring(dev, (n)*4, __FUNCTION__); \ + i915_wait_ring(dev, (n)*4, __func__); \ outcount = 0; \ outring = dev_priv->ring.tail; \ ringmask = dev_priv->ring.tail_mask; \ diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c index 9072e4a1894e..f6f6c92bf771 100644 --- a/drivers/char/drm/radeon_cp.c +++ b/drivers/char/drm/radeon_cp.c @@ -894,7 +894,7 @@ static u32 RADEON_READ_IGPGART(drm_radeon_private_t *dev_priv, int addr) #if RADEON_FIFO_DEBUG static void radeon_status(drm_radeon_private_t * dev_priv) { - printk("%s:\n", __FUNCTION__); + printk("%s:\n", __func__); printk("RBBM_STATUS = 0x%08x\n", (unsigned int)RADEON_READ(RADEON_RBBM_STATUS)); printk("CP_RB_RTPR = 0x%08x\n", diff --git a/drivers/char/ds1286.c b/drivers/char/ds1286.c index 59146e3365ba..ea35ab2c9909 100644 --- a/drivers/char/ds1286.c +++ b/drivers/char/ds1286.c @@ -39,6 +39,7 @@ #include <linux/spinlock.h> #include <linux/bcd.h> #include <linux/proc_fs.h> +#include <linux/jiffies.h> #include <asm/uaccess.h> #include <asm/system.h> @@ -451,7 +452,7 @@ static void ds1286_get_time(struct rtc_time *rtc_tm) */ if (ds1286_is_updating() != 0) - while (jiffies - uip_watchdog < 2*HZ/100) + while (time_before(jiffies, uip_watchdog + 2*HZ/100)) barrier(); /* diff --git a/drivers/char/epca.c b/drivers/char/epca.c index ffd747c5dff0..60a4df7dac12 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -38,8 +38,8 @@ #include <linux/slab.h> #include <linux/ioport.h> #include <linux/interrupt.h> -#include <asm/uaccess.h> -#include <asm/io.h> +#include <linux/uaccess.h> +#include <linux/io.h> #include <linux/spinlock.h> #include <linux/pci.h> #include "digiPCI.h" @@ -73,7 +73,8 @@ static int invalid_lilo_config; */ static DEFINE_SPINLOCK(epca_lock); -/* MAXBOARDS is typically 12, but ISA and EISA cards are restricted to 7 below. */ +/* MAXBOARDS is typically 12, but ISA and EISA cards are restricted + to 7 below. */ static struct board_info boards[MAXBOARDS]; static struct tty_driver *pc_driver; @@ -157,13 +158,12 @@ static void epca_error(int, char *); static void pc_close(struct tty_struct *, struct file *); static void shutdown(struct channel *); static void pc_hangup(struct tty_struct *); -static void pc_put_char(struct tty_struct *, unsigned char); static int pc_write_room(struct tty_struct *); static int pc_chars_in_buffer(struct tty_struct *); static void pc_flush_buffer(struct tty_struct *); static void pc_flush_chars(struct tty_struct *); static int block_til_ready(struct tty_struct *, struct file *, - struct channel *); + struct channel *); static int pc_open(struct tty_struct *, struct file *); static void post_fep_init(unsigned int crd); static void epcapoll(unsigned long); @@ -175,18 +175,18 @@ static unsigned termios2digi_c(struct channel *ch, unsigned); static void epcaparam(struct tty_struct *, struct channel *); static void receive_data(struct channel *); static int pc_ioctl(struct tty_struct *, struct file *, - unsigned int, unsigned long); + unsigned int, unsigned long); static int info_ioctl(struct tty_struct *, struct file *, - unsigned int, unsigned long); + unsigned int, unsigned long); static void pc_set_termios(struct tty_struct *, struct ktermios *); static void do_softint(struct work_struct *work); static void pc_stop(struct tty_struct *); static void pc_start(struct tty_struct *); -static void pc_throttle(struct tty_struct * tty); +static void pc_throttle(struct tty_struct *tty); static void pc_unthrottle(struct tty_struct *tty); static void digi_send_break(struct channel *ch, int msec); static void setup_empty_event(struct tty_struct *tty, struct channel *ch); -void epca_setup(char *, int *); +static void epca_setup(char *, int *); static int pc_write(struct tty_struct *, const unsigned char *, int); static int pc_init(void); @@ -243,7 +243,7 @@ static void assertmemoff(struct channel *ch) /* PCXEM windowing is the same as that used in the PCXR and CX series cards. */ static void pcxem_memwinon(struct board_info *b, unsigned int win) { - outb_p(FEPWIN|win, b->port + 1); + outb_p(FEPWIN | win, b->port + 1); } static void pcxem_memwinoff(struct board_info *b, unsigned int win) @@ -253,7 +253,7 @@ static void pcxem_memwinoff(struct board_info *b, unsigned int win) static void pcxem_globalwinon(struct channel *ch) { - outb_p( FEPWIN, (int)ch->board->port + 1); + outb_p(FEPWIN, (int)ch->board->port + 1); } static void pcxem_rxwinon(struct channel *ch) @@ -394,7 +394,7 @@ static struct channel *verifyChannel(struct tty_struct *tty) */ if (tty) { struct channel *ch = (struct channel *)tty->driver_data; - if ((ch >= &digi_channels[0]) && (ch < &digi_channels[nbdevs])) { + if (ch >= &digi_channels[0] && ch < &digi_channels[nbdevs]) { if (ch->magic == EPCA_MAGIC) return ch; } @@ -414,7 +414,7 @@ static void pc_sched_event(struct channel *ch, int event) static void epca_error(int line, char *msg) { - printk(KERN_ERR "epca_error (Digi): line = %d %s\n",line,msg); + printk(KERN_ERR "epca_error (Digi): line = %d %s\n", line, msg); } static void pc_close(struct tty_struct *tty, struct file *filp) @@ -425,7 +425,8 @@ static void pc_close(struct tty_struct *tty, struct file *filp) * verifyChannel returns the channel from the tty struct if it is * valid. This serves as a sanity check. */ - if ((ch = verifyChannel(tty)) != NULL) { + ch = verifyChannel(tty); + if (ch != NULL) { spin_lock_irqsave(&epca_lock, flags); if (tty_hung_up_p(filp)) { spin_unlock_irqrestore(&epca_lock, flags); @@ -440,7 +441,6 @@ static void pc_close(struct tty_struct *tty, struct file *filp) spin_unlock_irqrestore(&epca_lock, flags); return; } - /* Port open only once go ahead with shutdown & reset */ BUG_ON(ch->count < 0); @@ -455,12 +455,13 @@ static void pc_close(struct tty_struct *tty, struct file *filp) spin_unlock_irqrestore(&epca_lock, flags); if (ch->asyncflags & ASYNC_INITIALIZED) { - /* Setup an event to indicate when the transmit buffer empties */ + /* Setup an event to indicate when the + transmit buffer empties */ setup_empty_event(tty, ch); - tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */ + /* 30 seconds timeout */ + tty_wait_until_sent(tty, 3000); } - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + pc_flush_buffer(tty); tty_ldisc_flush(tty); shutdown(ch); @@ -477,7 +478,7 @@ static void pc_close(struct tty_struct *tty, struct file *filp) wake_up_interruptible(&ch->open_wait); } ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED | - ASYNC_CLOSING); + ASYNC_CLOSING); wake_up_interruptible(&ch->close_wait); } } @@ -524,16 +525,15 @@ static void shutdown(struct channel *ch) static void pc_hangup(struct tty_struct *tty) { struct channel *ch; - /* * verifyChannel returns the channel from the tty struct if it is * valid. This serves as a sanity check. */ - if ((ch = verifyChannel(tty)) != NULL) { + ch = verifyChannel(tty); + if (ch != NULL) { unsigned long flags; - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + pc_flush_buffer(tty); tty_ldisc_flush(tty); shutdown(ch); @@ -548,7 +548,7 @@ static void pc_hangup(struct tty_struct *tty) } static int pc_write(struct tty_struct *tty, - const unsigned char *buf, int bytesAvailable) + const unsigned char *buf, int bytesAvailable) { unsigned int head, tail; int dataLen; @@ -572,7 +572,8 @@ static int pc_write(struct tty_struct *tty, * verifyChannel returns the channel from the tty struct if it is * valid. This serves as a sanity check. */ - if ((ch = verifyChannel(tty)) == NULL) + ch = verifyChannel(tty); + if (ch == NULL) return 0; /* Make a pointer to the channel data structure found on the board. */ @@ -645,26 +646,19 @@ static int pc_write(struct tty_struct *tty, return amountCopied; } -static void pc_put_char(struct tty_struct *tty, unsigned char c) -{ - pc_write(tty, &c, 1); -} - static int pc_write_room(struct tty_struct *tty) { - int remain; + int remain = 0; struct channel *ch; unsigned long flags; unsigned int head, tail; struct board_chan __iomem *bc; - - remain = 0; - /* * verifyChannel returns the channel from the tty struct if it is * valid. This serves as a sanity check. */ - if ((ch = verifyChannel(tty)) != NULL) { + ch = verifyChannel(tty); + if (ch != NULL) { spin_lock_irqsave(&epca_lock, flags); globalwinon(ch); @@ -676,8 +670,8 @@ static int pc_write_room(struct tty_struct *tty) tail = readw(&bc->tout); /* Wrap tail if necessary */ tail &= (ch->txbufsize - 1); - - if ((remain = tail - head - 1) < 0 ) + remain = tail - head - 1; + if (remain < 0) remain += ch->txbufsize; if (remain && (ch->statusflags & LOWWAIT) == 0) { @@ -699,12 +693,12 @@ static int pc_chars_in_buffer(struct tty_struct *tty) unsigned long flags; struct channel *ch; struct board_chan __iomem *bc; - /* * verifyChannel returns the channel from the tty struct if it is * valid. This serves as a sanity check. */ - if ((ch = verifyChannel(tty)) == NULL) + ch = verifyChannel(tty); + if (ch == NULL) return 0; spin_lock_irqsave(&epca_lock, flags); @@ -715,7 +709,8 @@ static int pc_chars_in_buffer(struct tty_struct *tty) head = readw(&bc->tin); ctail = readw(&ch->mailbox->cout); - if (tail == head && readw(&ch->mailbox->cin) == ctail && readb(&bc->tbusy) == 0) + if (tail == head && readw(&ch->mailbox->cin) == ctail && + readb(&bc->tbusy) == 0) chars = 0; else { /* Begin if some space on the card has been used */ head = readw(&bc->tin) & (ch->txbufsize - 1); @@ -725,7 +720,8 @@ static int pc_chars_in_buffer(struct tty_struct *tty) * pc_write_room here we are finding the amount of bytes in the * buffer filled. Not the amount of bytes empty. */ - if ((remain = tail - head - 1) < 0 ) + remain = tail - head - 1; + if (remain < 0) remain += ch->txbufsize; chars = (int)(ch->txbufsize - remain); /* @@ -736,7 +732,7 @@ static int pc_chars_in_buffer(struct tty_struct *tty) * transmit buffer empties. */ if (!(ch->statusflags & EMPTYWAIT)) - setup_empty_event(tty,ch); + setup_empty_event(tty, ch); } /* End if some space on the card has been used */ memoff(ch); spin_unlock_irqrestore(&epca_lock, flags); @@ -754,7 +750,8 @@ static void pc_flush_buffer(struct tty_struct *tty) * verifyChannel returns the channel from the tty struct if it is * valid. This serves as a sanity check. */ - if ((ch = verifyChannel(tty)) == NULL) + ch = verifyChannel(tty); + if (ch == NULL) return; spin_lock_irqsave(&epca_lock, flags); @@ -775,23 +772,25 @@ static void pc_flush_chars(struct tty_struct *tty) * verifyChannel returns the channel from the tty struct if it is * valid. This serves as a sanity check. */ - if ((ch = verifyChannel(tty)) != NULL) { + ch = verifyChannel(tty); + if (ch != NULL) { unsigned long flags; spin_lock_irqsave(&epca_lock, flags); /* * If not already set and the transmitter is busy setup an * event to indicate when the transmit empties. */ - if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT)) - setup_empty_event(tty,ch); + if ((ch->statusflags & TXBUSY) && + !(ch->statusflags & EMPTYWAIT)) + setup_empty_event(tty, ch); spin_unlock_irqrestore(&epca_lock, flags); } } static int block_til_ready(struct tty_struct *tty, - struct file *filp, struct channel *ch) + struct file *filp, struct channel *ch) { - DECLARE_WAITQUEUE(wait,current); + DECLARE_WAITQUEUE(wait, current); int retval, do_clocal = 0; unsigned long flags; @@ -839,8 +838,7 @@ static int block_til_ready(struct tty_struct *tty, while (1) { set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || - !(ch->asyncflags & ASYNC_INITIALIZED)) - { + !(ch->asyncflags & ASYNC_INITIALIZED)) { if (ch->asyncflags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else @@ -880,7 +878,7 @@ static int block_til_ready(struct tty_struct *tty, return 0; } -static int pc_open(struct tty_struct *tty, struct file * filp) +static int pc_open(struct tty_struct *tty, struct file *filp) { struct channel *ch; unsigned long flags; @@ -923,7 +921,8 @@ static int pc_open(struct tty_struct *tty, struct file * filp) return(-ENODEV); } - if ((bc = ch->brdchan) == 0) { + bc = ch->brdchan; + if (bc == NULL) { tty->driver_data = NULL; return -ENODEV; } @@ -964,7 +963,7 @@ static int pc_open(struct tty_struct *tty, struct file * filp) * The below routine generally sets up parity, baud, flow control * issues, etc.... It effect both control flags and input flags. */ - epcaparam(tty,ch); + epcaparam(tty, ch); ch->asyncflags |= ASYNC_INITIALIZED; memoff(ch); spin_unlock_irqrestore(&epca_lock, flags); @@ -1002,8 +1001,8 @@ static void __exit epca_module_exit(void) del_timer_sync(&epca_timer); - if (tty_unregister_driver(pc_driver) || tty_unregister_driver(pc_info)) - { + if (tty_unregister_driver(pc_driver) || + tty_unregister_driver(pc_info)) { printk(KERN_WARNING "epca: cleanup_module failed to un-register tty driver\n"); return; } @@ -1034,7 +1033,6 @@ static const struct tty_operations pc_ops = { .flush_buffer = pc_flush_buffer, .chars_in_buffer = pc_chars_in_buffer, .flush_chars = pc_flush_chars, - .put_char = pc_put_char, .ioctl = pc_ioctl, .set_termios = pc_set_termios, .stop = pc_stop, @@ -1044,7 +1042,7 @@ static const struct tty_operations pc_ops = { .hangup = pc_hangup, }; -static int info_open(struct tty_struct *tty, struct file * filp) +static int info_open(struct tty_struct *tty, struct file *filp) { return 0; } @@ -1099,7 +1097,7 @@ static int __init pc_init(void) * Set up interrupt, we will worry about memory allocation in * post_fep_init. */ - printk(KERN_INFO "DIGI epca driver version %s loaded.\n",VERSION); + printk(KERN_INFO "DIGI epca driver version %s loaded.\n", VERSION); /* * NOTE : This code assumes that the number of ports found in the @@ -1252,7 +1250,7 @@ static int __init pc_init(void) if ((board_id & 0x30) == 0x30) bd->memory_seg = 0x8000; } else - printk(KERN_ERR "epca: Board at 0x%x doesn't appear to be an XI\n",(int)bd->port); + printk(KERN_ERR "epca: Board at 0x%x doesn't appear to be an XI\n", (int)bd->port); break; } } @@ -1326,12 +1324,12 @@ static void post_fep_init(unsigned int crd) */ /* PCI cards are already remapped at this point ISA are not */ bd->numports = readw(bd->re_map_membase + XEMPORTS); - epcaassert(bd->numports <= 64,"PCI returned a invalid number of ports"); + epcaassert(bd->numports <= 64, "PCI returned a invalid number of ports"); nbdevs += (bd->numports); } else { /* Fix up the mappings for ISA/EISA etc */ /* FIXME: 64K - can we be smarter ? */ - bd->re_map_membase = ioremap(bd->membase, 0x10000); + bd->re_map_membase = ioremap_nocache(bd->membase, 0x10000); } if (crd != 0) @@ -1362,7 +1360,8 @@ static void post_fep_init(unsigned int crd) * XEPORTS (address 0xc22) points at the number of channels the card * supports. (For 64XE, XI, XEM, and XR use 0xc02) */ - if ((bd->type == PCXEVE || bd->type == PCXE) && (readw(memaddr + XEPORTS) < 3)) + if ((bd->type == PCXEVE || bd->type == PCXE) && + (readw(memaddr + XEPORTS) < 3)) shrinkmem = 1; if (bd->type < PCIXEM) if (!request_region((int)bd->port, 4, board_desc[bd->type])) @@ -1461,10 +1460,12 @@ static void post_fep_init(unsigned int crd) case PCXEVE: case PCXE: - ch->txptr = memaddr + (((tseg - bd->memory_seg) << 4) & 0x1fff); + ch->txptr = memaddr + (((tseg - bd->memory_seg) << 4) + & 0x1fff); ch->txwin = FEPWIN | ((tseg - bd->memory_seg) >> 9); - ch->rxptr = memaddr + (((rseg - bd->memory_seg) << 4) & 0x1fff); - ch->rxwin = FEPWIN | ((rseg - bd->memory_seg) >>9 ); + ch->rxptr = memaddr + (((rseg - bd->memory_seg) << 4) + & 0x1fff); + ch->rxwin = FEPWIN | ((rseg - bd->memory_seg) >> 9); break; case PCXI: @@ -1518,8 +1519,9 @@ static void post_fep_init(unsigned int crd) } printk(KERN_INFO - "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n", - VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports); + "Digi PC/Xx Driver V%s: %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n", + VERSION, board_desc[bd->type], (long)bd->port, + (long)bd->membase, bd->numports); memwinoff(bd, 0); } @@ -1527,7 +1529,7 @@ static void epcapoll(unsigned long ignored) { unsigned long flags; int crd; - volatile unsigned int head, tail; + unsigned int head, tail; struct channel *ch; struct board_info *bd; @@ -1593,7 +1595,9 @@ static void doevent(int crd) chan0 = card_ptr[crd]; epcaassert(chan0 <= &digi_channels[nbdevs - 1], "ch out of range"); assertgwinon(chan0); - while ((tail = readw(&chan0->mailbox->eout)) != (head = readw(&chan0->mailbox->ein))) { /* Begin while something in event queue */ + while ((tail = readw(&chan0->mailbox->eout)) != + (head = readw(&chan0->mailbox->ein))) { + /* Begin while something in event queue */ assertgwinon(chan0); eventbuf = bd->re_map_membase + tail + ISTART; /* Get the channel the event occurred on */ @@ -1617,7 +1621,8 @@ static void doevent(int crd) goto next; } - if ((bc = ch->brdchan) == NULL) + bc = ch->brdchan; + if (bc == NULL) goto next; if (event & DATA_IND) { /* Begin DATA_IND */ @@ -1629,10 +1634,11 @@ static void doevent(int crd) /* A modem signal change has been indicated */ ch->imodem = mstat; if (ch->asyncflags & ASYNC_CHECK_CD) { - if (mstat & ch->dcd) /* We are now receiving dcd */ + /* We are now receiving dcd */ + if (mstat & ch->dcd) wake_up_interruptible(&ch->open_wait); - else - pc_sched_event(ch, EPCA_EVENT_HANGUP); /* No dcd; hangup */ + else /* No dcd; hangup */ + pc_sched_event(ch, EPCA_EVENT_HANGUP); } } tty = ch->tty; @@ -1647,7 +1653,8 @@ static void doevent(int crd) tty_wakeup(tty); } } else if (event & EMPTYTX_IND) { - /* This event is generated by setup_empty_event */ + /* This event is generated by + setup_empty_event */ ch->statusflags &= ~TXBUSY; if (ch->statusflags & EMPTYWAIT) { ch->statusflags &= ~EMPTYWAIT; @@ -1655,7 +1662,7 @@ static void doevent(int crd) } } } - next: +next: globalwinon(ch); BUG_ON(!bc); writew(1, &bc->idata); @@ -1665,7 +1672,7 @@ static void doevent(int crd) } static void fepcmd(struct channel *ch, int cmd, int word_or_byte, - int byte2, int ncmds, int bytecmd) + int byte2, int ncmds, int bytecmd) { unchar __iomem *memaddr; unsigned int head, cmdTail, cmdStart, cmdMax; @@ -1690,8 +1697,10 @@ static void fepcmd(struct channel *ch, int cmd, int word_or_byte, memaddr = ch->board->re_map_membase; if (head >= (cmdMax - cmdStart) || (head & 03)) { - printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n", __LINE__, cmd, head); - printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n", __LINE__, cmdMax, cmdStart); + printk(KERN_ERR "line %d: Out of range, cmd = %x, head = %x\n", + __LINE__, cmd, head); + printk(KERN_ERR "line %d: Out of range, cmdMax = %x, cmdStart = %x\n", + __LINE__, cmdMax, cmdStart); return; } if (bytecmd) { @@ -1770,7 +1779,7 @@ static unsigned termios2digi_h(struct channel *ch, unsigned cflag) static unsigned termios2digi_i(struct channel *ch, unsigned iflag) { unsigned res = iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK | - INPCK | ISTRIP|IXON|IXANY|IXOFF); + INPCK | ISTRIP | IXON | IXANY | IXOFF); if (ch->digiext.digi_flags & DIGI_AIXON) res |= IAIXON; return res; @@ -1838,7 +1847,7 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch) unsigned mval, hflow, cflag, iflag; bc = ch->brdchan; - epcaassert(bc !=0, "bc out of range"); + epcaassert(bc != NULL, "bc out of range"); assertgwinon(ch); ts = tty->termios; @@ -1884,8 +1893,10 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch) * Command sets channels iflag structure on the board. Such * things as input soft flow control, handling of parity * errors, and break handling are all set here. + * + * break handling, parity handling, input stripping, + * flow control chars */ - /* break handling, parity handling, input stripping, flow control chars */ fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0); } /* @@ -1981,7 +1992,7 @@ static void receive_data(struct channel *ch) return; /* If CREAD bit is off or device not open, set TX tail to head */ - if (!tty || !ts || !(ts->c_cflag & CREAD)) { + if (!tty || !ts || !(ts->c_cflag & CREAD)) { writew(head, &bc->rout); return; } @@ -1991,18 +2002,21 @@ static void receive_data(struct channel *ch) if (readb(&bc->orun)) { writeb(0, &bc->orun); - printk(KERN_WARNING "epca; overrun! DigiBoard device %s\n",tty->name); + printk(KERN_WARNING "epca; overrun! DigiBoard device %s\n", + tty->name); tty_insert_flip_char(tty, 0, TTY_OVERRUN); } rxwinon(ch); - while (bytesAvailable > 0) { /* Begin while there is data on the card */ + while (bytesAvailable > 0) { + /* Begin while there is data on the card */ wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail; /* * Even if head has wrapped around only report the amount of * data to be equal to the size - tail. Remember memcpy can't * automaticly wrap around the receive buffer. */ - dataToRead = (wrapgap < bytesAvailable) ? wrapgap : bytesAvailable; + dataToRead = (wrapgap < bytesAvailable) ? wrapgap + : bytesAvailable; /* Make sure we don't overflow the buffer */ dataToRead = tty_prepare_flip_string(tty, &rptr, dataToRead); if (dataToRead == 0) @@ -2153,14 +2167,14 @@ static int pc_tiocmset(struct tty_struct *tty, struct file *file, * The below routine generally sets up parity, baud, flow control * issues, etc.... It effect both control flags and input flags. */ - epcaparam(tty,ch); + epcaparam(tty, ch); memoff(ch); spin_unlock_irqrestore(&epca_lock, flags); return 0; } -static int pc_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) +static int pc_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) { digiflow_t dflow; int retval; @@ -2175,7 +2189,6 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, bc = ch->brdchan; else return -EINVAL; - /* * For POSIX compliance we need to add more ioctls. See tty_ioctl.c in * /usr/src/linux/drivers/char for a good example. In particular think @@ -2186,9 +2199,10 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, retval = tty_check_change(tty); if (retval) return retval; - /* Setup an event to indicate when the transmit buffer empties */ + /* Setup an event to indicate when the transmit + buffer empties */ spin_lock_irqsave(&epca_lock, flags); - setup_empty_event(tty,ch); + setup_empty_event(tty, ch); spin_unlock_irqrestore(&epca_lock, flags); tty_wait_until_sent(tty, 0); if (!arg) @@ -2198,29 +2212,14 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, retval = tty_check_change(tty); if (retval) return retval; - - /* Setup an event to indicate when the transmit buffer empties */ + /* Setup an event to indicate when the transmit buffer + empties */ spin_lock_irqsave(&epca_lock, flags); - setup_empty_event(tty,ch); + setup_empty_event(tty, ch); spin_unlock_irqrestore(&epca_lock, flags); tty_wait_until_sent(tty, 0); digi_send_break(ch, arg ? arg*(HZ/10) : HZ/4); return 0; - case TIOCGSOFTCAR: - if (put_user(C_CLOCAL(tty)?1:0, (unsigned long __user *)arg)) - return -EFAULT; - return 0; - case TIOCSSOFTCAR: - { - unsigned int value; - - if (get_user(value, (unsigned __user *)argp)) - return -EFAULT; - tty->termios->c_cflag = - ((tty->termios->c_cflag & ~CLOCAL) | - (value ? CLOCAL : 0)); - return 0; - } case TIOCMODG: mflag = pc_tiocmget(tty, file); if (put_user(mflag, (unsigned long __user *)argp)) @@ -2253,10 +2252,12 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, break; case DIGI_SETAW: case DIGI_SETAF: + lock_kernel(); if (cmd == DIGI_SETAW) { - /* Setup an event to indicate when the transmit buffer empties */ + /* Setup an event to indicate when the transmit + buffer empties */ spin_lock_irqsave(&epca_lock, flags); - setup_empty_event(tty,ch); + setup_empty_event(tty, ch); spin_unlock_irqrestore(&epca_lock, flags); tty_wait_until_sent(tty, 0); } else { @@ -2264,6 +2265,7 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); } + unlock_kernel(); /* Fall Thru */ case DIGI_SETA: if (copy_from_user(&ch->digiext, argp, sizeof(digi_t))) @@ -2285,7 +2287,7 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, * control issues, etc.... It effect both control flags and * input flags. */ - epcaparam(tty,ch); + epcaparam(tty, ch); memoff(ch); spin_unlock_irqrestore(&epca_lock, flags); break; @@ -2321,18 +2323,21 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, if (copy_from_user(&dflow, argp, sizeof(dflow))) return -EFAULT; - if (dflow.startc != startc || dflow.stopc != stopc) { /* Begin if setflow toggled */ + if (dflow.startc != startc || dflow.stopc != stopc) { + /* Begin if setflow toggled */ spin_lock_irqsave(&epca_lock, flags); globalwinon(ch); if (cmd == DIGI_SETFLOW) { ch->fepstartc = ch->startc = dflow.startc; ch->fepstopc = ch->stopc = dflow.stopc; - fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1); + fepcmd(ch, SONOFFC, ch->fepstartc, + ch->fepstopc, 0, 1); } else { ch->fepstartca = ch->startca = dflow.startc; ch->fepstopca = ch->stopca = dflow.stopc; - fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1); + fepcmd(ch, SAUXONOFFC, ch->fepstartca, + ch->fepstopca, 0, 1); } if (ch->statusflags & TXSTOPPED) @@ -2356,7 +2361,9 @@ static void pc_set_termios(struct tty_struct *tty, struct ktermios *old_termios) * verifyChannel returns the channel from the tty struct if it is * valid. This serves as a sanity check. */ - if ((ch = verifyChannel(tty)) != NULL) { /* Begin if channel valid */ + ch = verifyChannel(tty); + + if (ch != NULL) { /* Begin if channel valid */ spin_lock_irqsave(&epca_lock, flags); globalwinon(ch); epcaparam(tty, ch); @@ -2383,7 +2390,7 @@ static void do_softint(struct work_struct *work) if (tty && tty->driver_data) { if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) { - tty_hangup(tty); /* FIXME: module removal race here - AKPM */ + tty_hangup(tty); wake_up_interruptible(&ch->open_wait); ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE; } @@ -2403,9 +2410,11 @@ static void pc_stop(struct tty_struct *tty) * verifyChannel returns the channel from the tty struct if it is * valid. This serves as a sanity check. */ - if ((ch = verifyChannel(tty)) != NULL) { + ch = verifyChannel(tty); + if (ch != NULL) { spin_lock_irqsave(&epca_lock, flags); - if ((ch->statusflags & TXSTOPPED) == 0) { /* Begin if transmit stop requested */ + if ((ch->statusflags & TXSTOPPED) == 0) { + /* Begin if transmit stop requested */ globalwinon(ch); /* STOP transmitting now !! */ fepcmd(ch, PAUSETX, 0, 0, 0, 0); @@ -2423,11 +2432,14 @@ static void pc_start(struct tty_struct *tty) * verifyChannel returns the channel from the tty struct if it is * valid. This serves as a sanity check. */ - if ((ch = verifyChannel(tty)) != NULL) { + ch = verifyChannel(tty); + if (ch != NULL) { unsigned long flags; spin_lock_irqsave(&epca_lock, flags); - /* Just in case output was resumed because of a change in Digi-flow */ - if (ch->statusflags & TXSTOPPED) { /* Begin transmit resume requested */ + /* Just in case output was resumed because of a change + in Digi-flow */ + if (ch->statusflags & TXSTOPPED) { + /* Begin transmit resume requested */ struct board_chan __iomem *bc; globalwinon(ch); bc = ch->brdchan; @@ -2457,7 +2469,8 @@ static void pc_throttle(struct tty_struct *tty) * verifyChannel returns the channel from the tty struct if it is * valid. This serves as a sanity check. */ - if ((ch = verifyChannel(tty)) != NULL) { + ch = verifyChannel(tty); + if (ch != NULL) { spin_lock_irqsave(&epca_lock, flags); if ((ch->statusflags & RXSTOPPED) == 0) { globalwinon(ch); @@ -2477,8 +2490,10 @@ static void pc_unthrottle(struct tty_struct *tty) * verifyChannel returns the channel from the tty struct if it is * valid. This serves as a sanity check. */ - if ((ch = verifyChannel(tty)) != NULL) { - /* Just in case output was resumed because of a change in Digi-flow */ + ch = verifyChannel(tty); + if (ch != NULL) { + /* Just in case output was resumed because of a change + in Digi-flow */ spin_lock_irqsave(&epca_lock, flags); if (ch->statusflags & RXSTOPPED) { globalwinon(ch); @@ -2490,7 +2505,7 @@ static void pc_unthrottle(struct tty_struct *tty) } } -void digi_send_break(struct channel *ch, int msec) +static void digi_send_break(struct channel *ch, int msec) { unsigned long flags; @@ -2523,7 +2538,7 @@ static void setup_empty_event(struct tty_struct *tty, struct channel *ch) memoff(ch); } -void epca_setup(char *str, int *ints) +static void epca_setup(char *str, int *ints) { struct board_info board; int index, loop, last; @@ -2552,14 +2567,16 @@ void epca_setup(char *str, int *ints) * instructing the driver to ignore epcaconfig.) For * this reason we check for 2. */ - if (board.status == 2) { /* Begin ignore epcaconfig as well as lilo cmd line */ + if (board.status == 2) { + /* Begin ignore epcaconfig as well as lilo cmd line */ nbdevs = 0; num_cards = 0; return; } /* End ignore epcaconfig as well as lilo cmd line */ if (board.status > 2) { - printk(KERN_ERR "epca_setup: Invalid board status 0x%x\n", board.status); + printk(KERN_ERR "epca_setup: Invalid board status 0x%x\n", + board.status); invalid_lilo_config = 1; setup_error_code |= INVALID_BOARD_STATUS; return; @@ -2613,7 +2630,8 @@ void epca_setup(char *str, int *ints) case 6: board.membase = ints[index]; if (ints[index] <= 0) { - printk(KERN_ERR "epca_setup: Invalid memory base 0x%x\n",(unsigned int)board.membase); + printk(KERN_ERR "epca_setup: Invalid memory base 0x%x\n", + (unsigned int)board.membase); invalid_lilo_config = 1; setup_error_code |= INVALID_MEM_BASE; return; @@ -2744,7 +2762,7 @@ void epca_setup(char *str, int *ints) t2++; if (*t2) { - printk(KERN_ERR "epca_setup: Invalid memory base %s\n",str); + printk(KERN_ERR "epca_setup: Invalid memory base %s\n", str); invalid_lilo_config = 1; setup_error_code |= INVALID_MEM_BASE; return; @@ -2766,7 +2784,7 @@ void epca_setup(char *str, int *ints) /* I should REALLY validate the stuff here */ /* Copies our local copy of board into boards */ - memcpy((void *)&boards[num_cards],(void *)&board, sizeof(board)); + memcpy((void *)&boards[num_cards], (void *)&board, sizeof(board)); /* Does this get called once per lilo arg are what ? */ printk(KERN_INFO "PC/Xx: Added board %i, %s %i ports at 0x%4.4X base 0x%6.6X\n", num_cards, board_desc[board.type], @@ -2807,9 +2825,9 @@ static int __devinit epca_init_one(struct pci_dev *pdev, if (board_idx >= MAXBOARDS) goto err_out; - addr = pci_resource_start (pdev, epca_info_tbl[info_idx].bar_idx); + addr = pci_resource_start(pdev, epca_info_tbl[info_idx].bar_idx); if (!addr) { - printk (KERN_ERR PFX "PCI region #%d not available (size 0)\n", + printk(KERN_ERR PFX "PCI region #%d not available (size 0)\n", epca_info_tbl[info_idx].bar_idx); goto err_out; } @@ -2820,28 +2838,29 @@ static int __devinit epca_init_one(struct pci_dev *pdev, boards[board_idx].port = addr + PCI_IO_OFFSET; boards[board_idx].membase = addr; - if (!request_mem_region (addr + PCI_IO_OFFSET, 0x200000, "epca")) { - printk (KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n", + if (!request_mem_region(addr + PCI_IO_OFFSET, 0x200000, "epca")) { + printk(KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n", 0x200000, addr + PCI_IO_OFFSET); goto err_out; } - boards[board_idx].re_map_port = ioremap(addr + PCI_IO_OFFSET, 0x200000); + boards[board_idx].re_map_port = ioremap_nocache(addr + PCI_IO_OFFSET, + 0x200000); if (!boards[board_idx].re_map_port) { - printk (KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n", + printk(KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n", 0x200000, addr + PCI_IO_OFFSET); goto err_out_free_pciio; } - if (!request_mem_region (addr, 0x200000, "epca")) { - printk (KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n", + if (!request_mem_region(addr, 0x200000, "epca")) { + printk(KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n", 0x200000, addr); goto err_out_free_iounmap; } - boards[board_idx].re_map_membase = ioremap(addr, 0x200000); + boards[board_idx].re_map_membase = ioremap_nocache(addr, 0x200000); if (!boards[board_idx].re_map_membase) { - printk (KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n", + printk(KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n", 0x200000, addr + PCI_IO_OFFSET); goto err_out_free_memregion; } @@ -2858,11 +2877,11 @@ static int __devinit epca_init_one(struct pci_dev *pdev, return 0; err_out_free_memregion: - release_mem_region (addr, 0x200000); + release_mem_region(addr, 0x200000); err_out_free_iounmap: - iounmap (boards[board_idx].re_map_port); + iounmap(boards[board_idx].re_map_port); err_out_free_pciio: - release_mem_region (addr + PCI_IO_OFFSET, 0x200000); + release_mem_region(addr + PCI_IO_OFFSET, 0x200000); err_out: return -ENODEV; } @@ -2878,9 +2897,9 @@ static struct pci_device_id epca_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, epca_pci_tbl); -int __init init_PCI (void) +static int __init init_PCI(void) { - memset (&epca_driver, 0, sizeof (epca_driver)); + memset(&epca_driver, 0, sizeof(epca_driver)); epca_driver.name = "epca"; epca_driver.id_table = epca_pci_tbl; epca_driver.probe = epca_init_one; diff --git a/drivers/char/esp.c b/drivers/char/esp.c index f3fe62067344..84840ba13ff0 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c @@ -8,7 +8,7 @@ * Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92. Now * much more extensible to support other serial cards based on the * 16450/16550A UART's. Added support for the AST FourPort and the - * Accent Async board. + * Accent Async board. * * set_serial_info fixed to set the flags, custom divisor, and uart * type fields. Fix suggested by Michael K. Johnson 12/12/92. @@ -61,11 +61,11 @@ #include <linux/bitops.h> #include <asm/system.h> -#include <asm/io.h> +#include <linux/io.h> #include <asm/dma.h> #include <linux/slab.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <linux/hayesesp.h> @@ -127,8 +127,10 @@ static struct tty_driver *esp_driver; #undef SERIAL_DEBUG_FLOW #if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) -#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ - tty->name, (info->flags), serial_driver.refcount,info->count,tty->count,s) +#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ + tty->name, info->flags, \ + serial_driver.refcount, \ + info->count, tty->count, s) #else #define DBG_CNT(s) #endif @@ -189,7 +191,7 @@ static inline void serial_out(struct esp_struct *info, int offset, */ static void rs_stop(struct tty_struct *tty) { - struct esp_struct *info = (struct esp_struct *)tty->driver_data; + struct esp_struct *info = tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_stop")) @@ -206,12 +208,12 @@ static void rs_stop(struct tty_struct *tty) static void rs_start(struct tty_struct *tty) { - struct esp_struct *info = (struct esp_struct *)tty->driver_data; + struct esp_struct *info = tty->driver_data; unsigned long flags; - + if (serial_paranoia_check(info, tty->name, "rs_start")) return; - + spin_lock_irqsave(&info->lock, flags); if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) { info->IER |= UART_IER_THRI; @@ -233,7 +235,7 @@ static void rs_start(struct tty_struct *tty) * rs_interrupt() should try to keep the interrupt handler as fast as * possible. After you are done making modifications, it is not a bad * idea to do: - * + * * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c * * and look at the resulting assemble code in serial.s. @@ -290,7 +292,7 @@ static inline void receive_chars_pio(struct esp_struct *info, int num_bytes) } status_mask = (info->read_status_mask >> 2) & 0x07; - + for (i = 0; i < num_bytes - 1; i += 2) { *((unsigned short *)(pio_buf->data + i)) = inw(info->port + UART_ESI_RX); @@ -325,8 +327,7 @@ static inline void receive_chars_pio(struct esp_struct *info, int num_bytes) flag = TTY_BREAK; if (info->flags & ASYNC_SAK) do_SAK(tty); - } - else if (err_buf->data[i] & 0x02) + } else if (err_buf->data[i] & 0x02) flag = TTY_FRAME; else if (err_buf->data[i] & 0x01) flag = TTY_PARITY; @@ -341,23 +342,29 @@ static inline void receive_chars_pio(struct esp_struct *info, int num_bytes) release_pio_buffer(err_buf); } -static inline void receive_chars_dma(struct esp_struct *info, int num_bytes) +static void program_isa_dma(int dma, int dir, unsigned long addr, int len) { unsigned long flags; + + flags = claim_dma_lock(); + disable_dma(dma); + clear_dma_ff(dma); + set_dma_mode(dma, dir); + set_dma_addr(dma, addr); + set_dma_count(dma, len); + enable_dma(dma); + release_dma_lock(flags); +} + +static void receive_chars_dma(struct esp_struct *info, int num_bytes) +{ info->stat_flags &= ~ESP_STAT_RX_TIMEOUT; dma_bytes = num_bytes; info->stat_flags |= ESP_STAT_DMA_RX; - - flags=claim_dma_lock(); - disable_dma(dma); - clear_dma_ff(dma); - set_dma_mode(dma, DMA_MODE_READ); - set_dma_addr(dma, isa_virt_to_bus(dma_buffer)); - set_dma_count(dma, dma_bytes); - enable_dma(dma); - release_dma_lock(flags); - - serial_out(info, UART_ESI_CMD1, ESI_START_DMA_RX); + + program_isa_dma(dma, DMA_MODE_READ, isa_virt_to_bus(dma_buffer), + dma_bytes); + serial_out(info, UART_ESI_CMD1, ESI_START_DMA_RX); } static inline void receive_chars_dma_done(struct esp_struct *info, @@ -366,22 +373,22 @@ static inline void receive_chars_dma_done(struct esp_struct *info, struct tty_struct *tty = info->tty; int num_bytes; unsigned long flags; - - flags=claim_dma_lock(); + + flags = claim_dma_lock(); disable_dma(dma); clear_dma_ff(dma); info->stat_flags &= ~ESP_STAT_DMA_RX; num_bytes = dma_bytes - get_dma_residue(dma); release_dma_lock(flags); - + info->icount.rx += num_bytes; if (num_bytes > 0) { tty_insert_flip_string(tty, dma_buffer, num_bytes - 1); status &= (0x1c & info->read_status_mask); - + /* Is the status significant or do we throw the last byte ? */ if (!(status & info->ignore_status_mask)) { int statflag = 0; @@ -393,13 +400,13 @@ static inline void receive_chars_dma_done(struct esp_struct *info, do_SAK(tty); } else if (status & 0x08) { statflag = TTY_FRAME; - (info->icount.frame)++; - } - else if (status & 0x04) { + info->icount.frame++; + } else if (status & 0x04) { statflag = TTY_PARITY; - (info->icount.parity)++; + info->icount.parity++; } - tty_insert_flip_char(tty, dma_buffer[num_bytes - 1], statflag); + tty_insert_flip_char(tty, dma_buffer[num_bytes - 1], + statflag); } tty_schedule_flip(tty); } @@ -484,8 +491,6 @@ static inline void transmit_chars_pio(struct esp_struct *info, /* Caller must hold info->lock */ static inline void transmit_chars_dma(struct esp_struct *info, int num_bytes) { - unsigned long flags; - dma_bytes = num_bytes; if (info->xmit_tail + dma_bytes <= ESP_XMIT_SIZE) { @@ -517,26 +522,18 @@ static inline void transmit_chars_dma(struct esp_struct *info, int num_bytes) } info->stat_flags |= ESP_STAT_DMA_TX; - - flags=claim_dma_lock(); - disable_dma(dma); - clear_dma_ff(dma); - set_dma_mode(dma, DMA_MODE_WRITE); - set_dma_addr(dma, isa_virt_to_bus(dma_buffer)); - set_dma_count(dma, dma_bytes); - enable_dma(dma); - release_dma_lock(flags); - - serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX); + + program_isa_dma(dma, DMA_MODE_WRITE, isa_virt_to_bus(dma_buffer), + dma_bytes); + serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX); } static inline void transmit_chars_dma_done(struct esp_struct *info) { int num_bytes; unsigned long flags; - - flags=claim_dma_lock(); + flags = claim_dma_lock(); disable_dma(dma); clear_dma_ff(dma); @@ -547,27 +544,21 @@ static inline void transmit_chars_dma_done(struct esp_struct *info) if (dma_bytes != num_bytes) { dma_bytes -= num_bytes; memmove(dma_buffer, dma_buffer + num_bytes, dma_bytes); - - flags=claim_dma_lock(); - disable_dma(dma); - clear_dma_ff(dma); - set_dma_mode(dma, DMA_MODE_WRITE); - set_dma_addr(dma, isa_virt_to_bus(dma_buffer)); - set_dma_count(dma, dma_bytes); - enable_dma(dma); - release_dma_lock(flags); - - serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX); + + program_isa_dma(dma, DMA_MODE_WRITE, + isa_virt_to_bus(dma_buffer), dma_bytes); + + serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX); } else { dma_bytes = 0; info->stat_flags &= ~ESP_STAT_DMA_TX; } } -static inline void check_modem_status(struct esp_struct *info) +static void check_modem_status(struct esp_struct *info) { int status; - + serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT); status = serial_in(info, UART_ESI_STAT2); @@ -588,7 +579,7 @@ static inline void check_modem_status(struct esp_struct *info) #if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) printk("ttys%d CD now %s...", info->line, (status & UART_MSR_DCD) ? "on" : "off"); -#endif +#endif if (status & UART_MSR_DCD) wake_up_interruptible(&info->open_wait); else { @@ -605,7 +596,7 @@ static inline void check_modem_status(struct esp_struct *info) */ static irqreturn_t rs_interrupt_single(int irq, void *dev_id) { - struct esp_struct * info; + struct esp_struct *info; unsigned err_status; unsigned int scratch; @@ -617,7 +608,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id) scratch = serial_in(info, UART_ESI_SID); spin_lock(&info->lock); - + if (!info->tty) { spin_unlock(&info->lock); return IRQ_NONE; @@ -637,7 +628,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id) if (err_status & 0x80) /* Start break */ wake_up_interruptible(&info->break_wait); } - + if ((scratch & 0x88) || /* DMA completed or timed out */ (err_status & 0x1c) /* receive error */) { if (info->stat_flags & ESP_STAT_DMA_RX) @@ -667,7 +658,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id) receive_chars_dma(info, num_bytes); } } - + if (!(info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) && (scratch & 0x02) && (info->IER & UART_IER_THRI)) { if ((info->xmit_cnt <= 0) || info->tty->stopped) { @@ -722,11 +713,11 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id) * --------------------------------------------------------------- */ -static inline void esp_basic_init(struct esp_struct * info) +static void esp_basic_init(struct esp_struct *info) { /* put ESPC in enhanced mode */ serial_out(info, UART_ESI_CMD1, ESI_SET_MODE); - + if (info->stat_flags & ESP_STAT_NEVER_DMA) serial_out(info, UART_ESI_CMD2, 0x01); else @@ -783,13 +774,13 @@ static inline void esp_basic_init(struct esp_struct * info) serial_out(info, UART_ESI_CMD2, 0xff); } -static int startup(struct esp_struct * info) +static int startup(struct esp_struct *info) { unsigned long flags; - int retval=0; - unsigned int num_chars; + int retval = 0; + unsigned int num_chars; - spin_lock_irqsave(&info->lock, flags); + spin_lock_irqsave(&info->lock, flags); if (info->flags & ASYNC_INITIALIZED) goto out; @@ -802,7 +793,8 @@ static int startup(struct esp_struct * info) } #ifdef SERIAL_DEBUG_OPEN - printk("starting up ttys%d (irq %d)...", info->line, info->irq); + printk(KERN_DEBUG "starting up ttys%d (irq %d)...", + info->line, info->irq); #endif /* Flush the RX buffer. Using the ESI flush command may cause */ @@ -863,7 +855,7 @@ static int startup(struct esp_struct * info) dma_buffer = NULL; info->stat_flags |= ESP_STAT_USE_PIO; } - + } info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; @@ -872,7 +864,7 @@ static int startup(struct esp_struct * info) serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART); serial_out(info, UART_ESI_CMD2, UART_MCR); serial_out(info, UART_ESI_CMD2, info->MCR); - + /* * Finally, enable interrupts */ @@ -881,7 +873,7 @@ static int startup(struct esp_struct * info) UART_IER_DMA_TC; serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); serial_out(info, UART_ESI_CMD2, info->IER); - + if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; @@ -900,7 +892,7 @@ static int startup(struct esp_struct * info) if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) info->tty->alt_speed = 460800; } - + /* * set the speed of the serial port */ @@ -918,7 +910,7 @@ out_unlocked: * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. */ -static void shutdown(struct esp_struct * info) +static void shutdown(struct esp_struct *info) { unsigned long flags, f; @@ -929,7 +921,7 @@ static void shutdown(struct esp_struct * info) printk("Shutting down serial port %d (irq %d)....", info->line, info->irq); #endif - + spin_lock_irqsave(&info->lock, flags); /* * clear delta_msr_wait queue to avoid mem leaks: we may free the irq @@ -941,14 +933,14 @@ static void shutdown(struct esp_struct * info) /* stop a DMA transfer on the port being closed */ /* DMA lock is higher priority always */ if (info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) { - f=claim_dma_lock(); + f = claim_dma_lock(); disable_dma(dma); clear_dma_ff(dma); release_dma_lock(f); - + dma_bytes = 0; } - + /* * Free the IRQ */ @@ -970,7 +962,7 @@ static void shutdown(struct esp_struct * info) free_pages((unsigned long)dma_buffer, get_order(DMA_BUFFER_SZ)); dma_buffer = NULL; - } + } } if (info->xmit_buf) { @@ -992,7 +984,7 @@ static void shutdown(struct esp_struct * info) if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); - + info->flags &= ~ASYNC_INITIALIZED; spin_unlock_irqrestore(&info->lock, flags); } @@ -1005,7 +997,7 @@ static void change_speed(struct esp_struct *info) { unsigned short port; int quot = 0; - unsigned cflag,cval; + unsigned cflag, cval; int baud, bits; unsigned char flow1 = 0, flow2 = 0; unsigned long flags; @@ -1014,14 +1006,14 @@ static void change_speed(struct esp_struct *info) return; cflag = info->tty->termios->c_cflag; port = info->port; - + /* byte size and parity */ switch (cflag & CSIZE) { - case CS5: cval = 0x00; bits = 7; break; - case CS6: cval = 0x01; bits = 8; break; - case CS7: cval = 0x02; bits = 9; break; - case CS8: cval = 0x03; bits = 10; break; - default: cval = 0x00; bits = 7; break; + case CS5: cval = 0x00; bits = 7; break; + case CS6: cval = 0x01; bits = 8; break; + case CS7: cval = 0x02; bits = 9; break; + case CS8: cval = 0x03; bits = 10; break; + default: cval = 0x00; bits = 7; break; } if (cflag & CSTOPB) { cval |= 0x04; @@ -1037,14 +1029,12 @@ static void change_speed(struct esp_struct *info) if (cflag & CMSPAR) cval |= UART_LCR_SPAR; #endif - baud = tty_get_baud_rate(info->tty); if (baud == 38400 && - ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) + ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) quot = info->custom_divisor; else { - if (baud == 134) - /* Special case since 134 is really 134.5 */ + if (baud == 134) /* Special case since 134 is really 134.5 */ quot = (2*BASE_BAUD / 269); else if (baud) quot = BASE_BAUD / baud; @@ -1052,7 +1042,12 @@ static void change_speed(struct esp_struct *info) /* If the quotient is ever zero, default to 9600 bps */ if (!quot) quot = BASE_BAUD / 9600; - + + if (baud) { + /* Actual rate */ + baud = BASE_BAUD/quot; + tty_encode_baud_rate(info->tty, baud, baud); + } info->timeout = ((1024 * HZ * bits * quot) / BASE_BAUD) + (HZ / 50); /* CTS flow control flag and modem status interrupts */ @@ -1066,10 +1061,8 @@ static void change_speed(struct esp_struct *info) info->flags &= ~ASYNC_CTS_FLOW; if (cflag & CLOCAL) info->flags &= ~ASYNC_CHECK_CD; - else { + else info->flags |= ASYNC_CHECK_CD; - /* info->IER |= UART_IER_MSI; */ - } /* * Set up parity check flag @@ -1079,7 +1072,7 @@ static void change_speed(struct esp_struct *info) info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) info->read_status_mask |= UART_LSR_BI; - + info->ignore_status_mask = 0; #if 0 /* This should be safe, but for some broken bits of hardware... */ @@ -1092,7 +1085,7 @@ static void change_speed(struct esp_struct *info) info->ignore_status_mask |= UART_LSR_BI; info->read_status_mask |= UART_LSR_BI; /* - * If we're ignore parity and break indicators, ignore + * If we're ignore parity and break indicators, ignore * overruns too. (For real raw support). */ if (I_IGNPAR(info->tty)) { @@ -1130,19 +1123,19 @@ static void change_speed(struct esp_struct *info) serial_out(info, UART_ESI_CMD2, 0x10); serial_out(info, UART_ESI_CMD2, 0x21); switch (cflag & CSIZE) { - case CS5: - serial_out(info, UART_ESI_CMD2, 0x1f); - break; - case CS6: - serial_out(info, UART_ESI_CMD2, 0x3f); - break; - case CS7: - case CS8: - serial_out(info, UART_ESI_CMD2, 0x7f); - break; - default: - serial_out(info, UART_ESI_CMD2, 0xff); - break; + case CS5: + serial_out(info, UART_ESI_CMD2, 0x1f); + break; + case CS6: + serial_out(info, UART_ESI_CMD2, 0x3f); + break; + case CS7: + case CS8: + serial_out(info, UART_ESI_CMD2, 0x7f); + break; + default: + serial_out(info, UART_ESI_CMD2, 0xff); + break; } } @@ -1156,31 +1149,34 @@ static void change_speed(struct esp_struct *info) spin_unlock_irqrestore(&info->lock, flags); } -static void rs_put_char(struct tty_struct *tty, unsigned char ch) +static int rs_put_char(struct tty_struct *tty, unsigned char ch) { - struct esp_struct *info = (struct esp_struct *)tty->driver_data; + struct esp_struct *info = tty->driver_data; unsigned long flags; + int ret = 0; if (serial_paranoia_check(info, tty->name, "rs_put_char")) - return; + return 0; if (!info->xmit_buf) - return; + return 0; spin_lock_irqsave(&info->lock, flags); if (info->xmit_cnt < ESP_XMIT_SIZE - 1) { info->xmit_buf[info->xmit_head++] = ch; info->xmit_head &= ESP_XMIT_SIZE-1; info->xmit_cnt++; + ret = 1; } spin_unlock_irqrestore(&info->lock, flags); + return ret; } static void rs_flush_chars(struct tty_struct *tty) { - struct esp_struct *info = (struct esp_struct *)tty->driver_data; + struct esp_struct *info = tty->driver_data; unsigned long flags; - + if (serial_paranoia_check(info, tty->name, "rs_flush_chars")) return; @@ -1198,11 +1194,11 @@ out: spin_unlock_irqrestore(&info->lock, flags); } -static int rs_write(struct tty_struct * tty, +static int rs_write(struct tty_struct *tty, const unsigned char *buf, int count) { int c, t, ret = 0; - struct esp_struct *info = (struct esp_struct *)tty->driver_data; + struct esp_struct *info = tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_write")) @@ -1210,19 +1206,19 @@ static int rs_write(struct tty_struct * tty, if (!info->xmit_buf) return 0; - + while (1) { /* Thanks to R. Wolff for suggesting how to do this with */ /* interrupts enabled */ c = count; t = ESP_XMIT_SIZE - info->xmit_cnt - 1; - + if (t < c) c = t; t = ESP_XMIT_SIZE - info->xmit_head; - + if (t < c) c = t; @@ -1252,10 +1248,10 @@ static int rs_write(struct tty_struct * tty, static int rs_write_room(struct tty_struct *tty) { - struct esp_struct *info = (struct esp_struct *)tty->driver_data; + struct esp_struct *info = tty->driver_data; int ret; unsigned long flags; - + if (serial_paranoia_check(info, tty->name, "rs_write_room")) return 0; @@ -1270,8 +1266,8 @@ static int rs_write_room(struct tty_struct *tty) static int rs_chars_in_buffer(struct tty_struct *tty) { - struct esp_struct *info = (struct esp_struct *)tty->driver_data; - + struct esp_struct *info = tty->driver_data; + if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer")) return 0; return info->xmit_cnt; @@ -1279,9 +1275,9 @@ static int rs_chars_in_buffer(struct tty_struct *tty) static void rs_flush_buffer(struct tty_struct *tty) { - struct esp_struct *info = (struct esp_struct *)tty->driver_data; + struct esp_struct *info = tty->driver_data; unsigned long flags; - + if (serial_paranoia_check(info, tty->name, "rs_flush_buffer")) return; spin_lock_irqsave(&info->lock, flags); @@ -1293,20 +1289,20 @@ static void rs_flush_buffer(struct tty_struct *tty) /* * ------------------------------------------------------------ * rs_throttle() - * + * * This routine is called by the upper-layer tty layer to signal that * incoming characters should be throttled. * ------------------------------------------------------------ */ -static void rs_throttle(struct tty_struct * tty) +static void rs_throttle(struct tty_struct *tty) { - struct esp_struct *info = (struct esp_struct *)tty->driver_data; + struct esp_struct *info = tty->driver_data; unsigned long flags; #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; - + printk("throttle %s: %d....\n", tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty)); + tty_chars_in_buffer(tty)); #endif if (serial_paranoia_check(info, tty->name, "rs_throttle")) @@ -1321,20 +1317,20 @@ static void rs_throttle(struct tty_struct * tty) spin_unlock_irqrestore(&info->lock, flags); } -static void rs_unthrottle(struct tty_struct * tty) +static void rs_unthrottle(struct tty_struct *tty) { - struct esp_struct *info = (struct esp_struct *)tty->driver_data; + struct esp_struct *info = tty->driver_data; unsigned long flags; #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; - - printk("unthrottle %s: %d....\n", tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty)); + + printk(KERN_DEBUG "unthrottle %s: %d....\n", tty_name(tty, buf), + tty_chars_in_buffer(tty)); #endif if (serial_paranoia_check(info, tty->name, "rs_unthrottle")) return; - + spin_lock_irqsave(&info->lock, flags); info->IER |= UART_IER_RDI; serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); @@ -1350,11 +1346,12 @@ static void rs_unthrottle(struct tty_struct * tty) * ------------------------------------------------------------ */ -static int get_serial_info(struct esp_struct * info, +static int get_serial_info(struct esp_struct *info, struct serial_struct __user *retinfo) { struct serial_struct tmp; - + + lock_kernel(); memset(&tmp, 0, sizeof(tmp)); tmp.type = PORT_16550A; tmp.line = info->line; @@ -1367,20 +1364,22 @@ static int get_serial_info(struct esp_struct * info, tmp.closing_wait = info->closing_wait; tmp.custom_divisor = info->custom_divisor; tmp.hub6 = 0; - if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) + unlock_kernel(); + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) return -EFAULT; return 0; } -static int get_esp_config(struct esp_struct * info, +static int get_esp_config(struct esp_struct *info, struct hayes_esp_config __user *retinfo) { struct hayes_esp_config tmp; - + if (!retinfo) return -EFAULT; memset(&tmp, 0, sizeof(tmp)); + lock_kernel(); tmp.rx_timeout = info->config.rx_timeout; tmp.rx_trigger = info->config.rx_trigger; tmp.tx_trigger = info->config.tx_trigger; @@ -1388,11 +1387,12 @@ static int get_esp_config(struct esp_struct * info, tmp.flow_on = info->config.flow_on; tmp.pio_threshold = info->config.pio_threshold; tmp.dma_channel = (info->stat_flags & ESP_STAT_NEVER_DMA ? 0 : dma); + unlock_kernel(); return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0; } -static int set_serial_info(struct esp_struct * info, +static int set_serial_info(struct esp_struct *info, struct serial_struct __user *new_info) { struct serial_struct new_serial; @@ -1401,7 +1401,7 @@ static int set_serial_info(struct esp_struct * info, int retval = 0; struct esp_struct *current_async; - if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) + if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) return -EFAULT; old_info = *info; @@ -1422,7 +1422,7 @@ static int set_serial_info(struct esp_struct * info, return -EINVAL; if (!capable(CAP_SYS_ADMIN)) { - if (change_irq || + if (change_irq || (new_serial.close_delay != info->close_delay) || ((new_serial.flags & ~ASYNC_USR_MASK) != (info->flags & ~ASYNC_USR_MASK))) @@ -1507,8 +1507,8 @@ static int set_serial_info(struct esp_struct * info, return retval; } -static int set_esp_config(struct esp_struct * info, - struct hayes_esp_config __user * new_info) +static int set_esp_config(struct esp_struct *info, + struct hayes_esp_config __user *new_info) { struct hayes_esp_config new_config; unsigned int change_dma; @@ -1550,7 +1550,6 @@ static int set_esp_config(struct esp_struct * info, if (new_config.dma_channel) { /* PIO mode to DMA mode transition OR */ /* change current DMA channel */ - current_async = ports; while (current_async) { @@ -1559,16 +1558,15 @@ static int set_esp_config(struct esp_struct * info, return -EBUSY; } else if (current_async->count) return -EBUSY; - - current_async = - current_async->next_port; + + current_async = current_async->next_port; } shutdown(info); dma = new_config.dma_channel; info->stat_flags &= ~ESP_STAT_NEVER_DMA; - - /* all ports must use the same DMA channel */ + + /* all ports must use the same DMA channel */ spin_lock_irqsave(&info->lock, flags); current_async = ports; @@ -1580,7 +1578,6 @@ static int set_esp_config(struct esp_struct * info, spin_unlock_irqrestore(&info->lock, flags); } else { /* DMA mode to PIO mode only */ - if (info->count > 1) return -EBUSY; @@ -1596,8 +1593,6 @@ static int set_esp_config(struct esp_struct * info, if ((new_config.flow_off != info->config.flow_off) || (new_config.flow_on != info->config.flow_on)) { - unsigned long flags; - info->config.flow_off = new_config.flow_off; info->config.flow_on = new_config.flow_on; @@ -1612,8 +1607,6 @@ static int set_esp_config(struct esp_struct * info, if ((new_config.rx_trigger != info->config.rx_trigger) || (new_config.tx_trigger != info->config.tx_trigger)) { - unsigned long flags; - info->config.rx_trigger = new_config.rx_trigger; info->config.tx_trigger = new_config.tx_trigger; spin_lock_irqsave(&info->lock, flags); @@ -1628,8 +1621,6 @@ static int set_esp_config(struct esp_struct * info, } if (new_config.rx_timeout != info->config.rx_timeout) { - unsigned long flags; - info->config.rx_timeout = new_config.rx_timeout; spin_lock_irqsave(&info->lock, flags); @@ -1657,9 +1648,9 @@ static int set_esp_config(struct esp_struct * info, * 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. + * allows an RS485 driver to be written in user space. */ -static int get_lsr_info(struct esp_struct * info, unsigned int __user *value) +static int get_lsr_info(struct esp_struct *info, unsigned int __user *value) { unsigned char status; unsigned int result; @@ -1670,17 +1661,17 @@ static int get_lsr_info(struct esp_struct * info, unsigned int __user *value) status = serial_in(info, UART_ESI_STAT1); spin_unlock_irqrestore(&info->lock, flags); result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); - return put_user(result,value); + return put_user(result, value); } static int esp_tiocmget(struct tty_struct *tty, struct file *file) { - struct esp_struct * info = (struct esp_struct *)tty->driver_data; + struct esp_struct *info = tty->driver_data; unsigned char control, status; unsigned long flags; - if (serial_paranoia_check(info, tty->name, __FUNCTION__)) + if (serial_paranoia_check(info, tty->name, __func__)) return -ENODEV; if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; @@ -1703,10 +1694,10 @@ static int esp_tiocmget(struct tty_struct *tty, struct file *file) static int esp_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { - struct esp_struct * info = (struct esp_struct *)tty->driver_data; + struct esp_struct *info = tty->driver_data; unsigned long flags; - if (serial_paranoia_check(info, tty->name, __FUNCTION__)) + if (serial_paranoia_check(info, tty->name, __func__)) return -ENODEV; if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; @@ -1736,9 +1727,9 @@ static int esp_tiocmset(struct tty_struct *tty, struct file *file, */ static void esp_break(struct tty_struct *tty, int break_state) { - struct esp_struct * info = (struct esp_struct *)tty->driver_data; + struct esp_struct *info = tty->driver_data; unsigned long flags; - + if (serial_paranoia_check(info, tty->name, "esp_break")) return; @@ -1758,14 +1749,15 @@ static void esp_break(struct tty_struct *tty, int break_state) } } -static int rs_ioctl(struct tty_struct *tty, struct file * file, +static int rs_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - struct esp_struct * info = (struct esp_struct *)tty->driver_data; + struct esp_struct *info = tty->driver_data; struct async_icount cprev, cnow; /* kernel counter temps */ struct serial_icounter_struct __user *p_cuser; /* user space */ void __user *argp = (void __user *)arg; unsigned long flags; + int ret; if (serial_paranoia_check(info, tty->name, "rs_ioctl")) return -ENODEV; @@ -1778,97 +1770,93 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; } - - switch (cmd) { - case TIOCGSERIAL: - return get_serial_info(info, argp); - case TIOCSSERIAL: - return set_serial_info(info, argp); - case TIOCSERCONFIG: - /* do not reconfigure after initial configuration */ - return 0; - - case TIOCSERGWILD: - return put_user(0L, (unsigned long __user *)argp); - case TIOCSERGETLSR: /* Get line status register */ - return get_lsr_info(info, argp); - - case TIOCSERSWILD: - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - return 0; - - /* - * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - * - mask passed in arg for lines of interest - * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) - * Caller should use TIOCGICOUNT to see which one it was - */ - case TIOCMIWAIT: + switch (cmd) { + case TIOCGSERIAL: + return get_serial_info(info, argp); + case TIOCSSERIAL: + lock_kernel(); + ret = set_serial_info(info, argp); + unlock_kernel(); + return ret; + case TIOCSERGWILD: + return put_user(0L, (unsigned long __user *)argp); + case TIOCSERGETLSR: /* Get line status register */ + return get_lsr_info(info, argp); + case TIOCSERSWILD: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + return 0; + /* + * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change + * - mask passed in arg for lines of interest + * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) + * Caller should use TIOCGICOUNT to see which one it was + */ + case TIOCMIWAIT: + spin_lock_irqsave(&info->lock, flags); + cprev = info->icount; /* note the counters on entry */ + spin_unlock_irqrestore(&info->lock, flags); + while (1) { + /* FIXME: convert to new style wakeup */ + interruptible_sleep_on(&info->delta_msr_wait); + /* see if a signal did it */ + if (signal_pending(current)) + return -ERESTARTSYS; spin_lock_irqsave(&info->lock, flags); - cprev = info->icount; /* note the counters on entry */ + cnow = info->icount; /* atomic copy */ spin_unlock_irqrestore(&info->lock, flags); - while (1) { - /* FIXME: convert to new style wakeup */ - interruptible_sleep_on(&info->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - spin_lock_irqsave(&info->lock, flags); - cnow = info->icount; /* atomic copy */ - spin_unlock_irqrestore(&info->lock, flags); - if (cnow.rng == cprev.rng && - cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && - cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if (((arg & TIOCM_RNG) && - (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && - (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && - (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && - (cnow.cts != cprev.cts)) ) { - return 0; - } - cprev = cnow; + if (cnow.rng == cprev.rng && + cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && + cnow.cts == cprev.cts) + return -EIO; /* no change => error */ + if (((arg & TIOCM_RNG) && + (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && + (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && + (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && + (cnow.cts != cprev.cts))) { + return 0; } - /* NOTREACHED */ - - /* - * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) - * Return: write counters to the user passed counter struct - * NB: both 1->0 and 0->1 transitions are counted except for - * RI where only 0->1 is counted. - */ - case TIOCGICOUNT: - spin_lock_irqsave(&info->lock, flags); - cnow = info->icount; - spin_unlock_irqrestore(&info->lock, flags); - p_cuser = argp; - if (put_user(cnow.cts, &p_cuser->cts) || - put_user(cnow.dsr, &p_cuser->dsr) || - put_user(cnow.rng, &p_cuser->rng) || - put_user(cnow.dcd, &p_cuser->dcd)) - return -EFAULT; - + cprev = cnow; + } + /* NOTREACHED */ + /* + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) + * Return: write counters to the user passed counter struct + * NB: both 1->0 and 0->1 transitions are counted except for + * RI where only 0->1 is counted. + */ + case TIOCGICOUNT: + spin_lock_irqsave(&info->lock, flags); + cnow = info->icount; + spin_unlock_irqrestore(&info->lock, flags); + p_cuser = argp; + if (put_user(cnow.cts, &p_cuser->cts) || + put_user(cnow.dsr, &p_cuser->dsr) || + put_user(cnow.rng, &p_cuser->rng) || + put_user(cnow.dcd, &p_cuser->dcd)) + return -EFAULT; return 0; case TIOCGHAYESESP: return get_esp_config(info, argp); case TIOCSHAYESESP: - return set_esp_config(info, argp); - - default: - return -ENOIOCTLCMD; - } + lock_kernel(); + ret = set_esp_config(info, argp); + unlock_kernel(); + return ret; + default: + return -ENOIOCTLCMD; + } return 0; } static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { - struct esp_struct *info = (struct esp_struct *)tty->driver_data; + struct esp_struct *info = tty->driver_data; unsigned long flags; change_speed(info); @@ -1905,32 +1893,33 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) /* * ------------------------------------------------------------ * rs_close() - * + * * This routine is called when the serial port gets closed. First, we * wait for the last remaining data to be sent. Then, we unlink its * async structure from the interrupt chain if necessary, and we free * that IRQ if nothing is left in the chain. * ------------------------------------------------------------ */ -static void rs_close(struct tty_struct *tty, struct file * filp) +static void rs_close(struct tty_struct *tty, struct file *filp) { - struct esp_struct * info = (struct esp_struct *)tty->driver_data; + struct esp_struct *info = tty->driver_data; unsigned long flags; if (!info || serial_paranoia_check(info, tty->name, "rs_close")) return; - + spin_lock_irqsave(&info->lock, flags); - + if (tty_hung_up_p(filp)) { DBG_CNT("before DEC-hung"); goto out; } - + #ifdef SERIAL_DEBUG_OPEN - printk("rs_close ttys%d, count = %d\n", info->line, info->count); + printk(KERN_DEBUG "rs_close ttys%d, count = %d\n", + info->line, info->count); #endif - if ((tty->count == 1) && (info->count != 1)) { + if (tty->count == 1 && info->count != 1) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. Info->count should always @@ -1938,12 +1927,11 @@ static void rs_close(struct tty_struct *tty, struct file * filp) * one, we've got real problems, since it means the * serial port won't be shutdown. */ - printk("rs_close: bad serial port count; tty->count is 1, " - "info->count is %d\n", info->count); + printk(KERN_DEBUG "rs_close: bad serial port count; tty->count is 1, info->count is %d\n", info->count); info->count = 1; } if (--info->count < 0) { - printk("rs_close: bad serial port count for ttys%d: %d\n", + printk(KERN_ERR "rs_close: bad serial port count for ttys%d: %d\n", info->line, info->count); info->count = 0; } @@ -1955,7 +1943,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) spin_unlock_irqrestore(&info->lock, flags); /* - * Now we wait for the transmit buffer to clear; and we notify + * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. */ tty->closing = 1; @@ -1990,16 +1978,14 @@ static void rs_close(struct tty_struct *tty, struct file * filp) rs_wait_until_sent(tty, info->timeout); } shutdown(info); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + rs_flush_buffer(tty); tty_ldisc_flush(tty); tty->closing = 0; info->tty = NULL; if (info->blocked_open) { - if (info->close_delay) { + if (info->close_delay) msleep_interruptible(jiffies_to_msecs(info->close_delay)); - } wake_up_interruptible(&info->open_wait); } info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); @@ -2012,7 +1998,7 @@ out: static void rs_wait_until_sent(struct tty_struct *tty, int timeout) { - struct esp_struct *info = (struct esp_struct *)tty->driver_data; + struct esp_struct *info = tty->driver_data; unsigned long orig_jiffies, char_time; unsigned long flags; @@ -2036,10 +2022,10 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) msleep_interruptible(jiffies_to_msecs(char_time)); if (signal_pending(current)) - break; + return; if (timeout && time_after(jiffies, orig_jiffies + timeout)) - break; + return; spin_lock_irqsave(&info->lock, flags); serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); @@ -2054,11 +2040,11 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) */ static void esp_hangup(struct tty_struct *tty) { - struct esp_struct * info = (struct esp_struct *)tty->driver_data; - + struct esp_struct *info = tty->driver_data; + if (serial_paranoia_check(info, tty->name, "esp_hangup")) return; - + rs_flush_buffer(tty); shutdown(info); info->count = 0; @@ -2072,7 +2058,7 @@ static void esp_hangup(struct tty_struct *tty) * esp_open() and friends * ------------------------------------------------------------ */ -static int block_til_ready(struct tty_struct *tty, struct file * filp, +static int block_til_ready(struct tty_struct *tty, struct file *filp, struct esp_struct *info) { DECLARE_WAITQUEUE(wait, current); @@ -2121,11 +2107,11 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, retval = 0; add_wait_queue(&info->open_wait, &wait); #ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready before block: ttys%d, count = %d\n", + printk(KERN_DEBUG "block_til_ready before block: ttys%d, count = %d\n", info->line, info->count); #endif spin_lock_irqsave(&info->lock, flags); - if (!tty_hung_up_p(filp)) + if (!tty_hung_up_p(filp)) info->count--; info->blocked_open++; while (1) { @@ -2147,7 +2133,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, if (info->flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else - retval = -ERESTARTSYS; + retval = -ERESTARTSYS; #else retval = -EAGAIN; #endif @@ -2166,7 +2152,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, break; } #ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready blocking: ttys%d, count = %d\n", + printk(KERN_DEBUG "block_til_ready blocking: ttys%d, count = %d\n", info->line, info->count); #endif spin_unlock_irqrestore(&info->lock, flags); @@ -2180,14 +2166,14 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, info->blocked_open--; spin_unlock_irqrestore(&info->lock, flags); #ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready after blocking: ttys%d, count = %d\n", + printk(KERN_DEBUG "block_til_ready after blocking: ttys%d, count = %d\n", info->line, info->count); #endif if (retval) return retval; info->flags |= ASYNC_NORMAL_ACTIVE; return 0; -} +} /* * This routine is called whenever a serial port is opened. It @@ -2195,7 +2181,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, * the IRQ chain. It also performs the serial-specific * initialization for the tty structure. */ -static int esp_open(struct tty_struct *tty, struct file * filp) +static int esp_open(struct tty_struct *tty, struct file *filp) { struct esp_struct *info; int retval, line; @@ -2218,7 +2204,7 @@ static int esp_open(struct tty_struct *tty, struct file * filp) } #ifdef SERIAL_DEBUG_OPEN - printk("esp_open %s, count = %d\n", tty->name, info->count); + printk(KERN_DEBUG "esp_open %s, count = %d\n", tty->name, info->count); #endif spin_lock_irqsave(&info->lock, flags); info->count++; @@ -2226,7 +2212,7 @@ static int esp_open(struct tty_struct *tty, struct file * filp) info->tty = tty; spin_unlock_irqrestore(&info->lock, flags); - + /* * Start up serial port */ @@ -2237,14 +2223,13 @@ static int esp_open(struct tty_struct *tty, struct file * filp) retval = block_til_ready(tty, filp, info); if (retval) { #ifdef SERIAL_DEBUG_OPEN - printk("esp_open returning after block_til_ready with %d\n", + printk(KERN_DEBUG "esp_open returning after block_til_ready with %d\n", retval); #endif return retval; } - #ifdef SERIAL_DEBUG_OPEN - printk("esp_open %s successful...", tty->name); + printk(KERN_DEBUG "esp_open %s successful...", tty->name); #endif return 0; } @@ -2262,10 +2247,10 @@ static int esp_open(struct tty_struct *tty, struct file * filp) * number, and identifies which options were configured into this * driver. */ - -static inline void show_serial_version(void) + +static void show_serial_version(void) { - printk(KERN_INFO "%s version %s (DMA %u)\n", + printk(KERN_INFO "%s version %s (DMA %u)\n", serial_name, serial_version, dma); } @@ -2273,7 +2258,7 @@ static inline void show_serial_version(void) * This routine is called by espserial_init() to initialize a specific serial * port. */ -static inline int autoconfig(struct esp_struct * info) +static int autoconfig(struct esp_struct *info) { int port_detected = 0; unsigned long flags; @@ -2349,14 +2334,14 @@ static const struct tty_operations esp_ops = { static int __init espserial_init(void) { int i, offset; - struct esp_struct * info; + struct esp_struct *info; struct esp_struct *last_primary = NULL; - int esp[] = {0x100,0x140,0x180,0x200,0x240,0x280,0x300,0x380}; + int esp[] = { 0x100, 0x140, 0x180, 0x200, 0x240, 0x280, 0x300, 0x380 }; esp_driver = alloc_tty_driver(NR_PORTS); if (!esp_driver) return -ENOMEM; - + for (i = 0; i < NR_PRIMARY; i++) { if (irq[i] != 0) { if ((irq[i] < 2) || (irq[i] > 15) || (irq[i] == 6) || @@ -2378,20 +2363,20 @@ static int __init espserial_init(void) if ((flow_off < 1) || (flow_off > 1023)) flow_off = 1016; - + if ((flow_on < 1) || (flow_on > 1023)) flow_on = 944; if ((rx_timeout < 0) || (rx_timeout > 255)) rx_timeout = 128; - + if (flow_on >= flow_off) flow_on = flow_off - 1; show_serial_version(); /* Initialize the tty_driver structure */ - + esp_driver->owner = THIS_MODULE; esp_driver->name = "ttyP"; esp_driver->major = ESP_IN_MAJOR; @@ -2401,10 +2386,11 @@ static int __init espserial_init(void) esp_driver->init_termios = tty_std_termios; esp_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + esp_driver->init_termios.c_ispeed = 9600; + esp_driver->init_termios.c_ospeed = 9600; esp_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(esp_driver, &esp_ops); - if (tty_register_driver(esp_driver)) - { + if (tty_register_driver(esp_driver)) { printk(KERN_ERR "Couldn't register esp serial driver"); put_tty_driver(esp_driver); return 1; @@ -2412,8 +2398,7 @@ static int __init espserial_init(void) info = kzalloc(sizeof(struct esp_struct), GFP_KERNEL); - if (!info) - { + if (!info) { printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n"); tty_unregister_driver(esp_driver); put_tty_driver(esp_driver); @@ -2476,10 +2461,8 @@ static int __init espserial_init(void) info->stat_flags |= ESP_STAT_NEVER_DMA; info = kzalloc(sizeof(struct esp_struct), GFP_KERNEL); - if (!info) - { - printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n"); - + if (!info) { + printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n"); /* allow use of the already detected ports */ return 0; } @@ -2503,22 +2486,20 @@ static int __init espserial_init(void) return 0; } -static void __exit espserial_exit(void) +static void __exit espserial_exit(void) { int e1; struct esp_struct *temp_async; struct esp_pio_buffer *pio_buf; - /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ - if ((e1 = tty_unregister_driver(esp_driver))) - printk("SERIAL: failed to unregister serial driver (%d)\n", - e1); + e1 = tty_unregister_driver(esp_driver); + if (e1) + printk(KERN_ERR "esp: failed to unregister driver (%d)\n", e1); put_tty_driver(esp_driver); while (ports) { - if (ports->port) { + if (ports->port) release_region(ports->port, REGION_SIZE); - } temp_async = ports->next_port; kfree(ports); ports = temp_async; diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c index 7ed7da1d99cf..252f73e48596 100644 --- a/drivers/char/generic_serial.c +++ b/drivers/char/generic_serial.c @@ -40,27 +40,27 @@ static int gs_debug; #define gs_dprintk(f, str...) /* nothing */ #endif -#define func_enter() gs_dprintk (GS_DEBUG_FLOW, "gs: enter %s\n", __FUNCTION__) -#define func_exit() gs_dprintk (GS_DEBUG_FLOW, "gs: exit %s\n", __FUNCTION__) +#define func_enter() gs_dprintk (GS_DEBUG_FLOW, "gs: enter %s\n", __func__) +#define func_exit() gs_dprintk (GS_DEBUG_FLOW, "gs: exit %s\n", __func__) #define RS_EVENT_WRITE_WAKEUP 1 module_param(gs_debug, int, 0644); -void gs_put_char(struct tty_struct * tty, unsigned char ch) +int gs_put_char(struct tty_struct * tty, unsigned char ch) { struct gs_port *port; func_enter (); - if (!tty) return; + if (!tty) return 0; port = tty->driver_data; - if (!port) return; + if (!port) return 0; - if (! (port->flags & ASYNC_INITIALIZED)) return; + if (! (port->flags & ASYNC_INITIALIZED)) return 0; /* Take a lock on the serial tranmit buffer! */ mutex_lock(& port->port_write_mutex); @@ -68,7 +68,7 @@ void gs_put_char(struct tty_struct * tty, unsigned char ch) if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) { /* Sorry, buffer is full, drop character. Update statistics???? -- REW */ mutex_unlock(&port->port_write_mutex); - return; + return 0; } port->xmit_buf[port->xmit_head++] = ch; @@ -77,6 +77,7 @@ void gs_put_char(struct tty_struct * tty, unsigned char ch) mutex_unlock(&port->port_write_mutex); func_exit (); + return 1; } @@ -586,8 +587,7 @@ void gs_close(struct tty_struct * tty, struct file * filp) port->flags &= ~GS_ACTIVE; - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + gs_flush_buffer(tty); tty_ldisc_flush(tty); tty->closing = 0; diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 1399971be689..e7fb0bca3667 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -308,7 +308,7 @@ static int hpet_mmap(struct file *file, struct vm_area_struct *vma) if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT, PAGE_SIZE, vma->vm_page_prot)) { printk(KERN_ERR "%s: io_remap_pfn_range failed\n", - __FUNCTION__); + __func__); return -EAGAIN; } @@ -748,7 +748,7 @@ int hpet_alloc(struct hpet_data *hdp) */ if (hpet_is_known(hdp)) { printk(KERN_DEBUG "%s: duplicate HPET ignored\n", - __FUNCTION__); + __func__); return 0; } @@ -869,7 +869,7 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data) if (hpet_is_known(hdp)) { printk(KERN_DEBUG "%s: 0x%lx is busy\n", - __FUNCTION__, hdp->hd_phys_address); + __func__, hdp->hd_phys_address); iounmap(hdp->hd_address); return AE_ALREADY_EXISTS; } @@ -886,7 +886,7 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data) if (hpet_is_known(hdp)) { printk(KERN_DEBUG "%s: 0x%lx is busy\n", - __FUNCTION__, hdp->hd_phys_address); + __func__, hdp->hd_phys_address); iounmap(hdp->hd_address); return AE_ALREADY_EXISTS; } @@ -925,7 +925,7 @@ static int hpet_acpi_add(struct acpi_device *device) return -ENODEV; if (!data.hd_address || !data.hd_nirqs) { - printk("%s: no address or irqs in _CRS\n", __FUNCTION__); + printk("%s: no address or irqs in _CRS\n", __func__); return -ENODEV; } diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index d5a752da322f..59c6f9ab94e4 100644 --- a/drivers/char/hvsi.c +++ b/drivers/char/hvsi.c @@ -246,7 +246,7 @@ static void compact_inbuf(struct hvsi_struct *hp, uint8_t *read_to) { int remaining = (int)(hp->inbuf_end - read_to); - pr_debug("%s: %i chars remain\n", __FUNCTION__, remaining); + pr_debug("%s: %i chars remain\n", __func__, remaining); if (read_to != hp->inbuf) memmove(hp->inbuf, read_to, remaining); @@ -365,7 +365,7 @@ static int hvsi_version_respond(struct hvsi_struct *hp, uint16_t query_seqno) packet.u.version = HVSI_VERSION; packet.query_seqno = query_seqno+1; - pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len); + pr_debug("%s: sending %i bytes\n", __func__, packet.len); dbg_dump_hex((uint8_t*)&packet, packet.len); wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); @@ -437,7 +437,7 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, return NULL; if (overflow > 0) { - pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __FUNCTION__); + pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__); datalen = TTY_THRESHOLD_THROTTLE; } @@ -448,7 +448,7 @@ static struct tty_struct *hvsi_recv_data(struct hvsi_struct *hp, * we still have more data to deliver, so we need to save off the * overflow and send it later */ - pr_debug("%s: deferring overflow\n", __FUNCTION__); + pr_debug("%s: deferring overflow\n", __func__); memcpy(hp->throttle_buf, data + TTY_THRESHOLD_THROTTLE, overflow); hp->n_throttle = overflow; } @@ -474,11 +474,11 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ); if (chunklen == 0) { - pr_debug("%s: 0-length read\n", __FUNCTION__); + pr_debug("%s: 0-length read\n", __func__); return 0; } - pr_debug("%s: got %i bytes\n", __FUNCTION__, chunklen); + pr_debug("%s: got %i bytes\n", __func__, chunklen); dbg_dump_hex(hp->inbuf_end, chunklen); hp->inbuf_end += chunklen; @@ -495,7 +495,7 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, continue; } - pr_debug("%s: handling %i-byte packet\n", __FUNCTION__, + pr_debug("%s: handling %i-byte packet\n", __func__, len_packet(packet)); dbg_dump_packet(packet); @@ -526,7 +526,7 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, packet += len_packet(packet); if (*hangup || *handshake) { - pr_debug("%s: hangup or handshake\n", __FUNCTION__); + pr_debug("%s: hangup or handshake\n", __func__); /* * we need to send the hangup now before receiving any more data. * If we get "data, hangup, data", we can't deliver the second @@ -543,7 +543,7 @@ static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, static void hvsi_send_overflow(struct hvsi_struct *hp) { - pr_debug("%s: delivering %i bytes overflow\n", __FUNCTION__, + pr_debug("%s: delivering %i bytes overflow\n", __func__, hp->n_throttle); hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle); @@ -563,7 +563,7 @@ static irqreturn_t hvsi_interrupt(int irq, void *arg) unsigned long flags; int again = 1; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); while (again) { spin_lock_irqsave(&hp->lock, flags); @@ -647,7 +647,7 @@ static int hvsi_query(struct hvsi_struct *hp, uint16_t verb) packet.seqno = atomic_inc_return(&hp->seqno); packet.verb = verb; - pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len); + pr_debug("%s: sending %i bytes\n", __func__, packet.len); dbg_dump_hex((uint8_t*)&packet, packet.len); wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); @@ -674,7 +674,7 @@ static int hvsi_get_mctrl(struct hvsi_struct *hp) return ret; } - pr_debug("%s: mctrl 0x%x\n", __FUNCTION__, hp->mctrl); + pr_debug("%s: mctrl 0x%x\n", __func__, hp->mctrl); return 0; } @@ -694,7 +694,7 @@ static int hvsi_set_mctrl(struct hvsi_struct *hp, uint16_t mctrl) if (mctrl & TIOCM_DTR) packet.word = HVSI_TSDTR; - pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len); + pr_debug("%s: sending %i bytes\n", __func__, packet.len); dbg_dump_hex((uint8_t*)&packet, packet.len); wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); @@ -790,7 +790,7 @@ static void hvsi_close_protocol(struct hvsi_struct *hp) packet.len = 6; packet.verb = VSV_CLOSE_PROTOCOL; - pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len); + pr_debug("%s: sending %i bytes\n", __func__, packet.len); dbg_dump_hex((uint8_t*)&packet, packet.len); hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); @@ -803,7 +803,7 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp) int line = tty->index; int ret; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); if (line < 0 || line >= hvsi_count) return -ENODEV; @@ -868,7 +868,7 @@ static void hvsi_close(struct tty_struct *tty, struct file *filp) struct hvsi_struct *hp = tty->driver_data; unsigned long flags; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); if (tty_hung_up_p(filp)) return; @@ -920,7 +920,7 @@ static void hvsi_hangup(struct tty_struct *tty) struct hvsi_struct *hp = tty->driver_data; unsigned long flags; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); spin_lock_irqsave(&hp->lock, flags); @@ -942,7 +942,7 @@ static void hvsi_push(struct hvsi_struct *hp) n = hvsi_put_chars(hp, hp->outbuf, hp->n_outbuf); if (n > 0) { /* success */ - pr_debug("%s: wrote %i chars\n", __FUNCTION__, n); + pr_debug("%s: wrote %i chars\n", __func__, n); hp->n_outbuf = 0; } else if (n == -EIO) { __set_state(hp, HVSI_FSP_DIED); @@ -965,7 +965,7 @@ static void hvsi_write_worker(struct work_struct *work) spin_lock_irqsave(&hp->lock, flags); - pr_debug("%s: %i chars in buffer\n", __FUNCTION__, hp->n_outbuf); + pr_debug("%s: %i chars in buffer\n", __func__, hp->n_outbuf); if (!is_open(hp)) { /* @@ -983,7 +983,7 @@ static void hvsi_write_worker(struct work_struct *work) schedule_delayed_work(&hp->writer, 10); else { #ifdef DEBUG - pr_debug("%s: outbuf emptied after %li jiffies\n", __FUNCTION__, + pr_debug("%s: outbuf emptied after %li jiffies\n", __func__, jiffies - start_j); start_j = 0; #endif /* DEBUG */ @@ -1020,11 +1020,11 @@ static int hvsi_write(struct tty_struct *tty, spin_lock_irqsave(&hp->lock, flags); - pr_debug("%s: %i chars in buffer\n", __FUNCTION__, hp->n_outbuf); + pr_debug("%s: %i chars in buffer\n", __func__, hp->n_outbuf); if (!is_open(hp)) { /* we're either closing or not yet open; don't accept data */ - pr_debug("%s: not open\n", __FUNCTION__); + pr_debug("%s: not open\n", __func__); goto out; } @@ -1058,7 +1058,7 @@ out: spin_unlock_irqrestore(&hp->lock, flags); if (total != origcount) - pr_debug("%s: wanted %i, only wrote %i\n", __FUNCTION__, origcount, + pr_debug("%s: wanted %i, only wrote %i\n", __func__, origcount, total); return total; @@ -1072,7 +1072,7 @@ static void hvsi_throttle(struct tty_struct *tty) { struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); h_vio_signal(hp->vtermno, VIO_IRQ_DISABLE); } @@ -1083,7 +1083,7 @@ static void hvsi_unthrottle(struct tty_struct *tty) unsigned long flags; int shouldflip = 0; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); spin_lock_irqsave(&hp->lock, flags); if (hp->n_throttle) { @@ -1302,7 +1302,7 @@ static int __init hvsi_console_init(void) hp->virq = irq_create_mapping(NULL, irq[0]); if (hp->virq == NO_IRQ) { printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n", - __FUNCTION__, irq[0]); + __func__, irq[0]); continue; } diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index 8609b8236c67..f49037b744f9 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -82,6 +82,7 @@ static int i8k_ioctl(struct inode *, struct file *, unsigned int, unsigned long); static const struct file_operations i8k_fops = { + .owner = THIS_MODULE, .open = i8k_open_fs, .read = seq_read, .llseek = seq_lseek, @@ -554,13 +555,10 @@ static int __init i8k_init(void) return -ENODEV; /* Register the proc entry */ - proc_i8k = create_proc_entry("i8k", 0, NULL); + proc_i8k = proc_create("i8k", 0, NULL, &i8k_fops); if (!proc_i8k) return -ENOENT; - proc_i8k->proc_fops = &i8k_fops; - proc_i8k->owner = THIS_MODULE; - printk(KERN_INFO "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n", I8K_VERSION); diff --git a/drivers/char/ip2/i2ellis.c b/drivers/char/ip2/i2ellis.c index 61ef013b8445..3601017f58cf 100644 --- a/drivers/char/ip2/i2ellis.c +++ b/drivers/char/ip2/i2ellis.c @@ -53,7 +53,7 @@ static int ii2Safe; // Safe I/O address for delay routine static int iiDelayed; // Set when the iiResetDelay function is // called. Cleared when ANY board is reset. -static rwlock_t Dl_spinlock; +static DEFINE_RWLOCK(Dl_spinlock); //******** //* Code * @@ -82,7 +82,6 @@ static rwlock_t Dl_spinlock; static void iiEllisInit(void) { - LOCK_INIT(&Dl_spinlock); } //****************************************************************************** @@ -132,7 +131,7 @@ iiSetAddress( i2eBordStrPtr pB, int address, delayFunc_t delay ) || (address & 0x7) ) { - COMPLETE(pB,I2EE_BADADDR); + I2_COMPLETE(pB, I2EE_BADADDR); } // Initialize accelerators @@ -152,7 +151,7 @@ iiSetAddress( i2eBordStrPtr pB, int address, delayFunc_t delay ) pB->i2eValid = I2E_MAGIC; pB->i2eState = II_STATE_COLD; - COMPLETE(pB, I2EE_GOOD); + I2_COMPLETE(pB, I2EE_GOOD); } //****************************************************************************** @@ -177,12 +176,12 @@ iiReset(i2eBordStrPtr pB) // Magic number should be set, else even the address is suspect if (pB->i2eValid != I2E_MAGIC) { - COMPLETE(pB, I2EE_BADMAGIC); + I2_COMPLETE(pB, I2EE_BADMAGIC); } - OUTB(pB->i2eBase + FIFO_RESET, 0); // Any data will do + outb(0, pB->i2eBase + FIFO_RESET); /* Any data will do */ iiDelay(pB, 50); // Pause between resets - OUTB(pB->i2eBase + FIFO_RESET, 0); // Second reset + outb(0, pB->i2eBase + FIFO_RESET); /* Second reset */ // We must wait before even attempting to read anything from the FIFO: the // board's P.O.S.T may actually attempt to read and write its end of the @@ -203,7 +202,7 @@ iiReset(i2eBordStrPtr pB) // Ensure anything which would have been of use to standard loadware is // blanked out, since board has now forgotten everything!. - pB->i2eUsingIrq = IRQ_UNDEFINED; // Not set up to use an interrupt yet + pB->i2eUsingIrq = I2_IRQ_UNDEFINED; /* to not use an interrupt so far */ pB->i2eWaitingForEmptyFifo = 0; pB->i2eOutMailWaiting = 0; pB->i2eChannelPtr = NULL; @@ -215,7 +214,7 @@ iiReset(i2eBordStrPtr pB) pB->i2eFatalTrap = NULL; pB->i2eFatal = 0; - COMPLETE(pB, I2EE_GOOD); + I2_COMPLETE(pB, I2EE_GOOD); } //****************************************************************************** @@ -235,14 +234,14 @@ static int iiResetDelay(i2eBordStrPtr pB) { if (pB->i2eValid != I2E_MAGIC) { - COMPLETE(pB, I2EE_BADMAGIC); + I2_COMPLETE(pB, I2EE_BADMAGIC); } if (pB->i2eState != II_STATE_RESET) { - COMPLETE(pB, I2EE_BADSTATE); + I2_COMPLETE(pB, I2EE_BADSTATE); } iiDelay(pB,2000); /* Now we wait for two seconds. */ iiDelayed = 1; /* Delay has been called: ok to initialize */ - COMPLETE(pB, I2EE_GOOD); + I2_COMPLETE(pB, I2EE_GOOD); } //****************************************************************************** @@ -273,12 +272,12 @@ iiInitialize(i2eBordStrPtr pB) if (pB->i2eValid != I2E_MAGIC) { - COMPLETE(pB, I2EE_BADMAGIC); + I2_COMPLETE(pB, I2EE_BADMAGIC); } if (pB->i2eState != II_STATE_RESET || !iiDelayed) { - COMPLETE(pB, I2EE_BADSTATE); + I2_COMPLETE(pB, I2EE_BADSTATE); } // In case there is a failure short of our completely reading the power-up @@ -291,13 +290,12 @@ iiInitialize(i2eBordStrPtr pB) for (itemp = 0; itemp < sizeof(porStr); itemp++) { // We expect the entire message is ready. - if (HAS_NO_INPUT(pB)) - { + if (!I2_HAS_INPUT(pB)) { pB->i2ePomSize = itemp; - COMPLETE(pB, I2EE_PORM_SHORT); + I2_COMPLETE(pB, I2EE_PORM_SHORT); } - pB->i2ePom.c[itemp] = c = BYTE_FROM(pB); + pB->i2ePom.c[itemp] = c = inb(pB->i2eData); // We check the magic numbers as soon as they are supposed to be read // (rather than after) to minimize effect of reading something we @@ -306,22 +304,22 @@ iiInitialize(i2eBordStrPtr pB) (itemp == POR_2_INDEX && c != POR_MAGIC_2)) { pB->i2ePomSize = itemp+1; - COMPLETE(pB, I2EE_BADMAGIC); + I2_COMPLETE(pB, I2EE_BADMAGIC); } } pB->i2ePomSize = itemp; // Ensure that this was all the data... - if (HAS_INPUT(pB)) - COMPLETE(pB, I2EE_PORM_LONG); + if (I2_HAS_INPUT(pB)) + I2_COMPLETE(pB, I2EE_PORM_LONG); // For now, we'll fail to initialize if P.O.S.T reports bad chip mapper: // Implying we will not be able to download any code either: That's ok: the // condition is pretty explicit. if (pB->i2ePom.e.porDiag1 & POR_BAD_MAPPER) { - COMPLETE(pB, I2EE_POSTERR); + I2_COMPLETE(pB, I2EE_POSTERR); } // Determine anything which must be done differently depending on the family @@ -332,7 +330,7 @@ iiInitialize(i2eBordStrPtr pB) pB->i2eFifoStyle = FIFO_II; pB->i2eFifoSize = 512; // 512 bytes, always - pB->i2eDataWidth16 = NO; + pB->i2eDataWidth16 = false; pB->i2eMaxIrq = 15; // Because board cannot tell us it is in an 8-bit // slot, we do allow it to be done (documentation!) @@ -354,7 +352,7 @@ iiInitialize(i2eBordStrPtr pB) // should always be consistent for IntelliPort-II. Ditto below... if (pB->i2ePom.e.porPorts1 != 4) { - COMPLETE(pB, I2EE_INCONSIST); + I2_COMPLETE(pB, I2EE_INCONSIST); } break; @@ -364,7 +362,7 @@ iiInitialize(i2eBordStrPtr pB) pB->i2eChannelMap[0] = 0xff; // Eight port if (pB->i2ePom.e.porPorts1 != 8) { - COMPLETE(pB, I2EE_INCONSIST); + I2_COMPLETE(pB, I2EE_INCONSIST); } break; @@ -373,7 +371,7 @@ iiInitialize(i2eBordStrPtr pB) pB->i2eChannelMap[0] = 0x3f; // Six Port if (pB->i2ePom.e.porPorts1 != 6) { - COMPLETE(pB, I2EE_INCONSIST); + I2_COMPLETE(pB, I2EE_INCONSIST); } break; } @@ -402,7 +400,7 @@ iiInitialize(i2eBordStrPtr pB) if (itemp < 8 || itemp > 15) { - COMPLETE(pB, I2EE_INCONSIST); + I2_COMPLETE(pB, I2EE_INCONSIST); } pB->i2eFifoSize = (1 << itemp); @@ -450,26 +448,26 @@ iiInitialize(i2eBordStrPtr pB) switch (pB->i2ePom.e.porBus & (POR_BUS_SLOT16 | POR_BUS_DIP16) ) { case POR_BUS_SLOT16 | POR_BUS_DIP16: - pB->i2eDataWidth16 = YES; + pB->i2eDataWidth16 = true; pB->i2eMaxIrq = 15; break; case POR_BUS_SLOT16: - pB->i2eDataWidth16 = NO; + pB->i2eDataWidth16 = false; pB->i2eMaxIrq = 15; break; case 0: case POR_BUS_DIP16: // In an 8-bit slot, DIP switch don't care. default: - pB->i2eDataWidth16 = NO; + pB->i2eDataWidth16 = false; pB->i2eMaxIrq = 7; break; } break; // POR_ID_FIIEX case default: // Unknown type of board - COMPLETE(pB, I2EE_BAD_FAMILY); + I2_COMPLETE(pB, I2EE_BAD_FAMILY); break; } // End the switch based on family @@ -483,17 +481,14 @@ iiInitialize(i2eBordStrPtr pB) { case POR_BUS_T_ISA: case POR_BUS_T_UNK: // If the type of bus is undeclared, assume ok. - pB->i2eChangeIrq = YES; - break; case POR_BUS_T_MCA: case POR_BUS_T_EISA: - pB->i2eChangeIrq = NO; break; default: - COMPLETE(pB, I2EE_BADBUS); + I2_COMPLETE(pB, I2EE_BADBUS); } - if (pB->i2eDataWidth16 == YES) + if (pB->i2eDataWidth16) { pB->i2eWriteBuf = iiWriteBuf16; pB->i2eReadBuf = iiReadBuf16; @@ -529,7 +524,7 @@ iiInitialize(i2eBordStrPtr pB) break; default: - COMPLETE(pB, I2EE_INCONSIST); + I2_COMPLETE(pB, I2EE_INCONSIST); } // Initialize state information. @@ -549,7 +544,7 @@ iiInitialize(i2eBordStrPtr pB) // Everything is ok now, return with good status/ pB->i2eValid = I2E_MAGIC; - COMPLETE(pB, I2EE_GOOD); + I2_COMPLETE(pB, I2EE_GOOD); } //****************************************************************************** @@ -658,7 +653,7 @@ ii2DelayIO(unsigned int mseconds) while(mseconds--) { int i = ii2DelValue; while ( i-- ) { - INB ( ii2Safe ); + inb(ii2Safe); } } } @@ -709,11 +704,11 @@ iiWriteBuf16(i2eBordStrPtr pB, unsigned char *address, int count) { // Rudimentary sanity checking here. if (pB->i2eValid != I2E_MAGIC) - COMPLETE(pB, I2EE_INVALID); + I2_COMPLETE(pB, I2EE_INVALID); - OUTSW ( pB->i2eData, address, count); + I2_OUTSW(pB->i2eData, address, count); - COMPLETE(pB, I2EE_GOOD); + I2_COMPLETE(pB, I2EE_GOOD); } //****************************************************************************** @@ -738,11 +733,11 @@ iiWriteBuf8(i2eBordStrPtr pB, unsigned char *address, int count) { /* Rudimentary sanity checking here */ if (pB->i2eValid != I2E_MAGIC) - COMPLETE(pB, I2EE_INVALID); + I2_COMPLETE(pB, I2EE_INVALID); - OUTSB ( pB->i2eData, address, count ); + I2_OUTSB(pB->i2eData, address, count); - COMPLETE(pB, I2EE_GOOD); + I2_COMPLETE(pB, I2EE_GOOD); } //****************************************************************************** @@ -767,11 +762,11 @@ iiReadBuf16(i2eBordStrPtr pB, unsigned char *address, int count) { // Rudimentary sanity checking here. if (pB->i2eValid != I2E_MAGIC) - COMPLETE(pB, I2EE_INVALID); + I2_COMPLETE(pB, I2EE_INVALID); - INSW ( pB->i2eData, address, count); + I2_INSW(pB->i2eData, address, count); - COMPLETE(pB, I2EE_GOOD); + I2_COMPLETE(pB, I2EE_GOOD); } //****************************************************************************** @@ -796,11 +791,11 @@ iiReadBuf8(i2eBordStrPtr pB, unsigned char *address, int count) { // Rudimentary sanity checking here. if (pB->i2eValid != I2E_MAGIC) - COMPLETE(pB, I2EE_INVALID); + I2_COMPLETE(pB, I2EE_INVALID); - INSB ( pB->i2eData, address, count); + I2_INSB(pB->i2eData, address, count); - COMPLETE(pB, I2EE_GOOD); + I2_COMPLETE(pB, I2EE_GOOD); } //****************************************************************************** @@ -820,7 +815,7 @@ iiReadBuf8(i2eBordStrPtr pB, unsigned char *address, int count) static unsigned short iiReadWord16(i2eBordStrPtr pB) { - return (unsigned short)( INW(pB->i2eData) ); + return inw(pB->i2eData); } //****************************************************************************** @@ -842,9 +837,9 @@ iiReadWord8(i2eBordStrPtr pB) { unsigned short urs; - urs = INB ( pB->i2eData ); + urs = inb(pB->i2eData); - return ( ( INB ( pB->i2eData ) << 8 ) | urs ); + return (inb(pB->i2eData) << 8) | urs; } //****************************************************************************** @@ -865,7 +860,7 @@ iiReadWord8(i2eBordStrPtr pB) static void iiWriteWord16(i2eBordStrPtr pB, unsigned short value) { - WORD_TO(pB, (int)value); + outw((int)value, pB->i2eData); } //****************************************************************************** @@ -886,8 +881,8 @@ iiWriteWord16(i2eBordStrPtr pB, unsigned short value) static void iiWriteWord8(i2eBordStrPtr pB, unsigned short value) { - BYTE_TO(pB, (char)value); - BYTE_TO(pB, (char)(value >> 8) ); + outb((char)value, pB->i2eData); + outb((char)(value >> 8), pB->i2eData); } //****************************************************************************** @@ -939,30 +934,30 @@ iiWaitForTxEmptyII(i2eBordStrPtr pB, int mSdelay) // interrupts of any kind. - WRITE_LOCK_IRQSAVE(&Dl_spinlock,flags) - OUTB(pB->i2ePointer, SEL_COMMAND); - OUTB(pB->i2ePointer, SEL_CMD_SH); + write_lock_irqsave(&Dl_spinlock, flags); + outb(SEL_COMMAND, pB->i2ePointer); + outb(SEL_CMD_SH, pB->i2ePointer); - itemp = INB(pB->i2eStatus); + itemp = inb(pB->i2eStatus); - OUTB(pB->i2ePointer, SEL_COMMAND); - OUTB(pB->i2ePointer, SEL_CMD_UNSH); + outb(SEL_COMMAND, pB->i2ePointer); + outb(SEL_CMD_UNSH, pB->i2ePointer); if (itemp & ST_IN_EMPTY) { - UPDATE_FIFO_ROOM(pB); - WRITE_UNLOCK_IRQRESTORE(&Dl_spinlock,flags) - COMPLETE(pB, I2EE_GOOD); + I2_UPDATE_FIFO_ROOM(pB); + write_unlock_irqrestore(&Dl_spinlock, flags); + I2_COMPLETE(pB, I2EE_GOOD); } - WRITE_UNLOCK_IRQRESTORE(&Dl_spinlock,flags) + write_unlock_irqrestore(&Dl_spinlock, flags); if (mSdelay-- == 0) break; iiDelay(pB, 1); /* 1 mS granularity on checking condition */ } - COMPLETE(pB, I2EE_TXE_TIME); + I2_COMPLETE(pB, I2EE_TXE_TIME); } //****************************************************************************** @@ -1002,21 +997,21 @@ iiWaitForTxEmptyIIEX(i2eBordStrPtr pB, int mSdelay) // you will generally not want to service interrupts or in any way // disrupt the assumptions implicit in the larger context. - WRITE_LOCK_IRQSAVE(&Dl_spinlock,flags) + write_lock_irqsave(&Dl_spinlock, flags); - if (INB(pB->i2eStatus) & STE_OUT_MT) { - UPDATE_FIFO_ROOM(pB); - WRITE_UNLOCK_IRQRESTORE(&Dl_spinlock,flags) - COMPLETE(pB, I2EE_GOOD); + if (inb(pB->i2eStatus) & STE_OUT_MT) { + I2_UPDATE_FIFO_ROOM(pB); + write_unlock_irqrestore(&Dl_spinlock, flags); + I2_COMPLETE(pB, I2EE_GOOD); } - WRITE_UNLOCK_IRQRESTORE(&Dl_spinlock,flags) + write_unlock_irqrestore(&Dl_spinlock, flags); if (mSdelay-- == 0) break; iiDelay(pB, 1); // 1 mS granularity on checking condition } - COMPLETE(pB, I2EE_TXE_TIME); + I2_COMPLETE(pB, I2EE_TXE_TIME); } //****************************************************************************** @@ -1038,8 +1033,8 @@ static int iiTxMailEmptyII(i2eBordStrPtr pB) { int port = pB->i2ePointer; - OUTB ( port, SEL_OUTMAIL ); - return ( INB(port) == 0 ); + outb(SEL_OUTMAIL, port); + return inb(port) == 0; } //****************************************************************************** @@ -1060,7 +1055,7 @@ iiTxMailEmptyII(i2eBordStrPtr pB) static int iiTxMailEmptyIIEX(i2eBordStrPtr pB) { - return !(INB(pB->i2eStatus) & STE_OUT_MAIL); + return !(inb(pB->i2eStatus) & STE_OUT_MAIL); } //****************************************************************************** @@ -1084,10 +1079,10 @@ iiTrySendMailII(i2eBordStrPtr pB, unsigned char mail) { int port = pB->i2ePointer; - OUTB(port, SEL_OUTMAIL); - if (INB(port) == 0) { - OUTB(port, SEL_OUTMAIL); - OUTB(port, mail); + outb(SEL_OUTMAIL, port); + if (inb(port) == 0) { + outb(SEL_OUTMAIL, port); + outb(mail, port); return 1; } return 0; @@ -1112,10 +1107,9 @@ iiTrySendMailII(i2eBordStrPtr pB, unsigned char mail) static int iiTrySendMailIIEX(i2eBordStrPtr pB, unsigned char mail) { - if(INB(pB->i2eStatus) & STE_OUT_MAIL) { + if (inb(pB->i2eStatus) & STE_OUT_MAIL) return 0; - } - OUTB(pB->i2eXMail, mail); + outb(mail, pB->i2eXMail); return 1; } @@ -1136,9 +1130,9 @@ iiTrySendMailIIEX(i2eBordStrPtr pB, unsigned char mail) static unsigned short iiGetMailII(i2eBordStrPtr pB) { - if (HAS_MAIL(pB)) { - OUTB(pB->i2ePointer, SEL_INMAIL); - return INB(pB->i2ePointer); + if (I2_HAS_MAIL(pB)) { + outb(SEL_INMAIL, pB->i2ePointer); + return inb(pB->i2ePointer); } else { return NO_MAIL_HERE; } @@ -1161,11 +1155,10 @@ iiGetMailII(i2eBordStrPtr pB) static unsigned short iiGetMailIIEX(i2eBordStrPtr pB) { - if (HAS_MAIL(pB)) { - return INB(pB->i2eXMail); - } else { + if (I2_HAS_MAIL(pB)) + return inb(pB->i2eXMail); + else return NO_MAIL_HERE; - } } //****************************************************************************** @@ -1184,8 +1177,8 @@ iiGetMailIIEX(i2eBordStrPtr pB) static void iiEnableMailIrqII(i2eBordStrPtr pB) { - OUTB(pB->i2ePointer, SEL_MASK); - OUTB(pB->i2ePointer, ST_IN_MAIL); + outb(SEL_MASK, pB->i2ePointer); + outb(ST_IN_MAIL, pB->i2ePointer); } //****************************************************************************** @@ -1204,7 +1197,7 @@ iiEnableMailIrqII(i2eBordStrPtr pB) static void iiEnableMailIrqIIEX(i2eBordStrPtr pB) { - OUTB(pB->i2eXMask, MX_IN_MAIL); + outb(MX_IN_MAIL, pB->i2eXMask); } //****************************************************************************** @@ -1223,8 +1216,8 @@ iiEnableMailIrqIIEX(i2eBordStrPtr pB) static void iiWriteMaskII(i2eBordStrPtr pB, unsigned char value) { - OUTB(pB->i2ePointer, SEL_MASK); - OUTB(pB->i2ePointer, value); + outb(SEL_MASK, pB->i2ePointer); + outb(value, pB->i2ePointer); } //****************************************************************************** @@ -1243,7 +1236,7 @@ iiWriteMaskII(i2eBordStrPtr pB, unsigned char value) static void iiWriteMaskIIEX(i2eBordStrPtr pB, unsigned char value) { - OUTB(pB->i2eXMask, value); + outb(value, pB->i2eXMask); } //****************************************************************************** @@ -1354,9 +1347,8 @@ iiDownloadBlock ( i2eBordStrPtr pB, loadHdrStrPtr pSource, int isStandard) // immediately and be harmless, though not strictly necessary. itemp = MAX_DLOAD_ACK_TIME/10; while (--itemp) { - if (HAS_INPUT(pB)) { - switch(BYTE_FROM(pB)) - { + if (I2_HAS_INPUT(pB)) { + switch (inb(pB->i2eData)) { case LOADWARE_OK: pB->i2eState = isStandard ? II_STATE_STDLOADED :II_STATE_LOADED; diff --git a/drivers/char/ip2/i2ellis.h b/drivers/char/ip2/i2ellis.h index 433305062fb8..c88a64e527aa 100644 --- a/drivers/char/ip2/i2ellis.h +++ b/drivers/char/ip2/i2ellis.h @@ -185,10 +185,6 @@ typedef struct _i2eBordStr // The highest allowable IRQ, based on the // slot size. - unsigned char i2eChangeIrq; - // Whether tis valid to change IRQ's - // ISA = ok, EISA, MicroChannel, no - // Accelerators for various addresses on the board int i2eBase; // I/O Address of the Board int i2eData; // From here data transfers happen @@ -431,12 +427,6 @@ typedef struct _i2eBordStr // Manifests for i2eBordStr: //------------------------------------------- -#define YES 1 -#define NO 0 - -#define NULLFUNC (void (*)(void))0 -#define NULLPTR (void *)0 - typedef void (*delayFunc_t)(unsigned int); // i2eValid @@ -494,8 +484,8 @@ typedef void (*delayFunc_t)(unsigned int); // i2eUsingIrq // -#define IRQ_UNDEFINED 0x1352 // No valid irq (or polling = 0) can ever - // promote to this! +#define I2_IRQ_UNDEFINED 0x1352 /* No valid irq (or polling = 0) can + * ever promote to this! */ //------------------------------------------ // Handy Macros for i2ellis.c and others // Note these are common to -II and -IIEX @@ -504,41 +494,14 @@ typedef void (*delayFunc_t)(unsigned int); // Given a pointer to the board structure, does the input FIFO have any data or // not? // -#define HAS_INPUT(pB) !(INB(pB->i2eStatus) & ST_IN_EMPTY) -#define HAS_NO_INPUT(pB) (INB(pB->i2eStatus) & ST_IN_EMPTY) - -// Given a pointer to board structure, read a byte or word from the fifo -// -#define BYTE_FROM(pB) (unsigned char)INB(pB->i2eData) -#define WORD_FROM(pB) (unsigned short)INW(pB->i2eData) - -// Given a pointer to board structure, is there room for any data to be written -// to the data fifo? -// -#define HAS_OUTROOM(pB) !(INB(pB->i2eStatus) & ST_OUT_FULL) -#define HAS_NO_OUTROOM(pB) (INB(pB->i2eStatus) & ST_OUT_FULL) - -// Given a pointer to board structure, write a single byte to the fifo -// structure. Note that for 16-bit interfaces, the high order byte is undefined -// and unknown. -// -#define BYTE_TO(pB, c) OUTB(pB->i2eData,(c)) - -// Write a word to the fifo structure. For 8-bit interfaces, this may have -// unknown results. -// -#define WORD_TO(pB, c) OUTW(pB->i2eData,(c)) +#define I2_HAS_INPUT(pB) !(inb(pB->i2eStatus) & ST_IN_EMPTY) // Given a pointer to the board structure, is there anything in the incoming // mailbox? // -#define HAS_MAIL(pB) (INB(pB->i2eStatus) & ST_IN_MAIL) +#define I2_HAS_MAIL(pB) (inb(pB->i2eStatus) & ST_IN_MAIL) -#define UPDATE_FIFO_ROOM(pB) (pB)->i2eFifoRemains=(pB)->i2eFifoSize - -// Handy macro to round up a number (like the buffer write and read routines do) -// -#define ROUNDUP(number) (((number)+1) & (~1)) +#define I2_UPDATE_FIFO_ROOM(pB) ((pB)->i2eFifoRemains = (pB)->i2eFifoSize) //------------------------------------------ // Function Declarations for i2ellis.c @@ -593,20 +556,11 @@ static int iiDownloadBlock(i2eBordStrPtr, loadHdrStrPtr, int); // static int iiDownloadAll(i2eBordStrPtr, loadHdrStrPtr, int, int); -// Called indirectly always. Needed externally so the routine might be -// SPECIFIED as an argument to iiReset() -// -//static void ii2DelayIO(unsigned int); // N-millisecond delay using - //hardware spin -//static void ii2DelayTimer(unsigned int); // N-millisecond delay using Linux - //timer - // Many functions defined here return True if good, False otherwise, with an // error code in i2eError field. Here is a handy macro for setting the error // code and returning. // -#define COMPLETE(pB,code) \ - do { \ +#define I2_COMPLETE(pB,code) do { \ pB->i2eError = code; \ return (code == I2EE_GOOD);\ } while (0) diff --git a/drivers/char/ip2/i2hw.h b/drivers/char/ip2/i2hw.h index 15fe04e748f4..8aa6e7ab8d5b 100644 --- a/drivers/char/ip2/i2hw.h +++ b/drivers/char/ip2/i2hw.h @@ -129,7 +129,6 @@ registers, use byte operations only. //------------------------------------------------ // #include "ip2types.h" -#include "i2os.h" /* For any o.s., compiler, or host-related issues */ //------------------------------------------------------------------------- // Manifests for the I/O map: @@ -644,5 +643,10 @@ typedef union _loadHdrStr #define ABS_BIGGEST_BOX 16 // Absolute the most ports per box #define ABS_MOST_PORTS (ABS_MAX_BOXES * ABS_BIGGEST_BOX) +#define I2_OUTSW(port, addr, count) outsw((port), (addr), (((count)+1)/2)) +#define I2_OUTSB(port, addr, count) outsb((port), (addr), (((count)+1))&-2) +#define I2_INSW(port, addr, count) insw((port), (addr), (((count)+1)/2)) +#define I2_INSB(port, addr, count) insb((port), (addr), (((count)+1))&-2) + #endif // I2HW_H diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c index 9c25320121ef..938879cc7bcc 100644 --- a/drivers/char/ip2/i2lib.c +++ b/drivers/char/ip2/i2lib.c @@ -227,17 +227,17 @@ i2InitChannels ( i2eBordStrPtr pB, int nChannels, i2ChanStrPtr pCh) i2ChanStrPtr *ppCh; if (pB->i2eValid != I2E_MAGIC) { - COMPLETE(pB, I2EE_BADMAGIC); + I2_COMPLETE(pB, I2EE_BADMAGIC); } if (pB->i2eState != II_STATE_STDLOADED) { - COMPLETE(pB, I2EE_BADSTATE); + I2_COMPLETE(pB, I2EE_BADSTATE); } - LOCK_INIT(&pB->read_fifo_spinlock); - LOCK_INIT(&pB->write_fifo_spinlock); - LOCK_INIT(&pB->Dbuf_spinlock); - LOCK_INIT(&pB->Bbuf_spinlock); - LOCK_INIT(&pB->Fbuf_spinlock); + rwlock_init(&pB->read_fifo_spinlock); + rwlock_init(&pB->write_fifo_spinlock); + rwlock_init(&pB->Dbuf_spinlock); + rwlock_init(&pB->Bbuf_spinlock); + rwlock_init(&pB->Fbuf_spinlock); // NO LOCK needed yet - this is init @@ -259,10 +259,10 @@ i2InitChannels ( i2eBordStrPtr pB, int nChannels, i2ChanStrPtr pCh) if ( !(pB->i2eChannelMap[index >> 4] & (1 << (index & 0xf)) ) ) { continue; } - LOCK_INIT(&pCh->Ibuf_spinlock); - LOCK_INIT(&pCh->Obuf_spinlock); - LOCK_INIT(&pCh->Cbuf_spinlock); - LOCK_INIT(&pCh->Pbuf_spinlock); + rwlock_init(&pCh->Ibuf_spinlock); + rwlock_init(&pCh->Obuf_spinlock); + rwlock_init(&pCh->Cbuf_spinlock); + rwlock_init(&pCh->Pbuf_spinlock); // NO LOCK needed yet - this is init // Set up validity flag according to support level if (pB->i2eGoodMap[index >> 4] & (1 << (index & 0xf)) ) { @@ -347,7 +347,7 @@ i2InitChannels ( i2eBordStrPtr pB, int nChannels, i2ChanStrPtr pCh) } // No need to check for wrap here; this is initialization. pB->i2Fbuf_stuff = stuffIndex; - COMPLETE(pB, I2EE_GOOD); + I2_COMPLETE(pB, I2EE_GOOD); } @@ -374,7 +374,7 @@ i2DeQueueNeeds(i2eBordStrPtr pB, int type) case NEED_INLINE: - WRITE_LOCK_IRQSAVE(&pB->Dbuf_spinlock,flags); + write_lock_irqsave(&pB->Dbuf_spinlock, flags); if ( pB->i2Dbuf_stuff != pB->i2Dbuf_strip) { queueIndex = pB->i2Dbuf_strip; @@ -386,12 +386,12 @@ i2DeQueueNeeds(i2eBordStrPtr pB, int type) pB->i2Dbuf_strip = queueIndex; pCh->channelNeeds &= ~NEED_INLINE; } - WRITE_UNLOCK_IRQRESTORE(&pB->Dbuf_spinlock,flags); + write_unlock_irqrestore(&pB->Dbuf_spinlock, flags); break; case NEED_BYPASS: - WRITE_LOCK_IRQSAVE(&pB->Bbuf_spinlock,flags); + write_lock_irqsave(&pB->Bbuf_spinlock, flags); if (pB->i2Bbuf_stuff != pB->i2Bbuf_strip) { queueIndex = pB->i2Bbuf_strip; @@ -403,12 +403,12 @@ i2DeQueueNeeds(i2eBordStrPtr pB, int type) pB->i2Bbuf_strip = queueIndex; pCh->channelNeeds &= ~NEED_BYPASS; } - WRITE_UNLOCK_IRQRESTORE(&pB->Bbuf_spinlock,flags); + write_unlock_irqrestore(&pB->Bbuf_spinlock, flags); break; case NEED_FLOW: - WRITE_LOCK_IRQSAVE(&pB->Fbuf_spinlock,flags); + write_lock_irqsave(&pB->Fbuf_spinlock, flags); if (pB->i2Fbuf_stuff != pB->i2Fbuf_strip) { queueIndex = pB->i2Fbuf_strip; @@ -420,7 +420,7 @@ i2DeQueueNeeds(i2eBordStrPtr pB, int type) pB->i2Fbuf_strip = queueIndex; pCh->channelNeeds &= ~NEED_FLOW; } - WRITE_UNLOCK_IRQRESTORE(&pB->Fbuf_spinlock,flags); + write_unlock_irqrestore(&pB->Fbuf_spinlock, flags); break; default: printk(KERN_ERR "i2DeQueueNeeds called with bad type:%x\n",type); @@ -453,7 +453,7 @@ i2QueueNeeds(i2eBordStrPtr pB, i2ChanStrPtr pCh, int type) case NEED_INLINE: - WRITE_LOCK_IRQSAVE(&pB->Dbuf_spinlock,flags); + write_lock_irqsave(&pB->Dbuf_spinlock, flags); if ( !(pCh->channelNeeds & NEED_INLINE) ) { pCh->channelNeeds |= NEED_INLINE; @@ -463,12 +463,12 @@ i2QueueNeeds(i2eBordStrPtr pB, i2ChanStrPtr pCh, int type) queueIndex = 0; pB->i2Dbuf_stuff = queueIndex; } - WRITE_UNLOCK_IRQRESTORE(&pB->Dbuf_spinlock,flags); + write_unlock_irqrestore(&pB->Dbuf_spinlock, flags); break; case NEED_BYPASS: - WRITE_LOCK_IRQSAVE(&pB->Bbuf_spinlock,flags); + write_lock_irqsave(&pB->Bbuf_spinlock, flags); if ((type & NEED_BYPASS) && !(pCh->channelNeeds & NEED_BYPASS)) { pCh->channelNeeds |= NEED_BYPASS; @@ -478,12 +478,12 @@ i2QueueNeeds(i2eBordStrPtr pB, i2ChanStrPtr pCh, int type) queueIndex = 0; pB->i2Bbuf_stuff = queueIndex; } - WRITE_UNLOCK_IRQRESTORE(&pB->Bbuf_spinlock,flags); + write_unlock_irqrestore(&pB->Bbuf_spinlock, flags); break; case NEED_FLOW: - WRITE_LOCK_IRQSAVE(&pB->Fbuf_spinlock,flags); + write_lock_irqsave(&pB->Fbuf_spinlock, flags); if ((type & NEED_FLOW) && !(pCh->channelNeeds & NEED_FLOW)) { pCh->channelNeeds |= NEED_FLOW; @@ -493,7 +493,7 @@ i2QueueNeeds(i2eBordStrPtr pB, i2ChanStrPtr pCh, int type) queueIndex = 0; pB->i2Fbuf_stuff = queueIndex; } - WRITE_UNLOCK_IRQRESTORE(&pB->Fbuf_spinlock,flags); + write_unlock_irqrestore(&pB->Fbuf_spinlock, flags); break; case NEED_CREDIT: @@ -562,9 +562,8 @@ i2QueueCommands(int type, i2ChanStrPtr pCh, int timeout, int nCommands, pB = pCh->pMyBord; // Board must also exist, and THE INTERRUPT COMMAND ALREADY SENT - if (pB->i2eValid != I2E_MAGIC || pB->i2eUsingIrq == IRQ_UNDEFINED) { + if (pB->i2eValid != I2E_MAGIC || pB->i2eUsingIrq == I2_IRQ_UNDEFINED) return -2; - } // If the board has gone fatal, return bad, and also hit the trap routine if // it exists. if (pB->i2eFatal) { @@ -620,13 +619,13 @@ i2QueueCommands(int type, i2ChanStrPtr pCh, int timeout, int nCommands, switch(type) { case PTYPE_INLINE: lock_var_p = &pCh->Obuf_spinlock; - WRITE_LOCK_IRQSAVE(lock_var_p,flags); + write_lock_irqsave(lock_var_p, flags); stuffIndex = pCh->Obuf_stuff; bufroom = pCh->Obuf_strip - stuffIndex; break; case PTYPE_BYPASS: lock_var_p = &pCh->Cbuf_spinlock; - WRITE_LOCK_IRQSAVE(lock_var_p,flags); + write_lock_irqsave(lock_var_p, flags); stuffIndex = pCh->Cbuf_stuff; bufroom = pCh->Cbuf_strip - stuffIndex; break; @@ -645,7 +644,7 @@ i2QueueCommands(int type, i2ChanStrPtr pCh, int timeout, int nCommands, break; /* from for()- Enough room: goto proceed */ } ip2trace(CHANN, ITRC_QUEUE, 3, 1, totalsize); - WRITE_UNLOCK_IRQRESTORE(lock_var_p, flags); + write_unlock_irqrestore(lock_var_p, flags); } else ip2trace(CHANN, ITRC_QUEUE, 3, 1, totalsize); @@ -747,7 +746,7 @@ i2QueueCommands(int type, i2ChanStrPtr pCh, int timeout, int nCommands, { case PTYPE_INLINE: pCh->Obuf_stuff = stuffIndex; // Store buffer pointer - WRITE_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags); + write_unlock_irqrestore(&pCh->Obuf_spinlock, flags); pB->debugInlineQueued++; // Add the channel pointer to list of channels needing service (first @@ -757,7 +756,7 @@ i2QueueCommands(int type, i2ChanStrPtr pCh, int timeout, int nCommands, case PTYPE_BYPASS: pCh->Cbuf_stuff = stuffIndex; // Store buffer pointer - WRITE_UNLOCK_IRQRESTORE(&pCh->Cbuf_spinlock,flags); + write_unlock_irqrestore(&pCh->Cbuf_spinlock, flags); pB->debugBypassQueued++; // Add the channel pointer to list of channels needing service (first @@ -840,7 +839,7 @@ i2Input(i2ChanStrPtr pCh) count = -1; goto i2Input_exit; } - WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags); + write_lock_irqsave(&pCh->Ibuf_spinlock, flags); // initialize some accelerators and private copies stripIndex = pCh->Ibuf_strip; @@ -850,7 +849,7 @@ i2Input(i2ChanStrPtr pCh) // If buffer is empty or requested data count was 0, (trivial case) return // without any further thought. if ( count == 0 ) { - WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags); + write_unlock_irqrestore(&pCh->Ibuf_spinlock, flags); goto i2Input_exit; } // Adjust for buffer wrap @@ -891,10 +890,10 @@ i2Input(i2ChanStrPtr pCh) if ((pCh->sinceLastFlow += count) >= pCh->whenSendFlow) { pCh->sinceLastFlow -= pCh->whenSendFlow; - WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags); + write_unlock_irqrestore(&pCh->Ibuf_spinlock, flags); i2QueueNeeds(pCh->pMyBord, pCh, NEED_FLOW); } else { - WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags); + write_unlock_irqrestore(&pCh->Ibuf_spinlock, flags); } i2Input_exit: @@ -926,7 +925,7 @@ i2InputFlush(i2ChanStrPtr pCh) ip2trace (CHANN, ITRC_INPUT, 10, 0); - WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags); + write_lock_irqsave(&pCh->Ibuf_spinlock, flags); count = pCh->Ibuf_stuff - pCh->Ibuf_strip; // Adjust for buffer wrap @@ -947,10 +946,10 @@ i2InputFlush(i2ChanStrPtr pCh) if ( (pCh->sinceLastFlow += count) >= pCh->whenSendFlow ) { pCh->sinceLastFlow -= pCh->whenSendFlow; - WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags); + write_unlock_irqrestore(&pCh->Ibuf_spinlock, flags); i2QueueNeeds(pCh->pMyBord, pCh, NEED_FLOW); } else { - WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags); + write_unlock_irqrestore(&pCh->Ibuf_spinlock, flags); } ip2trace (CHANN, ITRC_INPUT, 19, 1, count); @@ -979,9 +978,9 @@ i2InputAvailable(i2ChanStrPtr pCh) // initialize some accelerators and private copies - READ_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags); + read_lock_irqsave(&pCh->Ibuf_spinlock, flags); count = pCh->Ibuf_stuff - pCh->Ibuf_strip; - READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags); + read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags); // Adjust for buffer wrap if (count < 0) @@ -1045,9 +1044,9 @@ i2Output(i2ChanStrPtr pCh, const char *pSource, int count) while ( count > 0 ) { // How much room in output buffer is there? - READ_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags); + read_lock_irqsave(&pCh->Obuf_spinlock, flags); amountToMove = pCh->Obuf_strip - pCh->Obuf_stuff - 1; - READ_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags); + read_unlock_irqrestore(&pCh->Obuf_spinlock, flags); if (amountToMove < 0) { amountToMove += OBUF_SIZE; } @@ -1075,7 +1074,7 @@ i2Output(i2ChanStrPtr pCh, const char *pSource, int count) if ( !(pCh->flush_flags && i2RetryFlushOutput(pCh) ) && amountToMove > 0 ) { - WRITE_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags); + write_lock_irqsave(&pCh->Obuf_spinlock, flags); stuffIndex = pCh->Obuf_stuff; // Had room to move some data: don't know whether the block size, @@ -1102,7 +1101,7 @@ i2Output(i2ChanStrPtr pCh, const char *pSource, int count) } pCh->Obuf_stuff = stuffIndex; - WRITE_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags); + write_unlock_irqrestore(&pCh->Obuf_spinlock, flags); ip2trace (CHANN, ITRC_OUTPUT, 13, 1, stuffIndex ); @@ -1352,9 +1351,9 @@ i2OutputFree(i2ChanStrPtr pCh) if ( !i2Validate ( pCh ) ) { return -1; } - READ_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags); + read_lock_irqsave(&pCh->Obuf_spinlock, flags); amountToMove = pCh->Obuf_strip - pCh->Obuf_stuff - 1; - READ_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags); + read_unlock_irqrestore(&pCh->Obuf_spinlock, flags); if (amountToMove < 0) { amountToMove += OBUF_SIZE; @@ -1464,11 +1463,11 @@ i2StripFifo(i2eBordStrPtr pB) // ip2trace (ITRC_NO_PORT, ITRC_SFIFO, ITRC_ENTER, 0 ); - while (HAS_INPUT(pB)) { + while (I2_HAS_INPUT(pB)) { // ip2trace (ITRC_NO_PORT, ITRC_SFIFO, 2, 0 ); // Process packet from fifo a one atomic unit - WRITE_LOCK_IRQSAVE(&pB->read_fifo_spinlock,bflags); + write_lock_irqsave(&pB->read_fifo_spinlock, bflags); // The first word (or two bytes) will have channel number and type of // packet, possibly other information @@ -1490,7 +1489,8 @@ i2StripFifo(i2eBordStrPtr pB) // sick! if ( ((unsigned int)count) > IBUF_SIZE ) { pB->i2eFatal = 2; - WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags); + write_unlock_irqrestore(&pB->read_fifo_spinlock, + bflags); return; /* Bail out ASAP */ } // Channel is illegally big ? @@ -1498,7 +1498,8 @@ i2StripFifo(i2eBordStrPtr pB) (NULL==(pCh = ((i2ChanStrPtr*)pB->i2eChannelPtr)[channel]))) { iiReadBuf(pB, junkBuffer, count); - WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags); + write_unlock_irqrestore(&pB->read_fifo_spinlock, + bflags); break; /* From switch: ready for next packet */ } @@ -1512,14 +1513,15 @@ i2StripFifo(i2eBordStrPtr pB) if(ID_OF(pB->i2eLeadoffWord) == ID_HOT_KEY) { pCh->hotKeyIn = iiReadWord(pB) & 0xff; - WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags); + write_unlock_irqrestore(&pB->read_fifo_spinlock, + bflags); i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_HOTACK); break; /* From the switch: ready for next packet */ } // Normal data! We crudely assume there is room for the data in our // buffer because the board wouldn't have exceeded his credit limit. - WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,cflags); + write_lock_irqsave(&pCh->Ibuf_spinlock, cflags); // We have 2 locks now stuffIndex = pCh->Ibuf_stuff; amountToRead = IBUF_SIZE - stuffIndex; @@ -1562,8 +1564,9 @@ i2StripFifo(i2eBordStrPtr pB) // Update stuff index pCh->Ibuf_stuff = stuffIndex; - WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,cflags); - WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags); + write_unlock_irqrestore(&pCh->Ibuf_spinlock, cflags); + write_unlock_irqrestore(&pB->read_fifo_spinlock, + bflags); #ifdef USE_IQ schedule_work(&pCh->tqueue_input); @@ -1585,7 +1588,8 @@ i2StripFifo(i2eBordStrPtr pB) iiReadBuf(pB, cmdBuffer, count); // We can release early with buffer grab - WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags); + write_unlock_irqrestore(&pB->read_fifo_spinlock, + bflags); pc = cmdBuffer; pcLimit = &(cmdBuffer[count]); @@ -1830,12 +1834,12 @@ i2StripFifo(i2eBordStrPtr pB) default: // Neither packet? should be impossible ip2trace (ITRC_NO_PORT, ITRC_SFIFO, 5, 1, PTYPE_OF(pB->i2eLeadoffWord) ); - WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock, + write_unlock_irqrestore(&pB->read_fifo_spinlock, bflags); break; } // End of switch on type of packets - } //while(board HAS_INPUT) + } /*while(board I2_HAS_INPUT)*/ ip2trace (ITRC_NO_PORT, ITRC_SFIFO, ITRC_RETURN, 0 ); @@ -1858,7 +1862,7 @@ i2Write2Fifo(i2eBordStrPtr pB, unsigned char *source, int count,int reserve) { int rc = 0; unsigned long flags; - WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags); + write_lock_irqsave(&pB->write_fifo_spinlock, flags); if (!pB->i2eWaitingForEmptyFifo) { if (pB->i2eFifoRemains > (count+reserve)) { pB->i2eFifoRemains -= count; @@ -1867,7 +1871,7 @@ i2Write2Fifo(i2eBordStrPtr pB, unsigned char *source, int count,int reserve) rc = count; } } - WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags); + write_unlock_irqrestore(&pB->write_fifo_spinlock, flags); return rc; } //****************************************************************************** @@ -1898,7 +1902,7 @@ i2StuffFifoBypass(i2eBordStrPtr pB) while ( --bailout && notClogged && (NULL != (pCh = i2DeQueueNeeds(pB,NEED_BYPASS)))) { - WRITE_LOCK_IRQSAVE(&pCh->Cbuf_spinlock,flags); + write_lock_irqsave(&pCh->Cbuf_spinlock, flags); stripIndex = pCh->Cbuf_strip; // as long as there are packets for this channel... @@ -1906,7 +1910,7 @@ i2StuffFifoBypass(i2eBordStrPtr pB) while (stripIndex != pCh->Cbuf_stuff) { pRemove = &(pCh->Cbuf[stripIndex]); packetSize = CMD_COUNT_OF(pRemove) + sizeof(i2CmdHeader); - paddedSize = ROUNDUP(packetSize); + paddedSize = roundup(packetSize, 2); if (paddedSize > 0) { if ( 0 == i2Write2Fifo(pB, pRemove, paddedSize,0)) { @@ -1930,7 +1934,7 @@ WriteDBGBuf("BYPS", pRemove, paddedSize); // Done with this channel. Move to next, removing this one from // the queue of channels if we cleaned it out (i.e., didn't get clogged. pCh->Cbuf_strip = stripIndex; - WRITE_UNLOCK_IRQRESTORE(&pCh->Cbuf_spinlock,flags); + write_unlock_irqrestore(&pCh->Cbuf_spinlock, flags); } // Either clogged or finished all the work #ifdef IP2DEBUG_TRACE @@ -1954,7 +1958,7 @@ static inline void i2StuffFifoFlow(i2eBordStrPtr pB) { i2ChanStrPtr pCh; - unsigned short paddedSize = ROUNDUP(sizeof(flowIn)); + unsigned short paddedSize = roundup(sizeof(flowIn), 2); ip2trace (ITRC_NO_PORT, ITRC_SFLOW, ITRC_ENTER, 2, pB->i2eFifoRemains, paddedSize ); @@ -2010,7 +2014,7 @@ i2StuffFifoInline(i2eBordStrPtr pB) while ( --bailout && notClogged && (NULL != (pCh = i2DeQueueNeeds(pB,NEED_INLINE))) ) { - WRITE_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags); + write_lock_irqsave(&pCh->Obuf_spinlock, flags); stripIndex = pCh->Obuf_strip; ip2trace (CHANN, ITRC_SICMD, 3, 2, stripIndex, pCh->Obuf_stuff ); @@ -2031,7 +2035,7 @@ i2StuffFifoInline(i2eBordStrPtr pB) packetSize = flowsize + sizeof(i2CmdHeader); } flowsize = CREDIT_USAGE(flowsize); - paddedSize = ROUNDUP(packetSize); + paddedSize = roundup(packetSize, 2); ip2trace (CHANN, ITRC_SICMD, 4, 2, pB->i2eFifoRemains, paddedSize ); @@ -2086,7 +2090,7 @@ WriteDBGBuf("DATA", pRemove, paddedSize); // Done with this channel. Move to next, removing this one from the // queue of channels if we cleaned it out (i.e., didn't get clogged. pCh->Obuf_strip = stripIndex; - WRITE_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags); + write_unlock_irqrestore(&pCh->Obuf_spinlock, flags); if ( notClogged ) { @@ -2190,10 +2194,11 @@ i2ServiceBoard ( i2eBordStrPtr pB ) if (inmail & MB_OUT_STRIPPED) { pB->i2eFifoOutInts++; - WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags); + write_lock_irqsave(&pB->write_fifo_spinlock, flags); pB->i2eFifoRemains = pB->i2eFifoSize; pB->i2eWaitingForEmptyFifo = 0; - WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags); + write_unlock_irqrestore(&pB->write_fifo_spinlock, + flags); ip2trace (ITRC_NO_PORT, ITRC_INTR, 30, 1, pB->i2eFifoRemains ); diff --git a/drivers/char/ip2/i2os.h b/drivers/char/ip2/i2os.h deleted file mode 100644 index eff9b542d699..000000000000 --- a/drivers/char/ip2/i2os.h +++ /dev/null @@ -1,127 +0,0 @@ -/******************************************************************************* -* -* (c) 1999 by Computone Corporation -* -******************************************************************************** -* -* -* PACKAGE: Linux tty Device Driver for IntelliPort II family of multiport -* serial I/O controllers. -* -* DESCRIPTION: Defines, definitions and includes which are heavily dependent -* on O/S, host, compiler, etc. This file is tailored for: -* Linux v2.0.0 and later -* Gnu gcc c2.7.2 -* 80x86 architecture -* -*******************************************************************************/ - -#ifndef I2OS_H /* To prevent multiple includes */ -#define I2OS_H 1 - -//------------------------------------------------- -// Required Includes -//------------------------------------------------- - -#include "ip2types.h" -#include <asm/io.h> /* For inb, etc */ - -//------------------------------------ -// Defines for I/O instructions: -//------------------------------------ - -#define INB(port) inb(port) -#define OUTB(port,value) outb((value),(port)) -#define INW(port) inw(port) -#define OUTW(port,value) outw((value),(port)) -#define OUTSW(port,addr,count) outsw((port),(addr),(((count)+1)/2)) -#define OUTSB(port,addr,count) outsb((port),(addr),(((count)+1))&-2) -#define INSW(port,addr,count) insw((port),(addr),(((count)+1)/2)) -#define INSB(port,addr,count) insb((port),(addr),(((count)+1))&-2) - -//-------------------------------------------- -// Interrupt control -//-------------------------------------------- - -#define LOCK_INIT(a) rwlock_init(a) - -#define SAVE_AND_DISABLE_INTS(a,b) { \ - /* printk("get_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \ - spin_lock_irqsave(a,b); \ -} - -#define RESTORE_INTS(a,b) { \ - /* printk("rel_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \ - spin_unlock_irqrestore(a,b); \ -} - -#define READ_LOCK_IRQSAVE(a,b) { \ - /* printk("get_read_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \ - read_lock_irqsave(a,b); \ -} - -#define READ_UNLOCK_IRQRESTORE(a,b) { \ - /* printk("rel_read_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \ - read_unlock_irqrestore(a,b); \ -} - -#define WRITE_LOCK_IRQSAVE(a,b) { \ - /* printk("get_write_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \ - write_lock_irqsave(a,b); \ -} - -#define WRITE_UNLOCK_IRQRESTORE(a,b) { \ - /* printk("rel_write_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \ - write_unlock_irqrestore(a,b); \ -} - - -//------------------------------------------------------------------------------ -// Hardware-delay loop -// -// Probably used in only one place (see i2ellis.c) but this helps keep things -// together. Note we have unwound the IN instructions. On machines with a -// reasonable cache, the eight instructions (1 byte each) should fit in cache -// nicely, and on un-cached machines, the code-fetch would tend not to dominate. -// Note that cx is shifted so that "count" still reflects the total number of -// iterations assuming no unwinding. -//------------------------------------------------------------------------------ - -//#define DELAY1MS(port,count,label) - -//------------------------------------------------------------------------------ -// Macros to switch to a new stack, saving stack pointers, and to restore the -// old stack (Used, for example, in i2lib.c) "heap" is the address of some -// buffer which will become the new stack (working down from highest address). -// The two words at the two lowest addresses in this stack are for storing the -// SS and SP. -//------------------------------------------------------------------------------ - -//#define TO_NEW_STACK(heap,size) -//#define TO_OLD_STACK(heap) - -//------------------------------------------------------------------------------ -// Macros to save the original IRQ vectors and masks, and to patch in new ones. -//------------------------------------------------------------------------------ - -//#define SAVE_IRQ_MASKS(dest) -//#define WRITE_IRQ_MASKS(src) -//#define SAVE_IRQ_VECTOR(value,dest) -//#define WRITE_IRQ_VECTOR(value,src) - -//------------------------------------------------------------------------------ -// Macro to copy data from one far pointer to another. -//------------------------------------------------------------------------------ - -#define I2_MOVE_DATA(fpSource,fpDest,count) memmove(fpDest,fpSource,count); - -//------------------------------------------------------------------------------ -// Macros to issue eoi's to host interrupt control (IBM AT 8259-style). -//------------------------------------------------------------------------------ - -//#define MASTER_EOI -//#define SLAVE_EOI - -#endif /* I2OS_H */ - - diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index b1d6cad84282..70957acaa960 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -133,8 +133,9 @@ *****************/ #include <linux/proc_fs.h> +#include <linux/seq_file.h> -static int ip2_read_procmem(char *, char **, off_t, int); +static const struct file_operations ip2mem_proc_fops; static int ip2_read_proc(char *, char **, off_t, int, int *, void * ); /********************/ @@ -168,7 +169,7 @@ static int Fip_firmware_size; static int ip2_open(PTTY, struct file *); static void ip2_close(PTTY, struct file *); static int ip2_write(PTTY, const unsigned char *, int); -static void ip2_putchar(PTTY, unsigned char); +static int ip2_putchar(PTTY, unsigned char); static void ip2_flush_chars(PTTY); static int ip2_write_room(PTTY); static int ip2_chars_in_buf(PTTY); @@ -354,14 +355,15 @@ have_requested_irq( char irq ) /* the driver initialisation function and returns what it returns. */ /******************************************************************************/ #ifdef MODULE -int -init_module(void) +static int __init +ip2_init_module(void) { #ifdef IP2DEBUG_INIT printk (KERN_DEBUG "Loading module ...\n" ); #endif return 0; } +module_init(ip2_init_module); #endif /* MODULE */ /******************************************************************************/ @@ -380,8 +382,8 @@ init_module(void) /* driver should be returned since it may be unloaded from memory. */ /******************************************************************************/ #ifdef MODULE -void -cleanup_module(void) +void __exit +ip2_cleanup_module(void) { int err; int i; @@ -423,7 +425,7 @@ cleanup_module(void) } put_tty_driver(ip2_tty_driver); unregister_chrdev(IP2_IPL_MAJOR, pcIpl); - remove_proc_entry("ip2mem", &proc_root); + remove_proc_entry("ip2mem", NULL); // free memory for (i = 0; i < IP2_MAX_BOARDS; i++) { @@ -451,6 +453,7 @@ cleanup_module(void) printk (KERN_DEBUG "IP2 Unloaded\n" ); #endif } +module_exit(ip2_cleanup_module); #endif /* MODULE */ static const struct tty_operations ip2_ops = { @@ -695,7 +698,7 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) } } /* Register the read_procmem thing */ - if (!create_proc_info_entry("ip2mem",0,&proc_root,ip2_read_procmem)) { + if (!proc_create("ip2mem",0,NULL,&ip2mem_proc_fops)) { printk(KERN_ERR "IP2: failed to register read_procmem\n"); } else { @@ -1049,9 +1052,9 @@ set_irq( int boardnum, int boardIrq ) * Write to FIFO; don't bother to adjust fifo capacity for this, since * board will respond almost immediately after SendMail hit. */ - WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags); + write_lock_irqsave(&pB->write_fifo_spinlock, flags); iiWriteBuf(pB, tempCommand, 4); - WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags); + write_unlock_irqrestore(&pB->write_fifo_spinlock, flags); pB->i2eUsingIrq = boardIrq; pB->i2eOutMailWaiting |= MB_OUT_STUFFED; @@ -1069,9 +1072,9 @@ set_irq( int boardnum, int boardIrq ) (CMD_OF(tempCommand))[4] = 64; // chars (CMD_OF(tempCommand))[5] = 87; // HW_TEST - WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags); + write_lock_irqsave(&pB->write_fifo_spinlock, flags); iiWriteBuf(pB, tempCommand, 8); - WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags); + write_unlock_irqrestore(&pB->write_fifo_spinlock, flags); CHANNEL_OF(tempCommand) = 0; PTYPE_OF(tempCommand) = PTYPE_BYPASS; @@ -1086,9 +1089,9 @@ set_irq( int boardnum, int boardIrq ) CMD_COUNT_OF(tempCommand) = 2; (CMD_OF(tempCommand))[0] = 44; /* get ping */ (CMD_OF(tempCommand))[1] = 200; /* 200 ms */ - WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags); + write_lock_irqsave(&pB->write_fifo_spinlock, flags); iiWriteBuf(pB, tempCommand, 4); - WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags); + write_unlock_irqrestore(&pB->write_fifo_spinlock, flags); #endif iiEnableMailIrq(pB); @@ -1267,12 +1270,12 @@ static void do_input(struct work_struct *work) // Data input if ( pCh->pTTY != NULL ) { - READ_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags) + read_lock_irqsave(&pCh->Ibuf_spinlock, flags); if (!pCh->throttled && (pCh->Ibuf_stuff != pCh->Ibuf_strip)) { - READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags) + read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags); i2Input( pCh ); } else - READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags) + read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags); } else { ip2trace(CHANN, ITRC_INPUT, 22, 0 ); @@ -1613,10 +1616,8 @@ ip2_close( PTTY tty, struct file *pFile ) serviceOutgoingFifo ( pCh->pMyBord ); - if ( tty->driver->flush_buffer ) - tty->driver->flush_buffer(tty); - if ( tty->ldisc.flush_buffer ) - tty->ldisc.flush_buffer(tty); + tty_ldisc_flush(tty); + tty_driver_flush_buffer(tty); tty->closing = 0; pCh->pTTY = NULL; @@ -1716,9 +1717,9 @@ ip2_write( PTTY tty, const unsigned char *pData, int count) ip2_flush_chars( tty ); /* This is the actual move bit. Make sure it does what we need!!!!! */ - WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags); + write_lock_irqsave(&pCh->Pbuf_spinlock, flags); bytesSent = i2Output( pCh, pData, count); - WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags); + write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags); ip2trace (CHANN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent ); @@ -1735,7 +1736,7 @@ ip2_write( PTTY tty, const unsigned char *pData, int count) /* */ /* */ /******************************************************************************/ -static void +static int ip2_putchar( PTTY tty, unsigned char ch ) { i2ChanStrPtr pCh = tty->driver_data; @@ -1743,13 +1744,14 @@ ip2_putchar( PTTY tty, unsigned char ch ) // ip2trace (CHANN, ITRC_PUTC, ITRC_ENTER, 1, ch ); - WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags); + write_lock_irqsave(&pCh->Pbuf_spinlock, flags); pCh->Pbuf[pCh->Pbuf_stuff++] = ch; if ( pCh->Pbuf_stuff == sizeof pCh->Pbuf ) { - WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags); + write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags); ip2_flush_chars( tty ); } else - WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags); + write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags); + return 1; // ip2trace (CHANN, ITRC_PUTC, ITRC_RETURN, 1, ch ); } @@ -1769,7 +1771,7 @@ ip2_flush_chars( PTTY tty ) i2ChanStrPtr pCh = tty->driver_data; unsigned long flags; - WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags); + write_lock_irqsave(&pCh->Pbuf_spinlock, flags); if ( pCh->Pbuf_stuff ) { // ip2trace (CHANN, ITRC_PUTC, 10, 1, strip ); @@ -1783,7 +1785,7 @@ ip2_flush_chars( PTTY tty ) } pCh->Pbuf_stuff -= strip; } - WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags); + write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags); } /******************************************************************************/ @@ -1801,9 +1803,9 @@ ip2_write_room ( PTTY tty ) i2ChanStrPtr pCh = tty->driver_data; unsigned long flags; - READ_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags); + read_lock_irqsave(&pCh->Pbuf_spinlock, flags); bytesFree = i2OutputFree( pCh ) - pCh->Pbuf_stuff; - READ_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags); + read_unlock_irqrestore(&pCh->Pbuf_spinlock, flags); ip2trace (CHANN, ITRC_WRITE, 11, 1, bytesFree ); @@ -1833,12 +1835,12 @@ ip2_chars_in_buf ( PTTY tty ) pCh->Obuf_char_count + pCh->Pbuf_stuff, pCh->Obuf_char_count, pCh->Pbuf_stuff ); #endif - READ_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags); + read_lock_irqsave(&pCh->Obuf_spinlock, flags); rc = pCh->Obuf_char_count; - READ_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags); - READ_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags); + read_unlock_irqrestore(&pCh->Obuf_spinlock, flags); + read_lock_irqsave(&pCh->Pbuf_spinlock, flags); rc += pCh->Pbuf_stuff; - READ_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags); + read_unlock_irqrestore(&pCh->Pbuf_spinlock, flags); return rc; } @@ -1862,9 +1864,9 @@ ip2_flush_buffer( PTTY tty ) #ifdef IP2DEBUG_WRITE printk (KERN_DEBUG "IP2: flush buffer\n" ); #endif - WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags); + write_lock_irqsave(&pCh->Pbuf_spinlock, flags); pCh->Pbuf_stuff = 0; - WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags); + write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags); i2FlushOutput( pCh ); ip2_owake(tty); @@ -1950,15 +1952,15 @@ ip2_unthrottle ( PTTY tty ) pCh->throttled = 0; i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME); serviceOutgoingFifo( pCh->pMyBord ); - READ_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags) + read_lock_irqsave(&pCh->Ibuf_spinlock, flags); if ( pCh->Ibuf_stuff != pCh->Ibuf_strip ) { - READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags) + read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags); #ifdef IP2DEBUG_READ printk (KERN_DEBUG "i2Input called from unthrottle\n" ); #endif i2Input( pCh ); } else - READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags) + read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags); } static void @@ -2201,9 +2203,9 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg ) * for masking). Caller should use TIOCGICOUNT to see which one it was */ case TIOCMIWAIT: - WRITE_LOCK_IRQSAVE(&pB->read_fifo_spinlock, flags); + write_lock_irqsave(&pB->read_fifo_spinlock, flags); cprev = pCh->icount; /* note the counters on entry */ - WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock, flags); + write_unlock_irqrestore(&pB->read_fifo_spinlock, flags); i2QueueCommands(PTYPE_BYPASS, pCh, 100, 4, CMD_DCD_REP, CMD_CTS_REP, CMD_DSR_REP, CMD_RI_REP); init_waitqueue_entry(&wait, current); @@ -2223,9 +2225,9 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg ) rc = -ERESTARTSYS; break; } - WRITE_LOCK_IRQSAVE(&pB->read_fifo_spinlock, flags); + write_lock_irqsave(&pB->read_fifo_spinlock, flags); cnow = pCh->icount; /* atomic copy */ - WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock, flags); + write_unlock_irqrestore(&pB->read_fifo_spinlock, flags); if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) { rc = -EIO; /* no change => rc */ @@ -2263,9 +2265,9 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg ) case TIOCGICOUNT: ip2trace (CHANN, ITRC_IOCTL, 11, 1, rc ); - WRITE_LOCK_IRQSAVE(&pB->read_fifo_spinlock, flags); + write_lock_irqsave(&pB->read_fifo_spinlock, flags); cnow = pCh->icount; - WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock, flags); + write_unlock_irqrestore(&pB->read_fifo_spinlock, flags); p_cuser = argp; rc = put_user(cnow.cts, &p_cuser->cts); rc = put_user(cnow.dsr, &p_cuser->dsr); @@ -2871,7 +2873,7 @@ ip2_ipl_ioctl ( struct inode *pInode, struct file *pFile, UINT cmd, ULONG arg ) case 65: /* Board - ip2stat */ if ( pB ) { rc = copy_to_user(argp, pB, sizeof(i2eBordStr)); - rc = put_user(INB(pB->i2eStatus), + rc = put_user(inb(pB->i2eStatus), (ULONG __user *)(arg + (ULONG)(&pB->i2eStatus) - (ULONG)pB ) ); } else { rc = -ENODEV; @@ -2967,65 +2969,61 @@ ip2_ipl_open( struct inode *pInode, struct file *pFile ) } return 0; } -/******************************************************************************/ -/* Function: ip2_read_procmem */ -/* Parameters: */ -/* */ -/* Returns: Length of output */ -/* */ -/* Description: */ -/* Supplies some driver operating parameters */ -/* Not real useful unless your debugging the fifo */ -/* */ -/******************************************************************************/ - -#define LIMIT (PAGE_SIZE - 120) static int -ip2_read_procmem(char *buf, char **start, off_t offset, int len) +proc_ip2mem_show(struct seq_file *m, void *v) { i2eBordStrPtr pB; i2ChanStrPtr pCh; PTTY tty; int i; - len = 0; - #define FMTLINE "%3d: 0x%08x 0x%08x 0%011o 0%011o\n" #define FMTLIN2 " 0x%04x 0x%04x tx flow 0x%x\n" #define FMTLIN3 " 0x%04x 0x%04x rc flow\n" - len += sprintf(buf+len,"\n"); + seq_printf(m,"\n"); for( i = 0; i < IP2_MAX_BOARDS; ++i ) { pB = i2BoardPtrTable[i]; if ( pB ) { - len += sprintf(buf+len,"board %d:\n",i); - len += sprintf(buf+len,"\tFifo rem: %d mty: %x outM %x\n", + seq_printf(m,"board %d:\n",i); + seq_printf(m,"\tFifo rem: %d mty: %x outM %x\n", pB->i2eFifoRemains,pB->i2eWaitingForEmptyFifo,pB->i2eOutMailWaiting); } } - len += sprintf(buf+len,"#: tty flags, port flags, cflags, iflags\n"); + seq_printf(m,"#: tty flags, port flags, cflags, iflags\n"); for (i=0; i < IP2_MAX_PORTS; i++) { - if (len > LIMIT) - break; pCh = DevTable[i]; if (pCh) { tty = pCh->pTTY; if (tty && tty->count) { - len += sprintf(buf+len,FMTLINE,i,(int)tty->flags,pCh->flags, + seq_printf(m,FMTLINE,i,(int)tty->flags,pCh->flags, tty->termios->c_cflag,tty->termios->c_iflag); - len += sprintf(buf+len,FMTLIN2, + seq_printf(m,FMTLIN2, pCh->outfl.asof,pCh->outfl.room,pCh->channelNeeds); - len += sprintf(buf+len,FMTLIN3,pCh->infl.asof,pCh->infl.room); + seq_printf(m,FMTLIN3,pCh->infl.asof,pCh->infl.room); } } } - return len; + return 0; +} + +static int proc_ip2mem_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_ip2mem_show, NULL); } +static const struct file_operations ip2mem_proc_fops = { + .owner = THIS_MODULE, + .open = proc_ip2mem_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + /* * This is the handler for /proc/tty/driver/ip2 * diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile index 553f0a408eda..eb8a1a8c188e 100644 --- a/drivers/char/ipmi/Makefile +++ b/drivers/char/ipmi/Makefile @@ -9,7 +9,3 @@ obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o obj-$(CONFIG_IPMI_SI) += ipmi_si.o obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o obj-$(CONFIG_IPMI_POWEROFF) += ipmi_poweroff.o - -ipmi_si.o: $(ipmi_si-objs) - $(LD) -r -o $@ $(ipmi_si-objs) - diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c index e736119b6497..7b98c067190a 100644 --- a/drivers/char/ipmi/ipmi_bt_sm.c +++ b/drivers/char/ipmi/ipmi_bt_sm.c @@ -37,26 +37,32 @@ #define BT_DEBUG_ENABLE 1 /* Generic messages */ #define BT_DEBUG_MSG 2 /* Prints all request/response buffers */ #define BT_DEBUG_STATES 4 /* Verbose look at state changes */ -/* BT_DEBUG_OFF must be zero to correspond to the default uninitialized - value */ +/* + * BT_DEBUG_OFF must be zero to correspond to the default uninitialized + * value + */ static int bt_debug; /* 0 == BT_DEBUG_OFF */ module_param(bt_debug, int, 0644); MODULE_PARM_DESC(bt_debug, "debug bitmask, 1=enable, 2=messages, 4=states"); -/* Typical "Get BT Capabilities" values are 2-3 retries, 5-10 seconds, - and 64 byte buffers. However, one HP implementation wants 255 bytes of - buffer (with a documented message of 160 bytes) so go for the max. - Since the Open IPMI architecture is single-message oriented at this - stage, the queue depth of BT is of no concern. */ +/* + * Typical "Get BT Capabilities" values are 2-3 retries, 5-10 seconds, + * and 64 byte buffers. However, one HP implementation wants 255 bytes of + * buffer (with a documented message of 160 bytes) so go for the max. + * Since the Open IPMI architecture is single-message oriented at this + * stage, the queue depth of BT is of no concern. + */ #define BT_NORMAL_TIMEOUT 5 /* seconds */ #define BT_NORMAL_RETRY_LIMIT 2 #define BT_RESET_DELAY 6 /* seconds after warm reset */ -/* States are written in chronological order and usually cover - multiple rows of the state table discussion in the IPMI spec. */ +/* + * States are written in chronological order and usually cover + * multiple rows of the state table discussion in the IPMI spec. + */ enum bt_states { BT_STATE_IDLE = 0, /* Order is critical in this list */ @@ -76,10 +82,12 @@ enum bt_states { BT_STATE_LONG_BUSY /* BT doesn't get hosed :-) */ }; -/* Macros seen at the end of state "case" blocks. They help with legibility - and debugging. */ +/* + * Macros seen at the end of state "case" blocks. They help with legibility + * and debugging. + */ -#define BT_STATE_CHANGE(X,Y) { bt->state = X; return Y; } +#define BT_STATE_CHANGE(X, Y) { bt->state = X; return Y; } #define BT_SI_SM_RETURN(Y) { last_printed = BT_STATE_PRINTME; return Y; } @@ -110,11 +118,13 @@ struct si_sm_data { #define BT_H_BUSY 0x40 #define BT_B_BUSY 0x80 -/* Some bits are toggled on each write: write once to set it, once - more to clear it; writing a zero does nothing. To absolutely - clear it, check its state and write if set. This avoids the "get - current then use as mask" scheme to modify one bit. Note that the - variable "bt" is hardcoded into these macros. */ +/* + * Some bits are toggled on each write: write once to set it, once + * more to clear it; writing a zero does nothing. To absolutely + * clear it, check its state and write if set. This avoids the "get + * current then use as mask" scheme to modify one bit. Note that the + * variable "bt" is hardcoded into these macros. + */ #define BT_STATUS bt->io->inputb(bt->io, 0) #define BT_CONTROL(x) bt->io->outputb(bt->io, 0, x) @@ -125,8 +135,10 @@ struct si_sm_data { #define BT_INTMASK_R bt->io->inputb(bt->io, 2) #define BT_INTMASK_W(x) bt->io->outputb(bt->io, 2, x) -/* Convenience routines for debugging. These are not multi-open safe! - Note the macros have hardcoded variables in them. */ +/* + * Convenience routines for debugging. These are not multi-open safe! + * Note the macros have hardcoded variables in them. + */ static char *state2txt(unsigned char state) { @@ -182,7 +194,8 @@ static char *status2txt(unsigned char status) static unsigned int bt_init_data(struct si_sm_data *bt, struct si_sm_io *io) { memset(bt, 0, sizeof(struct si_sm_data)); - if (bt->io != io) { /* external: one-time only things */ + if (bt->io != io) { + /* external: one-time only things */ bt->io = io; bt->seq = 0; } @@ -229,7 +242,7 @@ static int bt_start_transaction(struct si_sm_data *bt, printk(KERN_WARNING "BT: +++++++++++++++++ New command\n"); printk(KERN_WARNING "BT: NetFn/LUN CMD [%d data]:", size - 2); for (i = 0; i < size; i ++) - printk (" %02x", data[i]); + printk(" %02x", data[i]); printk("\n"); } bt->write_data[0] = size + 1; /* all data plus seq byte */ @@ -246,8 +259,10 @@ static int bt_start_transaction(struct si_sm_data *bt, return 0; } -/* After the upper state machine has been told SI_SM_TRANSACTION_COMPLETE - it calls this. Strip out the length and seq bytes. */ +/* + * After the upper state machine has been told SI_SM_TRANSACTION_COMPLETE + * it calls this. Strip out the length and seq bytes. + */ static int bt_get_result(struct si_sm_data *bt, unsigned char *data, @@ -269,10 +284,10 @@ static int bt_get_result(struct si_sm_data *bt, memcpy(data + 2, bt->read_data + 4, msg_len - 2); if (bt_debug & BT_DEBUG_MSG) { - printk (KERN_WARNING "BT: result %d bytes:", msg_len); + printk(KERN_WARNING "BT: result %d bytes:", msg_len); for (i = 0; i < msg_len; i++) printk(" %02x", data[i]); - printk ("\n"); + printk("\n"); } return msg_len; } @@ -292,8 +307,10 @@ static void reset_flags(struct si_sm_data *bt) BT_INTMASK_W(BT_BMC_HWRST); } -/* Get rid of an unwanted/stale response. This should only be needed for - BMCs that support multiple outstanding requests. */ +/* + * Get rid of an unwanted/stale response. This should only be needed for + * BMCs that support multiple outstanding requests. + */ static void drain_BMC2HOST(struct si_sm_data *bt) { @@ -326,8 +343,8 @@ static inline void write_all_bytes(struct si_sm_data *bt) printk(KERN_WARNING "BT: write %d bytes seq=0x%02X", bt->write_count, bt->seq); for (i = 0; i < bt->write_count; i++) - printk (" %02x", bt->write_data[i]); - printk ("\n"); + printk(" %02x", bt->write_data[i]); + printk("\n"); } for (i = 0; i < bt->write_count; i++) HOST2BMC(bt->write_data[i]); @@ -337,8 +354,10 @@ static inline int read_all_bytes(struct si_sm_data *bt) { unsigned char i; - /* length is "framing info", minimum = 4: NetFn, Seq, Cmd, cCode. - Keep layout of first four bytes aligned with write_data[] */ + /* + * length is "framing info", minimum = 4: NetFn, Seq, Cmd, cCode. + * Keep layout of first four bytes aligned with write_data[] + */ bt->read_data[0] = BMC2HOST; bt->read_count = bt->read_data[0]; @@ -362,8 +381,8 @@ static inline int read_all_bytes(struct si_sm_data *bt) if (max > 16) max = 16; for (i = 0; i < max; i++) - printk (" %02x", bt->read_data[i]); - printk ("%s\n", bt->read_count == max ? "" : " ..."); + printk(KERN_CONT " %02x", bt->read_data[i]); + printk(KERN_CONT "%s\n", bt->read_count == max ? "" : " ..."); } /* per the spec, the (NetFn[1], Seq[2], Cmd[3]) tuples must match */ @@ -402,8 +421,10 @@ static enum si_sm_result error_recovery(struct si_sm_data *bt, printk(KERN_WARNING "IPMI BT: %s in %s %s ", /* open-ended line */ reason, STATE2TXT, STATUS2TXT); - /* Per the IPMI spec, retries are based on the sequence number - known only to this module, so manage a restart here. */ + /* + * Per the IPMI spec, retries are based on the sequence number + * known only to this module, so manage a restart here. + */ (bt->error_retries)++; if (bt->error_retries < bt->BT_CAP_retries) { printk("%d retries left\n", @@ -412,8 +433,8 @@ static enum si_sm_result error_recovery(struct si_sm_data *bt, return SI_SM_CALL_WITHOUT_DELAY; } - printk("failed %d retries, sending error response\n", - bt->BT_CAP_retries); + printk(KERN_WARNING "failed %d retries, sending error response\n", + bt->BT_CAP_retries); if (!bt->nonzero_status) printk(KERN_ERR "IPMI BT: stuck, try power cycle\n"); @@ -424,8 +445,10 @@ static enum si_sm_result error_recovery(struct si_sm_data *bt, return SI_SM_CALL_WITHOUT_DELAY; } - /* Concoct a useful error message, set up the next state, and - be done with this sequence. */ + /* + * Concoct a useful error message, set up the next state, and + * be done with this sequence. + */ bt->state = BT_STATE_IDLE; switch (cCode) { @@ -461,10 +484,12 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) last_printed = bt->state; } - /* Commands that time out may still (eventually) provide a response. - This stale response will get in the way of a new response so remove - it if possible (hopefully during IDLE). Even if it comes up later - it will be rejected by its (now-forgotten) seq number. */ + /* + * Commands that time out may still (eventually) provide a response. + * This stale response will get in the way of a new response so remove + * it if possible (hopefully during IDLE). Even if it comes up later + * it will be rejected by its (now-forgotten) seq number. + */ if ((bt->state < BT_STATE_WRITE_BYTES) && (status & BT_B2H_ATN)) { drain_BMC2HOST(bt); @@ -472,7 +497,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) } if ((bt->state != BT_STATE_IDLE) && - (bt->state < BT_STATE_PRINTME)) { /* check timeout */ + (bt->state < BT_STATE_PRINTME)) { + /* check timeout */ bt->timeout -= time; if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1)) return error_recovery(bt, @@ -482,8 +508,10 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) switch (bt->state) { - /* Idle state first checks for asynchronous messages from another - channel, then does some opportunistic housekeeping. */ + /* + * Idle state first checks for asynchronous messages from another + * channel, then does some opportunistic housekeeping. + */ case BT_STATE_IDLE: if (status & BT_SMS_ATN) { @@ -531,16 +559,19 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); BT_CONTROL(BT_H_BUSY); /* set */ - /* Uncached, ordered writes should just proceeed serially but - some BMCs don't clear B2H_ATN with one hit. Fast-path a - workaround without too much penalty to the general case. */ + /* + * Uncached, ordered writes should just proceeed serially but + * some BMCs don't clear B2H_ATN with one hit. Fast-path a + * workaround without too much penalty to the general case. + */ BT_CONTROL(BT_B2H_ATN); /* clear it to ACK the BMC */ BT_STATE_CHANGE(BT_STATE_CLEAR_B2H, SI_SM_CALL_WITHOUT_DELAY); case BT_STATE_CLEAR_B2H: - if (status & BT_B2H_ATN) { /* keep hitting it */ + if (status & BT_B2H_ATN) { + /* keep hitting it */ BT_CONTROL(BT_B2H_ATN); BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY); } @@ -548,7 +579,8 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) SI_SM_CALL_WITHOUT_DELAY); case BT_STATE_READ_BYTES: - if (!(status & BT_H_BUSY)) /* check in case of retry */ + if (!(status & BT_H_BUSY)) + /* check in case of retry */ BT_CONTROL(BT_H_BUSY); BT_CONTROL(BT_CLR_RD_PTR); /* start of BMC2HOST buffer */ i = read_all_bytes(bt); /* true == packet seq match */ @@ -599,8 +631,10 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) BT_STATE_CHANGE(BT_STATE_XACTION_START, SI_SM_CALL_WITH_DELAY); - /* Get BT Capabilities, using timing of upper level state machine. - Set outreqs to prevent infinite loop on timeout. */ + /* + * Get BT Capabilities, using timing of upper level state machine. + * Set outreqs to prevent infinite loop on timeout. + */ case BT_STATE_CAPABILITIES_BEGIN: bt->BT_CAP_outreqs = 1; { @@ -638,10 +672,12 @@ static enum si_sm_result bt_event(struct si_sm_data *bt, long time) static int bt_detect(struct si_sm_data *bt) { - /* It's impossible for the BT status and interrupt registers to be - all 1's, (assuming a properly functioning, self-initialized BMC) - but that's what you get from reading a bogus address, so we - test that first. The calling routine uses negative logic. */ + /* + * It's impossible for the BT status and interrupt registers to be + * all 1's, (assuming a properly functioning, self-initialized BMC) + * but that's what you get from reading a bogus address, so we + * test that first. The calling routine uses negative logic. + */ if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF)) return 1; @@ -658,8 +694,7 @@ static int bt_size(void) return sizeof(struct si_sm_data); } -struct si_sm_handlers bt_smi_handlers = -{ +struct si_sm_handlers bt_smi_handlers = { .init_data = bt_init_data, .start_transaction = bt_start_transaction, .get_result = bt_get_result, diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c index c1b8228cb7b6..80704875794c 100644 --- a/drivers/char/ipmi/ipmi_kcs_sm.c +++ b/drivers/char/ipmi/ipmi_kcs_sm.c @@ -60,37 +60,58 @@ MODULE_PARM_DESC(kcs_debug, "debug bitmask, 1=enable, 2=messages, 4=states"); /* The states the KCS driver may be in. */ enum kcs_states { - KCS_IDLE, /* The KCS interface is currently - doing nothing. */ - KCS_START_OP, /* We are starting an operation. The - data is in the output buffer, but - nothing has been done to the - interface yet. This was added to - the state machine in the spec to - wait for the initial IBF. */ - KCS_WAIT_WRITE_START, /* We have written a write cmd to the - interface. */ - KCS_WAIT_WRITE, /* We are writing bytes to the - interface. */ - KCS_WAIT_WRITE_END, /* We have written the write end cmd - to the interface, and still need to - write the last byte. */ - KCS_WAIT_READ, /* We are waiting to read data from - the interface. */ - KCS_ERROR0, /* State to transition to the error - handler, this was added to the - state machine in the spec to be - sure IBF was there. */ - KCS_ERROR1, /* First stage error handler, wait for - the interface to respond. */ - KCS_ERROR2, /* The abort cmd has been written, - wait for the interface to - respond. */ - KCS_ERROR3, /* We wrote some data to the - interface, wait for it to switch to - read mode. */ - KCS_HOSED /* The hardware failed to follow the - state machine. */ + /* The KCS interface is currently doing nothing. */ + KCS_IDLE, + + /* + * We are starting an operation. The data is in the output + * buffer, but nothing has been done to the interface yet. This + * was added to the state machine in the spec to wait for the + * initial IBF. + */ + KCS_START_OP, + + /* We have written a write cmd to the interface. */ + KCS_WAIT_WRITE_START, + + /* We are writing bytes to the interface. */ + KCS_WAIT_WRITE, + + /* + * We have written the write end cmd to the interface, and + * still need to write the last byte. + */ + KCS_WAIT_WRITE_END, + + /* We are waiting to read data from the interface. */ + KCS_WAIT_READ, + + /* + * State to transition to the error handler, this was added to + * the state machine in the spec to be sure IBF was there. + */ + KCS_ERROR0, + + /* + * First stage error handler, wait for the interface to + * respond. + */ + KCS_ERROR1, + + /* + * The abort cmd has been written, wait for the interface to + * respond. + */ + KCS_ERROR2, + + /* + * We wrote some data to the interface, wait for it to switch + * to read mode. + */ + KCS_ERROR3, + + /* The hardware failed to follow the state machine. */ + KCS_HOSED }; #define MAX_KCS_READ_SIZE IPMI_MAX_MSG_LENGTH @@ -102,8 +123,7 @@ enum kcs_states { #define MAX_ERROR_RETRIES 10 #define ERROR0_OBF_WAIT_JIFFIES (2*HZ) -struct si_sm_data -{ +struct si_sm_data { enum kcs_states state; struct si_sm_io *io; unsigned char write_data[MAX_KCS_WRITE_SIZE]; @@ -187,7 +207,8 @@ static inline void start_error_recovery(struct si_sm_data *kcs, char *reason) (kcs->error_retries)++; if (kcs->error_retries > MAX_ERROR_RETRIES) { if (kcs_debug & KCS_DEBUG_ENABLE) - printk(KERN_DEBUG "ipmi_kcs_sm: kcs hosed: %s\n", reason); + printk(KERN_DEBUG "ipmi_kcs_sm: kcs hosed: %s\n", + reason); kcs->state = KCS_HOSED; } else { kcs->error0_timeout = jiffies + ERROR0_OBF_WAIT_JIFFIES; @@ -271,10 +292,9 @@ static int start_kcs_transaction(struct si_sm_data *kcs, unsigned char *data, if (kcs_debug & KCS_DEBUG_MSG) { printk(KERN_DEBUG "start_kcs_transaction -"); - for (i = 0; i < size; i ++) { + for (i = 0; i < size; i++) printk(" %02x", (unsigned char) (data [i])); - } - printk ("\n"); + printk("\n"); } kcs->error_retries = 0; memcpy(kcs->write_data, data, size); @@ -305,9 +325,11 @@ static int get_kcs_result(struct si_sm_data *kcs, unsigned char *data, kcs->read_pos = 3; } if (kcs->truncated) { - /* Report a truncated error. We might overwrite - another error, but that's too bad, the user needs - to know it was truncated. */ + /* + * Report a truncated error. We might overwrite + * another error, but that's too bad, the user needs + * to know it was truncated. + */ data[2] = IPMI_ERR_MSG_TRUNCATED; kcs->truncated = 0; } @@ -315,9 +337,11 @@ static int get_kcs_result(struct si_sm_data *kcs, unsigned char *data, return kcs->read_pos; } -/* This implements the state machine defined in the IPMI manual, see - that for details on how this works. Divide that flowchart into - sections delimited by "Wait for IBF" and this will become clear. */ +/* + * This implements the state machine defined in the IPMI manual, see + * that for details on how this works. Divide that flowchart into + * sections delimited by "Wait for IBF" and this will become clear. + */ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) { unsigned char status; @@ -388,11 +412,12 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) write_next_byte(kcs); } break; - + case KCS_WAIT_WRITE_END: if (state != KCS_WRITE_STATE) { start_error_recovery(kcs, - "Not in write state for write end"); + "Not in write state" + " for write end"); break; } clear_obf(kcs, status); @@ -413,13 +438,15 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) return SI_SM_CALL_WITH_DELAY; read_next_byte(kcs); } else { - /* We don't implement this exactly like the state - machine in the spec. Some broken hardware - does not write the final dummy byte to the - read register. Thus obf will never go high - here. We just go straight to idle, and we - handle clearing out obf in idle state if it - happens to come in. */ + /* + * We don't implement this exactly like the state + * machine in the spec. Some broken hardware + * does not write the final dummy byte to the + * read register. Thus obf will never go high + * here. We just go straight to idle, and we + * handle clearing out obf in idle state if it + * happens to come in. + */ clear_obf(kcs, status); kcs->orig_write_count = 0; kcs->state = KCS_IDLE; @@ -430,7 +457,8 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) case KCS_ERROR0: clear_obf(kcs, status); status = read_status(kcs); - if (GET_STATUS_OBF(status)) /* controller isn't responding */ + if (GET_STATUS_OBF(status)) + /* controller isn't responding */ if (time_before(jiffies, kcs->error0_timeout)) return SI_SM_CALL_WITH_TICK_DELAY; write_cmd(kcs, KCS_GET_STATUS_ABORT); @@ -442,7 +470,7 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) write_data(kcs, 0); kcs->state = KCS_ERROR2; break; - + case KCS_ERROR2: if (state != KCS_READ_STATE) { start_error_recovery(kcs, @@ -456,7 +484,7 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) write_data(kcs, KCS_READ_BYTE); kcs->state = KCS_ERROR3; break; - + case KCS_ERROR3: if (state != KCS_IDLE_STATE) { start_error_recovery(kcs, @@ -475,7 +503,7 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) return SI_SM_TRANSACTION_COMPLETE; } break; - + case KCS_HOSED: break; } @@ -495,10 +523,12 @@ static int kcs_size(void) static int kcs_detect(struct si_sm_data *kcs) { - /* It's impossible for the KCS status register to be all 1's, - (assuming a properly functioning, self-initialized BMC) - but that's what you get from reading a bogus address, so we - test that first. */ + /* + * It's impossible for the KCS status register to be all 1's, + * (assuming a properly functioning, self-initialized BMC) + * but that's what you get from reading a bogus address, so we + * test that first. + */ if (read_status(kcs) == 0xff) return 1; @@ -509,8 +539,7 @@ static void kcs_cleanup(struct si_sm_data *kcs) { } -struct si_sm_handlers kcs_smi_handlers = -{ +struct si_sm_handlers kcs_smi_handlers = { .init_data = init_kcs_data, .start_transaction = start_kcs_transaction, .get_result = get_kcs_result, diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 32b2b22996dc..8a59aaa21be5 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -47,7 +47,7 @@ #define PFX "IPMI message handler: " -#define IPMI_DRIVER_VERSION "39.1" +#define IPMI_DRIVER_VERSION "39.2" static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void); static int ipmi_init_msghandler(void); @@ -63,16 +63,16 @@ static struct proc_dir_entry *proc_ipmi_root; #define MAX_EVENTS_IN_QUEUE 25 -/* Don't let a message sit in a queue forever, always time it with at lest - the max message timer. This is in milliseconds. */ +/* + * Don't let a message sit in a queue forever, always time it with at lest + * the max message timer. This is in milliseconds. + */ #define MAX_MSG_TIMEOUT 60000 - /* * The main "user" data structure. */ -struct ipmi_user -{ +struct ipmi_user { struct list_head link; /* Set to "0" when the user is destroyed. */ @@ -91,8 +91,7 @@ struct ipmi_user int gets_events; }; -struct cmd_rcvr -{ +struct cmd_rcvr { struct list_head link; ipmi_user_t user; @@ -106,12 +105,12 @@ struct cmd_rcvr * or change any data until the RCU period completes. So we * use this next variable during mass deletion so we can have * a list and don't have to wait and restart the search on - * every individual deletion of a command. */ + * every individual deletion of a command. + */ struct cmd_rcvr *next; }; -struct seq_table -{ +struct seq_table { unsigned int inuse : 1; unsigned int broadcast : 1; @@ -119,53 +118,60 @@ struct seq_table unsigned long orig_timeout; unsigned int retries_left; - /* To verify on an incoming send message response that this is - the message that the response is for, we keep a sequence id - and increment it every time we send a message. */ + /* + * To verify on an incoming send message response that this is + * the message that the response is for, we keep a sequence id + * and increment it every time we send a message. + */ long seqid; - /* This is held so we can properly respond to the message on a - timeout, and it is used to hold the temporary data for - retransmission, too. */ + /* + * This is held so we can properly respond to the message on a + * timeout, and it is used to hold the temporary data for + * retransmission, too. + */ struct ipmi_recv_msg *recv_msg; }; -/* Store the information in a msgid (long) to allow us to find a - sequence table entry from the msgid. */ +/* + * Store the information in a msgid (long) to allow us to find a + * sequence table entry from the msgid. + */ #define STORE_SEQ_IN_MSGID(seq, seqid) (((seq&0xff)<<26) | (seqid&0x3ffffff)) #define GET_SEQ_FROM_MSGID(msgid, seq, seqid) \ do { \ seq = ((msgid >> 26) & 0x3f); \ seqid = (msgid & 0x3fffff); \ - } while (0) + } while (0) #define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff) -struct ipmi_channel -{ +struct ipmi_channel { unsigned char medium; unsigned char protocol; - /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR, - but may be changed by the user. */ + /* + * My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR, + * but may be changed by the user. + */ unsigned char address; - /* My LUN. This should generally stay the SMS LUN, but just in - case... */ + /* + * My LUN. This should generally stay the SMS LUN, but just in + * case... + */ unsigned char lun; }; #ifdef CONFIG_PROC_FS -struct ipmi_proc_entry -{ +struct ipmi_proc_entry { char *name; struct ipmi_proc_entry *next; }; #endif -struct bmc_device -{ +struct bmc_device { struct platform_device *dev; struct ipmi_device_id id; unsigned char guid[16]; @@ -186,10 +192,108 @@ struct bmc_device struct device_attribute aux_firmware_rev_attr; }; +/* + * Various statistics for IPMI, these index stats[] in the ipmi_smi + * structure. + */ +enum ipmi_stat_indexes { + /* Commands we got from the user that were invalid. */ + IPMI_STAT_sent_invalid_commands = 0, + + /* Commands we sent to the MC. */ + IPMI_STAT_sent_local_commands, + + /* Responses from the MC that were delivered to a user. */ + IPMI_STAT_handled_local_responses, + + /* Responses from the MC that were not delivered to a user. */ + IPMI_STAT_unhandled_local_responses, + + /* Commands we sent out to the IPMB bus. */ + IPMI_STAT_sent_ipmb_commands, + + /* Commands sent on the IPMB that had errors on the SEND CMD */ + IPMI_STAT_sent_ipmb_command_errs, + + /* Each retransmit increments this count. */ + IPMI_STAT_retransmitted_ipmb_commands, + + /* + * When a message times out (runs out of retransmits) this is + * incremented. + */ + IPMI_STAT_timed_out_ipmb_commands, + + /* + * This is like above, but for broadcasts. Broadcasts are + * *not* included in the above count (they are expected to + * time out). + */ + IPMI_STAT_timed_out_ipmb_broadcasts, + + /* Responses I have sent to the IPMB bus. */ + IPMI_STAT_sent_ipmb_responses, + + /* The response was delivered to the user. */ + IPMI_STAT_handled_ipmb_responses, + + /* The response had invalid data in it. */ + IPMI_STAT_invalid_ipmb_responses, + + /* The response didn't have anyone waiting for it. */ + IPMI_STAT_unhandled_ipmb_responses, + + /* Commands we sent out to the IPMB bus. */ + IPMI_STAT_sent_lan_commands, + + /* Commands sent on the IPMB that had errors on the SEND CMD */ + IPMI_STAT_sent_lan_command_errs, + + /* Each retransmit increments this count. */ + IPMI_STAT_retransmitted_lan_commands, + + /* + * When a message times out (runs out of retransmits) this is + * incremented. + */ + IPMI_STAT_timed_out_lan_commands, + + /* Responses I have sent to the IPMB bus. */ + IPMI_STAT_sent_lan_responses, + + /* The response was delivered to the user. */ + IPMI_STAT_handled_lan_responses, + + /* The response had invalid data in it. */ + IPMI_STAT_invalid_lan_responses, + + /* The response didn't have anyone waiting for it. */ + IPMI_STAT_unhandled_lan_responses, + + /* The command was delivered to the user. */ + IPMI_STAT_handled_commands, + + /* The command had invalid data in it. */ + IPMI_STAT_invalid_commands, + + /* The command didn't have anyone waiting for it. */ + IPMI_STAT_unhandled_commands, + + /* Invalid data in an event. */ + IPMI_STAT_invalid_events, + + /* Events that were received with the proper format. */ + IPMI_STAT_events, + + + /* This *must* remain last, add new values above this. */ + IPMI_NUM_STATS +}; + + #define IPMI_IPMB_NUM_SEQ 64 #define IPMI_MAX_CHANNELS 16 -struct ipmi_smi -{ +struct ipmi_smi { /* What interface number are we? */ int intf_num; @@ -198,8 +302,10 @@ struct ipmi_smi /* Used for a list of interfaces. */ struct list_head link; - /* The list of upper layers that are using me. seq_lock - * protects this. */ + /* + * The list of upper layers that are using me. seq_lock + * protects this. + */ struct list_head users; /* Information to supply to users. */ @@ -213,10 +319,12 @@ struct ipmi_smi char *my_dev_name; char *sysfs_name; - /* This is the lower-layer's sender routine. Note that you + /* + * This is the lower-layer's sender routine. Note that you * must either be holding the ipmi_interfaces_mutex or be in * an umpreemptible region to use this. You must fetch the - * value into a local variable and make sure it is not NULL. */ + * value into a local variable and make sure it is not NULL. + */ struct ipmi_smi_handlers *handlers; void *send_info; @@ -229,34 +337,45 @@ struct ipmi_smi /* Driver-model device for the system interface. */ struct device *si_dev; - /* A table of sequence numbers for this interface. We use the - sequence numbers for IPMB messages that go out of the - interface to match them up with their responses. A routine - is called periodically to time the items in this list. */ + /* + * A table of sequence numbers for this interface. We use the + * sequence numbers for IPMB messages that go out of the + * interface to match them up with their responses. A routine + * is called periodically to time the items in this list. + */ spinlock_t seq_lock; struct seq_table seq_table[IPMI_IPMB_NUM_SEQ]; int curr_seq; - /* Messages that were delayed for some reason (out of memory, - for instance), will go in here to be processed later in a - periodic timer interrupt. */ + /* + * Messages that were delayed for some reason (out of memory, + * for instance), will go in here to be processed later in a + * periodic timer interrupt. + */ spinlock_t waiting_msgs_lock; struct list_head waiting_msgs; - /* The list of command receivers that are registered for commands - on this interface. */ + /* + * The list of command receivers that are registered for commands + * on this interface. + */ struct mutex cmd_rcvrs_mutex; struct list_head cmd_rcvrs; - /* Events that were queues because no one was there to receive - them. */ + /* + * Events that were queues because no one was there to receive + * them. + */ spinlock_t events_lock; /* For dealing with event stuff. */ struct list_head waiting_events; unsigned int waiting_events_count; /* How many events in queue? */ - int delivering_events; + char delivering_events; + char event_msg_printed; - /* The event receiver for my BMC, only really used at panic - shutdown as a place to store this. */ + /* + * The event receiver for my BMC, only really used at panic + * shutdown as a place to store this. + */ unsigned char event_receiver; unsigned char event_receiver_lun; unsigned char local_sel_device; @@ -268,14 +387,18 @@ struct ipmi_smi int auto_maintenance_timeout; spinlock_t maintenance_mode_lock; /* Used in a timer... */ - /* A cheap hack, if this is non-null and a message to an - interface comes in with a NULL user, call this routine with - it. Note that the message will still be freed by the - caller. This only works on the system interface. */ + /* + * A cheap hack, if this is non-null and a message to an + * interface comes in with a NULL user, call this routine with + * it. Note that the message will still be freed by the + * caller. This only works on the system interface. + */ void (*null_user_handler)(ipmi_smi_t intf, struct ipmi_recv_msg *msg); - /* When we are scanning the channels for an SMI, this will - tell which channel we are scanning. */ + /* + * When we are scanning the channels for an SMI, this will + * tell which channel we are scanning. + */ int curr_channel; /* Channel information */ @@ -285,74 +408,14 @@ struct ipmi_smi struct proc_dir_entry *proc_dir; char proc_dir_name[10]; - spinlock_t counter_lock; /* For making counters atomic. */ - - /* Commands we got that were invalid. */ - unsigned int sent_invalid_commands; - - /* Commands we sent to the MC. */ - unsigned int sent_local_commands; - /* Responses from the MC that were delivered to a user. */ - unsigned int handled_local_responses; - /* Responses from the MC that were not delivered to a user. */ - unsigned int unhandled_local_responses; - - /* Commands we sent out to the IPMB bus. */ - unsigned int sent_ipmb_commands; - /* Commands sent on the IPMB that had errors on the SEND CMD */ - unsigned int sent_ipmb_command_errs; - /* Each retransmit increments this count. */ - unsigned int retransmitted_ipmb_commands; - /* When a message times out (runs out of retransmits) this is - incremented. */ - unsigned int timed_out_ipmb_commands; - - /* This is like above, but for broadcasts. Broadcasts are - *not* included in the above count (they are expected to - time out). */ - unsigned int timed_out_ipmb_broadcasts; + atomic_t stats[IPMI_NUM_STATS]; - /* Responses I have sent to the IPMB bus. */ - unsigned int sent_ipmb_responses; - - /* The response was delivered to the user. */ - unsigned int handled_ipmb_responses; - /* The response had invalid data in it. */ - unsigned int invalid_ipmb_responses; - /* The response didn't have anyone waiting for it. */ - unsigned int unhandled_ipmb_responses; - - /* Commands we sent out to the IPMB bus. */ - unsigned int sent_lan_commands; - /* Commands sent on the IPMB that had errors on the SEND CMD */ - unsigned int sent_lan_command_errs; - /* Each retransmit increments this count. */ - unsigned int retransmitted_lan_commands; - /* When a message times out (runs out of retransmits) this is - incremented. */ - unsigned int timed_out_lan_commands; - - /* Responses I have sent to the IPMB bus. */ - unsigned int sent_lan_responses; - - /* The response was delivered to the user. */ - unsigned int handled_lan_responses; - /* The response had invalid data in it. */ - unsigned int invalid_lan_responses; - /* The response didn't have anyone waiting for it. */ - unsigned int unhandled_lan_responses; - - /* The command was delivered to the user. */ - unsigned int handled_commands; - /* The command had invalid data in it. */ - unsigned int invalid_commands; - /* The command didn't have anyone waiting for it. */ - unsigned int unhandled_commands; - - /* Invalid data in an event. */ - unsigned int invalid_events; - /* Events that were received with the proper format. */ - unsigned int events; + /* + * run_to_completion duplicate of smb_info, smi_info + * and ipmi_serial_info structures. Used to decrease numbers of + * parameters passed by "low" level IPMI code. + */ + int run_to_completion; }; #define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev) @@ -368,12 +431,19 @@ static DEFINE_MUTEX(ipmidriver_mutex); static LIST_HEAD(ipmi_interfaces); static DEFINE_MUTEX(ipmi_interfaces_mutex); -/* List of watchers that want to know when smi's are added and - deleted. */ +/* + * List of watchers that want to know when smi's are added and deleted. + */ static LIST_HEAD(smi_watchers); static DEFINE_MUTEX(smi_watchers_mutex); +#define ipmi_inc_stat(intf, stat) \ + atomic_inc(&(intf)->stats[IPMI_STAT_ ## stat]) +#define ipmi_get_stat(intf, stat) \ + ((unsigned int) atomic_read(&(intf)->stats[IPMI_STAT_ ## stat])) + + static void free_recv_msg_list(struct list_head *q) { struct ipmi_recv_msg *msg, *msg2; @@ -417,10 +487,8 @@ static void clean_up_interface_data(ipmi_smi_t intf) for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) { if ((intf->seq_table[i].inuse) - && (intf->seq_table[i].recv_msg)) - { + && (intf->seq_table[i].recv_msg)) ipmi_free_recv_msg(intf->seq_table[i].recv_msg); - } } } @@ -487,6 +555,7 @@ int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher) } return -ENOMEM; } +EXPORT_SYMBOL(ipmi_smi_watcher_register); int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher) { @@ -495,6 +564,7 @@ int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher) mutex_unlock(&smi_watchers_mutex); return 0; } +EXPORT_SYMBOL(ipmi_smi_watcher_unregister); /* * Must be called with smi_watchers_mutex held. @@ -530,8 +600,7 @@ ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2) } if ((addr1->addr_type == IPMI_IPMB_ADDR_TYPE) - || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) - { + || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) { struct ipmi_ipmb_addr *ipmb_addr1 = (struct ipmi_ipmb_addr *) addr1; struct ipmi_ipmb_addr *ipmb_addr2 @@ -559,9 +628,8 @@ ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2) int ipmi_validate_addr(struct ipmi_addr *addr, int len) { - if (len < sizeof(struct ipmi_system_interface_addr)) { + if (len < sizeof(struct ipmi_system_interface_addr)) return -EINVAL; - } if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) { if (addr->channel != IPMI_BMC_CHANNEL) @@ -575,23 +643,21 @@ int ipmi_validate_addr(struct ipmi_addr *addr, int len) return -EINVAL; if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE) - || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) - { - if (len < sizeof(struct ipmi_ipmb_addr)) { + || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) { + if (len < sizeof(struct ipmi_ipmb_addr)) return -EINVAL; - } return 0; } if (addr->addr_type == IPMI_LAN_ADDR_TYPE) { - if (len < sizeof(struct ipmi_lan_addr)) { + if (len < sizeof(struct ipmi_lan_addr)) return -EINVAL; - } return 0; } return -EINVAL; } +EXPORT_SYMBOL(ipmi_validate_addr); unsigned int ipmi_addr_length(int addr_type) { @@ -599,34 +665,28 @@ unsigned int ipmi_addr_length(int addr_type) return sizeof(struct ipmi_system_interface_addr); if ((addr_type == IPMI_IPMB_ADDR_TYPE) - || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) - { + || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) return sizeof(struct ipmi_ipmb_addr); - } if (addr_type == IPMI_LAN_ADDR_TYPE) return sizeof(struct ipmi_lan_addr); return 0; } +EXPORT_SYMBOL(ipmi_addr_length); static void deliver_response(struct ipmi_recv_msg *msg) { if (!msg->user) { ipmi_smi_t intf = msg->user_msg_data; - unsigned long flags; /* Special handling for NULL users. */ if (intf->null_user_handler) { intf->null_user_handler(intf, msg); - spin_lock_irqsave(&intf->counter_lock, flags); - intf->handled_local_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, handled_local_responses); } else { /* No handler, so give up. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->unhandled_local_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, unhandled_local_responses); } ipmi_free_recv_msg(msg); } else { @@ -646,9 +706,11 @@ deliver_err_response(struct ipmi_recv_msg *msg, int err) deliver_response(msg); } -/* Find the next sequence number not being used and add the given - message with the given timeout to the sequence table. This must be - called with the interface's seq_lock held. */ +/* + * Find the next sequence number not being used and add the given + * message with the given timeout to the sequence table. This must be + * called with the interface's seq_lock held. + */ static int intf_next_seq(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, unsigned long timeout, @@ -660,10 +722,8 @@ static int intf_next_seq(ipmi_smi_t intf, int rv = 0; unsigned int i; - for (i = intf->curr_seq; - (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq; - i = (i+1)%IPMI_IPMB_NUM_SEQ) - { + for (i = intf->curr_seq; (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq; + i = (i+1)%IPMI_IPMB_NUM_SEQ) { if (!intf->seq_table[i].inuse) break; } @@ -671,8 +731,10 @@ static int intf_next_seq(ipmi_smi_t intf, if (!intf->seq_table[i].inuse) { intf->seq_table[i].recv_msg = recv_msg; - /* Start with the maximum timeout, when the send response - comes in we will start the real timer. */ + /* + * Start with the maximum timeout, when the send response + * comes in we will start the real timer. + */ intf->seq_table[i].timeout = MAX_MSG_TIMEOUT; intf->seq_table[i].orig_timeout = timeout; intf->seq_table[i].retries_left = retries; @@ -685,15 +747,17 @@ static int intf_next_seq(ipmi_smi_t intf, } else { rv = -EAGAIN; } - + return rv; } -/* Return the receive message for the given sequence number and - release the sequence number so it can be reused. Some other data - is passed in to be sure the message matches up correctly (to help - guard against message coming in after their timeout and the - sequence number being reused). */ +/* + * Return the receive message for the given sequence number and + * release the sequence number so it can be reused. Some other data + * is passed in to be sure the message matches up correctly (to help + * guard against message coming in after their timeout and the + * sequence number being reused). + */ static int intf_find_seq(ipmi_smi_t intf, unsigned char seq, short channel, @@ -712,11 +776,9 @@ static int intf_find_seq(ipmi_smi_t intf, if (intf->seq_table[seq].inuse) { struct ipmi_recv_msg *msg = intf->seq_table[seq].recv_msg; - if ((msg->addr.channel == channel) - && (msg->msg.cmd == cmd) - && (msg->msg.netfn == netfn) - && (ipmi_addr_equal(addr, &(msg->addr)))) - { + if ((msg->addr.channel == channel) && (msg->msg.cmd == cmd) + && (msg->msg.netfn == netfn) + && (ipmi_addr_equal(addr, &(msg->addr)))) { *recv_msg = msg; intf->seq_table[seq].inuse = 0; rv = 0; @@ -741,11 +803,12 @@ static int intf_start_seq_timer(ipmi_smi_t intf, GET_SEQ_FROM_MSGID(msgid, seq, seqid); spin_lock_irqsave(&(intf->seq_lock), flags); - /* We do this verification because the user can be deleted - while a message is outstanding. */ + /* + * We do this verification because the user can be deleted + * while a message is outstanding. + */ if ((intf->seq_table[seq].inuse) - && (intf->seq_table[seq].seqid == seqid)) - { + && (intf->seq_table[seq].seqid == seqid)) { struct seq_table *ent = &(intf->seq_table[seq]); ent->timeout = ent->orig_timeout; rv = 0; @@ -770,11 +833,12 @@ static int intf_err_seq(ipmi_smi_t intf, GET_SEQ_FROM_MSGID(msgid, seq, seqid); spin_lock_irqsave(&(intf->seq_lock), flags); - /* We do this verification because the user can be deleted - while a message is outstanding. */ + /* + * We do this verification because the user can be deleted + * while a message is outstanding. + */ if ((intf->seq_table[seq].inuse) - && (intf->seq_table[seq].seqid == seqid)) - { + && (intf->seq_table[seq].seqid == seqid)) { struct seq_table *ent = &(intf->seq_table[seq]); ent->inuse = 0; @@ -800,24 +864,30 @@ int ipmi_create_user(unsigned int if_num, int rv = 0; ipmi_smi_t intf; - /* There is no module usecount here, because it's not - required. Since this can only be used by and called from - other modules, they will implicitly use this module, and - thus this can't be removed unless the other modules are - removed. */ + /* + * There is no module usecount here, because it's not + * required. Since this can only be used by and called from + * other modules, they will implicitly use this module, and + * thus this can't be removed unless the other modules are + * removed. + */ if (handler == NULL) return -EINVAL; - /* Make sure the driver is actually initialized, this handles - problems with initialization order. */ + /* + * Make sure the driver is actually initialized, this handles + * problems with initialization order. + */ if (!initialized) { rv = ipmi_init_msghandler(); if (rv) return rv; - /* The init code doesn't return an error if it was turned - off, but it won't initialize. Check that. */ + /* + * The init code doesn't return an error if it was turned + * off, but it won't initialize. Check that. + */ if (!initialized) return -ENODEV; } @@ -858,8 +928,10 @@ int ipmi_create_user(unsigned int if_num, } } - /* Hold the lock so intf->handlers is guaranteed to be good - * until now */ + /* + * Hold the lock so intf->handlers is guaranteed to be good + * until now + */ mutex_unlock(&ipmi_interfaces_mutex); new_user->valid = 1; @@ -876,6 +948,7 @@ out_kfree: kfree(new_user); return rv; } +EXPORT_SYMBOL(ipmi_create_user); static void free_user(struct kref *ref) { @@ -899,8 +972,7 @@ int ipmi_destroy_user(ipmi_user_t user) for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) { if (intf->seq_table[i].inuse - && (intf->seq_table[i].recv_msg->user == user)) - { + && (intf->seq_table[i].recv_msg->user == user)) { intf->seq_table[i].inuse = 0; ipmi_free_recv_msg(intf->seq_table[i].recv_msg); } @@ -943,6 +1015,7 @@ int ipmi_destroy_user(ipmi_user_t user) return 0; } +EXPORT_SYMBOL(ipmi_destroy_user); void ipmi_get_version(ipmi_user_t user, unsigned char *major, @@ -951,6 +1024,7 @@ void ipmi_get_version(ipmi_user_t user, *major = user->intf->ipmi_version_major; *minor = user->intf->ipmi_version_minor; } +EXPORT_SYMBOL(ipmi_get_version); int ipmi_set_my_address(ipmi_user_t user, unsigned int channel, @@ -961,6 +1035,7 @@ int ipmi_set_my_address(ipmi_user_t user, user->intf->channels[channel].address = address; return 0; } +EXPORT_SYMBOL(ipmi_set_my_address); int ipmi_get_my_address(ipmi_user_t user, unsigned int channel, @@ -971,6 +1046,7 @@ int ipmi_get_my_address(ipmi_user_t user, *address = user->intf->channels[channel].address; return 0; } +EXPORT_SYMBOL(ipmi_get_my_address); int ipmi_set_my_LUN(ipmi_user_t user, unsigned int channel, @@ -981,6 +1057,7 @@ int ipmi_set_my_LUN(ipmi_user_t user, user->intf->channels[channel].lun = LUN & 0x3; return 0; } +EXPORT_SYMBOL(ipmi_set_my_LUN); int ipmi_get_my_LUN(ipmi_user_t user, unsigned int channel, @@ -991,6 +1068,7 @@ int ipmi_get_my_LUN(ipmi_user_t user, *address = user->intf->channels[channel].lun; return 0; } +EXPORT_SYMBOL(ipmi_get_my_LUN); int ipmi_get_maintenance_mode(ipmi_user_t user) { @@ -1075,6 +1153,11 @@ int ipmi_set_gets_events(ipmi_user_t user, int val) list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link) list_move_tail(&msg->link, &msgs); intf->waiting_events_count = 0; + if (intf->event_msg_printed) { + printk(KERN_WARNING PFX "Event queue no longer" + " full\n"); + intf->event_msg_printed = 0; + } intf->delivering_events = 1; spin_unlock_irqrestore(&intf->events_lock, flags); @@ -1094,6 +1177,7 @@ int ipmi_set_gets_events(ipmi_user_t user, int val) return 0; } +EXPORT_SYMBOL(ipmi_set_gets_events); static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf, unsigned char netfn, @@ -1159,6 +1243,7 @@ int ipmi_register_for_cmd(ipmi_user_t user, return rv; } +EXPORT_SYMBOL(ipmi_register_for_cmd); int ipmi_unregister_for_cmd(ipmi_user_t user, unsigned char netfn, @@ -1196,19 +1281,13 @@ int ipmi_unregister_for_cmd(ipmi_user_t user, } return rv; } - -void ipmi_user_set_run_to_completion(ipmi_user_t user, int val) -{ - ipmi_smi_t intf = user->intf; - if (intf->handlers) - intf->handlers->set_run_to_completion(intf->send_info, val); -} +EXPORT_SYMBOL(ipmi_unregister_for_cmd); static unsigned char ipmb_checksum(unsigned char *data, int size) { unsigned char csum = 0; - + for (; size > 0; size--, data++) csum += *data; @@ -1250,8 +1329,10 @@ static inline void format_ipmb_msg(struct ipmi_smi_msg *smi_msg, = ipmb_checksum(&(smi_msg->data[i+6]), smi_msg->data_size-6); - /* Add on the checksum size and the offset from the - broadcast. */ + /* + * Add on the checksum size and the offset from the + * broadcast. + */ smi_msg->data_size += 1 + i; smi_msg->msgid = msgid; @@ -1287,17 +1368,21 @@ static inline void format_lan_msg(struct ipmi_smi_msg *smi_msg, = ipmb_checksum(&(smi_msg->data[7]), smi_msg->data_size-7); - /* Add on the checksum size and the offset from the - broadcast. */ + /* + * Add on the checksum size and the offset from the + * broadcast. + */ smi_msg->data_size += 1; smi_msg->msgid = msgid; } -/* Separate from ipmi_request so that the user does not have to be - supplied in certain circumstances (mainly at panic time). If - messages are supplied, they will be freed, even if an error - occurs. */ +/* + * Separate from ipmi_request so that the user does not have to be + * supplied in certain circumstances (mainly at panic time). If + * messages are supplied, they will be freed, even if an error + * occurs. + */ static int i_ipmi_request(ipmi_user_t user, ipmi_smi_t intf, struct ipmi_addr *addr, @@ -1319,19 +1404,18 @@ static int i_ipmi_request(ipmi_user_t user, struct ipmi_smi_handlers *handlers; - if (supplied_recv) { + if (supplied_recv) recv_msg = supplied_recv; - } else { + else { recv_msg = ipmi_alloc_recv_msg(); - if (recv_msg == NULL) { + if (recv_msg == NULL) return -ENOMEM; - } } recv_msg->user_msg_data = user_msg_data; - if (supplied_smi) { + if (supplied_smi) smi_msg = (struct ipmi_smi_msg *) supplied_smi; - } else { + else { smi_msg = ipmi_alloc_smi_msg(); if (smi_msg == NULL) { ipmi_free_recv_msg(recv_msg); @@ -1350,8 +1434,10 @@ static int i_ipmi_request(ipmi_user_t user, if (user) kref_get(&user->refcount); recv_msg->msgid = msgid; - /* Store the message to send in the receive message so timeout - responses can get the proper response data. */ + /* + * Store the message to send in the receive message so timeout + * responses can get the proper response data. + */ recv_msg->msg = *msg; if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) { @@ -1365,9 +1451,7 @@ static int i_ipmi_request(ipmi_user_t user, smi_addr = (struct ipmi_system_interface_addr *) addr; if (smi_addr->lun > 3) { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } @@ -1377,13 +1461,12 @@ static int i_ipmi_request(ipmi_user_t user, if ((msg->netfn == IPMI_NETFN_APP_REQUEST) && ((msg->cmd == IPMI_SEND_MSG_CMD) || (msg->cmd == IPMI_GET_MSG_CMD) - || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD))) - { - /* We don't let the user do these, since we manage - the sequence numbers. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD))) { + /* + * We don't let the user do these, since we manage + * the sequence numbers. + */ + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } @@ -1391,14 +1474,12 @@ static int i_ipmi_request(ipmi_user_t user, if (((msg->netfn == IPMI_NETFN_APP_REQUEST) && ((msg->cmd == IPMI_COLD_RESET_CMD) || (msg->cmd == IPMI_WARM_RESET_CMD))) - || (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST)) - { + || (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST)) { spin_lock_irqsave(&intf->maintenance_mode_lock, flags); intf->auto_maintenance_timeout = IPMI_MAINTENANCE_MODE_TIMEOUT; if (!intf->maintenance_mode - && !intf->maintenance_mode_enable) - { + && !intf->maintenance_mode_enable) { intf->maintenance_mode_enable = 1; maintenance_mode_update(intf); } @@ -1407,9 +1488,7 @@ static int i_ipmi_request(ipmi_user_t user, } if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EMSGSIZE; goto out_err; } @@ -1421,31 +1500,23 @@ static int i_ipmi_request(ipmi_user_t user, if (msg->data_len > 0) memcpy(&(smi_msg->data[2]), msg->data, msg->data_len); smi_msg->data_size = msg->data_len + 2; - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_local_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_local_commands); } else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE) - || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) - { + || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) { struct ipmi_ipmb_addr *ipmb_addr; unsigned char ipmb_seq; long seqid; int broadcast = 0; if (addr->channel >= IPMI_MAX_CHANNELS) { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } if (intf->channels[addr->channel].medium - != IPMI_CHANNEL_MEDIUM_IPMB) - { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + != IPMI_CHANNEL_MEDIUM_IPMB) { + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } @@ -1457,9 +1528,11 @@ static int i_ipmi_request(ipmi_user_t user, retries = 4; } if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) { - /* Broadcasts add a zero at the beginning of the - message, but otherwise is the same as an IPMB - address. */ + /* + * Broadcasts add a zero at the beginning of the + * message, but otherwise is the same as an IPMB + * address. + */ addr->addr_type = IPMI_IPMB_ADDR_TYPE; broadcast = 1; } @@ -1469,21 +1542,19 @@ static int i_ipmi_request(ipmi_user_t user, if (retry_time_ms == 0) retry_time_ms = 1000; - /* 9 for the header and 1 for the checksum, plus - possibly one for the broadcast. */ + /* + * 9 for the header and 1 for the checksum, plus + * possibly one for the broadcast. + */ if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EMSGSIZE; goto out_err; } ipmb_addr = (struct ipmi_ipmb_addr *) addr; if (ipmb_addr->lun > 3) { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } @@ -1491,29 +1562,31 @@ static int i_ipmi_request(ipmi_user_t user, memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr)); if (recv_msg->msg.netfn & 0x1) { - /* It's a response, so use the user's sequence - from msgid. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_ipmb_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + /* + * It's a response, so use the user's sequence + * from msgid. + */ + ipmi_inc_stat(intf, sent_ipmb_responses); format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid, msgid, broadcast, source_address, source_lun); - /* Save the receive message so we can use it - to deliver the response. */ + /* + * Save the receive message so we can use it + * to deliver the response. + */ smi_msg->user_data = recv_msg; } else { /* It's a command, so get a sequence for it. */ spin_lock_irqsave(&(intf->seq_lock), flags); - spin_lock(&intf->counter_lock); - intf->sent_ipmb_commands++; - spin_unlock(&intf->counter_lock); + ipmi_inc_stat(intf, sent_ipmb_commands); - /* Create a sequence number with a 1 second - timeout and 4 retries. */ + /* + * Create a sequence number with a 1 second + * timeout and 4 retries. + */ rv = intf_next_seq(intf, recv_msg, retry_time_ms, @@ -1522,34 +1595,42 @@ static int i_ipmi_request(ipmi_user_t user, &ipmb_seq, &seqid); if (rv) { - /* We have used up all the sequence numbers, - probably, so abort. */ + /* + * We have used up all the sequence numbers, + * probably, so abort. + */ spin_unlock_irqrestore(&(intf->seq_lock), flags); goto out_err; } - /* Store the sequence number in the message, - so that when the send message response - comes back we can start the timer. */ + /* + * Store the sequence number in the message, + * so that when the send message response + * comes back we can start the timer. + */ format_ipmb_msg(smi_msg, msg, ipmb_addr, STORE_SEQ_IN_MSGID(ipmb_seq, seqid), ipmb_seq, broadcast, source_address, source_lun); - /* Copy the message into the recv message data, so we - can retransmit it later if necessary. */ + /* + * Copy the message into the recv message data, so we + * can retransmit it later if necessary. + */ memcpy(recv_msg->msg_data, smi_msg->data, smi_msg->data_size); recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg.data_len = smi_msg->data_size; - /* We don't unlock until here, because we need - to copy the completed message into the - recv_msg before we release the lock. - Otherwise, race conditions may bite us. I - know that's pretty paranoid, but I prefer - to be correct. */ + /* + * We don't unlock until here, because we need + * to copy the completed message into the + * recv_msg before we release the lock. + * Otherwise, race conditions may bite us. I + * know that's pretty paranoid, but I prefer + * to be correct. + */ spin_unlock_irqrestore(&(intf->seq_lock), flags); } } else if (addr->addr_type == IPMI_LAN_ADDR_TYPE) { @@ -1558,21 +1639,16 @@ static int i_ipmi_request(ipmi_user_t user, long seqid; if (addr->channel >= IPMI_MAX_CHANNELS) { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } if ((intf->channels[addr->channel].medium - != IPMI_CHANNEL_MEDIUM_8023LAN) + != IPMI_CHANNEL_MEDIUM_8023LAN) && (intf->channels[addr->channel].medium - != IPMI_CHANNEL_MEDIUM_ASYNC)) - { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + != IPMI_CHANNEL_MEDIUM_ASYNC)) { + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } @@ -1585,18 +1661,14 @@ static int i_ipmi_request(ipmi_user_t user, /* 11 for the header and 1 for the checksum. */ if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EMSGSIZE; goto out_err; } lan_addr = (struct ipmi_lan_addr *) addr; if (lan_addr->lun > 3) { - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } @@ -1604,28 +1676,30 @@ static int i_ipmi_request(ipmi_user_t user, memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr)); if (recv_msg->msg.netfn & 0x1) { - /* It's a response, so use the user's sequence - from msgid. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_lan_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + /* + * It's a response, so use the user's sequence + * from msgid. + */ + ipmi_inc_stat(intf, sent_lan_responses); format_lan_msg(smi_msg, msg, lan_addr, msgid, msgid, source_lun); - /* Save the receive message so we can use it - to deliver the response. */ + /* + * Save the receive message so we can use it + * to deliver the response. + */ smi_msg->user_data = recv_msg; } else { /* It's a command, so get a sequence for it. */ spin_lock_irqsave(&(intf->seq_lock), flags); - spin_lock(&intf->counter_lock); - intf->sent_lan_commands++; - spin_unlock(&intf->counter_lock); + ipmi_inc_stat(intf, sent_lan_commands); - /* Create a sequence number with a 1 second - timeout and 4 retries. */ + /* + * Create a sequence number with a 1 second + * timeout and 4 retries. + */ rv = intf_next_seq(intf, recv_msg, retry_time_ms, @@ -1634,40 +1708,46 @@ static int i_ipmi_request(ipmi_user_t user, &ipmb_seq, &seqid); if (rv) { - /* We have used up all the sequence numbers, - probably, so abort. */ + /* + * We have used up all the sequence numbers, + * probably, so abort. + */ spin_unlock_irqrestore(&(intf->seq_lock), flags); goto out_err; } - /* Store the sequence number in the message, - so that when the send message response - comes back we can start the timer. */ + /* + * Store the sequence number in the message, + * so that when the send message response + * comes back we can start the timer. + */ format_lan_msg(smi_msg, msg, lan_addr, STORE_SEQ_IN_MSGID(ipmb_seq, seqid), ipmb_seq, source_lun); - /* Copy the message into the recv message data, so we - can retransmit it later if necessary. */ + /* + * Copy the message into the recv message data, so we + * can retransmit it later if necessary. + */ memcpy(recv_msg->msg_data, smi_msg->data, smi_msg->data_size); recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg.data_len = smi_msg->data_size; - /* We don't unlock until here, because we need - to copy the completed message into the - recv_msg before we release the lock. - Otherwise, race conditions may bite us. I - know that's pretty paranoid, but I prefer - to be correct. */ + /* + * We don't unlock until here, because we need + * to copy the completed message into the + * recv_msg before we release the lock. + * Otherwise, race conditions may bite us. I + * know that's pretty paranoid, but I prefer + * to be correct. + */ spin_unlock_irqrestore(&(intf->seq_lock), flags); } } else { /* Unknown address type. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->sent_invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_invalid_commands); rv = -EINVAL; goto out_err; } @@ -1735,6 +1815,7 @@ int ipmi_request_settime(ipmi_user_t user, retries, retry_time_ms); } +EXPORT_SYMBOL(ipmi_request_settime); int ipmi_request_supply_msgs(ipmi_user_t user, struct ipmi_addr *addr, @@ -1766,6 +1847,7 @@ int ipmi_request_supply_msgs(ipmi_user_t user, lun, -1, 0); } +EXPORT_SYMBOL(ipmi_request_supply_msgs); #ifdef CONFIG_PROC_FS static int ipmb_file_read_proc(char *page, char **start, off_t off, @@ -1790,7 +1872,7 @@ static int version_file_read_proc(char *page, char **start, off_t off, char *out = (char *) page; ipmi_smi_t intf = data; - return sprintf(out, "%d.%d\n", + return sprintf(out, "%u.%u\n", ipmi_version_major(&intf->bmc->id), ipmi_version_minor(&intf->bmc->id)); } @@ -1801,65 +1883,65 @@ static int stat_file_read_proc(char *page, char **start, off_t off, char *out = (char *) page; ipmi_smi_t intf = data; - out += sprintf(out, "sent_invalid_commands: %d\n", - intf->sent_invalid_commands); - out += sprintf(out, "sent_local_commands: %d\n", - intf->sent_local_commands); - out += sprintf(out, "handled_local_responses: %d\n", - intf->handled_local_responses); - out += sprintf(out, "unhandled_local_responses: %d\n", - intf->unhandled_local_responses); - out += sprintf(out, "sent_ipmb_commands: %d\n", - intf->sent_ipmb_commands); - out += sprintf(out, "sent_ipmb_command_errs: %d\n", - intf->sent_ipmb_command_errs); - out += sprintf(out, "retransmitted_ipmb_commands: %d\n", - intf->retransmitted_ipmb_commands); - out += sprintf(out, "timed_out_ipmb_commands: %d\n", - intf->timed_out_ipmb_commands); - out += sprintf(out, "timed_out_ipmb_broadcasts: %d\n", - intf->timed_out_ipmb_broadcasts); - out += sprintf(out, "sent_ipmb_responses: %d\n", - intf->sent_ipmb_responses); - out += sprintf(out, "handled_ipmb_responses: %d\n", - intf->handled_ipmb_responses); - out += sprintf(out, "invalid_ipmb_responses: %d\n", - intf->invalid_ipmb_responses); - out += sprintf(out, "unhandled_ipmb_responses: %d\n", - intf->unhandled_ipmb_responses); - out += sprintf(out, "sent_lan_commands: %d\n", - intf->sent_lan_commands); - out += sprintf(out, "sent_lan_command_errs: %d\n", - intf->sent_lan_command_errs); - out += sprintf(out, "retransmitted_lan_commands: %d\n", - intf->retransmitted_lan_commands); - out += sprintf(out, "timed_out_lan_commands: %d\n", - intf->timed_out_lan_commands); - out += sprintf(out, "sent_lan_responses: %d\n", - intf->sent_lan_responses); - out += sprintf(out, "handled_lan_responses: %d\n", - intf->handled_lan_responses); - out += sprintf(out, "invalid_lan_responses: %d\n", - intf->invalid_lan_responses); - out += sprintf(out, "unhandled_lan_responses: %d\n", - intf->unhandled_lan_responses); - out += sprintf(out, "handled_commands: %d\n", - intf->handled_commands); - out += sprintf(out, "invalid_commands: %d\n", - intf->invalid_commands); - out += sprintf(out, "unhandled_commands: %d\n", - intf->unhandled_commands); - out += sprintf(out, "invalid_events: %d\n", - intf->invalid_events); - out += sprintf(out, "events: %d\n", - intf->events); + out += sprintf(out, "sent_invalid_commands: %u\n", + ipmi_get_stat(intf, sent_invalid_commands)); + out += sprintf(out, "sent_local_commands: %u\n", + ipmi_get_stat(intf, sent_local_commands)); + out += sprintf(out, "handled_local_responses: %u\n", + ipmi_get_stat(intf, handled_local_responses)); + out += sprintf(out, "unhandled_local_responses: %u\n", + ipmi_get_stat(intf, unhandled_local_responses)); + out += sprintf(out, "sent_ipmb_commands: %u\n", + ipmi_get_stat(intf, sent_ipmb_commands)); + out += sprintf(out, "sent_ipmb_command_errs: %u\n", + ipmi_get_stat(intf, sent_ipmb_command_errs)); + out += sprintf(out, "retransmitted_ipmb_commands: %u\n", + ipmi_get_stat(intf, retransmitted_ipmb_commands)); + out += sprintf(out, "timed_out_ipmb_commands: %u\n", + ipmi_get_stat(intf, timed_out_ipmb_commands)); + out += sprintf(out, "timed_out_ipmb_broadcasts: %u\n", + ipmi_get_stat(intf, timed_out_ipmb_broadcasts)); + out += sprintf(out, "sent_ipmb_responses: %u\n", + ipmi_get_stat(intf, sent_ipmb_responses)); + out += sprintf(out, "handled_ipmb_responses: %u\n", + ipmi_get_stat(intf, handled_ipmb_responses)); + out += sprintf(out, "invalid_ipmb_responses: %u\n", + ipmi_get_stat(intf, invalid_ipmb_responses)); + out += sprintf(out, "unhandled_ipmb_responses: %u\n", + ipmi_get_stat(intf, unhandled_ipmb_responses)); + out += sprintf(out, "sent_lan_commands: %u\n", + ipmi_get_stat(intf, sent_lan_commands)); + out += sprintf(out, "sent_lan_command_errs: %u\n", + ipmi_get_stat(intf, sent_lan_command_errs)); + out += sprintf(out, "retransmitted_lan_commands: %u\n", + ipmi_get_stat(intf, retransmitted_lan_commands)); + out += sprintf(out, "timed_out_lan_commands: %u\n", + ipmi_get_stat(intf, timed_out_lan_commands)); + out += sprintf(out, "sent_lan_responses: %u\n", + ipmi_get_stat(intf, sent_lan_responses)); + out += sprintf(out, "handled_lan_responses: %u\n", + ipmi_get_stat(intf, handled_lan_responses)); + out += sprintf(out, "invalid_lan_responses: %u\n", + ipmi_get_stat(intf, invalid_lan_responses)); + out += sprintf(out, "unhandled_lan_responses: %u\n", + ipmi_get_stat(intf, unhandled_lan_responses)); + out += sprintf(out, "handled_commands: %u\n", + ipmi_get_stat(intf, handled_commands)); + out += sprintf(out, "invalid_commands: %u\n", + ipmi_get_stat(intf, invalid_commands)); + out += sprintf(out, "unhandled_commands: %u\n", + ipmi_get_stat(intf, unhandled_commands)); + out += sprintf(out, "invalid_events: %u\n", + ipmi_get_stat(intf, invalid_events)); + out += sprintf(out, "events: %u\n", + ipmi_get_stat(intf, events)); return (out - ((char *) page)); } #endif /* CONFIG_PROC_FS */ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name, - read_proc_t *read_proc, write_proc_t *write_proc, + read_proc_t *read_proc, void *data, struct module *owner) { int rv = 0; @@ -1886,7 +1968,6 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name, } else { file->data = data; file->read_proc = read_proc; - file->write_proc = write_proc; file->owner = owner; mutex_lock(&smi->proc_entry_lock); @@ -1899,6 +1980,7 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name, return rv; } +EXPORT_SYMBOL(ipmi_smi_add_proc_entry); static int add_proc_entries(ipmi_smi_t smi, int num) { @@ -1909,23 +1991,22 @@ static int add_proc_entries(ipmi_smi_t smi, int num) smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root); if (!smi->proc_dir) rv = -ENOMEM; - else { + else smi->proc_dir->owner = THIS_MODULE; - } if (rv == 0) rv = ipmi_smi_add_proc_entry(smi, "stats", - stat_file_read_proc, NULL, + stat_file_read_proc, smi, THIS_MODULE); if (rv == 0) rv = ipmi_smi_add_proc_entry(smi, "ipmb", - ipmb_file_read_proc, NULL, + ipmb_file_read_proc, smi, THIS_MODULE); if (rv == 0) rv = ipmi_smi_add_proc_entry(smi, "version", - version_file_read_proc, NULL, + version_file_read_proc, smi, THIS_MODULE); #endif /* CONFIG_PROC_FS */ @@ -2210,37 +2291,47 @@ static int create_files(struct bmc_device *bmc) err = device_create_file(&bmc->dev->dev, &bmc->device_id_attr); - if (err) goto out; + if (err) + goto out; err = device_create_file(&bmc->dev->dev, &bmc->provides_dev_sdrs_attr); - if (err) goto out_devid; + if (err) + goto out_devid; err = device_create_file(&bmc->dev->dev, &bmc->revision_attr); - if (err) goto out_sdrs; + if (err) + goto out_sdrs; err = device_create_file(&bmc->dev->dev, &bmc->firmware_rev_attr); - if (err) goto out_rev; + if (err) + goto out_rev; err = device_create_file(&bmc->dev->dev, &bmc->version_attr); - if (err) goto out_firm; + if (err) + goto out_firm; err = device_create_file(&bmc->dev->dev, &bmc->add_dev_support_attr); - if (err) goto out_version; + if (err) + goto out_version; err = device_create_file(&bmc->dev->dev, &bmc->manufacturer_id_attr); - if (err) goto out_add_dev; + if (err) + goto out_add_dev; err = device_create_file(&bmc->dev->dev, &bmc->product_id_attr); - if (err) goto out_manu; + if (err) + goto out_manu; if (bmc->id.aux_firmware_revision_set) { err = device_create_file(&bmc->dev->dev, &bmc->aux_firmware_rev_attr); - if (err) goto out_prod_id; + if (err) + goto out_prod_id; } if (bmc->guid_set) { err = device_create_file(&bmc->dev->dev, &bmc->guid_attr); - if (err) goto out_aux_firm; + if (err) + goto out_aux_firm; } return 0; @@ -2368,8 +2459,10 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum, "ipmi_msghandler:" " Unable to register bmc device: %d\n", rv); - /* Don't go to out_err, you can only do that if - the device is registered already. */ + /* + * Don't go to out_err, you can only do that if + * the device is registered already. + */ return rv; } @@ -2560,17 +2653,18 @@ channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE) - && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD)) - { + && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD)) { /* It's the one we want */ if (msg->msg.data[0] != 0) { /* Got an error from the channel, just go on. */ if (msg->msg.data[0] == IPMI_INVALID_COMMAND_ERR) { - /* If the MC does not support this - command, that is legal. We just - assume it has one IPMB at channel - zero. */ + /* + * If the MC does not support this + * command, that is legal. We just + * assume it has one IPMB at channel + * zero. + */ intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB; intf->channels[0].protocol @@ -2591,7 +2685,7 @@ channel_handler(ipmi_smi_t intf, struct ipmi_recv_msg *msg) intf->channels[chan].medium = msg->msg.data[2] & 0x7f; intf->channels[chan].protocol = msg->msg.data[3] & 0x1f; - next_channel: + next_channel: intf->curr_channel++; if (intf->curr_channel >= IPMI_MAX_CHANNELS) wake_up(&intf->waitq); @@ -2619,6 +2713,7 @@ void ipmi_poll_interface(ipmi_user_t user) if (intf->handlers->poll) intf->handlers->poll(intf->send_info); } +EXPORT_SYMBOL(ipmi_poll_interface); int ipmi_register_smi(struct ipmi_smi_handlers *handlers, void *send_info, @@ -2633,14 +2728,18 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, ipmi_smi_t tintf; struct list_head *link; - /* Make sure the driver is actually initialized, this handles - problems with initialization order. */ + /* + * Make sure the driver is actually initialized, this handles + * problems with initialization order. + */ if (!initialized) { rv = ipmi_init_msghandler(); if (rv) return rv; - /* The init code doesn't return an error if it was turned - off, but it won't initialize. Check that. */ + /* + * The init code doesn't return an error if it was turned + * off, but it won't initialize. Check that. + */ if (!initialized) return -ENODEV; } @@ -2688,8 +2787,9 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, spin_lock_init(&intf->maintenance_mode_lock); INIT_LIST_HEAD(&intf->cmd_rcvrs); init_waitqueue_head(&intf->waitq); + for (i = 0; i < IPMI_NUM_STATS; i++) + atomic_set(&intf->stats[i], 0); - spin_lock_init(&intf->counter_lock); intf->proc_dir = NULL; mutex_lock(&smi_watchers_mutex); @@ -2717,11 +2817,12 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, get_guid(intf); if ((intf->ipmi_version_major > 1) - || ((intf->ipmi_version_major == 1) - && (intf->ipmi_version_minor >= 5))) - { - /* Start scanning the channels to see what is - available. */ + || ((intf->ipmi_version_major == 1) + && (intf->ipmi_version_minor >= 5))) { + /* + * Start scanning the channels to see what is + * available. + */ intf->null_user_handler = channel_handler; intf->curr_channel = 0; rv = send_channel_info_cmd(intf, 0); @@ -2769,6 +2870,7 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, return rv; } +EXPORT_SYMBOL(ipmi_register_smi); static void cleanup_smi_msgs(ipmi_smi_t intf) { @@ -2803,8 +2905,10 @@ int ipmi_unregister_smi(ipmi_smi_t intf) remove_proc_entries(intf); - /* Call all the watcher interfaces to tell them that - an interface is gone. */ + /* + * Call all the watcher interfaces to tell them that + * an interface is gone. + */ list_for_each_entry(w, &smi_watchers, link) w->smi_gone(intf_num); mutex_unlock(&smi_watchers_mutex); @@ -2812,22 +2916,21 @@ int ipmi_unregister_smi(ipmi_smi_t intf) kref_put(&intf->refcount, intf_free); return 0; } +EXPORT_SYMBOL(ipmi_unregister_smi); static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf, struct ipmi_smi_msg *msg) { struct ipmi_ipmb_addr ipmb_addr; struct ipmi_recv_msg *recv_msg; - unsigned long flags; - - /* This is 11, not 10, because the response must contain a - * completion code. */ + /* + * This is 11, not 10, because the response must contain a + * completion code. + */ if (msg->rsp_size < 11) { /* Message not big enough, just ignore it. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->invalid_ipmb_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, invalid_ipmb_responses); return 0; } @@ -2841,37 +2944,38 @@ static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf, ipmb_addr.channel = msg->rsp[3] & 0x0f; ipmb_addr.lun = msg->rsp[7] & 3; - /* It's a response from a remote entity. Look up the sequence - number and handle the response. */ + /* + * It's a response from a remote entity. Look up the sequence + * number and handle the response. + */ if (intf_find_seq(intf, msg->rsp[7] >> 2, msg->rsp[3] & 0x0f, msg->rsp[8], (msg->rsp[4] >> 2) & (~1), (struct ipmi_addr *) &(ipmb_addr), - &recv_msg)) - { - /* We were unable to find the sequence number, - so just nuke the message. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->unhandled_ipmb_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + &recv_msg)) { + /* + * We were unable to find the sequence number, + * so just nuke the message. + */ + ipmi_inc_stat(intf, unhandled_ipmb_responses); return 0; } memcpy(recv_msg->msg_data, &(msg->rsp[9]), msg->rsp_size - 9); - /* THe other fields matched, so no need to set them, except - for netfn, which needs to be the response that was - returned, not the request value. */ + /* + * The other fields matched, so no need to set them, except + * for netfn, which needs to be the response that was + * returned, not the request value. + */ recv_msg->msg.netfn = msg->rsp[4] >> 2; recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg.data_len = msg->rsp_size - 10; recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE; - spin_lock_irqsave(&intf->counter_lock, flags); - intf->handled_ipmb_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, handled_ipmb_responses); deliver_response(recv_msg); return 0; @@ -2888,14 +2992,11 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, ipmi_user_t user = NULL; struct ipmi_ipmb_addr *ipmb_addr; struct ipmi_recv_msg *recv_msg; - unsigned long flags; struct ipmi_smi_handlers *handlers; if (msg->rsp_size < 10) { /* Message not big enough, just ignore it. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, invalid_commands); return 0; } @@ -2919,19 +3020,17 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, if (user == NULL) { /* We didn't find a user, deliver an error response. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->unhandled_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, unhandled_commands); msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2); msg->data[1] = IPMI_SEND_MSG_CMD; msg->data[2] = msg->rsp[3]; msg->data[3] = msg->rsp[6]; - msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3); + msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3); msg->data[5] = ipmb_checksum(&(msg->data[3]), 2); msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address; - /* rqseq/lun */ - msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3); + /* rqseq/lun */ + msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3); msg->data[8] = msg->rsp[8]; /* cmd */ msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE; msg->data[10] = ipmb_checksum(&(msg->data[6]), 4); @@ -2950,23 +3049,25 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, handlers = intf->handlers; if (handlers) { handlers->sender(intf->send_info, msg, 0); - /* We used the message, so return the value - that causes it to not be freed or - queued. */ + /* + * We used the message, so return the value + * that causes it to not be freed or + * queued. + */ rv = -1; } rcu_read_unlock(); } else { /* Deliver the message to the user. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->handled_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, handled_commands); recv_msg = ipmi_alloc_recv_msg(); if (!recv_msg) { - /* We couldn't allocate memory for the - message, so requeue it for handling - later. */ + /* + * We couldn't allocate memory for the + * message, so requeue it for handling + * later. + */ rv = 1; kref_put(&user->refcount, free_user); } else { @@ -2977,8 +3078,10 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, ipmb_addr->lun = msg->rsp[7] & 3; ipmb_addr->channel = msg->rsp[3] & 0xf; - /* Extract the rest of the message information - from the IPMB header.*/ + /* + * Extract the rest of the message information + * from the IPMB header. + */ recv_msg->user = user; recv_msg->recv_type = IPMI_CMD_RECV_TYPE; recv_msg->msgid = msg->rsp[7] >> 2; @@ -2986,8 +3089,10 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf, recv_msg->msg.cmd = msg->rsp[8]; recv_msg->msg.data = recv_msg->msg_data; - /* We chop off 10, not 9 bytes because the checksum - at the end also needs to be removed. */ + /* + * We chop off 10, not 9 bytes because the checksum + * at the end also needs to be removed. + */ recv_msg->msg.data_len = msg->rsp_size - 10; memcpy(recv_msg->msg_data, &(msg->rsp[9]), @@ -3004,16 +3109,15 @@ static int handle_lan_get_msg_rsp(ipmi_smi_t intf, { struct ipmi_lan_addr lan_addr; struct ipmi_recv_msg *recv_msg; - unsigned long flags; - /* This is 13, not 12, because the response must contain a - * completion code. */ + /* + * This is 13, not 12, because the response must contain a + * completion code. + */ if (msg->rsp_size < 13) { /* Message not big enough, just ignore it. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->invalid_lan_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, invalid_lan_responses); return 0; } @@ -3030,37 +3134,38 @@ static int handle_lan_get_msg_rsp(ipmi_smi_t intf, lan_addr.privilege = msg->rsp[3] >> 4; lan_addr.lun = msg->rsp[9] & 3; - /* It's a response from a remote entity. Look up the sequence - number and handle the response. */ + /* + * It's a response from a remote entity. Look up the sequence + * number and handle the response. + */ if (intf_find_seq(intf, msg->rsp[9] >> 2, msg->rsp[3] & 0x0f, msg->rsp[10], (msg->rsp[6] >> 2) & (~1), (struct ipmi_addr *) &(lan_addr), - &recv_msg)) - { - /* We were unable to find the sequence number, - so just nuke the message. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->unhandled_lan_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + &recv_msg)) { + /* + * We were unable to find the sequence number, + * so just nuke the message. + */ + ipmi_inc_stat(intf, unhandled_lan_responses); return 0; } memcpy(recv_msg->msg_data, &(msg->rsp[11]), msg->rsp_size - 11); - /* The other fields matched, so no need to set them, except - for netfn, which needs to be the response that was - returned, not the request value. */ + /* + * The other fields matched, so no need to set them, except + * for netfn, which needs to be the response that was + * returned, not the request value. + */ recv_msg->msg.netfn = msg->rsp[6] >> 2; recv_msg->msg.data = recv_msg->msg_data; recv_msg->msg.data_len = msg->rsp_size - 12; recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE; - spin_lock_irqsave(&intf->counter_lock, flags); - intf->handled_lan_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, handled_lan_responses); deliver_response(recv_msg); return 0; @@ -3077,13 +3182,10 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf, ipmi_user_t user = NULL; struct ipmi_lan_addr *lan_addr; struct ipmi_recv_msg *recv_msg; - unsigned long flags; if (msg->rsp_size < 12) { /* Message not big enough, just ignore it. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->invalid_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, invalid_commands); return 0; } @@ -3107,23 +3209,23 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf, if (user == NULL) { /* We didn't find a user, just give up. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->unhandled_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, unhandled_commands); - rv = 0; /* Don't do anything with these messages, just - allow them to be freed. */ + /* + * Don't do anything with these messages, just allow + * them to be freed. + */ + rv = 0; } else { /* Deliver the message to the user. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->handled_commands++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, handled_commands); recv_msg = ipmi_alloc_recv_msg(); if (!recv_msg) { - /* We couldn't allocate memory for the - message, so requeue it for handling - later. */ + /* + * We couldn't allocate memory for the + * message, so requeue it for handling later. + */ rv = 1; kref_put(&user->refcount, free_user); } else { @@ -3137,8 +3239,10 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf, lan_addr->channel = msg->rsp[3] & 0xf; lan_addr->privilege = msg->rsp[3] >> 4; - /* Extract the rest of the message information - from the IPMB header.*/ + /* + * Extract the rest of the message information + * from the IPMB header. + */ recv_msg->user = user; recv_msg->recv_type = IPMI_CMD_RECV_TYPE; recv_msg->msgid = msg->rsp[9] >> 2; @@ -3146,8 +3250,10 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf, recv_msg->msg.cmd = msg->rsp[10]; recv_msg->msg.data = recv_msg->msg_data; - /* We chop off 12, not 11 bytes because the checksum - at the end also needs to be removed. */ + /* + * We chop off 12, not 11 bytes because the checksum + * at the end also needs to be removed. + */ recv_msg->msg.data_len = msg->rsp_size - 12; memcpy(recv_msg->msg_data, &(msg->rsp[11]), @@ -3163,7 +3269,7 @@ static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg, struct ipmi_smi_msg *msg) { struct ipmi_system_interface_addr *smi_addr; - + recv_msg->msgid = 0; smi_addr = (struct ipmi_system_interface_addr *) &(recv_msg->addr); smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; @@ -3189,9 +3295,7 @@ static int handle_read_event_rsp(ipmi_smi_t intf, if (msg->rsp_size < 19) { /* Message is too small to be an IPMB event. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->invalid_events++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, invalid_events); return 0; } @@ -3204,12 +3308,12 @@ static int handle_read_event_rsp(ipmi_smi_t intf, spin_lock_irqsave(&intf->events_lock, flags); - spin_lock(&intf->counter_lock); - intf->events++; - spin_unlock(&intf->counter_lock); + ipmi_inc_stat(intf, events); - /* Allocate and fill in one message for every user that is getting - events. */ + /* + * Allocate and fill in one message for every user that is + * getting events. + */ rcu_read_lock(); list_for_each_entry_rcu(user, &intf->users, link) { if (!user->gets_events) @@ -3223,9 +3327,11 @@ static int handle_read_event_rsp(ipmi_smi_t intf, list_del(&recv_msg->link); ipmi_free_recv_msg(recv_msg); } - /* We couldn't allocate memory for the - message, so requeue it for handling - later. */ + /* + * We couldn't allocate memory for the + * message, so requeue it for handling + * later. + */ rv = 1; goto out; } @@ -3246,13 +3352,17 @@ static int handle_read_event_rsp(ipmi_smi_t intf, deliver_response(recv_msg); } } else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) { - /* No one to receive the message, put it in queue if there's - not already too many things in the queue. */ + /* + * No one to receive the message, put it in queue if there's + * not already too many things in the queue. + */ recv_msg = ipmi_alloc_recv_msg(); if (!recv_msg) { - /* We couldn't allocate memory for the - message, so requeue it for handling - later. */ + /* + * We couldn't allocate memory for the + * message, so requeue it for handling + * later. + */ rv = 1; goto out; } @@ -3260,11 +3370,14 @@ static int handle_read_event_rsp(ipmi_smi_t intf, copy_event_into_recv_msg(recv_msg, msg); list_add_tail(&(recv_msg->link), &(intf->waiting_events)); intf->waiting_events_count++; - } else { - /* There's too many things in the queue, discard this - message. */ - printk(KERN_WARNING PFX "Event queue full, discarding an" - " incoming event\n"); + } else if (!intf->event_msg_printed) { + /* + * There's too many things in the queue, discard this + * message. + */ + printk(KERN_WARNING PFX "Event queue full, discarding" + " incoming events\n"); + intf->event_msg_printed = 1; } out: @@ -3277,16 +3390,15 @@ static int handle_bmc_rsp(ipmi_smi_t intf, struct ipmi_smi_msg *msg) { struct ipmi_recv_msg *recv_msg; - unsigned long flags; struct ipmi_user *user; recv_msg = (struct ipmi_recv_msg *) msg->user_data; - if (recv_msg == NULL) - { - printk(KERN_WARNING"IPMI message received with no owner. This\n" - "could be because of a malformed message, or\n" - "because of a hardware error. Contact your\n" - "hardware vender for assistance\n"); + if (recv_msg == NULL) { + printk(KERN_WARNING + "IPMI message received with no owner. This\n" + "could be because of a malformed message, or\n" + "because of a hardware error. Contact your\n" + "hardware vender for assistance\n"); return 0; } @@ -3294,16 +3406,12 @@ static int handle_bmc_rsp(ipmi_smi_t intf, /* Make sure the user still exists. */ if (user && !user->valid) { /* The user for the message went away, so give up. */ - spin_lock_irqsave(&intf->counter_lock, flags); - intf->unhandled_local_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, unhandled_local_responses); ipmi_free_recv_msg(recv_msg); } else { struct ipmi_system_interface_addr *smi_addr; - spin_lock_irqsave(&intf->counter_lock, flags); - intf->handled_local_responses++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, handled_local_responses); recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE; recv_msg->msgid = msg->msgid; smi_addr = ((struct ipmi_system_interface_addr *) @@ -3324,9 +3432,11 @@ static int handle_bmc_rsp(ipmi_smi_t intf, return 0; } -/* Handle a new message. Return 1 if the message should be requeued, - 0 if the message should be freed, or -1 if the message should not - be freed or requeued. */ +/* + * Handle a new message. Return 1 if the message should be requeued, + * 0 if the message should be freed, or -1 if the message should not + * be freed or requeued. + */ static int handle_new_recv_msg(ipmi_smi_t intf, struct ipmi_smi_msg *msg) { @@ -3351,10 +3461,12 @@ static int handle_new_recv_msg(ipmi_smi_t intf, msg->rsp[1] = msg->data[1]; msg->rsp[2] = IPMI_ERR_UNSPECIFIED; msg->rsp_size = 3; - } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))/* Netfn */ - || (msg->rsp[1] != msg->data[1])) /* Command */ - { - /* The response is not even marginally correct. */ + } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1)) + || (msg->rsp[1] != msg->data[1])) { + /* + * The NetFN and Command in the response is not even + * marginally correct. + */ printk(KERN_WARNING PFX "BMC returned incorrect response," " expected netfn %x cmd %x, got netfn %x cmd %x\n", (msg->data[0] >> 2) | 1, msg->data[1], @@ -3369,10 +3481,11 @@ static int handle_new_recv_msg(ipmi_smi_t intf, if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2)) && (msg->rsp[1] == IPMI_SEND_MSG_CMD) - && (msg->user_data != NULL)) - { - /* It's a response to a response we sent. For this we - deliver a send message response to the user. */ + && (msg->user_data != NULL)) { + /* + * It's a response to a response we sent. For this we + * deliver a send message response to the user. + */ struct ipmi_recv_msg *recv_msg = msg->user_data; requeue = 0; @@ -3398,8 +3511,7 @@ static int handle_new_recv_msg(ipmi_smi_t intf, recv_msg->msg_data[0] = msg->rsp[2]; deliver_response(recv_msg); } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2)) - && (msg->rsp[1] == IPMI_GET_MSG_CMD)) - { + && (msg->rsp[1] == IPMI_GET_MSG_CMD)) { /* It's from the receive queue. */ chan = msg->rsp[3] & 0xf; if (chan >= IPMI_MAX_CHANNELS) { @@ -3411,12 +3523,16 @@ static int handle_new_recv_msg(ipmi_smi_t intf, switch (intf->channels[chan].medium) { case IPMI_CHANNEL_MEDIUM_IPMB: if (msg->rsp[4] & 0x04) { - /* It's a response, so find the - requesting message and send it up. */ + /* + * It's a response, so find the + * requesting message and send it up. + */ requeue = handle_ipmb_get_msg_rsp(intf, msg); } else { - /* It's a command to the SMS from some other - entity. Handle that. */ + /* + * It's a command to the SMS from some other + * entity. Handle that. + */ requeue = handle_ipmb_get_msg_cmd(intf, msg); } break; @@ -3424,25 +3540,30 @@ static int handle_new_recv_msg(ipmi_smi_t intf, case IPMI_CHANNEL_MEDIUM_8023LAN: case IPMI_CHANNEL_MEDIUM_ASYNC: if (msg->rsp[6] & 0x04) { - /* It's a response, so find the - requesting message and send it up. */ + /* + * It's a response, so find the + * requesting message and send it up. + */ requeue = handle_lan_get_msg_rsp(intf, msg); } else { - /* It's a command to the SMS from some other - entity. Handle that. */ + /* + * It's a command to the SMS from some other + * entity. Handle that. + */ requeue = handle_lan_get_msg_cmd(intf, msg); } break; default: - /* We don't handle the channel type, so just - * free the message. */ + /* + * We don't handle the channel type, so just + * free the message. + */ requeue = 0; } } else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2)) - && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD)) - { + && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD)) { /* It's an asyncronous event. */ requeue = handle_read_event_rsp(intf, msg); } else { @@ -3458,71 +3579,82 @@ static int handle_new_recv_msg(ipmi_smi_t intf, void ipmi_smi_msg_received(ipmi_smi_t intf, struct ipmi_smi_msg *msg) { - unsigned long flags; + unsigned long flags = 0; /* keep us warning-free. */ int rv; + int run_to_completion; if ((msg->data_size >= 2) && (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2)) && (msg->data[1] == IPMI_SEND_MSG_CMD) - && (msg->user_data == NULL)) - { - /* This is the local response to a command send, start - the timer for these. The user_data will not be - NULL if this is a response send, and we will let - response sends just go through. */ - - /* Check for errors, if we get certain errors (ones - that mean basically we can try again later), we - ignore them and start the timer. Otherwise we - report the error immediately. */ + && (msg->user_data == NULL)) { + /* + * This is the local response to a command send, start + * the timer for these. The user_data will not be + * NULL if this is a response send, and we will let + * response sends just go through. + */ + + /* + * Check for errors, if we get certain errors (ones + * that mean basically we can try again later), we + * ignore them and start the timer. Otherwise we + * report the error immediately. + */ if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0) && (msg->rsp[2] != IPMI_NODE_BUSY_ERR) && (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR) && (msg->rsp[2] != IPMI_BUS_ERR) - && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR)) - { + && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR)) { int chan = msg->rsp[3] & 0xf; /* Got an error sending the message, handle it. */ - spin_lock_irqsave(&intf->counter_lock, flags); if (chan >= IPMI_MAX_CHANNELS) ; /* This shouldn't happen */ else if ((intf->channels[chan].medium == IPMI_CHANNEL_MEDIUM_8023LAN) || (intf->channels[chan].medium == IPMI_CHANNEL_MEDIUM_ASYNC)) - intf->sent_lan_command_errs++; + ipmi_inc_stat(intf, sent_lan_command_errs); else - intf->sent_ipmb_command_errs++; - spin_unlock_irqrestore(&intf->counter_lock, flags); + ipmi_inc_stat(intf, sent_ipmb_command_errs); intf_err_seq(intf, msg->msgid, msg->rsp[2]); - } else { + } else /* The message was sent, start the timer. */ intf_start_seq_timer(intf, msg->msgid); - } ipmi_free_smi_msg(msg); goto out; } - /* To preserve message order, if the list is not empty, we - tack this message onto the end of the list. */ - spin_lock_irqsave(&intf->waiting_msgs_lock, flags); + /* + * To preserve message order, if the list is not empty, we + * tack this message onto the end of the list. + */ + run_to_completion = intf->run_to_completion; + if (!run_to_completion) + spin_lock_irqsave(&intf->waiting_msgs_lock, flags); if (!list_empty(&intf->waiting_msgs)) { list_add_tail(&msg->link, &intf->waiting_msgs); - spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); + if (!run_to_completion) + spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); goto out; } - spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); - + if (!run_to_completion) + spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); + rv = handle_new_recv_msg(intf, msg); if (rv > 0) { - /* Could not handle the message now, just add it to a - list to handle later. */ - spin_lock_irqsave(&intf->waiting_msgs_lock, flags); + /* + * Could not handle the message now, just add it to a + * list to handle later. + */ + run_to_completion = intf->run_to_completion; + if (!run_to_completion) + spin_lock_irqsave(&intf->waiting_msgs_lock, flags); list_add_tail(&msg->link, &intf->waiting_msgs); - spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); + if (!run_to_completion) + spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); } else if (rv == 0) { ipmi_free_smi_msg(msg); } @@ -3530,6 +3662,7 @@ void ipmi_smi_msg_received(ipmi_smi_t intf, out: return; } +EXPORT_SYMBOL(ipmi_smi_msg_received); void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf) { @@ -3544,7 +3677,7 @@ void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf) } rcu_read_unlock(); } - +EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout); static struct ipmi_smi_msg * smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, @@ -3552,14 +3685,16 @@ smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg, { struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg(); if (!smi_msg) - /* If we can't allocate the message, then just return, we - get 4 retries, so this should be ok. */ + /* + * If we can't allocate the message, then just return, we + * get 4 retries, so this should be ok. + */ return NULL; memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len); smi_msg->data_size = recv_msg->msg.data_len; smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid); - + #ifdef DEBUG_MSGING { int m; @@ -3594,28 +3729,26 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, ent->inuse = 0; msg = ent->recv_msg; list_add_tail(&msg->link, timeouts); - spin_lock(&intf->counter_lock); if (ent->broadcast) - intf->timed_out_ipmb_broadcasts++; + ipmi_inc_stat(intf, timed_out_ipmb_broadcasts); else if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE) - intf->timed_out_lan_commands++; + ipmi_inc_stat(intf, timed_out_lan_commands); else - intf->timed_out_ipmb_commands++; - spin_unlock(&intf->counter_lock); + ipmi_inc_stat(intf, timed_out_ipmb_commands); } else { struct ipmi_smi_msg *smi_msg; /* More retries, send again. */ - /* Start with the max timer, set to normal - timer after the message is sent. */ + /* + * Start with the max timer, set to normal timer after + * the message is sent. + */ ent->timeout = MAX_MSG_TIMEOUT; ent->retries_left--; - spin_lock(&intf->counter_lock); if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE) - intf->retransmitted_lan_commands++; + ipmi_inc_stat(intf, retransmitted_lan_commands); else - intf->retransmitted_ipmb_commands++; - spin_unlock(&intf->counter_lock); + ipmi_inc_stat(intf, retransmitted_ipmb_commands); smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot, ent->seqid); @@ -3624,11 +3757,13 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, spin_unlock_irqrestore(&intf->seq_lock, *flags); - /* Send the new message. We send with a zero - * priority. It timed out, I doubt time is - * that critical now, and high priority - * messages are really only for messages to the - * local MC, which don't get resent. */ + /* + * Send the new message. We send with a zero + * priority. It timed out, I doubt time is that + * critical now, and high priority messages are really + * only for messages to the local MC, which don't get + * resent. + */ handlers = intf->handlers; if (handlers) intf->handlers->sender(intf->send_info, @@ -3659,16 +3794,20 @@ static void ipmi_timeout_handler(long timeout_period) list_del(&smi_msg->link); ipmi_free_smi_msg(smi_msg); } else { - /* To preserve message order, quit if we - can't handle a message. */ + /* + * To preserve message order, quit if we + * can't handle a message. + */ break; } } spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags); - /* Go through the seq table and find any messages that - have timed out, putting them in the timeouts - list. */ + /* + * Go through the seq table and find any messages that + * have timed out, putting them in the timeouts + * list. + */ INIT_LIST_HEAD(&timeouts); spin_lock_irqsave(&intf->seq_lock, flags); for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) @@ -3694,8 +3833,7 @@ static void ipmi_timeout_handler(long timeout_period) intf->auto_maintenance_timeout -= timeout_period; if (!intf->maintenance_mode - && (intf->auto_maintenance_timeout <= 0)) - { + && (intf->auto_maintenance_timeout <= 0)) { intf->maintenance_mode_enable = 0; maintenance_mode_update(intf); } @@ -3713,8 +3851,10 @@ static void ipmi_request_event(void) struct ipmi_smi_handlers *handlers; rcu_read_lock(); - /* Called from the timer, no need to check if handlers is - * valid. */ + /* + * Called from the timer, no need to check if handlers is + * valid. + */ list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { /* No event requests when in maintenance mode. */ if (intf->maintenance_mode_enable) @@ -3735,10 +3875,12 @@ static struct timer_list ipmi_timer; /* How many jiffies does it take to get to the timeout time. */ #define IPMI_TIMEOUT_JIFFIES ((IPMI_TIMEOUT_TIME * HZ) / 1000) -/* Request events from the queue every second (this is the number of - IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the - future, IPMI will add a way to know immediately if an event is in - the queue and this silliness can go away. */ +/* + * Request events from the queue every second (this is the number of + * IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the + * future, IPMI will add a way to know immediately if an event is in + * the queue and this silliness can go away. + */ #define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME)) static atomic_t stop_operation; @@ -3782,6 +3924,7 @@ struct ipmi_smi_msg *ipmi_alloc_smi_msg(void) } return rv; } +EXPORT_SYMBOL(ipmi_alloc_smi_msg); static void free_recv_msg(struct ipmi_recv_msg *msg) { @@ -3789,7 +3932,7 @@ static void free_recv_msg(struct ipmi_recv_msg *msg) kfree(msg); } -struct ipmi_recv_msg *ipmi_alloc_recv_msg(void) +static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void) { struct ipmi_recv_msg *rv; @@ -3808,6 +3951,7 @@ void ipmi_free_recv_msg(struct ipmi_recv_msg *msg) kref_put(&msg->user->refcount, free_user); msg->done(msg); } +EXPORT_SYMBOL(ipmi_free_recv_msg); #ifdef CONFIG_IPMI_PANIC_EVENT @@ -3825,8 +3969,7 @@ static void event_receiver_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg) if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) && (msg->msg.netfn == IPMI_NETFN_SENSOR_EVENT_RESPONSE) && (msg->msg.cmd == IPMI_GET_EVENT_RECEIVER_CMD) - && (msg->msg.data[0] == IPMI_CC_NO_ERROR)) - { + && (msg->msg.data[0] == IPMI_CC_NO_ERROR)) { /* A get event receiver command, save it. */ intf->event_receiver = msg->msg.data[1]; intf->event_receiver_lun = msg->msg.data[2] & 0x3; @@ -3838,10 +3981,11 @@ static void device_id_fetcher(ipmi_smi_t intf, struct ipmi_recv_msg *msg) if ((msg->addr.addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) && (msg->msg.netfn == IPMI_NETFN_APP_RESPONSE) && (msg->msg.cmd == IPMI_GET_DEVICE_ID_CMD) - && (msg->msg.data[0] == IPMI_CC_NO_ERROR)) - { - /* A get device id command, save if we are an event - receiver or generator. */ + && (msg->msg.data[0] == IPMI_CC_NO_ERROR)) { + /* + * A get device id command, save if we are an event + * receiver or generator. + */ intf->local_sel_device = (msg->msg.data[6] >> 2) & 1; intf->local_event_generator = (msg->msg.data[6] >> 5) & 1; } @@ -3874,8 +4018,10 @@ static void send_panic_events(char *str) data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */ data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */ - /* Put a few breadcrumbs in. Hopefully later we can add more things - to make the panic events more useful. */ + /* + * Put a few breadcrumbs in. Hopefully later we can add more things + * to make the panic events more useful. + */ if (str) { data[3] = str[0]; data[6] = str[1]; @@ -3891,6 +4037,7 @@ static void send_panic_events(char *str) /* Interface is not ready. */ continue; + intf->run_to_completion = 1; /* Send the event announcing the panic. */ intf->handlers->set_run_to_completion(intf->send_info, 1); i_ipmi_request(NULL, @@ -3908,9 +4055,11 @@ static void send_panic_events(char *str) } #ifdef CONFIG_IPMI_PANIC_STRING - /* On every interface, dump a bunch of OEM event holding the - string. */ - if (!str) + /* + * On every interface, dump a bunch of OEM event holding the + * string. + */ + if (!str) return; /* For every registered interface, send the event. */ @@ -3931,11 +4080,13 @@ static void send_panic_events(char *str) */ smp_rmb(); - /* First job here is to figure out where to send the - OEM events. There's no way in IPMI to send OEM - events using an event send command, so we have to - find the SEL to put them in and stick them in - there. */ + /* + * First job here is to figure out where to send the + * OEM events. There's no way in IPMI to send OEM + * events using an event send command, so we have to + * find the SEL to put them in and stick them in + * there. + */ /* Get capabilities from the get device id. */ intf->local_sel_device = 0; @@ -3983,24 +4134,29 @@ static void send_panic_events(char *str) } intf->null_user_handler = NULL; - /* Validate the event receiver. The low bit must not - be 1 (it must be a valid IPMB address), it cannot - be zero, and it must not be my address. */ - if (((intf->event_receiver & 1) == 0) + /* + * Validate the event receiver. The low bit must not + * be 1 (it must be a valid IPMB address), it cannot + * be zero, and it must not be my address. + */ + if (((intf->event_receiver & 1) == 0) && (intf->event_receiver != 0) - && (intf->event_receiver != intf->channels[0].address)) - { - /* The event receiver is valid, send an IPMB - message. */ + && (intf->event_receiver != intf->channels[0].address)) { + /* + * The event receiver is valid, send an IPMB + * message. + */ ipmb = (struct ipmi_ipmb_addr *) &addr; ipmb->addr_type = IPMI_IPMB_ADDR_TYPE; ipmb->channel = 0; /* FIXME - is this right? */ ipmb->lun = intf->event_receiver_lun; ipmb->slave_addr = intf->event_receiver; } else if (intf->local_sel_device) { - /* The event receiver was not valid (or was - me), but I am an SEL device, just dump it - in my SEL. */ + /* + * The event receiver was not valid (or was + * me), but I am an SEL device, just dump it + * in my SEL. + */ si = (struct ipmi_system_interface_addr *) &addr; si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; si->channel = IPMI_BMC_CHANNEL; @@ -4008,7 +4164,6 @@ static void send_panic_events(char *str) } else continue; /* No where to send the event. */ - msg.netfn = IPMI_NETFN_STORAGE_REQUEST; /* Storage. */ msg.cmd = IPMI_ADD_SEL_ENTRY_CMD; msg.data = data; @@ -4025,8 +4180,10 @@ static void send_panic_events(char *str) data[2] = 0xf0; /* OEM event without timestamp. */ data[3] = intf->channels[0].address; data[4] = j++; /* sequence # */ - /* Always give 11 bytes, so strncpy will fill - it with zeroes for me. */ + /* + * Always give 11 bytes, so strncpy will fill + * it with zeroes for me. + */ strncpy(data+5, p, 11); p += size; @@ -4043,7 +4200,7 @@ static void send_panic_events(char *str) intf->channels[0].lun, 0, 1); /* no retry, and no wait. */ } - } + } #endif /* CONFIG_IPMI_PANIC_STRING */ } #endif /* CONFIG_IPMI_PANIC_EVENT */ @@ -4052,7 +4209,7 @@ static int has_panicked; static int panic_event(struct notifier_block *this, unsigned long event, - void *ptr) + void *ptr) { ipmi_smi_t intf; @@ -4066,6 +4223,7 @@ static int panic_event(struct notifier_block *this, /* Interface is not ready. */ continue; + intf->run_to_completion = 1; intf->handlers->set_run_to_completion(intf->send_info, 1); } @@ -4133,11 +4291,16 @@ static __exit void cleanup_ipmi(void) atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block); - /* This can't be called if any interfaces exist, so no worry about - shutting down the interfaces. */ + /* + * This can't be called if any interfaces exist, so no worry + * about shutting down the interfaces. + */ - /* Tell the timer to stop, then wait for it to stop. This avoids - problems with race conditions removing the timer here. */ + /* + * Tell the timer to stop, then wait for it to stop. This + * avoids problems with race conditions removing the timer + * here. + */ atomic_inc(&stop_operation); del_timer_sync(&ipmi_timer); @@ -4164,31 +4327,6 @@ module_exit(cleanup_ipmi); module_init(ipmi_init_msghandler_mod); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>"); -MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI interface."); +MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI" + " interface."); MODULE_VERSION(IPMI_DRIVER_VERSION); - -EXPORT_SYMBOL(ipmi_create_user); -EXPORT_SYMBOL(ipmi_destroy_user); -EXPORT_SYMBOL(ipmi_get_version); -EXPORT_SYMBOL(ipmi_request_settime); -EXPORT_SYMBOL(ipmi_request_supply_msgs); -EXPORT_SYMBOL(ipmi_poll_interface); -EXPORT_SYMBOL(ipmi_register_smi); -EXPORT_SYMBOL(ipmi_unregister_smi); -EXPORT_SYMBOL(ipmi_register_for_cmd); -EXPORT_SYMBOL(ipmi_unregister_for_cmd); -EXPORT_SYMBOL(ipmi_smi_msg_received); -EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout); -EXPORT_SYMBOL(ipmi_alloc_smi_msg); -EXPORT_SYMBOL(ipmi_addr_length); -EXPORT_SYMBOL(ipmi_validate_addr); -EXPORT_SYMBOL(ipmi_set_gets_events); -EXPORT_SYMBOL(ipmi_smi_watcher_register); -EXPORT_SYMBOL(ipmi_smi_watcher_unregister); -EXPORT_SYMBOL(ipmi_set_my_address); -EXPORT_SYMBOL(ipmi_get_my_address); -EXPORT_SYMBOL(ipmi_set_my_LUN); -EXPORT_SYMBOL(ipmi_get_my_LUN); -EXPORT_SYMBOL(ipmi_smi_add_proc_entry); -EXPORT_SYMBOL(ipmi_user_set_run_to_completion); -EXPORT_SYMBOL(ipmi_free_recv_msg); diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c index b86186de7f07..a261bd735dfb 100644 --- a/drivers/char/ipmi/ipmi_poweroff.c +++ b/drivers/char/ipmi/ipmi_poweroff.c @@ -87,7 +87,10 @@ MODULE_PARM_DESC(ifnum_to_use, "The interface number to use for the watchdog " /* parameter definition to allow user to flag power cycle */ module_param(poweroff_powercycle, int, 0644); -MODULE_PARM_DESC(poweroff_powercycle, " Set to non-zero to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down."); +MODULE_PARM_DESC(poweroff_powercycle, + " Set to non-zero to enable power cycle instead of power" + " down. Power cycle is contingent on hardware support," + " otherwise it defaults back to power down."); /* Stuff from the get device id command. */ static unsigned int mfg_id; @@ -95,22 +98,25 @@ static unsigned int prod_id; static unsigned char capabilities; static unsigned char ipmi_version; -/* We use our own messages for this operation, we don't let the system - allocate them, since we may be in a panic situation. The whole - thing is single-threaded, anyway, so multiple messages are not - required. */ +/* + * We use our own messages for this operation, we don't let the system + * allocate them, since we may be in a panic situation. The whole + * thing is single-threaded, anyway, so multiple messages are not + * required. + */ +static atomic_t dummy_count = ATOMIC_INIT(0); static void dummy_smi_free(struct ipmi_smi_msg *msg) { + atomic_dec(&dummy_count); } static void dummy_recv_free(struct ipmi_recv_msg *msg) { + atomic_dec(&dummy_count); } -static struct ipmi_smi_msg halt_smi_msg = -{ +static struct ipmi_smi_msg halt_smi_msg = { .done = dummy_smi_free }; -static struct ipmi_recv_msg halt_recv_msg = -{ +static struct ipmi_recv_msg halt_recv_msg = { .done = dummy_recv_free }; @@ -127,8 +133,7 @@ static void receive_handler(struct ipmi_recv_msg *recv_msg, void *handler_data) complete(comp); } -static struct ipmi_user_hndl ipmi_poweroff_handler = -{ +static struct ipmi_user_hndl ipmi_poweroff_handler = { .ipmi_recv_hndl = receive_handler }; @@ -152,17 +157,28 @@ static int ipmi_request_wait_for_response(ipmi_user_t user, return halt_recv_msg.msg.data[0]; } -/* We are in run-to-completion mode, no completion is desired. */ +/* Wait for message to complete, spinning. */ static int ipmi_request_in_rc_mode(ipmi_user_t user, struct ipmi_addr *addr, struct kernel_ipmi_msg *send_msg) { int rv; + atomic_set(&dummy_count, 2); rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, NULL, &halt_smi_msg, &halt_recv_msg, 0); - if (rv) + if (rv) { + atomic_set(&dummy_count, 0); return rv; + } + + /* + * Spin until our message is done. + */ + while (atomic_read(&dummy_count) > 0) { + ipmi_poll_interface(user); + cpu_relax(); + } return halt_recv_msg.msg.data[0]; } @@ -184,47 +200,47 @@ static int ipmi_request_in_rc_mode(ipmi_user_t user, static void (*atca_oem_poweroff_hook)(ipmi_user_t user); -static void pps_poweroff_atca (ipmi_user_t user) +static void pps_poweroff_atca(ipmi_user_t user) { - struct ipmi_system_interface_addr smi_addr; - struct kernel_ipmi_msg send_msg; - int rv; - /* - * Configure IPMI address for local access - */ - smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - smi_addr.channel = IPMI_BMC_CHANNEL; - smi_addr.lun = 0; - - printk(KERN_INFO PFX "PPS powerdown hook used"); - - send_msg.netfn = IPMI_NETFN_OEM; - send_msg.cmd = IPMI_ATCA_PPS_GRACEFUL_RESTART; - send_msg.data = IPMI_ATCA_PPS_IANA; - send_msg.data_len = 3; - rv = ipmi_request_in_rc_mode(user, - (struct ipmi_addr *) &smi_addr, - &send_msg); - if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) { - printk(KERN_ERR PFX "Unable to send ATCA ," - " IPMI error 0x%x\n", rv); - } + struct ipmi_system_interface_addr smi_addr; + struct kernel_ipmi_msg send_msg; + int rv; + /* + * Configure IPMI address for local access + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; + + printk(KERN_INFO PFX "PPS powerdown hook used"); + + send_msg.netfn = IPMI_NETFN_OEM; + send_msg.cmd = IPMI_ATCA_PPS_GRACEFUL_RESTART; + send_msg.data = IPMI_ATCA_PPS_IANA; + send_msg.data_len = 3; + rv = ipmi_request_in_rc_mode(user, + (struct ipmi_addr *) &smi_addr, + &send_msg); + if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) { + printk(KERN_ERR PFX "Unable to send ATCA ," + " IPMI error 0x%x\n", rv); + } return; } -static int ipmi_atca_detect (ipmi_user_t user) +static int ipmi_atca_detect(ipmi_user_t user) { struct ipmi_system_interface_addr smi_addr; struct kernel_ipmi_msg send_msg; int rv; unsigned char data[1]; - /* - * Configure IPMI address for local access - */ - smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - smi_addr.channel = IPMI_BMC_CHANNEL; - smi_addr.lun = 0; + /* + * Configure IPMI address for local access + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; /* * Use get address info to check and see if we are ATCA @@ -238,28 +254,30 @@ static int ipmi_atca_detect (ipmi_user_t user) (struct ipmi_addr *) &smi_addr, &send_msg); - printk(KERN_INFO PFX "ATCA Detect mfg 0x%X prod 0x%X\n", mfg_id, prod_id); - if((mfg_id == IPMI_MOTOROLA_MANUFACTURER_ID) - && (prod_id == IPMI_MOTOROLA_PPS_IPMC_PRODUCT_ID)) { - printk(KERN_INFO PFX "Installing Pigeon Point Systems Poweroff Hook\n"); + printk(KERN_INFO PFX "ATCA Detect mfg 0x%X prod 0x%X\n", + mfg_id, prod_id); + if ((mfg_id == IPMI_MOTOROLA_MANUFACTURER_ID) + && (prod_id == IPMI_MOTOROLA_PPS_IPMC_PRODUCT_ID)) { + printk(KERN_INFO PFX + "Installing Pigeon Point Systems Poweroff Hook\n"); atca_oem_poweroff_hook = pps_poweroff_atca; } return !rv; } -static void ipmi_poweroff_atca (ipmi_user_t user) +static void ipmi_poweroff_atca(ipmi_user_t user) { struct ipmi_system_interface_addr smi_addr; struct kernel_ipmi_msg send_msg; int rv; unsigned char data[4]; - /* - * Configure IPMI address for local access - */ - smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - smi_addr.channel = IPMI_BMC_CHANNEL; - smi_addr.lun = 0; + /* + * Configure IPMI address for local access + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; printk(KERN_INFO PFX "Powering down via ATCA power command\n"); @@ -273,23 +291,24 @@ static void ipmi_poweroff_atca (ipmi_user_t user) data[2] = 0; /* Power Level */ data[3] = 0; /* Don't change saved presets */ send_msg.data = data; - send_msg.data_len = sizeof (data); + send_msg.data_len = sizeof(data); rv = ipmi_request_in_rc_mode(user, (struct ipmi_addr *) &smi_addr, &send_msg); - /** At this point, the system may be shutting down, and most - ** serial drivers (if used) will have interrupts turned off - ** it may be better to ignore IPMI_UNKNOWN_ERR_COMPLETION_CODE - ** return code - **/ - if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) { + /* + * At this point, the system may be shutting down, and most + * serial drivers (if used) will have interrupts turned off + * it may be better to ignore IPMI_UNKNOWN_ERR_COMPLETION_CODE + * return code + */ + if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) { printk(KERN_ERR PFX "Unable to send ATCA powerdown message," " IPMI error 0x%x\n", rv); goto out; } - if(atca_oem_poweroff_hook) - return atca_oem_poweroff_hook(user); + if (atca_oem_poweroff_hook) + atca_oem_poweroff_hook(user); out: return; } @@ -310,13 +329,13 @@ static void ipmi_poweroff_atca (ipmi_user_t user) #define IPMI_CPI1_PRODUCT_ID 0x000157 #define IPMI_CPI1_MANUFACTURER_ID 0x0108 -static int ipmi_cpi1_detect (ipmi_user_t user) +static int ipmi_cpi1_detect(ipmi_user_t user) { return ((mfg_id == IPMI_CPI1_MANUFACTURER_ID) && (prod_id == IPMI_CPI1_PRODUCT_ID)); } -static void ipmi_poweroff_cpi1 (ipmi_user_t user) +static void ipmi_poweroff_cpi1(ipmi_user_t user) { struct ipmi_system_interface_addr smi_addr; struct ipmi_ipmb_addr ipmb_addr; @@ -328,12 +347,12 @@ static void ipmi_poweroff_cpi1 (ipmi_user_t user) unsigned char aer_addr; unsigned char aer_lun; - /* - * Configure IPMI address for local access - */ - smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - smi_addr.channel = IPMI_BMC_CHANNEL; - smi_addr.lun = 0; + /* + * Configure IPMI address for local access + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; printk(KERN_INFO PFX "Powering down via CPI1 power command\n"); @@ -425,7 +444,7 @@ static void ipmi_poweroff_cpi1 (ipmi_user_t user) */ #define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00} -static int ipmi_dell_chassis_detect (ipmi_user_t user) +static int ipmi_dell_chassis_detect(ipmi_user_t user) { const char ipmi_version_major = ipmi_version & 0xF; const char ipmi_version_minor = (ipmi_version >> 4) & 0xF; @@ -444,25 +463,25 @@ static int ipmi_dell_chassis_detect (ipmi_user_t user) #define IPMI_NETFN_CHASSIS_REQUEST 0 #define IPMI_CHASSIS_CONTROL_CMD 0x02 -static int ipmi_chassis_detect (ipmi_user_t user) +static int ipmi_chassis_detect(ipmi_user_t user) { /* Chassis support, use it. */ return (capabilities & 0x80); } -static void ipmi_poweroff_chassis (ipmi_user_t user) +static void ipmi_poweroff_chassis(ipmi_user_t user) { struct ipmi_system_interface_addr smi_addr; struct kernel_ipmi_msg send_msg; int rv; unsigned char data[1]; - /* - * Configure IPMI address for local access - */ - smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - smi_addr.channel = IPMI_BMC_CHANNEL; - smi_addr.lun = 0; + /* + * Configure IPMI address for local access + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; powercyclefailed: printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n", @@ -525,15 +544,13 @@ static struct poweroff_function poweroff_functions[] = { /* Called on a powerdown request. */ -static void ipmi_poweroff_function (void) +static void ipmi_poweroff_function(void) { if (!ready) return; /* Use run-to-completion mode, since interrupts may be off. */ - ipmi_user_set_run_to_completion(ipmi_user, 1); specific_poweroff_func(ipmi_user); - ipmi_user_set_run_to_completion(ipmi_user, 0); } /* Wait for an IPMI interface to be installed, the first one installed @@ -561,13 +578,13 @@ static void ipmi_po_new_smi(int if_num, struct device *device) ipmi_ifnum = if_num; - /* - * Do a get device ide and store some results, since this is + /* + * Do a get device ide and store some results, since this is * used by several functions. - */ - smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; - smi_addr.channel = IPMI_BMC_CHANNEL; - smi_addr.lun = 0; + */ + smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + smi_addr.channel = IPMI_BMC_CHANNEL; + smi_addr.lun = 0; send_msg.netfn = IPMI_NETFN_APP_REQUEST; send_msg.cmd = IPMI_GET_DEVICE_ID_CMD; @@ -632,8 +649,7 @@ static void ipmi_po_smi_gone(int if_num) pm_power_off = old_poweroff_func; } -static struct ipmi_smi_watcher smi_watcher = -{ +static struct ipmi_smi_watcher smi_watcher = { .owner = THIS_MODULE, .new_smi = ipmi_po_new_smi, .smi_gone = ipmi_po_smi_gone @@ -675,12 +691,12 @@ static struct ctl_table_header *ipmi_table_header; /* * Startup and shutdown functions. */ -static int ipmi_poweroff_init (void) +static int ipmi_poweroff_init(void) { int rv; - printk (KERN_INFO "Copyright (C) 2004 MontaVista Software -" - " IPMI Powerdown via sys_reboot.\n"); + printk(KERN_INFO "Copyright (C) 2004 MontaVista Software -" + " IPMI Powerdown via sys_reboot.\n"); if (poweroff_powercycle) printk(KERN_INFO PFX "Power cycle is enabled.\n"); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 4f560d0bb808..5a5455585c1d 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -80,7 +80,7 @@ #define SI_USEC_PER_JIFFY (1000000/HZ) #define SI_TIMEOUT_JIFFIES (SI_TIMEOUT_TIME_USEC/SI_USEC_PER_JIFFY) #define SI_SHORT_TIMEOUT_USEC 250 /* .25ms when the SM request a - short timeout */ + short timeout */ /* Bit for BMC global enables. */ #define IPMI_BMC_RCV_MSG_INTR 0x01 @@ -114,14 +114,61 @@ static char *si_to_str[] = { "kcs", "smic", "bt" }; #define DEVICE_NAME "ipmi_si" -static struct device_driver ipmi_driver = -{ +static struct device_driver ipmi_driver = { .name = DEVICE_NAME, .bus = &platform_bus_type }; -struct smi_info -{ + +/* + * Indexes into stats[] in smi_info below. + */ +enum si_stat_indexes { + /* + * Number of times the driver requested a timer while an operation + * was in progress. + */ + SI_STAT_short_timeouts = 0, + + /* + * Number of times the driver requested a timer while nothing was in + * progress. + */ + SI_STAT_long_timeouts, + + /* Number of times the interface was idle while being polled. */ + SI_STAT_idles, + + /* Number of interrupts the driver handled. */ + SI_STAT_interrupts, + + /* Number of time the driver got an ATTN from the hardware. */ + SI_STAT_attentions, + + /* Number of times the driver requested flags from the hardware. */ + SI_STAT_flag_fetches, + + /* Number of times the hardware didn't follow the state machine. */ + SI_STAT_hosed_count, + + /* Number of completed messages. */ + SI_STAT_complete_transactions, + + /* Number of IPMI events received from the hardware. */ + SI_STAT_events, + + /* Number of watchdog pretimeouts. */ + SI_STAT_watchdog_pretimeouts, + + /* Number of asyncronous messages received. */ + SI_STAT_incoming_messages, + + + /* This *must* remain last, add new values above this. */ + SI_NUM_STATS +}; + +struct smi_info { int intf_num; ipmi_smi_t intf; struct si_sm_data *si_sm; @@ -134,8 +181,10 @@ struct smi_info struct ipmi_smi_msg *curr_msg; enum si_intf_state si_state; - /* Used to handle the various types of I/O that can occur with - IPMI */ + /* + * Used to handle the various types of I/O that can occur with + * IPMI + */ struct si_sm_io io; int (*io_setup)(struct smi_info *info); void (*io_cleanup)(struct smi_info *info); @@ -146,15 +195,18 @@ struct smi_info void (*addr_source_cleanup)(struct smi_info *info); void *addr_source_data; - /* Per-OEM handler, called from handle_flags(). - Returns 1 when handle_flags() needs to be re-run - or 0 indicating it set si_state itself. - */ + /* + * Per-OEM handler, called from handle_flags(). Returns 1 + * when handle_flags() needs to be re-run or 0 indicating it + * set si_state itself. + */ int (*oem_data_avail_handler)(struct smi_info *smi_info); - /* Flags from the last GET_MSG_FLAGS command, used when an ATTN - is set to hold the flags until we are done handling everything - from the flags. */ + /* + * Flags from the last GET_MSG_FLAGS command, used when an ATTN + * is set to hold the flags until we are done handling everything + * from the flags. + */ #define RECEIVE_MSG_AVAIL 0x01 #define EVENT_MSG_BUFFER_FULL 0x02 #define WDT_PRE_TIMEOUT_INT 0x08 @@ -162,25 +214,31 @@ struct smi_info #define OEM1_DATA_AVAIL 0x40 #define OEM2_DATA_AVAIL 0x80 #define OEM_DATA_AVAIL (OEM0_DATA_AVAIL | \ - OEM1_DATA_AVAIL | \ - OEM2_DATA_AVAIL) + OEM1_DATA_AVAIL | \ + OEM2_DATA_AVAIL) unsigned char msg_flags; - /* If set to true, this will request events the next time the - state machine is idle. */ + /* + * If set to true, this will request events the next time the + * state machine is idle. + */ atomic_t req_events; - /* If true, run the state machine to completion on every send - call. Generally used after a panic to make sure stuff goes - out. */ + /* + * If true, run the state machine to completion on every send + * call. Generally used after a panic to make sure stuff goes + * out. + */ int run_to_completion; /* The I/O port of an SI interface. */ int port; - /* The space between start addresses of the two ports. For - instance, if the first port is 0xca2 and the spacing is 4, then - the second port is 0xca6. */ + /* + * The space between start addresses of the two ports. For + * instance, if the first port is 0xca2 and the spacing is 4, then + * the second port is 0xca6. + */ unsigned int spacing; /* zero if no irq; */ @@ -195,10 +253,12 @@ struct smi_info /* Used to gracefully stop the timer without race conditions. */ atomic_t stop_operation; - /* The driver will disable interrupts when it gets into a - situation where it cannot handle messages due to lack of - memory. Once that situation clears up, it will re-enable - interrupts. */ + /* + * The driver will disable interrupts when it gets into a + * situation where it cannot handle messages due to lack of + * memory. Once that situation clears up, it will re-enable + * interrupts. + */ int interrupt_disabled; /* From the get device id response... */ @@ -208,33 +268,28 @@ struct smi_info struct device *dev; struct platform_device *pdev; - /* True if we allocated the device, false if it came from - * someplace else (like PCI). */ + /* + * True if we allocated the device, false if it came from + * someplace else (like PCI). + */ int dev_registered; /* Slave address, could be reported from DMI. */ unsigned char slave_addr; /* Counters and things for the proc filesystem. */ - spinlock_t count_lock; - unsigned long short_timeouts; - unsigned long long_timeouts; - unsigned long timeout_restarts; - unsigned long idles; - unsigned long interrupts; - unsigned long attentions; - unsigned long flag_fetches; - unsigned long hosed_count; - unsigned long complete_transactions; - unsigned long events; - unsigned long watchdog_pretimeouts; - unsigned long incoming_messages; - - struct task_struct *thread; + atomic_t stats[SI_NUM_STATS]; + + struct task_struct *thread; struct list_head link; }; +#define smi_inc_stat(smi, stat) \ + atomic_inc(&(smi)->stats[SI_STAT_ ## stat]) +#define smi_get_stat(smi, stat) \ + ((unsigned int) atomic_read(&(smi)->stats[SI_STAT_ ## stat])) + #define SI_MAX_PARMS 4 static int force_kipmid[SI_MAX_PARMS]; @@ -246,7 +301,7 @@ static int try_smi_init(struct smi_info *smi); static void cleanup_one_si(struct smi_info *to_clean); static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list); -static int register_xaction_notifier(struct notifier_block * nb) +static int register_xaction_notifier(struct notifier_block *nb) { return atomic_notifier_chain_register(&xaction_notifier_list, nb); } @@ -255,7 +310,7 @@ static void deliver_recv_msg(struct smi_info *smi_info, struct ipmi_smi_msg *msg) { /* Deliver the message to the upper layer with the lock - released. */ + released. */ spin_unlock(&(smi_info->si_lock)); ipmi_smi_msg_received(smi_info->intf, msg); spin_lock(&(smi_info->si_lock)); @@ -287,9 +342,12 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) struct timeval t; #endif - /* No need to save flags, we aleady have interrupts off and we - already hold the SMI lock. */ - spin_lock(&(smi_info->msg_lock)); + /* + * No need to save flags, we aleady have interrupts off and we + * already hold the SMI lock. + */ + if (!smi_info->run_to_completion) + spin_lock(&(smi_info->msg_lock)); /* Pick the high priority queue first. */ if (!list_empty(&(smi_info->hp_xmit_msgs))) { @@ -310,7 +368,7 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) link); #ifdef DEBUG_TIMING do_gettimeofday(&t); - printk("**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec); + printk(KERN_DEBUG "**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec); #endif err = atomic_notifier_call_chain(&xaction_notifier_list, 0, smi_info); @@ -322,14 +380,14 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info) smi_info->si_sm, smi_info->curr_msg->data, smi_info->curr_msg->data_size); - if (err) { + if (err) return_hosed_msg(smi_info, err); - } rv = SI_SM_CALL_WITHOUT_DELAY; } - out: - spin_unlock(&(smi_info->msg_lock)); + out: + if (!smi_info->run_to_completion) + spin_unlock(&(smi_info->msg_lock)); return rv; } @@ -338,8 +396,10 @@ static void start_enable_irq(struct smi_info *smi_info) { unsigned char msg[2]; - /* If we are enabling interrupts, we have to tell the - BMC to use them. */ + /* + * If we are enabling interrupts, we have to tell the + * BMC to use them. + */ msg[0] = (IPMI_NETFN_APP_REQUEST << 2); msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD; @@ -371,10 +431,12 @@ static void start_clear_flags(struct smi_info *smi_info) smi_info->si_state = SI_CLEARING_FLAGS; } -/* When we have a situtaion where we run out of memory and cannot - allocate messages, we just leave them in the BMC and run the system - polled until we can allocate some memory. Once we have some - memory, we will re-enable the interrupt. */ +/* + * When we have a situtaion where we run out of memory and cannot + * allocate messages, we just leave them in the BMC and run the system + * polled until we can allocate some memory. Once we have some + * memory, we will re-enable the interrupt. + */ static inline void disable_si_irq(struct smi_info *smi_info) { if ((smi_info->irq) && (!smi_info->interrupt_disabled)) { @@ -396,9 +458,7 @@ static void handle_flags(struct smi_info *smi_info) retry: if (smi_info->msg_flags & WDT_PRE_TIMEOUT_INT) { /* Watchdog pre-timeout */ - spin_lock(&smi_info->count_lock); - smi_info->watchdog_pretimeouts++; - spin_unlock(&smi_info->count_lock); + smi_inc_stat(smi_info, watchdog_pretimeouts); start_clear_flags(smi_info); smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT; @@ -444,12 +504,11 @@ static void handle_flags(struct smi_info *smi_info) smi_info->curr_msg->data_size); smi_info->si_state = SI_GETTING_EVENTS; } else if (smi_info->msg_flags & OEM_DATA_AVAIL && - smi_info->oem_data_avail_handler) { + smi_info->oem_data_avail_handler) { if (smi_info->oem_data_avail_handler(smi_info)) goto retry; - } else { + } else smi_info->si_state = SI_NORMAL; - } } static void handle_transaction_done(struct smi_info *smi_info) @@ -459,7 +518,7 @@ static void handle_transaction_done(struct smi_info *smi_info) struct timeval t; do_gettimeofday(&t); - printk("**Done: %d.%9.9d\n", t.tv_sec, t.tv_usec); + printk(KERN_DEBUG "**Done: %d.%9.9d\n", t.tv_sec, t.tv_usec); #endif switch (smi_info->si_state) { case SI_NORMAL: @@ -472,9 +531,11 @@ static void handle_transaction_done(struct smi_info *smi_info) smi_info->curr_msg->rsp, IPMI_MAX_MSG_LENGTH); - /* Do this here becase deliver_recv_msg() releases the - lock, and a new message can be put in during the - time the lock is released. */ + /* + * Do this here becase deliver_recv_msg() releases the + * lock, and a new message can be put in during the + * time the lock is released. + */ msg = smi_info->curr_msg; smi_info->curr_msg = NULL; deliver_recv_msg(smi_info, msg); @@ -488,12 +549,13 @@ static void handle_transaction_done(struct smi_info *smi_info) /* We got the flags from the SMI, now handle them. */ len = smi_info->handlers->get_result(smi_info->si_sm, msg, 4); if (msg[2] != 0) { - /* Error fetching flags, just give up for - now. */ + /* Error fetching flags, just give up for now. */ smi_info->si_state = SI_NORMAL; } else if (len < 4) { - /* Hmm, no flags. That's technically illegal, but - don't use uninitialized data. */ + /* + * Hmm, no flags. That's technically illegal, but + * don't use uninitialized data. + */ smi_info->si_state = SI_NORMAL; } else { smi_info->msg_flags = msg[3]; @@ -530,9 +592,11 @@ static void handle_transaction_done(struct smi_info *smi_info) smi_info->curr_msg->rsp, IPMI_MAX_MSG_LENGTH); - /* Do this here becase deliver_recv_msg() releases the - lock, and a new message can be put in during the - time the lock is released. */ + /* + * Do this here becase deliver_recv_msg() releases the + * lock, and a new message can be put in during the + * time the lock is released. + */ msg = smi_info->curr_msg; smi_info->curr_msg = NULL; if (msg->rsp[2] != 0) { @@ -543,14 +607,14 @@ static void handle_transaction_done(struct smi_info *smi_info) smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL; handle_flags(smi_info); } else { - spin_lock(&smi_info->count_lock); - smi_info->events++; - spin_unlock(&smi_info->count_lock); - - /* Do this before we deliver the message - because delivering the message releases the - lock and something else can mess with the - state. */ + smi_inc_stat(smi_info, events); + + /* + * Do this before we deliver the message + * because delivering the message releases the + * lock and something else can mess with the + * state. + */ handle_flags(smi_info); deliver_recv_msg(smi_info, msg); @@ -566,9 +630,11 @@ static void handle_transaction_done(struct smi_info *smi_info) smi_info->curr_msg->rsp, IPMI_MAX_MSG_LENGTH); - /* Do this here becase deliver_recv_msg() releases the - lock, and a new message can be put in during the - time the lock is released. */ + /* + * Do this here becase deliver_recv_msg() releases the + * lock, and a new message can be put in during the + * time the lock is released. + */ msg = smi_info->curr_msg; smi_info->curr_msg = NULL; if (msg->rsp[2] != 0) { @@ -579,14 +645,14 @@ static void handle_transaction_done(struct smi_info *smi_info) smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL; handle_flags(smi_info); } else { - spin_lock(&smi_info->count_lock); - smi_info->incoming_messages++; - spin_unlock(&smi_info->count_lock); - - /* Do this before we deliver the message - because delivering the message releases the - lock and something else can mess with the - state. */ + smi_inc_stat(smi_info, incoming_messages); + + /* + * Do this before we deliver the message + * because delivering the message releases the + * lock and something else can mess with the + * state. + */ handle_flags(smi_info); deliver_recv_msg(smi_info, msg); @@ -674,69 +740,70 @@ static void handle_transaction_done(struct smi_info *smi_info) } } -/* Called on timeouts and events. Timeouts should pass the elapsed - time, interrupts should pass in zero. Must be called with - si_lock held and interrupts disabled. */ +/* + * Called on timeouts and events. Timeouts should pass the elapsed + * time, interrupts should pass in zero. Must be called with + * si_lock held and interrupts disabled. + */ static enum si_sm_result smi_event_handler(struct smi_info *smi_info, int time) { enum si_sm_result si_sm_result; restart: - /* There used to be a loop here that waited a little while - (around 25us) before giving up. That turned out to be - pointless, the minimum delays I was seeing were in the 300us - range, which is far too long to wait in an interrupt. So - we just run until the state machine tells us something - happened or it needs a delay. */ + /* + * There used to be a loop here that waited a little while + * (around 25us) before giving up. That turned out to be + * pointless, the minimum delays I was seeing were in the 300us + * range, which is far too long to wait in an interrupt. So + * we just run until the state machine tells us something + * happened or it needs a delay. + */ si_sm_result = smi_info->handlers->event(smi_info->si_sm, time); time = 0; while (si_sm_result == SI_SM_CALL_WITHOUT_DELAY) - { si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0); - } - if (si_sm_result == SI_SM_TRANSACTION_COMPLETE) - { - spin_lock(&smi_info->count_lock); - smi_info->complete_transactions++; - spin_unlock(&smi_info->count_lock); + if (si_sm_result == SI_SM_TRANSACTION_COMPLETE) { + smi_inc_stat(smi_info, complete_transactions); handle_transaction_done(smi_info); si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0); - } - else if (si_sm_result == SI_SM_HOSED) - { - spin_lock(&smi_info->count_lock); - smi_info->hosed_count++; - spin_unlock(&smi_info->count_lock); + } else if (si_sm_result == SI_SM_HOSED) { + smi_inc_stat(smi_info, hosed_count); - /* Do the before return_hosed_msg, because that - releases the lock. */ + /* + * Do the before return_hosed_msg, because that + * releases the lock. + */ smi_info->si_state = SI_NORMAL; if (smi_info->curr_msg != NULL) { - /* If we were handling a user message, format - a response to send to the upper layer to - tell it about the error. */ + /* + * If we were handling a user message, format + * a response to send to the upper layer to + * tell it about the error. + */ return_hosed_msg(smi_info, IPMI_ERR_UNSPECIFIED); } si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0); } - /* We prefer handling attn over new messages. */ - if (si_sm_result == SI_SM_ATTN) - { + /* + * We prefer handling attn over new messages. But don't do + * this if there is not yet an upper layer to handle anything. + */ + if (likely(smi_info->intf) && si_sm_result == SI_SM_ATTN) { unsigned char msg[2]; - spin_lock(&smi_info->count_lock); - smi_info->attentions++; - spin_unlock(&smi_info->count_lock); + smi_inc_stat(smi_info, attentions); - /* Got a attn, send down a get message flags to see - what's causing it. It would be better to handle - this in the upper layer, but due to the way - interrupts work with the SMI, that's not really - possible. */ + /* + * Got a attn, send down a get message flags to see + * what's causing it. It would be better to handle + * this in the upper layer, but due to the way + * interrupts work with the SMI, that's not really + * possible. + */ msg[0] = (IPMI_NETFN_APP_REQUEST << 2); msg[1] = IPMI_GET_MSG_FLAGS_CMD; @@ -748,20 +815,19 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info, /* If we are currently idle, try to start the next message. */ if (si_sm_result == SI_SM_IDLE) { - spin_lock(&smi_info->count_lock); - smi_info->idles++; - spin_unlock(&smi_info->count_lock); + smi_inc_stat(smi_info, idles); si_sm_result = start_next_msg(smi_info); if (si_sm_result != SI_SM_IDLE) goto restart; - } + } if ((si_sm_result == SI_SM_IDLE) - && (atomic_read(&smi_info->req_events))) - { - /* We are idle and the upper layer requested that I fetch - events, so do so. */ + && (atomic_read(&smi_info->req_events))) { + /* + * We are idle and the upper layer requested that I fetch + * events, so do so. + */ atomic_set(&smi_info->req_events, 0); smi_info->curr_msg = ipmi_alloc_smi_msg(); @@ -803,56 +869,50 @@ static void sender(void *send_info, return; } - spin_lock_irqsave(&(smi_info->msg_lock), flags); #ifdef DEBUG_TIMING do_gettimeofday(&t); printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec); #endif if (smi_info->run_to_completion) { - /* If we are running to completion, then throw it in - the list and run transactions until everything is - clear. Priority doesn't matter here. */ + /* + * If we are running to completion, then throw it in + * the list and run transactions until everything is + * clear. Priority doesn't matter here. + */ + + /* + * Run to completion means we are single-threaded, no + * need for locks. + */ list_add_tail(&(msg->link), &(smi_info->xmit_msgs)); - /* We have to release the msg lock and claim the smi - lock in this case, because of race conditions. */ - spin_unlock_irqrestore(&(smi_info->msg_lock), flags); - - spin_lock_irqsave(&(smi_info->si_lock), flags); result = smi_event_handler(smi_info, 0); while (result != SI_SM_IDLE) { udelay(SI_SHORT_TIMEOUT_USEC); result = smi_event_handler(smi_info, SI_SHORT_TIMEOUT_USEC); } - spin_unlock_irqrestore(&(smi_info->si_lock), flags); return; - } else { - if (priority > 0) { - list_add_tail(&(msg->link), &(smi_info->hp_xmit_msgs)); - } else { - list_add_tail(&(msg->link), &(smi_info->xmit_msgs)); - } } - spin_unlock_irqrestore(&(smi_info->msg_lock), flags); - spin_lock_irqsave(&(smi_info->si_lock), flags); - if ((smi_info->si_state == SI_NORMAL) - && (smi_info->curr_msg == NULL)) - { + spin_lock_irqsave(&smi_info->msg_lock, flags); + if (priority > 0) + list_add_tail(&msg->link, &smi_info->hp_xmit_msgs); + else + list_add_tail(&msg->link, &smi_info->xmit_msgs); + spin_unlock_irqrestore(&smi_info->msg_lock, flags); + + spin_lock_irqsave(&smi_info->si_lock, flags); + if (smi_info->si_state == SI_NORMAL && smi_info->curr_msg == NULL) start_next_msg(smi_info); - } - spin_unlock_irqrestore(&(smi_info->si_lock), flags); + spin_unlock_irqrestore(&smi_info->si_lock, flags); } static void set_run_to_completion(void *send_info, int i_run_to_completion) { struct smi_info *smi_info = send_info; enum si_sm_result result; - unsigned long flags; - - spin_lock_irqsave(&(smi_info->si_lock), flags); smi_info->run_to_completion = i_run_to_completion; if (i_run_to_completion) { @@ -863,8 +923,6 @@ static void set_run_to_completion(void *send_info, int i_run_to_completion) SI_SHORT_TIMEOUT_USEC); } } - - spin_unlock_irqrestore(&(smi_info->si_lock), flags); } static int ipmi_thread(void *data) @@ -878,9 +936,8 @@ static int ipmi_thread(void *data) spin_lock_irqsave(&(smi_info->si_lock), flags); smi_result = smi_event_handler(smi_info, 0); spin_unlock_irqrestore(&(smi_info->si_lock), flags); - if (smi_result == SI_SM_CALL_WITHOUT_DELAY) { - /* do nothing */ - } + if (smi_result == SI_SM_CALL_WITHOUT_DELAY) + ; /* do nothing */ else if (smi_result == SI_SM_CALL_WITH_DELAY) schedule(); else @@ -931,7 +988,7 @@ static void smi_timeout(unsigned long data) spin_lock_irqsave(&(smi_info->si_lock), flags); #ifdef DEBUG_TIMING do_gettimeofday(&t); - printk("**Timer: %d.%9.9d\n", t.tv_sec, t.tv_usec); + printk(KERN_DEBUG "**Timer: %d.%9.9d\n", t.tv_sec, t.tv_usec); #endif jiffies_now = jiffies; time_diff = (((long)jiffies_now - (long)smi_info->last_timeout_jiffies) @@ -945,23 +1002,19 @@ static void smi_timeout(unsigned long data) if ((smi_info->irq) && (!smi_info->interrupt_disabled)) { /* Running with interrupts, only do long timeouts. */ smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES; - spin_lock_irqsave(&smi_info->count_lock, flags); - smi_info->long_timeouts++; - spin_unlock_irqrestore(&smi_info->count_lock, flags); + smi_inc_stat(smi_info, long_timeouts); goto do_add_timer; } - /* If the state machine asks for a short delay, then shorten - the timer timeout. */ + /* + * If the state machine asks for a short delay, then shorten + * the timer timeout. + */ if (smi_result == SI_SM_CALL_WITH_DELAY) { - spin_lock_irqsave(&smi_info->count_lock, flags); - smi_info->short_timeouts++; - spin_unlock_irqrestore(&smi_info->count_lock, flags); + smi_inc_stat(smi_info, short_timeouts); smi_info->si_timer.expires = jiffies + 1; } else { - spin_lock_irqsave(&smi_info->count_lock, flags); - smi_info->long_timeouts++; - spin_unlock_irqrestore(&smi_info->count_lock, flags); + smi_inc_stat(smi_info, long_timeouts); smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES; } @@ -979,13 +1032,11 @@ static irqreturn_t si_irq_handler(int irq, void *data) spin_lock_irqsave(&(smi_info->si_lock), flags); - spin_lock(&smi_info->count_lock); - smi_info->interrupts++; - spin_unlock(&smi_info->count_lock); + smi_inc_stat(smi_info, interrupts); #ifdef DEBUG_TIMING do_gettimeofday(&t); - printk("**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec); + printk(KERN_DEBUG "**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec); #endif smi_event_handler(smi_info, 0); spin_unlock_irqrestore(&(smi_info->si_lock), flags); @@ -1028,7 +1079,7 @@ static int smi_start_processing(void *send_info, * The BT interface is efficient enough to not need a thread, * and there is no need for a thread if we have interrupts. */ - else if ((new_smi->si_type != SI_BT) && (!new_smi->irq)) + else if ((new_smi->si_type != SI_BT) && (!new_smi->irq)) enable = 1; if (enable) { @@ -1054,8 +1105,7 @@ static void set_maintenance_mode(void *send_info, int enable) atomic_set(&smi_info->req_events, 0); } -static struct ipmi_smi_handlers handlers = -{ +static struct ipmi_smi_handlers handlers = { .owner = THIS_MODULE, .start_processing = smi_start_processing, .sender = sender, @@ -1065,8 +1115,10 @@ static struct ipmi_smi_handlers handlers = .poll = poll, }; -/* There can be 4 IO ports passed in (with or without IRQs), 4 addresses, - a default IO port, and 1 ACPI/SPMI address. That sets SI_MAX_DRIVERS */ +/* + * There can be 4 IO ports passed in (with or without IRQs), 4 addresses, + * a default IO port, and 1 ACPI/SPMI address. That sets SI_MAX_DRIVERS. + */ static LIST_HEAD(smi_infos); static DEFINE_MUTEX(smi_infos_lock); @@ -1257,10 +1309,9 @@ static void port_cleanup(struct smi_info *info) int idx; if (addr) { - for (idx = 0; idx < info->io_size; idx++) { + for (idx = 0; idx < info->io_size; idx++) release_region(addr + idx * info->io.regspacing, info->io.regsize); - } } } @@ -1274,8 +1325,10 @@ static int port_setup(struct smi_info *info) info->io_cleanup = port_cleanup; - /* Figure out the actual inb/inw/inl/etc routine to use based - upon the register size. */ + /* + * Figure out the actual inb/inw/inl/etc routine to use based + * upon the register size. + */ switch (info->io.regsize) { case 1: info->io.inputb = port_inb; @@ -1290,17 +1343,18 @@ static int port_setup(struct smi_info *info) info->io.outputb = port_outl; break; default: - printk("ipmi_si: Invalid register size: %d\n", + printk(KERN_WARNING "ipmi_si: Invalid register size: %d\n", info->io.regsize); return -EINVAL; } - /* Some BIOSes reserve disjoint I/O regions in their ACPI + /* + * Some BIOSes reserve disjoint I/O regions in their ACPI * tables. This causes problems when trying to register the * entire I/O region. Therefore we must register each I/O * port separately. */ - for (idx = 0; idx < info->io_size; idx++) { + for (idx = 0; idx < info->io_size; idx++) { if (request_region(addr + idx * info->io.regspacing, info->io.regsize, DEVICE_NAME) == NULL) { /* Undo allocations */ @@ -1388,8 +1442,10 @@ static int mem_setup(struct smi_info *info) info->io_cleanup = mem_cleanup; - /* Figure out the actual readb/readw/readl/etc routine to use based - upon the register size. */ + /* + * Figure out the actual readb/readw/readl/etc routine to use based + * upon the register size. + */ switch (info->io.regsize) { case 1: info->io.inputb = intf_mem_inb; @@ -1410,16 +1466,18 @@ static int mem_setup(struct smi_info *info) break; #endif default: - printk("ipmi_si: Invalid register size: %d\n", + printk(KERN_WARNING "ipmi_si: Invalid register size: %d\n", info->io.regsize); return -EINVAL; } - /* Calculate the total amount of memory to claim. This is an + /* + * Calculate the total amount of memory to claim. This is an * unusual looking calculation, but it avoids claiming any * more memory than it has to. It will claim everything * between the first address to the end of the last full - * register. */ + * register. + */ mapsize = ((info->io_size * info->io.regspacing) - (info->io.regspacing - info->io.regsize)); @@ -1749,9 +1807,11 @@ static __devinit void hardcode_find_bmc(void) #include <linux/acpi.h> -/* Once we get an ACPI failure, we don't try any more, because we go - through the tables sequentially. Once we don't find a table, there - are no more. */ +/* + * Once we get an ACPI failure, we don't try any more, because we go + * through the tables sequentially. Once we don't find a table, there + * are no more. + */ static int acpi_failure; /* For GPE-type interrupts. */ @@ -1765,9 +1825,7 @@ static u32 ipmi_acpi_gpe(void *context) spin_lock_irqsave(&(smi_info->si_lock), flags); - spin_lock(&smi_info->count_lock); - smi_info->interrupts++; - spin_unlock(&smi_info->count_lock); + smi_inc_stat(smi_info, interrupts); #ifdef DEBUG_TIMING do_gettimeofday(&t); @@ -1816,7 +1874,8 @@ static int acpi_gpe_irq_setup(struct smi_info *info) /* * Defined at - * http://h21007.www2.hp.com/dspp/files/unprotected/devresource/Docs/TechPapers/IA64/hpspmi.pdf + * http://h21007.www2.hp.com/dspp/files/unprotected/devresource/ + * Docs/TechPapers/IA64/hpspmi.pdf */ struct SPMITable { s8 Signature[4]; @@ -1838,14 +1897,18 @@ struct SPMITable { */ u8 InterruptType; - /* If bit 0 of InterruptType is set, then this is the SCI - interrupt in the GPEx_STS register. */ + /* + * If bit 0 of InterruptType is set, then this is the SCI + * interrupt in the GPEx_STS register. + */ u8 GPE; s16 Reserved; - /* If bit 1 of InterruptType is set, then this is the I/O - APIC/SAPIC interrupt. */ + /* + * If bit 1 of InterruptType is set, then this is the I/O + * APIC/SAPIC interrupt. + */ u32 GlobalSystemInterrupt; /* The actual register address. */ @@ -1863,7 +1926,7 @@ static __devinit int try_init_acpi(struct SPMITable *spmi) if (spmi->IPMIlegacy != 1) { printk(KERN_INFO "IPMI: Bad SPMI legacy %d\n", spmi->IPMIlegacy); - return -ENODEV; + return -ENODEV; } if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) @@ -1880,8 +1943,7 @@ static __devinit int try_init_acpi(struct SPMITable *spmi) info->addr_source = "ACPI"; /* Figure out the interface type. */ - switch (spmi->InterfaceType) - { + switch (spmi->InterfaceType) { case 1: /* KCS */ info->si_type = SI_KCS; break; @@ -1929,7 +1991,8 @@ static __devinit int try_init_acpi(struct SPMITable *spmi) info->io.addr_type = IPMI_IO_ADDR_SPACE; } else { kfree(info); - printk("ipmi_si: Unknown ACPI I/O Address type\n"); + printk(KERN_WARNING + "ipmi_si: Unknown ACPI I/O Address type\n"); return -EIO; } info->io.addr_data = spmi->addr.address; @@ -1963,8 +2026,7 @@ static __devinit void acpi_find_bmc(void) #endif #ifdef CONFIG_DMI -struct dmi_ipmi_data -{ +struct dmi_ipmi_data { u8 type; u8 addr_space; unsigned long base_addr; @@ -1989,11 +2051,10 @@ static int __devinit decode_dmi(const struct dmi_header *dm, /* I/O */ base_addr &= 0xFFFE; dmi->addr_space = IPMI_IO_ADDR_SPACE; - } - else { + } else /* Memory */ dmi->addr_space = IPMI_MEM_ADDR_SPACE; - } + /* If bit 4 of byte 0x10 is set, then the lsb for the address is odd. */ dmi->base_addr = base_addr | ((data[0x10] & 0x10) >> 4); @@ -2002,7 +2063,7 @@ static int __devinit decode_dmi(const struct dmi_header *dm, /* The top two bits of byte 0x10 hold the register spacing. */ reg_spacing = (data[0x10] & 0xC0) >> 6; - switch(reg_spacing){ + switch (reg_spacing) { case 0x00: /* Byte boundaries */ dmi->offset = 1; break; @@ -2018,12 +2079,14 @@ static int __devinit decode_dmi(const struct dmi_header *dm, } } else { /* Old DMI spec. */ - /* Note that technically, the lower bit of the base + /* + * Note that technically, the lower bit of the base * address should be 1 if the address is I/O and 0 if * the address is in memory. So many systems get that * wrong (and all that I have seen are I/O) so we just * ignore that bit and assume I/O. Systems that use - * memory should use the newer spec, anyway. */ + * memory should use the newer spec, anyway. + */ dmi->base_addr = base_addr & 0xfffe; dmi->addr_space = IPMI_IO_ADDR_SPACE; dmi->offset = 1; @@ -2230,13 +2293,13 @@ static struct pci_device_id ipmi_pci_devices[] = { MODULE_DEVICE_TABLE(pci, ipmi_pci_devices); static struct pci_driver ipmi_pci_driver = { - .name = DEVICE_NAME, - .id_table = ipmi_pci_devices, - .probe = ipmi_pci_probe, - .remove = __devexit_p(ipmi_pci_remove), + .name = DEVICE_NAME, + .id_table = ipmi_pci_devices, + .probe = ipmi_pci_probe, + .remove = __devexit_p(ipmi_pci_remove), #ifdef CONFIG_PM - .suspend = ipmi_pci_suspend, - .resume = ipmi_pci_resume, + .suspend = ipmi_pci_suspend, + .resume = ipmi_pci_resume, #endif }; #endif /* CONFIG_PCI */ @@ -2306,7 +2369,7 @@ static int __devinit ipmi_of_probe(struct of_device *dev, info->io.addr_data, info->io.regsize, info->io.regspacing, info->irq); - dev->dev.driver_data = (void*) info; + dev->dev.driver_data = (void *) info; return try_smi_init(info); } @@ -2319,14 +2382,16 @@ static int __devexit ipmi_of_remove(struct of_device *dev) static struct of_device_id ipmi_match[] = { - { .type = "ipmi", .compatible = "ipmi-kcs", .data = (void *)(unsigned long) SI_KCS }, - { .type = "ipmi", .compatible = "ipmi-smic", .data = (void *)(unsigned long) SI_SMIC }, - { .type = "ipmi", .compatible = "ipmi-bt", .data = (void *)(unsigned long) SI_BT }, + { .type = "ipmi", .compatible = "ipmi-kcs", + .data = (void *)(unsigned long) SI_KCS }, + { .type = "ipmi", .compatible = "ipmi-smic", + .data = (void *)(unsigned long) SI_SMIC }, + { .type = "ipmi", .compatible = "ipmi-bt", + .data = (void *)(unsigned long) SI_BT }, {}, }; -static struct of_platform_driver ipmi_of_platform_driver = -{ +static struct of_platform_driver ipmi_of_platform_driver = { .name = "ipmi", .match_table = ipmi_match, .probe = ipmi_of_probe, @@ -2347,32 +2412,32 @@ static int try_get_dev_id(struct smi_info *smi_info) if (!resp) return -ENOMEM; - /* Do a Get Device ID command, since it comes back with some - useful info. */ + /* + * Do a Get Device ID command, since it comes back with some + * useful info. + */ msg[0] = IPMI_NETFN_APP_REQUEST << 2; msg[1] = IPMI_GET_DEVICE_ID_CMD; smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2); smi_result = smi_info->handlers->event(smi_info->si_sm, 0); - for (;;) - { + for (;;) { if (smi_result == SI_SM_CALL_WITH_DELAY || smi_result == SI_SM_CALL_WITH_TICK_DELAY) { schedule_timeout_uninterruptible(1); smi_result = smi_info->handlers->event( smi_info->si_sm, 100); - } - else if (smi_result == SI_SM_CALL_WITHOUT_DELAY) - { + } else if (smi_result == SI_SM_CALL_WITHOUT_DELAY) { smi_result = smi_info->handlers->event( smi_info->si_sm, 0); - } - else + } else break; } if (smi_result == SI_SM_HOSED) { - /* We couldn't get the state machine to run, so whatever's at - the port is probably not an IPMI SMI interface. */ + /* + * We couldn't get the state machine to run, so whatever's at + * the port is probably not an IPMI SMI interface. + */ rv = -ENODEV; goto out; } @@ -2405,30 +2470,28 @@ static int stat_file_read_proc(char *page, char **start, off_t off, out += sprintf(out, "interrupts_enabled: %d\n", smi->irq && !smi->interrupt_disabled); - out += sprintf(out, "short_timeouts: %ld\n", - smi->short_timeouts); - out += sprintf(out, "long_timeouts: %ld\n", - smi->long_timeouts); - out += sprintf(out, "timeout_restarts: %ld\n", - smi->timeout_restarts); - out += sprintf(out, "idles: %ld\n", - smi->idles); - out += sprintf(out, "interrupts: %ld\n", - smi->interrupts); - out += sprintf(out, "attentions: %ld\n", - smi->attentions); - out += sprintf(out, "flag_fetches: %ld\n", - smi->flag_fetches); - out += sprintf(out, "hosed_count: %ld\n", - smi->hosed_count); - out += sprintf(out, "complete_transactions: %ld\n", - smi->complete_transactions); - out += sprintf(out, "events: %ld\n", - smi->events); - out += sprintf(out, "watchdog_pretimeouts: %ld\n", - smi->watchdog_pretimeouts); - out += sprintf(out, "incoming_messages: %ld\n", - smi->incoming_messages); + out += sprintf(out, "short_timeouts: %u\n", + smi_get_stat(smi, short_timeouts)); + out += sprintf(out, "long_timeouts: %u\n", + smi_get_stat(smi, long_timeouts)); + out += sprintf(out, "idles: %u\n", + smi_get_stat(smi, idles)); + out += sprintf(out, "interrupts: %u\n", + smi_get_stat(smi, interrupts)); + out += sprintf(out, "attentions: %u\n", + smi_get_stat(smi, attentions)); + out += sprintf(out, "flag_fetches: %u\n", + smi_get_stat(smi, flag_fetches)); + out += sprintf(out, "hosed_count: %u\n", + smi_get_stat(smi, hosed_count)); + out += sprintf(out, "complete_transactions: %u\n", + smi_get_stat(smi, complete_transactions)); + out += sprintf(out, "events: %u\n", + smi_get_stat(smi, events)); + out += sprintf(out, "watchdog_pretimeouts: %u\n", + smi_get_stat(smi, watchdog_pretimeouts)); + out += sprintf(out, "incoming_messages: %u\n", + smi_get_stat(smi, incoming_messages)); return out - page; } @@ -2460,7 +2523,7 @@ static int param_read_proc(char *page, char **start, off_t off, static int oem_data_avail_to_receive_msg_avail(struct smi_info *smi_info) { smi_info->msg_flags = ((smi_info->msg_flags & ~OEM_DATA_AVAIL) | - RECEIVE_MSG_AVAIL); + RECEIVE_MSG_AVAIL); return 1; } @@ -2502,10 +2565,9 @@ static void setup_dell_poweredge_oem_data_handler(struct smi_info *smi_info) id->ipmi_version == DELL_POWEREDGE_8G_BMC_IPMI_VERSION) { smi_info->oem_data_avail_handler = oem_data_avail_to_receive_msg_avail; - } - else if (ipmi_version_major(id) < 1 || - (ipmi_version_major(id) == 1 && - ipmi_version_minor(id) < 5)) { + } else if (ipmi_version_major(id) < 1 || + (ipmi_version_major(id) == 1 && + ipmi_version_minor(id) < 5)) { smi_info->oem_data_avail_handler = oem_data_avail_to_receive_msg_avail; } @@ -2597,8 +2659,10 @@ static void setup_xaction_handlers(struct smi_info *smi_info) static inline void wait_for_timer_and_thread(struct smi_info *smi_info) { if (smi_info->intf) { - /* The timer and thread are only running if the - interface has been started up and registered. */ + /* + * The timer and thread are only running if the + * interface has been started up and registered. + */ if (smi_info->thread != NULL) kthread_stop(smi_info->thread); del_timer_sync(&smi_info->si_timer); @@ -2676,6 +2740,7 @@ static int is_new_interface(struct smi_info *info) static int try_smi_init(struct smi_info *new_smi) { int rv; + int i; if (new_smi->addr_source) { printk(KERN_INFO "ipmi_si: Trying %s-specified %s state" @@ -2722,7 +2787,7 @@ static int try_smi_init(struct smi_info *new_smi) /* Allocate the state machine's data and initialize it. */ new_smi->si_sm = kmalloc(new_smi->handlers->size(), GFP_KERNEL); if (!new_smi->si_sm) { - printk(" Could not allocate state machine memory\n"); + printk(KERN_ERR "Could not allocate state machine memory\n"); rv = -ENOMEM; goto out_err; } @@ -2732,13 +2797,12 @@ static int try_smi_init(struct smi_info *new_smi) /* Now that we know the I/O size, we can set up the I/O. */ rv = new_smi->io_setup(new_smi); if (rv) { - printk(" Could not set up I/O space\n"); + printk(KERN_ERR "Could not set up I/O space\n"); goto out_err; } spin_lock_init(&(new_smi->si_lock)); spin_lock_init(&(new_smi->msg_lock)); - spin_lock_init(&(new_smi->count_lock)); /* Do low-level detection first. */ if (new_smi->handlers->detect(new_smi->si_sm)) { @@ -2749,8 +2813,10 @@ static int try_smi_init(struct smi_info *new_smi) goto out_err; } - /* Attempt a get device id command. If it fails, we probably - don't have a BMC here. */ + /* + * Attempt a get device id command. If it fails, we probably + * don't have a BMC here. + */ rv = try_get_dev_id(new_smi); if (rv) { if (new_smi->addr_source) @@ -2767,22 +2833,28 @@ static int try_smi_init(struct smi_info *new_smi) new_smi->curr_msg = NULL; atomic_set(&new_smi->req_events, 0); new_smi->run_to_completion = 0; + for (i = 0; i < SI_NUM_STATS; i++) + atomic_set(&new_smi->stats[i], 0); new_smi->interrupt_disabled = 0; atomic_set(&new_smi->stop_operation, 0); new_smi->intf_num = smi_num; smi_num++; - /* Start clearing the flags before we enable interrupts or the - timer to avoid racing with the timer. */ + /* + * Start clearing the flags before we enable interrupts or the + * timer to avoid racing with the timer. + */ start_clear_flags(new_smi); /* IRQ is defined to be set when non-zero. */ if (new_smi->irq) new_smi->si_state = SI_CLEARING_FLAGS_THEN_SET_IRQ; if (!new_smi->dev) { - /* If we don't already have a device from something - * else (like PCI), then register a new one. */ + /* + * If we don't already have a device from something + * else (like PCI), then register a new one. + */ new_smi->pdev = platform_device_alloc("ipmi_si", new_smi->intf_num); if (rv) { @@ -2820,7 +2892,7 @@ static int try_smi_init(struct smi_info *new_smi) } rv = ipmi_smi_add_proc_entry(new_smi->intf, "type", - type_file_read_proc, NULL, + type_file_read_proc, new_smi, THIS_MODULE); if (rv) { printk(KERN_ERR @@ -2830,7 +2902,7 @@ static int try_smi_init(struct smi_info *new_smi) } rv = ipmi_smi_add_proc_entry(new_smi->intf, "si_stats", - stat_file_read_proc, NULL, + stat_file_read_proc, new_smi, THIS_MODULE); if (rv) { printk(KERN_ERR @@ -2840,7 +2912,7 @@ static int try_smi_init(struct smi_info *new_smi) } rv = ipmi_smi_add_proc_entry(new_smi->intf, "params", - param_read_proc, NULL, + param_read_proc, new_smi, THIS_MODULE); if (rv) { printk(KERN_ERR @@ -2853,7 +2925,8 @@ static int try_smi_init(struct smi_info *new_smi) mutex_unlock(&smi_infos_lock); - printk(KERN_INFO "IPMI %s interface initialized\n",si_to_str[new_smi->si_type]); + printk(KERN_INFO "IPMI %s interface initialized\n", + si_to_str[new_smi->si_type]); return 0; @@ -2868,9 +2941,11 @@ static int try_smi_init(struct smi_info *new_smi) if (new_smi->irq_cleanup) new_smi->irq_cleanup(new_smi); - /* Wait until we know that we are out of any interrupt - handlers might have been running before we freed the - interrupt. */ + /* + * Wait until we know that we are out of any interrupt + * handlers might have been running before we freed the + * interrupt. + */ synchronize_sched(); if (new_smi->si_sm) { @@ -2942,11 +3017,10 @@ static __devinit int init_ipmi_si(void) #ifdef CONFIG_PCI rv = pci_register_driver(&ipmi_pci_driver); - if (rv){ + if (rv) printk(KERN_ERR "init_ipmi_si: Unable to register PCI driver: %d\n", rv); - } #endif #ifdef CONFIG_PPC_OF @@ -2975,7 +3049,8 @@ static __devinit int init_ipmi_si(void) of_unregister_platform_driver(&ipmi_of_platform_driver); #endif driver_unregister(&ipmi_driver); - printk("ipmi_si: Unable to find any System Interface(s)\n"); + printk(KERN_WARNING + "ipmi_si: Unable to find any System Interface(s)\n"); return -ENODEV; } else { mutex_unlock(&smi_infos_lock); @@ -2997,13 +3072,17 @@ static void cleanup_one_si(struct smi_info *to_clean) /* Tell the driver that we are shutting down. */ atomic_inc(&to_clean->stop_operation); - /* Make sure the timer and thread are stopped and will not run - again. */ + /* + * Make sure the timer and thread are stopped and will not run + * again. + */ wait_for_timer_and_thread(to_clean); - /* Timeouts are stopped, now make sure the interrupts are off - for the device. A little tricky with locks to make sure - there are no races. */ + /* + * Timeouts are stopped, now make sure the interrupts are off + * for the device. A little tricky with locks to make sure + * there are no races. + */ spin_lock_irqsave(&to_clean->si_lock, flags); while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) { spin_unlock_irqrestore(&to_clean->si_lock, flags); @@ -3074,4 +3153,5 @@ module_exit(cleanup_ipmi_si); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>"); -MODULE_DESCRIPTION("Interface to the IPMI driver for the KCS, SMIC, and BT system interfaces."); +MODULE_DESCRIPTION("Interface to the IPMI driver for the KCS, SMIC, and BT" + " system interfaces."); diff --git a/drivers/char/ipmi/ipmi_si_sm.h b/drivers/char/ipmi/ipmi_si_sm.h index 4b731b24dc16..df89f73475fb 100644 --- a/drivers/char/ipmi/ipmi_si_sm.h +++ b/drivers/char/ipmi/ipmi_si_sm.h @@ -34,22 +34,27 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* This is defined by the state machines themselves, it is an opaque - data type for them to use. */ +/* + * This is defined by the state machines themselves, it is an opaque + * data type for them to use. + */ struct si_sm_data; -/* The structure for doing I/O in the state machine. The state - machine doesn't have the actual I/O routines, they are done through - this interface. */ -struct si_sm_io -{ +/* + * The structure for doing I/O in the state machine. The state + * machine doesn't have the actual I/O routines, they are done through + * this interface. + */ +struct si_sm_io { unsigned char (*inputb)(struct si_sm_io *io, unsigned int offset); void (*outputb)(struct si_sm_io *io, unsigned int offset, unsigned char b); - /* Generic info used by the actual handling routines, the - state machine shouldn't touch these. */ + /* + * Generic info used by the actual handling routines, the + * state machine shouldn't touch these. + */ void __iomem *addr; int regspacing; int regsize; @@ -59,53 +64,67 @@ struct si_sm_io }; /* Results of SMI events. */ -enum si_sm_result -{ +enum si_sm_result { SI_SM_CALL_WITHOUT_DELAY, /* Call the driver again immediately */ SI_SM_CALL_WITH_DELAY, /* Delay some before calling again. */ - SI_SM_CALL_WITH_TICK_DELAY, /* Delay at least 1 tick before calling again. */ + SI_SM_CALL_WITH_TICK_DELAY,/* Delay >=1 tick before calling again. */ SI_SM_TRANSACTION_COMPLETE, /* A transaction is finished. */ SI_SM_IDLE, /* The SM is in idle state. */ SI_SM_HOSED, /* The hardware violated the state machine. */ - SI_SM_ATTN /* The hardware is asserting attn and the - state machine is idle. */ + + /* + * The hardware is asserting attn and the state machine is + * idle. + */ + SI_SM_ATTN }; /* Handlers for the SMI state machine. */ -struct si_sm_handlers -{ - /* Put the version number of the state machine here so the - upper layer can print it. */ +struct si_sm_handlers { + /* + * Put the version number of the state machine here so the + * upper layer can print it. + */ char *version; - /* Initialize the data and return the amount of I/O space to - reserve for the space. */ + /* + * Initialize the data and return the amount of I/O space to + * reserve for the space. + */ unsigned int (*init_data)(struct si_sm_data *smi, struct si_sm_io *io); - /* Start a new transaction in the state machine. This will - return -2 if the state machine is not idle, -1 if the size - is invalid (to large or too small), or 0 if the transaction - is successfully completed. */ + /* + * Start a new transaction in the state machine. This will + * return -2 if the state machine is not idle, -1 if the size + * is invalid (to large or too small), or 0 if the transaction + * is successfully completed. + */ int (*start_transaction)(struct si_sm_data *smi, unsigned char *data, unsigned int size); - /* Return the results after the transaction. This will return - -1 if the buffer is too small, zero if no transaction is - present, or the actual length of the result data. */ + /* + * Return the results after the transaction. This will return + * -1 if the buffer is too small, zero if no transaction is + * present, or the actual length of the result data. + */ int (*get_result)(struct si_sm_data *smi, unsigned char *data, unsigned int length); - /* Call this periodically (for a polled interface) or upon - receiving an interrupt (for a interrupt-driven interface). - If interrupt driven, you should probably poll this - periodically when not in idle state. This should be called - with the time that passed since the last call, if it is - significant. Time is in microseconds. */ + /* + * Call this periodically (for a polled interface) or upon + * receiving an interrupt (for a interrupt-driven interface). + * If interrupt driven, you should probably poll this + * periodically when not in idle state. This should be called + * with the time that passed since the last call, if it is + * significant. Time is in microseconds. + */ enum si_sm_result (*event)(struct si_sm_data *smi, long time); - /* Attempt to detect an SMI. Returns 0 on success or nonzero - on failure. */ + /* + * Attempt to detect an SMI. Returns 0 on success or nonzero + * on failure. + */ int (*detect)(struct si_sm_data *smi); /* The interface is shutting down, so clean it up. */ diff --git a/drivers/char/ipmi/ipmi_smic_sm.c b/drivers/char/ipmi/ipmi_smic_sm.c index e64ea7d25d24..faed92971907 100644 --- a/drivers/char/ipmi/ipmi_smic_sm.c +++ b/drivers/char/ipmi/ipmi_smic_sm.c @@ -85,6 +85,7 @@ enum smic_states { /* SMIC Flags Register Bits */ #define SMIC_RX_DATA_READY 0x80 #define SMIC_TX_DATA_READY 0x40 + /* * SMIC_SMI and SMIC_EVM_DATA_AVAIL are only used by * a few systems, and then only by Systems Management @@ -104,23 +105,22 @@ enum smic_states { #define EC_ILLEGAL_COMMAND 0x04 #define EC_BUFFER_FULL 0x05 -struct si_sm_data -{ +struct si_sm_data { enum smic_states state; struct si_sm_io *io; - unsigned char write_data[MAX_SMIC_WRITE_SIZE]; - int write_pos; - int write_count; - int orig_write_count; - unsigned char read_data[MAX_SMIC_READ_SIZE]; - int read_pos; - int truncated; - unsigned int error_retries; - long smic_timeout; + unsigned char write_data[MAX_SMIC_WRITE_SIZE]; + int write_pos; + int write_count; + int orig_write_count; + unsigned char read_data[MAX_SMIC_READ_SIZE]; + int read_pos; + int truncated; + unsigned int error_retries; + long smic_timeout; }; -static unsigned int init_smic_data (struct si_sm_data *smic, - struct si_sm_io *io) +static unsigned int init_smic_data(struct si_sm_data *smic, + struct si_sm_io *io) { smic->state = SMIC_IDLE; smic->io = io; @@ -150,11 +150,10 @@ static int start_smic_transaction(struct si_sm_data *smic, return IPMI_NOT_IN_MY_STATE_ERR; if (smic_debug & SMIC_DEBUG_MSG) { - printk(KERN_INFO "start_smic_transaction -"); - for (i = 0; i < size; i ++) { - printk (" %02x", (unsigned char) (data [i])); - } - printk ("\n"); + printk(KERN_DEBUG "start_smic_transaction -"); + for (i = 0; i < size; i++) + printk(" %02x", (unsigned char) data[i]); + printk("\n"); } smic->error_retries = 0; memcpy(smic->write_data, data, size); @@ -173,11 +172,10 @@ static int smic_get_result(struct si_sm_data *smic, int i; if (smic_debug & SMIC_DEBUG_MSG) { - printk (KERN_INFO "smic_get result -"); - for (i = 0; i < smic->read_pos; i ++) { - printk (" %02x", (smic->read_data [i])); - } - printk ("\n"); + printk(KERN_DEBUG "smic_get result -"); + for (i = 0; i < smic->read_pos; i++) + printk(" %02x", smic->read_data[i]); + printk("\n"); } if (length < smic->read_pos) { smic->read_pos = length; @@ -223,8 +221,8 @@ static inline void write_smic_control(struct si_sm_data *smic, smic->io->outputb(smic->io, 1, control); } -static inline void write_si_sm_data (struct si_sm_data *smic, - unsigned char data) +static inline void write_si_sm_data(struct si_sm_data *smic, + unsigned char data) { smic->io->outputb(smic->io, 0, data); } @@ -233,10 +231,9 @@ static inline void start_error_recovery(struct si_sm_data *smic, char *reason) { (smic->error_retries)++; if (smic->error_retries > SMIC_MAX_ERROR_RETRIES) { - if (smic_debug & SMIC_DEBUG_ENABLE) { + if (smic_debug & SMIC_DEBUG_ENABLE) printk(KERN_WARNING "ipmi_smic_drv: smic hosed: %s\n", reason); - } smic->state = SMIC_HOSED; } else { smic->write_count = smic->orig_write_count; @@ -254,14 +251,14 @@ static inline void write_next_byte(struct si_sm_data *smic) (smic->write_count)--; } -static inline void read_next_byte (struct si_sm_data *smic) +static inline void read_next_byte(struct si_sm_data *smic) { if (smic->read_pos >= MAX_SMIC_READ_SIZE) { - read_smic_data (smic); + read_smic_data(smic); smic->truncated = 1; } else { smic->read_data[smic->read_pos] = read_smic_data(smic); - (smic->read_pos)++; + smic->read_pos++; } } @@ -336,7 +333,7 @@ static inline void read_next_byte (struct si_sm_data *smic) SMIC_SC_SMS_RD_END 0xC6 */ -static enum si_sm_result smic_event (struct si_sm_data *smic, long time) +static enum si_sm_result smic_event(struct si_sm_data *smic, long time) { unsigned char status; unsigned char flags; @@ -347,13 +344,15 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) return SI_SM_HOSED; } if (smic->state != SMIC_IDLE) { - if (smic_debug & SMIC_DEBUG_STATES) { - printk(KERN_INFO + if (smic_debug & SMIC_DEBUG_STATES) + printk(KERN_DEBUG "smic_event - smic->smic_timeout = %ld," " time = %ld\n", smic->smic_timeout, time); - } -/* FIXME: smic_event is sometimes called with time > SMIC_RETRY_TIMEOUT */ + /* + * FIXME: smic_event is sometimes called with time > + * SMIC_RETRY_TIMEOUT + */ if (time < SMIC_RETRY_TIMEOUT) { smic->smic_timeout -= time; if (smic->smic_timeout < 0) { @@ -366,9 +365,9 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) if (flags & SMIC_FLAG_BSY) return SI_SM_CALL_WITH_DELAY; - status = read_smic_status (smic); + status = read_smic_status(smic); if (smic_debug & SMIC_DEBUG_STATES) - printk(KERN_INFO + printk(KERN_DEBUG "smic_event - state = %d, flags = 0x%02x," " status = 0x%02x\n", smic->state, flags, status); @@ -377,9 +376,7 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) case SMIC_IDLE: /* in IDLE we check for available messages */ if (flags & SMIC_SMS_DATA_AVAIL) - { return SI_SM_ATTN; - } return SI_SM_IDLE; case SMIC_START_OP: @@ -391,7 +388,7 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) case SMIC_OP_OK: if (status != SMIC_SC_SMS_READY) { - /* this should not happen */ + /* this should not happen */ start_error_recovery(smic, "state = SMIC_OP_OK," " status != SMIC_SC_SMS_READY"); @@ -411,8 +408,10 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) "status != SMIC_SC_SMS_WR_START"); return SI_SM_CALL_WITH_DELAY; } - /* we must not issue WR_(NEXT|END) unless - TX_DATA_READY is set */ + /* + * we must not issue WR_(NEXT|END) unless + * TX_DATA_READY is set + * */ if (flags & SMIC_TX_DATA_READY) { if (smic->write_count == 1) { /* last byte */ @@ -424,10 +423,8 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) } write_next_byte(smic); write_smic_flags(smic, flags | SMIC_FLAG_BSY); - } - else { + } else return SI_SM_CALL_WITH_DELAY; - } break; case SMIC_WRITE_NEXT: @@ -442,52 +439,48 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) if (smic->write_count == 1) { write_smic_control(smic, SMIC_CC_SMS_WR_END); smic->state = SMIC_WRITE_END; - } - else { + } else { write_smic_control(smic, SMIC_CC_SMS_WR_NEXT); smic->state = SMIC_WRITE_NEXT; } write_next_byte(smic); write_smic_flags(smic, flags | SMIC_FLAG_BSY); - } - else { + } else return SI_SM_CALL_WITH_DELAY; - } break; case SMIC_WRITE_END: if (status != SMIC_SC_SMS_WR_END) { - start_error_recovery (smic, - "state = SMIC_WRITE_END, " - "status != SMIC_SC_SMS_WR_END"); + start_error_recovery(smic, + "state = SMIC_WRITE_END, " + "status != SMIC_SC_SMS_WR_END"); return SI_SM_CALL_WITH_DELAY; } /* data register holds an error code */ data = read_smic_data(smic); if (data != 0) { - if (smic_debug & SMIC_DEBUG_ENABLE) { - printk(KERN_INFO + if (smic_debug & SMIC_DEBUG_ENABLE) + printk(KERN_DEBUG "SMIC_WRITE_END: data = %02x\n", data); - } start_error_recovery(smic, "state = SMIC_WRITE_END, " "data != SUCCESS"); return SI_SM_CALL_WITH_DELAY; - } else { + } else smic->state = SMIC_WRITE2READ; - } break; case SMIC_WRITE2READ: - /* we must wait for RX_DATA_READY to be set before we - can continue */ + /* + * we must wait for RX_DATA_READY to be set before we + * can continue + */ if (flags & SMIC_RX_DATA_READY) { write_smic_control(smic, SMIC_CC_SMS_RD_START); write_smic_flags(smic, flags | SMIC_FLAG_BSY); smic->state = SMIC_READ_START; - } else { + } else return SI_SM_CALL_WITH_DELAY; - } break; case SMIC_READ_START: @@ -502,15 +495,16 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) write_smic_control(smic, SMIC_CC_SMS_RD_NEXT); write_smic_flags(smic, flags | SMIC_FLAG_BSY); smic->state = SMIC_READ_NEXT; - } else { + } else return SI_SM_CALL_WITH_DELAY; - } break; case SMIC_READ_NEXT: switch (status) { - /* smic tells us that this is the last byte to be read - --> clean up */ + /* + * smic tells us that this is the last byte to be read + * --> clean up + */ case SMIC_SC_SMS_RD_END: read_next_byte(smic); write_smic_control(smic, SMIC_CC_SMS_RD_END); @@ -523,9 +517,8 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) write_smic_control(smic, SMIC_CC_SMS_RD_NEXT); write_smic_flags(smic, flags | SMIC_FLAG_BSY); smic->state = SMIC_READ_NEXT; - } else { + } else return SI_SM_CALL_WITH_DELAY; - } break; default: start_error_recovery( @@ -546,10 +539,9 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) data = read_smic_data(smic); /* data register holds an error code */ if (data != 0) { - if (smic_debug & SMIC_DEBUG_ENABLE) { - printk(KERN_INFO + if (smic_debug & SMIC_DEBUG_ENABLE) + printk(KERN_DEBUG "SMIC_READ_END: data = %02x\n", data); - } start_error_recovery(smic, "state = SMIC_READ_END, " "data != SUCCESS"); @@ -565,7 +557,7 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) default: if (smic_debug & SMIC_DEBUG_ENABLE) { - printk(KERN_WARNING "smic->state = %d\n", smic->state); + printk(KERN_DEBUG "smic->state = %d\n", smic->state); start_error_recovery(smic, "state = UNKNOWN"); return SI_SM_CALL_WITH_DELAY; } @@ -576,10 +568,12 @@ static enum si_sm_result smic_event (struct si_sm_data *smic, long time) static int smic_detect(struct si_sm_data *smic) { - /* It's impossible for the SMIC fnags register to be all 1's, - (assuming a properly functioning, self-initialized BMC) - but that's what you get from reading a bogus address, so we - test that first. */ + /* + * It's impossible for the SMIC fnags register to be all 1's, + * (assuming a properly functioning, self-initialized BMC) + * but that's what you get from reading a bogus address, so we + * test that first. + */ if (read_smic_flags(smic) == 0xff) return 1; @@ -595,8 +589,7 @@ static int smic_size(void) return sizeof(struct si_sm_data); } -struct si_sm_handlers smic_smi_handlers = -{ +struct si_sm_handlers smic_smi_handlers = { .init_data = init_smic_data, .start_transaction = start_smic_transaction, .get_result = smic_get_result, diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 8f45ca9235ad..1b9a87047817 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -54,13 +54,15 @@ #include <asm/atomic.h> #ifdef CONFIG_X86 -/* This is ugly, but I've determined that x86 is the only architecture - that can reasonably support the IPMI NMI watchdog timeout at this - time. If another architecture adds this capability somehow, it - will have to be a somewhat different mechanism and I have no idea - how it will work. So in the unlikely event that another - architecture supports this, we can figure out a good generic - mechanism for it at that time. */ +/* + * This is ugly, but I've determined that x86 is the only architecture + * that can reasonably support the IPMI NMI watchdog timeout at this + * time. If another architecture adds this capability somehow, it + * will have to be a somewhat different mechanism and I have no idea + * how it will work. So in the unlikely event that another + * architecture supports this, we can figure out a good generic + * mechanism for it at that time. + */ #include <asm/kdebug.h> #define HAVE_DIE_NMI #endif @@ -95,9 +97,8 @@ /* Operations that can be performed on a pretimout. */ #define WDOG_PREOP_NONE 0 #define WDOG_PREOP_PANIC 1 -#define WDOG_PREOP_GIVE_DATA 2 /* Cause data to be available to - read. Doesn't work in NMI - mode. */ +/* Cause data to be available to read. Doesn't work in NMI mode. */ +#define WDOG_PREOP_GIVE_DATA 2 /* Actions to perform on a full timeout. */ #define WDOG_SET_TIMEOUT_ACT(byte, use) \ @@ -108,8 +109,10 @@ #define WDOG_TIMEOUT_POWER_DOWN 2 #define WDOG_TIMEOUT_POWER_CYCLE 3 -/* Byte 3 of the get command, byte 4 of the get response is the - pre-timeout in seconds. */ +/* + * Byte 3 of the get command, byte 4 of the get response is the + * pre-timeout in seconds. + */ /* Bits for setting byte 4 of the set command, byte 5 of the get response. */ #define WDOG_EXPIRE_CLEAR_BIOS_FRB2 (1 << 1) @@ -118,11 +121,13 @@ #define WDOG_EXPIRE_CLEAR_SMS_OS (1 << 4) #define WDOG_EXPIRE_CLEAR_OEM (1 << 5) -/* Setting/getting the watchdog timer value. This is for bytes 5 and - 6 (the timeout time) of the set command, and bytes 6 and 7 (the - timeout time) and 8 and 9 (the current countdown value) of the - response. The timeout value is given in seconds (in the command it - is 100ms intervals). */ +/* + * Setting/getting the watchdog timer value. This is for bytes 5 and + * 6 (the timeout time) of the set command, and bytes 6 and 7 (the + * timeout time) and 8 and 9 (the current countdown value) of the + * response. The timeout value is given in seconds (in the command it + * is 100ms intervals). + */ #define WDOG_SET_TIMEOUT(byte1, byte2, val) \ (byte1) = (((val) * 10) & 0xff), (byte2) = (((val) * 10) >> 8) #define WDOG_GET_TIMEOUT(byte1, byte2) \ @@ -184,8 +189,10 @@ static int ipmi_set_timeout(int do_heartbeat); static void ipmi_register_watchdog(int ipmi_intf); static void ipmi_unregister_watchdog(int ipmi_intf); -/* If true, the driver will start running as soon as it is configured - and ready. */ +/* + * If true, the driver will start running as soon as it is configured + * and ready. + */ static int start_now; static int set_param_int(const char *val, struct kernel_param *kp) @@ -309,10 +316,12 @@ static int ipmi_ignore_heartbeat; /* Is someone using the watchdog? Only one user is allowed. */ static unsigned long ipmi_wdog_open; -/* If set to 1, the heartbeat command will set the state to reset and - start the timer. The timer doesn't normally run when the driver is - first opened until the heartbeat is set the first time, this - variable is used to accomplish this. */ +/* + * If set to 1, the heartbeat command will set the state to reset and + * start the timer. The timer doesn't normally run when the driver is + * first opened until the heartbeat is set the first time, this + * variable is used to accomplish this. + */ static int ipmi_start_timer_on_heartbeat; /* IPMI version of the BMC. */ @@ -329,10 +338,12 @@ static int nmi_handler_registered; static int ipmi_heartbeat(void); -/* We use a mutex to make sure that only one thing can send a set - timeout at one time, because we only have one copy of the data. - The mutex is claimed when the set_timeout is sent and freed - when both messages are free. */ +/* + * We use a mutex to make sure that only one thing can send a set + * timeout at one time, because we only have one copy of the data. + * The mutex is claimed when the set_timeout is sent and freed + * when both messages are free. + */ static atomic_t set_timeout_tofree = ATOMIC_INIT(0); static DEFINE_MUTEX(set_timeout_lock); static DECLARE_COMPLETION(set_timeout_wait); @@ -346,15 +357,13 @@ static void set_timeout_free_recv(struct ipmi_recv_msg *msg) if (atomic_dec_and_test(&set_timeout_tofree)) complete(&set_timeout_wait); } -static struct ipmi_smi_msg set_timeout_smi_msg = -{ +static struct ipmi_smi_msg set_timeout_smi_msg = { .done = set_timeout_free_smi }; -static struct ipmi_recv_msg set_timeout_recv_msg = -{ +static struct ipmi_recv_msg set_timeout_recv_msg = { .done = set_timeout_free_recv }; - + static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg, struct ipmi_recv_msg *recv_msg, int *send_heartbeat_now) @@ -373,13 +382,14 @@ static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg, WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS); if ((ipmi_version_major > 1) - || ((ipmi_version_major == 1) && (ipmi_version_minor >= 5))) - { + || ((ipmi_version_major == 1) && (ipmi_version_minor >= 5))) { /* This is an IPMI 1.5-only feature. */ data[0] |= WDOG_DONT_STOP_ON_SET; } else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) { - /* In ipmi 1.0, setting the timer stops the watchdog, we - need to start it back up again. */ + /* + * In ipmi 1.0, setting the timer stops the watchdog, we + * need to start it back up again. + */ hbnow = 1; } @@ -465,12 +475,10 @@ static void panic_recv_free(struct ipmi_recv_msg *msg) atomic_dec(&panic_done_count); } -static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg = -{ +static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg = { .done = panic_smi_free }; -static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg = -{ +static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg = { .done = panic_recv_free }; @@ -480,8 +488,10 @@ static void panic_halt_ipmi_heartbeat(void) struct ipmi_system_interface_addr addr; int rv; - /* Don't reset the timer if we have the timer turned off, that - re-enables the watchdog. */ + /* + * Don't reset the timer if we have the timer turned off, that + * re-enables the watchdog. + */ if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) return; @@ -505,19 +515,19 @@ static void panic_halt_ipmi_heartbeat(void) atomic_add(2, &panic_done_count); } -static struct ipmi_smi_msg panic_halt_smi_msg = -{ +static struct ipmi_smi_msg panic_halt_smi_msg = { .done = panic_smi_free }; -static struct ipmi_recv_msg panic_halt_recv_msg = -{ +static struct ipmi_recv_msg panic_halt_recv_msg = { .done = panic_recv_free }; -/* Special call, doesn't claim any locks. This is only to be called - at panic or halt time, in run-to-completion mode, when the caller - is the only CPU and the only thing that will be going is these IPMI - calls. */ +/* + * Special call, doesn't claim any locks. This is only to be called + * at panic or halt time, in run-to-completion mode, when the caller + * is the only CPU and the only thing that will be going is these IPMI + * calls. + */ static void panic_halt_ipmi_set_timeout(void) { int send_heartbeat_now; @@ -540,10 +550,12 @@ static void panic_halt_ipmi_set_timeout(void) ipmi_poll_interface(watchdog_user); } -/* We use a semaphore to make sure that only one thing can send a - heartbeat at one time, because we only have one copy of the data. - The semaphore is claimed when the set_timeout is sent and freed - when both messages are free. */ +/* + * We use a mutex to make sure that only one thing can send a + * heartbeat at one time, because we only have one copy of the data. + * The semaphore is claimed when the set_timeout is sent and freed + * when both messages are free. + */ static atomic_t heartbeat_tofree = ATOMIC_INIT(0); static DEFINE_MUTEX(heartbeat_lock); static DECLARE_COMPLETION(heartbeat_wait); @@ -557,15 +569,13 @@ static void heartbeat_free_recv(struct ipmi_recv_msg *msg) if (atomic_dec_and_test(&heartbeat_tofree)) complete(&heartbeat_wait); } -static struct ipmi_smi_msg heartbeat_smi_msg = -{ +static struct ipmi_smi_msg heartbeat_smi_msg = { .done = heartbeat_free_smi }; -static struct ipmi_recv_msg heartbeat_recv_msg = -{ +static struct ipmi_recv_msg heartbeat_recv_msg = { .done = heartbeat_free_recv }; - + static int ipmi_heartbeat(void) { struct kernel_ipmi_msg msg; @@ -580,10 +590,12 @@ static int ipmi_heartbeat(void) ipmi_watchdog_state = action_val; return ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); } else if (pretimeout_since_last_heartbeat) { - /* A pretimeout occurred, make sure we set the timeout. - We don't want to set the action, though, we want to - leave that alone (thus it can't be combined with the - above operation. */ + /* + * A pretimeout occurred, make sure we set the timeout. + * We don't want to set the action, though, we want to + * leave that alone (thus it can't be combined with the + * above operation. + */ return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY); } @@ -591,8 +603,10 @@ static int ipmi_heartbeat(void) atomic_set(&heartbeat_tofree, 2); - /* Don't reset the timer if we have the timer turned off, that - re-enables the watchdog. */ + /* + * Don't reset the timer if we have the timer turned off, that + * re-enables the watchdog. + */ if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) { mutex_unlock(&heartbeat_lock); return 0; @@ -625,10 +639,12 @@ static int ipmi_heartbeat(void) wait_for_completion(&heartbeat_wait); if (heartbeat_recv_msg.msg.data[0] != 0) { - /* Got an error in the heartbeat response. It was already - reported in ipmi_wdog_msg_handler, but we should return - an error here. */ - rv = -EINVAL; + /* + * Got an error in the heartbeat response. It was already + * reported in ipmi_wdog_msg_handler, but we should return + * an error here. + */ + rv = -EINVAL; } mutex_unlock(&heartbeat_lock); @@ -636,8 +652,7 @@ static int ipmi_heartbeat(void) return rv; } -static struct watchdog_info ident = -{ +static struct watchdog_info ident = { .options = 0, /* WDIOF_SETTIMEOUT, */ .firmware_version = 1, .identity = "IPMI" @@ -650,7 +665,7 @@ static int ipmi_ioctl(struct inode *inode, struct file *file, int i; int val; - switch(cmd) { + switch (cmd) { case WDIOC_GETSUPPORT: i = copy_to_user(argp, &ident, sizeof(ident)); return i ? -EFAULT : 0; @@ -690,15 +705,13 @@ static int ipmi_ioctl(struct inode *inode, struct file *file, i = copy_from_user(&val, argp, sizeof(int)); if (i) return -EFAULT; - if (val & WDIOS_DISABLECARD) - { + if (val & WDIOS_DISABLECARD) { ipmi_watchdog_state = WDOG_TIMEOUT_NONE; ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB); ipmi_start_timer_on_heartbeat = 0; } - if (val & WDIOS_ENABLECARD) - { + if (val & WDIOS_ENABLECARD) { ipmi_watchdog_state = action_val; ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB); } @@ -724,13 +737,13 @@ static ssize_t ipmi_write(struct file *file, int rv; if (len) { - if (!nowayout) { - size_t i; + if (!nowayout) { + size_t i; /* In case it was set long ago */ expect_close = 0; - for (i = 0; i != len; i++) { + for (i = 0; i != len; i++) { char c; if (get_user(c, buf + i)) @@ -758,15 +771,17 @@ static ssize_t ipmi_read(struct file *file, if (count <= 0) return 0; - /* Reading returns if the pretimeout has gone off, and it only does - it once per pretimeout. */ + /* + * Reading returns if the pretimeout has gone off, and it only does + * it once per pretimeout. + */ spin_lock(&ipmi_read_lock); if (!data_to_read) { if (file->f_flags & O_NONBLOCK) { rv = -EAGAIN; goto out; } - + init_waitqueue_entry(&wait, current); add_wait_queue(&read_q, &wait); while (!data_to_read) { @@ -776,7 +791,7 @@ static ssize_t ipmi_read(struct file *file, spin_lock(&ipmi_read_lock); } remove_wait_queue(&read_q, &wait); - + if (signal_pending(current)) { rv = -ERESTARTSYS; goto out; @@ -799,25 +814,27 @@ static ssize_t ipmi_read(struct file *file, static int ipmi_open(struct inode *ino, struct file *filep) { - switch (iminor(ino)) { - case WATCHDOG_MINOR: + switch (iminor(ino)) { + case WATCHDOG_MINOR: if (test_and_set_bit(0, &ipmi_wdog_open)) - return -EBUSY; + return -EBUSY; - /* Don't start the timer now, let it start on the - first heartbeat. */ + /* + * Don't start the timer now, let it start on the + * first heartbeat. + */ ipmi_start_timer_on_heartbeat = 1; return nonseekable_open(ino, filep); default: return (-ENODEV); - } + } } static unsigned int ipmi_poll(struct file *file, poll_table *wait) { unsigned int mask = 0; - + poll_wait(file, &read_q, wait); spin_lock(&ipmi_read_lock); @@ -851,7 +868,7 @@ static int ipmi_close(struct inode *ino, struct file *filep) clear_bit(0, &ipmi_wdog_open); } - ipmi_fasync (-1, filep, 0); + ipmi_fasync(-1, filep, 0); expect_close = 0; return 0; @@ -882,7 +899,7 @@ static void ipmi_wdog_msg_handler(struct ipmi_recv_msg *msg, msg->msg.data[0], msg->msg.cmd); } - + ipmi_free_recv_msg(msg); } @@ -902,14 +919,14 @@ static void ipmi_wdog_pretimeout_handler(void *handler_data) } } - /* On some machines, the heartbeat will give - an error and not work unless we re-enable - the timer. So do so. */ + /* + * On some machines, the heartbeat will give an error and not + * work unless we re-enable the timer. So do so. + */ pretimeout_since_last_heartbeat = 1; } -static struct ipmi_user_hndl ipmi_hndlrs = -{ +static struct ipmi_user_hndl ipmi_hndlrs = { .ipmi_recv_hndl = ipmi_wdog_msg_handler, .ipmi_watchdog_pretimeout = ipmi_wdog_pretimeout_handler }; @@ -949,8 +966,10 @@ static void ipmi_register_watchdog(int ipmi_intf) int old_timeout = timeout; int old_preop_val = preop_val; - /* Set the pretimeout to go off in a second and give - ourselves plenty of time to stop the timer. */ + /* + * Set the pretimeout to go off in a second and give + * ourselves plenty of time to stop the timer. + */ ipmi_watchdog_state = WDOG_TIMEOUT_RESET; preop_val = WDOG_PREOP_NONE; /* Make sure nothing happens */ pretimeout = 99; @@ -974,7 +993,7 @@ static void ipmi_register_watchdog(int ipmi_intf) " occur. The NMI pretimeout will" " likely not work\n"); } - out_restore: + out_restore: testing_nmi = 0; preop_val = old_preop_val; pretimeout = old_pretimeout; @@ -1009,9 +1028,11 @@ static void ipmi_unregister_watchdog(int ipmi_intf) /* Make sure no one can call us any more. */ misc_deregister(&ipmi_wdog_miscdev); - /* Wait to make sure the message makes it out. The lower layer has - pointers to our buffers, we want to make sure they are done before - we release our memory. */ + /* + * Wait to make sure the message makes it out. The lower layer has + * pointers to our buffers, we want to make sure they are done before + * we release our memory. + */ while (atomic_read(&set_timeout_tofree)) schedule_timeout_uninterruptible(1); @@ -1052,15 +1073,17 @@ ipmi_nmi(struct notifier_block *self, unsigned long val, void *data) return NOTIFY_STOP; } - /* If we are not expecting a timeout, ignore it. */ + /* If we are not expecting a timeout, ignore it. */ if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) return NOTIFY_OK; if (preaction_val != WDOG_PRETIMEOUT_NMI) return NOTIFY_OK; - /* If no one else handled the NMI, we assume it was the IPMI - watchdog. */ + /* + * If no one else handled the NMI, we assume it was the IPMI + * watchdog. + */ if (preop_val == WDOG_PREOP_PANIC) { /* On some machines, the heartbeat will give an error and not work unless we re-enable @@ -1082,7 +1105,7 @@ static int wdog_reboot_handler(struct notifier_block *this, unsigned long code, void *unused) { - static int reboot_event_handled = 0; + static int reboot_event_handled; if ((watchdog_user) && (!reboot_event_handled)) { /* Make sure we only do this once. */ @@ -1115,7 +1138,7 @@ static int wdog_panic_handler(struct notifier_block *this, unsigned long event, void *unused) { - static int panic_event_handled = 0; + static int panic_event_handled; /* On a panic, if we have a panic timeout, make sure to extend the watchdog timer to a reasonable value to complete the @@ -1125,7 +1148,7 @@ static int wdog_panic_handler(struct notifier_block *this, ipmi_watchdog_state != WDOG_TIMEOUT_NONE) { /* Make sure we do this only once. */ panic_event_handled = 1; - + timeout = 255; pretimeout = 0; panic_halt_ipmi_set_timeout(); @@ -1151,8 +1174,7 @@ static void ipmi_smi_gone(int if_num) ipmi_unregister_watchdog(if_num); } -static struct ipmi_smi_watcher smi_watcher = -{ +static struct ipmi_smi_watcher smi_watcher = { .owner = THIS_MODULE, .new_smi = ipmi_new_smi, .smi_gone = ipmi_smi_gone diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index eba2883b630e..4f3cefa8eb0e 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -126,8 +126,8 @@ #include <linux/delay.h> #include <linux/ioport.h> -#include <asm/uaccess.h> -#include <asm/io.h> +#include <linux/uaccess.h> +#include <linux/io.h> #include <asm/system.h> #include <linux/pci.h> @@ -189,7 +189,7 @@ struct isi_board { unsigned short status; unsigned short port_status; /* each bit for each port */ unsigned short shift_count; - struct isi_port * ports; + struct isi_port *ports; signed char count; spinlock_t card_lock; /* Card wide lock 11/5/00 -sameer */ unsigned long flags; @@ -205,11 +205,11 @@ struct isi_port { u16 channel; u16 status; u16 closing_wait; - struct isi_board * card; - struct tty_struct * tty; + struct isi_board *card; + struct tty_struct *tty; wait_queue_head_t close_wait; wait_queue_head_t open_wait; - unsigned char * xmit_buf; + unsigned char *xmit_buf; int xmit_head; int xmit_tail; int xmit_cnt; @@ -405,7 +405,7 @@ static void isicom_tx(unsigned long _data) /* find next active board */ card = (prev_card + 1) & 0x0003; - while(count-- > 0) { + while (count-- > 0) { if (isi_card[card].status & BOARD_ACTIVE) break; card = (card + 1) & 0x0003; @@ -428,7 +428,7 @@ static void isicom_tx(unsigned long _data) if (retries >= 100) goto unlock; - for (;count > 0;count--, port++) { + for (; count > 0; count--, port++) { /* port not active or tx disabled to force flow control */ if (!(port->flags & ASYNC_INITIALIZED) || !(port->status & ISI_TXOK)) @@ -471,9 +471,10 @@ static void isicom_tx(unsigned long _data) break; } } - if (cnt <= 0) break; + if (cnt <= 0) + break; word_count = cnt >> 1; - outsw(base, port->xmit_buf+port->xmit_tail,word_count); + outsw(base, port->xmit_buf+port->xmit_tail, word_count); port->xmit_tail = (port->xmit_tail + (word_count << 1)) & (SERIAL_XMIT_SIZE - 1); txcount -= (word_count << 1); @@ -556,7 +557,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) tty = port->tty; if (tty == NULL) { word_count = byte_count >> 1; - while(byte_count > 1) { + while (byte_count > 1) { inw(base); byte_count -= 2; } @@ -569,7 +570,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) if (header & 0x8000) { /* Status Packet */ header = inw(base); - switch(header & 0xff) { + switch (header & 0xff) { case 0: /* Change in EIA signals */ if (port->flags & ASYNC_CHECK_CD) { if (port->status & ISI_DCD) { @@ -656,7 +657,8 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) if (byte_count > 0) { pr_dbg("Intr(0x%lx:%d): Flip buffer overflow! dropping " "bytes...\n", base, channel + 1); - while(byte_count > 0) { /* drain out unread xtra data */ + /* drain out unread xtra data */ + while (byte_count > 0) { inw(base); byte_count -= 2; } @@ -679,8 +681,11 @@ static void isicom_config_port(struct isi_port *port) shift_count = card->shift_count; unsigned char flow_ctrl; - if (!(tty = port->tty) || !tty->termios) + tty = port->tty; + + if (tty == NULL) return; + /* FIXME: Switch to new tty baud API */ baud = C_BAUD(tty); if (baud & CBAUDEX) { baud &= ~CBAUDEX; @@ -706,7 +711,7 @@ static void isicom_config_port(struct isi_port *port) if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) baud++; /* 57.6 Kbps */ if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - baud +=2; /* 115 Kbps */ + baud += 2; /* 115 Kbps */ if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) baud += 3; /* 230 kbps*/ if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) @@ -716,15 +721,14 @@ static void isicom_config_port(struct isi_port *port) /* hang up */ drop_dtr(port); return; - } - else + } else raise_dtr(port); if (WaitTillCardIsFree(base) == 0) { - outw(0x8000 | (channel << shift_count) |0x03, base); + outw(0x8000 | (channel << shift_count) | 0x03, base); outw(linuxb_to_isib[baud] << 8 | 0x03, base); channel_setup = 0; - switch(C_CSIZE(tty)) { + switch (C_CSIZE(tty)) { case CS5: channel_setup |= ISICOM_CS5; break; @@ -767,7 +771,7 @@ static void isicom_config_port(struct isi_port *port) flow_ctrl |= ISICOM_INITIATE_XONXOFF; if (WaitTillCardIsFree(base) == 0) { - outw(0x8000 | (channel << shift_count) |0x04, base); + outw(0x8000 | (channel << shift_count) | 0x04, base); outw(flow_ctrl << 8 | 0x05, base); outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base); InterruptTheCard(base); @@ -805,20 +809,17 @@ static int isicom_setup_port(struct isi_port *port) struct isi_board *card = port->card; unsigned long flags; - if (port->flags & ASYNC_INITIALIZED) { + if (port->flags & ASYNC_INITIALIZED) return 0; - } if (!port->xmit_buf) { - unsigned long page; - - if (!(page = get_zeroed_page(GFP_KERNEL))) + /* Relies on BKL */ + unsigned long page = get_zeroed_page(GFP_KERNEL); + if (page == 0) return -ENOMEM; - - if (port->xmit_buf) { + if (port->xmit_buf) free_page(page); - return -ERESTARTSYS; - } - port->xmit_buf = (unsigned char *) page; + else + port->xmit_buf = (unsigned char *) page; } spin_lock_irqsave(&card->card_lock, flags); @@ -949,21 +950,18 @@ static int isicom_open(struct tty_struct *tty, struct file *filp) port->count++; tty->driver_data = port; port->tty = tty; - if ((error = isicom_setup_port(port))!=0) - return error; - if ((error = block_til_ready(tty, filp, port))!=0) - return error; - - return 0; + error = isicom_setup_port(port); + if (error == 0) + error = block_til_ready(tty, filp, port); + return error; } /* close et all */ static inline void isicom_shutdown_board(struct isi_board *bp) { - if (bp->status & BOARD_ACTIVE) { + if (bp->status & BOARD_ACTIVE) bp->status &= ~BOARD_ACTIVE; - } } /* card->lock HAS to be held */ @@ -1012,6 +1010,22 @@ static void isicom_shutdown_port(struct isi_port *port) } } +static void isicom_flush_buffer(struct tty_struct *tty) +{ + struct isi_port *port = tty->driver_data; + struct isi_board *card = port->card; + unsigned long flags; + + if (isicom_paranoia_check(port, tty->name, "isicom_flush_buffer")) + return; + + spin_lock_irqsave(&card->card_lock, flags); + port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; + spin_unlock_irqrestore(&card->card_lock, flags); + + tty_wakeup(tty); +} + static void isicom_close(struct tty_struct *tty, struct file *filp) { struct isi_port *port = tty->driver_data; @@ -1065,8 +1079,7 @@ static void isicom_close(struct tty_struct *tty, struct file *filp) isicom_shutdown_port(port); spin_unlock_irqrestore(&card->card_lock, flags); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + isicom_flush_buffer(tty); tty_ldisc_flush(tty); spin_lock_irqsave(&card->card_lock, flags); @@ -1104,7 +1117,7 @@ static int isicom_write(struct tty_struct *tty, const unsigned char *buf, spin_lock_irqsave(&card->card_lock, flags); - while(1) { + while (1) { cnt = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, SERIAL_XMIT_SIZE - port->xmit_head)); if (cnt <= 0) @@ -1125,28 +1138,29 @@ static int isicom_write(struct tty_struct *tty, const unsigned char *buf, } /* put_char et all */ -static void isicom_put_char(struct tty_struct *tty, unsigned char ch) +static int isicom_put_char(struct tty_struct *tty, unsigned char ch) { struct isi_port *port = tty->driver_data; struct isi_board *card = port->card; unsigned long flags; if (isicom_paranoia_check(port, tty->name, "isicom_put_char")) - return; + return 0; if (!port->xmit_buf) - return; + return 0; spin_lock_irqsave(&card->card_lock, flags); if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) { spin_unlock_irqrestore(&card->card_lock, flags); - return; + return 0; } port->xmit_buf[port->xmit_head++] = ch; port->xmit_head &= (SERIAL_XMIT_SIZE - 1); port->xmit_cnt++; spin_unlock_irqrestore(&card->card_lock, flags); + return 1; } /* flush_chars et all */ @@ -1258,6 +1272,8 @@ static int isicom_set_serial_info(struct isi_port *port, if (copy_from_user(&newinfo, info, sizeof(newinfo))) return -EFAULT; + lock_kernel(); + reconfig_port = ((port->flags & ASYNC_SPD_MASK) != (newinfo.flags & ASYNC_SPD_MASK)); @@ -1265,12 +1281,13 @@ static int isicom_set_serial_info(struct isi_port *port, if ((newinfo.close_delay != port->close_delay) || (newinfo.closing_wait != port->closing_wait) || ((newinfo.flags & ~ASYNC_USR_MASK) != - (port->flags & ~ASYNC_USR_MASK))) + (port->flags & ~ASYNC_USR_MASK))) { + unlock_kernel(); return -EPERM; - port->flags = ((port->flags & ~ ASYNC_USR_MASK) | + } + port->flags = ((port->flags & ~ASYNC_USR_MASK) | (newinfo.flags & ASYNC_USR_MASK)); - } - else { + } else { port->close_delay = newinfo.close_delay; port->closing_wait = newinfo.closing_wait; port->flags = ((port->flags & ~ASYNC_FLAGS) | @@ -1282,6 +1299,7 @@ static int isicom_set_serial_info(struct isi_port *port, isicom_config_port(port); spin_unlock_irqrestore(&port->card->card_lock, flags); } + unlock_kernel(); return 0; } @@ -1290,6 +1308,7 @@ static int isicom_get_serial_info(struct isi_port *port, { struct serial_struct out_info; + lock_kernel(); memset(&out_info, 0, sizeof(out_info)); /* out_info.type = ? */ out_info.line = port - isi_ports; @@ -1299,6 +1318,7 @@ static int isicom_get_serial_info(struct isi_port *port, /* out_info.baud_base = ? */ out_info.close_delay = port->close_delay; out_info.closing_wait = port->closing_wait; + unlock_kernel(); if (copy_to_user(info, &out_info, sizeof(out_info))) return -EFAULT; return 0; @@ -1314,7 +1334,7 @@ static int isicom_ioctl(struct tty_struct *tty, struct file *filp, if (isicom_paranoia_check(port, tty->name, "isicom_ioctl")) return -ENODEV; - switch(cmd) { + switch (cmd) { case TCSBRK: retval = tty_check_change(tty); if (retval) @@ -1331,19 +1351,6 @@ static int isicom_ioctl(struct tty_struct *tty, struct file *filp, tty_wait_until_sent(tty, 0); isicom_send_break(port, arg ? arg * (HZ/10) : HZ/4); return 0; - - case TIOCGSOFTCAR: - return put_user(C_CLOCAL(tty) ? 1 : 0, - (unsigned long __user *)argp); - - case TIOCSSOFTCAR: - if (get_user(arg, (unsigned long __user *) argp)) - return -EFAULT; - tty->termios->c_cflag = - ((tty->termios->c_cflag & ~CLOCAL) | - (arg ? CLOCAL : 0)); - return 0; - case TIOCGSERIAL: return isicom_get_serial_info(port, argp); @@ -1453,22 +1460,6 @@ static void isicom_hangup(struct tty_struct *tty) wake_up_interruptible(&port->open_wait); } -/* flush_buffer et all */ -static void isicom_flush_buffer(struct tty_struct *tty) -{ - struct isi_port *port = tty->driver_data; - struct isi_board *card = port->card; - unsigned long flags; - - if (isicom_paranoia_check(port, tty->name, "isicom_flush_buffer")) - return; - - spin_lock_irqsave(&card->card_lock, flags); - port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; - spin_unlock_irqrestore(&card->card_lock, flags); - - tty_wakeup(tty); -} /* * Driver init and deinit functions @@ -1592,7 +1583,7 @@ static int __devinit load_firmware(struct pci_dev *pdev, default: dev_err(&pdev->dev, "Unknown signature.\n"); goto end; - } + } retval = request_firmware(&fw, name, &pdev->dev); if (retval) @@ -1620,7 +1611,8 @@ static int __devinit load_firmware(struct pci_dev *pdev, if (WaitTillCardIsFree(base)) goto errrelfw; - if ((status = inw(base + 0x4)) != 0) { + status = inw(base + 0x4); + if (status != 0) { dev_warn(&pdev->dev, "Card%d rejected load header:\n" KERN_WARNING "Address:0x%x\n" KERN_WARNING "Count:0x%x\n" @@ -1637,12 +1629,13 @@ static int __devinit load_firmware(struct pci_dev *pdev, if (WaitTillCardIsFree(base)) goto errrelfw; - if ((status = inw(base + 0x4)) != 0) { + status = inw(base + 0x4); + if (status != 0) { dev_err(&pdev->dev, "Card%d got out of sync.Card " "Status:0x%x\n", index + 1, status); goto errrelfw; } - } + } /* XXX: should we test it by reading it back and comparing with original like * in load firmware package? */ @@ -1666,7 +1659,8 @@ static int __devinit load_firmware(struct pci_dev *pdev, if (WaitTillCardIsFree(base)) goto errrelfw; - if ((status = inw(base + 0x4)) != 0) { + status = inw(base + 0x4); + if (status != 0) { dev_warn(&pdev->dev, "Card%d rejected verify header:\n" KERN_WARNING "Address:0x%x\n" KERN_WARNING "Count:0x%x\n" @@ -1699,7 +1693,8 @@ static int __devinit load_firmware(struct pci_dev *pdev, if (WaitTillCardIsFree(base)) goto errrelfw; - if ((status = inw(base + 0x4)) != 0) { + status = inw(base + 0x4); + if (status != 0) { dev_err(&pdev->dev, "Card%d verify got out of sync. " "Card Status:0x%x\n", index + 1, status); goto errrelfw; @@ -1764,7 +1759,7 @@ static int __devinit isicom_probe(struct pci_dev *pdev, index + 1); retval = -EBUSY; goto errdec; - } + } retval = request_irq(board->irq, isicom_interrupt, IRQF_SHARED | IRQF_DISABLED, ISICOM_NAME, board); @@ -1818,7 +1813,7 @@ static int __init isicom_init(void) int retval, idx, channel; struct isi_port *port; - for(idx = 0; idx < BOARD_COUNT; idx++) { + for (idx = 0; idx < BOARD_COUNT; idx++) { port = &isi_ports[idx * 16]; isi_card[idx].ports = port; spin_lock_init(&isi_card[idx].card_lock); @@ -1832,7 +1827,7 @@ static int __init isicom_init(void) init_waitqueue_head(&port->open_wait); init_waitqueue_head(&port->close_wait); /* . . . */ - } + } isi_card[idx].base = 0; isi_card[idx].irq = 0; } diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index c645455c3fd1..7c8b62f162bf 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -1682,16 +1682,6 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm rc = 0; switch (cmd) { - case TIOCGSOFTCAR: - rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), - (unsigned __user *) arg); - break; - case TIOCSSOFTCAR: - if ((rc = get_user(ival, (unsigned __user *) arg)) == 0) - tty->termios->c_cflag = - (tty->termios->c_cflag & ~CLOCAL) | - (ival ? CLOCAL : 0); - break; case TIOCGSERIAL: rc = stli_getserial(portp, argp); break; @@ -3267,7 +3257,7 @@ static int stli_initecp(struct stlibrd *brdp) */ EBRDINIT(brdp); - brdp->membase = ioremap(brdp->memaddr, brdp->memsize); + brdp->membase = ioremap_nocache(brdp->memaddr, brdp->memsize); if (brdp->membase == NULL) { retval = -ENOMEM; goto err_reg; @@ -3424,7 +3414,7 @@ static int stli_initonb(struct stlibrd *brdp) */ EBRDINIT(brdp); - brdp->membase = ioremap(brdp->memaddr, brdp->memsize); + brdp->membase = ioremap_nocache(brdp->memaddr, brdp->memsize); if (brdp->membase == NULL) { retval = -ENOMEM; goto err_reg; @@ -3675,7 +3665,7 @@ static int stli_eisamemprobe(struct stlibrd *brdp) */ for (i = 0; (i < stli_eisamempsize); i++) { brdp->memaddr = stli_eisamemprobeaddrs[i]; - brdp->membase = ioremap(brdp->memaddr, brdp->memsize); + brdp->membase = ioremap_nocache(brdp->memaddr, brdp->memsize); if (brdp->membase == NULL) continue; @@ -4433,6 +4423,8 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un done = 0; rc = 0; + lock_kernel(); + switch (cmd) { case COM_GETPORTSTATS: rc = stli_getportstats(NULL, argp); @@ -4455,6 +4447,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un done++; break; } + unlock_kernel(); if (done) return rc; @@ -4472,6 +4465,8 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un if (brdp->state == 0) return -ENODEV; + lock_kernel(); + switch (cmd) { case STL_BINTR: EBRDINTR(brdp); @@ -4494,6 +4489,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un rc = -ENOIOCTLCMD; break; } + unlock_kernel(); return rc; } diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 60b934adea65..7f7e798c1384 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -110,6 +110,7 @@ const int max_vals[] = { const int NR_TYPES = ARRAY_SIZE(max_vals); struct kbd_struct kbd_table[MAX_NR_CONSOLES]; +EXPORT_SYMBOL_GPL(kbd_table); static struct kbd_struct *kbd = kbd_table; struct vt_spawn_console vt_spawn_con = { @@ -260,6 +261,7 @@ void kd_mksound(unsigned int hz, unsigned int ticks) } else kd_nosound(0); } +EXPORT_SYMBOL(kd_mksound); /* * Setting the keyboard rate. @@ -1230,7 +1232,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) if (rep && (!vc_kbd_mode(kbd, VC_REPEAT) || - (tty && !L_ECHO(tty) && tty->driver->chars_in_buffer(tty)))) { + (tty && !L_ECHO(tty) && tty_chars_in_buffer(tty)))) { /* * Don't repeat a key if the input buffers are not empty and the * characters get aren't echoed locally. This makes key repeat diff --git a/drivers/char/mem.c b/drivers/char/mem.c index e83623ead441..934ffafedaea 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -364,6 +364,7 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma) return 0; } +#ifdef CONFIG_DEVKMEM static int mmap_kmem(struct file * file, struct vm_area_struct * vma) { unsigned long pfn; @@ -384,6 +385,7 @@ static int mmap_kmem(struct file * file, struct vm_area_struct * vma) vma->vm_pgoff = pfn; return mmap_mem(file, vma); } +#endif #ifdef CONFIG_CRASH_DUMP /* @@ -422,6 +424,7 @@ static ssize_t read_oldmem(struct file *file, char __user *buf, extern long vread(char *buf, char *addr, unsigned long count); extern long vwrite(char *buf, char *addr, unsigned long count); +#ifdef CONFIG_DEVKMEM /* * This function reads the *virtual* memory as seen by the kernel. */ @@ -626,6 +629,7 @@ static ssize_t write_kmem(struct file * file, const char __user * buf, *ppos = p; return virtr + wrote; } +#endif #ifdef CONFIG_DEVPORT static ssize_t read_port(struct file * file, char __user * buf, @@ -803,6 +807,7 @@ static const struct file_operations mem_fops = { .get_unmapped_area = get_unmapped_area_mem, }; +#ifdef CONFIG_DEVKMEM static const struct file_operations kmem_fops = { .llseek = memory_lseek, .read = read_kmem, @@ -811,6 +816,7 @@ static const struct file_operations kmem_fops = { .open = open_kmem, .get_unmapped_area = get_unmapped_area_mem, }; +#endif static const struct file_operations null_fops = { .llseek = null_lseek, @@ -889,11 +895,13 @@ static int memory_open(struct inode * inode, struct file * filp) filp->f_mapping->backing_dev_info = &directly_mappable_cdev_bdi; break; +#ifdef CONFIG_DEVKMEM case 2: filp->f_op = &kmem_fops; filp->f_mapping->backing_dev_info = &directly_mappable_cdev_bdi; break; +#endif case 3: filp->f_op = &null_fops; break; @@ -942,7 +950,9 @@ static const struct { const struct file_operations *fops; } devlist[] = { /* list of minor devices */ {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops}, +#ifdef CONFIG_DEVKMEM {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops}, +#endif {3, "null", S_IRUGO | S_IWUGO, &null_fops}, #ifdef CONFIG_DEVPORT {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops}, diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 4d058dadbfcc..eaace0db0ff4 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -263,23 +263,26 @@ EXPORT_SYMBOL(misc_deregister); static int __init misc_init(void) { -#ifdef CONFIG_PROC_FS - struct proc_dir_entry *ent; + int err; - ent = create_proc_entry("misc", 0, NULL); - if (ent) - ent->proc_fops = &misc_proc_fops; +#ifdef CONFIG_PROC_FS + proc_create("misc", 0, NULL, &misc_proc_fops); #endif misc_class = class_create(THIS_MODULE, "misc"); + err = PTR_ERR(misc_class); if (IS_ERR(misc_class)) - return PTR_ERR(misc_class); + goto fail_remove; - if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) { - printk("unable to get major %d for misc devices\n", - MISC_MAJOR); - class_destroy(misc_class); - return -EIO; - } + err = -EIO; + if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) + goto fail_printk; return 0; + +fail_printk: + printk("unable to get major %d for misc devices\n", MISC_MAJOR); + class_destroy(misc_class); +fail_remove: + remove_proc_entry("misc", NULL); + return err; } subsys_initcall(misc_init); diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c index e60a74c66e3d..d83db5d880e0 100644 --- a/drivers/char/mmtimer.c +++ b/drivers/char/mmtimer.c @@ -74,9 +74,8 @@ static const struct file_operations mmtimer_fops = { * We only have comparison registers RTC1-4 currently available per * node. RTC0 is used by SAL. */ -#define NUM_COMPARATORS 3 /* Check for an RTC interrupt pending */ -static int inline mmtimer_int_pending(int comparator) +static int mmtimer_int_pending(int comparator) { if (HUB_L((unsigned long *)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED)) & SH_EVENT_OCCURRED_RTC1_INT_MASK << comparator) @@ -84,15 +83,16 @@ static int inline mmtimer_int_pending(int comparator) else return 0; } + /* Clear the RTC interrupt pending bit */ -static void inline mmtimer_clr_int_pending(int comparator) +static void mmtimer_clr_int_pending(int comparator) { HUB_S((u64 *)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED_ALIAS), SH_EVENT_OCCURRED_RTC1_INT_MASK << comparator); } /* Setup timer on comparator RTC1 */ -static void inline mmtimer_setup_int_0(u64 expires) +static void mmtimer_setup_int_0(int cpu, u64 expires) { u64 val; @@ -106,7 +106,7 @@ static void inline mmtimer_setup_int_0(u64 expires) mmtimer_clr_int_pending(0); val = ((u64)SGI_MMTIMER_VECTOR << SH_RTC1_INT_CONFIG_IDX_SHFT) | - ((u64)cpu_physical_id(smp_processor_id()) << + ((u64)cpu_physical_id(cpu) << SH_RTC1_INT_CONFIG_PID_SHFT); /* Set configuration */ @@ -122,7 +122,7 @@ static void inline mmtimer_setup_int_0(u64 expires) } /* Setup timer on comparator RTC2 */ -static void inline mmtimer_setup_int_1(u64 expires) +static void mmtimer_setup_int_1(int cpu, u64 expires) { u64 val; @@ -133,7 +133,7 @@ static void inline mmtimer_setup_int_1(u64 expires) mmtimer_clr_int_pending(1); val = ((u64)SGI_MMTIMER_VECTOR << SH_RTC2_INT_CONFIG_IDX_SHFT) | - ((u64)cpu_physical_id(smp_processor_id()) << + ((u64)cpu_physical_id(cpu) << SH_RTC2_INT_CONFIG_PID_SHFT); HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC2_INT_CONFIG), val); @@ -144,7 +144,7 @@ static void inline mmtimer_setup_int_1(u64 expires) } /* Setup timer on comparator RTC3 */ -static void inline mmtimer_setup_int_2(u64 expires) +static void mmtimer_setup_int_2(int cpu, u64 expires) { u64 val; @@ -155,7 +155,7 @@ static void inline mmtimer_setup_int_2(u64 expires) mmtimer_clr_int_pending(2); val = ((u64)SGI_MMTIMER_VECTOR << SH_RTC3_INT_CONFIG_IDX_SHFT) | - ((u64)cpu_physical_id(smp_processor_id()) << + ((u64)cpu_physical_id(cpu) << SH_RTC3_INT_CONFIG_PID_SHFT); HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC3_INT_CONFIG), val); @@ -170,22 +170,22 @@ static void inline mmtimer_setup_int_2(u64 expires) * in order to insure that the setup succeeds in a deterministic time frame. * It will check if the interrupt setup succeeded. */ -static int inline mmtimer_setup(int comparator, unsigned long expires) +static int mmtimer_setup(int cpu, int comparator, unsigned long expires) { switch (comparator) { case 0: - mmtimer_setup_int_0(expires); + mmtimer_setup_int_0(cpu, expires); break; case 1: - mmtimer_setup_int_1(expires); + mmtimer_setup_int_1(cpu, expires); break; case 2: - mmtimer_setup_int_2(expires); + mmtimer_setup_int_2(cpu, expires); break; } /* We might've missed our expiration time */ - if (rtc_time() < expires) + if (rtc_time() <= expires) return 1; /* @@ -195,7 +195,7 @@ static int inline mmtimer_setup(int comparator, unsigned long expires) return mmtimer_int_pending(comparator); } -static int inline mmtimer_disable_int(long nasid, int comparator) +static int mmtimer_disable_int(long nasid, int comparator) { switch (comparator) { case 0: @@ -216,18 +216,124 @@ static int inline mmtimer_disable_int(long nasid, int comparator) return 0; } -#define TIMER_OFF 0xbadcabLL +#define COMPARATOR 1 /* The comparator to use */ -/* There is one of these for each comparator */ -typedef struct mmtimer { - spinlock_t lock ____cacheline_aligned; +#define TIMER_OFF 0xbadcabLL /* Timer is not setup */ +#define TIMER_SET 0 /* Comparator is set for this timer */ + +/* There is one of these for each timer */ +struct mmtimer { + struct rb_node list; struct k_itimer *timer; - int i; int cpu; +}; + +struct mmtimer_node { + spinlock_t lock ____cacheline_aligned; + struct rb_root timer_head; + struct rb_node *next; struct tasklet_struct tasklet; -} mmtimer_t; +}; +static struct mmtimer_node *timers; + + +/* + * Add a new mmtimer struct to the node's mmtimer list. + * This function assumes the struct mmtimer_node is locked. + */ +static void mmtimer_add_list(struct mmtimer *n) +{ + int nodeid = n->timer->it.mmtimer.node; + unsigned long expires = n->timer->it.mmtimer.expires; + struct rb_node **link = &timers[nodeid].timer_head.rb_node; + struct rb_node *parent = NULL; + struct mmtimer *x; + + /* + * Find the right place in the rbtree: + */ + while (*link) { + parent = *link; + x = rb_entry(parent, struct mmtimer, list); + + if (expires < x->timer->it.mmtimer.expires) + link = &(*link)->rb_left; + else + link = &(*link)->rb_right; + } + + /* + * Insert the timer to the rbtree and check whether it + * replaces the first pending timer + */ + rb_link_node(&n->list, parent, link); + rb_insert_color(&n->list, &timers[nodeid].timer_head); + + if (!timers[nodeid].next || expires < rb_entry(timers[nodeid].next, + struct mmtimer, list)->timer->it.mmtimer.expires) + timers[nodeid].next = &n->list; +} + +/* + * Set the comparator for the next timer. + * This function assumes the struct mmtimer_node is locked. + */ +static void mmtimer_set_next_timer(int nodeid) +{ + struct mmtimer_node *n = &timers[nodeid]; + struct mmtimer *x; + struct k_itimer *t; + int o; + +restart: + if (n->next == NULL) + return; -static mmtimer_t ** timers; + x = rb_entry(n->next, struct mmtimer, list); + t = x->timer; + if (!t->it.mmtimer.incr) { + /* Not an interval timer */ + if (!mmtimer_setup(x->cpu, COMPARATOR, + t->it.mmtimer.expires)) { + /* Late setup, fire now */ + tasklet_schedule(&n->tasklet); + } + return; + } + + /* Interval timer */ + o = 0; + while (!mmtimer_setup(x->cpu, COMPARATOR, t->it.mmtimer.expires)) { + unsigned long e, e1; + struct rb_node *next; + t->it.mmtimer.expires += t->it.mmtimer.incr << o; + t->it_overrun += 1 << o; + o++; + if (o > 20) { + printk(KERN_ALERT "mmtimer: cannot reschedule timer\n"); + t->it.mmtimer.clock = TIMER_OFF; + n->next = rb_next(&x->list); + rb_erase(&x->list, &n->timer_head); + kfree(x); + goto restart; + } + + e = t->it.mmtimer.expires; + next = rb_next(&x->list); + + if (next == NULL) + continue; + + e1 = rb_entry(next, struct mmtimer, list)-> + timer->it.mmtimer.expires; + if (e > e1) { + n->next = next; + rb_erase(&x->list, &n->timer_head); + mmtimer_add_list(x); + goto restart; + } + } +} /** * mmtimer_ioctl - ioctl interface for /dev/mmtimer @@ -390,35 +496,6 @@ static int sgi_clock_set(clockid_t clockid, struct timespec *tp) return 0; } -/* - * Schedule the next periodic interrupt. This function will attempt - * to schedule a periodic interrupt later if necessary. If the scheduling - * of an interrupt fails then the time to skip is lengthened - * exponentially in order to ensure that the next interrupt - * can be properly scheduled.. - */ -static int inline reschedule_periodic_timer(mmtimer_t *x) -{ - int n; - struct k_itimer *t = x->timer; - - t->it.mmtimer.clock = x->i; - t->it_overrun--; - - n = 0; - do { - - t->it.mmtimer.expires += t->it.mmtimer.incr << n; - t->it_overrun += 1 << n; - n++; - if (n > 20) - return 1; - - } while (!mmtimer_setup(x->i, t->it.mmtimer.expires)); - - return 0; -} - /** * mmtimer_interrupt - timer interrupt handler * @irq: irq received @@ -435,71 +512,75 @@ static int inline reschedule_periodic_timer(mmtimer_t *x) static irqreturn_t mmtimer_interrupt(int irq, void *dev_id) { - int i; unsigned long expires = 0; int result = IRQ_NONE; unsigned indx = cpu_to_node(smp_processor_id()); + struct mmtimer *base; - /* - * Do this once for each comparison register - */ - for (i = 0; i < NUM_COMPARATORS; i++) { - mmtimer_t *base = timers[indx] + i; - /* Make sure this doesn't get reused before tasklet_sched */ - spin_lock(&base->lock); - if (base->cpu == smp_processor_id()) { - if (base->timer) - expires = base->timer->it.mmtimer.expires; - /* expires test won't work with shared irqs */ - if ((mmtimer_int_pending(i) > 0) || - (expires && (expires < rtc_time()))) { - mmtimer_clr_int_pending(i); - tasklet_schedule(&base->tasklet); - result = IRQ_HANDLED; - } + spin_lock(&timers[indx].lock); + base = rb_entry(timers[indx].next, struct mmtimer, list); + if (base == NULL) { + spin_unlock(&timers[indx].lock); + return result; + } + + if (base->cpu == smp_processor_id()) { + if (base->timer) + expires = base->timer->it.mmtimer.expires; + /* expires test won't work with shared irqs */ + if ((mmtimer_int_pending(COMPARATOR) > 0) || + (expires && (expires <= rtc_time()))) { + mmtimer_clr_int_pending(COMPARATOR); + tasklet_schedule(&timers[indx].tasklet); + result = IRQ_HANDLED; } - spin_unlock(&base->lock); - expires = 0; } + spin_unlock(&timers[indx].lock); return result; } -void mmtimer_tasklet(unsigned long data) { - mmtimer_t *x = (mmtimer_t *)data; - struct k_itimer *t = x->timer; +static void mmtimer_tasklet(unsigned long data) +{ + int nodeid = data; + struct mmtimer_node *mn = &timers[nodeid]; + struct mmtimer *x = rb_entry(mn->next, struct mmtimer, list); + struct k_itimer *t; unsigned long flags; - if (t == NULL) - return; - /* Send signal and deal with periodic signals */ - spin_lock_irqsave(&t->it_lock, flags); - spin_lock(&x->lock); - /* If timer was deleted between interrupt and here, leave */ - if (t != x->timer) + spin_lock_irqsave(&mn->lock, flags); + if (!mn->next) goto out; - t->it_overrun = 0; - if (posix_timer_event(t, 0) != 0) { + x = rb_entry(mn->next, struct mmtimer, list); + t = x->timer; + + if (t->it.mmtimer.clock == TIMER_OFF) + goto out; + + t->it_overrun = 0; - // printk(KERN_WARNING "mmtimer: cannot deliver signal.\n"); + mn->next = rb_next(&x->list); + rb_erase(&x->list, &mn->timer_head); + if (posix_timer_event(t, 0) != 0) t->it_overrun++; - } + if(t->it.mmtimer.incr) { - /* Periodic timer */ - if (reschedule_periodic_timer(x)) { - printk(KERN_WARNING "mmtimer: unable to reschedule\n"); - x->timer = NULL; - } + t->it.mmtimer.expires += t->it.mmtimer.incr; + mmtimer_add_list(x); } else { /* Ensure we don't false trigger in mmtimer_interrupt */ + t->it.mmtimer.clock = TIMER_OFF; t->it.mmtimer.expires = 0; + kfree(x); } + /* Set comparator for next timer, if there is one */ + mmtimer_set_next_timer(nodeid); + t->it_overrun_last = t->it_overrun; out: - spin_unlock(&x->lock); - spin_unlock_irqrestore(&t->it_lock, flags); + spin_unlock_irqrestore(&mn->lock, flags); } static int sgi_timer_create(struct k_itimer *timer) @@ -516,19 +597,50 @@ static int sgi_timer_create(struct k_itimer *timer) */ static int sgi_timer_del(struct k_itimer *timr) { - int i = timr->it.mmtimer.clock; cnodeid_t nodeid = timr->it.mmtimer.node; - mmtimer_t *t = timers[nodeid] + i; unsigned long irqflags; - if (i != TIMER_OFF) { - spin_lock_irqsave(&t->lock, irqflags); - mmtimer_disable_int(cnodeid_to_nasid(nodeid),i); - t->timer = NULL; + spin_lock_irqsave(&timers[nodeid].lock, irqflags); + if (timr->it.mmtimer.clock != TIMER_OFF) { + unsigned long expires = timr->it.mmtimer.expires; + struct rb_node *n = timers[nodeid].timer_head.rb_node; + struct mmtimer *uninitialized_var(t); + int r = 0; + timr->it.mmtimer.clock = TIMER_OFF; timr->it.mmtimer.expires = 0; - spin_unlock_irqrestore(&t->lock, irqflags); + + while (n) { + t = rb_entry(n, struct mmtimer, list); + if (t->timer == timr) + break; + + if (expires < t->timer->it.mmtimer.expires) + n = n->rb_left; + else + n = n->rb_right; + } + + if (!n) { + spin_unlock_irqrestore(&timers[nodeid].lock, irqflags); + return 0; + } + + if (timers[nodeid].next == n) { + timers[nodeid].next = rb_next(n); + r = 1; + } + + rb_erase(n, &timers[nodeid].timer_head); + kfree(t); + + if (r) { + mmtimer_disable_int(cnodeid_to_nasid(nodeid), + COMPARATOR); + mmtimer_set_next_timer(nodeid); + } } + spin_unlock_irqrestore(&timers[nodeid].lock, irqflags); return 0; } @@ -557,12 +669,11 @@ static int sgi_timer_set(struct k_itimer *timr, int flags, struct itimerspec * new_setting, struct itimerspec * old_setting) { - - int i; unsigned long when, period, irqflags; int err = 0; cnodeid_t nodeid; - mmtimer_t *base; + struct mmtimer *base; + struct rb_node *n; if (old_setting) sgi_timer_get(timr, old_setting); @@ -575,6 +686,10 @@ static int sgi_timer_set(struct k_itimer *timr, int flags, /* Clear timer */ return 0; + base = kmalloc(sizeof(struct mmtimer), GFP_KERNEL); + if (base == NULL) + return -ENOMEM; + if (flags & TIMER_ABSTIME) { struct timespec n; unsigned long now; @@ -604,47 +719,38 @@ static int sgi_timer_set(struct k_itimer *timr, int flags, preempt_disable(); nodeid = cpu_to_node(smp_processor_id()); -retry: - /* Don't use an allocated timer, or a deleted one that's pending */ - for(i = 0; i< NUM_COMPARATORS; i++) { - base = timers[nodeid] + i; - if (!base->timer && !base->tasklet.state) { - break; - } - } - - if (i == NUM_COMPARATORS) { - preempt_enable(); - return -EBUSY; - } - spin_lock_irqsave(&base->lock, irqflags); + /* Lock the node timer structure */ + spin_lock_irqsave(&timers[nodeid].lock, irqflags); - if (base->timer || base->tasklet.state != 0) { - spin_unlock_irqrestore(&base->lock, irqflags); - goto retry; - } base->timer = timr; base->cpu = smp_processor_id(); - timr->it.mmtimer.clock = i; + timr->it.mmtimer.clock = TIMER_SET; timr->it.mmtimer.node = nodeid; timr->it.mmtimer.incr = period; timr->it.mmtimer.expires = when; - if (period == 0) { - if (!mmtimer_setup(i, when)) { - mmtimer_disable_int(-1, i); - posix_timer_event(timr, 0); - timr->it.mmtimer.expires = 0; - } - } else { - timr->it.mmtimer.expires -= period; - if (reschedule_periodic_timer(base)) - err = -EINVAL; + n = timers[nodeid].next; + + /* Add the new struct mmtimer to node's timer list */ + mmtimer_add_list(base); + + if (timers[nodeid].next == n) { + /* No need to reprogram comparator for now */ + spin_unlock_irqrestore(&timers[nodeid].lock, irqflags); + preempt_enable(); + return err; } - spin_unlock_irqrestore(&base->lock, irqflags); + /* We need to reprogram the comparator */ + if (n) + mmtimer_disable_int(cnodeid_to_nasid(nodeid), COMPARATOR); + + mmtimer_set_next_timer(nodeid); + + /* Unlock the node timer structure */ + spin_unlock_irqrestore(&timers[nodeid].lock, irqflags); preempt_enable(); @@ -669,7 +775,6 @@ static struct k_clock sgi_clock = { */ static int __init mmtimer_init(void) { - unsigned i; cnodeid_t node, maxn = -1; if (!ia64_platform_is("sn2")) @@ -706,31 +811,18 @@ static int __init mmtimer_init(void) maxn++; /* Allocate list of node ptrs to mmtimer_t's */ - timers = kzalloc(sizeof(mmtimer_t *)*maxn, GFP_KERNEL); + timers = kzalloc(sizeof(struct mmtimer_node)*maxn, GFP_KERNEL); if (timers == NULL) { printk(KERN_ERR "%s: failed to allocate memory for device\n", MMTIMER_NAME); goto out3; } - /* Allocate mmtimer_t's for each online node */ + /* Initialize struct mmtimer's for each online node */ for_each_online_node(node) { - timers[node] = kmalloc_node(sizeof(mmtimer_t)*NUM_COMPARATORS, GFP_KERNEL, node); - if (timers[node] == NULL) { - printk(KERN_ERR "%s: failed to allocate memory for device\n", - MMTIMER_NAME); - goto out4; - } - for (i=0; i< NUM_COMPARATORS; i++) { - mmtimer_t * base = timers[node] + i; - - spin_lock_init(&base->lock); - base->timer = NULL; - base->cpu = 0; - base->i = i; - tasklet_init(&base->tasklet, mmtimer_tasklet, - (unsigned long) (base)); - } + spin_lock_init(&timers[node].lock); + tasklet_init(&timers[node].tasklet, mmtimer_tasklet, + (unsigned long) node); } sgi_clock_period = sgi_clock.res = NSEC_PER_SEC / sn_rtc_cycles_per_second; @@ -741,11 +833,8 @@ static int __init mmtimer_init(void) return 0; -out4: - for_each_online_node(node) { - kfree(timers[node]); - } out3: + kfree(timers); misc_deregister(&mmtimer_miscdev); out2: free_irq(SGI_MMTIMER_VECTOR, NULL); @@ -754,4 +843,3 @@ out1: } module_init(mmtimer_init); - diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index 64b7b2b18352..d57d3a61919b 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -2,7 +2,8 @@ /* * moxa.c -- MOXA Intellio family multiport serial driver. * - * Copyright (C) 1999-2000 Moxa Technologies (support@moxa.com.tw). + * Copyright (C) 1999-2000 Moxa Technologies (support@moxa.com). + * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com> * * This code is loosely based on the Linux serial driver, written by * Linus Torvalds, Theodore T'so and others. @@ -25,6 +26,7 @@ #include <linux/mm.h> #include <linux/ioport.h> #include <linux/errno.h> +#include <linux/firmware.h> #include <linux/signal.h> #include <linux/sched.h> #include <linux/timer.h> @@ -41,21 +43,26 @@ #include <linux/pci.h> #include <linux/init.h> #include <linux/bitops.h> -#include <linux/completion.h> #include <asm/system.h> #include <asm/io.h> #include <asm/uaccess.h> -#define MOXA_VERSION "5.1k" +#include "moxa.h" + +#define MOXA_VERSION "6.0k" + +#define MOXA_FW_HDRLEN 32 #define MOXAMAJOR 172 -#define MOXACUMAJOR 173 #define MAX_BOARDS 4 /* Don't change this value */ #define MAX_PORTS_PER_BOARD 32 /* Don't change this value */ #define MAX_PORTS (MAX_BOARDS * MAX_PORTS_PER_BOARD) +#define MOXA_IS_320(brd) ((brd)->boardType == MOXA_BOARD_C320_ISA || \ + (brd)->boardType == MOXA_BOARD_C320_PCI) + /* * Define the Moxa PCI vendor and device IDs. */ @@ -92,24 +99,16 @@ static struct pci_device_id moxa_pcibrds[] = { MODULE_DEVICE_TABLE(pci, moxa_pcibrds); #endif /* CONFIG_PCI */ -struct moxa_isa_board_conf { - int boardType; - int numPorts; - unsigned long baseAddr; -}; - -static struct moxa_isa_board_conf moxa_isa_boards[] = -{ -/* {MOXA_BOARD_C218_ISA,8,0xDC000}, */ -}; +struct moxa_port; static struct moxa_board_conf { int boardType; int numPorts; - unsigned long baseAddr; int busType; - int loadstat; + unsigned int ready; + + struct moxa_port *ports; void __iomem *basemem; void __iomem *intNdx; @@ -131,30 +130,27 @@ struct moxaq_str { }; struct moxa_port { + struct moxa_board_conf *board; + struct tty_struct *tty; + void __iomem *tableAddr; + int type; - int port; int close_delay; - unsigned short closing_wait; - int count; - int blocked_open; - long event; /* long req'd for set_bit --RR */ + unsigned int count; int asyncflags; - unsigned long statusflags; - struct tty_struct *tty; int cflag; + unsigned long statusflags; wait_queue_head_t open_wait; - struct completion close_wait; - - struct timer_list emptyTimer; - char chkPort; - char lineCtrl; - void __iomem *tableAddr; - long curBaud; - char DCDState; - char lowChkFlag; + u8 DCDState; + u8 lineCtrl; + u8 lowChkFlag; +}; - ushort breakCnt; +struct mon_str { + int tick; + int rxcnt[MAX_PORTS]; + int txcnt[MAX_PORTS]; }; /* statusflags */ @@ -168,20 +164,27 @@ struct moxa_port { #define WAKEUP_CHARS 256 static int ttymajor = MOXAMAJOR; +static struct mon_str moxaLog; +static unsigned int moxaFuncTout = HZ / 2; +static unsigned int moxaLowWaterChk; +static DEFINE_MUTEX(moxa_openlock); /* Variables for insmod */ #ifdef MODULE -static int baseaddr[4]; -static int type[4]; -static int numports[4]; +static unsigned long baseaddr[MAX_BOARDS]; +static unsigned int type[MAX_BOARDS]; +static unsigned int numports[MAX_BOARDS]; #endif MODULE_AUTHOR("William Chen"); MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver"); MODULE_LICENSE("GPL"); #ifdef MODULE -module_param_array(type, int, NULL, 0); -module_param_array(baseaddr, int, NULL, 0); -module_param_array(numports, int, NULL, 0); +module_param_array(type, uint, NULL, 0); +MODULE_PARM_DESC(type, "card type: C218=2, C320=4"); +module_param_array(baseaddr, ulong, NULL, 0); +MODULE_PARM_DESC(baseaddr, "base address"); +module_param_array(numports, uint, NULL, 0); +MODULE_PARM_DESC(numports, "numports (ignored for C218)"); #endif module_param(ttymajor, int, 0); @@ -194,9 +197,6 @@ static int moxa_write(struct tty_struct *, const unsigned char *, int); static int moxa_write_room(struct tty_struct *); static void moxa_flush_buffer(struct tty_struct *); static int moxa_chars_in_buffer(struct tty_struct *); -static void moxa_flush_chars(struct tty_struct *); -static void moxa_put_char(struct tty_struct *, unsigned char); -static int moxa_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long); static void moxa_throttle(struct tty_struct *); static void moxa_unthrottle(struct tty_struct *); static void moxa_set_termios(struct tty_struct *, struct ktermios *); @@ -208,44 +208,183 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); static void moxa_poll(unsigned long); static void moxa_set_tty_param(struct tty_struct *, struct ktermios *); -static int moxa_block_till_ready(struct tty_struct *, struct file *, - struct moxa_port *); static void moxa_setup_empty_event(struct tty_struct *); -static void moxa_check_xmit_empty(unsigned long); static void moxa_shut_down(struct moxa_port *); -static void moxa_receive_data(struct moxa_port *); /* * moxa board interface functions: */ -static void MoxaDriverInit(void); -static int MoxaDriverIoctl(unsigned int, unsigned long, int); -static int MoxaDriverPoll(void); -static int MoxaPortsOfCard(int); -static int MoxaPortIsValid(int); -static void MoxaPortEnable(int); -static void MoxaPortDisable(int); -static long MoxaPortGetMaxBaud(int); -static long MoxaPortSetBaud(int, long); -static int MoxaPortSetTermio(int, struct ktermios *, speed_t); -static int MoxaPortGetLineOut(int, int *, int *); -static void MoxaPortLineCtrl(int, int, int); -static void MoxaPortFlowCtrl(int, int, int, int, int, int); -static int MoxaPortLineStatus(int); -static int MoxaPortDCDChange(int); -static int MoxaPortDCDON(int); -static void MoxaPortFlushData(int, int); -static int MoxaPortWriteData(int, unsigned char *, int); -static int MoxaPortReadData(int, struct tty_struct *tty); -static int MoxaPortTxQueue(int); -static int MoxaPortRxQueue(int); -static int MoxaPortTxFree(int); -static void MoxaPortTxDisable(int); -static void MoxaPortTxEnable(int); -static int MoxaPortResetBrkCnt(int); -static void MoxaPortSendBreak(int, int); +static void MoxaPortEnable(struct moxa_port *); +static void MoxaPortDisable(struct moxa_port *); +static int MoxaPortSetTermio(struct moxa_port *, struct ktermios *, speed_t); +static int MoxaPortGetLineOut(struct moxa_port *, int *, int *); +static void MoxaPortLineCtrl(struct moxa_port *, int, int); +static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int); +static int MoxaPortLineStatus(struct moxa_port *); +static void MoxaPortFlushData(struct moxa_port *, int); +static int MoxaPortWriteData(struct moxa_port *, const unsigned char *, int); +static int MoxaPortReadData(struct moxa_port *); +static int MoxaPortTxQueue(struct moxa_port *); +static int MoxaPortRxQueue(struct moxa_port *); +static int MoxaPortTxFree(struct moxa_port *); +static void MoxaPortTxDisable(struct moxa_port *); +static void MoxaPortTxEnable(struct moxa_port *); static int moxa_get_serial_info(struct moxa_port *, struct serial_struct __user *); static int moxa_set_serial_info(struct moxa_port *, struct serial_struct __user *); -static void MoxaSetFifo(int port, int enable); +static void MoxaSetFifo(struct moxa_port *port, int enable); + +/* + * I/O functions + */ + +static void moxa_wait_finish(void __iomem *ofsAddr) +{ + unsigned long end = jiffies + moxaFuncTout; + + while (readw(ofsAddr + FuncCode) != 0) + if (time_after(jiffies, end)) + return; + if (readw(ofsAddr + FuncCode) != 0 && printk_ratelimit()) + printk(KERN_WARNING "moxa function expired\n"); +} + +static void moxafunc(void __iomem *ofsAddr, u16 cmd, u16 arg) +{ + writew(arg, ofsAddr + FuncArg); + writew(cmd, ofsAddr + FuncCode); + moxa_wait_finish(ofsAddr); +} + +static void moxa_low_water_check(void __iomem *ofsAddr) +{ + u16 rptr, wptr, mask, len; + + if (readb(ofsAddr + FlagStat) & Xoff_state) { + rptr = readw(ofsAddr + RXrptr); + wptr = readw(ofsAddr + RXwptr); + mask = readw(ofsAddr + RX_mask); + len = (wptr - rptr) & mask; + if (len <= Low_water) + moxafunc(ofsAddr, FC_SendXon, 0); + } +} + +/* + * TTY operations + */ + +static int moxa_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct moxa_port *ch = tty->driver_data; + void __user *argp = (void __user *)arg; + int status, ret = 0; + + if (tty->index == MAX_PORTS) { + if (cmd != MOXA_GETDATACOUNT && cmd != MOXA_GET_IOQUEUE && + cmd != MOXA_GETMSTATUS) + return -EINVAL; + } else if (!ch) + return -ENODEV; + + switch (cmd) { + case MOXA_GETDATACOUNT: + moxaLog.tick = jiffies; + if (copy_to_user(argp, &moxaLog, sizeof(moxaLog))) + ret = -EFAULT; + break; + case MOXA_FLUSH_QUEUE: + MoxaPortFlushData(ch, arg); + break; + case MOXA_GET_IOQUEUE: { + struct moxaq_str __user *argm = argp; + struct moxaq_str tmp; + struct moxa_port *p; + unsigned int i, j; + + mutex_lock(&moxa_openlock); + for (i = 0; i < MAX_BOARDS; i++) { + p = moxa_boards[i].ports; + for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) { + memset(&tmp, 0, sizeof(tmp)); + if (moxa_boards[i].ready) { + tmp.inq = MoxaPortRxQueue(p); + tmp.outq = MoxaPortTxQueue(p); + } + if (copy_to_user(argm, &tmp, sizeof(tmp))) { + mutex_unlock(&moxa_openlock); + return -EFAULT; + } + } + } + mutex_unlock(&moxa_openlock); + break; + } case MOXA_GET_OQUEUE: + status = MoxaPortTxQueue(ch); + ret = put_user(status, (unsigned long __user *)argp); + break; + case MOXA_GET_IQUEUE: + status = MoxaPortRxQueue(ch); + ret = put_user(status, (unsigned long __user *)argp); + break; + case MOXA_GETMSTATUS: { + struct mxser_mstatus __user *argm = argp; + struct mxser_mstatus tmp; + struct moxa_port *p; + unsigned int i, j; + + mutex_lock(&moxa_openlock); + for (i = 0; i < MAX_BOARDS; i++) { + p = moxa_boards[i].ports; + for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) { + memset(&tmp, 0, sizeof(tmp)); + if (!moxa_boards[i].ready) + goto copy; + + status = MoxaPortLineStatus(p); + if (status & 1) + tmp.cts = 1; + if (status & 2) + tmp.dsr = 1; + if (status & 4) + tmp.dcd = 1; + + if (!p->tty || !p->tty->termios) + tmp.cflag = p->cflag; + else + tmp.cflag = p->tty->termios->c_cflag; +copy: + if (copy_to_user(argm, &tmp, sizeof(tmp))) { + mutex_unlock(&moxa_openlock); + return -EFAULT; + } + } + } + mutex_unlock(&moxa_openlock); + break; + } + case TIOCGSERIAL: + mutex_lock(&moxa_openlock); + ret = moxa_get_serial_info(ch, argp); + mutex_unlock(&moxa_openlock); + break; + case TIOCSSERIAL: + mutex_lock(&moxa_openlock); + ret = moxa_set_serial_info(ch, argp); + mutex_unlock(&moxa_openlock); + break; + default: + ret = -ENOIOCTLCMD; + } + return ret; +} + +static void moxa_break_ctl(struct tty_struct *tty, int state) +{ + struct moxa_port *port = tty->driver_data; + + moxafunc(port->tableAddr, state ? FC_SendBreak : FC_StopBreak, + Magic_code); +} static const struct tty_operations moxa_ops = { .open = moxa_open, @@ -254,8 +393,6 @@ static const struct tty_operations moxa_ops = { .write_room = moxa_write_room, .flush_buffer = moxa_flush_buffer, .chars_in_buffer = moxa_chars_in_buffer, - .flush_chars = moxa_flush_chars, - .put_char = moxa_put_char, .ioctl = moxa_ioctl, .throttle = moxa_throttle, .unthrottle = moxa_unthrottle, @@ -263,15 +400,509 @@ static const struct tty_operations moxa_ops = { .stop = moxa_stop, .start = moxa_start, .hangup = moxa_hangup, + .break_ctl = moxa_break_ctl, .tiocmget = moxa_tiocmget, .tiocmset = moxa_tiocmset, }; static struct tty_driver *moxaDriver; -static struct moxa_port moxa_ports[MAX_PORTS]; static DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0); static DEFINE_SPINLOCK(moxa_lock); +/* + * HW init + */ + +static int moxa_check_fw_model(struct moxa_board_conf *brd, u8 model) +{ + switch (brd->boardType) { + case MOXA_BOARD_C218_ISA: + case MOXA_BOARD_C218_PCI: + if (model != 1) + goto err; + break; + case MOXA_BOARD_CP204J: + if (model != 3) + goto err; + break; + default: + if (model != 2) + goto err; + break; + } + return 0; +err: + return -EINVAL; +} + +static int moxa_check_fw(const void *ptr) +{ + const __le16 *lptr = ptr; + + if (*lptr != cpu_to_le16(0x7980)) + return -EINVAL; + + return 0; +} + +static int moxa_load_bios(struct moxa_board_conf *brd, const u8 *buf, + size_t len) +{ + void __iomem *baseAddr = brd->basemem; + u16 tmp; + + writeb(HW_reset, baseAddr + Control_reg); /* reset */ + msleep(10); + memset_io(baseAddr, 0, 4096); + memcpy_toio(baseAddr, buf, len); /* download BIOS */ + writeb(0, baseAddr + Control_reg); /* restart */ + + msleep(2000); + + switch (brd->boardType) { + case MOXA_BOARD_C218_ISA: + case MOXA_BOARD_C218_PCI: + tmp = readw(baseAddr + C218_key); + if (tmp != C218_KeyCode) + goto err; + break; + case MOXA_BOARD_CP204J: + tmp = readw(baseAddr + C218_key); + if (tmp != CP204J_KeyCode) + goto err; + break; + default: + tmp = readw(baseAddr + C320_key); + if (tmp != C320_KeyCode) + goto err; + tmp = readw(baseAddr + C320_status); + if (tmp != STS_init) { + printk(KERN_ERR "MOXA: bios upload failed -- CPU/Basic " + "module not found\n"); + return -EIO; + } + break; + } + + return 0; +err: + printk(KERN_ERR "MOXA: bios upload failed -- board not found\n"); + return -EIO; +} + +static int moxa_load_320b(struct moxa_board_conf *brd, const u8 *ptr, + size_t len) +{ + void __iomem *baseAddr = brd->basemem; + + if (len < 7168) { + printk(KERN_ERR "MOXA: invalid 320 bios -- too short\n"); + return -EINVAL; + } + + writew(len - 7168 - 2, baseAddr + C320bapi_len); + writeb(1, baseAddr + Control_reg); /* Select Page 1 */ + memcpy_toio(baseAddr + DynPage_addr, ptr, 7168); + writeb(2, baseAddr + Control_reg); /* Select Page 2 */ + memcpy_toio(baseAddr + DynPage_addr, ptr + 7168, len - 7168); + + return 0; +} + +static int moxa_real_load_code(struct moxa_board_conf *brd, const void *ptr, + size_t len) +{ + void __iomem *baseAddr = brd->basemem; + const u16 *uptr = ptr; + size_t wlen, len2, j; + unsigned long key, loadbuf, loadlen, checksum, checksum_ok; + unsigned int i, retry; + u16 usum, keycode; + + keycode = (brd->boardType == MOXA_BOARD_CP204J) ? CP204J_KeyCode : + C218_KeyCode; + + switch (brd->boardType) { + case MOXA_BOARD_CP204J: + case MOXA_BOARD_C218_ISA: + case MOXA_BOARD_C218_PCI: + key = C218_key; + loadbuf = C218_LoadBuf; + loadlen = C218DLoad_len; + checksum = C218check_sum; + checksum_ok = C218chksum_ok; + break; + default: + key = C320_key; + keycode = C320_KeyCode; + loadbuf = C320_LoadBuf; + loadlen = C320DLoad_len; + checksum = C320check_sum; + checksum_ok = C320chksum_ok; + break; + } + + usum = 0; + wlen = len >> 1; + for (i = 0; i < wlen; i++) + usum += le16_to_cpu(uptr[i]); + retry = 0; + do { + wlen = len >> 1; + j = 0; + while (wlen) { + len2 = (wlen > 2048) ? 2048 : wlen; + wlen -= len2; + memcpy_toio(baseAddr + loadbuf, ptr + j, len2 << 1); + j += len2 << 1; + + writew(len2, baseAddr + loadlen); + writew(0, baseAddr + key); + for (i = 0; i < 100; i++) { + if (readw(baseAddr + key) == keycode) + break; + msleep(10); + } + if (readw(baseAddr + key) != keycode) + return -EIO; + } + writew(0, baseAddr + loadlen); + writew(usum, baseAddr + checksum); + writew(0, baseAddr + key); + for (i = 0; i < 100; i++) { + if (readw(baseAddr + key) == keycode) + break; + msleep(10); + } + retry++; + } while ((readb(baseAddr + checksum_ok) != 1) && (retry < 3)); + if (readb(baseAddr + checksum_ok) != 1) + return -EIO; + + writew(0, baseAddr + key); + for (i = 0; i < 600; i++) { + if (readw(baseAddr + Magic_no) == Magic_code) + break; + msleep(10); + } + if (readw(baseAddr + Magic_no) != Magic_code) + return -EIO; + + if (MOXA_IS_320(brd)) { + if (brd->busType == MOXA_BUS_TYPE_PCI) { /* ASIC board */ + writew(0x3800, baseAddr + TMS320_PORT1); + writew(0x3900, baseAddr + TMS320_PORT2); + writew(28499, baseAddr + TMS320_CLOCK); + } else { + writew(0x3200, baseAddr + TMS320_PORT1); + writew(0x3400, baseAddr + TMS320_PORT2); + writew(19999, baseAddr + TMS320_CLOCK); + } + } + writew(1, baseAddr + Disable_IRQ); + writew(0, baseAddr + Magic_no); + for (i = 0; i < 500; i++) { + if (readw(baseAddr + Magic_no) == Magic_code) + break; + msleep(10); + } + if (readw(baseAddr + Magic_no) != Magic_code) + return -EIO; + + if (MOXA_IS_320(brd)) { + j = readw(baseAddr + Module_cnt); + if (j <= 0) + return -EIO; + brd->numPorts = j * 8; + writew(j, baseAddr + Module_no); + writew(0, baseAddr + Magic_no); + for (i = 0; i < 600; i++) { + if (readw(baseAddr + Magic_no) == Magic_code) + break; + msleep(10); + } + if (readw(baseAddr + Magic_no) != Magic_code) + return -EIO; + } + brd->intNdx = baseAddr + IRQindex; + brd->intPend = baseAddr + IRQpending; + brd->intTable = baseAddr + IRQtable; + + return 0; +} + +static int moxa_load_code(struct moxa_board_conf *brd, const void *ptr, + size_t len) +{ + void __iomem *ofsAddr, *baseAddr = brd->basemem; + struct moxa_port *port; + int retval, i; + + if (len % 2) { + printk(KERN_ERR "MOXA: bios length is not even\n"); + return -EINVAL; + } + + retval = moxa_real_load_code(brd, ptr, len); /* may change numPorts */ + if (retval) + return retval; + + switch (brd->boardType) { + case MOXA_BOARD_C218_ISA: + case MOXA_BOARD_C218_PCI: + case MOXA_BOARD_CP204J: + port = brd->ports; + for (i = 0; i < brd->numPorts; i++, port++) { + port->board = brd; + port->DCDState = 0; + port->tableAddr = baseAddr + Extern_table + + Extern_size * i; + ofsAddr = port->tableAddr; + writew(C218rx_mask, ofsAddr + RX_mask); + writew(C218tx_mask, ofsAddr + TX_mask); + writew(C218rx_spage + i * C218buf_pageno, ofsAddr + Page_rxb); + writew(readw(ofsAddr + Page_rxb) + C218rx_pageno, ofsAddr + EndPage_rxb); + + writew(C218tx_spage + i * C218buf_pageno, ofsAddr + Page_txb); + writew(readw(ofsAddr + Page_txb) + C218tx_pageno, ofsAddr + EndPage_txb); + + } + break; + default: + port = brd->ports; + for (i = 0; i < brd->numPorts; i++, port++) { + port->board = brd; + port->DCDState = 0; + port->tableAddr = baseAddr + Extern_table + + Extern_size * i; + ofsAddr = port->tableAddr; + switch (brd->numPorts) { + case 8: + writew(C320p8rx_mask, ofsAddr + RX_mask); + writew(C320p8tx_mask, ofsAddr + TX_mask); + writew(C320p8rx_spage + i * C320p8buf_pgno, ofsAddr + Page_rxb); + writew(readw(ofsAddr + Page_rxb) + C320p8rx_pgno, ofsAddr + EndPage_rxb); + writew(C320p8tx_spage + i * C320p8buf_pgno, ofsAddr + Page_txb); + writew(readw(ofsAddr + Page_txb) + C320p8tx_pgno, ofsAddr + EndPage_txb); + + break; + case 16: + writew(C320p16rx_mask, ofsAddr + RX_mask); + writew(C320p16tx_mask, ofsAddr + TX_mask); + writew(C320p16rx_spage + i * C320p16buf_pgno, ofsAddr + Page_rxb); + writew(readw(ofsAddr + Page_rxb) + C320p16rx_pgno, ofsAddr + EndPage_rxb); + writew(C320p16tx_spage + i * C320p16buf_pgno, ofsAddr + Page_txb); + writew(readw(ofsAddr + Page_txb) + C320p16tx_pgno, ofsAddr + EndPage_txb); + break; + + case 24: + writew(C320p24rx_mask, ofsAddr + RX_mask); + writew(C320p24tx_mask, ofsAddr + TX_mask); + writew(C320p24rx_spage + i * C320p24buf_pgno, ofsAddr + Page_rxb); + writew(readw(ofsAddr + Page_rxb) + C320p24rx_pgno, ofsAddr + EndPage_rxb); + writew(C320p24tx_spage + i * C320p24buf_pgno, ofsAddr + Page_txb); + writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb); + break; + case 32: + writew(C320p32rx_mask, ofsAddr + RX_mask); + writew(C320p32tx_mask, ofsAddr + TX_mask); + writew(C320p32tx_ofs, ofsAddr + Ofs_txb); + writew(C320p32rx_spage + i * C320p32buf_pgno, ofsAddr + Page_rxb); + writew(readb(ofsAddr + Page_rxb), ofsAddr + EndPage_rxb); + writew(C320p32tx_spage + i * C320p32buf_pgno, ofsAddr + Page_txb); + writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb); + break; + } + } + break; + } + return 0; +} + +static int moxa_load_fw(struct moxa_board_conf *brd, const struct firmware *fw) +{ + void *ptr = fw->data; + char rsn[64]; + u16 lens[5]; + size_t len; + unsigned int a, lenp, lencnt; + int ret = -EINVAL; + struct { + __le32 magic; /* 0x34303430 */ + u8 reserved1[2]; + u8 type; /* UNIX = 3 */ + u8 model; /* C218T=1, C320T=2, CP204=3 */ + u8 reserved2[8]; + __le16 len[5]; + } *hdr = ptr; + + BUILD_BUG_ON(ARRAY_SIZE(hdr->len) != ARRAY_SIZE(lens)); + + if (fw->size < MOXA_FW_HDRLEN) { + strcpy(rsn, "too short (even header won't fit)"); + goto err; + } + if (hdr->magic != cpu_to_le32(0x30343034)) { + sprintf(rsn, "bad magic: %.8x", le32_to_cpu(hdr->magic)); + goto err; + } + if (hdr->type != 3) { + sprintf(rsn, "not for linux, type is %u", hdr->type); + goto err; + } + if (moxa_check_fw_model(brd, hdr->model)) { + sprintf(rsn, "not for this card, model is %u", hdr->model); + goto err; + } + + len = MOXA_FW_HDRLEN; + lencnt = hdr->model == 2 ? 5 : 3; + for (a = 0; a < ARRAY_SIZE(lens); a++) { + lens[a] = le16_to_cpu(hdr->len[a]); + if (lens[a] && len + lens[a] <= fw->size && + moxa_check_fw(&fw->data[len])) + printk(KERN_WARNING "MOXA firmware: unexpected input " + "at offset %u, but going on\n", (u32)len); + if (!lens[a] && a < lencnt) { + sprintf(rsn, "too few entries in fw file"); + goto err; + } + len += lens[a]; + } + + if (len != fw->size) { + sprintf(rsn, "bad length: %u (should be %u)", (u32)fw->size, + (u32)len); + goto err; + } + + ptr += MOXA_FW_HDRLEN; + lenp = 0; /* bios */ + + strcpy(rsn, "read above"); + + ret = moxa_load_bios(brd, ptr, lens[lenp]); + if (ret) + goto err; + + /* we skip the tty section (lens[1]), since we don't need it */ + ptr += lens[lenp] + lens[lenp + 1]; + lenp += 2; /* comm */ + + if (hdr->model == 2) { + ret = moxa_load_320b(brd, ptr, lens[lenp]); + if (ret) + goto err; + /* skip another tty */ + ptr += lens[lenp] + lens[lenp + 1]; + lenp += 2; + } + + ret = moxa_load_code(brd, ptr, lens[lenp]); + if (ret) + goto err; + + return 0; +err: + printk(KERN_ERR "firmware failed to load, reason: %s\n", rsn); + return ret; +} + +static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev) +{ + const struct firmware *fw; + const char *file; + struct moxa_port *p; + unsigned int i; + int ret; + + brd->ports = kcalloc(MAX_PORTS_PER_BOARD, sizeof(*brd->ports), + GFP_KERNEL); + if (brd->ports == NULL) { + printk(KERN_ERR "cannot allocate memory for ports\n"); + ret = -ENOMEM; + goto err; + } + + for (i = 0, p = brd->ports; i < MAX_PORTS_PER_BOARD; i++, p++) { + p->type = PORT_16550A; + p->close_delay = 5 * HZ / 10; + p->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; + init_waitqueue_head(&p->open_wait); + } + + switch (brd->boardType) { + case MOXA_BOARD_C218_ISA: + case MOXA_BOARD_C218_PCI: + file = "c218tunx.cod"; + break; + case MOXA_BOARD_CP204J: + file = "cp204unx.cod"; + break; + default: + file = "c320tunx.cod"; + break; + } + + ret = request_firmware(&fw, file, dev); + if (ret) { + printk(KERN_ERR "MOXA: request_firmware failed. Make sure " + "you've placed '%s' file into your firmware " + "loader directory (e.g. /lib/firmware)\n", + file); + goto err_free; + } + + ret = moxa_load_fw(brd, fw); + + release_firmware(fw); + + if (ret) + goto err_free; + + spin_lock_bh(&moxa_lock); + brd->ready = 1; + if (!timer_pending(&moxaTimer)) + mod_timer(&moxaTimer, jiffies + HZ / 50); + spin_unlock_bh(&moxa_lock); + + return 0; +err_free: + kfree(brd->ports); +err: + return ret; +} + +static void moxa_board_deinit(struct moxa_board_conf *brd) +{ + unsigned int a, opened; + + mutex_lock(&moxa_openlock); + spin_lock_bh(&moxa_lock); + brd->ready = 0; + spin_unlock_bh(&moxa_lock); + + /* pci hot-un-plug support */ + for (a = 0; a < brd->numPorts; a++) + if (brd->ports[a].asyncflags & ASYNC_INITIALIZED) + tty_hangup(brd->ports[a].tty); + while (1) { + opened = 0; + for (a = 0; a < brd->numPorts; a++) + if (brd->ports[a].asyncflags & ASYNC_INITIALIZED) + opened++; + mutex_unlock(&moxa_openlock); + if (!opened) + break; + msleep(50); + mutex_lock(&moxa_openlock); + } + + iounmap(brd->basemem); + brd->basemem = NULL; + kfree(brd->ports); +} + #ifdef CONFIG_PCI static int __devinit moxa_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -299,10 +930,17 @@ static int __devinit moxa_pci_probe(struct pci_dev *pdev, } board = &moxa_boards[i]; - board->basemem = pci_iomap(pdev, 2, 0x4000); + + retval = pci_request_region(pdev, 2, "moxa-base"); + if (retval) { + dev_err(&pdev->dev, "can't request pci region 2\n"); + goto err; + } + + board->basemem = ioremap_nocache(pci_resource_start(pdev, 2), 0x4000); if (board->basemem == NULL) { dev_err(&pdev->dev, "can't remap io space 2\n"); - goto err; + goto err_reg; } board->boardType = board_type; @@ -321,9 +959,21 @@ static int __devinit moxa_pci_probe(struct pci_dev *pdev, } board->busType = MOXA_BUS_TYPE_PCI; + retval = moxa_init_board(board, &pdev->dev); + if (retval) + goto err_base; + pci_set_drvdata(pdev, board); - return (0); + dev_info(&pdev->dev, "board '%s' ready (%u ports, firmware loaded)\n", + moxa_brdname[board_type - 1], board->numPorts); + + return 0; +err_base: + iounmap(board->basemem); + board->basemem = NULL; +err_reg: + pci_release_region(pdev, 2); err: return retval; } @@ -332,8 +982,9 @@ static void __devexit moxa_pci_remove(struct pci_dev *pdev) { struct moxa_board_conf *brd = pci_get_drvdata(pdev); - pci_iounmap(pdev, brd->basemem); - brd->basemem = NULL; + moxa_board_deinit(brd); + + pci_release_region(pdev, 2); } static struct pci_driver moxa_pci_driver = { @@ -346,8 +997,8 @@ static struct pci_driver moxa_pci_driver = { static int __init moxa_init(void) { - int i, numBoards, retval = 0; - struct moxa_port *ch; + unsigned int isabrds = 0; + int retval = 0; printk(KERN_INFO "MOXA Intellio family driver version %s\n", MOXA_VERSION); @@ -368,154 +1019,176 @@ static int __init moxa_init(void) moxaDriver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(moxaDriver, &moxa_ops); - for (i = 0, ch = moxa_ports; i < MAX_PORTS; i++, ch++) { - ch->type = PORT_16550A; - ch->port = i; - ch->close_delay = 5 * HZ / 10; - ch->closing_wait = 30 * HZ; - ch->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; - init_waitqueue_head(&ch->open_wait); - init_completion(&ch->close_wait); - - setup_timer(&ch->emptyTimer, moxa_check_xmit_empty, - (unsigned long)ch); - } - - pr_debug("Moxa tty devices major number = %d\n", ttymajor); - if (tty_register_driver(moxaDriver)) { - printk(KERN_ERR "Couldn't install MOXA Smartio family driver !\n"); + printk(KERN_ERR "can't register MOXA Smartio tty driver!\n"); put_tty_driver(moxaDriver); return -1; } - mod_timer(&moxaTimer, jiffies + HZ / 50); - - /* Find the boards defined in source code */ - numBoards = 0; - for (i = 0; i < MAX_BOARDS; i++) { - if ((moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA) || - (moxa_isa_boards[i].boardType == MOXA_BOARD_C320_ISA)) { - moxa_boards[numBoards].boardType = moxa_isa_boards[i].boardType; - if (moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA) - moxa_boards[numBoards].numPorts = 8; - else - moxa_boards[numBoards].numPorts = moxa_isa_boards[i].numPorts; - moxa_boards[numBoards].busType = MOXA_BUS_TYPE_ISA; - moxa_boards[numBoards].baseAddr = moxa_isa_boards[i].baseAddr; - pr_debug("Moxa board %2d: %s board(baseAddr=%lx)\n", - numBoards + 1, - moxa_brdname[moxa_boards[numBoards].boardType-1], - moxa_boards[numBoards].baseAddr); - numBoards++; - } - } - /* Find the boards defined form module args. */ + /* Find the boards defined from module args. */ #ifdef MODULE + { + struct moxa_board_conf *brd = moxa_boards; + unsigned int i; for (i = 0; i < MAX_BOARDS; i++) { - if ((type[i] == MOXA_BOARD_C218_ISA) || - (type[i] == MOXA_BOARD_C320_ISA)) { + if (!baseaddr[i]) + break; + if (type[i] == MOXA_BOARD_C218_ISA || + type[i] == MOXA_BOARD_C320_ISA) { pr_debug("Moxa board %2d: %s board(baseAddr=%lx)\n", - numBoards + 1, moxa_brdname[type[i] - 1], - (unsigned long)baseaddr[i]); - if (numBoards >= MAX_BOARDS) { - printk(KERN_WARNING "More than %d MOXA " - "Intellio family boards found. Board " - "is ignored.\n", MAX_BOARDS); + isabrds + 1, moxa_brdname[type[i] - 1], + baseaddr[i]); + brd->boardType = type[i]; + brd->numPorts = type[i] == MOXA_BOARD_C218_ISA ? 8 : + numports[i]; + brd->busType = MOXA_BUS_TYPE_ISA; + brd->basemem = ioremap_nocache(baseaddr[i], 0x4000); + if (!brd->basemem) { + printk(KERN_ERR "MOXA: can't remap %lx\n", + baseaddr[i]); continue; } - moxa_boards[numBoards].boardType = type[i]; - if (moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA) - moxa_boards[numBoards].numPorts = 8; - else - moxa_boards[numBoards].numPorts = numports[i]; - moxa_boards[numBoards].busType = MOXA_BUS_TYPE_ISA; - moxa_boards[numBoards].baseAddr = baseaddr[i]; - numBoards++; + if (moxa_init_board(brd, NULL)) { + iounmap(brd->basemem); + brd->basemem = NULL; + continue; + } + + printk(KERN_INFO "MOXA isa board found at 0x%.8lu and " + "ready (%u ports, firmware loaded)\n", + baseaddr[i], brd->numPorts); + + brd++; + isabrds++; } } + } #endif #ifdef CONFIG_PCI retval = pci_register_driver(&moxa_pci_driver); if (retval) { - printk(KERN_ERR "Can't register moxa pci driver!\n"); - if (numBoards) + printk(KERN_ERR "Can't register MOXA pci driver!\n"); + if (isabrds) retval = 0; } #endif - for (i = 0; i < numBoards; i++) { - moxa_boards[i].basemem = ioremap(moxa_boards[i].baseAddr, - 0x4000); - } - return retval; } static void __exit moxa_exit(void) { - int i; + unsigned int i; - del_timer_sync(&moxaTimer); +#ifdef CONFIG_PCI + pci_unregister_driver(&moxa_pci_driver); +#endif + + for (i = 0; i < MAX_BOARDS; i++) /* ISA boards */ + if (moxa_boards[i].ready) + moxa_board_deinit(&moxa_boards[i]); - for (i = 0; i < MAX_PORTS; i++) - del_timer_sync(&moxa_ports[i].emptyTimer); + del_timer_sync(&moxaTimer); if (tty_unregister_driver(moxaDriver)) printk(KERN_ERR "Couldn't unregister MOXA Intellio family " "serial driver\n"); put_tty_driver(moxaDriver); - -#ifdef CONFIG_PCI - pci_unregister_driver(&moxa_pci_driver); -#endif - - for (i = 0; i < MAX_BOARDS; i++) - if (moxa_boards[i].basemem) - iounmap(moxa_boards[i].basemem); } module_init(moxa_init); module_exit(moxa_exit); +static void moxa_close_port(struct moxa_port *ch) +{ + moxa_shut_down(ch); + MoxaPortFlushData(ch, 2); + ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE; + ch->tty->driver_data = NULL; + ch->tty = NULL; +} + +static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp, + struct moxa_port *ch) +{ + DEFINE_WAIT(wait); + int retval = 0; + u8 dcd; + + while (1) { + prepare_to_wait(&ch->open_wait, &wait, TASK_INTERRUPTIBLE); + if (tty_hung_up_p(filp)) { +#ifdef SERIAL_DO_RESTART + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + spin_lock_bh(&moxa_lock); + dcd = ch->DCDState; + spin_unlock_bh(&moxa_lock); + if (dcd) + break; + + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + schedule(); + } + finish_wait(&ch->open_wait, &wait); + + return retval; +} + static int moxa_open(struct tty_struct *tty, struct file *filp) { + struct moxa_board_conf *brd; struct moxa_port *ch; int port; int retval; port = tty->index; if (port == MAX_PORTS) { - return (0); + return capable(CAP_SYS_ADMIN) ? 0 : -EPERM; } - if (!MoxaPortIsValid(port)) { - tty->driver_data = NULL; - return (-ENODEV); + if (mutex_lock_interruptible(&moxa_openlock)) + return -ERESTARTSYS; + brd = &moxa_boards[port / MAX_PORTS_PER_BOARD]; + if (!brd->ready) { + mutex_unlock(&moxa_openlock); + return -ENODEV; } - ch = &moxa_ports[port]; + ch = &brd->ports[port % MAX_PORTS_PER_BOARD]; ch->count++; tty->driver_data = ch; ch->tty = tty; if (!(ch->asyncflags & ASYNC_INITIALIZED)) { ch->statusflags = 0; moxa_set_tty_param(tty, tty->termios); - MoxaPortLineCtrl(ch->port, 1, 1); - MoxaPortEnable(ch->port); + MoxaPortLineCtrl(ch, 1, 1); + MoxaPortEnable(ch); + MoxaSetFifo(ch, ch->type == PORT_16550A); ch->asyncflags |= ASYNC_INITIALIZED; } - retval = moxa_block_till_ready(tty, filp, ch); + mutex_unlock(&moxa_openlock); - moxa_unthrottle(tty); - - if (ch->type == PORT_16550A) { - MoxaSetFifo(ch->port, 1); - } else { - MoxaSetFifo(ch->port, 0); - } + retval = 0; + if (!(filp->f_flags & O_NONBLOCK) && !C_CLOCAL(tty)) + retval = moxa_block_till_ready(tty, filp, ch); + mutex_lock(&moxa_openlock); + if (retval) { + if (ch->count) /* 0 means already hung up... */ + if (--ch->count == 0) + moxa_close_port(ch); + } else + ch->asyncflags |= ASYNC_NORMAL_ACTIVE; + mutex_unlock(&moxa_openlock); - return (retval); + return retval; } static void moxa_close(struct tty_struct *tty, struct file *filp) @@ -524,23 +1197,14 @@ static void moxa_close(struct tty_struct *tty, struct file *filp) int port; port = tty->index; - if (port == MAX_PORTS) { - return; - } - if (!MoxaPortIsValid(port)) { - pr_debug("Invalid portno in moxa_close\n"); - tty->driver_data = NULL; - return; - } - if (tty->driver_data == NULL) { + if (port == MAX_PORTS || tty_hung_up_p(filp)) return; - } - if (tty_hung_up_p(filp)) { - return; - } - ch = (struct moxa_port *) tty->driver_data; - if ((tty->count == 1) && (ch->count != 1)) { + mutex_lock(&moxa_openlock); + ch = tty->driver_data; + if (ch == NULL) + goto unlock; + if (tty->count == 1 && ch->count != 1) { printk(KERN_WARNING "moxa_close: bad serial port count; " "tty->count is 1, ch->count is %d\n", ch->count); ch->count = 1; @@ -550,59 +1214,35 @@ static void moxa_close(struct tty_struct *tty, struct file *filp) "device=%s\n", tty->name); ch->count = 0; } - if (ch->count) { - return; - } - ch->asyncflags |= ASYNC_CLOSING; + if (ch->count) + goto unlock; ch->cflag = tty->termios->c_cflag; if (ch->asyncflags & ASYNC_INITIALIZED) { moxa_setup_empty_event(tty); tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */ - del_timer_sync(&moxa_ports[ch->port].emptyTimer); - } - moxa_shut_down(ch); - MoxaPortFlushData(port, 2); - - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); - tty_ldisc_flush(tty); - - tty->closing = 0; - ch->event = 0; - ch->tty = NULL; - if (ch->blocked_open) { - if (ch->close_delay) { - msleep_interruptible(jiffies_to_msecs(ch->close_delay)); - } - wake_up_interruptible(&ch->open_wait); } - ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); - complete_all(&ch->close_wait); + + moxa_close_port(ch); +unlock: + mutex_unlock(&moxa_openlock); } static int moxa_write(struct tty_struct *tty, const unsigned char *buf, int count) { - struct moxa_port *ch; - int len, port; - unsigned long flags; + struct moxa_port *ch = tty->driver_data; + int len; - ch = (struct moxa_port *) tty->driver_data; if (ch == NULL) - return (0); - port = ch->port; + return 0; - spin_lock_irqsave(&moxa_lock, flags); - len = MoxaPortWriteData(port, (unsigned char *) buf, count); - spin_unlock_irqrestore(&moxa_lock, flags); + spin_lock_bh(&moxa_lock); + len = MoxaPortWriteData(ch, buf, count); + spin_unlock_bh(&moxa_lock); - /********************************************* - if ( !(ch->statusflags & LOWWAIT) && - ((len != count) || (MoxaPortTxFree(port) <= 100)) ) - ************************************************/ ch->statusflags |= LOWWAIT; - return (len); + return len; } static int moxa_write_room(struct tty_struct *tty) @@ -610,27 +1250,27 @@ static int moxa_write_room(struct tty_struct *tty) struct moxa_port *ch; if (tty->stopped) - return (0); - ch = (struct moxa_port *) tty->driver_data; + return 0; + ch = tty->driver_data; if (ch == NULL) - return (0); - return (MoxaPortTxFree(ch->port)); + return 0; + return MoxaPortTxFree(ch); } static void moxa_flush_buffer(struct tty_struct *tty) { - struct moxa_port *ch = (struct moxa_port *) tty->driver_data; + struct moxa_port *ch = tty->driver_data; if (ch == NULL) return; - MoxaPortFlushData(ch->port, 1); + MoxaPortFlushData(ch, 1); tty_wakeup(tty); } static int moxa_chars_in_buffer(struct tty_struct *tty) { + struct moxa_port *ch = tty->driver_data; int chars; - struct moxa_port *ch = (struct moxa_port *) tty->driver_data; /* * Sigh...I have to check if driver_data is NULL here, because @@ -639,8 +1279,9 @@ static int moxa_chars_in_buffer(struct tty_struct *tty) * routine. And since the open() failed, we return 0 here. TDJ */ if (ch == NULL) - return (0); - chars = MoxaPortTxQueue(ch->port); + return 0; + lock_kernel(); + chars = MoxaPortTxQueue(ch); if (chars) { /* * Make it possible to wakeup anything waiting for output @@ -649,73 +1290,54 @@ static int moxa_chars_in_buffer(struct tty_struct *tty) if (!(ch->statusflags & EMPTYWAIT)) moxa_setup_empty_event(tty); } - return (chars); -} - -static void moxa_flush_chars(struct tty_struct *tty) -{ - /* - * Don't think I need this, because this is called to empty the TX - * buffer for the 16450, 16550, etc. - */ -} - -static void moxa_put_char(struct tty_struct *tty, unsigned char c) -{ - struct moxa_port *ch; - int port; - unsigned long flags; - - ch = (struct moxa_port *) tty->driver_data; - if (ch == NULL) - return; - port = ch->port; - spin_lock_irqsave(&moxa_lock, flags); - MoxaPortWriteData(port, &c, 1); - spin_unlock_irqrestore(&moxa_lock, flags); - /************************************************ - if ( !(ch->statusflags & LOWWAIT) && (MoxaPortTxFree(port) <= 100) ) - *************************************************/ - ch->statusflags |= LOWWAIT; + unlock_kernel(); + return chars; } static int moxa_tiocmget(struct tty_struct *tty, struct file *file) { - struct moxa_port *ch = (struct moxa_port *) tty->driver_data; - int port; + struct moxa_port *ch; int flag = 0, dtr, rts; - port = tty->index; - if ((port != MAX_PORTS) && (!ch)) - return (-EINVAL); + mutex_lock(&moxa_openlock); + ch = tty->driver_data; + if (!ch) { + mutex_unlock(&moxa_openlock); + return -EINVAL; + } - MoxaPortGetLineOut(ch->port, &dtr, &rts); + MoxaPortGetLineOut(ch, &dtr, &rts); if (dtr) flag |= TIOCM_DTR; if (rts) flag |= TIOCM_RTS; - dtr = MoxaPortLineStatus(ch->port); + dtr = MoxaPortLineStatus(ch); if (dtr & 1) flag |= TIOCM_CTS; if (dtr & 2) flag |= TIOCM_DSR; if (dtr & 4) flag |= TIOCM_CD; + mutex_unlock(&moxa_openlock); return flag; } static int moxa_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { - struct moxa_port *ch = (struct moxa_port *) tty->driver_data; + struct moxa_port *ch; int port; int dtr, rts; port = tty->index; - if ((port != MAX_PORTS) && (!ch)) - return (-EINVAL); + mutex_lock(&moxa_openlock); + ch = tty->driver_data; + if (!ch) { + mutex_unlock(&moxa_openlock); + return -EINVAL; + } - MoxaPortGetLineOut(ch->port, &dtr, &rts); + MoxaPortGetLineOut(ch, &dtr, &rts); if (set & TIOCM_RTS) rts = 1; if (set & TIOCM_DTR) @@ -724,105 +1346,51 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file, rts = 0; if (clear & TIOCM_DTR) dtr = 0; - MoxaPortLineCtrl(ch->port, dtr, rts); + MoxaPortLineCtrl(ch, dtr, rts); + mutex_unlock(&moxa_openlock); return 0; } -static int moxa_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct moxa_port *ch = (struct moxa_port *) tty->driver_data; - register int port; - void __user *argp = (void __user *)arg; - int retval; - - port = tty->index; - if ((port != MAX_PORTS) && (!ch)) - return (-EINVAL); - - switch (cmd) { - case TCSBRK: /* SVID version: non-zero arg --> no break */ - retval = tty_check_change(tty); - if (retval) - return (retval); - moxa_setup_empty_event(tty); - tty_wait_until_sent(tty, 0); - if (!arg) - MoxaPortSendBreak(ch->port, 0); - return (0); - case TCSBRKP: /* support for POSIX tcsendbreak() */ - retval = tty_check_change(tty); - if (retval) - return (retval); - moxa_setup_empty_event(tty); - tty_wait_until_sent(tty, 0); - MoxaPortSendBreak(ch->port, arg); - return (0); - case TIOCGSOFTCAR: - return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) argp); - case TIOCSSOFTCAR: - if(get_user(retval, (unsigned long __user *) argp)) - return -EFAULT; - arg = retval; - tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | - (arg ? CLOCAL : 0)); - if (C_CLOCAL(tty)) - ch->asyncflags &= ~ASYNC_CHECK_CD; - else - ch->asyncflags |= ASYNC_CHECK_CD; - return (0); - case TIOCGSERIAL: - return moxa_get_serial_info(ch, argp); - - case TIOCSSERIAL: - return moxa_set_serial_info(ch, argp); - default: - retval = MoxaDriverIoctl(cmd, arg, port); - } - return (retval); -} - static void moxa_throttle(struct tty_struct *tty) { - struct moxa_port *ch = (struct moxa_port *) tty->driver_data; + struct moxa_port *ch = tty->driver_data; ch->statusflags |= THROTTLE; } static void moxa_unthrottle(struct tty_struct *tty) { - struct moxa_port *ch = (struct moxa_port *) tty->driver_data; + struct moxa_port *ch = tty->driver_data; ch->statusflags &= ~THROTTLE; } static void moxa_set_termios(struct tty_struct *tty, - struct ktermios *old_termios) + struct ktermios *old_termios) { - struct moxa_port *ch = (struct moxa_port *) tty->driver_data; + struct moxa_port *ch = tty->driver_data; if (ch == NULL) return; moxa_set_tty_param(tty, old_termios); - if (!(old_termios->c_cflag & CLOCAL) && - (tty->termios->c_cflag & CLOCAL)) + if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty)) wake_up_interruptible(&ch->open_wait); } static void moxa_stop(struct tty_struct *tty) { - struct moxa_port *ch = (struct moxa_port *) tty->driver_data; + struct moxa_port *ch = tty->driver_data; if (ch == NULL) return; - MoxaPortTxDisable(ch->port); + MoxaPortTxDisable(ch); ch->statusflags |= TXSTOPPED; } static void moxa_start(struct tty_struct *tty) { - struct moxa_port *ch = (struct moxa_port *) tty->driver_data; + struct moxa_port *ch = tty->driver_data; if (ch == NULL) return; @@ -830,91 +1398,143 @@ static void moxa_start(struct tty_struct *tty) if (!(ch->statusflags & TXSTOPPED)) return; - MoxaPortTxEnable(ch->port); + MoxaPortTxEnable(ch); ch->statusflags &= ~TXSTOPPED; } static void moxa_hangup(struct tty_struct *tty) { - struct moxa_port *ch = (struct moxa_port *) tty->driver_data; + struct moxa_port *ch; - moxa_flush_buffer(tty); - moxa_shut_down(ch); - ch->event = 0; + mutex_lock(&moxa_openlock); + ch = tty->driver_data; + if (ch == NULL) { + mutex_unlock(&moxa_openlock); + return; + } ch->count = 0; - ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE; - ch->tty = NULL; + moxa_close_port(ch); + mutex_unlock(&moxa_openlock); + wake_up_interruptible(&ch->open_wait); } -static void moxa_poll(unsigned long ignored) +static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd) { - register int card; - struct moxa_port *ch; - struct tty_struct *tp; - int i, ports; + dcd = !!dcd; - del_timer(&moxaTimer); + if (dcd != p->DCDState && p->tty && C_CLOCAL(p->tty)) { + if (!dcd) + tty_hangup(p->tty); + } + p->DCDState = dcd; +} - if (MoxaDriverPoll() < 0) { - mod_timer(&moxaTimer, jiffies + HZ / 50); - return; +static int moxa_poll_port(struct moxa_port *p, unsigned int handle, + u16 __iomem *ip) +{ + struct tty_struct *tty = p->tty; + void __iomem *ofsAddr; + unsigned int inited = p->asyncflags & ASYNC_INITIALIZED; + u16 intr; + + if (tty) { + if ((p->statusflags & EMPTYWAIT) && + MoxaPortTxQueue(p) == 0) { + p->statusflags &= ~EMPTYWAIT; + tty_wakeup(tty); + } + if ((p->statusflags & LOWWAIT) && !tty->stopped && + MoxaPortTxQueue(p) <= WAKEUP_CHARS) { + p->statusflags &= ~LOWWAIT; + tty_wakeup(tty); + } + + if (inited && !(p->statusflags & THROTTLE) && + MoxaPortRxQueue(p) > 0) { /* RX */ + MoxaPortReadData(p); + tty_schedule_flip(tty); + } + } else { + p->statusflags &= ~EMPTYWAIT; + MoxaPortFlushData(p, 0); /* flush RX */ } + + if (!handle) /* nothing else to do */ + return 0; + + intr = readw(ip); /* port irq status */ + if (intr == 0) + return 0; + + writew(0, ip); /* ACK port */ + ofsAddr = p->tableAddr; + if (intr & IntrTx) /* disable tx intr */ + writew(readw(ofsAddr + HostStat) & ~WakeupTx, + ofsAddr + HostStat); + + if (!inited) + return 0; + + if (tty && (intr & IntrBreak) && !I_IGNBRK(tty)) { /* BREAK */ + tty_insert_flip_char(tty, 0, TTY_BREAK); + tty_schedule_flip(tty); + } + + if (intr & IntrLine) + moxa_new_dcdstate(p, readb(ofsAddr + FlagStat) & DCD_state); + + return 0; +} + +static void moxa_poll(unsigned long ignored) +{ + struct moxa_board_conf *brd; + u16 __iomem *ip; + unsigned int card, port, served = 0; + + spin_lock(&moxa_lock); for (card = 0; card < MAX_BOARDS; card++) { - if ((ports = MoxaPortsOfCard(card)) <= 0) + brd = &moxa_boards[card]; + if (!brd->ready) continue; - ch = &moxa_ports[card * MAX_PORTS_PER_BOARD]; - for (i = 0; i < ports; i++, ch++) { - if ((ch->asyncflags & ASYNC_INITIALIZED) == 0) - continue; - if (!(ch->statusflags & THROTTLE) && - (MoxaPortRxQueue(ch->port) > 0)) - moxa_receive_data(ch); - if ((tp = ch->tty) == 0) - continue; - if (ch->statusflags & LOWWAIT) { - if (MoxaPortTxQueue(ch->port) <= WAKEUP_CHARS) { - if (!tp->stopped) { - ch->statusflags &= ~LOWWAIT; - tty_wakeup(tp); - } - } - } - if (!I_IGNBRK(tp) && (MoxaPortResetBrkCnt(ch->port) > 0)) { - tty_insert_flip_char(tp, 0, TTY_BREAK); - tty_schedule_flip(tp); - } - if (MoxaPortDCDChange(ch->port)) { - if (ch->asyncflags & ASYNC_CHECK_CD) { - if (MoxaPortDCDON(ch->port)) - wake_up_interruptible(&ch->open_wait); - else { - tty_hangup(tp); - wake_up_interruptible(&ch->open_wait); - ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE; - } + + served++; + + ip = NULL; + if (readb(brd->intPend) == 0xff) + ip = brd->intTable + readb(brd->intNdx); + + for (port = 0; port < brd->numPorts; port++) + moxa_poll_port(&brd->ports[port], !!ip, ip + port); + + if (ip) + writeb(0, brd->intPend); /* ACK */ + + if (moxaLowWaterChk) { + struct moxa_port *p = brd->ports; + for (port = 0; port < brd->numPorts; port++, p++) + if (p->lowChkFlag) { + p->lowChkFlag = 0; + moxa_low_water_check(p->tableAddr); } - } } } + moxaLowWaterChk = 0; - mod_timer(&moxaTimer, jiffies + HZ / 50); + if (served) + mod_timer(&moxaTimer, jiffies + HZ / 50); + spin_unlock(&moxa_lock); } /******************************************************************************/ static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_termios) { - register struct ktermios *ts; - struct moxa_port *ch; + register struct ktermios *ts = tty->termios; + struct moxa_port *ch = tty->driver_data; int rts, cts, txflow, rxflow, xany, baud; - ch = (struct moxa_port *) tty->driver_data; - ts = tty->termios; - if (ts->c_cflag & CLOCAL) - ch->asyncflags &= ~ASYNC_CHECK_CD; - else - ch->asyncflags |= ASYNC_CHECK_CD; rts = cts = txflow = rxflow = xany = 0; if (ts->c_cflag & CRTSCTS) rts = cts = 1; @@ -927,776 +1547,60 @@ static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_term /* Clear the features we don't support */ ts->c_cflag &= ~CMSPAR; - MoxaPortFlowCtrl(ch->port, rts, cts, txflow, rxflow, xany); - baud = MoxaPortSetTermio(ch->port, ts, tty_get_baud_rate(tty)); + MoxaPortFlowCtrl(ch, rts, cts, txflow, rxflow, xany); + baud = MoxaPortSetTermio(ch, ts, tty_get_baud_rate(tty)); if (baud == -1) baud = tty_termios_baud_rate(old_termios); /* Not put the baud rate into the termios data */ tty_encode_baud_rate(tty, baud, baud); } -static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp, - struct moxa_port *ch) -{ - DECLARE_WAITQUEUE(wait,current); - unsigned long flags; - int retval; - int do_clocal = C_CLOCAL(tty); - - /* - * If the device is in the middle of being closed, then block - * until it's done, and then try again. - */ - if (tty_hung_up_p(filp) || (ch->asyncflags & ASYNC_CLOSING)) { - if (ch->asyncflags & ASYNC_CLOSING) - wait_for_completion_interruptible(&ch->close_wait); -#ifdef SERIAL_DO_RESTART - if (ch->asyncflags & ASYNC_HUP_NOTIFY) - return (-EAGAIN); - else - return (-ERESTARTSYS); -#else - return (-EAGAIN); -#endif - } - /* - * If non-blocking mode is set, then make the check up front - * and then exit. - */ - if (filp->f_flags & O_NONBLOCK) { - ch->asyncflags |= ASYNC_NORMAL_ACTIVE; - return (0); - } - /* - * Block waiting for the carrier detect and the line to become free - */ - retval = 0; - add_wait_queue(&ch->open_wait, &wait); - pr_debug("block_til_ready before block: ttys%d, count = %d\n", - ch->port, ch->count); - spin_lock_irqsave(&moxa_lock, flags); - if (!tty_hung_up_p(filp)) - ch->count--; - ch->blocked_open++; - spin_unlock_irqrestore(&moxa_lock, flags); - - while (1) { - set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || - !(ch->asyncflags & ASYNC_INITIALIZED)) { -#ifdef SERIAL_DO_RESTART - if (ch->asyncflags & ASYNC_HUP_NOTIFY) - retval = -EAGAIN; - else - retval = -ERESTARTSYS; -#else - retval = -EAGAIN; -#endif - break; - } - if (!(ch->asyncflags & ASYNC_CLOSING) && (do_clocal || - MoxaPortDCDON(ch->port))) - break; - - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - schedule(); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&ch->open_wait, &wait); - - spin_lock_irqsave(&moxa_lock, flags); - if (!tty_hung_up_p(filp)) - ch->count++; - ch->blocked_open--; - spin_unlock_irqrestore(&moxa_lock, flags); - pr_debug("block_til_ready after blocking: ttys%d, count = %d\n", - ch->port, ch->count); - if (retval) - return (retval); - /* FIXME: review to see if we need to use set_bit on these */ - ch->asyncflags |= ASYNC_NORMAL_ACTIVE; - return 0; -} - static void moxa_setup_empty_event(struct tty_struct *tty) { struct moxa_port *ch = tty->driver_data; - unsigned long flags; - spin_lock_irqsave(&moxa_lock, flags); + spin_lock_bh(&moxa_lock); ch->statusflags |= EMPTYWAIT; - mod_timer(&moxa_ports[ch->port].emptyTimer, jiffies + HZ); - spin_unlock_irqrestore(&moxa_lock, flags); -} - -static void moxa_check_xmit_empty(unsigned long data) -{ - struct moxa_port *ch; - - ch = (struct moxa_port *) data; - if (ch->tty && (ch->statusflags & EMPTYWAIT)) { - if (MoxaPortTxQueue(ch->port) == 0) { - ch->statusflags &= ~EMPTYWAIT; - tty_wakeup(ch->tty); - return; - } - mod_timer(&moxa_ports[ch->port].emptyTimer, - round_jiffies(jiffies + HZ)); - } else - ch->statusflags &= ~EMPTYWAIT; + spin_unlock_bh(&moxa_lock); } static void moxa_shut_down(struct moxa_port *ch) { - struct tty_struct *tp; + struct tty_struct *tp = ch->tty; if (!(ch->asyncflags & ASYNC_INITIALIZED)) return; - tp = ch->tty; - - MoxaPortDisable(ch->port); + MoxaPortDisable(ch); /* * If we're a modem control device and HUPCL is on, drop RTS & DTR. */ - if (tp->termios->c_cflag & HUPCL) - MoxaPortLineCtrl(ch->port, 0, 0); + if (C_HUPCL(tp)) + MoxaPortLineCtrl(ch, 0, 0); + spin_lock_bh(&moxa_lock); ch->asyncflags &= ~ASYNC_INITIALIZED; + spin_unlock_bh(&moxa_lock); } -static void moxa_receive_data(struct moxa_port *ch) -{ - struct tty_struct *tp; - struct ktermios *ts; - unsigned long flags; - - ts = NULL; - tp = ch->tty; - if (tp) - ts = tp->termios; - /************************************************** - if ( !tp || !ts || !(ts->c_cflag & CREAD) ) { - *****************************************************/ - if (!tp || !ts) { - MoxaPortFlushData(ch->port, 0); - return; - } - spin_lock_irqsave(&moxa_lock, flags); - MoxaPortReadData(ch->port, tp); - spin_unlock_irqrestore(&moxa_lock, flags); - tty_schedule_flip(tp); -} - -#define Magic_code 0x404 - -/* - * System Configuration - */ -/* - * for C218 BIOS initialization - */ -#define C218_ConfBase 0x800 -#define C218_status (C218_ConfBase + 0) /* BIOS running status */ -#define C218_diag (C218_ConfBase + 2) /* diagnostic status */ -#define C218_key (C218_ConfBase + 4) /* WORD (0x218 for C218) */ -#define C218DLoad_len (C218_ConfBase + 6) /* WORD */ -#define C218check_sum (C218_ConfBase + 8) /* BYTE */ -#define C218chksum_ok (C218_ConfBase + 0x0a) /* BYTE (1:ok) */ -#define C218_TestRx (C218_ConfBase + 0x10) /* 8 bytes for 8 ports */ -#define C218_TestTx (C218_ConfBase + 0x18) /* 8 bytes for 8 ports */ -#define C218_RXerr (C218_ConfBase + 0x20) /* 8 bytes for 8 ports */ -#define C218_ErrFlag (C218_ConfBase + 0x28) /* 8 bytes for 8 ports */ - -#define C218_LoadBuf 0x0F00 -#define C218_KeyCode 0x218 -#define CP204J_KeyCode 0x204 - -/* - * for C320 BIOS initialization - */ -#define C320_ConfBase 0x800 -#define C320_LoadBuf 0x0f00 -#define STS_init 0x05 /* for C320_status */ - -#define C320_status C320_ConfBase + 0 /* BIOS running status */ -#define C320_diag C320_ConfBase + 2 /* diagnostic status */ -#define C320_key C320_ConfBase + 4 /* WORD (0320H for C320) */ -#define C320DLoad_len C320_ConfBase + 6 /* WORD */ -#define C320check_sum C320_ConfBase + 8 /* WORD */ -#define C320chksum_ok C320_ConfBase + 0x0a /* WORD (1:ok) */ -#define C320bapi_len C320_ConfBase + 0x0c /* WORD */ -#define C320UART_no C320_ConfBase + 0x0e /* WORD */ - -#define C320_KeyCode 0x320 - -#define FixPage_addr 0x0000 /* starting addr of static page */ -#define DynPage_addr 0x2000 /* starting addr of dynamic page */ -#define C218_start 0x3000 /* starting addr of C218 BIOS prg */ -#define Control_reg 0x1ff0 /* select page and reset control */ -#define HW_reset 0x80 - -/* - * Function Codes - */ -#define FC_CardReset 0x80 -#define FC_ChannelReset 1 /* C320 firmware not supported */ -#define FC_EnableCH 2 -#define FC_DisableCH 3 -#define FC_SetParam 4 -#define FC_SetMode 5 -#define FC_SetRate 6 -#define FC_LineControl 7 -#define FC_LineStatus 8 -#define FC_XmitControl 9 -#define FC_FlushQueue 10 -#define FC_SendBreak 11 -#define FC_StopBreak 12 -#define FC_LoopbackON 13 -#define FC_LoopbackOFF 14 -#define FC_ClrIrqTable 15 -#define FC_SendXon 16 -#define FC_SetTermIrq 17 /* C320 firmware not supported */ -#define FC_SetCntIrq 18 /* C320 firmware not supported */ -#define FC_SetBreakIrq 19 -#define FC_SetLineIrq 20 -#define FC_SetFlowCtl 21 -#define FC_GenIrq 22 -#define FC_InCD180 23 -#define FC_OutCD180 24 -#define FC_InUARTreg 23 -#define FC_OutUARTreg 24 -#define FC_SetXonXoff 25 -#define FC_OutCD180CCR 26 -#define FC_ExtIQueue 27 -#define FC_ExtOQueue 28 -#define FC_ClrLineIrq 29 -#define FC_HWFlowCtl 30 -#define FC_GetClockRate 35 -#define FC_SetBaud 36 -#define FC_SetDataMode 41 -#define FC_GetCCSR 43 -#define FC_GetDataError 45 -#define FC_RxControl 50 -#define FC_ImmSend 51 -#define FC_SetXonState 52 -#define FC_SetXoffState 53 -#define FC_SetRxFIFOTrig 54 -#define FC_SetTxFIFOCnt 55 -#define FC_UnixRate 56 -#define FC_UnixResetTimer 57 - -#define RxFIFOTrig1 0 -#define RxFIFOTrig4 1 -#define RxFIFOTrig8 2 -#define RxFIFOTrig14 3 - -/* - * Dual-Ported RAM - */ -#define DRAM_global 0 -#define INT_data (DRAM_global + 0) -#define Config_base (DRAM_global + 0x108) - -#define IRQindex (INT_data + 0) -#define IRQpending (INT_data + 4) -#define IRQtable (INT_data + 8) - -/* - * Interrupt Status - */ -#define IntrRx 0x01 /* receiver data O.K. */ -#define IntrTx 0x02 /* transmit buffer empty */ -#define IntrFunc 0x04 /* function complete */ -#define IntrBreak 0x08 /* received break */ -#define IntrLine 0x10 /* line status change - for transmitter */ -#define IntrIntr 0x20 /* received INTR code */ -#define IntrQuit 0x40 /* received QUIT code */ -#define IntrEOF 0x80 /* received EOF code */ - -#define IntrRxTrigger 0x100 /* rx data count reach tigger value */ -#define IntrTxTrigger 0x200 /* tx data count below trigger value */ - -#define Magic_no (Config_base + 0) -#define Card_model_no (Config_base + 2) -#define Total_ports (Config_base + 4) -#define Module_cnt (Config_base + 8) -#define Module_no (Config_base + 10) -#define Timer_10ms (Config_base + 14) -#define Disable_IRQ (Config_base + 20) -#define TMS320_PORT1 (Config_base + 22) -#define TMS320_PORT2 (Config_base + 24) -#define TMS320_CLOCK (Config_base + 26) - -/* - * DATA BUFFER in DRAM - */ -#define Extern_table 0x400 /* Base address of the external table - (24 words * 64) total 3K bytes - (24 words * 128) total 6K bytes */ -#define Extern_size 0x60 /* 96 bytes */ -#define RXrptr 0x00 /* read pointer for RX buffer */ -#define RXwptr 0x02 /* write pointer for RX buffer */ -#define TXrptr 0x04 /* read pointer for TX buffer */ -#define TXwptr 0x06 /* write pointer for TX buffer */ -#define HostStat 0x08 /* IRQ flag and general flag */ -#define FlagStat 0x0A -#define FlowControl 0x0C /* B7 B6 B5 B4 B3 B2 B1 B0 */ - /* x x x x | | | | */ - /* | | | + CTS flow */ - /* | | +--- RTS flow */ - /* | +------ TX Xon/Xoff */ - /* +--------- RX Xon/Xoff */ -#define Break_cnt 0x0E /* received break count */ -#define CD180TXirq 0x10 /* if non-0: enable TX irq */ -#define RX_mask 0x12 -#define TX_mask 0x14 -#define Ofs_rxb 0x16 -#define Ofs_txb 0x18 -#define Page_rxb 0x1A -#define Page_txb 0x1C -#define EndPage_rxb 0x1E -#define EndPage_txb 0x20 -#define Data_error 0x22 -#define RxTrigger 0x28 -#define TxTrigger 0x2a - -#define rRXwptr 0x34 -#define Low_water 0x36 - -#define FuncCode 0x40 -#define FuncArg 0x42 -#define FuncArg1 0x44 - -#define C218rx_size 0x2000 /* 8K bytes */ -#define C218tx_size 0x8000 /* 32K bytes */ - -#define C218rx_mask (C218rx_size - 1) -#define C218tx_mask (C218tx_size - 1) - -#define C320p8rx_size 0x2000 -#define C320p8tx_size 0x8000 -#define C320p8rx_mask (C320p8rx_size - 1) -#define C320p8tx_mask (C320p8tx_size - 1) - -#define C320p16rx_size 0x2000 -#define C320p16tx_size 0x4000 -#define C320p16rx_mask (C320p16rx_size - 1) -#define C320p16tx_mask (C320p16tx_size - 1) - -#define C320p24rx_size 0x2000 -#define C320p24tx_size 0x2000 -#define C320p24rx_mask (C320p24rx_size - 1) -#define C320p24tx_mask (C320p24tx_size - 1) - -#define C320p32rx_size 0x1000 -#define C320p32tx_size 0x1000 -#define C320p32rx_mask (C320p32rx_size - 1) -#define C320p32tx_mask (C320p32tx_size - 1) - -#define Page_size 0x2000 -#define Page_mask (Page_size - 1) -#define C218rx_spage 3 -#define C218tx_spage 4 -#define C218rx_pageno 1 -#define C218tx_pageno 4 -#define C218buf_pageno 5 - -#define C320p8rx_spage 3 -#define C320p8tx_spage 4 -#define C320p8rx_pgno 1 -#define C320p8tx_pgno 4 -#define C320p8buf_pgno 5 - -#define C320p16rx_spage 3 -#define C320p16tx_spage 4 -#define C320p16rx_pgno 1 -#define C320p16tx_pgno 2 -#define C320p16buf_pgno 3 - -#define C320p24rx_spage 3 -#define C320p24tx_spage 4 -#define C320p24rx_pgno 1 -#define C320p24tx_pgno 1 -#define C320p24buf_pgno 2 - -#define C320p32rx_spage 3 -#define C320p32tx_ofs C320p32rx_size -#define C320p32tx_spage 3 -#define C320p32buf_pgno 1 - -/* - * Host Status - */ -#define WakeupRx 0x01 -#define WakeupTx 0x02 -#define WakeupBreak 0x08 -#define WakeupLine 0x10 -#define WakeupIntr 0x20 -#define WakeupQuit 0x40 -#define WakeupEOF 0x80 /* used in VTIME control */ -#define WakeupRxTrigger 0x100 -#define WakeupTxTrigger 0x200 -/* - * Flag status - */ -#define Rx_over 0x01 -#define Xoff_state 0x02 -#define Tx_flowOff 0x04 -#define Tx_enable 0x08 -#define CTS_state 0x10 -#define DSR_state 0x20 -#define DCD_state 0x80 -/* - * FlowControl - */ -#define CTS_FlowCtl 1 -#define RTS_FlowCtl 2 -#define Tx_FlowCtl 4 -#define Rx_FlowCtl 8 -#define IXM_IXANY 0x10 - -#define LowWater 128 - -#define DTR_ON 1 -#define RTS_ON 2 -#define CTS_ON 1 -#define DSR_ON 2 -#define DCD_ON 8 - -/* mode definition */ -#define MX_CS8 0x03 -#define MX_CS7 0x02 -#define MX_CS6 0x01 -#define MX_CS5 0x00 - -#define MX_STOP1 0x00 -#define MX_STOP15 0x04 -#define MX_STOP2 0x08 - -#define MX_PARNONE 0x00 -#define MX_PAREVEN 0x40 -#define MX_PARODD 0xC0 - -/* - * Query - */ - -struct mon_str { - int tick; - int rxcnt[MAX_PORTS]; - int txcnt[MAX_PORTS]; -}; - -#define DCD_changed 0x01 -#define DCD_oldstate 0x80 - -static unsigned char moxaBuff[10240]; -static int moxaLowWaterChk; -static int moxaCard; -static struct mon_str moxaLog; -static int moxaFuncTout = HZ / 2; - -static void moxafunc(void __iomem *, int, ushort); -static void moxa_wait_finish(void __iomem *); -static void moxa_low_water_check(void __iomem *); -static int moxaloadbios(int, unsigned char __user *, int); -static int moxafindcard(int); -static int moxaload320b(int, unsigned char __user *, int); -static int moxaloadcode(int, unsigned char __user *, int); -static int moxaloadc218(int, void __iomem *, int); -static int moxaloadc320(int, void __iomem *, int, int *); - /***************************************************************************** * Driver level functions: * - * 1. MoxaDriverInit(void); * - * 2. MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port); * - * 3. MoxaDriverPoll(void); * *****************************************************************************/ -void MoxaDriverInit(void) -{ - struct moxa_port *p; - unsigned int i; - moxaFuncTout = HZ / 2; /* 500 mini-seconds */ - moxaCard = 0; - moxaLog.tick = 0; - moxaLowWaterChk = 0; - for (i = 0; i < MAX_PORTS; i++) { - p = &moxa_ports[i]; - p->chkPort = 0; - p->lowChkFlag = 0; - p->lineCtrl = 0; - moxaLog.rxcnt[i] = 0; - moxaLog.txcnt[i] = 0; - } -} - -#define MOXA 0x400 -#define MOXA_GET_IQUEUE (MOXA + 1) /* get input buffered count */ -#define MOXA_GET_OQUEUE (MOXA + 2) /* get output buffered count */ -#define MOXA_INIT_DRIVER (MOXA + 6) /* moxaCard=0 */ -#define MOXA_LOAD_BIOS (MOXA + 9) /* download BIOS */ -#define MOXA_FIND_BOARD (MOXA + 10) /* Check if MOXA card exist? */ -#define MOXA_LOAD_C320B (MOXA + 11) /* download 320B firmware */ -#define MOXA_LOAD_CODE (MOXA + 12) /* download firmware */ -#define MOXA_GETDATACOUNT (MOXA + 23) -#define MOXA_GET_IOQUEUE (MOXA + 27) -#define MOXA_FLUSH_QUEUE (MOXA + 28) -#define MOXA_GET_CONF (MOXA + 35) /* configuration */ -#define MOXA_GET_MAJOR (MOXA + 63) -#define MOXA_GET_CUMAJOR (MOXA + 64) -#define MOXA_GETMSTATUS (MOXA + 65) - -struct dl_str { - char __user *buf; - int len; - int cardno; -}; - -static struct dl_str dltmp; - -void MoxaPortFlushData(int port, int mode) +static void MoxaPortFlushData(struct moxa_port *port, int mode) { void __iomem *ofsAddr; - if ((mode < 0) || (mode > 2)) + if (mode < 0 || mode > 2) return; - ofsAddr = moxa_ports[port].tableAddr; + ofsAddr = port->tableAddr; moxafunc(ofsAddr, FC_FlushQueue, mode); if (mode != 1) { - moxa_ports[port].lowChkFlag = 0; + port->lowChkFlag = 0; moxa_low_water_check(ofsAddr); } } -int MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port) -{ - int i; - int status; - int MoxaPortTxQueue(int), MoxaPortRxQueue(int); - void __user *argp = (void __user *)arg; - - if (port == MAX_PORTS) { - if ((cmd != MOXA_GET_CONF) && (cmd != MOXA_INIT_DRIVER) && - (cmd != MOXA_LOAD_BIOS) && (cmd != MOXA_FIND_BOARD) && (cmd != MOXA_LOAD_C320B) && - (cmd != MOXA_LOAD_CODE) && (cmd != MOXA_GETDATACOUNT) && - (cmd != MOXA_GET_IOQUEUE) && (cmd != MOXA_GET_MAJOR) && - (cmd != MOXA_GET_CUMAJOR) && (cmd != MOXA_GETMSTATUS)) - return (-EINVAL); - } - switch (cmd) { - case MOXA_GET_CONF: - if(copy_to_user(argp, &moxa_boards, MAX_BOARDS * - sizeof(struct moxa_board_conf))) - return -EFAULT; - return (0); - case MOXA_INIT_DRIVER: - if ((int) arg == 0x404) - MoxaDriverInit(); - return (0); - case MOXA_GETDATACOUNT: - moxaLog.tick = jiffies; - if(copy_to_user(argp, &moxaLog, sizeof(struct mon_str))) - return -EFAULT; - return (0); - case MOXA_FLUSH_QUEUE: - MoxaPortFlushData(port, arg); - return (0); - case MOXA_GET_IOQUEUE: { - struct moxaq_str __user *argm = argp; - struct moxaq_str tmp; - - for (i = 0; i < MAX_PORTS; i++, argm++) { - memset(&tmp, 0, sizeof(tmp)); - if (moxa_ports[i].chkPort) { - tmp.inq = MoxaPortRxQueue(i); - tmp.outq = MoxaPortTxQueue(i); - } - if (copy_to_user(argm, &tmp, sizeof(tmp))) - return -EFAULT; - } - return (0); - } case MOXA_GET_OQUEUE: - i = MoxaPortTxQueue(port); - return put_user(i, (unsigned long __user *)argp); - case MOXA_GET_IQUEUE: - i = MoxaPortRxQueue(port); - return put_user(i, (unsigned long __user *)argp); - case MOXA_GET_MAJOR: - if(copy_to_user(argp, &ttymajor, sizeof(int))) - return -EFAULT; - return 0; - case MOXA_GET_CUMAJOR: - i = 0; - if(copy_to_user(argp, &i, sizeof(int))) - return -EFAULT; - return 0; - case MOXA_GETMSTATUS: { - struct mxser_mstatus __user *argm = argp; - struct mxser_mstatus tmp; - struct moxa_port *p; - - for (i = 0; i < MAX_PORTS; i++, argm++) { - p = &moxa_ports[i]; - memset(&tmp, 0, sizeof(tmp)); - if (!p->chkPort) { - goto copy; - } else { - status = MoxaPortLineStatus(p->port); - if (status & 1) - tmp.cts = 1; - if (status & 2) - tmp.dsr = 1; - if (status & 4) - tmp.dcd = 1; - } - - if (!p->tty || !p->tty->termios) - tmp.cflag = p->cflag; - else - tmp.cflag = p->tty->termios->c_cflag; -copy: - if (copy_to_user(argm, &tmp, sizeof(tmp))) - return -EFAULT; - } - return 0; - } default: - return (-ENOIOCTLCMD); - case MOXA_LOAD_BIOS: - case MOXA_FIND_BOARD: - case MOXA_LOAD_C320B: - case MOXA_LOAD_CODE: - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - break; - } - - if(copy_from_user(&dltmp, argp, sizeof(struct dl_str))) - return -EFAULT; - if(dltmp.cardno < 0 || dltmp.cardno >= MAX_BOARDS || dltmp.len < 0) - return -EINVAL; - - switch(cmd) - { - case MOXA_LOAD_BIOS: - i = moxaloadbios(dltmp.cardno, dltmp.buf, dltmp.len); - return (i); - case MOXA_FIND_BOARD: - return moxafindcard(dltmp.cardno); - case MOXA_LOAD_C320B: - moxaload320b(dltmp.cardno, dltmp.buf, dltmp.len); - default: /* to keep gcc happy */ - return (0); - case MOXA_LOAD_CODE: - i = moxaloadcode(dltmp.cardno, dltmp.buf, dltmp.len); - if (i == -1) - return (-EFAULT); - return (i); - - } -} - -int MoxaDriverPoll(void) -{ - struct moxa_board_conf *brd; - register ushort temp; - register int card; - void __iomem *ofsAddr; - void __iomem *ip; - int port, p, ports; - - if (moxaCard == 0) - return (-1); - for (card = 0; card < MAX_BOARDS; card++) { - brd = &moxa_boards[card]; - if (brd->loadstat == 0) - continue; - if ((ports = brd->numPorts) == 0) - continue; - if (readb(brd->intPend) == 0xff) { - ip = brd->intTable + readb(brd->intNdx); - p = card * MAX_PORTS_PER_BOARD; - ports <<= 1; - for (port = 0; port < ports; port += 2, p++) { - if ((temp = readw(ip + port)) != 0) { - writew(0, ip + port); - ofsAddr = moxa_ports[p].tableAddr; - if (temp & IntrTx) - writew(readw(ofsAddr + HostStat) & ~WakeupTx, ofsAddr + HostStat); - if (temp & IntrBreak) { - moxa_ports[p].breakCnt++; - } - if (temp & IntrLine) { - if (readb(ofsAddr + FlagStat) & DCD_state) { - if ((moxa_ports[p].DCDState & DCD_oldstate) == 0) - moxa_ports[p].DCDState = (DCD_oldstate | - DCD_changed); - } else { - if (moxa_ports[p].DCDState & DCD_oldstate) - moxa_ports[p].DCDState = DCD_changed; - } - } - } - } - writeb(0, brd->intPend); - } - if (moxaLowWaterChk) { - p = card * MAX_PORTS_PER_BOARD; - for (port = 0; port < ports; port++, p++) { - if (moxa_ports[p].lowChkFlag) { - moxa_ports[p].lowChkFlag = 0; - ofsAddr = moxa_ports[p].tableAddr; - moxa_low_water_check(ofsAddr); - } - } - } - } - moxaLowWaterChk = 0; - return (0); -} - -/***************************************************************************** - * Card level function: * - * 1. MoxaPortsOfCard(int cardno); * - *****************************************************************************/ -int MoxaPortsOfCard(int cardno) -{ - - if (moxa_boards[cardno].boardType == 0) - return (0); - return (moxa_boards[cardno].numPorts); -} - -/***************************************************************************** - * Port level functions: * - * 1. MoxaPortIsValid(int port); * - * 2. MoxaPortEnable(int port); * - * 3. MoxaPortDisable(int port); * - * 4. MoxaPortGetMaxBaud(int port); * - * 6. MoxaPortSetBaud(int port, long baud); * - * 8. MoxaPortSetTermio(int port, unsigned char *termio); * - * 9. MoxaPortGetLineOut(int port, int *dtrState, int *rtsState); * - * 10. MoxaPortLineCtrl(int port, int dtrState, int rtsState); * - * 11. MoxaPortFlowCtrl(int port, int rts, int cts, int rx, int tx,int xany); * - * 12. MoxaPortLineStatus(int port); * - * 13. MoxaPortDCDChange(int port); * - * 14. MoxaPortDCDON(int port); * - * 15. MoxaPortFlushData(int port, int mode); * - * 16. MoxaPortWriteData(int port, unsigned char * buffer, int length); * - * 17. MoxaPortReadData(int port, struct tty_struct *tty); * - * 20. MoxaPortTxQueue(int port); * - * 21. MoxaPortTxFree(int port); * - * 22. MoxaPortRxQueue(int port); * - * 24. MoxaPortTxDisable(int port); * - * 25. MoxaPortTxEnable(int port); * - * 27. MoxaPortResetBrkCnt(int port); * - * 30. MoxaPortSendBreak(int port, int ticks); * - *****************************************************************************/ /* * Moxa Port Number Description: * @@ -1733,33 +1637,6 @@ int MoxaPortsOfCard(int cardno) * -ENOIOCTLCMD * * - * Function 3: Moxa driver polling process routine. - * Syntax: - * int MoxaDriverPoll(void); - * - * return: 0 ; polling O.K. - * -1 : no any Moxa card. - * - * - * Function 4: Get the ports of this card. - * Syntax: - * int MoxaPortsOfCard(int cardno); - * - * int cardno : card number (0 - 3) - * - * return: 0 : this card is invalid - * 8/16/24/32 - * - * - * Function 5: Check this port is valid or invalid - * Syntax: - * int MoxaPortIsValid(int port); - * int port : port number (0 - 127, ref port description) - * - * return: 0 : this port is invalid - * 1 : this port is valid - * - * * Function 6: Enable this port to start Tx/Rx data. * Syntax: * void MoxaPortEnable(int port); @@ -1772,18 +1649,9 @@ int MoxaPortsOfCard(int cardno) * int port : port number (0 - 127) * * - * Function 8: Get the maximun available baud rate of this port. - * Syntax: - * long MoxaPortGetMaxBaud(int port); - * int port : port number (0 - 127) - * - * return: 0 : this port is invalid - * 38400/57600/115200 bps - * - * * Function 10: Setting baud rate of this port. * Syntax: - * long MoxaPortSetBaud(int port, long baud); + * speed_t MoxaPortSetBaud(int port, speed_t baud); * int port : port number (0 - 127) * long baud : baud rate (50 - 115200) * @@ -1850,25 +1718,6 @@ int MoxaPortsOfCard(int cardno) * Bit 2 - DCD state (0: off, 1: on) * * - * Function 17: Check the DCD state has changed since the last read - * of this function. - * Syntax: - * int MoxaPortDCDChange(int port); - * int port : port number (0 - 127) - * - * return: 0 : no changed - * 1 : DCD has changed - * - * - * Function 18: Check ths current DCD state is ON or not. - * Syntax: - * int MoxaPortDCDON(int port); - * int port : port number (0 - 127) - * - * return: 0 : DCD off - * 1 : DCD on - * - * * Function 19: Flush the Rx/Tx buffer data of this port. * Syntax: * void MoxaPortFlushData(int port, int mode); @@ -1942,40 +1791,20 @@ int MoxaPortsOfCard(int cardno) * return: 0 - .. : BREAK signal count * * - * Function 34: Send out a BREAK signal. - * Syntax: - * void MoxaPortSendBreak(int port, int ms100); - * int port : port number (0 - 127) - * int ms100 : break signal time interval. - * unit: 100 mini-second. if ms100 == 0, it will - * send out a about 250 ms BREAK signal. - * */ -int MoxaPortIsValid(int port) -{ - - if (moxaCard == 0) - return (0); - if (moxa_ports[port].chkPort == 0) - return (0); - return (1); -} -void MoxaPortEnable(int port) +static void MoxaPortEnable(struct moxa_port *port) { void __iomem *ofsAddr; - int MoxaPortLineStatus(int); - short lowwater = 512; + u16 lowwater = 512; - ofsAddr = moxa_ports[port].tableAddr; + ofsAddr = port->tableAddr; writew(lowwater, ofsAddr + Low_water); - moxa_ports[port].breakCnt = 0; - if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) || - (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) { + if (MOXA_IS_320(port->board)) moxafunc(ofsAddr, FC_SetBreakIrq, 0); - } else { - writew(readw(ofsAddr + HostStat) | WakeupBreak, ofsAddr + HostStat); - } + else + writew(readw(ofsAddr + HostStat) | WakeupBreak, + ofsAddr + HostStat); moxafunc(ofsAddr, FC_SetLineIrq, Magic_code); moxafunc(ofsAddr, FC_FlushQueue, 2); @@ -1984,9 +1813,9 @@ void MoxaPortEnable(int port) MoxaPortLineStatus(port); } -void MoxaPortDisable(int port) +static void MoxaPortDisable(struct moxa_port *port) { - void __iomem *ofsAddr = moxa_ports[port].tableAddr; + void __iomem *ofsAddr = port->tableAddr; moxafunc(ofsAddr, FC_SetFlowCtl, 0); /* disable flow control */ moxafunc(ofsAddr, FC_ClrLineIrq, Magic_code); @@ -1994,49 +1823,32 @@ void MoxaPortDisable(int port) moxafunc(ofsAddr, FC_DisableCH, Magic_code); } -long MoxaPortGetMaxBaud(int port) -{ - if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) || - (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) - return (460800L); - else - return (921600L); -} - - -long MoxaPortSetBaud(int port, long baud) +static speed_t MoxaPortSetBaud(struct moxa_port *port, speed_t baud) { - void __iomem *ofsAddr; - long max, clock; - unsigned int val; + void __iomem *ofsAddr = port->tableAddr; + unsigned int clock, val; + speed_t max; - if ((baud < 50L) || ((max = MoxaPortGetMaxBaud(port)) == 0)) - return (0); - ofsAddr = moxa_ports[port].tableAddr; + max = MOXA_IS_320(port->board) ? 460800 : 921600; + if (baud < 50) + return 0; if (baud > max) baud = max; - if (max == 38400L) - clock = 614400L; /* for 9.8304 Mhz : max. 38400 bps */ - else if (max == 57600L) - clock = 691200L; /* for 11.0592 Mhz : max. 57600 bps */ - else - clock = 921600L; /* for 14.7456 Mhz : max. 115200 bps */ + clock = 921600; val = clock / baud; moxafunc(ofsAddr, FC_SetBaud, val); baud = clock / val; - moxa_ports[port].curBaud = baud; - return (baud); + return baud; } -int MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud) +static int MoxaPortSetTermio(struct moxa_port *port, struct ktermios *termio, + speed_t baud) { void __iomem *ofsAddr; tcflag_t cflag; tcflag_t mode = 0; - if (moxa_ports[port].chkPort == 0 || termio == 0) - return (-1); - ofsAddr = moxa_ports[port].tableAddr; + ofsAddr = port->tableAddr; cflag = termio->c_cflag; /* termio->c_cflag */ mode = termio->c_cflag & CSIZE; @@ -2065,13 +1877,11 @@ int MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud) } else mode |= MX_PARNONE; - moxafunc(ofsAddr, FC_SetDataMode, (ushort) mode); + moxafunc(ofsAddr, FC_SetDataMode, (u16)mode); + + if (MOXA_IS_320(port->board) && baud >= 921600) + return -1; - if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) || - (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) { - if (baud >= 921600L) - return (-1); - } baud = MoxaPortSetBaud(port, baud); if (termio->c_iflag & (IXON | IXOFF | IXANY)) { @@ -2081,51 +1891,37 @@ int MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud) moxa_wait_finish(ofsAddr); } - return (baud); + return baud; } -int MoxaPortGetLineOut(int port, int *dtrState, int *rtsState) +static int MoxaPortGetLineOut(struct moxa_port *port, int *dtrState, + int *rtsState) { + if (dtrState) + *dtrState = !!(port->lineCtrl & DTR_ON); + if (rtsState) + *rtsState = !!(port->lineCtrl & RTS_ON); - if (!MoxaPortIsValid(port)) - return (-1); - if (dtrState) { - if (moxa_ports[port].lineCtrl & DTR_ON) - *dtrState = 1; - else - *dtrState = 0; - } - if (rtsState) { - if (moxa_ports[port].lineCtrl & RTS_ON) - *rtsState = 1; - else - *rtsState = 0; - } - return (0); + return 0; } -void MoxaPortLineCtrl(int port, int dtr, int rts) +static void MoxaPortLineCtrl(struct moxa_port *port, int dtr, int rts) { - void __iomem *ofsAddr; - int mode; + u8 mode = 0; - ofsAddr = moxa_ports[port].tableAddr; - mode = 0; if (dtr) mode |= DTR_ON; if (rts) mode |= RTS_ON; - moxa_ports[port].lineCtrl = mode; - moxafunc(ofsAddr, FC_LineControl, mode); + port->lineCtrl = mode; + moxafunc(port->tableAddr, FC_LineControl, mode); } -void MoxaPortFlowCtrl(int port, int rts, int cts, int txflow, int rxflow, int txany) +static void MoxaPortFlowCtrl(struct moxa_port *port, int rts, int cts, + int txflow, int rxflow, int txany) { - void __iomem *ofsAddr; - int mode; + int mode = 0; - ofsAddr = moxa_ports[port].tableAddr; - mode = 0; if (rts) mode |= RTS_FlowCtl; if (cts) @@ -2136,81 +1932,50 @@ void MoxaPortFlowCtrl(int port, int rts, int cts, int txflow, int rxflow, int tx mode |= Rx_FlowCtl; if (txany) mode |= IXM_IXANY; - moxafunc(ofsAddr, FC_SetFlowCtl, mode); + moxafunc(port->tableAddr, FC_SetFlowCtl, mode); } -int MoxaPortLineStatus(int port) +static int MoxaPortLineStatus(struct moxa_port *port) { void __iomem *ofsAddr; int val; - ofsAddr = moxa_ports[port].tableAddr; - if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) || - (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) { + ofsAddr = port->tableAddr; + if (MOXA_IS_320(port->board)) { moxafunc(ofsAddr, FC_LineStatus, 0); val = readw(ofsAddr + FuncArg); } else { val = readw(ofsAddr + FlagStat) >> 4; } val &= 0x0B; - if (val & 8) { + if (val & 8) val |= 4; - if ((moxa_ports[port].DCDState & DCD_oldstate) == 0) - moxa_ports[port].DCDState = (DCD_oldstate | DCD_changed); - } else { - if (moxa_ports[port].DCDState & DCD_oldstate) - moxa_ports[port].DCDState = DCD_changed; - } + spin_lock_bh(&moxa_lock); + moxa_new_dcdstate(port, val & 8); + spin_unlock_bh(&moxa_lock); val &= 7; - return (val); -} - -int MoxaPortDCDChange(int port) -{ - int n; - - if (moxa_ports[port].chkPort == 0) - return (0); - n = moxa_ports[port].DCDState; - moxa_ports[port].DCDState &= ~DCD_changed; - n &= DCD_changed; - return (n); -} - -int MoxaPortDCDON(int port) -{ - int n; - - if (moxa_ports[port].chkPort == 0) - return (0); - if (moxa_ports[port].DCDState & DCD_oldstate) - n = 1; - else - n = 0; - return (n); + return val; } -int MoxaPortWriteData(int port, unsigned char * buffer, int len) +static int MoxaPortWriteData(struct moxa_port *port, + const unsigned char *buffer, int len) { - int c, total, i; - ushort tail; - int cnt; - ushort head, tx_mask, spage, epage; - ushort pageno, pageofs, bufhead; void __iomem *baseAddr, *ofsAddr, *ofs; + unsigned int c, total; + u16 head, tail, tx_mask, spage, epage; + u16 pageno, pageofs, bufhead; - ofsAddr = moxa_ports[port].tableAddr; - baseAddr = moxa_boards[port / MAX_PORTS_PER_BOARD].basemem; + ofsAddr = port->tableAddr; + baseAddr = port->board->basemem; tx_mask = readw(ofsAddr + TX_mask); spage = readw(ofsAddr + Page_txb); epage = readw(ofsAddr + EndPage_txb); tail = readw(ofsAddr + TXwptr); head = readw(ofsAddr + TXrptr); - c = (head > tail) ? (head - tail - 1) - : (head - tail + tx_mask); + c = (head > tail) ? (head - tail - 1) : (head - tail + tx_mask); if (c > len) c = len; - moxaLog.txcnt[port] += c; + moxaLog.txcnt[port->tty->index] += c; total = c; if (spage == epage) { bufhead = readw(ofsAddr + Ofs_txb); @@ -2222,249 +1987,179 @@ int MoxaPortWriteData(int port, unsigned char * buffer, int len) len = tx_mask + 1 - tail; len = (c > len) ? len : c; ofs = baseAddr + DynPage_addr + bufhead + tail; - for (i = 0; i < len; i++) - writeb(*buffer++, ofs + i); + memcpy_toio(ofs, buffer, len); + buffer += len; tail = (tail + len) & tx_mask; c -= len; } - writew(tail, ofsAddr + TXwptr); } else { - len = c; pageno = spage + (tail >> 13); pageofs = tail & Page_mask; - do { - cnt = Page_size - pageofs; - if (cnt > c) - cnt = c; - c -= cnt; + while (c > 0) { + len = Page_size - pageofs; + if (len > c) + len = c; writeb(pageno, baseAddr + Control_reg); ofs = baseAddr + DynPage_addr + pageofs; - for (i = 0; i < cnt; i++) - writeb(*buffer++, ofs + i); - if (c == 0) { - writew((tail + len) & tx_mask, ofsAddr + TXwptr); - break; - } + memcpy_toio(ofs, buffer, len); + buffer += len; if (++pageno == epage) pageno = spage; pageofs = 0; - } while (1); + c -= len; + } + tail = (tail + total) & tx_mask; } + writew(tail, ofsAddr + TXwptr); writeb(1, ofsAddr + CD180TXirq); /* start to send */ - return (total); + return total; } -int MoxaPortReadData(int port, struct tty_struct *tty) +static int MoxaPortReadData(struct moxa_port *port) { - register ushort head, pageofs; - int i, count, cnt, len, total, remain; - ushort tail, rx_mask, spage, epage; - ushort pageno, bufhead; + struct tty_struct *tty = port->tty; + unsigned char *dst; void __iomem *baseAddr, *ofsAddr, *ofs; + unsigned int count, len, total; + u16 tail, rx_mask, spage, epage; + u16 pageno, pageofs, bufhead, head; - ofsAddr = moxa_ports[port].tableAddr; - baseAddr = moxa_boards[port / MAX_PORTS_PER_BOARD].basemem; + ofsAddr = port->tableAddr; + baseAddr = port->board->basemem; head = readw(ofsAddr + RXrptr); tail = readw(ofsAddr + RXwptr); rx_mask = readw(ofsAddr + RX_mask); spage = readw(ofsAddr + Page_rxb); epage = readw(ofsAddr + EndPage_rxb); - count = (tail >= head) ? (tail - head) - : (tail - head + rx_mask + 1); + count = (tail >= head) ? (tail - head) : (tail - head + rx_mask + 1); if (count == 0) return 0; total = count; - remain = count - total; - moxaLog.rxcnt[port] += total; - count = total; + moxaLog.rxcnt[tty->index] += total; if (spage == epage) { bufhead = readw(ofsAddr + Ofs_rxb); writew(spage, baseAddr + Control_reg); while (count > 0) { - if (tail >= head) - len = tail - head; - else - len = rx_mask + 1 - head; - len = (count > len) ? len : count; ofs = baseAddr + DynPage_addr + bufhead + head; - for (i = 0; i < len; i++) - tty_insert_flip_char(tty, readb(ofs + i), TTY_NORMAL); + len = (tail >= head) ? (tail - head) : + (rx_mask + 1 - head); + len = tty_prepare_flip_string(tty, &dst, + min(len, count)); + memcpy_fromio(dst, ofs, len); head = (head + len) & rx_mask; count -= len; } - writew(head, ofsAddr + RXrptr); } else { - len = count; pageno = spage + (head >> 13); pageofs = head & Page_mask; - do { - cnt = Page_size - pageofs; - if (cnt > count) - cnt = count; - count -= cnt; + while (count > 0) { writew(pageno, baseAddr + Control_reg); ofs = baseAddr + DynPage_addr + pageofs; - for (i = 0; i < cnt; i++) - tty_insert_flip_char(tty, readb(ofs + i), TTY_NORMAL); - if (count == 0) { - writew((head + len) & rx_mask, ofsAddr + RXrptr); - break; - } - if (++pageno == epage) + len = tty_prepare_flip_string(tty, &dst, + min(Page_size - pageofs, count)); + memcpy_fromio(dst, ofs, len); + + count -= len; + pageofs = (pageofs + len) & Page_mask; + if (pageofs == 0 && ++pageno == epage) pageno = spage; - pageofs = 0; - } while (1); + } + head = (head + total) & rx_mask; } - if ((readb(ofsAddr + FlagStat) & Xoff_state) && (remain < LowWater)) { + writew(head, ofsAddr + RXrptr); + if (readb(ofsAddr + FlagStat) & Xoff_state) { moxaLowWaterChk = 1; - moxa_ports[port].lowChkFlag = 1; + port->lowChkFlag = 1; } - return (total); + return total; } -int MoxaPortTxQueue(int port) +static int MoxaPortTxQueue(struct moxa_port *port) { - void __iomem *ofsAddr; - ushort rptr, wptr, mask; - int len; + void __iomem *ofsAddr = port->tableAddr; + u16 rptr, wptr, mask; - ofsAddr = moxa_ports[port].tableAddr; rptr = readw(ofsAddr + TXrptr); wptr = readw(ofsAddr + TXwptr); mask = readw(ofsAddr + TX_mask); - len = (wptr - rptr) & mask; - return (len); + return (wptr - rptr) & mask; } -int MoxaPortTxFree(int port) +static int MoxaPortTxFree(struct moxa_port *port) { - void __iomem *ofsAddr; - ushort rptr, wptr, mask; - int len; + void __iomem *ofsAddr = port->tableAddr; + u16 rptr, wptr, mask; - ofsAddr = moxa_ports[port].tableAddr; rptr = readw(ofsAddr + TXrptr); wptr = readw(ofsAddr + TXwptr); mask = readw(ofsAddr + TX_mask); - len = mask - ((wptr - rptr) & mask); - return (len); + return mask - ((wptr - rptr) & mask); } -int MoxaPortRxQueue(int port) +static int MoxaPortRxQueue(struct moxa_port *port) { - void __iomem *ofsAddr; - ushort rptr, wptr, mask; - int len; + void __iomem *ofsAddr = port->tableAddr; + u16 rptr, wptr, mask; - ofsAddr = moxa_ports[port].tableAddr; rptr = readw(ofsAddr + RXrptr); wptr = readw(ofsAddr + RXwptr); mask = readw(ofsAddr + RX_mask); - len = (wptr - rptr) & mask; - return (len); + return (wptr - rptr) & mask; } - -void MoxaPortTxDisable(int port) +static void MoxaPortTxDisable(struct moxa_port *port) { - void __iomem *ofsAddr; - - ofsAddr = moxa_ports[port].tableAddr; - moxafunc(ofsAddr, FC_SetXoffState, Magic_code); + moxafunc(port->tableAddr, FC_SetXoffState, Magic_code); } -void MoxaPortTxEnable(int port) +static void MoxaPortTxEnable(struct moxa_port *port) { - void __iomem *ofsAddr; - - ofsAddr = moxa_ports[port].tableAddr; - moxafunc(ofsAddr, FC_SetXonState, Magic_code); -} - - -int MoxaPortResetBrkCnt(int port) -{ - ushort cnt; - cnt = moxa_ports[port].breakCnt; - moxa_ports[port].breakCnt = 0; - return (cnt); -} - - -void MoxaPortSendBreak(int port, int ms100) -{ - void __iomem *ofsAddr; - - ofsAddr = moxa_ports[port].tableAddr; - if (ms100) { - moxafunc(ofsAddr, FC_SendBreak, Magic_code); - msleep(ms100 * 10); - } else { - moxafunc(ofsAddr, FC_SendBreak, Magic_code); - msleep(250); - } - moxafunc(ofsAddr, FC_StopBreak, Magic_code); + moxafunc(port->tableAddr, FC_SetXonState, Magic_code); } static int moxa_get_serial_info(struct moxa_port *info, - struct serial_struct __user *retinfo) + struct serial_struct __user *retinfo) { - struct serial_struct tmp; - - memset(&tmp, 0, sizeof(tmp)); - tmp.type = info->type; - tmp.line = info->port; - tmp.port = 0; - tmp.irq = 0; - tmp.flags = info->asyncflags; - tmp.baud_base = 921600; - tmp.close_delay = info->close_delay; - tmp.closing_wait = info->closing_wait; - tmp.custom_divisor = 0; - tmp.hub6 = 0; - if(copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - return (0); + struct serial_struct tmp = { + .type = info->type, + .line = info->tty->index, + .flags = info->asyncflags, + .baud_base = 921600, + .close_delay = info->close_delay + }; + return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0; } static int moxa_set_serial_info(struct moxa_port *info, - struct serial_struct __user *new_info) + struct serial_struct __user *new_info) { struct serial_struct new_serial; - if(copy_from_user(&new_serial, new_info, sizeof(new_serial))) + if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) return -EFAULT; - if ((new_serial.irq != 0) || - (new_serial.port != 0) || -// (new_serial.type != info->type) || - (new_serial.custom_divisor != 0) || - (new_serial.baud_base != 921600)) - return (-EPERM); + if (new_serial.irq != 0 || new_serial.port != 0 || + new_serial.custom_divisor != 0 || + new_serial.baud_base != 921600) + return -EPERM; if (!capable(CAP_SYS_ADMIN)) { if (((new_serial.flags & ~ASYNC_USR_MASK) != (info->asyncflags & ~ASYNC_USR_MASK))) - return (-EPERM); - } else { + return -EPERM; + } else info->close_delay = new_serial.close_delay * HZ / 100; - info->closing_wait = new_serial.closing_wait * HZ / 100; - } new_serial.flags = (new_serial.flags & ~ASYNC_FLAGS); new_serial.flags |= (info->asyncflags & ASYNC_FLAGS); - if (new_serial.type == PORT_16550A) { - MoxaSetFifo(info->port, 1); - } else { - MoxaSetFifo(info->port, 0); - } + MoxaSetFifo(info, new_serial.type == PORT_16550A); info->type = new_serial.type; - return (0); + return 0; } @@ -2472,374 +2167,10 @@ static int moxa_set_serial_info(struct moxa_port *info, /***************************************************************************** * Static local functions: * *****************************************************************************/ -static void moxafunc(void __iomem *ofsAddr, int cmd, ushort arg) -{ - - writew(arg, ofsAddr + FuncArg); - writew(cmd, ofsAddr + FuncCode); - moxa_wait_finish(ofsAddr); -} - -static void moxa_wait_finish(void __iomem *ofsAddr) -{ - unsigned long i, j; - - i = jiffies; - while (readw(ofsAddr + FuncCode) != 0) { - j = jiffies; - if ((j - i) > moxaFuncTout) { - return; - } - } -} - -static void moxa_low_water_check(void __iomem *ofsAddr) -{ - int len; - ushort rptr, wptr, mask; - - if (readb(ofsAddr + FlagStat) & Xoff_state) { - rptr = readw(ofsAddr + RXrptr); - wptr = readw(ofsAddr + RXwptr); - mask = readw(ofsAddr + RX_mask); - len = (wptr - rptr) & mask; - if (len <= Low_water) - moxafunc(ofsAddr, FC_SendXon, 0); - } -} - -static int moxaloadbios(int cardno, unsigned char __user *tmp, int len) -{ - void __iomem *baseAddr; - int i; - - if(len < 0 || len > sizeof(moxaBuff)) - return -EINVAL; - if(copy_from_user(moxaBuff, tmp, len)) - return -EFAULT; - baseAddr = moxa_boards[cardno].basemem; - writeb(HW_reset, baseAddr + Control_reg); /* reset */ - msleep(10); - for (i = 0; i < 4096; i++) - writeb(0, baseAddr + i); /* clear fix page */ - for (i = 0; i < len; i++) - writeb(moxaBuff[i], baseAddr + i); /* download BIOS */ - writeb(0, baseAddr + Control_reg); /* restart */ - return (0); -} - -static int moxafindcard(int cardno) -{ - void __iomem *baseAddr; - ushort tmp; - - baseAddr = moxa_boards[cardno].basemem; - switch (moxa_boards[cardno].boardType) { - case MOXA_BOARD_C218_ISA: - case MOXA_BOARD_C218_PCI: - if ((tmp = readw(baseAddr + C218_key)) != C218_KeyCode) { - return (-1); - } - break; - case MOXA_BOARD_CP204J: - if ((tmp = readw(baseAddr + C218_key)) != CP204J_KeyCode) { - return (-1); - } - break; - default: - if ((tmp = readw(baseAddr + C320_key)) != C320_KeyCode) { - return (-1); - } - if ((tmp = readw(baseAddr + C320_status)) != STS_init) { - return (-2); - } - } - return (0); -} - -static int moxaload320b(int cardno, unsigned char __user *tmp, int len) -{ - void __iomem *baseAddr; - int i; - - if(len < 0 || len > sizeof(moxaBuff)) - return -EINVAL; - if(copy_from_user(moxaBuff, tmp, len)) - return -EFAULT; - baseAddr = moxa_boards[cardno].basemem; - writew(len - 7168 - 2, baseAddr + C320bapi_len); - writeb(1, baseAddr + Control_reg); /* Select Page 1 */ - for (i = 0; i < 7168; i++) - writeb(moxaBuff[i], baseAddr + DynPage_addr + i); - writeb(2, baseAddr + Control_reg); /* Select Page 2 */ - for (i = 0; i < (len - 7168); i++) - writeb(moxaBuff[i + 7168], baseAddr + DynPage_addr + i); - return (0); -} - -static int moxaloadcode(int cardno, unsigned char __user *tmp, int len) -{ - void __iomem *baseAddr, *ofsAddr; - int retval, port, i; - - if(len < 0 || len > sizeof(moxaBuff)) - return -EINVAL; - if(copy_from_user(moxaBuff, tmp, len)) - return -EFAULT; - baseAddr = moxa_boards[cardno].basemem; - switch (moxa_boards[cardno].boardType) { - case MOXA_BOARD_C218_ISA: - case MOXA_BOARD_C218_PCI: - case MOXA_BOARD_CP204J: - retval = moxaloadc218(cardno, baseAddr, len); - if (retval) - return (retval); - port = cardno * MAX_PORTS_PER_BOARD; - for (i = 0; i < moxa_boards[cardno].numPorts; i++, port++) { - struct moxa_port *p = &moxa_ports[port]; - - p->chkPort = 1; - p->curBaud = 9600L; - p->DCDState = 0; - p->tableAddr = baseAddr + Extern_table + Extern_size * i; - ofsAddr = p->tableAddr; - writew(C218rx_mask, ofsAddr + RX_mask); - writew(C218tx_mask, ofsAddr + TX_mask); - writew(C218rx_spage + i * C218buf_pageno, ofsAddr + Page_rxb); - writew(readw(ofsAddr + Page_rxb) + C218rx_pageno, ofsAddr + EndPage_rxb); - - writew(C218tx_spage + i * C218buf_pageno, ofsAddr + Page_txb); - writew(readw(ofsAddr + Page_txb) + C218tx_pageno, ofsAddr + EndPage_txb); - - } - break; - default: - retval = moxaloadc320(cardno, baseAddr, len, - &moxa_boards[cardno].numPorts); - if (retval) - return (retval); - port = cardno * MAX_PORTS_PER_BOARD; - for (i = 0; i < moxa_boards[cardno].numPorts; i++, port++) { - struct moxa_port *p = &moxa_ports[port]; - - p->chkPort = 1; - p->curBaud = 9600L; - p->DCDState = 0; - p->tableAddr = baseAddr + Extern_table + Extern_size * i; - ofsAddr = p->tableAddr; - if (moxa_boards[cardno].numPorts == 8) { - writew(C320p8rx_mask, ofsAddr + RX_mask); - writew(C320p8tx_mask, ofsAddr + TX_mask); - writew(C320p8rx_spage + i * C320p8buf_pgno, ofsAddr + Page_rxb); - writew(readw(ofsAddr + Page_rxb) + C320p8rx_pgno, ofsAddr + EndPage_rxb); - writew(C320p8tx_spage + i * C320p8buf_pgno, ofsAddr + Page_txb); - writew(readw(ofsAddr + Page_txb) + C320p8tx_pgno, ofsAddr + EndPage_txb); - - } else if (moxa_boards[cardno].numPorts == 16) { - writew(C320p16rx_mask, ofsAddr + RX_mask); - writew(C320p16tx_mask, ofsAddr + TX_mask); - writew(C320p16rx_spage + i * C320p16buf_pgno, ofsAddr + Page_rxb); - writew(readw(ofsAddr + Page_rxb) + C320p16rx_pgno, ofsAddr + EndPage_rxb); - writew(C320p16tx_spage + i * C320p16buf_pgno, ofsAddr + Page_txb); - writew(readw(ofsAddr + Page_txb) + C320p16tx_pgno, ofsAddr + EndPage_txb); - - } else if (moxa_boards[cardno].numPorts == 24) { - writew(C320p24rx_mask, ofsAddr + RX_mask); - writew(C320p24tx_mask, ofsAddr + TX_mask); - writew(C320p24rx_spage + i * C320p24buf_pgno, ofsAddr + Page_rxb); - writew(readw(ofsAddr + Page_rxb) + C320p24rx_pgno, ofsAddr + EndPage_rxb); - writew(C320p24tx_spage + i * C320p24buf_pgno, ofsAddr + Page_txb); - writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb); - } else if (moxa_boards[cardno].numPorts == 32) { - writew(C320p32rx_mask, ofsAddr + RX_mask); - writew(C320p32tx_mask, ofsAddr + TX_mask); - writew(C320p32tx_ofs, ofsAddr + Ofs_txb); - writew(C320p32rx_spage + i * C320p32buf_pgno, ofsAddr + Page_rxb); - writew(readb(ofsAddr + Page_rxb), ofsAddr + EndPage_rxb); - writew(C320p32tx_spage + i * C320p32buf_pgno, ofsAddr + Page_txb); - writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb); - } - } - break; - } - moxa_boards[cardno].loadstat = 1; - return (0); -} - -static int moxaloadc218(int cardno, void __iomem *baseAddr, int len) -{ - char retry; - int i, j, len1, len2; - ushort usum, *ptr, keycode; - - if (moxa_boards[cardno].boardType == MOXA_BOARD_CP204J) - keycode = CP204J_KeyCode; - else - keycode = C218_KeyCode; - usum = 0; - len1 = len >> 1; - ptr = (ushort *) moxaBuff; - for (i = 0; i < len1; i++) - usum += le16_to_cpu(*(ptr + i)); - retry = 0; - do { - len1 = len >> 1; - j = 0; - while (len1) { - len2 = (len1 > 2048) ? 2048 : len1; - len1 -= len2; - for (i = 0; i < len2 << 1; i++) - writeb(moxaBuff[i + j], baseAddr + C218_LoadBuf + i); - j += i; - - writew(len2, baseAddr + C218DLoad_len); - writew(0, baseAddr + C218_key); - for (i = 0; i < 100; i++) { - if (readw(baseAddr + C218_key) == keycode) - break; - msleep(10); - } - if (readw(baseAddr + C218_key) != keycode) { - return (-1); - } - } - writew(0, baseAddr + C218DLoad_len); - writew(usum, baseAddr + C218check_sum); - writew(0, baseAddr + C218_key); - for (i = 0; i < 100; i++) { - if (readw(baseAddr + C218_key) == keycode) - break; - msleep(10); - } - retry++; - } while ((readb(baseAddr + C218chksum_ok) != 1) && (retry < 3)); - if (readb(baseAddr + C218chksum_ok) != 1) { - return (-1); - } - writew(0, baseAddr + C218_key); - for (i = 0; i < 100; i++) { - if (readw(baseAddr + Magic_no) == Magic_code) - break; - msleep(10); - } - if (readw(baseAddr + Magic_no) != Magic_code) { - return (-1); - } - writew(1, baseAddr + Disable_IRQ); - writew(0, baseAddr + Magic_no); - for (i = 0; i < 100; i++) { - if (readw(baseAddr + Magic_no) == Magic_code) - break; - msleep(10); - } - if (readw(baseAddr + Magic_no) != Magic_code) { - return (-1); - } - moxaCard = 1; - moxa_boards[cardno].intNdx = baseAddr + IRQindex; - moxa_boards[cardno].intPend = baseAddr + IRQpending; - moxa_boards[cardno].intTable = baseAddr + IRQtable; - return (0); -} - -static int moxaloadc320(int cardno, void __iomem *baseAddr, int len, int *numPorts) -{ - ushort usum; - int i, j, wlen, len2, retry; - ushort *uptr; - - usum = 0; - wlen = len >> 1; - uptr = (ushort *) moxaBuff; - for (i = 0; i < wlen; i++) - usum += le16_to_cpu(uptr[i]); - retry = 0; - j = 0; - do { - while (wlen) { - if (wlen > 2048) - len2 = 2048; - else - len2 = wlen; - wlen -= len2; - len2 <<= 1; - for (i = 0; i < len2; i++) - writeb(moxaBuff[j + i], baseAddr + C320_LoadBuf + i); - len2 >>= 1; - j += i; - writew(len2, baseAddr + C320DLoad_len); - writew(0, baseAddr + C320_key); - for (i = 0; i < 10; i++) { - if (readw(baseAddr + C320_key) == C320_KeyCode) - break; - msleep(10); - } - if (readw(baseAddr + C320_key) != C320_KeyCode) - return (-1); - } - writew(0, baseAddr + C320DLoad_len); - writew(usum, baseAddr + C320check_sum); - writew(0, baseAddr + C320_key); - for (i = 0; i < 10; i++) { - if (readw(baseAddr + C320_key) == C320_KeyCode) - break; - msleep(10); - } - retry++; - } while ((readb(baseAddr + C320chksum_ok) != 1) && (retry < 3)); - if (readb(baseAddr + C320chksum_ok) != 1) - return (-1); - writew(0, baseAddr + C320_key); - for (i = 0; i < 600; i++) { - if (readw(baseAddr + Magic_no) == Magic_code) - break; - msleep(10); - } - if (readw(baseAddr + Magic_no) != Magic_code) - return (-100); - - if (moxa_boards[cardno].busType == MOXA_BUS_TYPE_PCI) { /* ASIC board */ - writew(0x3800, baseAddr + TMS320_PORT1); - writew(0x3900, baseAddr + TMS320_PORT2); - writew(28499, baseAddr + TMS320_CLOCK); - } else { - writew(0x3200, baseAddr + TMS320_PORT1); - writew(0x3400, baseAddr + TMS320_PORT2); - writew(19999, baseAddr + TMS320_CLOCK); - } - writew(1, baseAddr + Disable_IRQ); - writew(0, baseAddr + Magic_no); - for (i = 0; i < 500; i++) { - if (readw(baseAddr + Magic_no) == Magic_code) - break; - msleep(10); - } - if (readw(baseAddr + Magic_no) != Magic_code) - return (-102); - - j = readw(baseAddr + Module_cnt); - if (j <= 0) - return (-101); - *numPorts = j * 8; - writew(j, baseAddr + Module_no); - writew(0, baseAddr + Magic_no); - for (i = 0; i < 600; i++) { - if (readw(baseAddr + Magic_no) == Magic_code) - break; - msleep(10); - } - if (readw(baseAddr + Magic_no) != Magic_code) - return (-102); - moxaCard = 1; - moxa_boards[cardno].intNdx = baseAddr + IRQindex; - moxa_boards[cardno].intPend = baseAddr + IRQpending; - moxa_boards[cardno].intTable = baseAddr + IRQtable; - return (0); -} -static void MoxaSetFifo(int port, int enable) +static void MoxaSetFifo(struct moxa_port *port, int enable) { - void __iomem *ofsAddr = moxa_ports[port].tableAddr; + void __iomem *ofsAddr = port->tableAddr; if (!enable) { moxafunc(ofsAddr, FC_SetRxFIFOTrig, 0); diff --git a/drivers/char/moxa.h b/drivers/char/moxa.h new file mode 100644 index 000000000000..87d16ce57be7 --- /dev/null +++ b/drivers/char/moxa.h @@ -0,0 +1,304 @@ +#ifndef MOXA_H_FILE +#define MOXA_H_FILE + +#define MOXA 0x400 +#define MOXA_GET_IQUEUE (MOXA + 1) /* get input buffered count */ +#define MOXA_GET_OQUEUE (MOXA + 2) /* get output buffered count */ +#define MOXA_GETDATACOUNT (MOXA + 23) +#define MOXA_GET_IOQUEUE (MOXA + 27) +#define MOXA_FLUSH_QUEUE (MOXA + 28) +#define MOXA_GETMSTATUS (MOXA + 65) + +/* + * System Configuration + */ + +#define Magic_code 0x404 + +/* + * for C218 BIOS initialization + */ +#define C218_ConfBase 0x800 +#define C218_status (C218_ConfBase + 0) /* BIOS running status */ +#define C218_diag (C218_ConfBase + 2) /* diagnostic status */ +#define C218_key (C218_ConfBase + 4) /* WORD (0x218 for C218) */ +#define C218DLoad_len (C218_ConfBase + 6) /* WORD */ +#define C218check_sum (C218_ConfBase + 8) /* BYTE */ +#define C218chksum_ok (C218_ConfBase + 0x0a) /* BYTE (1:ok) */ +#define C218_TestRx (C218_ConfBase + 0x10) /* 8 bytes for 8 ports */ +#define C218_TestTx (C218_ConfBase + 0x18) /* 8 bytes for 8 ports */ +#define C218_RXerr (C218_ConfBase + 0x20) /* 8 bytes for 8 ports */ +#define C218_ErrFlag (C218_ConfBase + 0x28) /* 8 bytes for 8 ports */ + +#define C218_LoadBuf 0x0F00 +#define C218_KeyCode 0x218 +#define CP204J_KeyCode 0x204 + +/* + * for C320 BIOS initialization + */ +#define C320_ConfBase 0x800 +#define C320_LoadBuf 0x0f00 +#define STS_init 0x05 /* for C320_status */ + +#define C320_status C320_ConfBase + 0 /* BIOS running status */ +#define C320_diag C320_ConfBase + 2 /* diagnostic status */ +#define C320_key C320_ConfBase + 4 /* WORD (0320H for C320) */ +#define C320DLoad_len C320_ConfBase + 6 /* WORD */ +#define C320check_sum C320_ConfBase + 8 /* WORD */ +#define C320chksum_ok C320_ConfBase + 0x0a /* WORD (1:ok) */ +#define C320bapi_len C320_ConfBase + 0x0c /* WORD */ +#define C320UART_no C320_ConfBase + 0x0e /* WORD */ + +#define C320_KeyCode 0x320 + +#define FixPage_addr 0x0000 /* starting addr of static page */ +#define DynPage_addr 0x2000 /* starting addr of dynamic page */ +#define C218_start 0x3000 /* starting addr of C218 BIOS prg */ +#define Control_reg 0x1ff0 /* select page and reset control */ +#define HW_reset 0x80 + +/* + * Function Codes + */ +#define FC_CardReset 0x80 +#define FC_ChannelReset 1 /* C320 firmware not supported */ +#define FC_EnableCH 2 +#define FC_DisableCH 3 +#define FC_SetParam 4 +#define FC_SetMode 5 +#define FC_SetRate 6 +#define FC_LineControl 7 +#define FC_LineStatus 8 +#define FC_XmitControl 9 +#define FC_FlushQueue 10 +#define FC_SendBreak 11 +#define FC_StopBreak 12 +#define FC_LoopbackON 13 +#define FC_LoopbackOFF 14 +#define FC_ClrIrqTable 15 +#define FC_SendXon 16 +#define FC_SetTermIrq 17 /* C320 firmware not supported */ +#define FC_SetCntIrq 18 /* C320 firmware not supported */ +#define FC_SetBreakIrq 19 +#define FC_SetLineIrq 20 +#define FC_SetFlowCtl 21 +#define FC_GenIrq 22 +#define FC_InCD180 23 +#define FC_OutCD180 24 +#define FC_InUARTreg 23 +#define FC_OutUARTreg 24 +#define FC_SetXonXoff 25 +#define FC_OutCD180CCR 26 +#define FC_ExtIQueue 27 +#define FC_ExtOQueue 28 +#define FC_ClrLineIrq 29 +#define FC_HWFlowCtl 30 +#define FC_GetClockRate 35 +#define FC_SetBaud 36 +#define FC_SetDataMode 41 +#define FC_GetCCSR 43 +#define FC_GetDataError 45 +#define FC_RxControl 50 +#define FC_ImmSend 51 +#define FC_SetXonState 52 +#define FC_SetXoffState 53 +#define FC_SetRxFIFOTrig 54 +#define FC_SetTxFIFOCnt 55 +#define FC_UnixRate 56 +#define FC_UnixResetTimer 57 + +#define RxFIFOTrig1 0 +#define RxFIFOTrig4 1 +#define RxFIFOTrig8 2 +#define RxFIFOTrig14 3 + +/* + * Dual-Ported RAM + */ +#define DRAM_global 0 +#define INT_data (DRAM_global + 0) +#define Config_base (DRAM_global + 0x108) + +#define IRQindex (INT_data + 0) +#define IRQpending (INT_data + 4) +#define IRQtable (INT_data + 8) + +/* + * Interrupt Status + */ +#define IntrRx 0x01 /* receiver data O.K. */ +#define IntrTx 0x02 /* transmit buffer empty */ +#define IntrFunc 0x04 /* function complete */ +#define IntrBreak 0x08 /* received break */ +#define IntrLine 0x10 /* line status change + for transmitter */ +#define IntrIntr 0x20 /* received INTR code */ +#define IntrQuit 0x40 /* received QUIT code */ +#define IntrEOF 0x80 /* received EOF code */ + +#define IntrRxTrigger 0x100 /* rx data count reach tigger value */ +#define IntrTxTrigger 0x200 /* tx data count below trigger value */ + +#define Magic_no (Config_base + 0) +#define Card_model_no (Config_base + 2) +#define Total_ports (Config_base + 4) +#define Module_cnt (Config_base + 8) +#define Module_no (Config_base + 10) +#define Timer_10ms (Config_base + 14) +#define Disable_IRQ (Config_base + 20) +#define TMS320_PORT1 (Config_base + 22) +#define TMS320_PORT2 (Config_base + 24) +#define TMS320_CLOCK (Config_base + 26) + +/* + * DATA BUFFER in DRAM + */ +#define Extern_table 0x400 /* Base address of the external table + (24 words * 64) total 3K bytes + (24 words * 128) total 6K bytes */ +#define Extern_size 0x60 /* 96 bytes */ +#define RXrptr 0x00 /* read pointer for RX buffer */ +#define RXwptr 0x02 /* write pointer for RX buffer */ +#define TXrptr 0x04 /* read pointer for TX buffer */ +#define TXwptr 0x06 /* write pointer for TX buffer */ +#define HostStat 0x08 /* IRQ flag and general flag */ +#define FlagStat 0x0A +#define FlowControl 0x0C /* B7 B6 B5 B4 B3 B2 B1 B0 */ + /* x x x x | | | | */ + /* | | | + CTS flow */ + /* | | +--- RTS flow */ + /* | +------ TX Xon/Xoff */ + /* +--------- RX Xon/Xoff */ +#define Break_cnt 0x0E /* received break count */ +#define CD180TXirq 0x10 /* if non-0: enable TX irq */ +#define RX_mask 0x12 +#define TX_mask 0x14 +#define Ofs_rxb 0x16 +#define Ofs_txb 0x18 +#define Page_rxb 0x1A +#define Page_txb 0x1C +#define EndPage_rxb 0x1E +#define EndPage_txb 0x20 +#define Data_error 0x22 +#define RxTrigger 0x28 +#define TxTrigger 0x2a + +#define rRXwptr 0x34 +#define Low_water 0x36 + +#define FuncCode 0x40 +#define FuncArg 0x42 +#define FuncArg1 0x44 + +#define C218rx_size 0x2000 /* 8K bytes */ +#define C218tx_size 0x8000 /* 32K bytes */ + +#define C218rx_mask (C218rx_size - 1) +#define C218tx_mask (C218tx_size - 1) + +#define C320p8rx_size 0x2000 +#define C320p8tx_size 0x8000 +#define C320p8rx_mask (C320p8rx_size - 1) +#define C320p8tx_mask (C320p8tx_size - 1) + +#define C320p16rx_size 0x2000 +#define C320p16tx_size 0x4000 +#define C320p16rx_mask (C320p16rx_size - 1) +#define C320p16tx_mask (C320p16tx_size - 1) + +#define C320p24rx_size 0x2000 +#define C320p24tx_size 0x2000 +#define C320p24rx_mask (C320p24rx_size - 1) +#define C320p24tx_mask (C320p24tx_size - 1) + +#define C320p32rx_size 0x1000 +#define C320p32tx_size 0x1000 +#define C320p32rx_mask (C320p32rx_size - 1) +#define C320p32tx_mask (C320p32tx_size - 1) + +#define Page_size 0x2000U +#define Page_mask (Page_size - 1) +#define C218rx_spage 3 +#define C218tx_spage 4 +#define C218rx_pageno 1 +#define C218tx_pageno 4 +#define C218buf_pageno 5 + +#define C320p8rx_spage 3 +#define C320p8tx_spage 4 +#define C320p8rx_pgno 1 +#define C320p8tx_pgno 4 +#define C320p8buf_pgno 5 + +#define C320p16rx_spage 3 +#define C320p16tx_spage 4 +#define C320p16rx_pgno 1 +#define C320p16tx_pgno 2 +#define C320p16buf_pgno 3 + +#define C320p24rx_spage 3 +#define C320p24tx_spage 4 +#define C320p24rx_pgno 1 +#define C320p24tx_pgno 1 +#define C320p24buf_pgno 2 + +#define C320p32rx_spage 3 +#define C320p32tx_ofs C320p32rx_size +#define C320p32tx_spage 3 +#define C320p32buf_pgno 1 + +/* + * Host Status + */ +#define WakeupRx 0x01 +#define WakeupTx 0x02 +#define WakeupBreak 0x08 +#define WakeupLine 0x10 +#define WakeupIntr 0x20 +#define WakeupQuit 0x40 +#define WakeupEOF 0x80 /* used in VTIME control */ +#define WakeupRxTrigger 0x100 +#define WakeupTxTrigger 0x200 +/* + * Flag status + */ +#define Rx_over 0x01 +#define Xoff_state 0x02 +#define Tx_flowOff 0x04 +#define Tx_enable 0x08 +#define CTS_state 0x10 +#define DSR_state 0x20 +#define DCD_state 0x80 +/* + * FlowControl + */ +#define CTS_FlowCtl 1 +#define RTS_FlowCtl 2 +#define Tx_FlowCtl 4 +#define Rx_FlowCtl 8 +#define IXM_IXANY 0x10 + +#define LowWater 128 + +#define DTR_ON 1 +#define RTS_ON 2 +#define CTS_ON 1 +#define DSR_ON 2 +#define DCD_ON 8 + +/* mode definition */ +#define MX_CS8 0x03 +#define MX_CS7 0x02 +#define MX_CS6 0x01 +#define MX_CS5 0x00 + +#define MX_STOP1 0x00 +#define MX_STOP15 0x04 +#define MX_STOP2 0x08 + +#define MX_PARNONE 0x00 +#define MX_PAREVEN 0x40 +#define MX_PARODD 0xC0 + +#endif diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c index ff146c2b08fd..fe2a95b5d3c0 100644 --- a/drivers/char/mspec.c +++ b/drivers/char/mspec.c @@ -180,7 +180,7 @@ mspec_close(struct vm_area_struct *vma) my_page = vdata->maddr[index]; vdata->maddr[index] = 0; if (!mspec_zero_block(my_page, PAGE_SIZE)) - uncached_free_page(my_page); + uncached_free_page(my_page, 1); else printk(KERN_WARNING "mspec_close(): " "failed to zero page %ld\n", my_page); @@ -209,7 +209,7 @@ mspec_nopfn(struct vm_area_struct *vma, unsigned long address) index = (address - vdata->vm_start) >> PAGE_SHIFT; maddr = (volatile unsigned long) vdata->maddr[index]; if (maddr == 0) { - maddr = uncached_alloc_page(numa_node_id()); + maddr = uncached_alloc_page(numa_node_id(), 1); if (maddr == 0) return NOPFN_OOM; @@ -218,7 +218,7 @@ mspec_nopfn(struct vm_area_struct *vma, unsigned long address) vdata->count++; vdata->maddr[index] = maddr; } else { - uncached_free_page(maddr); + uncached_free_page(maddr, 1); maddr = vdata->maddr[index]; } spin_unlock(&vdata->lock); @@ -367,7 +367,7 @@ mspec_init(void) int nasid; unsigned long phys; - scratch_page[nid] = uncached_alloc_page(nid); + scratch_page[nid] = uncached_alloc_page(nid, 1); if (scratch_page[nid] == 0) goto free_scratch_pages; phys = __pa(scratch_page[nid]); @@ -414,7 +414,7 @@ mspec_init(void) free_scratch_pages: for_each_node(nid) { if (scratch_page[nid] != 0) - uncached_free_page(scratch_page[nid]); + uncached_free_page(scratch_page[nid], 1); } return ret; } @@ -431,7 +431,7 @@ mspec_exit(void) for_each_node(nid) { if (scratch_page[nid] != 0) - uncached_free_page(scratch_page[nid]); + uncached_free_page(scratch_page[nid], 1); } } } diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 68c2e9234691..4b81a85c5b53 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -307,6 +307,200 @@ static unsigned char mxser_msr[MXSER_PORTS + 1]; static struct mxser_mon_ext mon_data_ext; static int mxser_set_baud_method[MXSER_PORTS + 1]; +static void mxser_enable_must_enchance_mode(unsigned long baseio) +{ + u8 oldlcr; + u8 efr; + + oldlcr = inb(baseio + UART_LCR); + outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); + + efr = inb(baseio + MOXA_MUST_EFR_REGISTER); + efr |= MOXA_MUST_EFR_EFRB_ENABLE; + + outb(efr, baseio + MOXA_MUST_EFR_REGISTER); + outb(oldlcr, baseio + UART_LCR); +} + +static void mxser_disable_must_enchance_mode(unsigned long baseio) +{ + u8 oldlcr; + u8 efr; + + oldlcr = inb(baseio + UART_LCR); + outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); + + efr = inb(baseio + MOXA_MUST_EFR_REGISTER); + efr &= ~MOXA_MUST_EFR_EFRB_ENABLE; + + outb(efr, baseio + MOXA_MUST_EFR_REGISTER); + outb(oldlcr, baseio + UART_LCR); +} + +static void mxser_set_must_xon1_value(unsigned long baseio, u8 value) +{ + u8 oldlcr; + u8 efr; + + oldlcr = inb(baseio + UART_LCR); + outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); + + efr = inb(baseio + MOXA_MUST_EFR_REGISTER); + efr &= ~MOXA_MUST_EFR_BANK_MASK; + efr |= MOXA_MUST_EFR_BANK0; + + outb(efr, baseio + MOXA_MUST_EFR_REGISTER); + outb(value, baseio + MOXA_MUST_XON1_REGISTER); + outb(oldlcr, baseio + UART_LCR); +} + +static void mxser_set_must_xoff1_value(unsigned long baseio, u8 value) +{ + u8 oldlcr; + u8 efr; + + oldlcr = inb(baseio + UART_LCR); + outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); + + efr = inb(baseio + MOXA_MUST_EFR_REGISTER); + efr &= ~MOXA_MUST_EFR_BANK_MASK; + efr |= MOXA_MUST_EFR_BANK0; + + outb(efr, baseio + MOXA_MUST_EFR_REGISTER); + outb(value, baseio + MOXA_MUST_XOFF1_REGISTER); + outb(oldlcr, baseio + UART_LCR); +} + +static void mxser_set_must_fifo_value(struct mxser_port *info) +{ + u8 oldlcr; + u8 efr; + + oldlcr = inb(info->ioaddr + UART_LCR); + outb(MOXA_MUST_ENTER_ENCHANCE, info->ioaddr + UART_LCR); + + efr = inb(info->ioaddr + MOXA_MUST_EFR_REGISTER); + efr &= ~MOXA_MUST_EFR_BANK_MASK; + efr |= MOXA_MUST_EFR_BANK1; + + outb(efr, info->ioaddr + MOXA_MUST_EFR_REGISTER); + outb((u8)info->rx_high_water, info->ioaddr + MOXA_MUST_RBRTH_REGISTER); + outb((u8)info->rx_trigger, info->ioaddr + MOXA_MUST_RBRTI_REGISTER); + outb((u8)info->rx_low_water, info->ioaddr + MOXA_MUST_RBRTL_REGISTER); + outb(oldlcr, info->ioaddr + UART_LCR); +} + +static void mxser_set_must_enum_value(unsigned long baseio, u8 value) +{ + u8 oldlcr; + u8 efr; + + oldlcr = inb(baseio + UART_LCR); + outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); + + efr = inb(baseio + MOXA_MUST_EFR_REGISTER); + efr &= ~MOXA_MUST_EFR_BANK_MASK; + efr |= MOXA_MUST_EFR_BANK2; + + outb(efr, baseio + MOXA_MUST_EFR_REGISTER); + outb(value, baseio + MOXA_MUST_ENUM_REGISTER); + outb(oldlcr, baseio + UART_LCR); +} + +static void mxser_get_must_hardware_id(unsigned long baseio, u8 *pId) +{ + u8 oldlcr; + u8 efr; + + oldlcr = inb(baseio + UART_LCR); + outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); + + efr = inb(baseio + MOXA_MUST_EFR_REGISTER); + efr &= ~MOXA_MUST_EFR_BANK_MASK; + efr |= MOXA_MUST_EFR_BANK2; + + outb(efr, baseio + MOXA_MUST_EFR_REGISTER); + *pId = inb(baseio + MOXA_MUST_HWID_REGISTER); + outb(oldlcr, baseio + UART_LCR); +} + +static void SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(unsigned long baseio) +{ + u8 oldlcr; + u8 efr; + + oldlcr = inb(baseio + UART_LCR); + outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); + + efr = inb(baseio + MOXA_MUST_EFR_REGISTER); + efr &= ~MOXA_MUST_EFR_SF_MASK; + + outb(efr, baseio + MOXA_MUST_EFR_REGISTER); + outb(oldlcr, baseio + UART_LCR); +} + +static void mxser_enable_must_tx_software_flow_control(unsigned long baseio) +{ + u8 oldlcr; + u8 efr; + + oldlcr = inb(baseio + UART_LCR); + outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); + + efr = inb(baseio + MOXA_MUST_EFR_REGISTER); + efr &= ~MOXA_MUST_EFR_SF_TX_MASK; + efr |= MOXA_MUST_EFR_SF_TX1; + + outb(efr, baseio + MOXA_MUST_EFR_REGISTER); + outb(oldlcr, baseio + UART_LCR); +} + +static void mxser_disable_must_tx_software_flow_control(unsigned long baseio) +{ + u8 oldlcr; + u8 efr; + + oldlcr = inb(baseio + UART_LCR); + outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); + + efr = inb(baseio + MOXA_MUST_EFR_REGISTER); + efr &= ~MOXA_MUST_EFR_SF_TX_MASK; + + outb(efr, baseio + MOXA_MUST_EFR_REGISTER); + outb(oldlcr, baseio + UART_LCR); +} + +static void mxser_enable_must_rx_software_flow_control(unsigned long baseio) +{ + u8 oldlcr; + u8 efr; + + oldlcr = inb(baseio + UART_LCR); + outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); + + efr = inb(baseio + MOXA_MUST_EFR_REGISTER); + efr &= ~MOXA_MUST_EFR_SF_RX_MASK; + efr |= MOXA_MUST_EFR_SF_RX1; + + outb(efr, baseio + MOXA_MUST_EFR_REGISTER); + outb(oldlcr, baseio + UART_LCR); +} + +static void mxser_disable_must_rx_software_flow_control(unsigned long baseio) +{ + u8 oldlcr; + u8 efr; + + oldlcr = inb(baseio + UART_LCR); + outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR); + + efr = inb(baseio + MOXA_MUST_EFR_REGISTER); + efr &= ~MOXA_MUST_EFR_SF_RX_MASK; + + outb(efr, baseio + MOXA_MUST_EFR_REGISTER); + outb(oldlcr, baseio + UART_LCR); +} + #ifdef CONFIG_PCI static int __devinit CheckIsMoxaMust(unsigned long io) { @@ -314,16 +508,16 @@ static int __devinit CheckIsMoxaMust(unsigned long io) int i; outb(0, io + UART_LCR); - DISABLE_MOXA_MUST_ENCHANCE_MODE(io); + mxser_disable_must_enchance_mode(io); oldmcr = inb(io + UART_MCR); outb(0, io + UART_MCR); - SET_MOXA_MUST_XON1_VALUE(io, 0x11); + mxser_set_must_xon1_value(io, 0x11); if ((hwid = inb(io + UART_MCR)) != 0) { outb(oldmcr, io + UART_MCR); return MOXA_OTHER_UART; } - GET_MOXA_MUST_HARDWARE_ID(io, &hwid); + mxser_get_must_hardware_id(io, &hwid); for (i = 1; i < UART_INFO_NUM; i++) { /* 0 = OTHER_UART */ if (hwid == Gpci_uart_info[i].type) return (int)hwid; @@ -494,10 +688,10 @@ static int mxser_set_baud(struct mxser_port *info, long newspd) } else quot /= newspd; - SET_MOXA_MUST_ENUM_VALUE(info->ioaddr, quot); + mxser_set_must_enum_value(info->ioaddr, quot); } else #endif - SET_MOXA_MUST_ENUM_VALUE(info->ioaddr, 0); + mxser_set_must_enum_value(info->ioaddr, 0); return 0; } @@ -553,14 +747,14 @@ static int mxser_change_speed(struct mxser_port *info, if (info->board->chip_flag) { fcr = UART_FCR_ENABLE_FIFO; fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE; - SET_MOXA_MUST_FIFO_VALUE(info); + mxser_set_must_fifo_value(info); } else fcr = 0; } else { fcr = UART_FCR_ENABLE_FIFO; if (info->board->chip_flag) { fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE; - SET_MOXA_MUST_FIFO_VALUE(info); + mxser_set_must_fifo_value(info); } else { switch (info->rx_trigger) { case 1: @@ -657,17 +851,21 @@ static int mxser_change_speed(struct mxser_port *info, } } if (info->board->chip_flag) { - SET_MOXA_MUST_XON1_VALUE(info->ioaddr, START_CHAR(info->tty)); - SET_MOXA_MUST_XOFF1_VALUE(info->ioaddr, STOP_CHAR(info->tty)); + mxser_set_must_xon1_value(info->ioaddr, START_CHAR(info->tty)); + mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(info->tty)); if (I_IXON(info->tty)) { - ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr); + mxser_enable_must_rx_software_flow_control( + info->ioaddr); } else { - DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr); + mxser_disable_must_rx_software_flow_control( + info->ioaddr); } if (I_IXOFF(info->tty)) { - ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr); + mxser_enable_must_tx_software_flow_control( + info->ioaddr); } else { - DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr); + mxser_disable_must_tx_software_flow_control( + info->ioaddr); } } @@ -927,6 +1125,27 @@ static int mxser_open(struct tty_struct *tty, struct file *filp) return 0; } +static void mxser_flush_buffer(struct tty_struct *tty) +{ + struct mxser_port *info = tty->driver_data; + char fcr; + unsigned long flags; + + + spin_lock_irqsave(&info->slock, flags); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + + fcr = inb(info->ioaddr + UART_FCR); + outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), + info->ioaddr + UART_FCR); + outb(fcr, info->ioaddr + UART_FCR); + + spin_unlock_irqrestore(&info->slock, flags); + + tty_wakeup(tty); +} + + /* * This routine is called when the serial port gets closed. First, we * wait for the last remaining data to be sent. Then, we unlink its @@ -1013,9 +1232,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp) } mxser_shutdown(info); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); - + mxser_flush_buffer(tty); tty_ldisc_flush(tty); tty->closing = 0; @@ -1072,16 +1289,16 @@ static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int cou return total; } -static void mxser_put_char(struct tty_struct *tty, unsigned char ch) +static int mxser_put_char(struct tty_struct *tty, unsigned char ch) { struct mxser_port *info = tty->driver_data; unsigned long flags; if (!info->xmit_buf) - return; + return 0; if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) - return; + return 0; spin_lock_irqsave(&info->slock, flags); info->xmit_buf[info->xmit_head++] = ch; @@ -1099,6 +1316,7 @@ static void mxser_put_char(struct tty_struct *tty, unsigned char ch) spin_unlock_irqrestore(&info->slock, flags); } } + return 1; } @@ -1142,26 +1360,6 @@ static int mxser_chars_in_buffer(struct tty_struct *tty) return info->xmit_cnt; } -static void mxser_flush_buffer(struct tty_struct *tty) -{ - struct mxser_port *info = tty->driver_data; - char fcr; - unsigned long flags; - - - spin_lock_irqsave(&info->slock, flags); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - - fcr = inb(info->ioaddr + UART_FCR); - outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), - info->ioaddr + UART_FCR); - outb(fcr, info->ioaddr + UART_FCR); - - spin_unlock_irqrestore(&info->slock, flags); - - tty_wakeup(tty); -} - /* * ------------------------------------------------------------ * friends of mxser_ioctl() @@ -1460,6 +1658,7 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) struct mxser_port *port; int result, status; unsigned int i, j; + int ret = 0; switch (cmd) { case MOXA_GET_MAJOR: @@ -1467,18 +1666,21 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) case MOXA_CHKPORTENABLE: result = 0; - + lock_kernel(); for (i = 0; i < MXSER_BOARDS; i++) for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) if (mxser_boards[i].ports[j].ioaddr) result |= (1 << i); - + unlock_kernel(); return put_user(result, (unsigned long __user *)argp); case MOXA_GETDATACOUNT: + lock_kernel(); if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log))) - return -EFAULT; - return 0; + ret = -EFAULT; + unlock_kernel(); + return ret; case MOXA_GETMSTATUS: + lock_kernel(); for (i = 0; i < MXSER_BOARDS; i++) for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) { port = &mxser_boards[i].ports[j]; @@ -1515,6 +1717,7 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) else GMStatus[i].cts = 0; } + unlock_kernel(); if (copy_to_user(argp, GMStatus, sizeof(struct mxser_mstatus) * MXSER_PORTS)) return -EFAULT; @@ -1524,7 +1727,8 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) unsigned long opmode; unsigned cflag, iflag; - for (i = 0; i < MXSER_BOARDS; i++) + lock_kernel(); + for (i = 0; i < MXSER_BOARDS; i++) { for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) { port = &mxser_boards[i].ports[j]; if (!port->ioaddr) @@ -1589,13 +1793,14 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) mon_data_ext.iftype[i] = opmode; } - if (copy_to_user(argp, &mon_data_ext, - sizeof(mon_data_ext))) - return -EFAULT; - - return 0; - - } default: + } + unlock_kernel(); + if (copy_to_user(argp, &mon_data_ext, + sizeof(mon_data_ext))) + return -EFAULT; + return 0; + } + default: return -ENOIOCTLCMD; } return 0; @@ -1651,16 +1856,20 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, opmode != RS422_MODE && opmode != RS485_4WIRE_MODE) return -EFAULT; + lock_kernel(); mask = ModeMask[p]; shiftbit = p * 2; val = inb(info->opmode_ioaddr); val &= mask; val |= (opmode << shiftbit); outb(val, info->opmode_ioaddr); + unlock_kernel(); } else { + lock_kernel(); shiftbit = p * 2; opmode = inb(info->opmode_ioaddr) >> shiftbit; opmode &= OP_MODE_MASK; + unlock_kernel(); if (put_user(opmode, (int __user *)argp)) return -EFAULT; } @@ -1687,19 +1896,18 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, tty_wait_until_sent(tty, 0); mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4); return 0; - case TIOCGSOFTCAR: - return put_user(!!C_CLOCAL(tty), (unsigned long __user *)argp); - case TIOCSSOFTCAR: - if (get_user(arg, (unsigned long __user *)argp)) - return -EFAULT; - tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); - return 0; case TIOCGSERIAL: - return mxser_get_serial_info(info, argp); + lock_kernel(); + retval = mxser_get_serial_info(info, argp); + unlock_kernel(); + return retval; case TIOCSSERIAL: - return mxser_set_serial_info(info, argp); + lock_kernel(); + retval = mxser_set_serial_info(info, argp); + unlock_kernel(); + return retval; case TIOCSERGETLSR: /* Get line status register */ - return mxser_get_lsr_info(info, argp); + return mxser_get_lsr_info(info, argp); /* * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change * - mask passed in arg for lines of interest @@ -1746,24 +1954,27 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, case MOXA_HighSpeedOn: return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp); case MOXA_SDS_RSTICOUNTER: + lock_kernel(); info->mon_data.rxcnt = 0; info->mon_data.txcnt = 0; + unlock_kernel(); return 0; case MOXA_ASPP_OQUEUE:{ int len, lsr; + lock_kernel(); len = mxser_chars_in_buffer(tty); - lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT; - len += (lsr ? 0 : 1); + unlock_kernel(); return put_user(len, (int __user *)argp); } case MOXA_ASPP_MON: { int mcr, status; + lock_kernel(); status = mxser_get_msr(info->ioaddr, 1, tty->index); mxser_check_modem_status(info, status); @@ -1782,7 +1993,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD; else info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD; - + unlock_kernel(); if (copy_to_user(argp, &info->mon_data, sizeof(struct mxser_mon))) return -EFAULT; @@ -1925,7 +2136,8 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi if (info->board->chip_flag) { spin_lock_irqsave(&info->slock, flags); - DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr); + mxser_disable_must_rx_software_flow_control( + info->ioaddr); spin_unlock_irqrestore(&info->slock, flags); } @@ -1979,6 +2191,7 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout) timeout, char_time); printk("jiff=%lu...", jiffies); #endif + lock_kernel(); while (!((lsr = inb(info->ioaddr + UART_LSR)) & UART_LSR_TEMT)) { #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT printk("lsr = %d (jiff=%lu)...", lsr, jiffies); @@ -1990,6 +2203,7 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout) break; } set_current_state(TASK_RUNNING); + unlock_kernel(); #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); @@ -2342,7 +2556,7 @@ static int __devinit mxser_initbrd(struct mxser_board *brd, /* Enhance mode enabled here */ if (brd->chip_flag != MOXA_OTHER_UART) - ENABLE_MOXA_MUST_ENCHANCE_MODE(info->ioaddr); + mxser_enable_must_enchance_mode(info->ioaddr); info->flags = ASYNC_SHARE_IRQ; info->type = brd->uart_type; diff --git a/drivers/char/mxser.h b/drivers/char/mxser.h index 844171115954..41878a69203d 100644 --- a/drivers/char/mxser.h +++ b/drivers/char/mxser.h @@ -147,141 +147,4 @@ /* Rx software flow control mask */ #define MOXA_MUST_EFR_SF_RX_MASK 0x03 -#define ENABLE_MOXA_MUST_ENCHANCE_MODE(baseio) do { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ - outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr |= MOXA_MUST_EFR_EFRB_ENABLE; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} while (0) - -#define DISABLE_MOXA_MUST_ENCHANCE_MODE(baseio) do { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ - outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_EFRB_ENABLE; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} while (0) - -#define SET_MOXA_MUST_XON1_VALUE(baseio, Value) do { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ - outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ - __efr |= MOXA_MUST_EFR_BANK0; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb((u8)(Value), (baseio)+MOXA_MUST_XON1_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} while (0) - -#define SET_MOXA_MUST_XOFF1_VALUE(baseio, Value) do { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ - outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ - __efr |= MOXA_MUST_EFR_BANK0; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb((u8)(Value), (baseio)+MOXA_MUST_XOFF1_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} while (0) - -#define SET_MOXA_MUST_FIFO_VALUE(info) do { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((info)->ioaddr+UART_LCR); \ - outb(MOXA_MUST_ENTER_ENCHANCE, (info)->ioaddr+UART_LCR);\ - __efr = inb((info)->ioaddr+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ - __efr |= MOXA_MUST_EFR_BANK1; \ - outb(__efr, (info)->ioaddr+MOXA_MUST_EFR_REGISTER); \ - outb((u8)((info)->rx_high_water), (info)->ioaddr+ \ - MOXA_MUST_RBRTH_REGISTER); \ - outb((u8)((info)->rx_trigger), (info)->ioaddr+ \ - MOXA_MUST_RBRTI_REGISTER); \ - outb((u8)((info)->rx_low_water), (info)->ioaddr+ \ - MOXA_MUST_RBRTL_REGISTER); \ - outb(__oldlcr, (info)->ioaddr+UART_LCR); \ -} while (0) - -#define SET_MOXA_MUST_ENUM_VALUE(baseio, Value) do { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ - outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ - __efr |= MOXA_MUST_EFR_BANK2; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb((u8)(Value), (baseio)+MOXA_MUST_ENUM_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} while (0) - -#define GET_MOXA_MUST_HARDWARE_ID(baseio, pId) do { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ - outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_BANK_MASK; \ - __efr |= MOXA_MUST_EFR_BANK2; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - *pId = inb((baseio)+MOXA_MUST_HWID_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} while (0) - -#define SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(baseio) do { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ - outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_SF_MASK; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} while (0) - -#define ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) do { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ - outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \ - __efr |= MOXA_MUST_EFR_SF_TX1; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} while (0) - -#define DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) do { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ - outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} while (0) - -#define ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) do { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ - outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \ - __efr |= MOXA_MUST_EFR_SF_RX1; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} while (0) - -#define DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) do { \ - u8 __oldlcr, __efr; \ - __oldlcr = inb((baseio)+UART_LCR); \ - outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \ - __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \ - __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \ - outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \ - outb(__oldlcr, (baseio)+UART_LCR); \ -} while (0) - #endif diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c index 06803ed5568c..a35bfd7ee80e 100644 --- a/drivers/char/n_hdlc.c +++ b/drivers/char/n_hdlc.c @@ -342,12 +342,10 @@ static int n_hdlc_tty_open (struct tty_struct *tty) #endif /* Flush any pending characters in the driver and discipline. */ - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer (tty); + tty->ldisc.flush_buffer(tty); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer (tty); + tty_driver_flush_buffer(tty); if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_open() success\n",__FILE__,__LINE__); @@ -399,7 +397,7 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) /* Send the next block of data to device */ tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); - actual = tty->driver->write(tty, tbuf->buf, tbuf->count); + actual = tty->ops->write(tty, tbuf->buf, tbuf->count); /* rollback was possible and has been done */ if (actual == -ERESTARTSYS) { @@ -578,26 +576,36 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, return -EFAULT; } + lock_kernel(); + for (;;) { - if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) + if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { + unlock_kernel(); return -EIO; + } n_hdlc = tty2n_hdlc (tty); if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || - tty != n_hdlc->tty) + tty != n_hdlc->tty) { + unlock_kernel(); return 0; + } rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list); if (rbuf) break; /* no data */ - if (file->f_flags & O_NONBLOCK) + if (file->f_flags & O_NONBLOCK) { + unlock_kernel(); return -EAGAIN; + } interruptible_sleep_on (&tty->read_wait); - if (signal_pending(current)) + if (signal_pending(current)) { + unlock_kernel(); return -EINTR; + } } if (rbuf->count > nr) @@ -618,7 +626,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, kfree(rbuf); else n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf); - + unlock_kernel(); return ret; } /* end of n_hdlc_tty_read() */ @@ -661,6 +669,8 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, count = maxframe; } + lock_kernel(); + add_wait_queue(&tty->write_wait, &wait); set_current_state(TASK_INTERRUPTIBLE); @@ -695,7 +705,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, n_hdlc_buf_put(&n_hdlc->tx_buf_list,tbuf); n_hdlc_send_frames(n_hdlc,tty); } - + unlock_kernel(); return error; } /* end of n_hdlc_tty_write() */ @@ -740,8 +750,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, case TIOCOUTQ: /* get the pending tx byte count in the driver */ - count = tty->driver->chars_in_buffer ? - tty->driver->chars_in_buffer(tty) : 0; + count = tty_chars_in_buffer(tty); /* add size of next output frame in queue */ spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags); if (n_hdlc->tx_buf_list.head) diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c index 6b918b80f73e..902169062332 100644 --- a/drivers/char/n_r3964.c +++ b/drivers/char/n_r3964.c @@ -376,8 +376,9 @@ static void put_char(struct r3964_info *pInfo, unsigned char ch) if (tty == NULL) return; - if (tty->driver->put_char) { - tty->driver->put_char(tty, ch); + /* FIXME: put_char should not be called from an IRQ */ + if (tty->ops->put_char) { + tty->ops->put_char(tty, ch); } pInfo->bcc ^= ch; } @@ -386,12 +387,9 @@ static void flush(struct r3964_info *pInfo) { struct tty_struct *tty = pInfo->tty; - if (tty == NULL) + if (tty == NULL || tty->ops->flush_chars == NULL) return; - - if (tty->driver->flush_chars) { - tty->driver->flush_chars(tty); - } + tty->ops->flush_chars(tty); } static void trigger_transmit(struct r3964_info *pInfo) @@ -449,12 +447,11 @@ static void transmit_block(struct r3964_info *pInfo) struct r3964_block_header *pBlock = pInfo->tx_first; int room = 0; - if ((tty == NULL) || (pBlock == NULL)) { + if (tty == NULL || pBlock == NULL) { return; } - if (tty->driver->write_room) - room = tty->driver->write_room(tty); + room = tty_write_room(tty); TRACE_PS("transmit_block %p, room %d, length %d", pBlock, room, pBlock->length); @@ -1075,12 +1072,15 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, TRACE_L("read()"); + lock_kernel(); + pClient = findClient(pInfo, task_pid(current)); if (pClient) { pMsg = remove_msg(pInfo, pClient); if (pMsg == NULL) { /* no messages available. */ if (file->f_flags & O_NONBLOCK) { + unlock_kernel(); return -EAGAIN; } /* block until there is a message: */ @@ -1090,8 +1090,10 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, /* If we still haven't got a message, we must have been signalled */ - if (!pMsg) + if (!pMsg) { + unlock_kernel(); return -EINTR; + } /* deliver msg to client process: */ theMsg.msg_id = pMsg->msg_id; @@ -1102,12 +1104,15 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, kfree(pMsg); TRACE_M("r3964_read - msg kfree %p", pMsg); - if (copy_to_user(buf, &theMsg, count)) + if (copy_to_user(buf, &theMsg, count)) { + unlock_kernel(); return -EFAULT; + } TRACE_PS("read - return %d", count); return count; } + unlock_kernel(); return -EPERM; } @@ -1156,6 +1161,8 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, pHeader->locks = 0; pHeader->owner = NULL; + lock_kernel(); + pClient = findClient(pInfo, task_pid(current)); if (pClient) { pHeader->owner = pClient; @@ -1173,6 +1180,8 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, add_tx_queue(pInfo, pHeader); trigger_transmit(pInfo); + unlock_kernel(); + return 0; } diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 0c09409fa45d..19105ec203f7 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -147,10 +147,8 @@ static void put_tty_queue(unsigned char c, struct tty_struct *tty) static void check_unthrottle(struct tty_struct *tty) { - if (tty->count && - test_and_clear_bit(TTY_THROTTLED, &tty->flags) && - tty->driver->unthrottle) - tty->driver->unthrottle(tty); + if (tty->count) + tty_unthrottle(tty); } /** @@ -183,22 +181,24 @@ static void reset_buffer_flags(struct tty_struct *tty) * at hangup) or when the N_TTY line discipline internally has to * clean the pending queue (for example some signals). * - * FIXME: tty->ctrl_status is not spinlocked and relies on - * lock_kernel() still. + * Locking: ctrl_lock */ static void n_tty_flush_buffer(struct tty_struct *tty) { + unsigned long flags; /* clear everything and unthrottle the driver */ reset_buffer_flags(tty); if (!tty->link) return; + spin_lock_irqsave(&tty->ctrl_lock, flags); if (tty->link->packet) { tty->ctrl_status |= TIOCPKT_FLUSHREAD; wake_up_interruptible(&tty->link->read_wait); } + spin_unlock_irqrestore(&tty->ctrl_lock, flags); } /** @@ -264,17 +264,18 @@ static inline int is_continuation(unsigned char c, struct tty_struct *tty) * relevant in the world today. If you ever need them, add them here. * * Called from both the receive and transmit sides and can be called - * re-entrantly. Relies on lock_kernel() still. + * re-entrantly. Relies on lock_kernel() for tty->column state. */ static int opost(unsigned char c, struct tty_struct *tty) { int space, spaces; - space = tty->driver->write_room(tty); + space = tty_write_room(tty); if (!space) return -1; + lock_kernel(); if (O_OPOST(tty)) { switch (c) { case '\n': @@ -283,7 +284,7 @@ static int opost(unsigned char c, struct tty_struct *tty) if (O_ONLCR(tty)) { if (space < 2) return -1; - tty->driver->put_char(tty, '\r'); + tty_put_char(tty, '\r'); tty->column = 0; } tty->canon_column = tty->column; @@ -305,7 +306,7 @@ static int opost(unsigned char c, struct tty_struct *tty) if (space < spaces) return -1; tty->column += spaces; - tty->driver->write(tty, " ", spaces); + tty->ops->write(tty, " ", spaces); return 0; } tty->column += spaces; @@ -322,7 +323,8 @@ static int opost(unsigned char c, struct tty_struct *tty) break; } } - tty->driver->put_char(tty, c); + tty_put_char(tty, c); + unlock_kernel(); return 0; } @@ -337,7 +339,8 @@ static int opost(unsigned char c, struct tty_struct *tty) * the simple cases normally found and helps to generate blocks of * symbols for the console driver and thus improve performance. * - * Called from write_chan under the tty layer write lock. + * Called from write_chan under the tty layer write lock. Relies + * on lock_kernel for the tty->column state. */ static ssize_t opost_block(struct tty_struct *tty, @@ -347,12 +350,13 @@ static ssize_t opost_block(struct tty_struct *tty, int i; const unsigned char *cp; - space = tty->driver->write_room(tty); + space = tty_write_room(tty); if (!space) return 0; if (nr > space) nr = space; + lock_kernel(); for (i = 0, cp = buf; i < nr; i++, cp++) { switch (*cp) { case '\n': @@ -384,27 +388,15 @@ static ssize_t opost_block(struct tty_struct *tty, } } break_out: - if (tty->driver->flush_chars) - tty->driver->flush_chars(tty); - i = tty->driver->write(tty, buf, i); + if (tty->ops->flush_chars) + tty->ops->flush_chars(tty); + i = tty->ops->write(tty, buf, i); + unlock_kernel(); return i; } /** - * put_char - write character to driver - * @c: character (or part of unicode symbol) - * @tty: terminal device - * - * Queue a byte to the driver layer for output - */ - -static inline void put_char(unsigned char c, struct tty_struct *tty) -{ - tty->driver->put_char(tty, c); -} - -/** * echo_char - echo characters * @c: unicode byte to echo * @tty: terminal device @@ -416,8 +408,8 @@ static inline void put_char(unsigned char c, struct tty_struct *tty) static void echo_char(unsigned char c, struct tty_struct *tty) { if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') { - put_char('^', tty); - put_char(c ^ 0100, tty); + tty_put_char(tty, '^'); + tty_put_char(tty, c ^ 0100); tty->column += 2; } else opost(c, tty); @@ -426,7 +418,7 @@ static void echo_char(unsigned char c, struct tty_struct *tty) static inline void finish_erasing(struct tty_struct *tty) { if (tty->erasing) { - put_char('/', tty); + tty_put_char(tty, '/'); tty->column++; tty->erasing = 0; } @@ -510,7 +502,7 @@ static void eraser(unsigned char c, struct tty_struct *tty) if (L_ECHO(tty)) { if (L_ECHOPRT(tty)) { if (!tty->erasing) { - put_char('\\', tty); + tty_put_char(tty, '\\'); tty->column++; tty->erasing = 1; } @@ -518,7 +510,7 @@ static void eraser(unsigned char c, struct tty_struct *tty) echo_char(c, tty); while (--cnt > 0) { head = (head+1) & (N_TTY_BUF_SIZE-1); - put_char(tty->read_buf[head], tty); + tty_put_char(tty, tty->read_buf[head]); } } else if (kill_type == ERASE && !L_ECHOE(tty)) { echo_char(ERASE_CHAR(tty), tty); @@ -546,22 +538,22 @@ static void eraser(unsigned char c, struct tty_struct *tty) /* Now backup to that column. */ while (tty->column > col) { /* Can't use opost here. */ - put_char('\b', tty); + tty_put_char(tty, '\b'); if (tty->column > 0) tty->column--; } } else { if (iscntrl(c) && L_ECHOCTL(tty)) { - put_char('\b', tty); - put_char(' ', tty); - put_char('\b', tty); + tty_put_char(tty, '\b'); + tty_put_char(tty, ' '); + tty_put_char(tty, '\b'); if (tty->column > 0) tty->column--; } if (!iscntrl(c) || L_ECHOCTL(tty)) { - put_char('\b', tty); - put_char(' ', tty); - put_char('\b', tty); + tty_put_char(tty, '\b'); + tty_put_char(tty, ' '); + tty_put_char(tty, '\b'); if (tty->column > 0) tty->column--; } @@ -592,8 +584,7 @@ static inline void isig(int sig, struct tty_struct *tty, int flush) kill_pgrp(tty->pgrp, sig, 1); if (flush || !L_NOFLSH(tty)) { n_tty_flush_buffer(tty); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + tty_driver_flush_buffer(tty); } } @@ -701,7 +692,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && ((I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty)) || - c == INTR_CHAR(tty) || c == QUIT_CHAR(tty))) + c == INTR_CHAR(tty) || c == QUIT_CHAR(tty) || c == SUSP_CHAR(tty))) start_tty(tty); if (tty->closing) { @@ -725,7 +716,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) tty->lnext = 0; if (L_ECHO(tty)) { if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { - put_char('\a', tty); /* beep if no space */ + tty_put_char(tty, '\a'); /* beep if no space */ return; } /* Record the column of first canon char. */ @@ -739,13 +730,6 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) return; } - if (c == '\r') { - if (I_IGNCR(tty)) - return; - if (I_ICRNL(tty)) - c = '\n'; - } else if (c == '\n' && I_INLCR(tty)) - c = '\r'; if (I_IXON(tty)) { if (c == START_CHAR(tty)) { start_tty(tty); @@ -756,6 +740,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) return; } } + if (L_ISIG(tty)) { int signal; signal = SIGINT; @@ -775,8 +760,7 @@ send_signal: */ if (!L_NOFLSH(tty)) { n_tty_flush_buffer(tty); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + tty_driver_flush_buffer(tty); } if (L_ECHO(tty)) echo_char(c, tty); @@ -785,6 +769,15 @@ send_signal: return; } } + + if (c == '\r') { + if (I_IGNCR(tty)) + return; + if (I_ICRNL(tty)) + c = '\n'; + } else if (c == '\n' && I_INLCR(tty)) + c = '\r'; + if (tty->icanon) { if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) || (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) { @@ -796,8 +789,8 @@ send_signal: if (L_ECHO(tty)) { finish_erasing(tty); if (L_ECHOCTL(tty)) { - put_char('^', tty); - put_char('\b', tty); + tty_put_char(tty, '^'); + tty_put_char(tty, '\b'); } } return; @@ -818,7 +811,7 @@ send_signal: if (c == '\n') { if (L_ECHO(tty) || L_ECHONL(tty)) { if (tty->read_cnt >= N_TTY_BUF_SIZE-1) - put_char('\a', tty); + tty_put_char(tty, '\a'); opost('\n', tty); } goto handle_newline; @@ -836,7 +829,7 @@ send_signal: */ if (L_ECHO(tty)) { if (tty->read_cnt >= N_TTY_BUF_SIZE-1) - put_char('\a', tty); + tty_put_char(tty, '\a'); /* Record the column of first canon char. */ if (tty->canon_head == tty->read_head) tty->canon_column = tty->column; @@ -866,7 +859,7 @@ handle_newline: finish_erasing(tty); if (L_ECHO(tty)) { if (tty->read_cnt >= N_TTY_BUF_SIZE-1) { - put_char('\a', tty); /* beep if no space */ + tty_put_char(tty, '\a'); /* beep if no space */ return; } if (c == '\n') @@ -970,8 +963,8 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, break; } } - if (tty->driver->flush_chars) - tty->driver->flush_chars(tty); + if (tty->ops->flush_chars) + tty->ops->flush_chars(tty); } n_tty_set_room(tty); @@ -987,12 +980,8 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, * mode. We don't want to throttle the driver if we're in * canonical mode and don't have a newline yet! */ - if (tty->receive_room < TTY_THRESHOLD_THROTTLE) { - /* check TTY_THROTTLED first so it indicates our state */ - if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) && - tty->driver->throttle) - tty->driver->throttle(tty); - } + if (tty->receive_room < TTY_THRESHOLD_THROTTLE) + tty_throttle(tty); } int is_ignored(int sig) @@ -1076,6 +1065,9 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) tty->real_raw = 0; } n_tty_set_room(tty); + /* The termios change make the tty ready for I/O */ + wake_up_interruptible(&tty->write_wait); + wake_up_interruptible(&tty->read_wait); } /** @@ -1194,6 +1186,11 @@ extern ssize_t redirected_tty_write(struct file *, const char __user *, * Perform job control management checks on this file/tty descriptor * and if appropriate send any needed signals and return a negative * error code if action should be taken. + * + * FIXME: + * Locking: None - redirected write test is safe, testing + * current->signal should possibly lock current->sighand + * pgrp locking ? */ static int job_control(struct tty_struct *tty, struct file *file) @@ -1246,6 +1243,7 @@ static ssize_t read_chan(struct tty_struct *tty, struct file *file, ssize_t size; long timeout; unsigned long flags; + int packet; do_it_again: @@ -1289,16 +1287,19 @@ do_it_again: if (mutex_lock_interruptible(&tty->atomic_read_lock)) return -ERESTARTSYS; } + packet = tty->packet; add_wait_queue(&tty->read_wait, &wait); while (nr) { /* First test for status change. */ - if (tty->packet && tty->link->ctrl_status) { + if (packet && tty->link->ctrl_status) { unsigned char cs; if (b != buf) break; + spin_lock_irqsave(&tty->link->ctrl_lock, flags); cs = tty->link->ctrl_status; tty->link->ctrl_status = 0; + spin_unlock_irqrestore(&tty->link->ctrl_lock, flags); if (tty_put_user(tty, cs, b++)) { retval = -EFAULT; b--; @@ -1333,6 +1334,7 @@ do_it_again: retval = -ERESTARTSYS; break; } + /* FIXME: does n_tty_set_room need locking ? */ n_tty_set_room(tty); timeout = schedule_timeout(timeout); continue; @@ -1340,7 +1342,7 @@ do_it_again: __set_current_state(TASK_RUNNING); /* Deal with packet mode. */ - if (tty->packet && b == buf) { + if (packet && b == buf) { if (tty_put_user(tty, TIOCPKT_DATA, b++)) { retval = -EFAULT; b--; @@ -1388,6 +1390,8 @@ do_it_again: break; } else { int uncopied; + /* The copy function takes the read lock and handles + locking internally for this case */ uncopied = copy_from_read_buf(tty, &b, &nr); uncopied += copy_from_read_buf(tty, &b, &nr); if (uncopied) { @@ -1429,7 +1433,6 @@ do_it_again: goto do_it_again; n_tty_set_room(tty); - return retval; } @@ -1492,11 +1495,11 @@ static ssize_t write_chan(struct tty_struct *tty, struct file *file, break; b++; nr--; } - if (tty->driver->flush_chars) - tty->driver->flush_chars(tty); + if (tty->ops->flush_chars) + tty->ops->flush_chars(tty); } else { while (nr > 0) { - c = tty->driver->write(tty, b, nr); + c = tty->ops->write(tty, b, nr); if (c < 0) { retval = c; goto break_out; @@ -1533,11 +1536,6 @@ break_out: * * This code must be sure never to sleep through a hangup. * Called without the kernel lock held - fine - * - * FIXME: if someone changes the VMIN or discipline settings for the - * terminal while another process is in poll() the poll does not - * recompute the new limits. Possibly set_termios should issue - * a read wakeup to fix this bug. */ static unsigned int normal_poll(struct tty_struct *tty, struct file *file, @@ -1561,9 +1559,9 @@ static unsigned int normal_poll(struct tty_struct *tty, struct file *file, else tty->minimum_to_wake = 1; } - if (!tty_is_writelocked(tty) && - tty->driver->chars_in_buffer(tty) < WAKEUP_CHARS && - tty->driver->write_room(tty) > 0) + if (tty->ops->write && !tty_is_writelocked(tty) && + tty_chars_in_buffer(tty) < WAKEUP_CHARS && + tty_write_room(tty) > 0) mask |= POLLOUT | POLLWRNORM; return mask; } diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c index 6a6843a0a674..66a0f931c66c 100644 --- a/drivers/char/nozomi.c +++ b/drivers/char/nozomi.c @@ -73,7 +73,7 @@ do { \ char tmp[P_BUF_SIZE]; \ snprintf(tmp, sizeof(tmp), ##args); \ printk(_err_flag_ "[%d] %s(): %s\n", __LINE__, \ - __FUNCTION__, tmp); \ + __func__, tmp); \ } while (0) #define DBG1(args...) D_(0x01, ##args) @@ -1407,7 +1407,7 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev, /* Find out what card type it is */ nozomi_get_card_type(dc); - dc->base_addr = ioremap(start, dc->card_type); + dc->base_addr = ioremap_nocache(start, dc->card_type); if (!dc->base_addr) { dev_err(&pdev->dev, "Unable to map card MMIO\n"); ret = -ENODEV; @@ -1724,6 +1724,8 @@ static int ntty_tiocmget(struct tty_struct *tty, struct file *file) const struct ctrl_dl *ctrl_dl = &port->ctrl_dl; const struct ctrl_ul *ctrl_ul = &port->ctrl_ul; + /* Note: these could change under us but it is not clear this + matters if so */ return (ctrl_ul->RTS ? TIOCM_RTS : 0) | (ctrl_ul->DTR ? TIOCM_DTR : 0) | (ctrl_dl->DCD ? TIOCM_CAR : 0) | @@ -1849,16 +1851,6 @@ static void ntty_throttle(struct tty_struct *tty) spin_unlock_irqrestore(&dc->spin_mutex, flags); } -/* just to discard single character writes */ -static void ntty_put_char(struct tty_struct *tty, unsigned char c) -{ - /* - * card does not react correct when we write single chars - * to the card, so we discard them - */ - DBG2("PUT CHAR Function: %c", c); -} - /* Returns number of chars in buffer, called by tty layer */ static s32 ntty_chars_in_buffer(struct tty_struct *tty) { @@ -1892,7 +1884,6 @@ static const struct tty_operations tty_ops = { .unthrottle = ntty_unthrottle, .throttle = ntty_throttle, .chars_in_buffer = ntty_chars_in_buffer, - .put_char = ntty_put_char, .tiocmget = ntty_tiocmget, .tiocmset = ntty_tiocmset, }; diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index 454d7324ba40..4a933d413423 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -53,7 +53,7 @@ module_param(pc_debug, int, 0600); #define DEBUGP(n, rdr, x, args...) do { \ if (pc_debug >= (n)) \ dev_printk(KERN_DEBUG, reader_to_dev(rdr), "%s:" x, \ - __FUNCTION__ , ## args); \ + __func__ , ## args); \ } while (0) #else #define DEBUGP(n, rdr, x, args...) diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index 5f291bf739a6..035084c07329 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -47,7 +47,7 @@ module_param(pc_debug, int, 0600); #define DEBUGP(n, rdr, x, args...) do { \ if (pc_debug >= (n)) \ dev_printk(KERN_DEBUG, reader_to_dev(rdr), "%s:" x, \ - __FUNCTION__ , ##args); \ + __func__ , ##args); \ } while (0) #else #define DEBUGP(n, rdr, x, args...) diff --git a/drivers/char/pcmcia/ipwireless/hardware.c b/drivers/char/pcmcia/ipwireless/hardware.c index 1f978ff87fa8..fa9d3c945f31 100644 --- a/drivers/char/pcmcia/ipwireless/hardware.c +++ b/drivers/char/pcmcia/ipwireless/hardware.c @@ -354,32 +354,6 @@ struct ipw_rx_packet { unsigned int channel_idx; }; -#ifdef IPWIRELESS_STATE_DEBUG -int ipwireless_dump_hardware_state(char *p, size_t limit, - struct ipw_hardware *hw) -{ - return snprintf(p, limit, - "debug: initializing=%d\n" - "debug: tx_ready=%d\n" - "debug: tx_queued=%d\n" - "debug: rx_ready=%d\n" - "debug: rx_bytes_queued=%d\n" - "debug: blocking_rx=%d\n" - "debug: removed=%d\n" - "debug: hardware.shutting_down=%d\n" - "debug: to_setup=%d\n", - hw->initializing, - hw->tx_ready, - hw->tx_queued, - hw->rx_ready, - hw->rx_bytes_queued, - hw->blocking_rx, - hw->removed, - hw->shutting_down, - hw->to_setup); -} -#endif - static char *data_type(const unsigned char *buf, unsigned length) { struct nl_packet_header *hdr = (struct nl_packet_header *) buf; diff --git a/drivers/char/pcmcia/ipwireless/hardware.h b/drivers/char/pcmcia/ipwireless/hardware.h index c83190ffb0e7..19ce5eb266b1 100644 --- a/drivers/char/pcmcia/ipwireless/hardware.h +++ b/drivers/char/pcmcia/ipwireless/hardware.h @@ -58,7 +58,5 @@ void ipwireless_init_hardware_v1(struct ipw_hardware *hw, void *reboot_cb_data); void ipwireless_init_hardware_v2_v3(struct ipw_hardware *hw); void ipwireless_sleep(unsigned int tenths); -int ipwireless_dump_hardware_state(char *p, size_t limit, - struct ipw_hardware *hw); #endif diff --git a/drivers/char/pcmcia/ipwireless/network.c b/drivers/char/pcmcia/ipwireless/network.c index d793e68b3e0d..fe914d34f7f6 100644 --- a/drivers/char/pcmcia/ipwireless/network.c +++ b/drivers/char/pcmcia/ipwireless/network.c @@ -63,21 +63,6 @@ struct ipw_network { struct work_struct work_go_offline; }; - -#ifdef IPWIRELESS_STATE_DEBUG -int ipwireless_dump_network_state(char *p, size_t limit, - struct ipw_network *network) -{ - return snprintf(p, limit, - "debug: ppp_blocked=%d\n" - "debug: outgoing_packets_queued=%d\n" - "debug: network.shutting_down=%d\n", - network->ppp_blocked, - network->outgoing_packets_queued, - network->shutting_down); -} -#endif - static void notify_packet_sent(void *callback_data, unsigned int packet_length) { struct ipw_network *network = callback_data; diff --git a/drivers/char/pcmcia/ipwireless/network.h b/drivers/char/pcmcia/ipwireless/network.h index b0e1e952fd14..ccacd26fc7ef 100644 --- a/drivers/char/pcmcia/ipwireless/network.h +++ b/drivers/char/pcmcia/ipwireless/network.h @@ -49,7 +49,4 @@ void ipwireless_ppp_close(struct ipw_network *net); int ipwireless_ppp_channel_index(struct ipw_network *net); int ipwireless_ppp_unit_number(struct ipw_network *net); -int ipwireless_dump_network_state(char *p, size_t limit, - struct ipw_network *net); - #endif diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 583356426dfb..1dd0e992c83d 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -503,20 +503,9 @@ static void* mgslpc_get_text_ptr(void) * The wrappers maintain line discipline references * while calling into the line discipline. * - * ldisc_flush_buffer - flush line discipline receive buffers * ldisc_receive_buf - pass receive data to line discipline */ -static void ldisc_flush_buffer(struct tty_struct *tty) -{ - struct tty_ldisc *ld = tty_ldisc_ref(tty); - if (ld) { - if (ld->flush_buffer) - ld->flush_buffer(tty); - tty_ldisc_deref(ld); - } -} - static void ldisc_receive_buf(struct tty_struct *tty, const __u8 *data, char *flags, int count) { @@ -1556,7 +1545,7 @@ static void mgslpc_change_params(MGSLPC_INFO *info) /* Add a character to the transmit buffer */ -static void mgslpc_put_char(struct tty_struct *tty, unsigned char ch) +static int mgslpc_put_char(struct tty_struct *tty, unsigned char ch) { MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data; unsigned long flags; @@ -1567,10 +1556,10 @@ static void mgslpc_put_char(struct tty_struct *tty, unsigned char ch) } if (mgslpc_paranoia_check(info, tty->name, "mgslpc_put_char")) - return; + return 0; if (!info->tx_buf) - return; + return 0; spin_lock_irqsave(&info->lock,flags); @@ -1583,6 +1572,7 @@ static void mgslpc_put_char(struct tty_struct *tty, unsigned char ch) } spin_unlock_irqrestore(&info->lock,flags); + return 1; } /* Enable transmitter so remaining characters in the @@ -2467,10 +2457,9 @@ static void mgslpc_close(struct tty_struct *tty, struct file * filp) if (info->flags & ASYNC_INITIALIZED) mgslpc_wait_until_sent(tty, info->timeout); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + mgslpc_flush_buffer(tty); - ldisc_flush_buffer(tty); + tty_ldisc_flush(tty); shutdown(info); diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 706ff34728f1..0a05c038ae6f 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -181,6 +181,7 @@ static int pty_set_lock(struct tty_struct *tty, int __user * arg) static void pty_flush_buffer(struct tty_struct *tty) { struct tty_struct *to = tty->link; + unsigned long flags; if (!to) return; @@ -189,8 +190,10 @@ static void pty_flush_buffer(struct tty_struct *tty) to->ldisc.flush_buffer(to); if (to->packet) { + spin_lock_irqsave(&tty->ctrl_lock, flags); tty->ctrl_status |= TIOCPKT_FLUSHWRITE; wake_up_interruptible(&to->read_wait); + spin_unlock_irqrestore(&tty->ctrl_lock, flags); } } @@ -251,6 +254,18 @@ static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file, static int legacy_count = CONFIG_LEGACY_PTY_COUNT; module_param(legacy_count, int, 0); +static const struct tty_operations pty_ops_bsd = { + .open = pty_open, + .close = pty_close, + .write = pty_write, + .write_room = pty_write_room, + .flush_buffer = pty_flush_buffer, + .chars_in_buffer = pty_chars_in_buffer, + .unthrottle = pty_unthrottle, + .set_termios = pty_set_termios, + .ioctl = pty_bsd_ioctl, +}; + static void __init legacy_pty_init(void) { if (legacy_count <= 0) @@ -281,7 +296,6 @@ static void __init legacy_pty_init(void) pty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW; pty_driver->other = pty_slave_driver; tty_set_operations(pty_driver, &pty_ops); - pty_driver->ioctl = pty_bsd_ioctl; pty_slave_driver->owner = THIS_MODULE; pty_slave_driver->driver_name = "pty_slave"; @@ -374,6 +388,19 @@ static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file, return -ENOIOCTLCMD; } +static const struct tty_operations pty_unix98_ops = { + .open = pty_open, + .close = pty_close, + .write = pty_write, + .write_room = pty_write_room, + .flush_buffer = pty_flush_buffer, + .chars_in_buffer = pty_chars_in_buffer, + .unthrottle = pty_unthrottle, + .set_termios = pty_set_termios, + .ioctl = pty_unix98_ioctl +}; + + static void __init unix98_pty_init(void) { ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX); @@ -400,8 +427,7 @@ static void __init unix98_pty_init(void) ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM; ptm_driver->other = pts_driver; - tty_set_operations(ptm_driver, &pty_ops); - ptm_driver->ioctl = pty_unix98_ioctl; + tty_set_operations(ptm_driver, &pty_unix98_ops); pts_driver->owner = THIS_MODULE; pts_driver->driver_name = "pty_slave"; diff --git a/drivers/char/random.c b/drivers/char/random.c index f43c89f7c449..0cf98bd4f2d2 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -272,7 +272,7 @@ static int random_write_wakeup_thresh = 128; static int trickle_thresh __read_mostly = INPUT_POOL_WORDS * 28; -static DEFINE_PER_CPU(int, trickle_count) = 0; +static DEFINE_PER_CPU(int, trickle_count); /* * A pool of size .poolwords is stirred with a primitive polynomial @@ -370,17 +370,19 @@ static struct poolinfo { */ static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); +static struct fasync_struct *fasync; #if 0 -static int debug = 0; +static int debug; module_param(debug, bool, 0644); -#define DEBUG_ENT(fmt, arg...) do { if (debug) \ - printk(KERN_DEBUG "random %04d %04d %04d: " \ - fmt,\ - input_pool.entropy_count,\ - blocking_pool.entropy_count,\ - nonblocking_pool.entropy_count,\ - ## arg); } while (0) +#define DEBUG_ENT(fmt, arg...) do { \ + if (debug) \ + printk(KERN_DEBUG "random %04d %04d %04d: " \ + fmt,\ + input_pool.entropy_count,\ + blocking_pool.entropy_count,\ + nonblocking_pool.entropy_count,\ + ## arg); } while (0) #else #define DEBUG_ENT(fmt, arg...) do {} while (0) #endif @@ -394,7 +396,7 @@ module_param(debug, bool, 0644); struct entropy_store; struct entropy_store { - /* mostly-read data: */ + /* read-only data: */ struct poolinfo *poolinfo; __u32 *pool; const char *name; @@ -402,7 +404,7 @@ struct entropy_store { struct entropy_store *pull; /* read-write data: */ - spinlock_t lock ____cacheline_aligned_in_smp; + spinlock_t lock; unsigned add_ptr; int entropy_count; int input_rotate; @@ -438,25 +440,26 @@ static struct entropy_store nonblocking_pool = { }; /* - * This function adds a byte into the entropy "pool". It does not + * This function adds bytes into the entropy "pool". It does not * update the entropy estimate. The caller should call - * credit_entropy_store if this is appropriate. + * credit_entropy_bits if this is appropriate. * * The pool is stirred with a primitive polynomial of the appropriate * degree, and then twisted. We twist by three bits at a time because * it's cheap to do so and helps slightly in the expected case where * the entropy is concentrated in the low-order bits. */ -static void __add_entropy_words(struct entropy_store *r, const __u32 *in, - int nwords, __u32 out[16]) +static void mix_pool_bytes_extract(struct entropy_store *r, const void *in, + int nbytes, __u8 out[64]) { static __u32 const twist_table[8] = { 0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158, 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 }; - unsigned long i, add_ptr, tap1, tap2, tap3, tap4, tap5; - int new_rotate, input_rotate; + unsigned long i, j, tap1, tap2, tap3, tap4, tap5; + int input_rotate; int wordmask = r->poolinfo->poolwords - 1; - __u32 w, next_w; + const char *bytes = in; + __u32 w; unsigned long flags; /* Taps are constant, so we can load them without holding r->lock. */ @@ -465,78 +468,76 @@ static void __add_entropy_words(struct entropy_store *r, const __u32 *in, tap3 = r->poolinfo->tap3; tap4 = r->poolinfo->tap4; tap5 = r->poolinfo->tap5; - next_w = *in++; spin_lock_irqsave(&r->lock, flags); - prefetch_range(r->pool, wordmask); input_rotate = r->input_rotate; - add_ptr = r->add_ptr; + i = r->add_ptr; - while (nwords--) { - w = rol32(next_w, input_rotate); - if (nwords > 0) - next_w = *in++; - i = add_ptr = (add_ptr - 1) & wordmask; - /* - * Normally, we add 7 bits of rotation to the pool. - * At the beginning of the pool, add an extra 7 bits - * rotation, so that successive passes spread the - * input bits across the pool evenly. - */ - new_rotate = input_rotate + 14; - if (i) - new_rotate = input_rotate + 7; - input_rotate = new_rotate & 31; + /* mix one byte at a time to simplify size handling and churn faster */ + while (nbytes--) { + w = rol32(*bytes++, input_rotate & 31); + i = (i - 1) & wordmask; /* XOR in the various taps */ + w ^= r->pool[i]; w ^= r->pool[(i + tap1) & wordmask]; w ^= r->pool[(i + tap2) & wordmask]; w ^= r->pool[(i + tap3) & wordmask]; w ^= r->pool[(i + tap4) & wordmask]; w ^= r->pool[(i + tap5) & wordmask]; - w ^= r->pool[i]; + + /* Mix the result back in with a twist */ r->pool[i] = (w >> 3) ^ twist_table[w & 7]; + + /* + * Normally, we add 7 bits of rotation to the pool. + * At the beginning of the pool, add an extra 7 bits + * rotation, so that successive passes spread the + * input bits across the pool evenly. + */ + input_rotate += i ? 7 : 14; } r->input_rotate = input_rotate; - r->add_ptr = add_ptr; + r->add_ptr = i; - if (out) { - for (i = 0; i < 16; i++) { - out[i] = r->pool[add_ptr]; - add_ptr = (add_ptr - 1) & wordmask; - } - } + if (out) + for (j = 0; j < 16; j++) + ((__u32 *)out)[j] = r->pool[(i - j) & wordmask]; spin_unlock_irqrestore(&r->lock, flags); } -static inline void add_entropy_words(struct entropy_store *r, const __u32 *in, - int nwords) +static void mix_pool_bytes(struct entropy_store *r, const void *in, int bytes) { - __add_entropy_words(r, in, nwords, NULL); + mix_pool_bytes_extract(r, in, bytes, NULL); } /* * Credit (or debit) the entropy store with n bits of entropy */ -static void credit_entropy_store(struct entropy_store *r, int nbits) +static void credit_entropy_bits(struct entropy_store *r, int nbits) { unsigned long flags; + if (!nbits) + return; + spin_lock_irqsave(&r->lock, flags); - if (r->entropy_count + nbits < 0) { - DEBUG_ENT("negative entropy/overflow (%d+%d)\n", - r->entropy_count, nbits); + DEBUG_ENT("added %d entropy credits to %s\n", nbits, r->name); + r->entropy_count += nbits; + if (r->entropy_count < 0) { + DEBUG_ENT("negative entropy/overflow\n"); r->entropy_count = 0; - } else if (r->entropy_count + nbits > r->poolinfo->POOLBITS) { + } else if (r->entropy_count > r->poolinfo->POOLBITS) r->entropy_count = r->poolinfo->POOLBITS; - } else { - r->entropy_count += nbits; - if (nbits) - DEBUG_ENT("added %d entropy credits to %s\n", - nbits, r->name); + + /* should we wake readers? */ + if (r == &input_pool && + r->entropy_count >= random_read_wakeup_thresh) { + wake_up_interruptible(&random_read_wait); + kill_fasync(&fasync, SIGIO, POLL_IN); } spin_unlock_irqrestore(&r->lock, flags); @@ -551,7 +552,7 @@ static void credit_entropy_store(struct entropy_store *r, int nbits) /* There is one of these per entropy source */ struct timer_rand_state { cycles_t last_time; - long last_delta,last_delta2; + long last_delta, last_delta2; unsigned dont_count_entropy:1; }; @@ -586,7 +587,7 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) sample.jiffies = jiffies; sample.cycles = get_cycles(); sample.num = num; - add_entropy_words(&input_pool, (u32 *)&sample, sizeof(sample)/4); + mix_pool_bytes(&input_pool, &sample, sizeof(sample)); /* * Calculate number of bits of randomness we probably added. @@ -620,13 +621,9 @@ static void add_timer_randomness(struct timer_rand_state *state, unsigned num) * Round down by 1 bit on general principles, * and limit entropy entimate to 12 bits. */ - credit_entropy_store(&input_pool, - min_t(int, fls(delta>>1), 11)); + credit_entropy_bits(&input_pool, + min_t(int, fls(delta>>1), 11)); } - - if(input_pool.entropy_count >= random_read_wakeup_thresh) - wake_up_interruptible(&random_read_wait); - out: preempt_enable(); } @@ -677,7 +674,7 @@ void add_disk_randomness(struct gendisk *disk) * *********************************************************************/ -static ssize_t extract_entropy(struct entropy_store *r, void * buf, +static ssize_t extract_entropy(struct entropy_store *r, void *buf, size_t nbytes, int min, int rsvd); /* @@ -704,10 +701,10 @@ static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) "(%d of %d requested)\n", r->name, bytes * 8, nbytes * 8, r->entropy_count); - bytes=extract_entropy(r->pull, tmp, bytes, - random_read_wakeup_thresh / 8, rsvd); - add_entropy_words(r, tmp, (bytes + 3) / 4); - credit_entropy_store(r, bytes*8); + bytes = extract_entropy(r->pull, tmp, bytes, + random_read_wakeup_thresh / 8, rsvd); + mix_pool_bytes(r, tmp, bytes); + credit_entropy_bits(r, bytes*8); } } @@ -744,13 +741,15 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min, if (r->limit && nbytes + reserved >= r->entropy_count / 8) nbytes = r->entropy_count/8 - reserved; - if(r->entropy_count / 8 >= nbytes + reserved) + if (r->entropy_count / 8 >= nbytes + reserved) r->entropy_count -= nbytes*8; else r->entropy_count = reserved; - if (r->entropy_count < random_write_wakeup_thresh) + if (r->entropy_count < random_write_wakeup_thresh) { wake_up_interruptible(&random_write_wait); + kill_fasync(&fasync, SIGIO, POLL_OUT); + } } DEBUG_ENT("debiting %d entropy credits from %s%s\n", @@ -764,45 +763,46 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min, static void extract_buf(struct entropy_store *r, __u8 *out) { int i; - __u32 data[16], buf[5 + SHA_WORKSPACE_WORDS]; + __u32 hash[5], workspace[SHA_WORKSPACE_WORDS]; + __u8 extract[64]; + + /* Generate a hash across the pool, 16 words (512 bits) at a time */ + sha_init(hash); + for (i = 0; i < r->poolinfo->poolwords; i += 16) + sha_transform(hash, (__u8 *)(r->pool + i), workspace); - sha_init(buf); /* - * As we hash the pool, we mix intermediate values of - * the hash back into the pool. This eliminates - * backtracking attacks (where the attacker knows - * the state of the pool plus the current outputs, and - * attempts to find previous ouputs), unless the hash - * function can be inverted. + * We mix the hash back into the pool to prevent backtracking + * attacks (where the attacker knows the state of the pool + * plus the current outputs, and attempts to find previous + * ouputs), unless the hash function can be inverted. By + * mixing at least a SHA1 worth of hash data back, we make + * brute-forcing the feedback as hard as brute-forcing the + * hash. */ - for (i = 0; i < r->poolinfo->poolwords; i += 16) { - /* hash blocks of 16 words = 512 bits */ - sha_transform(buf, (__u8 *)(r->pool + i), buf + 5); - /* feed back portion of the resulting hash */ - add_entropy_words(r, &buf[i % 5], 1); - } + mix_pool_bytes_extract(r, hash, sizeof(hash), extract); /* - * To avoid duplicates, we atomically extract a - * portion of the pool while mixing, and hash one - * final time. + * To avoid duplicates, we atomically extract a portion of the + * pool while mixing, and hash one final time. */ - __add_entropy_words(r, &buf[i % 5], 1, data); - sha_transform(buf, (__u8 *)data, buf + 5); + sha_transform(hash, extract, workspace); + memset(extract, 0, sizeof(extract)); + memset(workspace, 0, sizeof(workspace)); /* - * In case the hash function has some recognizable - * output pattern, we fold it in half. + * In case the hash function has some recognizable output + * pattern, we fold it in half. Thus, we always feed back + * twice as much data as we output. */ - - buf[0] ^= buf[3]; - buf[1] ^= buf[4]; - buf[2] ^= rol32(buf[2], 16); - memcpy(out, buf, EXTRACT_SIZE); - memset(buf, 0, sizeof(buf)); + hash[0] ^= hash[3]; + hash[1] ^= hash[4]; + hash[2] ^= rol32(hash[2], 16); + memcpy(out, hash, EXTRACT_SIZE); + memset(hash, 0, sizeof(hash)); } -static ssize_t extract_entropy(struct entropy_store *r, void * buf, +static ssize_t extract_entropy(struct entropy_store *r, void *buf, size_t nbytes, int min, int reserved) { ssize_t ret = 0, i; @@ -872,7 +872,6 @@ void get_random_bytes(void *buf, int nbytes) { extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0); } - EXPORT_SYMBOL(get_random_bytes); /* @@ -894,12 +893,11 @@ static void init_std_data(struct entropy_store *r) spin_unlock_irqrestore(&r->lock, flags); now = ktime_get_real(); - add_entropy_words(r, (__u32 *)&now, sizeof(now)/4); - add_entropy_words(r, (__u32 *)utsname(), - sizeof(*(utsname()))/4); + mix_pool_bytes(r, &now, sizeof(now)); + mix_pool_bytes(r, utsname(), sizeof(*(utsname()))); } -static int __init rand_initialize(void) +static int rand_initialize(void) { init_std_data(&input_pool); init_std_data(&blocking_pool); @@ -940,7 +938,7 @@ void rand_initialize_disk(struct gendisk *disk) #endif static ssize_t -random_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos) +random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) { ssize_t n, retval = 0, count = 0; @@ -1002,8 +1000,7 @@ random_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos) } static ssize_t -urandom_read(struct file * file, char __user * buf, - size_t nbytes, loff_t *ppos) +urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) { return extract_entropy_user(&nonblocking_pool, buf, nbytes); } @@ -1038,16 +1035,15 @@ write_pool(struct entropy_store *r, const char __user *buffer, size_t count) count -= bytes; p += bytes; - add_entropy_words(r, buf, (bytes + 3) / 4); + mix_pool_bytes(r, buf, bytes); cond_resched(); } return 0; } -static ssize_t -random_write(struct file * file, const char __user * buffer, - size_t count, loff_t *ppos) +static ssize_t random_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) { size_t ret; struct inode *inode = file->f_path.dentry->d_inode; @@ -1064,9 +1060,7 @@ random_write(struct file * file, const char __user * buffer, return (ssize_t)count; } -static int -random_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) +static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) { int size, ent_count; int __user *p = (int __user *)arg; @@ -1074,8 +1068,8 @@ random_ioctl(struct inode * inode, struct file * file, switch (cmd) { case RNDGETENTCNT: - ent_count = input_pool.entropy_count; - if (put_user(ent_count, p)) + /* inherently racy, no point locking */ + if (put_user(input_pool.entropy_count, p)) return -EFAULT; return 0; case RNDADDTOENTCNT: @@ -1083,13 +1077,7 @@ random_ioctl(struct inode * inode, struct file * file, return -EPERM; if (get_user(ent_count, p)) return -EFAULT; - credit_entropy_store(&input_pool, ent_count); - /* - * Wake up waiting processes if we have enough - * entropy. - */ - if (input_pool.entropy_count >= random_read_wakeup_thresh) - wake_up_interruptible(&random_read_wait); + credit_entropy_bits(&input_pool, ent_count); return 0; case RNDADDENTROPY: if (!capable(CAP_SYS_ADMIN)) @@ -1104,39 +1092,45 @@ random_ioctl(struct inode * inode, struct file * file, size); if (retval < 0) return retval; - credit_entropy_store(&input_pool, ent_count); - /* - * Wake up waiting processes if we have enough - * entropy. - */ - if (input_pool.entropy_count >= random_read_wakeup_thresh) - wake_up_interruptible(&random_read_wait); + credit_entropy_bits(&input_pool, ent_count); return 0; case RNDZAPENTCNT: case RNDCLEARPOOL: /* Clear the entropy pool counters. */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; - init_std_data(&input_pool); - init_std_data(&blocking_pool); - init_std_data(&nonblocking_pool); + rand_initialize(); return 0; default: return -EINVAL; } } +static int random_fasync(int fd, struct file *filp, int on) +{ + return fasync_helper(fd, filp, on, &fasync); +} + +static int random_release(struct inode *inode, struct file *filp) +{ + return fasync_helper(-1, filp, 0, &fasync); +} + const struct file_operations random_fops = { .read = random_read, .write = random_write, .poll = random_poll, - .ioctl = random_ioctl, + .unlocked_ioctl = random_ioctl, + .fasync = random_fasync, + .release = random_release, }; const struct file_operations urandom_fops = { .read = urandom_read, .write = random_write, - .ioctl = random_ioctl, + .unlocked_ioctl = random_ioctl, + .fasync = random_fasync, + .release = random_release, }; /*************************************************************** @@ -1157,7 +1151,6 @@ void generate_random_uuid(unsigned char uuid_out[16]) /* Set the UUID variant to DCE */ uuid_out[8] = (uuid_out[8] & 0x3F) | 0x80; } - EXPORT_SYMBOL(generate_random_uuid); /******************************************************************** @@ -1339,7 +1332,7 @@ ctl_table random_table[] = { #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -static __u32 twothirdsMD4Transform (__u32 const buf[4], __u32 const in[12]) +static __u32 twothirdsMD4Transform(__u32 const buf[4], __u32 const in[12]) { __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; @@ -1487,8 +1480,8 @@ __u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr, */ memcpy(hash, saddr, 16); - hash[4]=((__force u16)sport << 16) + (__force u16)dport; - memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7); + hash[4] = ((__force u16)sport << 16) + (__force u16)dport; + memcpy(&hash[5], keyptr->secret, sizeof(__u32) * 7); seq = twothirdsMD4Transform((const __u32 *)daddr, hash) & HASH_MASK; seq += keyptr->count; @@ -1538,10 +1531,10 @@ __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, * Note that the words are placed into the starting vector, which is * then mixed with a partial MD4 over random data. */ - hash[0]=(__force u32)saddr; - hash[1]=(__force u32)daddr; - hash[2]=((__force u16)sport << 16) + (__force u16)dport; - hash[3]=keyptr->secret[11]; + hash[0] = (__force u32)saddr; + hash[1] = (__force u32)daddr; + hash[2] = ((__force u16)sport << 16) + (__force u16)dport; + hash[3] = keyptr->secret[11]; seq = half_md4_transform(hash, keyptr->secret) & HASH_MASK; seq += keyptr->count; @@ -1556,10 +1549,7 @@ __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, * Choosing a clock of 64 ns period is OK. (period of 274 s) */ seq += ktime_to_ns(ktime_get_real()) >> 6; -#if 0 - printk("init_seq(%lx, %lx, %d, %d) = %d\n", - saddr, daddr, sport, dport, seq); -#endif + return seq; } @@ -1582,14 +1572,15 @@ u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport) } #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, __be16 dport) +u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, + __be16 dport) { struct keydata *keyptr = get_keyptr(); u32 hash[12]; memcpy(hash, saddr, 16); hash[4] = (__force u32)dport; - memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7); + memcpy(&hash[5], keyptr->secret, sizeof(__u32) * 7); return twothirdsMD4Transform((const __u32 *)daddr, hash); } @@ -1617,13 +1608,9 @@ u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, seq += ktime_to_ns(ktime_get_real()); seq &= (1ull << 48) - 1; -#if 0 - printk("dccp init_seq(%lx, %lx, %d, %d) = %d\n", - saddr, daddr, sport, dport, seq); -#endif + return seq; } - EXPORT_SYMBOL(secure_dccp_sequence_number); #endif diff --git a/drivers/char/rio/cirrus.h b/drivers/char/rio/cirrus.h index f4f837f86829..a03a538a3efb 100644 --- a/drivers/char/rio/cirrus.h +++ b/drivers/char/rio/cirrus.h @@ -43,83 +43,83 @@ /* Bit fields for particular registers shared with driver */ /* COR1 - driver and RTA */ -#define COR1_ODD 0x80 /* Odd parity */ -#define COR1_EVEN 0x00 /* Even parity */ -#define COR1_NOP 0x00 /* No parity */ -#define COR1_FORCE 0x20 /* Force parity */ -#define COR1_NORMAL 0x40 /* With parity */ -#define COR1_1STOP 0x00 /* 1 stop bit */ -#define COR1_15STOP 0x04 /* 1.5 stop bits */ -#define COR1_2STOP 0x08 /* 2 stop bits */ -#define COR1_5BITS 0x00 /* 5 data bits */ -#define COR1_6BITS 0x01 /* 6 data bits */ -#define COR1_7BITS 0x02 /* 7 data bits */ -#define COR1_8BITS 0x03 /* 8 data bits */ - -#define COR1_HOST 0xef /* Safe host bits */ +#define RIOC_COR1_ODD 0x80 /* Odd parity */ +#define RIOC_COR1_EVEN 0x00 /* Even parity */ +#define RIOC_COR1_NOP 0x00 /* No parity */ +#define RIOC_COR1_FORCE 0x20 /* Force parity */ +#define RIOC_COR1_NORMAL 0x40 /* With parity */ +#define RIOC_COR1_1STOP 0x00 /* 1 stop bit */ +#define RIOC_COR1_15STOP 0x04 /* 1.5 stop bits */ +#define RIOC_COR1_2STOP 0x08 /* 2 stop bits */ +#define RIOC_COR1_5BITS 0x00 /* 5 data bits */ +#define RIOC_COR1_6BITS 0x01 /* 6 data bits */ +#define RIOC_COR1_7BITS 0x02 /* 7 data bits */ +#define RIOC_COR1_8BITS 0x03 /* 8 data bits */ + +#define RIOC_COR1_HOST 0xef /* Safe host bits */ /* RTA only */ -#define COR1_CINPCK 0x00 /* Check parity of received characters */ -#define COR1_CNINPCK 0x10 /* Don't check parity */ +#define RIOC_COR1_CINPCK 0x00 /* Check parity of received characters */ +#define RIOC_COR1_CNINPCK 0x10 /* Don't check parity */ /* COR2 bits for both RTA and driver use */ -#define COR2_IXANY 0x80 /* IXANY - any character is XON */ -#define COR2_IXON 0x40 /* IXON - enable tx soft flowcontrol */ -#define COR2_RTSFLOW 0x02 /* Enable tx hardware flow control */ +#define RIOC_COR2_IXANY 0x80 /* IXANY - any character is XON */ +#define RIOC_COR2_IXON 0x40 /* IXON - enable tx soft flowcontrol */ +#define RIOC_COR2_RTSFLOW 0x02 /* Enable tx hardware flow control */ /* Additional driver bits */ -#define COR2_HUPCL 0x20 /* Hang up on close */ -#define COR2_CTSFLOW 0x04 /* Enable rx hardware flow control */ -#define COR2_IXOFF 0x01 /* Enable rx software flow control */ -#define COR2_DTRFLOW 0x08 /* Enable tx hardware flow control */ +#define RIOC_COR2_HUPCL 0x20 /* Hang up on close */ +#define RIOC_COR2_CTSFLOW 0x04 /* Enable rx hardware flow control */ +#define RIOC_COR2_IXOFF 0x01 /* Enable rx software flow control */ +#define RIOC_COR2_DTRFLOW 0x08 /* Enable tx hardware flow control */ /* RTA use only */ -#define COR2_ETC 0x20 /* Embedded transmit options */ -#define COR2_LOCAL 0x10 /* Local loopback mode */ -#define COR2_REMOTE 0x08 /* Remote loopback mode */ -#define COR2_HOST 0xc2 /* Safe host bits */ +#define RIOC_COR2_ETC 0x20 /* Embedded transmit options */ +#define RIOC_COR2_LOCAL 0x10 /* Local loopback mode */ +#define RIOC_COR2_REMOTE 0x08 /* Remote loopback mode */ +#define RIOC_COR2_HOST 0xc2 /* Safe host bits */ /* COR3 - RTA use only */ -#define COR3_SCDRNG 0x80 /* Enable special char detect for range */ -#define COR3_SCD34 0x40 /* Special character detect for SCHR's 3 + 4 */ -#define COR3_FCT 0x20 /* Flow control transparency */ -#define COR3_SCD12 0x10 /* Special character detect for SCHR's 1 + 2 */ -#define COR3_FIFO12 0x0c /* 12 chars for receive FIFO threshold */ -#define COR3_FIFO10 0x0a /* 10 chars for receive FIFO threshold */ -#define COR3_FIFO8 0x08 /* 8 chars for receive FIFO threshold */ -#define COR3_FIFO6 0x06 /* 6 chars for receive FIFO threshold */ - -#define COR3_THRESHOLD COR3_FIFO8 /* MUST BE LESS THAN MCOR_THRESHOLD */ - -#define COR3_DEFAULT (COR3_FCT | COR3_THRESHOLD) +#define RIOC_COR3_SCDRNG 0x80 /* Enable special char detect for range */ +#define RIOC_COR3_SCD34 0x40 /* Special character detect for SCHR's 3 + 4 */ +#define RIOC_COR3_FCT 0x20 /* Flow control transparency */ +#define RIOC_COR3_SCD12 0x10 /* Special character detect for SCHR's 1 + 2 */ +#define RIOC_COR3_FIFO12 0x0c /* 12 chars for receive FIFO threshold */ +#define RIOC_COR3_FIFO10 0x0a /* 10 chars for receive FIFO threshold */ +#define RIOC_COR3_FIFO8 0x08 /* 8 chars for receive FIFO threshold */ +#define RIOC_COR3_FIFO6 0x06 /* 6 chars for receive FIFO threshold */ + +#define RIOC_COR3_THRESHOLD RIOC_COR3_FIFO8 /* MUST BE LESS THAN MCOR_THRESHOLD */ + +#define RIOC_COR3_DEFAULT (RIOC_COR3_FCT | RIOC_COR3_THRESHOLD) /* Default bits for COR3 */ /* COR4 driver and RTA use */ -#define COR4_IGNCR 0x80 /* Throw away CR's on input */ -#define COR4_ICRNL 0x40 /* Map CR -> NL on input */ -#define COR4_INLCR 0x20 /* Map NL -> CR on input */ -#define COR4_IGNBRK 0x10 /* Ignore Break */ -#define COR4_NBRKINT 0x08 /* No interrupt on break (-BRKINT) */ -#define COR4_RAISEMOD 0x01 /* Raise modem output lines on non-zero baud */ +#define RIOC_COR4_IGNCR 0x80 /* Throw away CR's on input */ +#define RIOC_COR4_ICRNL 0x40 /* Map CR -> NL on input */ +#define RIOC_COR4_INLCR 0x20 /* Map NL -> CR on input */ +#define RIOC_COR4_IGNBRK 0x10 /* Ignore Break */ +#define RIOC_COR4_NBRKINT 0x08 /* No interrupt on break (-BRKINT) */ +#define RIOC_COR4_RAISEMOD 0x01 /* Raise modem output lines on non-zero baud */ /* COR4 driver only */ -#define COR4_IGNPAR 0x04 /* IGNPAR (ignore characters with errors) */ -#define COR4_PARMRK 0x02 /* PARMRK */ +#define RIOC_COR4_IGNPAR 0x04 /* IGNPAR (ignore characters with errors) */ +#define RIOC_COR4_PARMRK 0x02 /* PARMRK */ -#define COR4_HOST 0xf8 /* Safe host bits */ +#define RIOC_COR4_HOST 0xf8 /* Safe host bits */ /* COR4 RTA only */ -#define COR4_CIGNPAR 0x02 /* Thrown away bad characters */ -#define COR4_CPARMRK 0x04 /* PARMRK characters */ -#define COR4_CNPARMRK 0x03 /* Don't PARMRK */ +#define RIOC_COR4_CIGNPAR 0x02 /* Thrown away bad characters */ +#define RIOC_COR4_CPARMRK 0x04 /* PARMRK characters */ +#define RIOC_COR4_CNPARMRK 0x03 /* Don't PARMRK */ /* COR5 driver and RTA use */ -#define COR5_ISTRIP 0x80 /* Strip input chars to 7 bits */ -#define COR5_LNE 0x40 /* Enable LNEXT processing */ -#define COR5_CMOE 0x20 /* Match good and errored characters */ -#define COR5_ONLCR 0x02 /* NL -> CR NL on output */ -#define COR5_OCRNL 0x01 /* CR -> NL on output */ +#define RIOC_COR5_ISTRIP 0x80 /* Strip input chars to 7 bits */ +#define RIOC_COR5_LNE 0x40 /* Enable LNEXT processing */ +#define RIOC_COR5_CMOE 0x20 /* Match good and errored characters */ +#define RIOC_COR5_ONLCR 0x02 /* NL -> CR NL on output */ +#define RIOC_COR5_OCRNL 0x01 /* CR -> NL on output */ /* ** Spare bits - these are not used in the CIRRUS registers, so we use @@ -128,86 +128,86 @@ /* ** tstop and tbusy indication */ -#define COR5_TSTATE_ON 0x08 /* Turn on monitoring of tbusy and tstop */ -#define COR5_TSTATE_OFF 0x04 /* Turn off monitoring of tbusy and tstop */ +#define RIOC_COR5_TSTATE_ON 0x08 /* Turn on monitoring of tbusy and tstop */ +#define RIOC_COR5_TSTATE_OFF 0x04 /* Turn off monitoring of tbusy and tstop */ /* ** TAB3 */ -#define COR5_TAB3 0x10 /* TAB3 mode */ +#define RIOC_COR5_TAB3 0x10 /* TAB3 mode */ -#define COR5_HOST 0xc3 /* Safe host bits */ +#define RIOC_COR5_HOST 0xc3 /* Safe host bits */ /* CCSR */ -#define CCSR_TXFLOFF 0x04 /* Tx is xoffed */ +#define RIOC_CCSR_TXFLOFF 0x04 /* Tx is xoffed */ /* MSVR1 */ /* NB. DTR / CD swapped from Cirrus spec as the pins are also reversed on the RTA. This is because otherwise DCD would get lost on the 1 parallel / 3 serial option. */ -#define MSVR1_CD 0x80 /* CD (DSR on Cirrus) */ -#define MSVR1_RTS 0x40 /* RTS (CTS on Cirrus) */ -#define MSVR1_RI 0x20 /* RI */ -#define MSVR1_DTR 0x10 /* DTR (CD on Cirrus) */ -#define MSVR1_CTS 0x01 /* CTS output pin (RTS on Cirrus) */ +#define RIOC_MSVR1_CD 0x80 /* CD (DSR on Cirrus) */ +#define RIOC_MSVR1_RTS 0x40 /* RTS (CTS on Cirrus) */ +#define RIOC_MSVR1_RI 0x20 /* RI */ +#define RIOC_MSVR1_DTR 0x10 /* DTR (CD on Cirrus) */ +#define RIOC_MSVR1_CTS 0x01 /* CTS output pin (RTS on Cirrus) */ /* Next two used to indicate state of tbusy and tstop to driver */ -#define MSVR1_TSTOP 0x08 /* Set if port flow controlled */ -#define MSVR1_TEMPTY 0x04 /* Set if port tx buffer empty */ +#define RIOC_MSVR1_TSTOP 0x08 /* Set if port flow controlled */ +#define RIOC_MSVR1_TEMPTY 0x04 /* Set if port tx buffer empty */ -#define MSVR1_HOST 0xf3 /* The bits the host wants */ +#define RIOC_MSVR1_HOST 0xf3 /* The bits the host wants */ /* Defines for the subscripts of a CONFIG packet */ -#define CONFIG_COR1 1 /* Option register 1 */ -#define CONFIG_COR2 2 /* Option register 2 */ -#define CONFIG_COR4 3 /* Option register 4 */ -#define CONFIG_COR5 4 /* Option register 5 */ -#define CONFIG_TXXON 5 /* Tx XON character */ -#define CONFIG_TXXOFF 6 /* Tx XOFF character */ -#define CONFIG_RXXON 7 /* Rx XON character */ -#define CONFIG_RXXOFF 8 /* Rx XOFF character */ -#define CONFIG_LNEXT 9 /* LNEXT character */ -#define CONFIG_TXBAUD 10 /* Tx baud rate */ -#define CONFIG_RXBAUD 11 /* Rx baud rate */ - -#define PRE_EMPTIVE 0x80 /* Pre-emptive bit in command field */ +#define RIOC_CONFIG_COR1 1 /* Option register 1 */ +#define RIOC_CONFIG_COR2 2 /* Option register 2 */ +#define RIOC_CONFIG_COR4 3 /* Option register 4 */ +#define RIOC_CONFIG_COR5 4 /* Option register 5 */ +#define RIOC_CONFIG_TXXON 5 /* Tx XON character */ +#define RIOC_CONFIG_TXXOFF 6 /* Tx XOFF character */ +#define RIOC_CONFIG_RXXON 7 /* Rx XON character */ +#define RIOC_CONFIG_RXXOFF 8 /* Rx XOFF character */ +#define RIOC_CONFIG_LNEXT 9 /* LNEXT character */ +#define RIOC_CONFIG_TXBAUD 10 /* Tx baud rate */ +#define RIOC_CONFIG_RXBAUD 11 /* Rx baud rate */ + +#define RIOC_PRE_EMPTIVE 0x80 /* Pre-emptive bit in command field */ /* Packet types going from Host to remote - with the exception of OPEN, MOPEN, CONFIG, SBREAK and MEMDUMP the remaining bytes of the data array will not be used */ -#define OPEN 0x00 /* Open a port */ -#define CONFIG 0x01 /* Configure a port */ -#define MOPEN 0x02 /* Modem open (block for DCD) */ -#define CLOSE 0x03 /* Close a port */ -#define WFLUSH (0x04 | PRE_EMPTIVE) /* Write flush */ -#define RFLUSH (0x05 | PRE_EMPTIVE) /* Read flush */ -#define RESUME (0x06 | PRE_EMPTIVE) /* Resume if xoffed */ -#define SBREAK 0x07 /* Start break */ -#define EBREAK 0x08 /* End break */ -#define SUSPEND (0x09 | PRE_EMPTIVE) /* Susp op (behave as tho xoffed) */ -#define FCLOSE (0x0a | PRE_EMPTIVE) /* Force close */ -#define XPRINT 0x0b /* Xprint packet */ -#define MBIS (0x0c | PRE_EMPTIVE) /* Set modem lines */ -#define MBIC (0x0d | PRE_EMPTIVE) /* Clear modem lines */ -#define MSET (0x0e | PRE_EMPTIVE) /* Set modem lines */ -#define PCLOSE 0x0f /* Pseudo close - Leaves rx/tx enabled */ -#define MGET (0x10 | PRE_EMPTIVE) /* Force update of modem status */ -#define MEMDUMP (0x11 | PRE_EMPTIVE) /* Send back mem from addr supplied */ -#define READ_REGISTER (0x12 | PRE_EMPTIVE) /* Read CD1400 register (debug) */ +#define RIOC_OPEN 0x00 /* Open a port */ +#define RIOC_CONFIG 0x01 /* Configure a port */ +#define RIOC_MOPEN 0x02 /* Modem open (block for DCD) */ +#define RIOC_CLOSE 0x03 /* Close a port */ +#define RIOC_WFLUSH (0x04 | RIOC_PRE_EMPTIVE) /* Write flush */ +#define RIOC_RFLUSH (0x05 | RIOC_PRE_EMPTIVE) /* Read flush */ +#define RIOC_RESUME (0x06 | RIOC_PRE_EMPTIVE) /* Resume if xoffed */ +#define RIOC_SBREAK 0x07 /* Start break */ +#define RIOC_EBREAK 0x08 /* End break */ +#define RIOC_SUSPEND (0x09 | RIOC_PRE_EMPTIVE) /* Susp op (behave as tho xoffed) */ +#define RIOC_FCLOSE (0x0a | RIOC_PRE_EMPTIVE) /* Force close */ +#define RIOC_XPRINT 0x0b /* Xprint packet */ +#define RIOC_MBIS (0x0c | RIOC_PRE_EMPTIVE) /* Set modem lines */ +#define RIOC_MBIC (0x0d | RIOC_PRE_EMPTIVE) /* Clear modem lines */ +#define RIOC_MSET (0x0e | RIOC_PRE_EMPTIVE) /* Set modem lines */ +#define RIOC_PCLOSE 0x0f /* Pseudo close - Leaves rx/tx enabled */ +#define RIOC_MGET (0x10 | RIOC_PRE_EMPTIVE) /* Force update of modem status */ +#define RIOC_MEMDUMP (0x11 | RIOC_PRE_EMPTIVE) /* Send back mem from addr supplied */ +#define RIOC_READ_REGISTER (0x12 | RIOC_PRE_EMPTIVE) /* Read CD1400 register (debug) */ /* "Command" packets going from remote to host COMPLETE and MODEM_STATUS use data[4] / data[3] to indicate current state and modem status respectively */ -#define COMPLETE (0x20 | PRE_EMPTIVE) +#define RIOC_COMPLETE (0x20 | RIOC_PRE_EMPTIVE) /* Command complete */ -#define BREAK_RECEIVED (0x21 | PRE_EMPTIVE) +#define RIOC_BREAK_RECEIVED (0x21 | RIOC_PRE_EMPTIVE) /* Break received */ -#define MODEM_STATUS (0x22 | PRE_EMPTIVE) +#define RIOC_MODEM_STATUS (0x22 | RIOC_PRE_EMPTIVE) /* Change in modem status */ /* "Command" packet that could go either way - handshake wake-up */ -#define HANDSHAKE (0x23 | PRE_EMPTIVE) +#define RIOC_HANDSHAKE (0x23 | RIOC_PRE_EMPTIVE) /* Wake-up to HOST / RTA */ #endif diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index 0ce96670f979..412777cd1e68 100644 --- a/drivers/char/rio/rio_linux.c +++ b/drivers/char/rio/rio_linux.c @@ -344,7 +344,7 @@ int rio_minor(struct tty_struct *tty) static int rio_set_real_termios(void *ptr) { - return RIOParam((struct Port *) ptr, CONFIG, 1, 1); + return RIOParam((struct Port *) ptr, RIOC_CONFIG, 1, 1); } @@ -487,7 +487,7 @@ static int rio_get_CD(void *ptr) int rv; func_enter(); - rv = (PortP->ModemState & MSVR1_CD) != 0; + rv = (PortP->ModemState & RIOC_MSVR1_CD) != 0; rio_dprintk(RIO_DEBUG_INIT, "Getting CD status: %d\n", rv); @@ -607,7 +607,8 @@ static int rio_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd rio_dprintk(RIO_DEBUG_TTY, "BREAK on deleted RTA\n"); rc = -EIO; } else { - if (RIOShortCommand(p, PortP, SBREAK, 2, 250) == RIO_FAIL) { + if (RIOShortCommand(p, PortP, RIOC_SBREAK, 2, 250) == + RIO_FAIL) { rio_dprintk(RIO_DEBUG_INTR, "SBREAK RIOShortCommand failed\n"); rc = -EIO; } @@ -622,7 +623,8 @@ static int rio_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd l = arg ? arg * 100 : 250; if (l > 255) l = 255; - if (RIOShortCommand(p, PortP, SBREAK, 2, arg ? arg * 100 : 250) == RIO_FAIL) { + if (RIOShortCommand(p, PortP, RIOC_SBREAK, 2, + arg ? arg * 100 : 250) == RIO_FAIL) { rio_dprintk(RIO_DEBUG_INTR, "SBREAK RIOShortCommand failed\n"); rc = -EIO; } diff --git a/drivers/char/rio/rio_linux.h b/drivers/char/rio/rio_linux.h index dc3f005614a3..7f26cd7c815e 100644 --- a/drivers/char/rio/rio_linux.h +++ b/drivers/char/rio/rio_linux.h @@ -186,9 +186,9 @@ static inline void *rio_memcpy_fromio(void *dest, void __iomem *source, int n) #ifdef DEBUG #define rio_dprintk(f, str...) do { if (rio_debug & f) printk (str);} while (0) -#define func_enter() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter %s\n", __FUNCTION__) -#define func_exit() rio_dprintk (RIO_DEBUG_FLOW, "rio: exit %s\n", __FUNCTION__) -#define func_enter2() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter %s (port %d)\n",__FUNCTION__, port->line) +#define func_enter() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter %s\n", __func__) +#define func_exit() rio_dprintk (RIO_DEBUG_FLOW, "rio: exit %s\n", __func__) +#define func_enter2() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter %s (port %d)\n",__func__, port->line) #else #define rio_dprintk(f, str...) /* nothing */ #define func_enter() diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c index bf36959fc121..7b96e0814887 100644 --- a/drivers/char/rio/riocmd.c +++ b/drivers/char/rio/riocmd.c @@ -417,7 +417,7 @@ static int RIOCommandRup(struct rio_info *p, uint Rup, struct Host *HostP, struc PortP = p->RIOPortp[SysPort]; rio_spin_lock_irqsave(&PortP->portSem, flags); switch (readb(&PktCmdP->Command)) { - case BREAK_RECEIVED: + case RIOC_BREAK_RECEIVED: rio_dprintk(RIO_DEBUG_CMD, "Received a break!\n"); /* If the current line disc. is not multi-threading and the current processor is not the default, reset rup_intr @@ -428,16 +428,16 @@ static int RIOCommandRup(struct rio_info *p, uint Rup, struct Host *HostP, struc gs_got_break(&PortP->gs); break; - case COMPLETE: + case RIOC_COMPLETE: rio_dprintk(RIO_DEBUG_CMD, "Command complete on phb %d host %Zd\n", readb(&PktCmdP->PhbNum), HostP - p->RIOHosts); subCommand = 1; switch (readb(&PktCmdP->SubCommand)) { - case MEMDUMP: + case RIOC_MEMDUMP: rio_dprintk(RIO_DEBUG_CMD, "Memory dump cmd (0x%x) from addr 0x%x\n", readb(&PktCmdP->SubCommand), readw(&PktCmdP->SubAddr)); break; - case READ_REGISTER: + case RIOC_READ_REGISTER: rio_dprintk(RIO_DEBUG_CMD, "Read register (0x%x)\n", readw(&PktCmdP->SubAddr)); - p->CdRegister = (readb(&PktCmdP->ModemStatus) & MSVR1_HOST); + p->CdRegister = (readb(&PktCmdP->ModemStatus) & RIOC_MSVR1_HOST); break; default: subCommand = 0; @@ -456,14 +456,15 @@ static int RIOCommandRup(struct rio_info *p, uint Rup, struct Host *HostP, struc rio_dprintk(RIO_DEBUG_CMD, "No change\n"); /* FALLTHROUGH */ - case MODEM_STATUS: + case RIOC_MODEM_STATUS: /* ** Knock out the tbusy and tstop bits, as these are not relevant ** to the check for modem status change (they're just there because ** it's a convenient place to put them!). */ ReportedModemStatus = readb(&PktCmdP->ModemStatus); - if ((PortP->ModemState & MSVR1_HOST) == (ReportedModemStatus & MSVR1_HOST)) { + if ((PortP->ModemState & RIOC_MSVR1_HOST) == + (ReportedModemStatus & RIOC_MSVR1_HOST)) { rio_dprintk(RIO_DEBUG_CMD, "Modem status unchanged 0x%x\n", PortP->ModemState); /* ** Update ModemState just in case tbusy or tstop states have @@ -497,7 +498,7 @@ static int RIOCommandRup(struct rio_info *p, uint Rup, struct Host *HostP, struc /* ** Is there a carrier? */ - if (PortP->ModemState & MSVR1_CD) { + if (PortP->ModemState & RIOC_MSVR1_CD) { /* ** Has carrier just appeared? */ @@ -691,7 +692,7 @@ void RIOPollHostCommands(struct rio_info *p, struct Host *HostP) */ rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags); FreeMe = RIOCommandRup(p, Rup, HostP, PacketP); - if (readb(&PacketP->data[5]) == MEMDUMP) { + if (readb(&PacketP->data[5]) == RIOC_MEMDUMP) { rio_dprintk(RIO_DEBUG_CMD, "Memdump from 0x%x complete\n", readw(&(PacketP->data[6]))); rio_memcpy_fromio(p->RIOMemDump, &(PacketP->data[8]), 32); } diff --git a/drivers/char/rio/rioctrl.c b/drivers/char/rio/rioctrl.c index d8eb2bcbe015..d65ceb9a434a 100644 --- a/drivers/char/rio/rioctrl.c +++ b/drivers/char/rio/rioctrl.c @@ -422,7 +422,8 @@ int riocontrol(struct rio_info *p, dev_t dev, int cmd, unsigned long arg, int su } rio_spin_lock_irqsave(&PortP->portSem, flags); - if (RIOPreemptiveCmd(p, (p->RIOPortp[port]), RESUME) == RIO_FAIL) { + if (RIOPreemptiveCmd(p, (p->RIOPortp[port]), RIOC_RESUME) == + RIO_FAIL) { rio_dprintk(RIO_DEBUG_CTRL, "RIO_RESUME failed\n"); rio_spin_unlock_irqrestore(&PortP->portSem, flags); return -EBUSY; @@ -636,7 +637,8 @@ int riocontrol(struct rio_info *p, dev_t dev, int cmd, unsigned long arg, int su return -ENXIO; } PortP = (p->RIOPortp[PortTty.port]); - RIOParam(PortP, CONFIG, PortP->State & RIO_MODEM, OK_TO_SLEEP); + RIOParam(PortP, RIOC_CONFIG, PortP->State & RIO_MODEM, + OK_TO_SLEEP); return retval; case RIO_SET_PORT_PARAMS: @@ -1247,7 +1249,7 @@ int riocontrol(struct rio_info *p, dev_t dev, int cmd, unsigned long arg, int su rio_spin_lock_irqsave(&PortP->portSem, flags); - if (RIOPreemptiveCmd(p, PortP, MEMDUMP) == RIO_FAIL) { + if (RIOPreemptiveCmd(p, PortP, RIOC_MEMDUMP) == RIO_FAIL) { rio_dprintk(RIO_DEBUG_CTRL, "RIO_MEM_DUMP failed\n"); rio_spin_unlock_irqrestore(&PortP->portSem, flags); return -EBUSY; @@ -1313,7 +1315,8 @@ int riocontrol(struct rio_info *p, dev_t dev, int cmd, unsigned long arg, int su rio_spin_lock_irqsave(&PortP->portSem, flags); - if (RIOPreemptiveCmd(p, PortP, READ_REGISTER) == RIO_FAIL) { + if (RIOPreemptiveCmd(p, PortP, RIOC_READ_REGISTER) == + RIO_FAIL) { rio_dprintk(RIO_DEBUG_CTRL, "RIO_READ_REGISTER failed\n"); rio_spin_unlock_irqrestore(&PortP->portSem, flags); return -EBUSY; @@ -1434,50 +1437,50 @@ int RIOPreemptiveCmd(struct rio_info *p, struct Port *PortP, u8 Cmd) PktCmdP->PhbNum = port; switch (Cmd) { - case MEMDUMP: + case RIOC_MEMDUMP: rio_dprintk(RIO_DEBUG_CTRL, "Queue MEMDUMP command blk %p " "(addr 0x%x)\n", CmdBlkP, (int) SubCmd.Addr); - PktCmdP->SubCommand = MEMDUMP; + PktCmdP->SubCommand = RIOC_MEMDUMP; PktCmdP->SubAddr = SubCmd.Addr; break; - case FCLOSE: + case RIOC_FCLOSE: rio_dprintk(RIO_DEBUG_CTRL, "Queue FCLOSE command blk %p\n", CmdBlkP); break; - case READ_REGISTER: + case RIOC_READ_REGISTER: rio_dprintk(RIO_DEBUG_CTRL, "Queue READ_REGISTER (0x%x) " "command blk %p\n", (int) SubCmd.Addr, CmdBlkP); - PktCmdP->SubCommand = READ_REGISTER; + PktCmdP->SubCommand = RIOC_READ_REGISTER; PktCmdP->SubAddr = SubCmd.Addr; break; - case RESUME: + case RIOC_RESUME: rio_dprintk(RIO_DEBUG_CTRL, "Queue RESUME command blk %p\n", CmdBlkP); break; - case RFLUSH: + case RIOC_RFLUSH: rio_dprintk(RIO_DEBUG_CTRL, "Queue RFLUSH command blk %p\n", CmdBlkP); CmdBlkP->PostFuncP = RIORFlushEnable; break; - case SUSPEND: + case RIOC_SUSPEND: rio_dprintk(RIO_DEBUG_CTRL, "Queue SUSPEND command blk %p\n", CmdBlkP); break; - case MGET: + case RIOC_MGET: rio_dprintk(RIO_DEBUG_CTRL, "Queue MGET command blk %p\n", CmdBlkP); break; - case MSET: - case MBIC: - case MBIS: + case RIOC_MSET: + case RIOC_MBIC: + case RIOC_MBIS: CmdBlkP->Packet.data[4] = (char) PortP->ModemLines; rio_dprintk(RIO_DEBUG_CTRL, "Queue MSET/MBIC/MBIS command " "blk %p\n", CmdBlkP); break; - case WFLUSH: + case RIOC_WFLUSH: /* ** If we have queued up the maximum number of Write flushes ** allowed then we should not bother sending any more to the diff --git a/drivers/char/rio/riointr.c b/drivers/char/rio/riointr.c index 4734e26e1ccd..ea21686c69a4 100644 --- a/drivers/char/rio/riointr.c +++ b/drivers/char/rio/riointr.c @@ -401,9 +401,8 @@ void RIOServiceHost(struct rio_info *p, struct Host *HostP) PortP->InUse = NOT_INUSE; rio_spin_unlock(&PortP->portSem); - if (RIOParam(PortP, OPEN, ((PortP->Cor2Copy & (COR2_RTSFLOW | COR2_CTSFLOW)) == (COR2_RTSFLOW | COR2_CTSFLOW)) ? 1 : 0, DONT_SLEEP) == RIO_FAIL) { + if (RIOParam(PortP, RIOC_OPEN, ((PortP->Cor2Copy & (RIOC_COR2_RTSFLOW | RIOC_COR2_CTSFLOW)) == (RIOC_COR2_RTSFLOW | RIOC_COR2_CTSFLOW)) ? 1 : 0, DONT_SLEEP) == RIO_FAIL) continue; /* with next port */ - } rio_spin_lock(&PortP->portSem); PortP->MagicFlags &= ~MAGIC_REBOOT; } @@ -429,7 +428,7 @@ void RIOServiceHost(struct rio_info *p, struct Host *HostP) */ PktCmdP = (struct PktCmd __iomem *) &PacketP->data[0]; - writeb(WFLUSH, &PktCmdP->Command); + writeb(RIOC_WFLUSH, &PktCmdP->Command); p = PortP->HostPort % (u16) PORTS_PER_RTA; diff --git a/drivers/char/rio/rioparam.c b/drivers/char/rio/rioparam.c index da276ed57b3f..4810b845cc21 100644 --- a/drivers/char/rio/rioparam.c +++ b/drivers/char/rio/rioparam.c @@ -177,7 +177,7 @@ int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag) } rio_spin_lock_irqsave(&PortP->portSem, flags); - if (cmd == OPEN) { + if (cmd == RIOC_OPEN) { /* ** If the port is set to store or lock the parameters, and it is ** paramed with OPEN, we want to restore the saved port termio, but @@ -241,50 +241,50 @@ int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag) case CS5: { rio_dprintk(RIO_DEBUG_PARAM, "5 bit data\n"); - Cor1 |= COR1_5BITS; + Cor1 |= RIOC_COR1_5BITS; break; } case CS6: { rio_dprintk(RIO_DEBUG_PARAM, "6 bit data\n"); - Cor1 |= COR1_6BITS; + Cor1 |= RIOC_COR1_6BITS; break; } case CS7: { rio_dprintk(RIO_DEBUG_PARAM, "7 bit data\n"); - Cor1 |= COR1_7BITS; + Cor1 |= RIOC_COR1_7BITS; break; } case CS8: { rio_dprintk(RIO_DEBUG_PARAM, "8 bit data\n"); - Cor1 |= COR1_8BITS; + Cor1 |= RIOC_COR1_8BITS; break; } } if (TtyP->termios->c_cflag & CSTOPB) { rio_dprintk(RIO_DEBUG_PARAM, "2 stop bits\n"); - Cor1 |= COR1_2STOP; + Cor1 |= RIOC_COR1_2STOP; } else { rio_dprintk(RIO_DEBUG_PARAM, "1 stop bit\n"); - Cor1 |= COR1_1STOP; + Cor1 |= RIOC_COR1_1STOP; } if (TtyP->termios->c_cflag & PARENB) { rio_dprintk(RIO_DEBUG_PARAM, "Enable parity\n"); - Cor1 |= COR1_NORMAL; + Cor1 |= RIOC_COR1_NORMAL; } else { rio_dprintk(RIO_DEBUG_PARAM, "Disable parity\n"); - Cor1 |= COR1_NOP; + Cor1 |= RIOC_COR1_NOP; } if (TtyP->termios->c_cflag & PARODD) { rio_dprintk(RIO_DEBUG_PARAM, "Odd parity\n"); - Cor1 |= COR1_ODD; + Cor1 |= RIOC_COR1_ODD; } else { rio_dprintk(RIO_DEBUG_PARAM, "Even parity\n"); - Cor1 |= COR1_EVEN; + Cor1 |= RIOC_COR1_EVEN; } /* @@ -292,11 +292,11 @@ int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag) */ if (TtyP->termios->c_iflag & IXON) { rio_dprintk(RIO_DEBUG_PARAM, "Enable start/stop output control\n"); - Cor2 |= COR2_IXON; + Cor2 |= RIOC_COR2_IXON; } else { if (PortP->Config & RIO_IXON) { rio_dprintk(RIO_DEBUG_PARAM, "Force enable start/stop output control\n"); - Cor2 |= COR2_IXON; + Cor2 |= RIOC_COR2_IXON; } else rio_dprintk(RIO_DEBUG_PARAM, "IXON has been disabled.\n"); } @@ -304,29 +304,29 @@ int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag) if (TtyP->termios->c_iflag & IXANY) { if (PortP->Config & RIO_IXANY) { rio_dprintk(RIO_DEBUG_PARAM, "Enable any key to restart output\n"); - Cor2 |= COR2_IXANY; + Cor2 |= RIOC_COR2_IXANY; } else rio_dprintk(RIO_DEBUG_PARAM, "IXANY has been disabled due to sanity reasons.\n"); } if (TtyP->termios->c_iflag & IXOFF) { rio_dprintk(RIO_DEBUG_PARAM, "Enable start/stop input control 2\n"); - Cor2 |= COR2_IXOFF; + Cor2 |= RIOC_COR2_IXOFF; } if (TtyP->termios->c_cflag & HUPCL) { rio_dprintk(RIO_DEBUG_PARAM, "Hangup on last close\n"); - Cor2 |= COR2_HUPCL; + Cor2 |= RIOC_COR2_HUPCL; } if (C_CRTSCTS(TtyP)) { rio_dprintk(RIO_DEBUG_PARAM, "Rx hardware flow control enabled\n"); - Cor2 |= COR2_CTSFLOW; - Cor2 |= COR2_RTSFLOW; + Cor2 |= RIOC_COR2_CTSFLOW; + Cor2 |= RIOC_COR2_RTSFLOW; } else { rio_dprintk(RIO_DEBUG_PARAM, "Rx hardware flow control disabled\n"); - Cor2 &= ~COR2_CTSFLOW; - Cor2 &= ~COR2_RTSFLOW; + Cor2 &= ~RIOC_COR2_CTSFLOW; + Cor2 &= ~RIOC_COR2_RTSFLOW; } @@ -341,36 +341,36 @@ int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag) */ if (TtyP->termios->c_iflag & IGNBRK) { rio_dprintk(RIO_DEBUG_PARAM, "Ignore break condition\n"); - Cor4 |= COR4_IGNBRK; + Cor4 |= RIOC_COR4_IGNBRK; } if (!(TtyP->termios->c_iflag & BRKINT)) { rio_dprintk(RIO_DEBUG_PARAM, "Break generates NULL condition\n"); - Cor4 |= COR4_NBRKINT; + Cor4 |= RIOC_COR4_NBRKINT; } else { rio_dprintk(RIO_DEBUG_PARAM, "Interrupt on break condition\n"); } if (TtyP->termios->c_iflag & INLCR) { rio_dprintk(RIO_DEBUG_PARAM, "Map newline to carriage return on input\n"); - Cor4 |= COR4_INLCR; + Cor4 |= RIOC_COR4_INLCR; } if (TtyP->termios->c_iflag & IGNCR) { rio_dprintk(RIO_DEBUG_PARAM, "Ignore carriage return on input\n"); - Cor4 |= COR4_IGNCR; + Cor4 |= RIOC_COR4_IGNCR; } if (TtyP->termios->c_iflag & ICRNL) { rio_dprintk(RIO_DEBUG_PARAM, "Map carriage return to newline on input\n"); - Cor4 |= COR4_ICRNL; + Cor4 |= RIOC_COR4_ICRNL; } if (TtyP->termios->c_iflag & IGNPAR) { rio_dprintk(RIO_DEBUG_PARAM, "Ignore characters with parity errors\n"); - Cor4 |= COR4_IGNPAR; + Cor4 |= RIOC_COR4_IGNPAR; } if (TtyP->termios->c_iflag & PARMRK) { rio_dprintk(RIO_DEBUG_PARAM, "Mark parity errors\n"); - Cor4 |= COR4_PARMRK; + Cor4 |= RIOC_COR4_PARMRK; } /* @@ -378,22 +378,22 @@ int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag) ** on reception of a config packet. ** The download code handles the zero baud condition. */ - Cor4 |= COR4_RAISEMOD; + Cor4 |= RIOC_COR4_RAISEMOD; /* ** COR 5 */ - Cor5 = COR5_CMOE; + Cor5 = RIOC_COR5_CMOE; /* ** Set to monitor tbusy/tstop (or not). */ if (PortP->MonitorTstate) - Cor5 |= COR5_TSTATE_ON; + Cor5 |= RIOC_COR5_TSTATE_ON; else - Cor5 |= COR5_TSTATE_OFF; + Cor5 |= RIOC_COR5_TSTATE_OFF; /* ** Could set LNE here if you wanted LNext processing. SVR4 will use it. @@ -401,24 +401,24 @@ int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag) if (TtyP->termios->c_iflag & ISTRIP) { rio_dprintk(RIO_DEBUG_PARAM, "Strip input characters\n"); if (!(PortP->State & RIO_TRIAD_MODE)) { - Cor5 |= COR5_ISTRIP; + Cor5 |= RIOC_COR5_ISTRIP; } } if (TtyP->termios->c_oflag & ONLCR) { rio_dprintk(RIO_DEBUG_PARAM, "Map newline to carriage-return, newline on output\n"); if (PortP->CookMode == COOK_MEDIUM) - Cor5 |= COR5_ONLCR; + Cor5 |= RIOC_COR5_ONLCR; } if (TtyP->termios->c_oflag & OCRNL) { rio_dprintk(RIO_DEBUG_PARAM, "Map carriage return to newline on output\n"); if (PortP->CookMode == COOK_MEDIUM) - Cor5 |= COR5_OCRNL; + Cor5 |= RIOC_COR5_OCRNL; } if ((TtyP->termios->c_oflag & TABDLY) == TAB3) { rio_dprintk(RIO_DEBUG_PARAM, "Tab delay 3 set\n"); if (PortP->CookMode == COOK_MEDIUM) - Cor5 |= COR5_TAB3; + Cor5 |= RIOC_COR5_TAB3; } /* diff --git a/drivers/char/rio/riotty.c b/drivers/char/rio/riotty.c index 1cb8580a161d..c99354843be1 100644 --- a/drivers/char/rio/riotty.c +++ b/drivers/char/rio/riotty.c @@ -211,7 +211,7 @@ int riotopen(struct tty_struct *tty, struct file *filp) rio_dprintk(RIO_DEBUG_TTY, "Waiting for RIO_CLOSING to go away\n"); if (repeat_this-- <= 0) { rio_dprintk(RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n"); - RIOPreemptiveCmd(p, PortP, FCLOSE); + RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE); retval = -EINTR; goto bombout; } @@ -264,7 +264,7 @@ int riotopen(struct tty_struct *tty, struct file *filp) here. If I read the docs correctly the "open" command piggybacks the parameters immediately. -- REW */ - RIOParam(PortP, OPEN, 1, OK_TO_SLEEP); /* Open the port */ + RIOParam(PortP, RIOC_OPEN, 1, OK_TO_SLEEP); /* Open the port */ rio_spin_lock_irqsave(&PortP->portSem, flags); /* @@ -275,7 +275,7 @@ int riotopen(struct tty_struct *tty, struct file *filp) rio_spin_unlock_irqrestore(&PortP->portSem, flags); if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) { rio_dprintk(RIO_DEBUG_TTY, "Waiting for open to finish broken by signal\n"); - RIOPreemptiveCmd(p, PortP, FCLOSE); + RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE); func_exit(); return -EINTR; } @@ -297,7 +297,8 @@ int riotopen(struct tty_struct *tty, struct file *filp) ** insert test for carrier here. -- ??? ** I already see that test here. What's the deal? -- REW */ - if ((PortP->gs.tty->termios->c_cflag & CLOCAL) || (PortP->ModemState & MSVR1_CD)) { + if ((PortP->gs.tty->termios->c_cflag & CLOCAL) || + (PortP->ModemState & RIOC_MSVR1_CD)) { rio_dprintk(RIO_DEBUG_TTY, "open(%d) Modem carr on\n", SysPort); /* tp->tm.c_state |= CARR_ON; @@ -325,7 +326,7 @@ int riotopen(struct tty_struct *tty, struct file *filp) ** I think it's OK. -- REW */ rio_dprintk(RIO_DEBUG_TTY, "open(%d) sleeping for carr broken by signal\n", SysPort); - RIOPreemptiveCmd(p, PortP, FCLOSE); + RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE); /* tp->tm.c_state &= ~WOPEN; */ @@ -416,7 +417,7 @@ int riotclose(void *ptr) */ PortP->State &= ~RIO_MOPEN; PortP->State &= ~RIO_CARR_ON; - PortP->ModemState &= ~MSVR1_CD; + PortP->ModemState &= ~RIOC_MSVR1_CD; /* ** If the device was open as both a Modem and a tty line ** then we need to wimp out here, as the port has not really @@ -453,7 +454,7 @@ int riotclose(void *ptr) if (repeat_this-- <= 0) { rv = -EINTR; rio_dprintk(RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n"); - RIOPreemptiveCmd(p, PortP, FCLOSE); + RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE); goto close_end; } rio_dprintk(RIO_DEBUG_TTY, "Calling timeout to flush in closing\n"); @@ -492,8 +493,8 @@ int riotclose(void *ptr) /* Can't call RIOShortCommand with the port locked. */ rio_spin_unlock_irqrestore(&PortP->portSem, flags); - if (RIOShortCommand(p, PortP, CLOSE, 1, 0) == RIO_FAIL) { - RIOPreemptiveCmd(p, PortP, FCLOSE); + if (RIOShortCommand(p, PortP, RIOC_CLOSE, 1, 0) == RIO_FAIL) { + RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE); rio_spin_lock_irqsave(&PortP->portSem, flags); goto close_end; } @@ -503,7 +504,7 @@ int riotclose(void *ptr) try--; if (time_after(jiffies, end_time)) { rio_dprintk(RIO_DEBUG_TTY, "Run out of tries - force the bugger shut!\n"); - RIOPreemptiveCmd(p, PortP, FCLOSE); + RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE); break; } rio_dprintk(RIO_DEBUG_TTY, "Close: PortState:ISOPEN is %d\n", PortP->PortState & PORT_ISOPEN); @@ -515,14 +516,14 @@ int riotclose(void *ptr) } if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) { rio_dprintk(RIO_DEBUG_TTY, "RTA EINTR in delay \n"); - RIOPreemptiveCmd(p, PortP, FCLOSE); + RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE); break; } } rio_spin_lock_irqsave(&PortP->portSem, flags); rio_dprintk(RIO_DEBUG_TTY, "Close: try was %d on completion\n", try); - /* RIOPreemptiveCmd(p, PortP, FCLOSE); */ + /* RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE); */ /* ** 15.10.1998 ARG - ESIL 0761 part fix diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index 3f9d0a9ac36d..f073c710ab8d 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c @@ -4,9 +4,9 @@ * Copyright (C) 1994-1996 Dmitry Gorodchanin (pgmdsg@ibi.com) * * This code is loosely based on the Linux serial driver, written by - * Linus Torvalds, Theodore T'so and others. The RISCom/8 card - * programming info was obtained from various drivers for other OSes - * (FreeBSD, ISC, etc), but no source code from those drivers were + * Linus Torvalds, Theodore T'so and others. The RISCom/8 card + * programming info was obtained from various drivers for other OSes + * (FreeBSD, ISC, etc), but no source code from those drivers were * directly included in this driver. * * @@ -33,7 +33,7 @@ #include <linux/module.h> -#include <asm/io.h> +#include <linux/io.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/ioport.h> @@ -49,7 +49,7 @@ #include <linux/tty_flip.h> #include <linux/spinlock.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include "riscom8.h" #include "riscom8_reg.h" @@ -57,15 +57,15 @@ /* Am I paranoid or not ? ;-) */ #define RISCOM_PARANOIA_CHECK -/* - * Crazy InteliCom/8 boards sometimes has swapped CTS & DSR signals. +/* + * Crazy InteliCom/8 boards sometimes have swapped CTS & DSR signals. * You can slightly speed up things by #undefing the following option, - * if you are REALLY sure that your board is correct one. + * if you are REALLY sure that your board is correct one. */ #define RISCOM_BRAIN_DAMAGED_CTS -/* +/* * The following defines are mostly for testing purposes. But if you need * some nice reporting in your syslog, you can define them also. */ @@ -112,7 +112,7 @@ static unsigned short rc_ioport[] = { #define RC_NIOPORT ARRAY_SIZE(rc_ioport) -static inline int rc_paranoia_check(struct riscom_port const * port, +static int rc_paranoia_check(struct riscom_port const *port, char *name, const char *routine) { #ifdef RISCOM_PARANOIA_CHECK @@ -134,52 +134,53 @@ static inline int rc_paranoia_check(struct riscom_port const * port, } /* - * + * * Service functions for RISCom/8 driver. - * + * */ /* Get board number from pointer */ -static inline int board_No (struct riscom_board const * bp) +static inline int board_No(struct riscom_board const *bp) { return bp - rc_board; } /* Get port number from pointer */ -static inline int port_No (struct riscom_port const * port) +static inline int port_No(struct riscom_port const *port) { - return RC_PORT(port - rc_port); + return RC_PORT(port - rc_port); } /* Get pointer to board from pointer to port */ -static inline struct riscom_board * port_Board(struct riscom_port const * port) +static inline struct riscom_board *port_Board(struct riscom_port const *port) { return &rc_board[RC_BOARD(port - rc_port)]; } /* Input Byte from CL CD180 register */ -static inline unsigned char rc_in(struct riscom_board const * bp, unsigned short reg) +static inline unsigned char rc_in(struct riscom_board const *bp, + unsigned short reg) { return inb(bp->base + RC_TO_ISA(reg)); } /* Output Byte to CL CD180 register */ -static inline void rc_out(struct riscom_board const * bp, unsigned short reg, +static inline void rc_out(struct riscom_board const *bp, unsigned short reg, unsigned char val) { outb(val, bp->base + RC_TO_ISA(reg)); } /* Wait for Channel Command Register ready */ -static inline void rc_wait_CCR(struct riscom_board const * bp) +static void rc_wait_CCR(struct riscom_board const *bp) { unsigned long delay; /* FIXME: need something more descriptive then 100000 :) */ - for (delay = 100000; delay; delay--) + for (delay = 100000; delay; delay--) if (!rc_in(bp, CD180_CCR)) return; - + printk(KERN_INFO "rc%d: Timeout waiting for CCR.\n", board_No(bp)); } @@ -187,11 +188,11 @@ static inline void rc_wait_CCR(struct riscom_board const * bp) * RISCom/8 probe functions. */ -static inline int rc_request_io_range(struct riscom_board * const bp) +static int rc_request_io_range(struct riscom_board * const bp) { int i; - - for (i = 0; i < RC_NIOPORT; i++) + + for (i = 0; i < RC_NIOPORT; i++) if (!request_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1, "RISCom/8")) { goto out_release; @@ -200,42 +201,42 @@ static inline int rc_request_io_range(struct riscom_board * const bp) out_release: printk(KERN_INFO "rc%d: Skipping probe at 0x%03x. IO address in use.\n", board_No(bp), bp->base); - while(--i >= 0) + while (--i >= 0) release_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1); return 1; } -static inline void rc_release_io_range(struct riscom_board * const bp) +static void rc_release_io_range(struct riscom_board * const bp) { int i; - - for (i = 0; i < RC_NIOPORT; i++) + + for (i = 0; i < RC_NIOPORT; i++) release_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1); } - + /* Reset and setup CD180 chip */ -static void __init rc_init_CD180(struct riscom_board const * bp) +static void __init rc_init_CD180(struct riscom_board const *bp) { unsigned long flags; - + spin_lock_irqsave(&riscom_lock, flags); - rc_out(bp, RC_CTOUT, 0); /* Clear timeout */ - rc_wait_CCR(bp); /* Wait for CCR ready */ - rc_out(bp, CD180_CCR, CCR_HARDRESET); /* Reset CD180 chip */ + rc_out(bp, RC_CTOUT, 0); /* Clear timeout */ + rc_wait_CCR(bp); /* Wait for CCR ready */ + rc_out(bp, CD180_CCR, CCR_HARDRESET); /* Reset CD180 chip */ spin_unlock_irqrestore(&riscom_lock, flags); - msleep(50); /* Delay 0.05 sec */ + msleep(50); /* Delay 0.05 sec */ spin_lock_irqsave(&riscom_lock, flags); - rc_out(bp, CD180_GIVR, RC_ID); /* Set ID for this chip */ - rc_out(bp, CD180_GICR, 0); /* Clear all bits */ - rc_out(bp, CD180_PILR1, RC_ACK_MINT); /* Prio for modem intr */ - rc_out(bp, CD180_PILR2, RC_ACK_TINT); /* Prio for transmitter intr */ - rc_out(bp, CD180_PILR3, RC_ACK_RINT); /* Prio for receiver intr */ - + rc_out(bp, CD180_GIVR, RC_ID); /* Set ID for this chip */ + rc_out(bp, CD180_GICR, 0); /* Clear all bits */ + rc_out(bp, CD180_PILR1, RC_ACK_MINT); /* Prio for modem intr */ + rc_out(bp, CD180_PILR2, RC_ACK_TINT); /* Prio for tx intr */ + rc_out(bp, CD180_PILR3, RC_ACK_RINT); /* Prio for rx intr */ + /* Setting up prescaler. We need 4 ticks per 1 ms */ rc_out(bp, CD180_PPRH, (RC_OSCFREQ/(1000000/RISCOM_TPS)) >> 8); rc_out(bp, CD180_PPRL, (RC_OSCFREQ/(1000000/RISCOM_TPS)) & 0xff); - + spin_unlock_irqrestore(&riscom_lock, flags); } @@ -245,12 +246,12 @@ static int __init rc_probe(struct riscom_board *bp) unsigned char val1, val2; int irqs = 0; int retries; - + bp->irq = 0; if (rc_request_io_range(bp)) return 1; - + /* Are the I/O ports here ? */ rc_out(bp, CD180_PPRL, 0x5a); outb(0xff, 0x80); @@ -258,34 +259,34 @@ static int __init rc_probe(struct riscom_board *bp) rc_out(bp, CD180_PPRL, 0xa5); outb(0x00, 0x80); val2 = rc_in(bp, CD180_PPRL); - + if ((val1 != 0x5a) || (val2 != 0xa5)) { printk(KERN_ERR "rc%d: RISCom/8 Board at 0x%03x not found.\n", board_No(bp), bp->base); goto out_release; } - + /* It's time to find IRQ for this board */ - for (retries = 0; retries < 5 && irqs <= 0; retries++) { + for (retries = 0; retries < 5 && irqs <= 0; retries++) { irqs = probe_irq_on(); - rc_init_CD180(bp); /* Reset CD180 chip */ - rc_out(bp, CD180_CAR, 2); /* Select port 2 */ + rc_init_CD180(bp); /* Reset CD180 chip */ + rc_out(bp, CD180_CAR, 2); /* Select port 2 */ rc_wait_CCR(bp); - rc_out(bp, CD180_CCR, CCR_TXEN); /* Enable transmitter */ - rc_out(bp, CD180_IER, IER_TXRDY); /* Enable tx empty intr */ + rc_out(bp, CD180_CCR, CCR_TXEN); /* Enable transmitter */ + rc_out(bp, CD180_IER, IER_TXRDY);/* Enable tx empty intr */ msleep(50); irqs = probe_irq_off(irqs); - val1 = rc_in(bp, RC_BSR); /* Get Board Status reg */ - val2 = rc_in(bp, RC_ACK_TINT); /* ACK interrupt */ - rc_init_CD180(bp); /* Reset CD180 again */ - + val1 = rc_in(bp, RC_BSR); /* Get Board Status reg */ + val2 = rc_in(bp, RC_ACK_TINT); /* ACK interrupt */ + rc_init_CD180(bp); /* Reset CD180 again */ + if ((val1 & RC_BSR_TINT) || (val2 != (RC_ID | GIVR_IT_TX))) { printk(KERN_ERR "rc%d: RISCom/8 Board at 0x%03x not " "found.\n", board_No(bp), bp->base); goto out_release; } } - + if (irqs <= 0) { printk(KERN_ERR "rc%d: Can't find IRQ for RISCom/8 board " "at 0x%03x.\n", board_No(bp), bp->base); @@ -293,113 +294,112 @@ static int __init rc_probe(struct riscom_board *bp) } bp->irq = irqs; bp->flags |= RC_BOARD_PRESENT; - + printk(KERN_INFO "rc%d: RISCom/8 Rev. %c board detected at " "0x%03x, IRQ %d.\n", board_No(bp), (rc_in(bp, CD180_GFRCR) & 0x0f) + 'A', /* Board revision */ bp->base, bp->irq); - + return 0; out_release: rc_release_io_range(bp); return 1; } -/* - * +/* + * * Interrupt processing routines. - * + * */ -static inline struct riscom_port * rc_get_port(struct riscom_board const * bp, - unsigned char const * what) +static struct riscom_port *rc_get_port(struct riscom_board const *bp, + unsigned char const *what) { unsigned char channel; - struct riscom_port * port; - + struct riscom_port *port; + channel = rc_in(bp, CD180_GICR) >> GICR_CHAN_OFF; if (channel < CD180_NCH) { port = &rc_port[board_No(bp) * RC_NPORT + channel]; - if (port->flags & ASYNC_INITIALIZED) { + if (port->flags & ASYNC_INITIALIZED) return port; - } } - printk(KERN_ERR "rc%d: %s interrupt from invalid port %d\n", + printk(KERN_ERR "rc%d: %s interrupt from invalid port %d\n", board_No(bp), what, channel); return NULL; } -static inline void rc_receive_exc(struct riscom_board const * bp) +static void rc_receive_exc(struct riscom_board const *bp) { struct riscom_port *port; struct tty_struct *tty; unsigned char status; unsigned char ch, flag; - - if (!(port = rc_get_port(bp, "Receive"))) + + port = rc_get_port(bp, "Receive"); + if (port == NULL) return; tty = port->tty; - -#ifdef RC_REPORT_OVERRUN + +#ifdef RC_REPORT_OVERRUN status = rc_in(bp, CD180_RCSR); if (status & RCSR_OE) port->overrun++; status &= port->mark_mask; -#else +#else status = rc_in(bp, CD180_RCSR) & port->mark_mask; -#endif +#endif ch = rc_in(bp, CD180_RDR); - if (!status) { + if (!status) return; - } if (status & RCSR_TOUT) { printk(KERN_WARNING "rc%d: port %d: Receiver timeout. " - "Hardware problems ?\n", + "Hardware problems ?\n", board_No(bp), port_No(port)); return; - + } else if (status & RCSR_BREAK) { printk(KERN_INFO "rc%d: port %d: Handling break...\n", board_No(bp), port_No(port)); flag = TTY_BREAK; if (port->flags & ASYNC_SAK) do_SAK(tty); - - } else if (status & RCSR_PE) + + } else if (status & RCSR_PE) flag = TTY_PARITY; - - else if (status & RCSR_FE) + + else if (status & RCSR_FE) flag = TTY_FRAME; - - else if (status & RCSR_OE) + + else if (status & RCSR_OE) flag = TTY_OVERRUN; - else flag = TTY_NORMAL; - + tty_insert_flip_char(tty, ch, flag); tty_flip_buffer_push(tty); } -static inline void rc_receive(struct riscom_board const * bp) +static void rc_receive(struct riscom_board const *bp) { struct riscom_port *port; struct tty_struct *tty; unsigned char count; - - if (!(port = rc_get_port(bp, "Receive"))) + + port = rc_get_port(bp, "Receive"); + if (port == NULL) return; - + tty = port->tty; - + count = rc_in(bp, CD180_RDCR); - + #ifdef RC_REPORT_FIFO port->hits[count > 8 ? 9 : count]++; -#endif - +#endif + while (count--) { if (tty_buffer_request_room(tty, 1) == 0) { printk(KERN_WARNING "rc%d: port %d: Working around " @@ -412,26 +412,26 @@ static inline void rc_receive(struct riscom_board const * bp) tty_flip_buffer_push(tty); } -static inline void rc_transmit(struct riscom_board const * bp) +static void rc_transmit(struct riscom_board const *bp) { struct riscom_port *port; struct tty_struct *tty; unsigned char count; - - - if (!(port = rc_get_port(bp, "Transmit"))) + + port = rc_get_port(bp, "Transmit"); + if (port == NULL) return; - + tty = port->tty; - - if (port->IER & IER_TXEMPTY) { + + if (port->IER & IER_TXEMPTY) { /* FIFO drained */ rc_out(bp, CD180_CAR, port_No(port)); port->IER &= ~IER_TXEMPTY; rc_out(bp, CD180_IER, port->IER); return; } - + if ((port->xmit_cnt <= 0 && !port->break_length) || tty->stopped || tty->hw_stopped) { rc_out(bp, CD180_CAR, port_No(port)); @@ -439,7 +439,7 @@ static inline void rc_transmit(struct riscom_board const * bp) rc_out(bp, CD180_IER, port->IER); return; } - + if (port->break_length) { if (port->break_length > 0) { if (port->COR2 & COR2_ETC) { @@ -451,7 +451,8 @@ static inline void rc_transmit(struct riscom_board const * bp) rc_out(bp, CD180_TDR, CD180_C_ESC); rc_out(bp, CD180_TDR, CD180_C_DELAY); rc_out(bp, CD180_TDR, count); - if (!(port->break_length -= count)) + port->break_length -= count; + if (port->break_length == 0) port->break_length--; } else { rc_out(bp, CD180_TDR, CD180_C_ESC); @@ -463,7 +464,7 @@ static inline void rc_transmit(struct riscom_board const * bp) } return; } - + count = CD180_NFIFO; do { rc_out(bp, CD180_TDR, port->xmit_buf[port->xmit_tail++]); @@ -471,7 +472,7 @@ static inline void rc_transmit(struct riscom_board const * bp) if (--port->xmit_cnt <= 0) break; } while (--count > 0); - + if (port->xmit_cnt <= 0) { rc_out(bp, CD180_CAR, port_No(port)); port->IER &= ~IER_TXRDY; @@ -481,25 +482,26 @@ static inline void rc_transmit(struct riscom_board const * bp) tty_wakeup(tty); } -static inline void rc_check_modem(struct riscom_board const * bp) +static void rc_check_modem(struct riscom_board const *bp) { struct riscom_port *port; struct tty_struct *tty; unsigned char mcr; - - if (!(port = rc_get_port(bp, "Modem"))) + + port = rc_get_port(bp, "Modem"); + if (port == NULL) return; - + tty = port->tty; - + mcr = rc_in(bp, CD180_MCR); - if (mcr & MCR_CDCHG) { - if (rc_in(bp, CD180_MSVR) & MSVR_CD) + if (mcr & MCR_CDCHG) { + if (rc_in(bp, CD180_MSVR) & MSVR_CD) wake_up_interruptible(&port->open_wait); else tty_hangup(tty); } - + #ifdef RISCOM_BRAIN_DAMAGED_CTS if (mcr & MCR_CTSCHG) { if (rc_in(bp, CD180_MSVR) & MSVR_CTS) { @@ -526,13 +528,13 @@ static inline void rc_check_modem(struct riscom_board const * bp) rc_out(bp, CD180_IER, port->IER); } #endif /* RISCOM_BRAIN_DAMAGED_CTS */ - + /* Clear change bits */ rc_out(bp, CD180_MCR, 0); } /* The main interrupt processing routine */ -static irqreturn_t rc_interrupt(int dummy, void * dev_id) +static irqreturn_t rc_interrupt(int dummy, void *dev_id) { unsigned char status; unsigned char ack; @@ -547,13 +549,11 @@ static irqreturn_t rc_interrupt(int dummy, void * dev_id) (RC_BSR_TOUT | RC_BSR_TINT | RC_BSR_MINT | RC_BSR_RINT))) { handled = 1; - if (status & RC_BSR_TOUT) + if (status & RC_BSR_TOUT) printk(KERN_WARNING "rc%d: Got timeout. Hardware " "error?\n", board_No(bp)); - else if (status & RC_BSR_RINT) { ack = rc_in(bp, RC_ACK_RINT); - if (ack == (RC_ID | GIVR_IT_RCV)) rc_receive(bp); else if (ack == (RC_ID | GIVR_IT_REXC)) @@ -562,29 +562,23 @@ static irqreturn_t rc_interrupt(int dummy, void * dev_id) printk(KERN_WARNING "rc%d: Bad receive ack " "0x%02x.\n", board_No(bp), ack); - } else if (status & RC_BSR_TINT) { ack = rc_in(bp, RC_ACK_TINT); - if (ack == (RC_ID | GIVR_IT_TX)) rc_transmit(bp); else printk(KERN_WARNING "rc%d: Bad transmit ack " "0x%02x.\n", board_No(bp), ack); - } else /* if (status & RC_BSR_MINT) */ { ack = rc_in(bp, RC_ACK_MINT); - - if (ack == (RC_ID | GIVR_IT_MODEM)) + if (ack == (RC_ID | GIVR_IT_MODEM)) rc_check_modem(bp); else printk(KERN_WARNING "rc%d: Bad modem ack " "0x%02x.\n", board_No(bp), ack); - - } - + } rc_out(bp, CD180_EOIR, 0); /* Mark end of interrupt */ rc_out(bp, RC_CTOUT, 0); /* Clear timeout flag */ } @@ -596,24 +590,24 @@ static irqreturn_t rc_interrupt(int dummy, void * dev_id) */ /* Called with disabled interrupts */ -static int rc_setup_board(struct riscom_board * bp) +static int rc_setup_board(struct riscom_board *bp) { int error; - if (bp->flags & RC_BOARD_ACTIVE) + if (bp->flags & RC_BOARD_ACTIVE) return 0; - + error = request_irq(bp->irq, rc_interrupt, IRQF_DISABLED, "RISCom/8", bp); - if (error) + if (error) return error; - + rc_out(bp, RC_CTOUT, 0); /* Just in case */ bp->DTR = ~0; rc_out(bp, RC_DTR, bp->DTR); /* Drop DTR on all ports */ - + bp->flags |= RC_BOARD_ACTIVE; - + return 0; } @@ -622,40 +616,40 @@ static void rc_shutdown_board(struct riscom_board *bp) { if (!(bp->flags & RC_BOARD_ACTIVE)) return; - + bp->flags &= ~RC_BOARD_ACTIVE; - + free_irq(bp->irq, NULL); - + bp->DTR = ~0; rc_out(bp, RC_DTR, bp->DTR); /* Drop DTR on all ports */ - + } /* - * Setting up port characteristics. + * Setting up port characteristics. * Must be called with disabled interrupts */ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port) { - struct tty_struct *tty; + struct tty_struct *tty = port->tty; unsigned long baud; long tmp; unsigned char cor1 = 0, cor3 = 0; unsigned char mcor1 = 0, mcor2 = 0; - - if (!(tty = port->tty) || !tty->termios) + + if (tty == NULL || tty->termios == NULL) return; port->IER = 0; port->COR2 = 0; port->MSVR = MSVR_RTS; - + baud = tty_get_baud_rate(tty); - + /* Select port on the board */ rc_out(bp, CD180_CAR, port_No(port)); - + if (!baud) { /* Drop DTR & exit */ bp->DTR |= (1u << port_No(port)); @@ -666,69 +660,68 @@ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port) bp->DTR &= ~(1u << port_No(port)); rc_out(bp, RC_DTR, bp->DTR); } - + /* - * Now we must calculate some speed depended things + * Now we must calculate some speed depended things */ - + /* Set baud rate for port */ tmp = (((RC_OSCFREQ + baud/2) / baud + CD180_TPC/2) / CD180_TPC); - rc_out(bp, CD180_RBPRH, (tmp >> 8) & 0xff); - rc_out(bp, CD180_TBPRH, (tmp >> 8) & 0xff); - rc_out(bp, CD180_RBPRL, tmp & 0xff); + rc_out(bp, CD180_RBPRH, (tmp >> 8) & 0xff); + rc_out(bp, CD180_TBPRH, (tmp >> 8) & 0xff); + rc_out(bp, CD180_RBPRL, tmp & 0xff); rc_out(bp, CD180_TBPRL, tmp & 0xff); - + baud = (baud + 5) / 10; /* Estimated CPS */ - + /* Two timer ticks seems enough to wakeup something like SLIP driver */ - tmp = ((baud + HZ/2) / HZ) * 2 - CD180_NFIFO; + tmp = ((baud + HZ/2) / HZ) * 2 - CD180_NFIFO; port->wakeup_chars = (tmp < 0) ? 0 : ((tmp >= SERIAL_XMIT_SIZE) ? SERIAL_XMIT_SIZE - 1 : tmp); - + /* Receiver timeout will be transmission time for 1.5 chars */ tmp = (RISCOM_TPS + RISCOM_TPS/2 + baud/2) / baud; tmp = (tmp > 0xff) ? 0xff : tmp; rc_out(bp, CD180_RTPR, tmp); - - switch (C_CSIZE(tty)) { - case CS5: + + switch (C_CSIZE(tty)) { + case CS5: cor1 |= COR1_5BITS; break; - case CS6: + case CS6: cor1 |= COR1_6BITS; break; - case CS7: + case CS7: cor1 |= COR1_7BITS; break; - case CS8: + case CS8: cor1 |= COR1_8BITS; break; } - - if (C_CSTOPB(tty)) + if (C_CSTOPB(tty)) cor1 |= COR1_2SB; - + cor1 |= COR1_IGNORE; - if (C_PARENB(tty)) { + if (C_PARENB(tty)) { cor1 |= COR1_NORMPAR; - if (C_PARODD(tty)) + if (C_PARODD(tty)) cor1 |= COR1_ODDP; - if (I_INPCK(tty)) + if (I_INPCK(tty)) cor1 &= ~COR1_IGNORE; } /* Set marking of some errors */ port->mark_mask = RCSR_OE | RCSR_TOUT; - if (I_INPCK(tty)) + if (I_INPCK(tty)) port->mark_mask |= RCSR_FE | RCSR_PE; - if (I_BRKINT(tty) || I_PARMRK(tty)) + if (I_BRKINT(tty) || I_PARMRK(tty)) port->mark_mask |= RCSR_BREAK; - if (I_IGNPAR(tty)) + if (I_IGNPAR(tty)) port->mark_mask &= ~(RCSR_FE | RCSR_PE); - if (I_IGNBRK(tty)) { + if (I_IGNBRK(tty)) { port->mark_mask &= ~RCSR_BREAK; - if (I_IGNPAR(tty)) + if (I_IGNPAR(tty)) /* Real raw mode. Ignore all */ port->mark_mask &= ~RCSR_OE; } @@ -738,7 +731,8 @@ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port) port->IER |= IER_DSR | IER_CTS; mcor1 |= MCOR1_DSRZD | MCOR1_CTSZD; mcor2 |= MCOR2_DSROD | MCOR2_CTSOD; - tty->hw_stopped = !(rc_in(bp, CD180_MSVR) & (MSVR_CTS|MSVR_DSR)); + tty->hw_stopped = !(rc_in(bp, CD180_MSVR) & + (MSVR_CTS|MSVR_DSR)); #else port->COR2 |= COR2_CTSAE; #endif @@ -761,13 +755,13 @@ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port) mcor1 |= MCOR1_CDZD; mcor2 |= MCOR2_CDOD; } - - if (C_CREAD(tty)) + + if (C_CREAD(tty)) /* Enable receiver */ port->IER |= IER_RXD; - + /* Set input FIFO size (1-8 bytes) */ - cor3 |= RISCOM_RXFIFO; + cor3 |= RISCOM_RXFIFO; /* Setting up CD180 channel registers */ rc_out(bp, CD180_COR1, cor1); rc_out(bp, CD180_COR2, port->COR2); @@ -791,36 +785,30 @@ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port) static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port) { unsigned long flags; - + if (port->flags & ASYNC_INITIALIZED) return 0; - + if (!port->xmit_buf) { /* We may sleep in get_zeroed_page() */ - unsigned long tmp; - - if (!(tmp = get_zeroed_page(GFP_KERNEL))) + unsigned long tmp = get_zeroed_page(GFP_KERNEL); + if (tmp == 0) return -ENOMEM; - - if (port->xmit_buf) { + if (port->xmit_buf) free_page(tmp); - return -ERESTARTSYS; - } - port->xmit_buf = (unsigned char *) tmp; + else + port->xmit_buf = (unsigned char *) tmp; } - spin_lock_irqsave(&riscom_lock, flags); - if (port->tty) + if (port->tty) clear_bit(TTY_IO_ERROR, &port->tty->flags); - - if (port->count == 1) + if (port->count == 1) bp->count++; - port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; rc_change_speed(bp, port); port->flags |= ASYNC_INITIALIZED; - + spin_unlock_irqrestore(&riscom_lock, flags); return 0; } @@ -829,38 +817,39 @@ static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port) static void rc_shutdown_port(struct riscom_board *bp, struct riscom_port *port) { struct tty_struct *tty; - - if (!(port->flags & ASYNC_INITIALIZED)) + + if (!(port->flags & ASYNC_INITIALIZED)) return; - + #ifdef RC_REPORT_OVERRUN printk(KERN_INFO "rc%d: port %d: Total %ld overruns were detected.\n", board_No(bp), port_No(port), port->overrun); -#endif +#endif #ifdef RC_REPORT_FIFO { int i; - + printk(KERN_INFO "rc%d: port %d: FIFO hits [ ", board_No(bp), port_No(port)); - for (i = 0; i < 10; i++) { + for (i = 0; i < 10; i++) printk("%ld ", port->hits[i]); - } printk("].\n"); } -#endif +#endif if (port->xmit_buf) { free_page((unsigned long) port->xmit_buf); port->xmit_buf = NULL; } - if (!(tty = port->tty) || C_HUPCL(tty)) { + tty = port->tty; + + if (tty == NULL || C_HUPCL(tty)) { /* Drop DTR */ bp->DTR |= (1u << port_No(port)); rc_out(bp, RC_DTR, bp->DTR); } - - /* Select port */ + + /* Select port */ rc_out(bp, CD180_CAR, port_No(port)); /* Reset port */ rc_wait_CCR(bp); @@ -868,28 +857,26 @@ static void rc_shutdown_port(struct riscom_board *bp, struct riscom_port *port) /* Disable all interrupts from this port */ port->IER = 0; rc_out(bp, CD180_IER, port->IER); - - if (tty) + + if (tty) set_bit(TTY_IO_ERROR, &tty->flags); port->flags &= ~ASYNC_INITIALIZED; - + if (--bp->count < 0) { printk(KERN_INFO "rc%d: rc_shutdown_port: " "bad board count: %d\n", board_No(bp), bp->count); bp->count = 0; } - /* * If this is the last opened port on the board * shutdown whole board */ - if (!bp->count) + if (!bp->count) rc_shutdown_board(bp); } - -static int block_til_ready(struct tty_struct *tty, struct file * filp, +static int block_til_ready(struct tty_struct *tty, struct file *filp, struct riscom_port *port) { DECLARE_WAITQUEUE(wait, current); @@ -921,7 +908,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, return 0; } - if (C_CLOCAL(tty)) + if (C_CLOCAL(tty)) do_clocal = 1; /* @@ -959,7 +946,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, if (port->flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else - retval = -ERESTARTSYS; + retval = -ERESTARTSYS; break; } if (!(port->flags & ASYNC_CLOSING) && @@ -978,50 +965,63 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, port->blocked_open--; if (retval) return retval; - + port->flags |= ASYNC_NORMAL_ACTIVE; return 0; -} +} -static int rc_open(struct tty_struct * tty, struct file * filp) +static int rc_open(struct tty_struct *tty, struct file *filp) { int board; int error; - struct riscom_port * port; - struct riscom_board * bp; - + struct riscom_port *port; + struct riscom_board *bp; + board = RC_BOARD(tty->index); if (board >= RC_NBOARD || !(rc_board[board].flags & RC_BOARD_PRESENT)) return -ENODEV; - + bp = &rc_board[board]; port = rc_port + board * RC_NPORT + RC_PORT(tty->index); if (rc_paranoia_check(port, tty->name, "rc_open")) return -ENODEV; - - if ((error = rc_setup_board(bp))) + + error = rc_setup_board(bp); + if (error) return error; - + port->count++; tty->driver_data = port; port->tty = tty; - - if ((error = rc_setup_port(bp, port))) - return error; - - if ((error = block_til_ready(tty, filp, port))) - return error; - - return 0; + + error = rc_setup_port(bp, port); + if (error == 0) + error = block_til_ready(tty, filp, port); + return error; } -static void rc_close(struct tty_struct * tty, struct file * filp) +static void rc_flush_buffer(struct tty_struct *tty) +{ + struct riscom_port *port = (struct riscom_port *)tty->driver_data; + unsigned long flags; + + if (rc_paranoia_check(port, tty->name, "rc_flush_buffer")) + return; + + spin_lock_irqsave(&riscom_lock, flags); + port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; + spin_unlock_irqrestore(&riscom_lock, flags); + + tty_wakeup(tty); +} + +static void rc_close(struct tty_struct *tty, struct file *filp) { struct riscom_port *port = (struct riscom_port *) tty->driver_data; struct riscom_board *bp; unsigned long flags; unsigned long timeout; - + if (!port || rc_paranoia_check(port, tty->name, "close")) return; @@ -1029,7 +1029,7 @@ static void rc_close(struct tty_struct * tty, struct file * filp) if (tty_hung_up_p(filp)) goto out; - + bp = port_Board(port); if ((tty->count == 1) && (port->count != 1)) { printk(KERN_INFO "rc%d: rc_close: bad port count;" @@ -1047,7 +1047,7 @@ static void rc_close(struct tty_struct * tty, struct file * filp) goto out; port->flags |= ASYNC_CLOSING; /* - * Now we wait for the transmit buffer to clear; and we notify + * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. */ tty->closing = 1; @@ -1070,24 +1070,22 @@ static void rc_close(struct tty_struct * tty, struct file * filp) * has completely drained; this is especially * important if there is a transmit FIFO! */ - timeout = jiffies+HZ; - while(port->IER & IER_TXEMPTY) { + timeout = jiffies + HZ; + while (port->IER & IER_TXEMPTY) { msleep_interruptible(jiffies_to_msecs(port->timeout)); if (time_after(jiffies, timeout)) break; } } rc_shutdown_port(bp, port); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + rc_flush_buffer(tty); tty_ldisc_flush(tty); tty->closing = 0; port->tty = NULL; if (port->blocked_open) { - if (port->close_delay) { + if (port->close_delay) msleep_interruptible(jiffies_to_msecs(port->close_delay)); - } wake_up_interruptible(&port->open_wait); } port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); @@ -1097,17 +1095,17 @@ out: spin_unlock_irqrestore(&riscom_lock, flags); } -static int rc_write(struct tty_struct * tty, +static int rc_write(struct tty_struct *tty, const unsigned char *buf, int count) { struct riscom_port *port = (struct riscom_port *)tty->driver_data; struct riscom_board *bp; int c, total = 0; unsigned long flags; - + if (rc_paranoia_check(port, tty->name, "rc_write")) return 0; - + bp = port_Board(port); if (!tty || !port->xmit_buf) @@ -1144,38 +1142,41 @@ static int rc_write(struct tty_struct * tty, return total; } -static void rc_put_char(struct tty_struct * tty, unsigned char ch) +static int rc_put_char(struct tty_struct *tty, unsigned char ch) { struct riscom_port *port = (struct riscom_port *)tty->driver_data; unsigned long flags; + int ret = 0; if (rc_paranoia_check(port, tty->name, "rc_put_char")) - return; + return 0; if (!tty || !port->xmit_buf) - return; + return 0; spin_lock_irqsave(&riscom_lock, flags); - + if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) goto out; port->xmit_buf[port->xmit_head++] = ch; port->xmit_head &= SERIAL_XMIT_SIZE - 1; port->xmit_cnt++; + ret = 1; out: spin_unlock_irqrestore(&riscom_lock, flags); + return ret; } -static void rc_flush_chars(struct tty_struct * tty) +static void rc_flush_chars(struct tty_struct *tty) { struct riscom_port *port = (struct riscom_port *)tty->driver_data; unsigned long flags; - + if (rc_paranoia_check(port, tty->name, "rc_flush_chars")) return; - + if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || !port->xmit_buf) return; @@ -1189,11 +1190,11 @@ static void rc_flush_chars(struct tty_struct * tty) spin_unlock_irqrestore(&riscom_lock, flags); } -static int rc_write_room(struct tty_struct * tty) +static int rc_write_room(struct tty_struct *tty) { struct riscom_port *port = (struct riscom_port *)tty->driver_data; int ret; - + if (rc_paranoia_check(port, tty->name, "rc_write_room")) return 0; @@ -1206,39 +1207,22 @@ static int rc_write_room(struct tty_struct * tty) static int rc_chars_in_buffer(struct tty_struct *tty) { struct riscom_port *port = (struct riscom_port *)tty->driver_data; - + if (rc_paranoia_check(port, tty->name, "rc_chars_in_buffer")) return 0; - - return port->xmit_cnt; -} - -static void rc_flush_buffer(struct tty_struct *tty) -{ - struct riscom_port *port = (struct riscom_port *)tty->driver_data; - unsigned long flags; - - if (rc_paranoia_check(port, tty->name, "rc_flush_buffer")) - return; - - spin_lock_irqsave(&riscom_lock, flags); - - port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; - spin_unlock_irqrestore(&riscom_lock, flags); - - tty_wakeup(tty); + return port->xmit_cnt; } static int rc_tiocmget(struct tty_struct *tty, struct file *file) { struct riscom_port *port = (struct riscom_port *)tty->driver_data; - struct riscom_board * bp; + struct riscom_board *bp; unsigned char status; unsigned int result; unsigned long flags; - if (rc_paranoia_check(port, tty->name, __FUNCTION__)) + if (rc_paranoia_check(port, tty->name, __func__)) return -ENODEV; bp = port_Board(port); @@ -1266,7 +1250,7 @@ static int rc_tiocmset(struct tty_struct *tty, struct file *file, unsigned long flags; struct riscom_board *bp; - if (rc_paranoia_check(port, tty->name, __FUNCTION__)) + if (rc_paranoia_check(port, tty->name, __func__)) return -ENODEV; bp = port_Board(port); @@ -1292,11 +1276,11 @@ static int rc_tiocmset(struct tty_struct *tty, struct file *file, return 0; } -static inline void rc_send_break(struct riscom_port * port, unsigned long length) +static void rc_send_break(struct riscom_port *port, unsigned long length) { struct riscom_board *bp = port_Board(port); unsigned long flags; - + spin_lock_irqsave(&riscom_lock, flags); port->break_length = RISCOM_TPS / HZ * length; @@ -1312,17 +1296,17 @@ static inline void rc_send_break(struct riscom_port * port, unsigned long length spin_unlock_irqrestore(&riscom_lock, flags); } -static inline int rc_set_serial_info(struct riscom_port * port, - struct serial_struct __user * newinfo) +static int rc_set_serial_info(struct riscom_port *port, + struct serial_struct __user *newinfo) { struct serial_struct tmp; struct riscom_board *bp = port_Board(port); int change_speed; - + if (copy_from_user(&tmp, newinfo, sizeof(tmp))) return -EFAULT; - -#if 0 + +#if 0 if ((tmp.irq != bp->irq) || (tmp.port != bp->base) || (tmp.type != PORT_CIRRUS) || @@ -1331,16 +1315,16 @@ static inline int rc_set_serial_info(struct riscom_port * port, (tmp.xmit_fifo_size != CD180_NFIFO) || (tmp.flags & ~RISCOM_LEGAL_FLAGS)) return -EINVAL; -#endif - +#endif + change_speed = ((port->flags & ASYNC_SPD_MASK) != (tmp.flags & ASYNC_SPD_MASK)); - + if (!capable(CAP_SYS_ADMIN)) { if ((tmp.close_delay != port->close_delay) || (tmp.closing_wait != port->closing_wait) || ((tmp.flags & ~ASYNC_USR_MASK) != - (port->flags & ~ASYNC_USR_MASK))) + (port->flags & ~ASYNC_USR_MASK))) return -EPERM; port->flags = ((port->flags & ~ASYNC_USR_MASK) | (tmp.flags & ASYNC_USR_MASK)); @@ -1360,12 +1344,12 @@ static inline int rc_set_serial_info(struct riscom_port * port, return 0; } -static inline int rc_get_serial_info(struct riscom_port * port, +static int rc_get_serial_info(struct riscom_port *port, struct serial_struct __user *retinfo) { struct serial_struct tmp; struct riscom_board *bp = port_Board(port); - + memset(&tmp, 0, sizeof(tmp)); tmp.type = PORT_CIRRUS; tmp.line = port - rc_port; @@ -1379,19 +1363,18 @@ static inline int rc_get_serial_info(struct riscom_port * port, return copy_to_user(retinfo, &tmp, sizeof(tmp)) ? -EFAULT : 0; } -static int rc_ioctl(struct tty_struct * tty, struct file * filp, +static int rc_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, unsigned long arg) - { struct riscom_port *port = (struct riscom_port *)tty->driver_data; void __user *argp = (void __user *)arg; - int retval; - + int retval = 0; + if (rc_paranoia_check(port, tty->name, "rc_ioctl")) return -ENODEV; - + switch (cmd) { - case TCSBRK: /* SVID version: non-zero arg --> no break */ + case TCSBRK: /* SVID version: non-zero arg --> no break */ retval = tty_check_change(tty); if (retval) return retval; @@ -1399,45 +1382,40 @@ static int rc_ioctl(struct tty_struct * tty, struct file * filp, if (!arg) rc_send_break(port, HZ/4); /* 1/4 second */ break; - case TCSBRKP: /* support for POSIX tcsendbreak() */ + case TCSBRKP: /* support for POSIX tcsendbreak() */ retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0); rc_send_break(port, arg ? arg*(HZ/10) : HZ/4); break; - case TIOCGSOFTCAR: - return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned __user *)argp); - case TIOCSSOFTCAR: - if (get_user(arg,(unsigned __user *) argp)) - return -EFAULT; - tty->termios->c_cflag = - ((tty->termios->c_cflag & ~CLOCAL) | - (arg ? CLOCAL : 0)); + case TIOCGSERIAL: + lock_kernel(); + retval = rc_get_serial_info(port, argp); + unlock_kernel(); break; - case TIOCGSERIAL: - return rc_get_serial_info(port, argp); - case TIOCSSERIAL: - return rc_set_serial_info(port, argp); - default: - return -ENOIOCTLCMD; + case TIOCSSERIAL: + lock_kernel(); + retval = rc_set_serial_info(port, argp); + unlock_kernel(); + break; + default: + retval = -ENOIOCTLCMD; } - return 0; + return retval; } -static void rc_throttle(struct tty_struct * tty) +static void rc_throttle(struct tty_struct *tty) { struct riscom_port *port = (struct riscom_port *)tty->driver_data; struct riscom_board *bp; unsigned long flags; - + if (rc_paranoia_check(port, tty->name, "rc_throttle")) return; - bp = port_Board(port); spin_lock_irqsave(&riscom_lock, flags); - port->MSVR &= ~MSVR_RTS; rc_out(bp, CD180_CAR, port_No(port)); if (I_IXOFF(tty)) { @@ -1446,23 +1424,20 @@ static void rc_throttle(struct tty_struct * tty) rc_wait_CCR(bp); } rc_out(bp, CD180_MSVR, port->MSVR); - spin_unlock_irqrestore(&riscom_lock, flags); } -static void rc_unthrottle(struct tty_struct * tty) +static void rc_unthrottle(struct tty_struct *tty) { struct riscom_port *port = (struct riscom_port *)tty->driver_data; struct riscom_board *bp; unsigned long flags; - + if (rc_paranoia_check(port, tty->name, "rc_unthrottle")) return; - bp = port_Board(port); - - spin_lock_irqsave(&riscom_lock, flags); + spin_lock_irqsave(&riscom_lock, flags); port->MSVR |= MSVR_RTS; rc_out(bp, CD180_CAR, port_No(port)); if (I_IXOFF(tty)) { @@ -1471,62 +1446,58 @@ static void rc_unthrottle(struct tty_struct * tty) rc_wait_CCR(bp); } rc_out(bp, CD180_MSVR, port->MSVR); - spin_unlock_irqrestore(&riscom_lock, flags); } -static void rc_stop(struct tty_struct * tty) +static void rc_stop(struct tty_struct *tty) { struct riscom_port *port = (struct riscom_port *)tty->driver_data; struct riscom_board *bp; unsigned long flags; - + if (rc_paranoia_check(port, tty->name, "rc_stop")) return; - + bp = port_Board(port); - - spin_lock_irqsave(&riscom_lock, flags); + spin_lock_irqsave(&riscom_lock, flags); port->IER &= ~IER_TXRDY; rc_out(bp, CD180_CAR, port_No(port)); rc_out(bp, CD180_IER, port->IER); - spin_unlock_irqrestore(&riscom_lock, flags); } -static void rc_start(struct tty_struct * tty) +static void rc_start(struct tty_struct *tty) { struct riscom_port *port = (struct riscom_port *)tty->driver_data; struct riscom_board *bp; unsigned long flags; - + if (rc_paranoia_check(port, tty->name, "rc_start")) return; - + bp = port_Board(port); - + spin_lock_irqsave(&riscom_lock, flags); - if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) { + if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) { port->IER |= IER_TXRDY; rc_out(bp, CD180_CAR, port_No(port)); rc_out(bp, CD180_IER, port->IER); } - spin_unlock_irqrestore(&riscom_lock, flags); } -static void rc_hangup(struct tty_struct * tty) +static void rc_hangup(struct tty_struct *tty) { struct riscom_port *port = (struct riscom_port *)tty->driver_data; struct riscom_board *bp; - + if (rc_paranoia_check(port, tty->name, "rc_hangup")) return; - + bp = port_Board(port); - + rc_shutdown_port(bp, port); port->count = 0; port->flags &= ~ASYNC_NORMAL_ACTIVE; @@ -1534,17 +1505,14 @@ static void rc_hangup(struct tty_struct * tty) wake_up_interruptible(&port->open_wait); } -static void rc_set_termios(struct tty_struct * tty, struct ktermios * old_termios) +static void rc_set_termios(struct tty_struct *tty, + struct ktermios *old_termios) { struct riscom_port *port = (struct riscom_port *)tty->driver_data; unsigned long flags; - + if (rc_paranoia_check(port, tty->name, "rc_set_termios")) return; - - if (tty->termios->c_cflag == old_termios->c_cflag && - tty->termios->c_iflag == old_termios->c_iflag) - return; spin_lock_irqsave(&riscom_lock, flags); rc_change_speed(port_Board(port), port); @@ -1583,9 +1551,9 @@ static int __init rc_init_drivers(void) int i; riscom_driver = alloc_tty_driver(RC_NBOARD * RC_NPORT); - if (!riscom_driver) + if (!riscom_driver) return -ENOMEM; - + riscom_driver->owner = THIS_MODULE; riscom_driver->name = "ttyL"; riscom_driver->major = RISCOM8_NORMAL_MAJOR; @@ -1598,23 +1566,21 @@ static int __init rc_init_drivers(void) riscom_driver->init_termios.c_ospeed = 9600; riscom_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(riscom_driver, &riscom_ops); - if ((error = tty_register_driver(riscom_driver))) { + error = tty_register_driver(riscom_driver); + if (error != 0) { put_tty_driver(riscom_driver); printk(KERN_ERR "rc: Couldn't register RISCom/8 driver, " - "error = %d\n", - error); + "error = %d\n", error); return 1; } - memset(rc_port, 0, sizeof(rc_port)); for (i = 0; i < RC_NPORT * RC_NBOARD; i++) { rc_port[i].magic = RISCOM8_MAGIC; - rc_port[i].close_delay = 50 * HZ/100; - rc_port[i].closing_wait = 3000 * HZ/100; + rc_port[i].close_delay = 50 * HZ / 100; + rc_port[i].closing_wait = 3000 * HZ / 100; init_waitqueue_head(&rc_port[i].open_wait); init_waitqueue_head(&rc_port[i].close_wait); } - return 0; } @@ -1627,13 +1593,13 @@ static void rc_release_drivers(void) #ifndef MODULE /* * Called at boot time. - * + * * You can specify IO base for up to RC_NBOARD cards, * using line "riscom8=0xiobase1,0xiobase2,.." at LILO prompt. * Note that there will be no probing at default * addresses in this case. * - */ + */ static int __init riscom8_setup(char *str) { int ints[RC_NBOARD]; @@ -1644,7 +1610,7 @@ static int __init riscom8_setup(char *str) for (i = 0; i < RC_NBOARD; i++) { if (i < ints[0]) rc_board[i].base = ints[i+1]; - else + else rc_board[i].base = 0; } return 1; @@ -1659,8 +1625,8 @@ static char banner[] __initdata = static char no_boards_msg[] __initdata = KERN_INFO "rc: No RISCom/8 boards detected.\n"; -/* - * This routine must be called by kernel at boot time +/* + * This routine must be called by kernel at boot time */ static int __init riscom8_init(void) { @@ -1669,13 +1635,12 @@ static int __init riscom8_init(void) printk(banner); - if (rc_init_drivers()) + if (rc_init_drivers()) return -EIO; - for (i = 0; i < RC_NBOARD; i++) - if (rc_board[i].base && !rc_probe(&rc_board[i])) + for (i = 0; i < RC_NBOARD; i++) + if (rc_board[i].base && !rc_probe(&rc_board[i])) found++; - if (!found) { rc_release_drivers(); printk(no_boards_msg); @@ -1702,13 +1667,13 @@ MODULE_LICENSE("GPL"); * by specifying "iobase=0xXXX iobase1=0xXXX ..." as insmod parameter. * */ -static int __init riscom8_init_module (void) +static int __init riscom8_init_module(void) { #ifdef MODULE int i; if (iobase || iobase1 || iobase2 || iobase3) { - for(i = 0; i < RC_NBOARD; i++) + for (i = 0; i < RC_NBOARD; i++) rc_board[i].base = 0; } @@ -1724,18 +1689,17 @@ static int __init riscom8_init_module (void) return riscom8_init(); } - -static void __exit riscom8_exit_module (void) + +static void __exit riscom8_exit_module(void) { int i; - + rc_release_drivers(); - for (i = 0; i < RC_NBOARD; i++) - if (rc_board[i].flags & RC_BOARD_PRESENT) + for (i = 0; i < RC_NBOARD; i++) + if (rc_board[i].flags & RC_BOARD_PRESENT) rc_release_io_range(&rc_board[i]); - + } module_init(riscom8_init_module); module_exit(riscom8_exit_module); - diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index f585bc8579e9..743dc80a9325 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -449,7 +449,8 @@ static void rp_do_transmit(struct r_port *info) while (1) { if (tty->stopped || tty->hw_stopped) break; - c = min(info->xmit_fifo_room, min(info->xmit_cnt, XMIT_BUF_SIZE - info->xmit_tail)); + c = min(info->xmit_fifo_room, info->xmit_cnt); + c = min(c, XMIT_BUF_SIZE - info->xmit_tail); if (c <= 0 || info->xmit_fifo_room <= 0) break; sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) (info->xmit_buf + info->xmit_tail), c / 2); @@ -1433,29 +1434,38 @@ static int rp_ioctl(struct tty_struct *tty, struct file *file, { struct r_port *info = (struct r_port *) tty->driver_data; void __user *argp = (void __user *)arg; + int ret = 0; if (cmd != RCKP_GET_PORTS && rocket_paranoia_check(info, "rp_ioctl")) return -ENXIO; + lock_kernel(); + switch (cmd) { case RCKP_GET_STRUCT: if (copy_to_user(argp, info, sizeof (struct r_port))) - return -EFAULT; - return 0; + ret = -EFAULT; + break; case RCKP_GET_CONFIG: - return get_config(info, argp); + ret = get_config(info, argp); + break; case RCKP_SET_CONFIG: - return set_config(info, argp); + ret = set_config(info, argp); + break; case RCKP_GET_PORTS: - return get_ports(info, argp); + ret = get_ports(info, argp); + break; case RCKP_RESET_RM2: - return reset_rm2(info, argp); + ret = reset_rm2(info, argp); + break; case RCKP_GET_VERSION: - return get_version(info, argp); + ret = get_version(info, argp); + break; default: - return -ENOIOCTLCMD; + ret = -ENOIOCTLCMD; } - return 0; + unlock_kernel(); + return ret; } static void rp_send_xchar(struct tty_struct *tty, char ch) @@ -1575,6 +1585,7 @@ static void rp_wait_until_sent(struct tty_struct *tty, int timeout) jiffies); printk(KERN_INFO "cps=%d...\n", info->cps); #endif + lock_kernel(); while (1) { txcnt = sGetTxCnt(cp); if (!txcnt) { @@ -1602,6 +1613,7 @@ static void rp_wait_until_sent(struct tty_struct *tty, int timeout) break; } __set_current_state(TASK_RUNNING); + unlock_kernel(); #ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT printk(KERN_INFO "txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies); #endif @@ -1651,14 +1663,14 @@ static void rp_hangup(struct tty_struct *tty) * writing routines will write directly to transmit FIFO. * Write buffer and counters protected by spinlocks */ -static void rp_put_char(struct tty_struct *tty, unsigned char ch) +static int rp_put_char(struct tty_struct *tty, unsigned char ch) { struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; unsigned long flags; if (rocket_paranoia_check(info, "rp_put_char")) - return; + return 0; /* * Grab the port write mutex, locking out other processes that try to @@ -1687,6 +1699,7 @@ static void rp_put_char(struct tty_struct *tty, unsigned char ch) } spin_unlock_irqrestore(&info->slock, flags); mutex_unlock(&info->write_mtx); + return 1; } /* @@ -1749,10 +1762,10 @@ static int rp_write(struct tty_struct *tty, /* Write remaining data into the port's xmit_buf */ while (1) { - if (!info->tty) /* Seemingly obligatory check... */ + if (!info->tty) /* Seemingly obligatory check... */ goto end; - - c = min(count, min(XMIT_BUF_SIZE - info->xmit_cnt - 1, XMIT_BUF_SIZE - info->xmit_head)); + c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1); + c = min(c, XMIT_BUF_SIZE - info->xmit_head); if (c <= 0) break; diff --git a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h index b01d38125a8f..143cc432fdb2 100644 --- a/drivers/char/rocket_int.h +++ b/drivers/char/rocket_int.h @@ -55,7 +55,7 @@ static inline void sOutW(unsigned short port, unsigned short value) static inline void out32(unsigned short port, Byte_t *p) { - u32 value = le32_to_cpu(get_unaligned((__le32 *)p)); + u32 value = get_unaligned_le32(p); #ifdef ROCKET_DEBUG_IO printk(KERN_DEBUG "out32(%x, %lx)...\n", port, value); #endif diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index e2ec2ee4cf79..5f80a9dff573 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -1069,10 +1069,8 @@ no_irq: } #ifdef CONFIG_PROC_FS - ent = create_proc_entry("driver/rtc", 0, NULL); - if (ent) - ent->proc_fops = &rtc_proc_fops; - else + ent = proc_create("driver/rtc", 0, NULL, &rtc_proc_fops); + if (!ent) printk(KERN_WARNING "rtc: Failed to register with procfs.\n"); #endif diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index df8cd0ca97eb..fd2db07a50fc 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -1060,7 +1060,7 @@ static void config_setup(struct cyclades_port *info) } /* config_setup */ -static void cy_put_char(struct tty_struct *tty, unsigned char ch) +static int cy_put_char(struct tty_struct *tty, unsigned char ch) { struct cyclades_port *info = (struct cyclades_port *)tty->driver_data; unsigned long flags; @@ -1070,7 +1070,7 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch) #endif if (serial_paranoia_check(info, tty->name, "cy_put_char")) - return; + return 0; if (!info->xmit_buf) return; @@ -1078,13 +1078,14 @@ static void cy_put_char(struct tty_struct *tty, unsigned char ch) local_irq_save(flags); if (info->xmit_cnt >= PAGE_SIZE - 1) { local_irq_restore(flags); - return; + return 0; } info->xmit_buf[info->xmit_head++] = ch; info->xmit_head &= PAGE_SIZE - 1; info->xmit_cnt++; local_irq_restore(flags); + return 1; } /* cy_put_char */ static void cy_flush_chars(struct tty_struct *tty) @@ -1539,6 +1540,8 @@ cy_ioctl(struct tty_struct *tty, struct file *file, printk("cy_ioctl %s, cmd = %x arg = %lx\n", tty->name, cmd, arg); /* */ #endif + lock_kernel(); + switch (cmd) { case CYGETMON: ret_val = get_mon_info(info, argp); @@ -1584,18 +1587,6 @@ cy_ioctl(struct tty_struct *tty, struct file *file, break; /* The following commands are incompletely implemented!!! */ - case TIOCGSOFTCAR: - ret_val = - put_user(C_CLOCAL(tty) ? 1 : 0, - (unsigned long __user *)argp); - break; - case TIOCSSOFTCAR: - ret_val = get_user(val, (unsigned long __user *)argp); - if (ret_val) - break; - tty->termios->c_cflag = - ((tty->termios->c_cflag & ~CLOCAL) | (val ? CLOCAL : 0)); - break; case TIOCGSERIAL: ret_val = get_serial_info(info, argp); break; @@ -1605,6 +1596,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file, default: ret_val = -ENOIOCTLCMD; } + unlock_kernel(); #ifdef SERIAL_DEBUG_OTHER printk("cy_ioctl done\n"); @@ -1683,8 +1675,7 @@ static void cy_close(struct tty_struct *tty, struct file *filp) if (info->flags & ASYNC_INITIALIZED) tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */ shutdown(info); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + cy_flush_buffer(tty); tty_ldisc_flush(tty); info->tty = NULL; if (info->blocked_open) { diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index b9c1dba6bd01..8fe099a41065 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c @@ -80,7 +80,7 @@ scdrv_open(struct inode *inode, struct file *file) sd = kzalloc(sizeof (struct subch_data_s), GFP_KERNEL); if (sd == NULL) { printk("%s: couldn't allocate subchannel data\n", - __FUNCTION__); + __func__); return -ENOMEM; } @@ -90,7 +90,7 @@ scdrv_open(struct inode *inode, struct file *file) if (sd->sd_subch < 0) { kfree(sd); - printk("%s: couldn't allocate subchannel\n", __FUNCTION__); + printk("%s: couldn't allocate subchannel\n", __func__); return -EBUSY; } @@ -110,7 +110,7 @@ scdrv_open(struct inode *inode, struct file *file) if (rv) { ia64_sn_irtr_close(sd->sd_nasid, sd->sd_subch); kfree(sd); - printk("%s: irq request failed (%d)\n", __FUNCTION__, rv); + printk("%s: irq request failed (%d)\n", __func__, rv); return -EBUSY; } @@ -215,7 +215,7 @@ scdrv_read(struct file *file, char __user *buf, size_t count, loff_t *f_pos) */ if (count < len) { pr_debug("%s: only accepting %d of %d bytes\n", - __FUNCTION__, (int) count, len); + __func__, (int) count, len); } len = min((int) count, len); if (copy_to_user(buf, sd->sd_rb, len)) @@ -384,7 +384,7 @@ scdrv_init(void) if (alloc_chrdev_region(&first_dev, 0, num_cnodes, SYSCTL_BASENAME) < 0) { printk("%s: failed to register SN system controller device\n", - __FUNCTION__); + __func__); return -ENODEV; } snsc_class = class_create(THIS_MODULE, SYSCTL_BASENAME); @@ -403,7 +403,7 @@ scdrv_init(void) GFP_KERNEL); if (!scd) { printk("%s: failed to allocate device info" - "for %s/%s\n", __FUNCTION__, + "for %s/%s\n", __func__, SYSCTL_BASENAME, devname); continue; } @@ -412,7 +412,7 @@ scdrv_init(void) scd->scd_nasid = cnodeid_to_nasid(cnode); if (!(salbuf = kmalloc(SCDRV_BUFSZ, GFP_KERNEL))) { printk("%s: failed to allocate driver buffer" - "(%s%s)\n", __FUNCTION__, + "(%s%s)\n", __func__, SYSCTL_BASENAME, devname); kfree(scd); continue; @@ -424,7 +424,7 @@ scdrv_init(void) ("%s: failed to initialize SAL for" " system controller communication" " (%s/%s): outdated PROM?\n", - __FUNCTION__, SYSCTL_BASENAME, devname); + __func__, SYSCTL_BASENAME, devname); kfree(scd); kfree(salbuf); continue; @@ -435,7 +435,7 @@ scdrv_init(void) if (cdev_add(&scd->scd_cdev, dev, 1)) { printk("%s: failed to register system" " controller device (%s%s)\n", - __FUNCTION__, SYSCTL_BASENAME, devname); + __func__, SYSCTL_BASENAME, devname); kfree(scd); kfree(salbuf); continue; diff --git a/drivers/char/snsc_event.c b/drivers/char/snsc_event.c index 1b75b0b7d542..53b3d44f8c06 100644 --- a/drivers/char/snsc_event.c +++ b/drivers/char/snsc_event.c @@ -63,16 +63,13 @@ static int scdrv_parse_event(char *event, int *src, int *code, int *esp_code, char *desc) { char *desc_end; - __be32 from_buf; /* record event source address */ - from_buf = get_unaligned((__be32 *)event); - *src = be32_to_cpup(&from_buf); + *src = get_unaligned_be32(event); event += 4; /* move on to event code */ /* record the system controller's event code */ - from_buf = get_unaligned((__be32 *)event); - *code = be32_to_cpup(&from_buf); + *code = get_unaligned_be32(event); event += 4; /* move on to event arguments */ /* how many arguments are in the packet? */ @@ -86,8 +83,7 @@ scdrv_parse_event(char *event, int *src, int *code, int *esp_code, char *desc) /* not an integer argument, so give up */ return -1; } - from_buf = get_unaligned((__be32 *)event); - *esp_code = be32_to_cpup(&from_buf); + *esp_code = get_unaligned_be32(event); event += 4; /* parse out the event description */ @@ -275,7 +271,7 @@ scdrv_event_init(struct sysctl_data_s *scd) event_sd = kzalloc(sizeof (struct subch_data_s), GFP_KERNEL); if (event_sd == NULL) { printk(KERN_WARNING "%s: couldn't allocate subchannel info" - " for event monitoring\n", __FUNCTION__); + " for event monitoring\n", __func__); return; } @@ -289,7 +285,7 @@ scdrv_event_init(struct sysctl_data_s *scd) if (event_sd->sd_subch < 0) { kfree(event_sd); printk(KERN_WARNING "%s: couldn't open event subchannel\n", - __FUNCTION__); + __func__); return; } @@ -299,7 +295,7 @@ scdrv_event_init(struct sysctl_data_s *scd) "system controller events", event_sd); if (rv) { printk(KERN_WARNING "%s: irq request failed (%d)\n", - __FUNCTION__, rv); + __func__, rv); ia64_sn_irtr_close(event_sd->sd_nasid, event_sd->sd_subch); kfree(event_sd); return; diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index c03ad164c39a..58533de59027 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -506,7 +506,7 @@ static struct sonypi_device { while (--n && (command)) \ udelay(1); \ if (!n && (verbose || !quiet)) \ - printk(KERN_WARNING "sonypi command failed at %s : %s (line %d)\n", __FILE__, __FUNCTION__, __LINE__); \ + printk(KERN_WARNING "sonypi command failed at %s : %s (line %d)\n", __FILE__, __func__, __LINE__); \ } #ifdef CONFIG_ACPI diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index 4b5b5b78acb4..2ee4d9893757 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -131,8 +131,8 @@ static int sx_rxfifo = SPECIALIX_RXFIFO; #define SX_DEBUG_FIFO 0x0800 -#define func_enter() dprintk (SX_DEBUG_FLOW, "io8: enter %s\n",__FUNCTION__) -#define func_exit() dprintk (SX_DEBUG_FLOW, "io8: exit %s\n", __FUNCTION__) +#define func_enter() dprintk (SX_DEBUG_FLOW, "io8: enter %s\n",__func__) +#define func_exit() dprintk (SX_DEBUG_FLOW, "io8: exit %s\n", __func__) #define jiffies_from_ms(a) ((((a) * HZ)/1000)+1) @@ -874,7 +874,7 @@ static irqreturn_t sx_interrupt(int dummy, void *dev_id) spin_lock_irqsave(&bp->lock, flags); - dprintk (SX_DEBUG_FLOW, "enter %s port %d room: %ld\n", __FUNCTION__, port_No(sx_get_port(bp, "INT")), SERIAL_XMIT_SIZE - sx_get_port(bp, "ITN")->xmit_cnt - 1); + dprintk (SX_DEBUG_FLOW, "enter %s port %d room: %ld\n", __func__, port_No(sx_get_port(bp, "INT")), SERIAL_XMIT_SIZE - sx_get_port(bp, "ITN")->xmit_cnt - 1); if (!(bp->flags & SX_BOARD_ACTIVE)) { dprintk (SX_DEBUG_IRQ, "sx: False interrupt. irq %d.\n", bp->irq); spin_unlock_irqrestore(&bp->lock, flags); @@ -1504,6 +1504,27 @@ static int sx_open(struct tty_struct * tty, struct file * filp) return 0; } +static void sx_flush_buffer(struct tty_struct *tty) +{ + struct specialix_port *port = (struct specialix_port *)tty->driver_data; + unsigned long flags; + struct specialix_board * bp; + + func_enter(); + + if (sx_paranoia_check(port, tty->name, "sx_flush_buffer")) { + func_exit(); + return; + } + + bp = port_Board(port); + spin_lock_irqsave(&port->lock, flags); + port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; + spin_unlock_irqrestore(&port->lock, flags); + tty_wakeup(tty); + + func_exit(); +} static void sx_close(struct tty_struct * tty, struct file * filp) { @@ -1597,8 +1618,7 @@ static void sx_close(struct tty_struct * tty, struct file * filp) } sx_shutdown_port(bp, port); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + sx_flush_buffer(tty); tty_ldisc_flush(tty); spin_lock_irqsave(&port->lock, flags); tty->closing = 0; @@ -1670,7 +1690,7 @@ static int sx_write(struct tty_struct * tty, } -static void sx_put_char(struct tty_struct * tty, unsigned char ch) +static int sx_put_char(struct tty_struct * tty, unsigned char ch) { struct specialix_port *port = (struct specialix_port *)tty->driver_data; unsigned long flags; @@ -1680,12 +1700,12 @@ static void sx_put_char(struct tty_struct * tty, unsigned char ch) if (sx_paranoia_check(port, tty->name, "sx_put_char")) { func_exit(); - return; + return 0; } dprintk (SX_DEBUG_TX, "check tty: %p %p\n", tty, port->xmit_buf); if (!port->xmit_buf) { func_exit(); - return; + return 0; } bp = port_Board(port); spin_lock_irqsave(&port->lock, flags); @@ -1695,7 +1715,7 @@ static void sx_put_char(struct tty_struct * tty, unsigned char ch) spin_unlock_irqrestore(&port->lock, flags); dprintk (SX_DEBUG_TX, "Exit size\n"); func_exit(); - return; + return 0; } dprintk (SX_DEBUG_TX, "Handle xmit: %p %p\n", port, port->xmit_buf); port->xmit_buf[port->xmit_head++] = ch; @@ -1704,6 +1724,7 @@ static void sx_put_char(struct tty_struct * tty, unsigned char ch) spin_unlock_irqrestore(&port->lock, flags); func_exit(); + return 1; } @@ -1770,28 +1791,6 @@ static int sx_chars_in_buffer(struct tty_struct *tty) } -static void sx_flush_buffer(struct tty_struct *tty) -{ - struct specialix_port *port = (struct specialix_port *)tty->driver_data; - unsigned long flags; - struct specialix_board * bp; - - func_enter(); - - if (sx_paranoia_check(port, tty->name, "sx_flush_buffer")) { - func_exit(); - return; - } - - bp = port_Board(port); - spin_lock_irqsave(&port->lock, flags); - port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; - spin_unlock_irqrestore(&port->lock, flags); - tty_wakeup(tty); - - func_exit(); -} - static int sx_tiocmget(struct tty_struct *tty, struct file *file) { @@ -1803,7 +1802,7 @@ static int sx_tiocmget(struct tty_struct *tty, struct file *file) func_enter(); - if (sx_paranoia_check(port, tty->name, __FUNCTION__)) { + if (sx_paranoia_check(port, tty->name, __func__)) { func_exit(); return -ENODEV; } @@ -1845,7 +1844,7 @@ static int sx_tiocmset(struct tty_struct *tty, struct file *file, func_enter(); - if (sx_paranoia_check(port, tty->name, __FUNCTION__)) { + if (sx_paranoia_check(port, tty->name, __func__)) { func_exit(); return -ENODEV; } @@ -1922,29 +1921,13 @@ static inline int sx_set_serial_info(struct specialix_port * port, int change_speed; func_enter(); - /* - if (!access_ok(VERIFY_READ, (void *) newinfo, sizeof(tmp))) { - func_exit(); - return -EFAULT; - } - */ + if (copy_from_user(&tmp, newinfo, sizeof(tmp))) { func_enter(); return -EFAULT; } -#if 0 - if ((tmp.irq != bp->irq) || - (tmp.port != bp->base) || - (tmp.type != PORT_CIRRUS) || - (tmp.baud_base != (SX_OSCFREQ + CD186x_TPC/2) / CD186x_TPC) || - (tmp.custom_divisor != 0) || - (tmp.xmit_fifo_size != CD186x_NFIFO) || - (tmp.flags & ~SPECIALIX_LEGAL_FLAGS)) { - func_exit(); - return -EINVAL; - } -#endif + lock_kernel(); change_speed = ((port->flags & ASYNC_SPD_MASK) != (tmp.flags & ASYNC_SPD_MASK)); @@ -1956,6 +1939,7 @@ static inline int sx_set_serial_info(struct specialix_port * port, ((tmp.flags & ~ASYNC_USR_MASK) != (port->flags & ~ASYNC_USR_MASK))) { func_exit(); + unlock_kernel(); return -EPERM; } port->flags = ((port->flags & ~ASYNC_USR_MASK) | @@ -1972,6 +1956,7 @@ static inline int sx_set_serial_info(struct specialix_port * port, sx_change_speed(bp, port); } func_exit(); + unlock_kernel(); return 0; } @@ -1984,12 +1969,8 @@ static inline int sx_get_serial_info(struct specialix_port * port, func_enter(); - /* - if (!access_ok(VERIFY_WRITE, (void *) retinfo, sizeof(tmp))) - return -EFAULT; - */ - memset(&tmp, 0, sizeof(tmp)); + lock_kernel(); tmp.type = PORT_CIRRUS; tmp.line = port - sx_port; tmp.port = bp->base; @@ -2000,6 +1981,7 @@ static inline int sx_get_serial_info(struct specialix_port * port, tmp.closing_wait = port->closing_wait * HZ/100; tmp.custom_divisor = port->custom_divisor; tmp.xmit_fifo_size = CD186x_NFIFO; + unlock_kernel(); if (copy_to_user(retinfo, &tmp, sizeof(tmp))) { func_exit(); return -EFAULT; @@ -2045,23 +2027,6 @@ static int sx_ioctl(struct tty_struct * tty, struct file * filp, sx_send_break(port, arg ? arg*(HZ/10) : HZ/4); func_exit(); return 0; - case TIOCGSOFTCAR: - if (put_user(C_CLOCAL(tty)?1:0, (unsigned long __user *)argp)) { - func_exit(); - return -EFAULT; - } - func_exit(); - return 0; - case TIOCSSOFTCAR: - if (get_user(arg, (unsigned long __user *) argp)) { - func_exit(); - return -EFAULT; - } - tty->termios->c_cflag = - ((tty->termios->c_cflag & ~CLOCAL) | - (arg ? CLOCAL : 0)); - func_exit(); - return 0; case TIOCGSERIAL: func_exit(); return sx_get_serial_info(port, argp); diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 874aaa08e956..d17be10c5d21 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -875,6 +875,7 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout) timeout = HZ; tend = jiffies + timeout; + lock_kernel(); while (stl_datastate(portp)) { if (signal_pending(current)) break; @@ -882,6 +883,7 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout) if (time_after_eq(jiffies, tend)) break; } + unlock_kernel(); } /*****************************************************************************/ @@ -1273,18 +1275,9 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd rc = 0; + lock_kernel(); + switch (cmd) { - case TIOCGSOFTCAR: - rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), - (unsigned __user *) argp); - break; - case TIOCSSOFTCAR: - if (get_user(ival, (unsigned int __user *) arg)) - return -EFAULT; - tty->termios->c_cflag = - (tty->termios->c_cflag & ~CLOCAL) | - (ival ? CLOCAL : 0); - break; case TIOCGSERIAL: rc = stl_getserial(portp, argp); break; @@ -1308,7 +1301,7 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd rc = -ENOIOCTLCMD; break; } - + unlock_kernel(); return rc; } diff --git a/drivers/char/sx.c b/drivers/char/sx.c index a6e1c9ba1217..f39f6fd89350 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c @@ -384,11 +384,11 @@ static struct real_driver sx_real_driver = { #define sx_dprintk(f, str...) /* nothing */ #endif -#define func_enter() sx_dprintk(SX_DEBUG_FLOW, "sx: enter %s\n",__FUNCTION__) -#define func_exit() sx_dprintk(SX_DEBUG_FLOW, "sx: exit %s\n",__FUNCTION__) +#define func_enter() sx_dprintk(SX_DEBUG_FLOW, "sx: enter %s\n",__func__) +#define func_exit() sx_dprintk(SX_DEBUG_FLOW, "sx: exit %s\n",__func__) #define func_enter2() sx_dprintk(SX_DEBUG_FLOW, "sx: enter %s (port %d)\n", \ - __FUNCTION__, port->line) + __func__, port->line) /* * Firmware loader driver specific routines @@ -1574,7 +1574,7 @@ static void sx_close(void *ptr) sx_dprintk(SX_DEBUG_CLOSE, "WARNING port count:%d\n", port->gs.count); /*printk("%s SETTING port count to zero: %p count: %d\n", - __FUNCTION__, port, port->gs.count); + __func__, port, port->gs.count); port->gs.count = 0;*/ } @@ -1844,6 +1844,7 @@ static void sx_break(struct tty_struct *tty, int flag) int rv; func_enter(); + lock_kernel(); if (flag) rv = sx_send_command(port, HS_START, -1, HS_IDLE_BREAK); @@ -1852,7 +1853,7 @@ static void sx_break(struct tty_struct *tty, int flag) if (rv != 1) printk(KERN_ERR "sx: couldn't send break (%x).\n", read_sx_byte(port->board, CHAN_OFFSET(port, hi_hstat))); - + unlock_kernel(); func_exit(); } @@ -1888,23 +1889,12 @@ static int sx_ioctl(struct tty_struct *tty, struct file *filp, int rc; struct sx_port *port = tty->driver_data; void __user *argp = (void __user *)arg; - int ival; /* func_enter2(); */ rc = 0; + lock_kernel(); switch (cmd) { - case TIOCGSOFTCAR: - rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), - (unsigned __user *)argp); - break; - case TIOCSSOFTCAR: - if ((rc = get_user(ival, (unsigned __user *)argp)) == 0) { - tty->termios->c_cflag = - (tty->termios->c_cflag & ~CLOCAL) | - (ival ? CLOCAL : 0); - } - break; case TIOCGSERIAL: rc = gs_getserial(&port->gs, argp); break; @@ -1915,6 +1905,7 @@ static int sx_ioctl(struct tty_struct *tty, struct file *filp, rc = -ENOIOCTLCMD; break; } + unlock_kernel(); /* func_exit(); */ return rc; @@ -2549,7 +2540,7 @@ static int __devinit sx_eisa_probe(struct device *dev) goto err_flag; } board->base2 = - board->base = ioremap(board->hw_base, SI2_EISA_WINDOW_LEN); + board->base = ioremap_nocache(board->hw_base, SI2_EISA_WINDOW_LEN); if (!board->base) { dev_err(dev, "can't remap memory\n"); goto err_reg; @@ -2626,7 +2617,7 @@ static void __devinit fix_sx_pci(struct pci_dev *pdev, struct sx_board *board) pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &hwbase); hwbase &= PCI_BASE_ADDRESS_MEM_MASK; - rebase = ioremap(hwbase, 0x80); + rebase = ioremap_nocache(hwbase, 0x80); t = readl(rebase + CNTRL_REG_OFFSET); if (t != CNTRL_REG_GOODVALUE) { printk(KERN_DEBUG "sx: performing cntrl reg fix: %08x -> " @@ -2770,7 +2761,7 @@ static int __init sx_init(void) if (!request_region(board->hw_base, board->hw_len, "sx")) continue; board->base2 = - board->base = ioremap(board->hw_base, board->hw_len); + board->base = ioremap_nocache(board->hw_base, board->hw_len); if (!board->base) goto err_sx_reg; board->flags &= ~SX_BOARD_TYPE; @@ -2794,7 +2785,7 @@ err_sx_reg: if (!request_region(board->hw_base, board->hw_len, "sx")) continue; board->base2 = - board->base = ioremap(board->hw_base, board->hw_len); + board->base = ioremap_nocache(board->hw_base, board->hw_len); if (!board->base) goto err_si_reg; board->flags &= ~SX_BOARD_TYPE; @@ -2817,7 +2808,7 @@ err_si_reg: if (!request_region(board->hw_base, board->hw_len, "sx")) continue; board->base2 = - board->base = ioremap(board->hw_base, board->hw_len); + board->base = ioremap_nocache(board->hw_base, board->hw_len); if (!board->base) goto err_si1_reg; board->flags &= ~SX_BOARD_TYPE; diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index fadab1d9510f..513b7c2f3e26 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -2026,10 +2026,11 @@ static void mgsl_change_params(struct mgsl_struct *info) * * Return Value: None */ -static void mgsl_put_char(struct tty_struct *tty, unsigned char ch) +static int mgsl_put_char(struct tty_struct *tty, unsigned char ch) { struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data; unsigned long flags; + int ret; if ( debug_level >= DEBUG_LEVEL_INFO ) { printk( "%s(%d):mgsl_put_char(%d) on %s\n", @@ -2037,23 +2038,23 @@ static void mgsl_put_char(struct tty_struct *tty, unsigned char ch) } if (mgsl_paranoia_check(info, tty->name, "mgsl_put_char")) - return; + return 0; if (!tty || !info->xmit_buf) - return; + return 0; spin_lock_irqsave(&info->irq_spinlock,flags); if ( (info->params.mode == MGSL_MODE_ASYNC ) || !info->tx_active ) { - if (info->xmit_cnt < SERIAL_XMIT_SIZE - 1) { info->xmit_buf[info->xmit_head++] = ch; info->xmit_head &= SERIAL_XMIT_SIZE-1; info->xmit_cnt++; + ret = 1; } } - spin_unlock_irqrestore(&info->irq_spinlock,flags); + return ret; } /* end of mgsl_put_char() */ @@ -2942,6 +2943,7 @@ static int mgsl_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data; + int ret; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgsl_ioctl %s cmd=%08X\n", __FILE__,__LINE__, @@ -2956,7 +2958,10 @@ static int mgsl_ioctl(struct tty_struct *tty, struct file * file, return -EIO; } - return mgsl_ioctl_common(info, cmd, arg); + lock_kernel(); + ret = mgsl_ioctl_common(info, cmd, arg); + unlock_kernel(); + return ret; } static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg) @@ -3153,8 +3158,7 @@ static void mgsl_close(struct tty_struct *tty, struct file * filp) if (info->flags & ASYNC_INITIALIZED) mgsl_wait_until_sent(tty, info->timeout); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + mgsl_flush_buffer(tty); tty_ldisc_flush(tty); @@ -3217,7 +3221,8 @@ static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout) * interval should also be less than the timeout. * Note: use tight timings here to satisfy the NIST-PCTS. */ - + + lock_kernel(); if ( info->params.data_rate ) { char_time = info->timeout/(32 * 5); if (!char_time) @@ -3247,6 +3252,7 @@ static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout) break; } } + unlock_kernel(); exit: if (debug_level >= DEBUG_LEVEL_INFO) @@ -4144,7 +4150,8 @@ static int mgsl_claim_resources(struct mgsl_struct *info) } info->lcr_mem_requested = true; - info->memory_base = ioremap(info->phys_memory_base,0x40000); + info->memory_base = ioremap_nocache(info->phys_memory_base, + 0x40000); if (!info->memory_base) { printk( "%s(%d):Cant map shared memory on device %s MemAddr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_memory_base ); @@ -4157,12 +4164,14 @@ static int mgsl_claim_resources(struct mgsl_struct *info) goto errout; } - info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE) + info->lcr_offset; + info->lcr_base = ioremap_nocache(info->phys_lcr_base, + PAGE_SIZE); if (!info->lcr_base) { printk( "%s(%d):Cant map LCR memory on device %s MemAddr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_lcr_base ); goto errout; } + info->lcr_base += info->lcr_offset; } else { /* claim DMA channel */ diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index f3d8d72e5ea4..2001b0e52dc6 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -151,7 +151,7 @@ static void hangup(struct tty_struct *tty); static void set_termios(struct tty_struct *tty, struct ktermios *old_termios); static int write(struct tty_struct *tty, const unsigned char *buf, int count); -static void put_char(struct tty_struct *tty, unsigned char ch); +static int put_char(struct tty_struct *tty, unsigned char ch); static void send_xchar(struct tty_struct *tty, char ch); static void wait_until_sent(struct tty_struct *tty, int timeout); static int write_room(struct tty_struct *tty); @@ -771,8 +771,7 @@ static void close(struct tty_struct *tty, struct file *filp) if (info->flags & ASYNC_INITIALIZED) wait_until_sent(tty, info->timeout); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + flush_buffer(tty); tty_ldisc_flush(tty); shutdown(info); @@ -913,20 +912,24 @@ cleanup: return ret; } -static void put_char(struct tty_struct *tty, unsigned char ch) +static int put_char(struct tty_struct *tty, unsigned char ch) { struct slgt_info *info = tty->driver_data; unsigned long flags; + int ret; if (sanity_check(info, tty->name, "put_char")) - return; + return 0; DBGINFO(("%s put_char(%d)\n", info->device_name, ch)); if (!info->tx_buf) - return; + return 0; spin_lock_irqsave(&info->lock,flags); - if (!info->tx_active && (info->tx_count < info->max_frame_size)) + if (!info->tx_active && (info->tx_count < info->max_frame_size)) { info->tx_buf[info->tx_count++] = ch; + ret = 1; + } spin_unlock_irqrestore(&info->lock,flags); + return ret; } static void send_xchar(struct tty_struct *tty, char ch) @@ -967,6 +970,8 @@ static void wait_until_sent(struct tty_struct *tty, int timeout) * Note: use tight timings here to satisfy the NIST-PCTS. */ + lock_kernel(); + if (info->params.data_rate) { char_time = info->timeout/(32 * 5); if (!char_time) @@ -984,6 +989,7 @@ static void wait_until_sent(struct tty_struct *tty, int timeout) if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; } + unlock_kernel(); exit: DBGINFO(("%s wait_until_sent exit\n", info->device_name)); @@ -1097,6 +1103,7 @@ static int ioctl(struct tty_struct *tty, struct file *file, struct serial_icounter_struct __user *p_cuser; /* user space */ unsigned long flags; void __user *argp = (void __user *)arg; + int ret; if (sanity_check(info, tty->name, "ioctl")) return -ENODEV; @@ -1108,37 +1115,54 @@ static int ioctl(struct tty_struct *tty, struct file *file, return -EIO; } + lock_kernel(); + switch (cmd) { case MGSL_IOCGPARAMS: - return get_params(info, argp); + ret = get_params(info, argp); + break; case MGSL_IOCSPARAMS: - return set_params(info, argp); + ret = set_params(info, argp); + break; case MGSL_IOCGTXIDLE: - return get_txidle(info, argp); + ret = get_txidle(info, argp); + break; case MGSL_IOCSTXIDLE: - return set_txidle(info, (int)arg); + ret = set_txidle(info, (int)arg); + break; case MGSL_IOCTXENABLE: - return tx_enable(info, (int)arg); + ret = tx_enable(info, (int)arg); + break; case MGSL_IOCRXENABLE: - return rx_enable(info, (int)arg); + ret = rx_enable(info, (int)arg); + break; case MGSL_IOCTXABORT: - return tx_abort(info); + ret = tx_abort(info); + break; case MGSL_IOCGSTATS: - return get_stats(info, argp); + ret = get_stats(info, argp); + break; case MGSL_IOCWAITEVENT: - return wait_mgsl_event(info, argp); + ret = wait_mgsl_event(info, argp); + break; case TIOCMIWAIT: - return modem_input_wait(info,(int)arg); + ret = modem_input_wait(info,(int)arg); + break; case MGSL_IOCGIF: - return get_interface(info, argp); + ret = get_interface(info, argp); + break; case MGSL_IOCSIF: - return set_interface(info,(int)arg); + ret = set_interface(info,(int)arg); + break; case MGSL_IOCSGPIO: - return set_gpio(info, argp); + ret = set_gpio(info, argp); + break; case MGSL_IOCGGPIO: - return get_gpio(info, argp); + ret = get_gpio(info, argp); + break; case MGSL_IOCWAITGPIO: - return wait_gpio(info, argp); + ret = wait_gpio(info, argp); + break; case TIOCGICOUNT: spin_lock_irqsave(&info->lock,flags); cnow = info->icount; @@ -1155,12 +1179,14 @@ static int ioctl(struct tty_struct *tty, struct file *file, put_user(cnow.parity, &p_cuser->parity) || put_user(cnow.brk, &p_cuser->brk) || put_user(cnow.buf_overrun, &p_cuser->buf_overrun)) - return -EFAULT; - return 0; + ret = -EFAULT; + ret = 0; + break; default: - return -ENOIOCTLCMD; + ret = -ENOIOCTLCMD; } - return 0; + unlock_kernel(); + return ret; } /* @@ -3324,7 +3350,7 @@ static int claim_resources(struct slgt_info *info) else info->reg_addr_requested = true; - info->reg_addr = ioremap(info->phys_reg_addr, SLGT_REG_SIZE); + info->reg_addr = ioremap_nocache(info->phys_reg_addr, SLGT_REG_SIZE); if (!info->reg_addr) { DBGERR(("%s cant map device registers, addr=%08X\n", info->device_name, info->phys_reg_addr)); diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index e98c3e6f8216..bec54866e0bb 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -519,7 +519,7 @@ static void hangup(struct tty_struct *tty); static void set_termios(struct tty_struct *tty, struct ktermios *old_termios); static int write(struct tty_struct *tty, const unsigned char *buf, int count); -static void put_char(struct tty_struct *tty, unsigned char ch); +static int put_char(struct tty_struct *tty, unsigned char ch); static void send_xchar(struct tty_struct *tty, char ch); static void wait_until_sent(struct tty_struct *tty, int timeout); static int write_room(struct tty_struct *tty); @@ -862,8 +862,7 @@ static void close(struct tty_struct *tty, struct file *filp) if (info->flags & ASYNC_INITIALIZED) wait_until_sent(tty, info->timeout); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + flush_buffer(tty); tty_ldisc_flush(tty); @@ -1046,10 +1045,11 @@ cleanup: /* Add a character to the transmit buffer. */ -static void put_char(struct tty_struct *tty, unsigned char ch) +static int put_char(struct tty_struct *tty, unsigned char ch) { SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; unsigned long flags; + int ret = 0; if ( debug_level >= DEBUG_LEVEL_INFO ) { printk( "%s(%d):%s put_char(%d)\n", @@ -1057,10 +1057,10 @@ static void put_char(struct tty_struct *tty, unsigned char ch) } if (sanity_check(info, tty->name, "put_char")) - return; + return 0; if (!info->tx_buf) - return; + return 0; spin_lock_irqsave(&info->lock,flags); @@ -1072,10 +1072,12 @@ static void put_char(struct tty_struct *tty, unsigned char ch) if (info->tx_put >= info->max_frame_size) info->tx_put -= info->max_frame_size; info->tx_count++; + ret = 1; } } spin_unlock_irqrestore(&info->lock,flags); + return ret; } /* Send a high-priority XON/XOFF character @@ -1119,6 +1121,8 @@ static void wait_until_sent(struct tty_struct *tty, int timeout) if (sanity_check(info, tty->name, "wait_until_sent")) return; + lock_kernel(); + if (!(info->flags & ASYNC_INITIALIZED)) goto exit; @@ -1161,6 +1165,7 @@ static void wait_until_sent(struct tty_struct *tty, int timeout) } exit: + unlock_kernel(); if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s wait_until_sent() exit\n", __FILE__,__LINE__, info->device_name ); @@ -1176,6 +1181,7 @@ static int write_room(struct tty_struct *tty) if (sanity_check(info, tty->name, "write_room")) return 0; + lock_kernel(); if (info->params.mode == MGSL_MODE_HDLC) { ret = (info->tx_active) ? 0 : HDLC_MAX_FRAME_SIZE; } else { @@ -1183,6 +1189,7 @@ static int write_room(struct tty_struct *tty) if (ret < 0) ret = 0; } + unlock_kernel(); if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s write_room()=%d\n", @@ -1303,7 +1310,7 @@ static void tx_release(struct tty_struct *tty) * * Return Value: 0 if success, otherwise error code */ -static int ioctl(struct tty_struct *tty, struct file *file, +static int do_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { SLMP_INFO *info = (SLMP_INFO *)tty->driver_data; @@ -1393,6 +1400,16 @@ static int ioctl(struct tty_struct *tty, struct file *file, return 0; } +static int ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret; + lock_kernel(); + ret = do_ioctl(tty, file, cmd, arg); + unlock_kernel(); + return ret; +} + /* * /proc fs routines.... */ @@ -3626,7 +3643,8 @@ static int claim_resources(SLMP_INFO *info) else info->sca_statctrl_requested = true; - info->memory_base = ioremap(info->phys_memory_base,SCA_MEM_SIZE); + info->memory_base = ioremap_nocache(info->phys_memory_base, + SCA_MEM_SIZE); if (!info->memory_base) { printk( "%s(%d):%s Cant map shared memory, MemAddr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_memory_base ); @@ -3634,7 +3652,7 @@ static int claim_resources(SLMP_INFO *info) goto errout; } - info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE); + info->lcr_base = ioremap_nocache(info->phys_lcr_base, PAGE_SIZE); if (!info->lcr_base) { printk( "%s(%d):%s Cant map LCR memory, MemAddr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_lcr_base ); @@ -3643,7 +3661,7 @@ static int claim_resources(SLMP_INFO *info) } info->lcr_base += info->lcr_offset; - info->sca_base = ioremap(info->phys_sca_base,PAGE_SIZE); + info->sca_base = ioremap_nocache(info->phys_sca_base, PAGE_SIZE); if (!info->sca_base) { printk( "%s(%d):%s Cant map SCA memory, MemAddr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_sca_base ); @@ -3652,7 +3670,8 @@ static int claim_resources(SLMP_INFO *info) } info->sca_base += info->sca_offset; - info->statctrl_base = ioremap(info->phys_statctrl_base,PAGE_SIZE); + info->statctrl_base = ioremap_nocache(info->phys_statctrl_base, + PAGE_SIZE); if (!info->statctrl_base) { printk( "%s(%d):%s Cant map SCA Status/Control memory, MemAddr=%08X\n", __FILE__,__LINE__,info->device_name, info->phys_statctrl_base ); diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index 1ade193c9128..9e9bad8bdcf4 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -196,6 +196,48 @@ static struct sysrq_key_op sysrq_showlocks_op = { #define sysrq_showlocks_op (*(struct sysrq_key_op *)0) #endif +#ifdef CONFIG_SMP +static DEFINE_SPINLOCK(show_lock); + +static void showacpu(void *dummy) +{ + unsigned long flags; + + /* Idle CPUs have no interesting backtrace. */ + if (idle_cpu(smp_processor_id())) + return; + + spin_lock_irqsave(&show_lock, flags); + printk(KERN_INFO "CPU%d:\n", smp_processor_id()); + show_stack(NULL, NULL); + spin_unlock_irqrestore(&show_lock, flags); +} + +static void sysrq_showregs_othercpus(struct work_struct *dummy) +{ + smp_call_function(showacpu, NULL, 0, 0); +} + +static DECLARE_WORK(sysrq_showallcpus, sysrq_showregs_othercpus); + +static void sysrq_handle_showallcpus(int key, struct tty_struct *tty) +{ + struct pt_regs *regs = get_irq_regs(); + if (regs) { + printk(KERN_INFO "CPU%d:\n", smp_processor_id()); + show_regs(regs); + } + schedule_work(&sysrq_showallcpus); +} + +static struct sysrq_key_op sysrq_showallcpus_op = { + .handler = sysrq_handle_showallcpus, + .help_msg = "aLlcpus", + .action_msg = "Show backtrace of all active CPUs", + .enable_mask = SYSRQ_ENABLE_DUMP, +}; +#endif + static void sysrq_handle_showregs(int key, struct tty_struct *tty) { struct pt_regs *regs = get_irq_regs(); @@ -340,7 +382,11 @@ static struct sysrq_key_op *sysrq_key_table[36] = { &sysrq_kill_op, /* i */ NULL, /* j */ &sysrq_SAK_op, /* k */ +#ifdef CONFIG_SMP + &sysrq_showallcpus_op, /* l */ +#else NULL, /* l */ +#endif &sysrq_showmem_op, /* m */ &sysrq_unrt_op, /* n */ /* o: This will often be registered as 'Off' at init time */ diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c index ce5ebe3b168f..64f1ceed0b2c 100644 --- a/drivers/char/toshiba.c +++ b/drivers/char/toshiba.c @@ -520,12 +520,11 @@ static int __init toshiba_init(void) { struct proc_dir_entry *pde; - pde = create_proc_entry("toshiba", 0, NULL); + pde = proc_create("toshiba", 0, NULL, &proc_toshiba_fops); if (!pde) { misc_deregister(&tosh_device); return -ENOMEM; } - pde->proc_fops = &proc_toshiba_fops; } #endif diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 8f3f7620f95a..3738cfa209ff 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -23,7 +23,7 @@ if TCG_TPM config TCG_TIS tristate "TPM Interface Specification 1.2 Interface" - depends on PNPACPI + depends on PNP ---help--- If you have a TPM security chip that is compliant with the TCG TIS 1.2 TPM specification say Yes and it will be accessible @@ -32,7 +32,6 @@ config TCG_TIS config TCG_NSC tristate "National Semiconductor TPM Interface" - depends on PNPACPI ---help--- If you have a TPM security chip from National Semiconductor say Yes and it will be accessible from within Linux. To @@ -48,7 +47,7 @@ config TCG_ATMEL config TCG_INFINEON tristate "Infineon Technologies TPM Interface" - depends on PNPACPI + depends on PNP ---help--- If you have a TPM security chip from Infineon Technologies (either SLD 9630 TT 1.1 or SLB 9635 TT 1.2) say Yes and it diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 6313326bc41f..ab18c1e7b115 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c @@ -264,7 +264,7 @@ static const struct tpm_vendor_specific tpm_nsc = { static struct platform_device *pdev = NULL; -static void __devexit tpm_nsc_remove(struct device *dev) +static void tpm_nsc_remove(struct device *dev) { struct tpm_chip *chip = dev_get_drvdata(dev); if ( chip ) { diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c index 7722466e052f..6342b0534f4d 100644 --- a/drivers/char/tty_audit.c +++ b/drivers/char/tty_audit.c @@ -92,7 +92,7 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid, get_task_comm(name, tsk); audit_log_untrustedstring(ab, name); audit_log_format(ab, " data="); - audit_log_n_untrustedstring(ab, buf->valid, buf->data); + audit_log_n_untrustedstring(ab, buf->data, buf->valid); audit_log_end(ab); } buf->valid = 0; @@ -151,14 +151,9 @@ void tty_audit_fork(struct signal_struct *sig) /** * tty_audit_push_task - Flush task's pending audit data */ -void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid) +void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid) { struct tty_audit_buf *buf; - /* FIXME I think this is correct. Check against netlink once that is - * I really need to read this code more closely. But that's for - * another patch. - */ - unsigned int sessionid = audit_get_sessionid(tsk); spin_lock_irq(&tsk->sighand->siglock); buf = tsk->signal->tty_audit_buf; @@ -238,6 +233,10 @@ void tty_audit_add_data(struct tty_struct *tty, unsigned char *data, if (unlikely(size == 0)) return; + if (tty->driver->type == TTY_DRIVER_TYPE_PTY + && tty->driver->subtype == PTY_TYPE_MASTER) + return; + buf = tty_audit_buf_get(tty); if (!buf) return; @@ -300,53 +299,3 @@ void tty_audit_push(struct tty_struct *tty) tty_audit_buf_put(buf); } } - -/** - * tty_audit_opening - A TTY is being opened. - * - * As a special hack, tasks that close all their TTYs and open new ones - * are assumed to be system daemons (e.g. getty) and auditing is - * automatically disabled for them. - */ -void tty_audit_opening(void) -{ - int disable; - - disable = 1; - spin_lock_irq(¤t->sighand->siglock); - if (current->signal->audit_tty == 0) - disable = 0; - spin_unlock_irq(¤t->sighand->siglock); - if (!disable) - return; - - task_lock(current); - if (current->files) { - struct fdtable *fdt; - unsigned i; - - /* - * We don't take a ref to the file, so we must hold ->file_lock - * instead. - */ - spin_lock(¤t->files->file_lock); - fdt = files_fdtable(current->files); - for (i = 0; i < fdt->max_fds; i++) { - struct file *filp; - - filp = fcheck_files(current->files, i); - if (filp && is_tty(filp)) { - disable = 0; - break; - } - } - spin_unlock(¤t->files->file_lock); - } - task_unlock(current); - if (!disable) - return; - - spin_lock_irq(¤t->sighand->siglock); - current->signal->audit_tty = 0; - spin_unlock_irq(¤t->sighand->siglock); -} diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 98b65a230994..1d298c2cf930 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -91,7 +91,6 @@ #include <linux/module.h> #include <linux/smp_lock.h> #include <linux/device.h> -#include <linux/idr.h> #include <linux/wait.h> #include <linux/bitops.h> #include <linux/delay.h> @@ -137,9 +136,6 @@ EXPORT_SYMBOL(tty_mutex); #ifdef CONFIG_UNIX98_PTYS extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */ -extern int pty_limit; /* Config limit on Unix98 ptys */ -static DEFINE_IDR(allocated_ptys); -static DEFINE_MUTEX(allocated_ptys_lock); static int ptmx_open(struct inode *, struct file *); #endif @@ -152,8 +148,7 @@ ssize_t redirected_tty_write(struct file *, const char __user *, static unsigned int tty_poll(struct file *, poll_table *); static int tty_open(struct inode *, struct file *); static int tty_release(struct inode *, struct file *); -int tty_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); +long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg); #ifdef CONFIG_COMPAT static long tty_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); @@ -1109,8 +1104,8 @@ restart: a reference to the old ldisc. If we ended up flipping back to the existing ldisc we have two references to it */ - if (tty->ldisc.num != o_ldisc.num && tty->driver->set_ldisc) - tty->driver->set_ldisc(tty); + if (tty->ldisc.num != o_ldisc.num && tty->ops->set_ldisc) + tty->ops->set_ldisc(tty); tty_ldisc_put(o_ldisc.num); @@ -1182,9 +1177,8 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line) if (*str == '\0') str = NULL; - if (tty_line >= 0 && tty_line <= p->num && p->poll_init && - !p->poll_init(p, tty_line, str)) { - + if (tty_line >= 0 && tty_line <= p->num && p->ops && + p->ops->poll_init && !p->ops->poll_init(p, tty_line, str)) { res = p; *line = tty_line; break; @@ -1205,26 +1199,37 @@ EXPORT_SYMBOL_GPL(tty_find_polling_driver); * not in the foreground, send a SIGTTOU. If the signal is blocked or * ignored, go ahead and perform the operation. (POSIX 7.2) * - * Locking: none + * Locking: ctrl_lock */ int tty_check_change(struct tty_struct *tty) { + unsigned long flags; + int ret = 0; + if (current->signal->tty != tty) return 0; + + spin_lock_irqsave(&tty->ctrl_lock, flags); + if (!tty->pgrp) { printk(KERN_WARNING "tty_check_change: tty->pgrp == NULL!\n"); - return 0; + goto out; } if (task_pgrp(current) == tty->pgrp) - return 0; + goto out; if (is_ignored(SIGTTOU)) - return 0; - if (is_current_pgrp_orphaned()) - return -EIO; + goto out; + if (is_current_pgrp_orphaned()) { + ret = -EIO; + goto out; + } kill_pgrp(task_pgrp(current), SIGTTOU, 1); set_thread_flag(TIF_SIGPENDING); - return -ERESTARTSYS; + ret = -ERESTARTSYS; +out: + spin_unlock_irqrestore(&tty->ctrl_lock, flags); + return ret; } EXPORT_SYMBOL(tty_check_change); @@ -1247,8 +1252,8 @@ static unsigned int hung_up_tty_poll(struct file *filp, poll_table *wait) return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM; } -static int hung_up_tty_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +static long hung_up_tty_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { return cmd == TIOCSPGRP ? -ENOTTY : -EIO; } @@ -1264,7 +1269,7 @@ static const struct file_operations tty_fops = { .read = tty_read, .write = tty_write, .poll = tty_poll, - .ioctl = tty_ioctl, + .unlocked_ioctl = tty_ioctl, .compat_ioctl = tty_compat_ioctl, .open = tty_open, .release = tty_release, @@ -1277,7 +1282,7 @@ static const struct file_operations ptmx_fops = { .read = tty_read, .write = tty_write, .poll = tty_poll, - .ioctl = tty_ioctl, + .unlocked_ioctl = tty_ioctl, .compat_ioctl = tty_compat_ioctl, .open = ptmx_open, .release = tty_release, @@ -1290,7 +1295,7 @@ static const struct file_operations console_fops = { .read = tty_read, .write = redirected_tty_write, .poll = tty_poll, - .ioctl = tty_ioctl, + .unlocked_ioctl = tty_ioctl, .compat_ioctl = tty_compat_ioctl, .open = tty_open, .release = tty_release, @@ -1302,7 +1307,7 @@ static const struct file_operations hung_up_tty_fops = { .read = hung_up_tty_read, .write = hung_up_tty_write, .poll = hung_up_tty_poll, - .ioctl = hung_up_tty_ioctl, + .unlocked_ioctl = hung_up_tty_ioctl, .compat_ioctl = hung_up_tty_compat_ioctl, .release = tty_release, }; @@ -1404,6 +1409,7 @@ static void do_tty_hangup(struct work_struct *work) struct task_struct *p; struct tty_ldisc *ld; int closecount = 0, n; + unsigned long flags; if (!tty) return; @@ -1441,8 +1447,7 @@ static void do_tty_hangup(struct work_struct *work) /* We may have no line discipline at this point */ if (ld->flush_buffer) ld->flush_buffer(tty); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + tty_driver_flush_buffer(tty); if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && ld->write_wakeup) ld->write_wakeup(tty); @@ -1480,19 +1485,24 @@ static void do_tty_hangup(struct work_struct *work) __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p); __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p); put_pid(p->signal->tty_old_pgrp); /* A noop */ + spin_lock_irqsave(&tty->ctrl_lock, flags); if (tty->pgrp) p->signal->tty_old_pgrp = get_pid(tty->pgrp); + spin_unlock_irqrestore(&tty->ctrl_lock, flags); spin_unlock_irq(&p->sighand->siglock); } while_each_pid_task(tty->session, PIDTYPE_SID, p); } read_unlock(&tasklist_lock); + spin_lock_irqsave(&tty->ctrl_lock, flags); tty->flags = 0; put_pid(tty->session); put_pid(tty->pgrp); tty->session = NULL; tty->pgrp = NULL; tty->ctrl_status = 0; + spin_unlock_irqrestore(&tty->ctrl_lock, flags); + /* * If one of the devices matches a console pointer, we * cannot just call hangup() because that will cause @@ -1500,11 +1510,11 @@ static void do_tty_hangup(struct work_struct *work) * So we just call close() the right number of times. */ if (cons_filp) { - if (tty->driver->close) + if (tty->ops->close) for (n = 0; n < closecount; n++) - tty->driver->close(tty, cons_filp); - } else if (tty->driver->hangup) - (tty->driver->hangup)(tty); + tty->ops->close(tty, cons_filp); + } else if (tty->ops->hangup) + (tty->ops->hangup)(tty); /* * We don't want to have driver/ldisc interactions beyond * the ones we did here. The driver layer expects no @@ -1626,16 +1636,17 @@ void disassociate_ctty(int on_exit) struct tty_struct *tty; struct pid *tty_pgrp = NULL; - lock_kernel(); mutex_lock(&tty_mutex); tty = get_current_tty(); if (tty) { tty_pgrp = get_pid(tty->pgrp); mutex_unlock(&tty_mutex); + lock_kernel(); /* XXX: here we race, there is nothing protecting tty */ if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) tty_vhangup(tty); + unlock_kernel(); } else if (on_exit) { struct pid *old_pgrp; spin_lock_irq(¤t->sighand->siglock); @@ -1648,7 +1659,6 @@ void disassociate_ctty(int on_exit) put_pid(old_pgrp); } mutex_unlock(&tty_mutex); - unlock_kernel(); return; } if (tty_pgrp) { @@ -1667,10 +1677,13 @@ void disassociate_ctty(int on_exit) /* It is possible that do_tty_hangup has free'd this tty */ tty = get_current_tty(); if (tty) { + unsigned long flags; + spin_lock_irqsave(&tty->ctrl_lock, flags); put_pid(tty->session); put_pid(tty->pgrp); tty->session = NULL; tty->pgrp = NULL; + spin_unlock_irqrestore(&tty->ctrl_lock, flags); } else { #ifdef TTY_DEBUG_HANGUP printk(KERN_DEBUG "error attempted to write to tty [0x%p]" @@ -1683,7 +1696,6 @@ void disassociate_ctty(int on_exit) read_lock(&tasklist_lock); session_clear_tty(task_session(current)); read_unlock(&tasklist_lock); - unlock_kernel(); } /** @@ -1693,8 +1705,10 @@ void disassociate_ctty(int on_exit) void no_tty(void) { struct task_struct *tsk = current; + lock_kernel(); if (tsk->signal->leader) disassociate_ctty(0); + unlock_kernel(); proc_clear_tty(tsk); } @@ -1714,21 +1728,26 @@ void no_tty(void) * but not always. * * Locking: - * Broken. Relies on BKL which is unsafe here. + * Uses the tty control lock internally */ void stop_tty(struct tty_struct *tty) { - if (tty->stopped) + unsigned long flags; + spin_lock_irqsave(&tty->ctrl_lock, flags); + if (tty->stopped) { + spin_unlock_irqrestore(&tty->ctrl_lock, flags); return; + } tty->stopped = 1; if (tty->link && tty->link->packet) { tty->ctrl_status &= ~TIOCPKT_START; tty->ctrl_status |= TIOCPKT_STOP; wake_up_interruptible(&tty->link->read_wait); } - if (tty->driver->stop) - (tty->driver->stop)(tty); + spin_unlock_irqrestore(&tty->ctrl_lock, flags); + if (tty->ops->stop) + (tty->ops->stop)(tty); } EXPORT_SYMBOL(stop_tty); @@ -1743,21 +1762,26 @@ EXPORT_SYMBOL(stop_tty); * driver start method is invoked and the line discipline woken. * * Locking: - * Broken. Relies on BKL which is unsafe here. + * ctrl_lock */ void start_tty(struct tty_struct *tty) { - if (!tty->stopped || tty->flow_stopped) + unsigned long flags; + spin_lock_irqsave(&tty->ctrl_lock, flags); + if (!tty->stopped || tty->flow_stopped) { + spin_unlock_irqrestore(&tty->ctrl_lock, flags); return; + } tty->stopped = 0; if (tty->link && tty->link->packet) { tty->ctrl_status &= ~TIOCPKT_STOP; tty->ctrl_status |= TIOCPKT_START; wake_up_interruptible(&tty->link->read_wait); } - if (tty->driver->start) - (tty->driver->start)(tty); + spin_unlock_irqrestore(&tty->ctrl_lock, flags); + if (tty->ops->start) + (tty->ops->start)(tty); /* If we have a running line discipline it may need kicking */ tty_wakeup(tty); } @@ -1775,10 +1799,8 @@ EXPORT_SYMBOL(start_tty); * for hung up devices before calling the line discipline method. * * Locking: - * Locks the line discipline internally while needed - * For historical reasons the line discipline read method is - * invoked under the BKL. This will go away in time so do not rely on it - * in new code. Multiple read calls may be outstanding in parallel. + * Locks the line discipline internally while needed. Multiple + * read calls may be outstanding in parallel. */ static ssize_t tty_read(struct file *file, char __user *buf, size_t count, @@ -1799,13 +1821,11 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count, /* We want to wait for the line discipline to sort out in this situation */ ld = tty_ldisc_ref_wait(tty); - lock_kernel(); if (ld->read) i = (ld->read)(tty, file, buf, count); else i = -EIO; tty_ldisc_deref(ld); - unlock_kernel(); if (i > 0) inode->i_atime = current_fs_time(inode->i_sb); return i; @@ -1893,9 +1913,7 @@ static inline ssize_t do_tty_write( ret = -EFAULT; if (copy_from_user(tty->write_buf, buf, size)) break; - lock_kernel(); ret = write(tty, file, tty->write_buf, size); - unlock_kernel(); if (ret <= 0) break; written += ret; @@ -1948,10 +1966,13 @@ static ssize_t tty_write(struct file *file, const char __user *buf, tty = (struct tty_struct *)file->private_data; if (tty_paranoia_check(tty, inode, "tty_write")) return -EIO; - if (!tty || !tty->driver->write || + if (!tty || !tty->ops->write || (test_bit(TTY_IO_ERROR, &tty->flags))) return -EIO; - + /* Short term debug to catch buggy drivers */ + if (tty->ops->write_room == NULL) + printk(KERN_ERR "tty driver %s lacks a write_room method.\n", + tty->driver->name); ld = tty_ldisc_ref_wait(tty); if (!ld->write) ret = -EIO; @@ -2098,6 +2119,7 @@ static int init_dev(struct tty_driver *driver, int idx, goto fail_no_mem; initialize_tty_struct(tty); tty->driver = driver; + tty->ops = driver->ops; tty->index = idx; tty_line_name(driver, idx, tty->name); @@ -2128,6 +2150,7 @@ static int init_dev(struct tty_driver *driver, int idx, goto free_mem_out; initialize_tty_struct(o_tty); o_tty->driver = driver->other; + o_tty->ops = driver->ops; o_tty->index = idx; tty_line_name(driver->other, idx, o_tty->name); @@ -2432,8 +2455,8 @@ static void release_dev(struct file *filp) } } #endif - if (tty->driver->close) - tty->driver->close(tty, filp); + if (tty->ops->close) + tty->ops->close(tty, filp); /* * Sanity check: if tty->count is going to zero, there shouldn't be @@ -2612,15 +2635,9 @@ static void release_dev(struct file *filp) */ release_tty(tty, idx); -#ifdef CONFIG_UNIX98_PTYS /* Make this pty number available for reallocation */ - if (devpts) { - mutex_lock(&allocated_ptys_lock); - idr_remove(&allocated_ptys, idx); - mutex_unlock(&allocated_ptys_lock); - } -#endif - + if (devpts) + devpts_kill_index(idx); } /** @@ -2716,8 +2733,8 @@ got_driver: printk(KERN_DEBUG "opening %s...", tty->name); #endif if (!retval) { - if (tty->driver->open) - retval = tty->driver->open(tty, filp); + if (tty->ops->open) + retval = tty->ops->open(tty, filp); else retval = -ENODEV; } @@ -2755,7 +2772,6 @@ got_driver: __proc_set_tty(current, tty); spin_unlock_irq(¤t->sighand->siglock); mutex_unlock(&tty_mutex); - tty_audit_opening(); return 0; } @@ -2777,29 +2793,13 @@ static int ptmx_open(struct inode *inode, struct file *filp) struct tty_struct *tty; int retval; int index; - int idr_ret; nonseekable_open(inode, filp); /* find a device that is not in use. */ - mutex_lock(&allocated_ptys_lock); - if (!idr_pre_get(&allocated_ptys, GFP_KERNEL)) { - mutex_unlock(&allocated_ptys_lock); - return -ENOMEM; - } - idr_ret = idr_get_new(&allocated_ptys, NULL, &index); - if (idr_ret < 0) { - mutex_unlock(&allocated_ptys_lock); - if (idr_ret == -EAGAIN) - return -ENOMEM; - return -EIO; - } - if (index >= pty_limit) { - idr_remove(&allocated_ptys, index); - mutex_unlock(&allocated_ptys_lock); - return -EIO; - } - mutex_unlock(&allocated_ptys_lock); + index = devpts_new_index(); + if (index < 0) + return index; mutex_lock(&tty_mutex); retval = init_dev(ptm_driver, index, &tty); @@ -2812,23 +2812,19 @@ static int ptmx_open(struct inode *inode, struct file *filp) filp->private_data = tty; file_move(filp, &tty->tty_files); - retval = -ENOMEM; - if (devpts_pty_new(tty->link)) + retval = devpts_pty_new(tty->link); + if (retval) goto out1; - check_tty_count(tty, "tty_open"); - retval = ptm_driver->open(tty, filp); - if (!retval) { - tty_audit_opening(); + check_tty_count(tty, "ptmx_open"); + retval = ptm_driver->ops->open(tty, filp); + if (!retval) return 0; - } out1: release_dev(filp); return retval; out: - mutex_lock(&allocated_ptys_lock); - idr_remove(&allocated_ptys, index); - mutex_unlock(&allocated_ptys_lock); + devpts_kill_index(index); return retval; } #endif @@ -2885,6 +2881,7 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait) static int tty_fasync(int fd, struct file *filp, int on) { struct tty_struct *tty; + unsigned long flags; int retval; tty = (struct tty_struct *)filp->private_data; @@ -2900,6 +2897,7 @@ static int tty_fasync(int fd, struct file *filp, int on) struct pid *pid; if (!waitqueue_active(&tty->read_wait)) tty->minimum_to_wake = 1; + spin_lock_irqsave(&tty->ctrl_lock, flags); if (tty->pgrp) { pid = tty->pgrp; type = PIDTYPE_PGID; @@ -2907,6 +2905,7 @@ static int tty_fasync(int fd, struct file *filp, int on) pid = task_pid(current); type = PIDTYPE_PID; } + spin_unlock_irqrestore(&tty->ctrl_lock, flags); retval = __f_setown(filp, pid, type, 0); if (retval) return retval; @@ -2992,6 +2991,8 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, struct winsize __user *arg) { struct winsize tmp_ws; + struct pid *pgrp, *rpgrp; + unsigned long flags; if (copy_from_user(&tmp_ws, arg, sizeof(*arg))) return -EFAULT; @@ -3009,10 +3010,21 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, } } #endif - if (tty->pgrp) - kill_pgrp(tty->pgrp, SIGWINCH, 1); - if ((real_tty->pgrp != tty->pgrp) && real_tty->pgrp) - kill_pgrp(real_tty->pgrp, SIGWINCH, 1); + /* Get the PID values and reference them so we can + avoid holding the tty ctrl lock while sending signals */ + spin_lock_irqsave(&tty->ctrl_lock, flags); + pgrp = get_pid(tty->pgrp); + rpgrp = get_pid(real_tty->pgrp); + spin_unlock_irqrestore(&tty->ctrl_lock, flags); + + if (pgrp) + kill_pgrp(pgrp, SIGWINCH, 1); + if (rpgrp != pgrp && rpgrp) + kill_pgrp(rpgrp, SIGWINCH, 1); + + put_pid(pgrp); + put_pid(rpgrp); + tty->winsize = tmp_ws; real_tty->winsize = tmp_ws; done: @@ -3073,10 +3085,13 @@ static int fionbio(struct file *file, int __user *p) if (get_user(nonblock, p)) return -EFAULT; + /* file->f_flags is still BKL protected in the fs layer - vomit */ + lock_kernel(); if (nonblock) file->f_flags |= O_NONBLOCK; else file->f_flags &= ~O_NONBLOCK; + unlock_kernel(); return 0; } @@ -3134,6 +3149,27 @@ unlock: } /** + * tty_get_pgrp - return a ref counted pgrp pid + * @tty: tty to read + * + * Returns a refcounted instance of the pid struct for the process + * group controlling the tty. + */ + +struct pid *tty_get_pgrp(struct tty_struct *tty) +{ + unsigned long flags; + struct pid *pgrp; + + spin_lock_irqsave(&tty->ctrl_lock, flags); + pgrp = get_pid(tty->pgrp); + spin_unlock_irqrestore(&tty->ctrl_lock, flags); + + return pgrp; +} +EXPORT_SYMBOL_GPL(tty_get_pgrp); + +/** * tiocgpgrp - get process group * @tty: tty passed by user * @real_tty: tty side of the tty pased by the user if a pty else the tty @@ -3147,13 +3183,18 @@ unlock: static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) { + struct pid *pid; + int ret; /* * (tty == real_tty) is a cheap way of * testing if the tty is NOT a master pty. */ if (tty == real_tty && current->signal->tty != real_tty) return -ENOTTY; - return put_user(pid_vnr(real_tty->pgrp), p); + pid = tty_get_pgrp(real_tty); + ret = put_user(pid_vnr(pid), p); + put_pid(pid); + return ret; } /** @@ -3165,7 +3206,7 @@ static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t * Set the process group of the tty to the session passed. Only * permitted where the tty session is our session. * - * Locking: None + * Locking: RCU, ctrl lock */ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) @@ -3173,6 +3214,7 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t struct pid *pgrp; pid_t pgrp_nr; int retval = tty_check_change(real_tty); + unsigned long flags; if (retval == -EIO) return -ENOTTY; @@ -3195,8 +3237,10 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t if (session_of_pgrp(pgrp) != task_session(current)) goto out_unlock; retval = 0; + spin_lock_irqsave(&tty->ctrl_lock, flags); put_pid(real_tty->pgrp); real_tty->pgrp = get_pid(pgrp); + spin_unlock_irqrestore(&tty->ctrl_lock, flags); out_unlock: rcu_read_unlock(); return retval; @@ -3240,10 +3284,16 @@ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t _ static int tiocsetd(struct tty_struct *tty, int __user *p) { int ldisc; + int ret; if (get_user(ldisc, p)) return -EFAULT; - return tty_set_ldisc(tty, ldisc); + + lock_kernel(); + ret = tty_set_ldisc(tty, ldisc); + unlock_kernel(); + + return ret; } /** @@ -3263,18 +3313,18 @@ static int send_break(struct tty_struct *tty, unsigned int duration) { if (tty_write_lock(tty, 0) < 0) return -EINTR; - tty->driver->break_ctl(tty, -1); + tty->ops->break_ctl(tty, -1); if (!signal_pending(current)) msleep_interruptible(duration); - tty->driver->break_ctl(tty, 0); + tty->ops->break_ctl(tty, 0); tty_write_unlock(tty); - if (signal_pending(current)) + if (!signal_pending(current)) return -EINTR; return 0; } /** - * tiocmget - get modem status + * tty_tiocmget - get modem status * @tty: tty device * @file: user file pointer * @p: pointer to result @@ -3289,8 +3339,8 @@ static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p { int retval = -EINVAL; - if (tty->driver->tiocmget) { - retval = tty->driver->tiocmget(tty, file); + if (tty->ops->tiocmget) { + retval = tty->ops->tiocmget(tty, file); if (retval >= 0) retval = put_user(retval, p); @@ -3299,7 +3349,7 @@ static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p } /** - * tiocmset - set modem status + * tty_tiocmset - set modem status * @tty: tty device * @file: user file pointer * @cmd: command - clear bits, set bits or set all @@ -3316,7 +3366,7 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int { int retval = -EINVAL; - if (tty->driver->tiocmset) { + if (tty->ops->tiocmset) { unsigned int set, clear, val; retval = get_user(val, p); @@ -3340,7 +3390,7 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP; clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP; - retval = tty->driver->tiocmset(tty, file, set, clear); + retval = tty->ops->tiocmset(tty, file, set, clear); } return retval; } @@ -3348,20 +3398,18 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int /* * Split this up, as gcc can choke on it otherwise.. */ -int tty_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) +long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct tty_struct *tty, *real_tty; void __user *p = (void __user *)arg; int retval; struct tty_ldisc *ld; + struct inode *inode = file->f_dentry->d_inode; tty = (struct tty_struct *)file->private_data; if (tty_paranoia_check(tty, inode, "tty_ioctl")) return -EINVAL; - /* CHECKME: is this safe as one end closes ? */ - real_tty = tty; if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER) @@ -3370,21 +3418,28 @@ int tty_ioctl(struct inode *inode, struct file *file, /* * Break handling by driver */ - if (!tty->driver->break_ctl) { + + retval = -EINVAL; + + if (!tty->ops->break_ctl) { switch (cmd) { case TIOCSBRK: case TIOCCBRK: - if (tty->driver->ioctl) - return tty->driver->ioctl(tty, file, cmd, arg); - return -EINVAL; + if (tty->ops->ioctl) + retval = tty->ops->ioctl(tty, file, cmd, arg); + if (retval != -EINVAL && retval != -ENOIOCTLCMD) + printk(KERN_WARNING "tty: driver %s needs updating to use break_ctl\n", tty->driver->name); + return retval; /* These two ioctl's always return success; even if */ /* the driver doesn't support them. */ case TCSBRK: case TCSBRKP: - if (!tty->driver->ioctl) + if (!tty->ops->ioctl) return 0; - retval = tty->driver->ioctl(tty, file, cmd, arg); + retval = tty->ops->ioctl(tty, file, cmd, arg); + if (retval != -EINVAL && retval != -ENOIOCTLCMD) + printk(KERN_WARNING "tty: driver %s needs updating to use break_ctl\n", tty->driver->name); if (retval == -ENOIOCTLCMD) retval = 0; return retval; @@ -3442,7 +3497,6 @@ int tty_ioctl(struct inode *inode, struct file *file, case TIOCGSID: return tiocgsid(tty, real_tty, p); case TIOCGETD: - /* FIXME: check this is ok */ return put_user(tty->ldisc.num, (int __user *)p); case TIOCSETD: return tiocsetd(tty, p); @@ -3454,11 +3508,13 @@ int tty_ioctl(struct inode *inode, struct file *file, * Break handling */ case TIOCSBRK: /* Turn break on, unconditionally */ - tty->driver->break_ctl(tty, -1); + if (tty->ops->break_ctl) + tty->ops->break_ctl(tty, -1); return 0; case TIOCCBRK: /* Turn break off, unconditionally */ - tty->driver->break_ctl(tty, 0); + if (tty->ops->break_ctl) + tty->ops->break_ctl(tty, 0); return 0; case TCSBRK: /* SVID version: non-zero arg --> no break */ /* non-zero arg means wait for all output data @@ -3487,8 +3543,8 @@ int tty_ioctl(struct inode *inode, struct file *file, } break; } - if (tty->driver->ioctl) { - retval = (tty->driver->ioctl)(tty, file, cmd, arg); + if (tty->ops->ioctl) { + retval = (tty->ops->ioctl)(tty, file, cmd, arg); if (retval != -ENOIOCTLCMD) return retval; } @@ -3515,8 +3571,8 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd, if (tty_paranoia_check(tty, inode, "tty_ioctl")) return -EINVAL; - if (tty->driver->compat_ioctl) { - retval = (tty->driver->compat_ioctl)(tty, file, cmd, arg); + if (tty->ops->compat_ioctl) { + retval = (tty->ops->compat_ioctl)(tty, file, cmd, arg); if (retval != -ENOIOCTLCMD) return retval; } @@ -3566,8 +3622,7 @@ void __do_SAK(struct tty_struct *tty) tty_ldisc_flush(tty); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + tty_driver_flush_buffer(tty); read_lock(&tasklist_lock); /* Kill the entire session */ @@ -3773,19 +3828,32 @@ static void initialize_tty_struct(struct tty_struct *tty) mutex_init(&tty->atomic_read_lock); mutex_init(&tty->atomic_write_lock); spin_lock_init(&tty->read_lock); + spin_lock_init(&tty->ctrl_lock); INIT_LIST_HEAD(&tty->tty_files); INIT_WORK(&tty->SAK_work, do_SAK_work); } -/* - * The default put_char routine if the driver did not define one. +/** + * tty_put_char - write one character to a tty + * @tty: tty + * @ch: character + * + * Write one byte to the tty using the provided put_char method + * if present. Returns the number of characters successfully output. + * + * Note: the specific put_char operation in the driver layer may go + * away soon. Don't call it directly, use this method */ -static void tty_default_put_char(struct tty_struct *tty, unsigned char ch) +int tty_put_char(struct tty_struct *tty, unsigned char ch) { - tty->driver->write(tty, &ch, 1); + if (tty->ops->put_char) + return tty->ops->put_char(tty, ch); + return tty->ops->write(tty, &ch, 1); } +EXPORT_SYMBOL_GPL(tty_put_char); + static struct class *tty_class; /** @@ -3868,37 +3936,8 @@ void put_tty_driver(struct tty_driver *driver) void tty_set_operations(struct tty_driver *driver, const struct tty_operations *op) { - driver->open = op->open; - driver->close = op->close; - driver->write = op->write; - driver->put_char = op->put_char; - driver->flush_chars = op->flush_chars; - driver->write_room = op->write_room; - driver->chars_in_buffer = op->chars_in_buffer; - driver->ioctl = op->ioctl; - driver->compat_ioctl = op->compat_ioctl; - driver->set_termios = op->set_termios; - driver->throttle = op->throttle; - driver->unthrottle = op->unthrottle; - driver->stop = op->stop; - driver->start = op->start; - driver->hangup = op->hangup; - driver->break_ctl = op->break_ctl; - driver->flush_buffer = op->flush_buffer; - driver->set_ldisc = op->set_ldisc; - driver->wait_until_sent = op->wait_until_sent; - driver->send_xchar = op->send_xchar; - driver->read_proc = op->read_proc; - driver->write_proc = op->write_proc; - driver->tiocmget = op->tiocmget; - driver->tiocmset = op->tiocmset; -#ifdef CONFIG_CONSOLE_POLL - driver->poll_init = op->poll_init; - driver->poll_get_char = op->poll_get_char; - driver->poll_put_char = op->poll_put_char; -#endif -} - + driver->ops = op; +}; EXPORT_SYMBOL(alloc_tty_driver); EXPORT_SYMBOL(put_tty_driver); @@ -3961,9 +4000,6 @@ int tty_register_driver(struct tty_driver *driver) return error; } - if (!driver->put_char) - driver->put_char = tty_default_put_char; - mutex_lock(&tty_mutex); list_add(&driver->tty_drivers, &tty_drivers); mutex_unlock(&tty_mutex); @@ -4039,14 +4075,19 @@ void proc_clear_tty(struct task_struct *p) } EXPORT_SYMBOL(proc_clear_tty); +/* Called under the sighand lock */ + static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) { if (tty) { - /* We should not have a session or pgrp to here but.... */ + unsigned long flags; + /* We should not have a session or pgrp to put here but.... */ + spin_lock_irqsave(&tty->ctrl_lock, flags); put_pid(tty->session); put_pid(tty->pgrp); - tty->session = get_pid(task_session(tsk)); tty->pgrp = get_pid(task_pgrp(tsk)); + spin_unlock_irqrestore(&tty->ctrl_lock, flags); + tty->session = get_pid(task_session(tsk)); } put_pid(tsk->signal->tty_old_pgrp); tsk->signal->tty = tty; diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index f95a80b2265f..b1a757a5ee27 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -21,6 +21,7 @@ #include <linux/module.h> #include <linux/bitops.h> #include <linux/mutex.h> +#include <linux/smp_lock.h> #include <asm/io.h> #include <asm/uaccess.h> @@ -39,6 +40,50 @@ #define TERMIOS_OLD 8 +int tty_chars_in_buffer(struct tty_struct *tty) +{ + if (tty->ops->chars_in_buffer) + return tty->ops->chars_in_buffer(tty); + else + return 0; +} + +EXPORT_SYMBOL(tty_chars_in_buffer); + +int tty_write_room(struct tty_struct *tty) +{ + if (tty->ops->write_room) + return tty->ops->write_room(tty); + return 2048; +} + +EXPORT_SYMBOL(tty_write_room); + +void tty_driver_flush_buffer(struct tty_struct *tty) +{ + if (tty->ops->flush_buffer) + tty->ops->flush_buffer(tty); +} + +EXPORT_SYMBOL(tty_driver_flush_buffer); + +void tty_throttle(struct tty_struct *tty) +{ + /* check TTY_THROTTLED first so it indicates our state */ + if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) && + tty->ops->throttle) + tty->ops->throttle(tty); +} +EXPORT_SYMBOL(tty_throttle); + +void tty_unthrottle(struct tty_struct *tty) +{ + if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) && + tty->ops->unthrottle) + tty->ops->unthrottle(tty); +} +EXPORT_SYMBOL(tty_unthrottle); + /** * tty_wait_until_sent - wait for I/O to finish * @tty: tty we are waiting for @@ -57,15 +102,13 @@ void tty_wait_until_sent(struct tty_struct *tty, long timeout) printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf)); #endif - if (!tty->driver->chars_in_buffer) - return; if (!timeout) timeout = MAX_SCHEDULE_TIMEOUT; if (wait_event_interruptible_timeout(tty->write_wait, - !tty->driver->chars_in_buffer(tty), timeout) < 0) - return; - if (tty->driver->wait_until_sent) - tty->driver->wait_until_sent(tty, timeout); + !tty_chars_in_buffer(tty), timeout) >= 0) { + if (tty->ops->wait_until_sent) + tty->ops->wait_until_sent(tty, timeout); + } } EXPORT_SYMBOL(tty_wait_until_sent); @@ -393,8 +436,9 @@ EXPORT_SYMBOL(tty_termios_hw_change); static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) { int canon_change; - struct ktermios old_termios = *tty->termios; + struct ktermios old_termios; struct tty_ldisc *ld; + unsigned long flags; /* * Perform the actual termios internal changes under lock. @@ -404,7 +448,7 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) /* FIXME: we need to decide on some locking/ordering semantics for the set_termios notification eventually */ mutex_lock(&tty->termios_mutex); - + old_termios = *tty->termios; *tty->termios = *new_termios; unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON; @@ -429,17 +473,19 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) STOP_CHAR(tty) == '\023' && START_CHAR(tty) == '\021'); if (old_flow != new_flow) { + spin_lock_irqsave(&tty->ctrl_lock, flags); tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP); if (new_flow) tty->ctrl_status |= TIOCPKT_DOSTOP; else tty->ctrl_status |= TIOCPKT_NOSTOP; + spin_unlock_irqrestore(&tty->ctrl_lock, flags); wake_up_interruptible(&tty->link->read_wait); } } - if (tty->driver->set_termios) - (*tty->driver->set_termios)(tty, &old_termios); + if (tty->ops->set_termios) + (*tty->ops->set_termios)(tty, &old_termios); else tty_termios_copy_hw(tty->termios, &old_termios); @@ -474,7 +520,9 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt) if (retval) return retval; + mutex_lock(&tty->termios_mutex); memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios)); + mutex_unlock(&tty->termios_mutex); if (opt & TERMIOS_TERMIO) { if (user_termio_to_kernel_termios(&tmp_termios, @@ -660,12 +708,14 @@ static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars) { struct tchars tmp; + mutex_lock(&tty->termios_mutex); tmp.t_intrc = tty->termios->c_cc[VINTR]; tmp.t_quitc = tty->termios->c_cc[VQUIT]; tmp.t_startc = tty->termios->c_cc[VSTART]; tmp.t_stopc = tty->termios->c_cc[VSTOP]; tmp.t_eofc = tty->termios->c_cc[VEOF]; tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */ + mutex_unlock(&tty->termios_mutex); return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0; } @@ -675,12 +725,14 @@ static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars) if (copy_from_user(&tmp, tchars, sizeof(tmp))) return -EFAULT; + mutex_lock(&tty->termios_mutex); tty->termios->c_cc[VINTR] = tmp.t_intrc; tty->termios->c_cc[VQUIT] = tmp.t_quitc; tty->termios->c_cc[VSTART] = tmp.t_startc; tty->termios->c_cc[VSTOP] = tmp.t_stopc; tty->termios->c_cc[VEOF] = tmp.t_eofc; tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */ + mutex_unlock(&tty->termios_mutex); return 0; } #endif @@ -690,6 +742,7 @@ static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars) { struct ltchars tmp; + mutex_lock(&tty->termios_mutex); tmp.t_suspc = tty->termios->c_cc[VSUSP]; /* what is dsuspc anyway? */ tmp.t_dsuspc = tty->termios->c_cc[VSUSP]; @@ -698,6 +751,7 @@ static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars) tmp.t_flushc = tty->termios->c_cc[VEOL2]; tmp.t_werasc = tty->termios->c_cc[VWERASE]; tmp.t_lnextc = tty->termios->c_cc[VLNEXT]; + mutex_unlock(&tty->termios_mutex); return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0; } @@ -708,6 +762,7 @@ static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars) if (copy_from_user(&tmp, ltchars, sizeof(tmp))) return -EFAULT; + mutex_lock(&tty->termios_mutex); tty->termios->c_cc[VSUSP] = tmp.t_suspc; /* what is dsuspc anyway? */ tty->termios->c_cc[VEOL2] = tmp.t_dsuspc; @@ -716,6 +771,7 @@ static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars) tty->termios->c_cc[VEOL2] = tmp.t_flushc; tty->termios->c_cc[VWERASE] = tmp.t_werasc; tty->termios->c_cc[VLNEXT] = tmp.t_lnextc; + mutex_unlock(&tty->termios_mutex); return 0; } #endif @@ -732,8 +788,8 @@ static int send_prio_char(struct tty_struct *tty, char ch) { int was_stopped = tty->stopped; - if (tty->driver->send_xchar) { - tty->driver->send_xchar(tty, ch); + if (tty->ops->send_xchar) { + tty->ops->send_xchar(tty, ch); return 0; } @@ -742,7 +798,7 @@ static int send_prio_char(struct tty_struct *tty, char ch) if (was_stopped) start_tty(tty); - tty->driver->write(tty, &ch, 1); + tty->ops->write(tty, &ch, 1); if (was_stopped) stop_tty(tty); tty_write_unlock(tty); @@ -750,6 +806,33 @@ static int send_prio_char(struct tty_struct *tty, char ch) } /** + * tty_change_softcar - carrier change ioctl helper + * @tty: tty to update + * @arg: enable/disable CLOCAL + * + * Perform a change to the CLOCAL state and call into the driver + * layer to make it visible. All done with the termios mutex + */ + +static int tty_change_softcar(struct tty_struct *tty, int arg) +{ + int ret = 0; + int bit = arg ? CLOCAL : 0; + struct ktermios old; + + mutex_lock(&tty->termios_mutex); + old = *tty->termios; + tty->termios->c_cflag &= ~CLOCAL; + tty->termios->c_cflag |= bit; + if (tty->ops->set_termios) + tty->ops->set_termios(tty, &old); + if ((tty->termios->c_cflag & CLOCAL) != bit) + ret = -EINVAL; + mutex_unlock(&tty->termios_mutex); + return ret; +} + +/** * tty_mode_ioctl - mode related ioctls * @tty: tty for the ioctl * @file: file pointer for the tty @@ -859,12 +942,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, case TIOCSSOFTCAR: if (get_user(arg, (unsigned int __user *) arg)) return -EFAULT; - mutex_lock(&tty->termios_mutex); - tty->termios->c_cflag = - ((tty->termios->c_cflag & ~CLOCAL) | - (arg ? CLOCAL : 0)); - mutex_unlock(&tty->termios_mutex); - return 0; + return tty_change_softcar(tty, arg); default: return -ENOIOCTLCMD; } @@ -889,8 +967,7 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg) ld->flush_buffer(tty); /* fall through */ case TCOFLUSH: - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + tty_driver_flush_buffer(tty); break; default: tty_ldisc_deref(ld); @@ -905,6 +982,7 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { struct tty_struct *real_tty; + unsigned long flags; int retval; if (tty->driver->type == TTY_DRIVER_TYPE_PTY && @@ -946,9 +1024,7 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file, case TCFLSH: return tty_perform_flush(tty, arg); case TIOCOUTQ: - return put_user(tty->driver->chars_in_buffer ? - tty->driver->chars_in_buffer(tty) : 0, - (int __user *) arg); + return put_user(tty_chars_in_buffer(tty), (int __user *) arg); case TIOCINQ: retval = tty->read_cnt; if (L_ICANON(tty)) @@ -963,6 +1039,7 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file, return -ENOTTY; if (get_user(pktmode, (int __user *) arg)) return -EFAULT; + spin_lock_irqsave(&tty->ctrl_lock, flags); if (pktmode) { if (!tty->packet) { tty->packet = 1; @@ -970,6 +1047,7 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file, } } else tty->packet = 0; + spin_unlock_irqrestore(&tty->ctrl_lock, flags); return 0; } default: diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c index 8de6b95aeb84..3d3e1c2b310f 100644 --- a/drivers/char/viocons.c +++ b/drivers/char/viocons.c @@ -628,13 +628,13 @@ static int viotty_write(struct tty_struct *tty, const unsigned char *buf, /* * TTY put_char method */ -static void viotty_put_char(struct tty_struct *tty, unsigned char ch) +static int viotty_put_char(struct tty_struct *tty, unsigned char ch) { struct port_info *pi; pi = get_port_data(tty); if (pi == NULL) - return; + return 0; /* This will append '\r' as well if the char is '\n' */ if (viochar_is_console(pi)) @@ -642,6 +642,7 @@ static void viotty_put_char(struct tty_struct *tty, unsigned char ch) if (viopath_isactive(pi->lp)) internal_write(pi, &ch, 1); + return 1; } /* @@ -704,8 +705,11 @@ static int viotty_ioctl(struct tty_struct *tty, struct file *file, case KDSKBLED: return 0; } - - return n_tty_ioctl(tty, file, cmd, arg); + /* FIXME: WTF is this being called for ??? */ + lock_kernel(); + ret = n_tty_ioctl(tty, file, cmd, arg); + unlock_kernel(); + return ret; } /* diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index db7a731e2362..58aad63831f4 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -249,6 +249,7 @@ static int proc_viotape_open(struct inode *inode, struct file *file) } static const struct file_operations proc_viotape_operations = { + .owner = THIS_MODULE, .open = proc_viotape_open, .read = seq_read, .llseek = seq_lseek, @@ -915,7 +916,6 @@ static struct vio_driver viotape_driver = { int __init viotap_init(void) { int ret; - struct proc_dir_entry *e; if (!firmware_has_feature(FW_FEATURE_ISERIES)) return -ENODEV; @@ -968,11 +968,8 @@ int __init viotap_init(void) if (ret) goto unreg_class; - e = create_proc_entry("iSeries/viotape", S_IFREG|S_IRUGO, NULL); - if (e) { - e->owner = THIS_MODULE; - e->proc_fops = &proc_viotape_operations; - } + proc_create("iSeries/viotape", S_IFREG|S_IRUGO, NULL, + &proc_viotape_operations); return 0; diff --git a/drivers/char/vt.c b/drivers/char/vt.c index df4c3ead9e2b..e458b08139af 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -301,7 +301,7 @@ static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr) d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr)); scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row); - scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char, + scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_scrl_erase_char, vc->vc_size_row * nr); } @@ -319,7 +319,7 @@ static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr) s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t); step = vc->vc_cols * nr; scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row); - scr_memsetw(s, vc->vc_video_erase_char, 2 * step); + scr_memsetw(s, vc->vc_scrl_erase_char, 2 * step); } static void do_update_region(struct vc_data *vc, unsigned long start, int count) @@ -400,7 +400,7 @@ static u8 build_attr(struct vc_data *vc, u8 _color, u8 _intensity, u8 _blink, * Bit 7 : blink */ { - u8 a = vc->vc_color; + u8 a = _color; if (!vc->vc_can_do_color) return _intensity | (_italic ? 2 : 0) | @@ -434,6 +434,7 @@ static void update_attr(struct vc_data *vc) vc->vc_blink, vc->vc_underline, vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic); vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' '; + vc->vc_scrl_erase_char = (build_attr(vc, vc->vc_def_color, 1, false, false, false, false) << 8) | ' '; } /* Note: inverting the screen twice should revert to the original state */ @@ -908,15 +909,21 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) if (vc->vc_tty) { struct winsize ws, *cws = &vc->vc_tty->winsize; + unsigned long flags; memset(&ws, 0, sizeof(ws)); ws.ws_row = vc->vc_rows; ws.ws_col = vc->vc_cols; ws.ws_ypixel = vc->vc_scan_lines; + + mutex_lock(&vc->vc_tty->termios_mutex); + spin_lock_irqsave(&vc->vc_tty->ctrl_lock, flags); if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) && vc->vc_tty->pgrp) kill_pgrp(vc->vc_tty->pgrp, SIGWINCH, 1); + spin_unlock_irqrestore(&vc->vc_tty->ctrl_lock, flags); *cws = ws; + mutex_unlock(&vc->vc_tty->termios_mutex); } if (CON_IS_VISIBLE(vc)) @@ -2540,6 +2547,9 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) if (get_user(type, p)) return -EFAULT; ret = 0; + + lock_kernel(); + switch (type) { case TIOCL_SETSEL: @@ -2559,7 +2569,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) ret = sel_loadlut(p); break; case TIOCL_GETSHIFTSTATE: - + /* * Make it possible to react to Shift+Mousebutton. * Note that 'shift_state' is an undocumented @@ -2614,6 +2624,7 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) ret = -EINVAL; break; } + unlock_kernel(); return ret; } @@ -2631,11 +2642,11 @@ static int con_write(struct tty_struct *tty, const unsigned char *buf, int count return retval; } -static void con_put_char(struct tty_struct *tty, unsigned char ch) +static int con_put_char(struct tty_struct *tty, unsigned char ch) { if (in_interrupt()) - return; /* n_r3964 calls put_char() from interrupt context */ - do_con_write(tty, &ch, 1); + return 0; /* n_r3964 calls put_char() from interrupt context */ + return do_con_write(tty, &ch, 1); } static int con_write_room(struct tty_struct *tty) @@ -3828,7 +3839,7 @@ static int con_font_get(struct vc_data *vc, struct console_font_op *op) goto out; c = (font.width+7)/8 * 32 * font.charcount; - + if (op->data && font.charcount > op->charcount) rc = -ENOSPC; if (!(op->flags & KD_FONT_FLAG_OLD)) { @@ -3993,6 +4004,7 @@ u16 screen_glyph(struct vc_data *vc, int offset) c |= 0x100; return c; } +EXPORT_SYMBOL_GPL(screen_glyph); /* used by vcs - note the word offset */ unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed) diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index e6f89e8b9258..3211afd9d57e 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -373,11 +373,17 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, unsigned char ucval; void __user *up = (void __user *)arg; int i, perm; - + int ret = 0; + console = vc->vc_num; - if (!vc_cons_allocated(console)) /* impossible? */ - return -ENOIOCTLCMD; + lock_kernel(); + + if (!vc_cons_allocated(console)) { /* impossible? */ + ret = -ENOIOCTLCMD; + goto out; + } + /* * To have permissions to do most of the vt ioctls, we either have @@ -391,15 +397,15 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, switch (cmd) { case KIOCSOUND: if (!perm) - return -EPERM; + goto eperm; if (arg) arg = CLOCK_TICK_RATE / arg; kd_mksound(arg, 0); - return 0; + break; case KDMKTONE: if (!perm) - return -EPERM; + goto eperm; { unsigned int ticks, count; @@ -412,7 +418,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, if (count) count = CLOCK_TICK_RATE / count; kd_mksound(count, ticks); - return 0; + break; } case KDGKBTYPE: @@ -435,14 +441,18 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, * KDADDIO and KDDELIO may be able to add ports beyond what * we reject here, but to be safe... */ - if (arg < GPFIRST || arg > GPLAST) - return -EINVAL; - return sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0; + if (arg < GPFIRST || arg > GPLAST) { + ret = -EINVAL; + break; + } + ret = sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0; + break; case KDENABIO: case KDDISABIO: - return sys_ioperm(GPFIRST, GPNUM, + ret = sys_ioperm(GPFIRST, GPNUM, (cmd == KDENABIO)) ? -ENXIO : 0; + break; #endif /* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */ @@ -450,19 +460,20 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, case KDKBDREP: { struct kbd_repeat kbrep; - int err; if (!capable(CAP_SYS_TTY_CONFIG)) - return -EPERM; + goto eperm; - if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) - return -EFAULT; - err = kbd_rate(&kbrep); - if (err) - return err; + if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) { + ret = -EFAULT; + break; + } + ret = kbd_rate(&kbrep); + if (ret) + break; if (copy_to_user(up, &kbrep, sizeof(struct kbd_repeat))) - return -EFAULT; - return 0; + ret = -EFAULT; + break; } case KDSETMODE: @@ -475,7 +486,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, * need to restore their engine state. --BenH */ if (!perm) - return -EPERM; + goto eperm; switch (arg) { case KD_GRAPHICS: break; @@ -485,13 +496,14 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, case KD_TEXT: break; default: - return -EINVAL; + ret = -EINVAL; + goto out; } if (vc->vc_mode == (unsigned char) arg) - return 0; + break; vc->vc_mode = (unsigned char) arg; if (console != fg_console) - return 0; + break; /* * explicitly blank/unblank the screen if switching modes */ @@ -501,7 +513,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, else do_blank_screen(1); release_console_sem(); - return 0; + break; case KDGETMODE: ucval = vc->vc_mode; @@ -513,11 +525,12 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, * these work like a combination of mmap and KDENABIO. * this could be easily finished. */ - return -EINVAL; + ret = -EINVAL; + break; case KDSKBMODE: if (!perm) - return -EPERM; + goto eperm; switch(arg) { case K_RAW: kbd->kbdmode = VC_RAW; @@ -534,10 +547,11 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, compute_shiftstate(); break; default: - return -EINVAL; + ret = -EINVAL; + goto out; } tty_ldisc_flush(tty); - return 0; + break; case KDGKBMODE: ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW : @@ -557,28 +571,32 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, set_vc_kbd_mode(kbd, VC_META); break; default: - return -EINVAL; + ret = -EINVAL; } - return 0; + break; case KDGKBMETA: ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT); setint: - return put_user(ucval, (int __user *)arg); + ret = put_user(ucval, (int __user *)arg); + break; case KDGETKEYCODE: case KDSETKEYCODE: if(!capable(CAP_SYS_TTY_CONFIG)) - perm=0; - return do_kbkeycode_ioctl(cmd, up, perm); + perm = 0; + ret = do_kbkeycode_ioctl(cmd, up, perm); + break; case KDGKBENT: case KDSKBENT: - return do_kdsk_ioctl(cmd, up, perm, kbd); + ret = do_kdsk_ioctl(cmd, up, perm, kbd); + break; case KDGKBSENT: case KDSKBSENT: - return do_kdgkb_ioctl(cmd, up, perm); + ret = do_kdgkb_ioctl(cmd, up, perm); + break; case KDGKBDIACR: { @@ -586,26 +604,31 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, struct kbdiacr diacr; int i; - if (put_user(accent_table_size, &a->kb_cnt)) - return -EFAULT; + if (put_user(accent_table_size, &a->kb_cnt)) { + ret = -EFAULT; + break; + } for (i = 0; i < accent_table_size; i++) { diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr); diacr.base = conv_uni_to_8bit(accent_table[i].base); diacr.result = conv_uni_to_8bit(accent_table[i].result); - if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) - return -EFAULT; + if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) { + ret = -EFAULT; + break; + } } - return 0; + break; } case KDGKBDIACRUC: { struct kbdiacrsuc __user *a = up; if (put_user(accent_table_size, &a->kb_cnt)) - return -EFAULT; - if (copy_to_user(a->kbdiacruc, accent_table, accent_table_size*sizeof(struct kbdiacruc))) - return -EFAULT; - return 0; + ret = -EFAULT; + else if (copy_to_user(a->kbdiacruc, accent_table, + accent_table_size*sizeof(struct kbdiacruc))) + ret = -EFAULT; + break; } case KDSKBDIACR: @@ -616,20 +639,26 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, int i; if (!perm) - return -EPERM; - if (get_user(ct,&a->kb_cnt)) - return -EFAULT; - if (ct >= MAX_DIACR) - return -EINVAL; + goto eperm; + if (get_user(ct,&a->kb_cnt)) { + ret = -EFAULT; + break; + } + if (ct >= MAX_DIACR) { + ret = -EINVAL; + break; + } accent_table_size = ct; for (i = 0; i < ct; i++) { - if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) - return -EFAULT; + if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) { + ret = -EFAULT; + break; + } accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr); accent_table[i].base = conv_8bit_to_uni(diacr.base); accent_table[i].result = conv_8bit_to_uni(diacr.result); } - return 0; + break; } case KDSKBDIACRUC: @@ -638,15 +667,19 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, unsigned int ct; if (!perm) - return -EPERM; - if (get_user(ct,&a->kb_cnt)) - return -EFAULT; - if (ct >= MAX_DIACR) - return -EINVAL; + goto eperm; + if (get_user(ct,&a->kb_cnt)) { + ret = -EFAULT; + break; + } + if (ct >= MAX_DIACR) { + ret = -EINVAL; + break; + } accent_table_size = ct; if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc))) - return -EFAULT; - return 0; + ret = -EFAULT; + break; } /* the ioctls below read/set the flags usually shown in the leds */ @@ -657,26 +690,29 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, case KDSKBLED: if (!perm) - return -EPERM; - if (arg & ~0x77) - return -EINVAL; + goto eperm; + if (arg & ~0x77) { + ret = -EINVAL; + break; + } kbd->ledflagstate = (arg & 7); kbd->default_ledflagstate = ((arg >> 4) & 7); set_leds(); - return 0; + break; /* the ioctls below only set the lights, not the functions */ /* for those, see KDGKBLED and KDSKBLED above */ case KDGETLED: ucval = getledstate(); setchar: - return put_user(ucval, (char __user *)arg); + ret = put_user(ucval, (char __user *)arg); + break; case KDSETLED: if (!perm) - return -EPERM; + goto eperm; setledstate(kbd, arg); - return 0; + break; /* * A process can indicate its willingness to accept signals @@ -688,16 +724,17 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, case KDSIGACCEPT: { if (!perm || !capable(CAP_KILL)) - return -EPERM; + goto eperm; if (!valid_signal(arg) || arg < 1 || arg == SIGKILL) - return -EINVAL; - - spin_lock_irq(&vt_spawn_con.lock); - put_pid(vt_spawn_con.pid); - vt_spawn_con.pid = get_pid(task_pid(current)); - vt_spawn_con.sig = arg; - spin_unlock_irq(&vt_spawn_con.lock); - return 0; + ret = -EINVAL; + else { + spin_lock_irq(&vt_spawn_con.lock); + put_pid(vt_spawn_con.pid); + vt_spawn_con.pid = get_pid(task_pid(current)); + vt_spawn_con.sig = arg; + spin_unlock_irq(&vt_spawn_con.lock); + } + break; } case VT_SETMODE: @@ -705,11 +742,15 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, struct vt_mode tmp; if (!perm) - return -EPERM; - if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) - return -EFAULT; - if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) - return -EINVAL; + goto eperm; + if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) { + ret = -EFAULT; + goto out; + } + if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) { + ret = -EINVAL; + goto out; + } acquire_console_sem(); vc->vt_mode = tmp; /* the frsig is ignored, so we set it to 0 */ @@ -719,7 +760,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, /* no switch is required -- saw@shade.msu.ru */ vc->vt_newvt = -1; release_console_sem(); - return 0; + break; } case VT_GETMODE: @@ -732,7 +773,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, release_console_sem(); rc = copy_to_user(up, &tmp, sizeof(struct vt_mode)); - return rc ? -EFAULT : 0; + if (rc) + ret = -EFAULT; + break; } /* @@ -746,12 +789,16 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, unsigned short state, mask; if (put_user(fg_console + 1, &vtstat->v_active)) - return -EFAULT; - state = 1; /* /dev/tty0 is always open */ - for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1) - if (VT_IS_IN_USE(i)) - state |= mask; - return put_user(state, &vtstat->v_state); + ret = -EFAULT; + else { + state = 1; /* /dev/tty0 is always open */ + for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; + ++i, mask <<= 1) + if (VT_IS_IN_USE(i)) + state |= mask; + ret = put_user(state, &vtstat->v_state); + } + break; } /* @@ -771,27 +818,31 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, */ case VT_ACTIVATE: if (!perm) - return -EPERM; + goto eperm; if (arg == 0 || arg > MAX_NR_CONSOLES) - return -ENXIO; - arg--; - acquire_console_sem(); - i = vc_allocate(arg); - release_console_sem(); - if (i) - return i; - set_console(arg); - return 0; + ret = -ENXIO; + else { + arg--; + acquire_console_sem(); + ret = vc_allocate(arg); + release_console_sem(); + if (ret) + break; + set_console(arg); + } + break; /* * wait until the specified VT has been activated */ case VT_WAITACTIVE: if (!perm) - return -EPERM; + goto eperm; if (arg == 0 || arg > MAX_NR_CONSOLES) - return -ENXIO; - return vt_waitactive(arg-1); + ret = -ENXIO; + else + ret = vt_waitactive(arg - 1); + break; /* * If a vt is under process control, the kernel will not switch to it @@ -805,10 +856,12 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, */ case VT_RELDISP: if (!perm) - return -EPERM; - if (vc->vt_mode.mode != VT_PROCESS) - return -EINVAL; + goto eperm; + if (vc->vt_mode.mode != VT_PROCESS) { + ret = -EINVAL; + break; + } /* * Switching-from response */ @@ -829,10 +882,10 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, int newvt; newvt = vc->vt_newvt; vc->vt_newvt = -1; - i = vc_allocate(newvt); - if (i) { + ret = vc_allocate(newvt); + if (ret) { release_console_sem(); - return i; + break; } /* * When we actually do the console switch, @@ -841,31 +894,27 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, */ complete_change_console(vc_cons[newvt].d); } - } - - /* - * Switched-to response - */ - else - { + } else { + /* + * Switched-to response + */ /* * If it's just an ACK, ignore it */ - if (arg != VT_ACKACQ) { - release_console_sem(); - return -EINVAL; - } + if (arg != VT_ACKACQ) + ret = -EINVAL; } release_console_sem(); - - return 0; + break; /* * Disallocate memory associated to VT (but leave VT1) */ case VT_DISALLOCATE: - if (arg > MAX_NR_CONSOLES) - return -ENXIO; + if (arg > MAX_NR_CONSOLES) { + ret = -ENXIO; + break; + } if (arg == 0) { /* deallocate all unused consoles, but leave 0 */ acquire_console_sem(); @@ -877,14 +926,14 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, /* deallocate a single console, if possible */ arg--; if (VT_BUSY(arg)) - return -EBUSY; - if (arg) { /* leave 0 */ + ret = -EBUSY; + else if (arg) { /* leave 0 */ acquire_console_sem(); vc_deallocate(arg); release_console_sem(); } } - return 0; + break; case VT_RESIZE: { @@ -893,21 +942,21 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, ushort ll,cc; if (!perm) - return -EPERM; + goto eperm; if (get_user(ll, &vtsizes->v_rows) || get_user(cc, &vtsizes->v_cols)) - return -EFAULT; - - for (i = 0; i < MAX_NR_CONSOLES; i++) { - vc = vc_cons[i].d; + ret = -EFAULT; + else { + for (i = 0; i < MAX_NR_CONSOLES; i++) { + vc = vc_cons[i].d; - if (vc) { - vc->vc_resize_user = 1; - vc_lock_resize(vc_cons[i].d, cc, ll); + if (vc) { + vc->vc_resize_user = 1; + vc_lock_resize(vc_cons[i].d, cc, ll); + } } } - - return 0; + break; } case VT_RESIZEX: @@ -915,10 +964,13 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, struct vt_consize __user *vtconsize = up; ushort ll,cc,vlin,clin,vcol,ccol; if (!perm) - return -EPERM; + goto eperm; if (!access_ok(VERIFY_READ, vtconsize, - sizeof(struct vt_consize))) - return -EFAULT; + sizeof(struct vt_consize))) { + ret = -EFAULT; + break; + } + /* FIXME: Should check the copies properly */ __get_user(ll, &vtconsize->v_rows); __get_user(cc, &vtconsize->v_cols); __get_user(vlin, &vtconsize->v_vlin); @@ -928,21 +980,28 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, vlin = vlin ? vlin : vc->vc_scan_lines; if (clin) { if (ll) { - if (ll != vlin/clin) - return -EINVAL; /* Parameters don't add up */ + if (ll != vlin/clin) { + /* Parameters don't add up */ + ret = -EINVAL; + break; + } } else ll = vlin/clin; } if (vcol && ccol) { if (cc) { - if (cc != vcol/ccol) - return -EINVAL; + if (cc != vcol/ccol) { + ret = -EINVAL; + break; + } } else cc = vcol/ccol; } - if (clin > 32) - return -EINVAL; + if (clin > 32) { + ret = -EINVAL; + break; + } for (i = 0; i < MAX_NR_CONSOLES; i++) { if (!vc_cons[i].d) @@ -956,19 +1015,20 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, vc_resize(vc_cons[i].d, cc, ll); release_console_sem(); } - return 0; + break; } case PIO_FONT: { if (!perm) - return -EPERM; + goto eperm; op.op = KD_FONT_OP_SET; op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */ op.width = 8; op.height = 0; op.charcount = 256; op.data = up; - return con_font_op(vc_cons[fg_console].d, &op); + ret = con_font_op(vc_cons[fg_console].d, &op); + break; } case GIO_FONT: { @@ -978,100 +1038,124 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, op.height = 32; op.charcount = 256; op.data = up; - return con_font_op(vc_cons[fg_console].d, &op); + ret = con_font_op(vc_cons[fg_console].d, &op); + break; } case PIO_CMAP: if (!perm) - return -EPERM; - return con_set_cmap(up); + ret = -EPERM; + else + ret = con_set_cmap(up); + break; case GIO_CMAP: - return con_get_cmap(up); + ret = con_get_cmap(up); + break; case PIO_FONTX: case GIO_FONTX: - return do_fontx_ioctl(cmd, up, perm, &op); + ret = do_fontx_ioctl(cmd, up, perm, &op); + break; case PIO_FONTRESET: { if (!perm) - return -EPERM; + goto eperm; #ifdef BROKEN_GRAPHICS_PROGRAMS /* With BROKEN_GRAPHICS_PROGRAMS defined, the default font is not saved. */ - return -ENOSYS; + ret = -ENOSYS; + break; #else { op.op = KD_FONT_OP_SET_DEFAULT; op.data = NULL; - i = con_font_op(vc_cons[fg_console].d, &op); - if (i) - return i; + ret = con_font_op(vc_cons[fg_console].d, &op); + if (ret) + break; con_set_default_unimap(vc_cons[fg_console].d); - return 0; + break; } #endif } case KDFONTOP: { - if (copy_from_user(&op, up, sizeof(op))) - return -EFAULT; + if (copy_from_user(&op, up, sizeof(op))) { + ret = -EFAULT; + break; + } if (!perm && op.op != KD_FONT_OP_GET) - return -EPERM; - i = con_font_op(vc, &op); - if (i) return i; + goto eperm; + ret = con_font_op(vc, &op); + if (ret) + break; if (copy_to_user(up, &op, sizeof(op))) - return -EFAULT; - return 0; + ret = -EFAULT; + break; } case PIO_SCRNMAP: if (!perm) - return -EPERM; - return con_set_trans_old(up); + ret = -EPERM; + else + ret = con_set_trans_old(up); + break; case GIO_SCRNMAP: - return con_get_trans_old(up); + ret = con_get_trans_old(up); + break; case PIO_UNISCRNMAP: if (!perm) - return -EPERM; - return con_set_trans_new(up); + ret = -EPERM; + else + ret = con_set_trans_new(up); + break; case GIO_UNISCRNMAP: - return con_get_trans_new(up); + ret = con_get_trans_new(up); + break; case PIO_UNIMAPCLR: { struct unimapinit ui; if (!perm) - return -EPERM; - i = copy_from_user(&ui, up, sizeof(struct unimapinit)); - if (i) return -EFAULT; - con_clear_unimap(vc, &ui); - return 0; + goto eperm; + ret = copy_from_user(&ui, up, sizeof(struct unimapinit)); + if (!ret) + con_clear_unimap(vc, &ui); + break; } case PIO_UNIMAP: case GIO_UNIMAP: - return do_unimap_ioctl(cmd, up, perm, vc); + ret = do_unimap_ioctl(cmd, up, perm, vc); + break; case VT_LOCKSWITCH: if (!capable(CAP_SYS_TTY_CONFIG)) - return -EPERM; + goto eperm; vt_dont_switch = 1; - return 0; + break; case VT_UNLOCKSWITCH: if (!capable(CAP_SYS_TTY_CONFIG)) - return -EPERM; + goto eperm; vt_dont_switch = 0; - return 0; + break; case VT_GETHIFONTMASK: - return put_user(vc->vc_hi_font_mask, (unsigned short __user *)arg); + ret = put_user(vc->vc_hi_font_mask, + (unsigned short __user *)arg); + break; default: - return -ENOIOCTLCMD; + ret = -ENOIOCTLCMD; } +out: + unlock_kernel(); + return ret; +eperm: + ret = -EPERM; + goto out; } /* diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index c159ae64eeb2..5f076aef74fa 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -69,6 +69,15 @@ config CPU_FREQ_DEFAULT_GOV_PERFORMANCE the frequency statically to the highest frequency supported by the CPU. +config CPU_FREQ_DEFAULT_GOV_POWERSAVE + bool "powersave" + depends on EMBEDDED + select CPU_FREQ_GOV_POWERSAVE + help + Use the CPUFreq governor 'powersave' as default. This sets + the frequency statically to the lowest frequency supported by + the CPU. + config CPU_FREQ_DEFAULT_GOV_USERSPACE bool "userspace" select CPU_FREQ_GOV_USERSPACE diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index d3575f5ec6d2..7fce038fa57e 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -583,15 +583,13 @@ out: i += sprintf(&buf[i], "\n"); return i; } -/** - * show_affected_cpus - show the CPUs affected by each transition - */ -static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf) + +static ssize_t show_cpus(cpumask_t mask, char *buf) { ssize_t i = 0; unsigned int cpu; - for_each_cpu_mask(cpu, policy->cpus) { + for_each_cpu_mask(cpu, mask) { if (i) i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), " "); i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), "%u", cpu); @@ -602,6 +600,25 @@ static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf) return i; } +/** + * show_related_cpus - show the CPUs affected by each transition even if + * hw coordination is in use + */ +static ssize_t show_related_cpus(struct cpufreq_policy *policy, char *buf) +{ + if (cpus_empty(policy->related_cpus)) + return show_cpus(policy->cpus, buf); + return show_cpus(policy->related_cpus, buf); +} + +/** + * show_affected_cpus - show the CPUs affected by each transition + */ +static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf) +{ + return show_cpus(policy->cpus, buf); +} + static ssize_t store_scaling_setspeed(struct cpufreq_policy *policy, const char *buf, size_t count) { @@ -646,6 +663,7 @@ define_one_ro(cpuinfo_max_freq); define_one_ro(scaling_available_governors); define_one_ro(scaling_driver); define_one_ro(scaling_cur_freq); +define_one_ro(related_cpus); define_one_ro(affected_cpus); define_one_rw(scaling_min_freq); define_one_rw(scaling_max_freq); @@ -658,6 +676,7 @@ static struct attribute *default_attrs[] = { &scaling_min_freq.attr, &scaling_max_freq.attr, &affected_cpus.attr, + &related_cpus.attr, &scaling_governor.attr, &scaling_driver.attr, &scaling_available_governors.attr, diff --git a/drivers/cpufreq/cpufreq_powersave.c b/drivers/cpufreq/cpufreq_powersave.c index 13fe06b94b0a..88d2f44fba48 100644 --- a/drivers/cpufreq/cpufreq_powersave.c +++ b/drivers/cpufreq/cpufreq_powersave.c @@ -35,12 +35,12 @@ static int cpufreq_governor_powersave(struct cpufreq_policy *policy, return 0; } -static struct cpufreq_governor cpufreq_gov_powersave = { +struct cpufreq_governor cpufreq_gov_powersave = { .name = "powersave", .governor = cpufreq_governor_powersave, .owner = THIS_MODULE, }; - +EXPORT_SYMBOL(cpufreq_gov_powersave); static int __init cpufreq_gov_powersave_init(void) { @@ -58,5 +58,9 @@ MODULE_AUTHOR("Dominik Brodowski <linux@brodo.de>"); MODULE_DESCRIPTION("CPUfreq policy governor 'powersave'"); MODULE_LICENSE("GPL"); +#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE +fs_initcall(cpufreq_gov_powersave_init); +#else module_init(cpufreq_gov_powersave_init); +#endif module_exit(cpufreq_gov_powersave_exit); diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index ef09e069433b..ae70d63a8b26 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -288,7 +288,7 @@ cpufreq_stat_notifier_trans (struct notifier_block *nb, unsigned long val, if (!stat) return 0; - old_index = freq_table_get_index(stat, freq->old); + old_index = stat->last_index; new_index = freq_table_get_index(stat, freq->new); cpufreq_stats_update(freq->cpu); diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 2b382990fe58..6e6c3c4aea6b 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -67,7 +67,7 @@ config EDAC_E7XXX E7205, E7500, E7501 and E7505 server chipsets. config EDAC_E752X - tristate "Intel e752x (e7520, e7525, e7320)" + tristate "Intel e752x (e7520, e7525, e7320) and 3100" depends on EDAC_MM_EDAC && PCI && X86 && HOTPLUG help Support for error detection and correction on the Intel diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c index f22075410591..2b95f1a3edfc 100644 --- a/drivers/edac/amd76x_edac.c +++ b/drivers/edac/amd76x_edac.c @@ -17,6 +17,7 @@ #include <linux/pci.h> #include <linux/pci_ids.h> #include <linux/slab.h> +#include <linux/edac.h> #include "edac_core.h" #define AMD76X_REVISION " Ver: 2.0.2 " __DATE__ @@ -344,6 +345,9 @@ static struct pci_driver amd76x_driver = { static int __init amd76x_init(void) { + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + return pci_register_driver(&amd76x_driver); } @@ -358,3 +362,6 @@ module_exit(amd76x_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh"); MODULE_DESCRIPTION("MC support for AMD 76x memory controllers"); + +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c index 6eb434749cd5..c94a0eb492cb 100644 --- a/drivers/edac/e752x_edac.c +++ b/drivers/edac/e752x_edac.c @@ -29,6 +29,7 @@ #define EDAC_MOD_STR "e752x_edac" static int force_function_unhide; +static int sysbus_parity = -1; static struct edac_pci_ctl_info *e752x_pci; @@ -62,6 +63,14 @@ static struct edac_pci_ctl_info *e752x_pci; #define PCI_DEVICE_ID_INTEL_7320_1_ERR 0x3593 #endif /* PCI_DEVICE_ID_INTEL_7320_1_ERR */ +#ifndef PCI_DEVICE_ID_INTEL_3100_0 +#define PCI_DEVICE_ID_INTEL_3100_0 0x35B0 +#endif /* PCI_DEVICE_ID_INTEL_3100_0 */ + +#ifndef PCI_DEVICE_ID_INTEL_3100_1_ERR +#define PCI_DEVICE_ID_INTEL_3100_1_ERR 0x35B1 +#endif /* PCI_DEVICE_ID_INTEL_3100_1_ERR */ + #define E752X_NR_CSROWS 8 /* number of csrows */ /* E752X register addresses - device 0 function 0 */ @@ -152,6 +161,12 @@ static struct edac_pci_ctl_info *e752x_pci; /* error syndrome register (16b) */ #define E752X_DEVPRES1 0xF4 /* Device Present 1 register (8b) */ +/* 3100 IMCH specific register addresses - device 0 function 1 */ +#define I3100_NSI_FERR 0x48 /* NSI first error reg (32b) */ +#define I3100_NSI_NERR 0x4C /* NSI next error reg (32b) */ +#define I3100_NSI_SMICMD 0x54 /* NSI SMI command register (32b) */ +#define I3100_NSI_EMASK 0x90 /* NSI error mask register (32b) */ + /* ICH5R register addresses - device 30 function 0 */ #define ICH5R_PCI_STAT 0x06 /* PCI status register (16b) */ #define ICH5R_PCI_2ND_STAT 0x1E /* PCI status secondary reg (16b) */ @@ -160,7 +175,8 @@ static struct edac_pci_ctl_info *e752x_pci; enum e752x_chips { E7520 = 0, E7525 = 1, - E7320 = 2 + E7320 = 2, + I3100 = 3 }; struct e752x_pvt { @@ -185,8 +201,10 @@ struct e752x_dev_info { struct e752x_error_info { u32 ferr_global; u32 nerr_global; - u8 hi_ferr; - u8 hi_nerr; + u32 nsi_ferr; /* 3100 only */ + u32 nsi_nerr; /* 3100 only */ + u8 hi_ferr; /* all but 3100 */ + u8 hi_nerr; /* all but 3100 */ u16 sysbus_ferr; u16 sysbus_nerr; u8 buf_ferr; @@ -215,6 +233,10 @@ static const struct e752x_dev_info e752x_devs[] = { .err_dev = PCI_DEVICE_ID_INTEL_7320_1_ERR, .ctl_dev = PCI_DEVICE_ID_INTEL_7320_0, .ctl_name = "E7320"}, + [I3100] = { + .err_dev = PCI_DEVICE_ID_INTEL_3100_1_ERR, + .ctl_dev = PCI_DEVICE_ID_INTEL_3100_0, + .ctl_name = "3100"}, }; static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci, @@ -402,7 +424,7 @@ static inline void process_threshold_ce(struct mem_ctl_info *mci, u16 error, static char *global_message[11] = { "PCI Express C1", "PCI Express C", "PCI Express B1", "PCI Express B", "PCI Express A1", "PCI Express A", - "DMA Controler", "HUB Interface", "System Bus", + "DMA Controler", "HUB or NS Interface", "System Bus", "DRAM Controler", "Internal Buffer" }; @@ -455,6 +477,63 @@ static inline void hub_error(int fatal, u8 errors, int *error_found, do_hub_error(fatal, errors); } +#define NSI_FATAL_MASK 0x0c080081 +#define NSI_NON_FATAL_MASK 0x23a0ba64 +#define NSI_ERR_MASK (NSI_FATAL_MASK | NSI_NON_FATAL_MASK) + +static char *nsi_message[30] = { + "NSI Link Down", /* NSI_FERR/NSI_NERR bit 0, fatal error */ + "", /* reserved */ + "NSI Parity Error", /* bit 2, non-fatal */ + "", /* reserved */ + "", /* reserved */ + "Correctable Error Message", /* bit 5, non-fatal */ + "Non-Fatal Error Message", /* bit 6, non-fatal */ + "Fatal Error Message", /* bit 7, fatal */ + "", /* reserved */ + "Receiver Error", /* bit 9, non-fatal */ + "", /* reserved */ + "Bad TLP", /* bit 11, non-fatal */ + "Bad DLLP", /* bit 12, non-fatal */ + "REPLAY_NUM Rollover", /* bit 13, non-fatal */ + "", /* reserved */ + "Replay Timer Timeout", /* bit 15, non-fatal */ + "", /* reserved */ + "", /* reserved */ + "", /* reserved */ + "Data Link Protocol Error", /* bit 19, fatal */ + "", /* reserved */ + "Poisoned TLP", /* bit 21, non-fatal */ + "", /* reserved */ + "Completion Timeout", /* bit 23, non-fatal */ + "Completer Abort", /* bit 24, non-fatal */ + "Unexpected Completion", /* bit 25, non-fatal */ + "Receiver Overflow", /* bit 26, fatal */ + "Malformed TLP", /* bit 27, fatal */ + "", /* reserved */ + "Unsupported Request" /* bit 29, non-fatal */ +}; + +static void do_nsi_error(int fatal, u32 errors) +{ + int i; + + for (i = 0; i < 30; i++) { + if (errors & (1 << i)) + printk(KERN_WARNING "%sError %s\n", + fatal_message[fatal], nsi_message[i]); + } +} + +static inline void nsi_error(int fatal, u32 errors, int *error_found, + int handle_error) +{ + *error_found = 1; + + if (handle_error) + do_nsi_error(fatal, errors); +} + static char *membuf_message[4] = { "Internal PMWB to DRAM parity", "Internal PMWB to System Bus Parity", @@ -546,6 +625,31 @@ static void e752x_check_hub_interface(struct e752x_error_info *info, } } +static void e752x_check_ns_interface(struct e752x_error_info *info, + int *error_found, int handle_error) +{ + u32 stat32; + + stat32 = info->nsi_ferr; + if (stat32 & NSI_ERR_MASK) { /* Error, so process */ + if (stat32 & NSI_FATAL_MASK) /* check for fatal errors */ + nsi_error(1, stat32 & NSI_FATAL_MASK, error_found, + handle_error); + if (stat32 & NSI_NON_FATAL_MASK) /* check for non-fatal ones */ + nsi_error(0, stat32 & NSI_NON_FATAL_MASK, error_found, + handle_error); + } + stat32 = info->nsi_nerr; + if (stat32 & NSI_ERR_MASK) { + if (stat32 & NSI_FATAL_MASK) + nsi_error(1, stat32 & NSI_FATAL_MASK, error_found, + handle_error); + if (stat32 & NSI_NON_FATAL_MASK) + nsi_error(0, stat32 & NSI_NON_FATAL_MASK, error_found, + handle_error); + } +} + static void e752x_check_sysbus(struct e752x_error_info *info, int *error_found, int handle_error) { @@ -653,7 +757,15 @@ static void e752x_get_error_info(struct mem_ctl_info *mci, pci_read_config_dword(dev, E752X_FERR_GLOBAL, &info->ferr_global); if (info->ferr_global) { - pci_read_config_byte(dev, E752X_HI_FERR, &info->hi_ferr); + if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) { + pci_read_config_dword(dev, I3100_NSI_FERR, + &info->nsi_ferr); + info->hi_ferr = 0; + } else { + pci_read_config_byte(dev, E752X_HI_FERR, + &info->hi_ferr); + info->nsi_ferr = 0; + } pci_read_config_word(dev, E752X_SYSBUS_FERR, &info->sysbus_ferr); pci_read_config_byte(dev, E752X_BUF_FERR, &info->buf_ferr); @@ -669,10 +781,15 @@ static void e752x_get_error_info(struct mem_ctl_info *mci, pci_read_config_dword(dev, E752X_DRAM_RETR_ADD, &info->dram_retr_add); + /* ignore the reserved bits just in case */ if (info->hi_ferr & 0x7f) pci_write_config_byte(dev, E752X_HI_FERR, info->hi_ferr); + if (info->nsi_ferr & NSI_ERR_MASK) + pci_write_config_dword(dev, I3100_NSI_FERR, + info->nsi_ferr); + if (info->sysbus_ferr) pci_write_config_word(dev, E752X_SYSBUS_FERR, info->sysbus_ferr); @@ -692,7 +809,15 @@ static void e752x_get_error_info(struct mem_ctl_info *mci, pci_read_config_dword(dev, E752X_NERR_GLOBAL, &info->nerr_global); if (info->nerr_global) { - pci_read_config_byte(dev, E752X_HI_NERR, &info->hi_nerr); + if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) { + pci_read_config_dword(dev, I3100_NSI_NERR, + &info->nsi_nerr); + info->hi_nerr = 0; + } else { + pci_read_config_byte(dev, E752X_HI_NERR, + &info->hi_nerr); + info->nsi_nerr = 0; + } pci_read_config_word(dev, E752X_SYSBUS_NERR, &info->sysbus_nerr); pci_read_config_byte(dev, E752X_BUF_NERR, &info->buf_nerr); @@ -706,6 +831,10 @@ static void e752x_get_error_info(struct mem_ctl_info *mci, pci_write_config_byte(dev, E752X_HI_NERR, info->hi_nerr); + if (info->nsi_nerr & NSI_ERR_MASK) + pci_write_config_dword(dev, I3100_NSI_NERR, + info->nsi_nerr); + if (info->sysbus_nerr) pci_write_config_word(dev, E752X_SYSBUS_NERR, info->sysbus_nerr); @@ -750,6 +879,7 @@ static int e752x_process_error_info(struct mem_ctl_info *mci, global_error(0, stat32, &error_found, handle_errors); e752x_check_hub_interface(info, &error_found, handle_errors); + e752x_check_ns_interface(info, &error_found, handle_errors); e752x_check_sysbus(info, &error_found, handle_errors); e752x_check_membuf(info, &error_found, handle_errors); e752x_check_dram(mci, info, &error_found, handle_errors); @@ -920,15 +1050,53 @@ fail: return 1; } +/* Setup system bus parity mask register. + * Sysbus parity supported on: + * e7320/e7520/e7525 + Xeon + * i3100 + Xeon/Celeron + * Sysbus parity not supported on: + * i3100 + Pentium M/Celeron M/Core Duo/Core2 Duo + */ +static void e752x_init_sysbus_parity_mask(struct e752x_pvt *pvt) +{ + char *cpu_id = cpu_data(0).x86_model_id; + struct pci_dev *dev = pvt->dev_d0f1; + int enable = 1; + + /* Allow module paramter override, else see if CPU supports parity */ + if (sysbus_parity != -1) { + enable = sysbus_parity; + } else if (cpu_id[0] && + ((strstr(cpu_id, "Pentium") && strstr(cpu_id, " M ")) || + (strstr(cpu_id, "Celeron") && strstr(cpu_id, " M ")) || + (strstr(cpu_id, "Core") && strstr(cpu_id, "Duo")))) { + e752x_printk(KERN_INFO, "System Bus Parity not " + "supported by CPU, disabling\n"); + enable = 0; + } + + if (enable) + pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x0000); + else + pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x0309); +} + static void e752x_init_error_reporting_regs(struct e752x_pvt *pvt) { struct pci_dev *dev; dev = pvt->dev_d0f1; /* Turn off error disable & SMI in case the BIOS turned it on */ - pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00); - pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00); - pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x00); + if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) { + pci_write_config_dword(dev, I3100_NSI_EMASK, 0); + pci_write_config_dword(dev, I3100_NSI_SMICMD, 0); + } else { + pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00); + pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00); + } + + e752x_init_sysbus_parity_mask(pvt); + pci_write_config_word(dev, E752X_SYSBUS_SMICMD, 0x00); pci_write_config_byte(dev, E752X_BUF_ERRMASK, 0x00); pci_write_config_byte(dev, E752X_BUF_SMICMD, 0x00); @@ -949,16 +1117,6 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) debugf0("%s(): mci\n", __func__); debugf0("Starting Probe1\n"); - /* make sure error reporting method is sane */ - switch (edac_op_state) { - case EDAC_OPSTATE_POLL: - case EDAC_OPSTATE_NMI: - break; - default: - edac_op_state = EDAC_OPSTATE_POLL; - break; - } - /* check to see if device 0 function 1 is enabled; if it isn't, we * assume the BIOS has reserved it for a reason and is expecting * exclusive access, we take care not to violate that assumption and @@ -985,8 +1143,9 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) debugf3("%s(): init mci\n", __func__); mci->mtype_cap = MEM_FLAG_RDDR; - mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED | - EDAC_FLAG_S4ECD4ED; + /* 3100 IMCH supports SECDEC only */ + mci->edac_ctl_cap = (dev_idx == I3100) ? EDAC_FLAG_SECDED : + (EDAC_FLAG_NONE | EDAC_FLAG_SECDED | EDAC_FLAG_S4ECD4ED); /* FIXME - what if different memory types are in different csrows? */ mci->mod_name = EDAC_MOD_STR; mci->mod_ver = E752X_REVISION; @@ -1018,7 +1177,10 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) e752x_init_csrows(mci, pdev, ddrcsr); e752x_init_mem_map_table(pdev, pvt); - mci->edac_cap |= EDAC_FLAG_NONE; + if (dev_idx == I3100) + mci->edac_cap = EDAC_FLAG_SECDED; /* the only mode supported */ + else + mci->edac_cap |= EDAC_FLAG_NONE; debugf3("%s(): tolm, remapbase, remaplimit\n", __func__); /* load the top of low memory, remap base, and remap limit vars */ @@ -1110,6 +1272,9 @@ static const struct pci_device_id e752x_pci_tbl[] __devinitdata = { PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, E7320}, { + PCI_VEND_DEV(INTEL, 3100_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, + I3100}, + { 0, } /* 0 terminated list. */ }; @@ -1128,6 +1293,10 @@ static int __init e752x_init(void) int pci_rc; debugf3("%s()\n", __func__); + + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + pci_rc = pci_register_driver(&e752x_driver); return (pci_rc < 0) ? pci_rc : 0; } @@ -1143,10 +1312,15 @@ module_exit(e752x_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Linux Networx (http://lnxi.com) Tom Zimmerman\n"); -MODULE_DESCRIPTION("MC support for Intel e752x memory controllers"); +MODULE_DESCRIPTION("MC support for Intel e752x/3100 memory controllers"); module_param(force_function_unhide, int, 0444); MODULE_PARM_DESC(force_function_unhide, "if BIOS sets Dev0:Fun1 up as hidden:" " 1=force unhide and hope BIOS doesn't fight driver for Dev0:Fun1 access"); + module_param(edac_op_state, int, 0444); MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); + +module_param(sysbus_parity, int, 0444); +MODULE_PARM_DESC(sysbus_parity, "0=disable system bus parity checking," + " 1=enable system bus parity checking, default=auto-detect"); diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c index 96ecc4926641..c7d11cc4e21a 100644 --- a/drivers/edac/e7xxx_edac.c +++ b/drivers/edac/e7xxx_edac.c @@ -414,16 +414,6 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx) debugf0("%s(): mci\n", __func__); - /* make sure error reporting method is sane */ - switch (edac_op_state) { - case EDAC_OPSTATE_POLL: - case EDAC_OPSTATE_NMI: - break; - default: - edac_op_state = EDAC_OPSTATE_POLL; - break; - } - pci_read_config_dword(pdev, E7XXX_DRC, &drc); drc_chan = dual_channel_active(drc, dev_idx); @@ -565,6 +555,9 @@ static struct pci_driver e7xxx_driver = { static int __init e7xxx_init(void) { + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + return pci_register_driver(&e7xxx_driver); } diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c index b9552bc03dea..63372fa7ecfe 100644 --- a/drivers/edac/edac_device.c +++ b/drivers/edac/edac_device.c @@ -36,7 +36,7 @@ * is protected by the 'device_ctls_mutex' lock */ static DEFINE_MUTEX(device_ctls_mutex); -static struct list_head edac_device_list = LIST_HEAD_INIT(edac_device_list); +static LIST_HEAD(edac_device_list); #ifdef CONFIG_EDAC_DEBUG static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev) @@ -375,37 +375,6 @@ static void del_edac_device_from_global_list(struct edac_device_ctl_info wait_for_completion(&edac_device->removal_complete); } -/** - * edac_device_find - * Search for a edac_device_ctl_info structure whose index is 'idx'. - * - * If found, return a pointer to the structure. - * Else return NULL. - * - * Caller must hold device_ctls_mutex. - */ -struct edac_device_ctl_info *edac_device_find(int idx) -{ - struct list_head *item; - struct edac_device_ctl_info *edac_dev; - - /* Iterate over list, looking for exact match of ID */ - list_for_each(item, &edac_device_list) { - edac_dev = list_entry(item, struct edac_device_ctl_info, link); - - if (edac_dev->dev_idx >= idx) { - if (edac_dev->dev_idx == idx) - return edac_dev; - - /* not on list, so terminate early */ - break; - } - } - - return NULL; -} -EXPORT_SYMBOL_GPL(edac_device_find); - /* * edac_device_workq_function * performs the operation scheduled by a workq request diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 063a1bffe38b..a4cf1645f588 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -36,7 +36,7 @@ /* lock to memory controller's control array */ static DEFINE_MUTEX(mem_ctls_mutex); -static struct list_head mc_devices = LIST_HEAD_INIT(mc_devices); +static LIST_HEAD(mc_devices); #ifdef CONFIG_EDAC_DEBUG @@ -886,24 +886,3 @@ void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci, mci->csrows[csrow].channels[channel].ce_count++; } EXPORT_SYMBOL(edac_mc_handle_fbd_ce); - -/* - * Iterate over all MC instances and check for ECC, et al, errors - */ -void edac_check_mc_devices(void) -{ - struct list_head *item; - struct mem_ctl_info *mci; - - debugf3("%s()\n", __func__); - mutex_lock(&mem_ctls_mutex); - - list_for_each(item, &mc_devices) { - mci = list_entry(item, struct mem_ctl_info, link); - - if (mci->edac_check != NULL) - mci->edac_check(mci); - } - - mutex_unlock(&mem_ctls_mutex); -} diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h index cbc419c8ebc1..233d4798c3aa 100644 --- a/drivers/edac/edac_module.h +++ b/drivers/edac/edac_module.h @@ -27,7 +27,6 @@ extern int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci); extern void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci); extern int edac_create_sysfs_mci_device(struct mem_ctl_info *mci); extern void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci); -extern void edac_check_mc_devices(void); extern int edac_get_log_ue(void); extern int edac_get_log_ce(void); extern int edac_get_panic_on_ue(void); diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c index 32be43576a8e..9b24340b52e1 100644 --- a/drivers/edac/edac_pci.c +++ b/drivers/edac/edac_pci.c @@ -29,7 +29,7 @@ #include "edac_module.h" static DEFINE_MUTEX(edac_pci_ctls_mutex); -static struct list_head edac_pci_list = LIST_HEAD_INIT(edac_pci_list); +static LIST_HEAD(edac_pci_list); /* * edac_pci_alloc_ctl_info @@ -189,6 +189,9 @@ static void del_edac_pci_from_global_list(struct edac_pci_ctl_info *pci) wait_for_completion(&pci->complete); } +#if 0 +/* Older code, but might use in the future */ + /* * edac_pci_find() * Search for an edac_pci_ctl_info structure whose index is 'idx' @@ -219,6 +222,7 @@ struct edac_pci_ctl_info *edac_pci_find(int idx) return NULL; } EXPORT_SYMBOL_GPL(edac_pci_find); +#endif /* * edac_pci_workq_function() @@ -422,7 +426,7 @@ EXPORT_SYMBOL_GPL(edac_pci_del_device); * * a Generic parity check API */ -void edac_pci_generic_check(struct edac_pci_ctl_info *pci) +static void edac_pci_generic_check(struct edac_pci_ctl_info *pci) { debugf4("%s()\n", __func__); edac_pci_do_parity_check(); diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c index 71c3195d3704..2c1fa1bb6df2 100644 --- a/drivers/edac/edac_pci_sysfs.c +++ b/drivers/edac/edac_pci_sysfs.c @@ -37,17 +37,17 @@ int edac_pci_get_check_errors(void) return check_pci_errors; } -int edac_pci_get_log_pe(void) +static int edac_pci_get_log_pe(void) { return edac_pci_log_pe; } -int edac_pci_get_log_npe(void) +static int edac_pci_get_log_npe(void) { return edac_pci_log_npe; } -int edac_pci_get_panic_on_pe(void) +static int edac_pci_get_panic_on_pe(void) { return edac_pci_panic_on_pe; } @@ -197,7 +197,8 @@ error_out: * * unregister the kobj for the EDAC PCI instance */ -void edac_pci_unregister_sysfs_instance_kobj(struct edac_pci_ctl_info *pci) +static void edac_pci_unregister_sysfs_instance_kobj( + struct edac_pci_ctl_info *pci) { debugf0("%s()\n", __func__); @@ -337,7 +338,7 @@ static struct kobj_type ktype_edac_pci_main_kobj = { * setup the sysfs for EDAC PCI attributes * assumes edac_class has already been initialized */ -int edac_pci_main_kobj_setup(void) +static int edac_pci_main_kobj_setup(void) { int err; struct sysdev_class *edac_class; diff --git a/drivers/edac/i3000_edac.c b/drivers/edac/i3000_edac.c index 5d4292811c14..6c9a0f2a593c 100644 --- a/drivers/edac/i3000_edac.c +++ b/drivers/edac/i3000_edac.c @@ -326,15 +326,6 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx) return -ENODEV; } - switch (edac_op_state) { - case EDAC_OPSTATE_POLL: - case EDAC_OPSTATE_NMI: - break; - default: - edac_op_state = EDAC_OPSTATE_POLL; - break; - } - c0dra[0] = readb(window + I3000_C0DRA + 0); /* ranks 0,1 */ c0dra[1] = readb(window + I3000_C0DRA + 1); /* ranks 2,3 */ c1dra[0] = readb(window + I3000_C1DRA + 0); /* ranks 0,1 */ @@ -503,6 +494,10 @@ static int __init i3000_init(void) int pci_rc; debugf3("MC: %s()\n", __func__); + + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + pci_rc = pci_register_driver(&i3000_driver); if (pci_rc < 0) goto fail0; diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c index 5a852017c17a..4a16b5b61cfb 100644 --- a/drivers/edac/i5000_edac.c +++ b/drivers/edac/i5000_edac.c @@ -1286,16 +1286,6 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx) if (PCI_FUNC(pdev->devfn) != 0) return -ENODEV; - /* make sure error reporting method is sane */ - switch (edac_op_state) { - case EDAC_OPSTATE_POLL: - case EDAC_OPSTATE_NMI: - break; - default: - edac_op_state = EDAC_OPSTATE_POLL; - break; - } - /* Ask the devices for the number of CSROWS and CHANNELS so * that we can calculate the memory resources, etc * @@ -1478,6 +1468,9 @@ static int __init i5000_init(void) debugf2("MC: " __FILE__ ": %s()\n", __func__); + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + pci_rc = pci_register_driver(&i5000_driver); return (pci_rc < 0) ? pci_rc : 0; @@ -1501,5 +1494,6 @@ MODULE_AUTHOR ("Linux Networx (http://lnxi.com) Doug Thompson <norsk5@xmission.com>"); MODULE_DESCRIPTION("MC Driver for Intel I5000 memory controllers - " I5000_REVISION); + module_param(edac_op_state, int, 0444); MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/drivers/edac/i82443bxgx_edac.c b/drivers/edac/i82443bxgx_edac.c index 83bfe37c4bbb..c5305e3ee434 100644 --- a/drivers/edac/i82443bxgx_edac.c +++ b/drivers/edac/i82443bxgx_edac.c @@ -29,6 +29,7 @@ #include <linux/slab.h> +#include <linux/edac.h> #include "edac_core.h" #define I82443_REVISION "0.1" @@ -386,6 +387,9 @@ static struct pci_driver i82443bxgx_edacmc_driver = { static int __init i82443bxgx_edacmc_init(void) { + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + return pci_register_driver(&i82443bxgx_edacmc_driver); } @@ -400,3 +404,6 @@ module_exit(i82443bxgx_edacmc_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD"); MODULE_DESCRIPTION("EDAC MC support for Intel 82443BX/GX memory controllers"); + +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c index f5ecd2c4d813..c0088ba9672b 100644 --- a/drivers/edac/i82860_edac.c +++ b/drivers/edac/i82860_edac.c @@ -14,6 +14,7 @@ #include <linux/pci.h> #include <linux/pci_ids.h> #include <linux/slab.h> +#include <linux/edac.h> #include "edac_core.h" #define I82860_REVISION " Ver: 2.0.2 " __DATE__ @@ -294,6 +295,9 @@ static int __init i82860_init(void) debugf3("%s()\n", __func__); + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + if ((pci_rc = pci_register_driver(&i82860_driver)) < 0) goto fail0; @@ -345,3 +349,6 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com) " "Ben Woodard <woodard@redhat.com>"); MODULE_DESCRIPTION("ECC support for Intel 82860 memory hub controllers"); + +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c index 031abadc439a..e43bdc43a1bf 100644 --- a/drivers/edac/i82875p_edac.c +++ b/drivers/edac/i82875p_edac.c @@ -18,6 +18,7 @@ #include <linux/pci.h> #include <linux/pci_ids.h> #include <linux/slab.h> +#include <linux/edac.h> #include "edac_core.h" #define I82875P_REVISION " Ver: 2.0.2 " __DATE__ @@ -393,6 +394,7 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx) struct i82875p_error_info discard; debugf0("%s()\n", __func__); + ovrfl_pdev = pci_get_device(PCI_VEND_DEV(INTEL, 82875_6), NULL); if (i82875p_setup_overfl_dev(pdev, &ovrfl_pdev, &ovrfl_window)) @@ -532,6 +534,10 @@ static int __init i82875p_init(void) int pci_rc; debugf3("%s()\n", __func__); + + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + pci_rc = pci_register_driver(&i82875p_driver); if (pci_rc < 0) @@ -586,3 +592,6 @@ module_exit(i82875p_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh"); MODULE_DESCRIPTION("MC support for Intel 82875 memory hub controllers"); + +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c index 0ee888456932..2eed3ea2cf62 100644 --- a/drivers/edac/i82975x_edac.c +++ b/drivers/edac/i82975x_edac.c @@ -14,7 +14,7 @@ #include <linux/pci.h> #include <linux/pci_ids.h> #include <linux/slab.h> - +#include <linux/edac.h> #include "edac_core.h" #define I82975X_REVISION " Ver: 1.0.0 " __DATE__ @@ -611,6 +611,9 @@ static int __init i82975x_init(void) debugf3("%s()\n", __func__); + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + pci_rc = pci_register_driver(&i82975x_driver); if (pci_rc < 0) goto fail0; @@ -664,3 +667,6 @@ module_exit(i82975x_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Arvind R. <arvind@acarlab.com>"); MODULE_DESCRIPTION("MC support for Intel 82975 memory hub controllers"); + +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/drivers/edac/pasemi_edac.c b/drivers/edac/pasemi_edac.c index 90320917be28..8e6b91bd2e99 100644 --- a/drivers/edac/pasemi_edac.c +++ b/drivers/edac/pasemi_edac.c @@ -26,6 +26,7 @@ #include <linux/pci.h> #include <linux/pci_ids.h> #include <linux/slab.h> +#include <linux/edac.h> #include "edac_core.h" #define MODULE_NAME "pasemi_edac" @@ -284,6 +285,9 @@ static struct pci_driver pasemi_edac_driver = { static int __init pasemi_edac_init(void) { + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + return pci_register_driver(&pasemi_edac_driver); } @@ -298,3 +302,6 @@ module_exit(pasemi_edac_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>"); MODULE_DESCRIPTION("MC support for PA Semi PWRficient memory controller"); +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); + diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c index e25f712f2dc3..9900675e9598 100644 --- a/drivers/edac/r82600_edac.c +++ b/drivers/edac/r82600_edac.c @@ -20,6 +20,7 @@ #include <linux/pci.h> #include <linux/pci_ids.h> #include <linux/slab.h> +#include <linux/edac.h> #include "edac_core.h" #define R82600_REVISION " Ver: 2.0.2 " __DATE__ @@ -393,6 +394,9 @@ static struct pci_driver r82600_driver = { static int __init r82600_init(void) { + /* Ensure that the OPSTATE is set correctly for POLL or NMI */ + opstate_init(); + return pci_register_driver(&r82600_driver); } @@ -412,3 +416,6 @@ MODULE_DESCRIPTION("MC support for Radisys 82600 memory controllers"); module_param(disable_hardware_scrub, bool, 0644); MODULE_PARM_DESC(disable_hardware_scrub, "If set, disable the chipset's automatic scrub for CEs"); + +module_param(edac_op_state, int, 0444); +MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 40ffd767647d..dc2cec6127d1 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -17,6 +17,15 @@ config EDD obscure configurations. Most disk controller BIOS vendors do not yet implement this feature. +config EDD_OFF + bool "Sets default behavior for EDD detection to off" + depends on EDD + default n + help + Say Y if you want EDD disabled by default, even though it is compiled into the + kernel. Say N if you want EDD enabled by default. EDD can be dynamically set + using the kernel parameter 'edd={on|skipmbr|off}'. + config EFI_VARS tristate "EFI Variable Support via sysfs" depends on EFI diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c index f235940719e7..25918f7dfd0f 100644 --- a/drivers/firmware/dcdbas.c +++ b/drivers/firmware/dcdbas.c @@ -63,7 +63,7 @@ static void smi_data_buf_free(void) return; dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n", - __FUNCTION__, smi_data_buf_phys_addr, smi_data_buf_size); + __func__, smi_data_buf_phys_addr, smi_data_buf_size); dma_free_coherent(&dcdbas_pdev->dev, smi_data_buf_size, smi_data_buf, smi_data_buf_handle); @@ -92,7 +92,7 @@ static int smi_data_buf_realloc(unsigned long size) if (!buf) { dev_dbg(&dcdbas_pdev->dev, "%s: failed to allocate memory size %lu\n", - __FUNCTION__, size); + __func__, size); return -ENOMEM; } /* memory zeroed by dma_alloc_coherent */ @@ -110,7 +110,7 @@ static int smi_data_buf_realloc(unsigned long size) smi_data_buf_size = size; dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n", - __FUNCTION__, smi_data_buf_phys_addr, smi_data_buf_size); + __func__, smi_data_buf_phys_addr, smi_data_buf_size); return 0; } @@ -258,7 +258,7 @@ static int smi_request(struct smi_cmd *smi_cmd) if (smi_cmd->magic != SMI_CMD_MAGIC) { dev_info(&dcdbas_pdev->dev, "%s: invalid magic value\n", - __FUNCTION__); + __func__); return -EBADR; } @@ -267,7 +267,7 @@ static int smi_request(struct smi_cmd *smi_cmd) set_cpus_allowed_ptr(current, &cpumask_of_cpu(0)); if (smp_processor_id() != 0) { dev_dbg(&dcdbas_pdev->dev, "%s: failed to get CPU 0\n", - __FUNCTION__); + __func__); ret = -EBUSY; goto out; } @@ -428,7 +428,7 @@ static int host_control_smi(void) default: dev_dbg(&dcdbas_pdev->dev, "%s: invalid SMI type %u\n", - __FUNCTION__, host_control_smi_type); + __func__, host_control_smi_type); return -ENOSYS; } @@ -456,13 +456,13 @@ static void dcdbas_host_control(void) host_control_action = HC_ACTION_NONE; if (!smi_data_buf) { - dev_dbg(&dcdbas_pdev->dev, "%s: no SMI buffer\n", __FUNCTION__); + dev_dbg(&dcdbas_pdev->dev, "%s: no SMI buffer\n", __func__); return; } if (smi_data_buf_size < sizeof(struct apm_cmd)) { dev_dbg(&dcdbas_pdev->dev, "%s: SMI buffer too small\n", - __FUNCTION__); + __func__); return; } diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c index 477a3d0e3caf..6a8b1e037e07 100644 --- a/drivers/firmware/dell_rbu.c +++ b/drivers/firmware/dell_rbu.c @@ -123,7 +123,7 @@ static int create_packet(void *data, size_t length) if (!newpacket) { printk(KERN_WARNING "dell_rbu:%s: failed to allocate new " - "packet\n", __FUNCTION__); + "packet\n", __func__); retval = -ENOMEM; spin_lock(&rbu_data.lock); goto out_noalloc; @@ -152,7 +152,7 @@ static int create_packet(void *data, size_t length) printk(KERN_WARNING "dell_rbu:%s: failed to allocate " "invalid_addr_packet_array \n", - __FUNCTION__); + __func__); retval = -ENOMEM; spin_lock(&rbu_data.lock); goto out_alloc_packet; @@ -164,7 +164,7 @@ static int create_packet(void *data, size_t length) if (!packet_data_temp_buf) { printk(KERN_WARNING "dell_rbu:%s: failed to allocate new " - "packet\n", __FUNCTION__); + "packet\n", __func__); retval = -ENOMEM; spin_lock(&rbu_data.lock); goto out_alloc_packet_array; @@ -416,7 +416,7 @@ static int img_update_realloc(unsigned long size) */ if ((size != 0) && (rbu_data.image_update_buffer == NULL)) { printk(KERN_ERR "dell_rbu:%s: corruption " - "check failed\n", __FUNCTION__); + "check failed\n", __func__); return -EINVAL; } /* @@ -642,7 +642,7 @@ static ssize_t write_rbu_image_type(struct kobject *kobj, if (req_firm_rc) { printk(KERN_ERR "dell_rbu:%s request_firmware_nowait" - " failed %d\n", __FUNCTION__, rc); + " failed %d\n", __func__, rc); rc = -EIO; } else rbu_data.entry_created = 1; @@ -718,7 +718,7 @@ static int __init dcdrbu_init(void) if (IS_ERR(rbu_device)) { printk(KERN_ERR "dell_rbu:%s:platform_device_register_simple " - "failed\n", __FUNCTION__); + "failed\n", __func__); return PTR_ERR(rbu_device); } diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 24c62b848bf9..7f138c6195ff 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -382,7 +382,7 @@ fail: spin_unlock_irqrestore(&gpio_lock, flags); if (status) pr_debug("%s: gpio-%d status %d\n", - __FUNCTION__, gpio, status); + __func__, gpio, status); return status; } EXPORT_SYMBOL_GPL(gpio_direction_input); @@ -420,7 +420,7 @@ fail: spin_unlock_irqrestore(&gpio_lock, flags); if (status) pr_debug("%s: gpio-%d status %d\n", - __FUNCTION__, gpio, status); + __func__, gpio, status); return status; } EXPORT_SYMBOL_GPL(gpio_direction_output); diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c index e0e0af536108..5a99e81d2784 100644 --- a/drivers/gpio/pca953x.c +++ b/drivers/gpio/pca953x.c @@ -23,13 +23,7 @@ #define PCA953X_INVERT 2 #define PCA953X_DIRECTION 3 -/* This is temporary - in 2.6.26 i2c_driver_data should replace it. */ -struct pca953x_desc { - char name[I2C_NAME_SIZE]; - unsigned long driver_data; -}; - -static const struct pca953x_desc pca953x_descs[] = { +static const struct i2c_device_id pca953x_id[] = { { "pca9534", 8, }, { "pca9535", 16, }, { "pca9536", 4, }, @@ -37,7 +31,9 @@ static const struct pca953x_desc pca953x_descs[] = { { "pca9538", 8, }, { "pca9539", 16, }, /* REVISIT several pca955x parts should work here too */ + { } }; +MODULE_DEVICE_TABLE(i2c, pca953x_id); struct pca953x_chip { unsigned gpio_start; @@ -192,26 +188,17 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) gc->owner = THIS_MODULE; } -static int __devinit pca953x_probe(struct i2c_client *client) +static int __devinit pca953x_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct pca953x_platform_data *pdata; struct pca953x_chip *chip; int ret, i; - const struct pca953x_desc *id = NULL; pdata = client->dev.platform_data; if (pdata == NULL) return -ENODEV; - /* this loop vanishes when we get i2c_device_id */ - for (i = 0; i < ARRAY_SIZE(pca953x_descs); i++) - if (!strcmp(pca953x_descs[i].name, client->name)) { - id = pca953x_descs + i; - break; - } - if (!id) - return -ENODEV; - chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; @@ -291,6 +278,7 @@ static struct i2c_driver pca953x_driver = { }, .probe = pca953x_probe, .remove = pca953x_remove, + .id_table = pca953x_id, }; static int __init pca953x_init(void) diff --git a/drivers/gpio/pcf857x.c b/drivers/gpio/pcf857x.c index 1106aa15ac79..aa6cc8b2a2bc 100644 --- a/drivers/gpio/pcf857x.c +++ b/drivers/gpio/pcf857x.c @@ -26,6 +26,21 @@ #include <asm/gpio.h> +static const struct i2c_device_id pcf857x_id[] = { + { "pcf8574", 8 }, + { "pca8574", 8 }, + { "pca9670", 8 }, + { "pca9672", 8 }, + { "pca9674", 8 }, + { "pcf8575", 16 }, + { "pca8575", 16 }, + { "pca9671", 16 }, + { "pca9673", 16 }, + { "pca9675", 16 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pcf857x_id); + /* * The pcf857x, pca857x, and pca967x chips only expose one read and one * write register. Writing a "one" bit (to match the reset state) lets @@ -142,7 +157,8 @@ static void pcf857x_set16(struct gpio_chip *chip, unsigned offset, int value) /*-------------------------------------------------------------------------*/ -static int pcf857x_probe(struct i2c_client *client) +static int pcf857x_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct pcf857x_platform_data *pdata; struct pcf857x *gpio; @@ -172,13 +188,8 @@ static int pcf857x_probe(struct i2c_client *client) * * NOTE: we don't distinguish here between *4 and *4a parts. */ - if (strcmp(client->name, "pcf8574") == 0 - || strcmp(client->name, "pca8574") == 0 - || strcmp(client->name, "pca9670") == 0 - || strcmp(client->name, "pca9672") == 0 - || strcmp(client->name, "pca9674") == 0 - ) { - gpio->chip.ngpio = 8; + gpio->chip.ngpio = id->driver_data; + if (gpio->chip.ngpio == 8) { gpio->chip.direction_input = pcf857x_input8; gpio->chip.get = pcf857x_get8; gpio->chip.direction_output = pcf857x_output8; @@ -198,13 +209,7 @@ static int pcf857x_probe(struct i2c_client *client) * * NOTE: we don't distinguish here between '75 and '75c parts. */ - } else if (strcmp(client->name, "pcf8575") == 0 - || strcmp(client->name, "pca8575") == 0 - || strcmp(client->name, "pca9671") == 0 - || strcmp(client->name, "pca9673") == 0 - || strcmp(client->name, "pca9675") == 0 - ) { - gpio->chip.ngpio = 16; + } else if (gpio->chip.ngpio == 16) { gpio->chip.direction_input = pcf857x_input16; gpio->chip.get = pcf857x_get16; gpio->chip.direction_output = pcf857x_output16; @@ -313,6 +318,7 @@ static struct i2c_driver pcf857x_driver = { }, .probe = pcf857x_probe, .remove = pcf857x_remove, + .id_table = pcf857x_id, }; static int __init pcf857x_init(void) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index e03c67dd3e63..f43d6d3cf2fa 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -606,7 +606,7 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) case 2: if ((end - start) < 2) return NULL; - item->data.u16 = le16_to_cpu(get_unaligned((__le16*)start)); + item->data.u16 = get_unaligned_le16(start); start = (__u8 *)((__le16 *)start + 1); return start; @@ -614,7 +614,7 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) item->size++; if ((end - start) < 4) return NULL; - item->data.u32 = le32_to_cpu(get_unaligned((__le32*)start)); + item->data.u32 = get_unaligned_le32(start); start = (__u8 *)((__le32 *)start + 1); return start; } @@ -765,7 +765,7 @@ static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) report += offset >> 3; /* adjust byte index */ offset &= 7; /* now only need bit offset into one byte */ - x = le64_to_cpu(get_unaligned((__le64 *) report)); + x = get_unaligned_le64(report); x = (x >> offset) & ((1ULL << n) - 1); /* extract bit field */ return (u32) x; } diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c index ed71a8bc70dc..5c8b6e0ff47c 100644 --- a/drivers/hwmon/ads7828.c +++ b/drivers/hwmon/ads7828.c @@ -224,7 +224,7 @@ static int ads7828_detect(struct i2c_adapter *adapter, int address, int kind) if (in_data & 0xF000) { printk(KERN_DEBUG "%s : Doesn't look like an ads7828 device\n", - __FUNCTION__); + __func__); goto exit_free; } } diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c index 1464338e4e11..dc1f30e432ea 100644 --- a/drivers/hwmon/f75375s.c +++ b/drivers/hwmon/f75375s.c @@ -117,7 +117,8 @@ struct f75375_data { static int f75375_attach_adapter(struct i2c_adapter *adapter); static int f75375_detect(struct i2c_adapter *adapter, int address, int kind); static int f75375_detach_client(struct i2c_client *client); -static int f75375_probe(struct i2c_client *client); +static int f75375_probe(struct i2c_client *client, + const struct i2c_device_id *id); static int f75375_remove(struct i2c_client *client); static struct i2c_driver f75375_legacy_driver = { @@ -128,12 +129,20 @@ static struct i2c_driver f75375_legacy_driver = { .detach_client = f75375_detach_client, }; +static const struct i2c_device_id f75375_id[] = { + { "f75373", f75373 }, + { "f75375", f75375 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, f75375_id); + static struct i2c_driver f75375_driver = { .driver = { .name = "f75375", }, .probe = f75375_probe, .remove = f75375_remove, + .id_table = f75375_id, }; static inline int f75375_read8(struct i2c_client *client, u8 reg) @@ -628,7 +637,8 @@ static void f75375_init(struct i2c_client *client, struct f75375_data *data, } -static int f75375_probe(struct i2c_client *client) +static int f75375_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct f75375_data *data = i2c_get_clientdata(client); struct f75375s_platform_data *f75375s_pdata = client->dev.platform_data; @@ -643,15 +653,7 @@ static int f75375_probe(struct i2c_client *client) i2c_set_clientdata(client, data); data->client = client; mutex_init(&data->update_lock); - - if (strcmp(client->name, "f75375") == 0) - data->kind = f75375; - else if (strcmp(client->name, "f75373") == 0) - data->kind = f75373; - else { - dev_err(&client->dev, "Unsupported device: %s\n", client->name); - return -ENODEV; - } + data->kind = id->driver_data; if ((err = sysfs_create_group(&client->dev.kobj, &f75375_group))) goto exit_free; @@ -712,6 +714,7 @@ static int f75375_detect(struct i2c_adapter *adapter, int address, int kind) u8 version = 0; int err = 0; const char *name = ""; + struct i2c_device_id id; if (!(client = kzalloc(sizeof(*client), GFP_KERNEL))) { err = -ENOMEM; @@ -748,7 +751,9 @@ static int f75375_detect(struct i2c_adapter *adapter, int address, int kind) if ((err = i2c_attach_client(client))) goto exit_free; - if ((err = f75375_probe(client)) < 0) + strlcpy(id.name, name, I2C_NAME_SIZE); + id.driver_data = kind; + if ((err = f75375_probe(client, &id)) < 0) goto exit_detach; return 0; diff --git a/drivers/i2c/busses/i2c-amd756-s4882.c b/drivers/i2c/busses/i2c-amd756-s4882.c index e5e96c817566..c38a0a112208 100644 --- a/drivers/i2c/busses/i2c-amd756-s4882.c +++ b/drivers/i2c/busses/i2c-amd756-s4882.c @@ -1,7 +1,7 @@ /* * i2c-amd756-s4882.c - i2c-amd756 extras for the Tyan S4882 motherboard * - * Copyright (C) 2004 Jean Delvare <khali@linux-fr.org> + * Copyright (C) 2004, 2008 Jean Delvare <khali@linux-fr.org> * * 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 @@ -231,7 +231,8 @@ ERROR2: kfree(s4882_adapter); s4882_adapter = NULL; ERROR1: - i2c_del_adapter(&amd756_smbus); + /* Restore physical bus */ + i2c_add_adapter(&amd756_smbus); ERROR0: return error; } diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 9bbe96cef719..fdc9ad805e35 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -38,7 +38,6 @@ #include <linux/ioport.h> #include <linux/i2c.h> #include <linux/init.h> -#include <linux/apm_bios.h> #include <linux/dmi.h> #include <asm/io.h> @@ -223,7 +222,7 @@ static int piix4_transaction(void) dev_err(&piix4_adapter.dev, "Failed! (%02x)\n", temp); return -1; } else { - dev_dbg(&piix4_adapter.dev, "Successfull!\n"); + dev_dbg(&piix4_adapter.dev, "Successful!\n"); } } @@ -343,12 +342,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr, switch (size) { - case PIIX4_BYTE: /* Where is the result put? I assume here it is in - SMBHSTDAT0 but it might just as well be in the - SMBHSTCMD. No clue in the docs */ - - data->byte = inb_p(SMBHSTDAT0); - break; + case PIIX4_BYTE: case PIIX4_BYTE_DATA: data->byte = inb_p(SMBHSTDAT0); break; diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index 283769cecee2..9ca8f9155f95 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -238,7 +238,7 @@ static int sis5595_transaction(struct i2c_adapter *adap) dev_dbg(&adap->dev, "Failed! (%02x)\n", temp); return -1; } else { - dev_dbg(&adap->dev, "Successfull!\n"); + dev_dbg(&adap->dev, "Successful!\n"); } } @@ -316,14 +316,8 @@ static s32 sis5595_access(struct i2c_adapter *adap, u16 addr, } size = (size == I2C_SMBUS_PROC_CALL) ? SIS5595_PROC_CALL : SIS5595_WORD_DATA; break; -/* - case I2C_SMBUS_BLOCK_DATA: - printk(KERN_WARNING "sis5595.o: Block data not yet implemented!\n"); - return -1; - break; -*/ default: - printk(KERN_WARNING "sis5595.o: Unsupported transaction %d\n", size); + dev_warn(&adap->dev, "Unsupported transaction %d\n", size); return -1; } @@ -338,9 +332,7 @@ static s32 sis5595_access(struct i2c_adapter *adap, u16 addr, switch (size) { - case SIS5595_BYTE: /* Where is the result put? I assume here it is in - SMB_DATA but it might just as well be in the - SMB_CMD. No clue in the docs */ + case SIS5595_BYTE: case SIS5595_BYTE_DATA: data->byte = sis5595_read(SMB_BYTE); break; diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index 5fd734f99ee9..3765dd7f450f 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -136,7 +136,7 @@ static int sis630_transaction_start(struct i2c_adapter *adap, int size, u8 *oldc dev_dbg(&adap->dev, "Failed! (%02x)\n", temp); return -1; } else { - dev_dbg(&adap->dev, "Successfull!\n"); + dev_dbg(&adap->dev, "Successful!\n"); } } diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c index c2a9f8c94f5e..d08eeec53913 100644 --- a/drivers/i2c/busses/i2c-stub.c +++ b/drivers/i2c/busses/i2c-stub.c @@ -33,7 +33,7 @@ static unsigned short chip_addr[MAX_CHIPS]; module_param_array(chip_addr, ushort, NULL, S_IRUGO); MODULE_PARM_DESC(chip_addr, - "Chip addresses (up to 10, between 0x03 and 0x77)\n"); + "Chip addresses (up to 10, between 0x03 and 0x77)"); struct stub_chip { u8 pointer; diff --git a/drivers/i2c/busses/i2c-taos-evm.c b/drivers/i2c/busses/i2c-taos-evm.c index 1b0cfd5472fd..de9db49e54d9 100644 --- a/drivers/i2c/busses/i2c-taos-evm.c +++ b/drivers/i2c/busses/i2c-taos-evm.c @@ -51,7 +51,6 @@ struct taos_data { /* TAOS TSL2550 EVM */ static struct i2c_board_info tsl2550_info = { I2C_BOARD_INFO("tsl2550", 0x39), - .type = "tsl2550", }; /* Instantiate i2c devices based on the adapter name */ @@ -59,7 +58,7 @@ static struct i2c_client *taos_instantiate_device(struct i2c_adapter *adapter) { if (!strncmp(adapter->name, "TAOS TSL2550 EVM", 16)) { dev_info(&adapter->dev, "Instantiating device %s at 0x%02x\n", - tsl2550_info.driver_name, tsl2550_info.addr); + tsl2550_info.type, tsl2550_info.addr); return i2c_new_device(adapter, &tsl2550_info); } diff --git a/drivers/i2c/chips/ds1682.c b/drivers/i2c/chips/ds1682.c index 9e94542c18a2..23be4d42cb02 100644 --- a/drivers/i2c/chips/ds1682.c +++ b/drivers/i2c/chips/ds1682.c @@ -200,7 +200,8 @@ static struct bin_attribute ds1682_eeprom_attr = { /* * Called when a ds1682 device is matched with this driver */ -static int ds1682_probe(struct i2c_client *client) +static int ds1682_probe(struct i2c_client *client, + const struct i2c_device_id *id) { int rc; @@ -234,12 +235,19 @@ static int ds1682_remove(struct i2c_client *client) return 0; } +static const struct i2c_device_id ds1682_id[] = { + { "ds1682", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ds1682_id); + static struct i2c_driver ds1682_driver = { .driver = { .name = "ds1682", }, .probe = ds1682_probe, .remove = ds1682_remove, + .id_table = ds1682_id, }; static int __init ds1682_init(void) diff --git a/drivers/i2c/chips/menelaus.c b/drivers/i2c/chips/menelaus.c index 2dea0123a958..b36db1797c11 100644 --- a/drivers/i2c/chips/menelaus.c +++ b/drivers/i2c/chips/menelaus.c @@ -1149,7 +1149,8 @@ static inline void menelaus_rtc_init(struct menelaus_chip *m) static struct i2c_driver menelaus_i2c_driver; -static int menelaus_probe(struct i2c_client *client) +static int menelaus_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct menelaus_chip *menelaus; int rev = 0, val; @@ -1242,12 +1243,19 @@ static int __exit menelaus_remove(struct i2c_client *client) return 0; } +static const struct i2c_device_id menelaus_id[] = { + { "menelaus", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, menelaus_id); + static struct i2c_driver menelaus_i2c_driver = { .driver = { .name = DRIVER_NAME, }, .probe = menelaus_probe, .remove = __exit_p(menelaus_remove), + .id_table = menelaus_id, }; static int __init menelaus_init(void) diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c index b67f69c2e7f3..85949685191b 100644 --- a/drivers/i2c/chips/tps65010.c +++ b/drivers/i2c/chips/tps65010.c @@ -64,7 +64,6 @@ static struct i2c_driver tps65010_driver; * as part of board setup by a bootloader. */ enum tps_model { - TPS_UNKNOWN = 0, TPS65010, TPS65011, TPS65012, @@ -527,11 +526,13 @@ static int __exit tps65010_remove(struct i2c_client *client) flush_scheduled_work(); debugfs_remove(tps->file); kfree(tps); + i2c_set_clientdata(client, NULL); the_tps = NULL; return 0; } -static int tps65010_probe(struct i2c_client *client) +static int tps65010_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct tps65010 *tps; int status; @@ -552,20 +553,7 @@ static int tps65010_probe(struct i2c_client *client) mutex_init(&tps->lock); INIT_DELAYED_WORK(&tps->work, tps65010_work); tps->client = client; - - if (strcmp(client->name, "tps65010") == 0) - tps->model = TPS65010; - else if (strcmp(client->name, "tps65011") == 0) - tps->model = TPS65011; - else if (strcmp(client->name, "tps65012") == 0) - tps->model = TPS65012; - else if (strcmp(client->name, "tps65013") == 0) - tps->model = TPS65013; - else { - dev_warn(&client->dev, "unknown chip '%s'\n", client->name); - status = -ENODEV; - goto fail1; - } + tps->model = id->driver_data; /* the IRQ is active low, but many gpio lines can't support that * so this driver uses falling-edge triggers instead. @@ -594,9 +582,6 @@ static int tps65010_probe(struct i2c_client *client) case TPS65012: tps->por = 1; break; - case TPS_UNKNOWN: - printk(KERN_WARNING "%s: unknown TPS chip\n", DRIVER_NAME); - break; /* else CHGCONFIG.POR is replaced by AUA, enabling a WAIT mode */ } tps->chgconf = i2c_smbus_read_byte_data(client, TPS_CHGCONFIG); @@ -615,6 +600,7 @@ static int tps65010_probe(struct i2c_client *client) i2c_smbus_read_byte_data(client, TPS_DEFGPIO), i2c_smbus_read_byte_data(client, TPS_MASK3)); + i2c_set_clientdata(client, tps); the_tps = tps; #if defined(CONFIG_USB_GADGET) && !defined(CONFIG_USB_OTG) @@ -682,12 +668,22 @@ fail1: return status; } +static const struct i2c_device_id tps65010_id[] = { + { "tps65010", TPS65010 }, + { "tps65011", TPS65011 }, + { "tps65012", TPS65012 }, + { "tps65013", TPS65013 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tps65010_id); + static struct i2c_driver tps65010_driver = { .driver = { .name = "tps65010", }, .probe = tps65010_probe, .remove = __exit_p(tps65010_remove), + .id_table = tps65010_id, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/i2c/chips/tsl2550.c b/drivers/i2c/chips/tsl2550.c index a10fd2791a69..1a9cc135219f 100644 --- a/drivers/i2c/chips/tsl2550.c +++ b/drivers/i2c/chips/tsl2550.c @@ -364,7 +364,8 @@ static int tsl2550_init_client(struct i2c_client *client) */ static struct i2c_driver tsl2550_driver; -static int __devinit tsl2550_probe(struct i2c_client *client) +static int __devinit tsl2550_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); struct tsl2550_data *data; @@ -451,6 +452,12 @@ static int tsl2550_resume(struct i2c_client *client) #endif /* CONFIG_PM */ +static const struct i2c_device_id tsl2550_id[] = { + { "tsl2550", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tsl2550_id); + static struct i2c_driver tsl2550_driver = { .driver = { .name = TSL2550_DRV_NAME, @@ -460,6 +467,7 @@ static struct i2c_driver tsl2550_driver = { .resume = tsl2550_resume, .probe = tsl2550_probe, .remove = __devexit_p(tsl2550_remove), + .id_table = tsl2550_id, }; static int __init tsl2550_init(void) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 6c7fa8d53c0e..26384daccb96 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -48,6 +48,17 @@ static DEFINE_IDR(i2c_adapter_idr); /* ------------------------------------------------------------------------- */ +static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, + const struct i2c_client *client) +{ + while (id->name[0]) { + if (strcmp(client->name, id->name) == 0) + return id; + id++; + } + return NULL; +} + static int i2c_device_match(struct device *dev, struct device_driver *drv) { struct i2c_client *client = to_i2c_client(dev); @@ -59,6 +70,10 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv) if (!is_newstyle_driver(driver)) return 0; + /* match on an id table if there is one */ + if (driver->id_table) + return i2c_match_id(driver->id_table, client) != NULL; + /* new style drivers use the same kind of driver matching policy * as platform devices or SPI: compare device and driver IDs. */ @@ -73,11 +88,17 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) struct i2c_client *client = to_i2c_client(dev); /* by definition, legacy drivers can't hotplug */ - if (dev->driver || !client->driver_name) + if (dev->driver) return 0; - if (add_uevent_var(env, "MODALIAS=%s", client->driver_name)) - return -ENOMEM; + if (client->driver_name[0]) { + if (add_uevent_var(env, "MODALIAS=%s", client->driver_name)) + return -ENOMEM; + } else { + if (add_uevent_var(env, "MODALIAS=%s%s", + I2C_MODULE_PREFIX, client->name)) + return -ENOMEM; + } dev_dbg(dev, "uevent\n"); return 0; } @@ -90,13 +111,19 @@ static int i2c_device_probe(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct i2c_driver *driver = to_i2c_driver(dev->driver); + const struct i2c_device_id *id; int status; if (!driver->probe) return -ENODEV; client->driver = driver; dev_dbg(dev, "probe\n"); - status = driver->probe(client); + + if (driver->id_table) + id = i2c_match_id(driver->id_table, client); + else + id = NULL; + status = driver->probe(client, id); if (status) client->driver = NULL; return status; @@ -179,9 +206,9 @@ static ssize_t show_client_name(struct device *dev, struct device_attribute *att static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf) { struct i2c_client *client = to_i2c_client(dev); - return client->driver_name + return client->driver_name[0] ? sprintf(buf, "%s\n", client->driver_name) - : 0; + : sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name); } static struct device_attribute i2c_dev_attrs[] = { @@ -300,15 +327,21 @@ void i2c_unregister_device(struct i2c_client *client) EXPORT_SYMBOL_GPL(i2c_unregister_device); -static int dummy_nop(struct i2c_client *client) +static int dummy_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + return 0; +} + +static int dummy_remove(struct i2c_client *client) { return 0; } static struct i2c_driver dummy_driver = { .driver.name = "dummy", - .probe = dummy_nop, - .remove = dummy_nop, + .probe = dummy_probe, + .remove = dummy_remove, }; /** diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index fe9df38f62cc..68e7f19dc036 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -782,7 +782,7 @@ static ide_startstop_t cdrom_start_seek_continuation(ide_drive_t *drive) sector_div(frame, queue_hardsect_size(drive->queue) >> SECTOR_BITS); - memset(rq->cmd, 0, sizeof(rq->cmd)); + memset(rq->cmd, 0, BLK_MAX_CDB); rq->cmd[0] = GPCMD_SEEK; put_unaligned(cpu_to_be32(frame), (unsigned int *) &rq->cmd[2]); @@ -1694,7 +1694,7 @@ static int ide_cdrom_prep_fs(struct request_queue *q, struct request *rq) long block = (long)rq->hard_sector / (hard_sect >> 9); unsigned long blocks = rq->hard_nr_sectors / (hard_sect >> 9); - memset(rq->cmd, 0, sizeof(rq->cmd)); + memset(rq->cmd, 0, BLK_MAX_CDB); if (rq_data_dir(rq) == READ) rq->cmd[0] = GPCMD_READ_10; diff --git a/drivers/ide/ide-cd_verbose.c b/drivers/ide/ide-cd_verbose.c index 6ed7ca071331..6490a2dea96b 100644 --- a/drivers/ide/ide-cd_verbose.c +++ b/drivers/ide/ide-cd_verbose.c @@ -326,7 +326,7 @@ void ide_cd_log_error(const char *name, struct request *failed_command, printk(KERN_ERR " The failed \"%s\" packet command " "was: \n \"", s); - for (i = 0; i < sizeof(failed_command->cmd); i++) + for (i = 0; i < BLK_MAX_CDB; i++) printk(KERN_CONT "%02x ", failed_command->cmd[i]); printk(KERN_CONT "\"\n"); } diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 788783da9025..696525342e9a 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -1550,8 +1550,7 @@ irqreturn_t ide_intr (int irq, void *dev_id) void ide_init_drive_cmd (struct request *rq) { - memset(rq, 0, sizeof(*rq)); - rq->ref_count = 1; + blk_rq_init(NULL, rq); } EXPORT_SYMBOL(ide_init_drive_cmd); diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c index 7b2f3815a838..8d6ad812a014 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c @@ -822,6 +822,7 @@ static int ide_drivers_open(struct inode *inode, struct file *file) } static const struct file_operations ide_drivers_operations = { + .owner = THIS_MODULE, .open = ide_drivers_open, .read = seq_read, .llseek = seq_lseek, @@ -830,16 +831,12 @@ static const struct file_operations ide_drivers_operations = { void proc_ide_create(void) { - struct proc_dir_entry *entry; - proc_ide_root = proc_mkdir("ide", NULL); if (!proc_ide_root) return; - entry = create_proc_entry("drivers", 0, proc_ide_root); - if (entry) - entry->proc_fops = &ide_drivers_operations; + proc_create("drivers", 0, proc_ide_root, &ide_drivers_operations); } void proc_ide_destroy(void) diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 54a43b044608..1e1f26331a24 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -662,7 +662,7 @@ static void idetape_create_request_sense_cmd(struct ide_atapi_pc *pc) static void idetape_init_rq(struct request *rq, u8 cmd) { - memset(rq, 0, sizeof(*rq)); + blk_rq_init(NULL, rq); rq->cmd_type = REQ_TYPE_SPECIAL; rq->cmd[0] = cmd; } diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 9a846a0cd5a4..0c908ca3ff79 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -494,8 +494,7 @@ int ide_raw_taskfile(ide_drive_t *drive, ide_task_t *task, u8 *buf, u16 nsect) { struct request rq; - memset(&rq, 0, sizeof(rq)); - rq.ref_count = 1; + blk_rq_init(NULL, &rq); rq.cmd_type = REQ_TYPE_ATA_TASKFILE; rq.buffer = buf; diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index 999584c03d97..c758dcb13b14 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -564,7 +564,7 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg) if (!(drive->dn % 2)) ide_acpi_get_timing(hwif); - memset(&rq, 0, sizeof(rq)); + blk_rq_init(NULL, &rq); memset(&rqpm, 0, sizeof(rqpm)); memset(&args, 0, sizeof(args)); rq.cmd_type = REQ_TYPE_PM_SUSPEND; @@ -602,7 +602,7 @@ static int generic_ide_resume(struct device *dev) ide_acpi_exec_tfs(drive); - memset(&rq, 0, sizeof(rq)); + blk_rq_init(NULL, &rq); memset(&rqpm, 0, sizeof(rqpm)); memset(&args, 0, sizeof(args)); rq.cmd_type = REQ_TYPE_PM_RESUME; diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c index b36a22b8c213..c1922f9cfe80 100644 --- a/drivers/ide/pci/alim15x3.c +++ b/drivers/ide/pci/alim15x3.c @@ -412,14 +412,14 @@ static u8 __devinit ali_cable_detect(ide_hwif_t *hwif) return cbl; } -#ifndef CONFIG_SPARC64 +#if !defined(CONFIG_SPARC64) && !defined(CONFIG_PPC) /** * init_hwif_ali15x3 - Initialize the ALI IDE x86 stuff * @hwif: interface to configure * * Obtain the IRQ tables for an ALi based IDE solution on the PC * class platforms. This part of the code isn't applicable to the - * Sparc systems + * Sparc and PowerPC systems. */ static void __devinit init_hwif_ali15x3 (ide_hwif_t *hwif) @@ -463,7 +463,9 @@ static void __devinit init_hwif_ali15x3 (ide_hwif_t *hwif) hwif->irq = irq; } } -#endif +#else +#define init_hwif_ali15x3 NULL +#endif /* !defined(CONFIG_SPARC64) && !defined(CONFIG_PPC) */ /** * init_dma_ali15x3 - set up DMA on ALi15x3 @@ -517,9 +519,7 @@ static const struct ide_dma_ops ali_dma_ops = { static const struct ide_port_info ali15x3_chipset __devinitdata = { .name = "ALI15X3", .init_chipset = init_chipset_ali15x3, -#ifndef CONFIG_SPARC64 .init_hwif = init_hwif_ali15x3, -#endif .init_dma = init_dma_ali15x3, .port_ops = &ali_port_ops, .pio_mask = ATA_PIO5, diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index 4cf8fc54aa2a..0006b9e58567 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -737,8 +737,15 @@ static const struct ide_port_ops sil_sata_port_ops = { .cable_detect = sil_cable_detect, }; -static struct ide_dma_ops sil_dma_ops = { +static const struct ide_dma_ops sil_dma_ops = { + .dma_host_set = ide_dma_host_set, + .dma_setup = ide_dma_setup, + .dma_exec_cmd = ide_dma_exec_cmd, + .dma_start = ide_dma_start, + .dma_end = __ide_dma_end, .dma_test_irq = siimage_dma_test_irq, + .dma_timeout = ide_dma_timeout, + .dma_lost_irq = ide_dma_lost_irq, }; #define DECLARE_SII_DEV(name_str, p_ops) \ diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index 4e3128ff73c1..fe78f7d25099 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -38,6 +38,7 @@ #include <linux/dma-mapping.h> #include <linux/sched.h> #include <linux/hugetlb.h> +#include <linux/dma-attrs.h> #include "uverbs.h" @@ -72,9 +73,10 @@ static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int d * @addr: userspace virtual address to start at * @size: length of region to pin * @access: IB_ACCESS_xxx flags for memory being pinned + * @dmasync: flush in-flight DMA when the memory region is written */ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, - size_t size, int access) + size_t size, int access, int dmasync) { struct ib_umem *umem; struct page **page_list; @@ -87,6 +89,10 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, int ret; int off; int i; + DEFINE_DMA_ATTRS(attrs); + + if (dmasync) + dma_set_attr(DMA_ATTR_WRITE_BARRIER, &attrs); if (!can_do_mlock()) return ERR_PTR(-EPERM); @@ -174,10 +180,11 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, sg_set_page(&chunk->page_list[i], page_list[i + off], PAGE_SIZE, 0); } - chunk->nmap = ib_dma_map_sg(context->device, - &chunk->page_list[0], - chunk->nents, - DMA_BIDIRECTIONAL); + chunk->nmap = ib_dma_map_sg_attrs(context->device, + &chunk->page_list[0], + chunk->nents, + DMA_BIDIRECTIONAL, + &attrs); if (chunk->nmap <= 0) { for (i = 0; i < chunk->nents; ++i) put_page(sg_page(&chunk->page_list[i])); diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c index 6af2c0f79a67..2acf9b62cf99 100644 --- a/drivers/infiniband/hw/amso1100/c2_provider.c +++ b/drivers/infiniband/hw/amso1100/c2_provider.c @@ -452,7 +452,7 @@ static struct ib_mr *c2_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, return ERR_PTR(-ENOMEM); c2mr->pd = c2pd; - c2mr->umem = ib_umem_get(pd->uobject->context, start, length, acc); + c2mr->umem = ib_umem_get(pd->uobject->context, start, length, acc, 0); if (IS_ERR(c2mr->umem)) { err = PTR_ERR(c2mr->umem); kfree(c2mr); diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c index 66eb7030aea8..ed2ee4ba4b7c 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.c +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c @@ -456,7 +456,8 @@ void cxio_count_scqes(struct t3_cq *cq, struct t3_wq *wq, int *count) ptr = cq->sw_rptr; while (!Q_EMPTY(ptr, cq->sw_wptr)) { cqe = cq->sw_queue + (Q_PTR2IDX(ptr, cq->size_log2)); - if ((SQ_TYPE(*cqe) || (CQE_OPCODE(*cqe) == T3_READ_RESP)) && + if ((SQ_TYPE(*cqe) || + ((CQE_OPCODE(*cqe) == T3_READ_RESP) && wq->oldest_read)) && (CQE_QPID(*cqe) == wq->qpid)) (*count)++; ptr++; @@ -829,7 +830,8 @@ int cxio_rdma_init(struct cxio_rdev *rdev_p, struct t3_rdma_init_attr *attr) wqe->mpaattrs = attr->mpaattrs; wqe->qpcaps = attr->qpcaps; wqe->ulpdu_size = cpu_to_be16(attr->tcp_emss); - wqe->flags = cpu_to_be32(attr->flags); + wqe->rqe_count = cpu_to_be16(attr->rqe_count); + wqe->flags_rtr_type = cpu_to_be16(attr->flags|V_RTR_TYPE(attr->rtr_type)); wqe->ord = cpu_to_be32(attr->ord); wqe->ird = cpu_to_be32(attr->ird); wqe->qp_dma_addr = cpu_to_be64(attr->qp_dma_addr); @@ -1135,6 +1137,18 @@ int cxio_poll_cq(struct t3_wq *wq, struct t3_cq *cq, struct t3_cqe *cqe, if (RQ_TYPE(*hw_cqe) && (CQE_OPCODE(*hw_cqe) == T3_READ_RESP)) { /* + * If this is an unsolicited read response, then the read + * was generated by the kernel driver as part of peer-2-peer + * connection setup. So ignore the completion. + */ + if (!wq->oldest_read) { + if (CQE_STATUS(*hw_cqe)) + wq->error = 1; + ret = -1; + goto skip_cqe; + } + + /* * Don't write to the HWCQ, so create a new read req CQE * in local memory. */ diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.h b/drivers/infiniband/hw/cxgb3/cxio_hal.h index 99543d634704..2bcff7f5046e 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_hal.h +++ b/drivers/infiniband/hw/cxgb3/cxio_hal.h @@ -53,6 +53,7 @@ #define T3_MAX_PBL_SIZE 256 #define T3_MAX_RQ_SIZE 1024 #define T3_MAX_NUM_STAG (1<<15) +#define T3_MAX_MR_SIZE 0x100000000ULL #define T3_STAG_UNSET 0xffffffff diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h index 969d4d928455..f1a25a821a45 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_wr.h +++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h @@ -278,6 +278,17 @@ enum t3_qp_caps { uP_RI_QP_STAG0_ENABLE = 0x10 } __attribute__ ((packed)); +enum rdma_init_rtr_types { + RTR_READ = 1, + RTR_WRITE = 2, + RTR_SEND = 3, +}; + +#define S_RTR_TYPE 2 +#define M_RTR_TYPE 0x3 +#define V_RTR_TYPE(x) ((x) << S_RTR_TYPE) +#define G_RTR_TYPE(x) ((((x) >> S_RTR_TYPE)) & M_RTR_TYPE) + struct t3_rdma_init_attr { u32 tid; u32 qpid; @@ -293,7 +304,9 @@ struct t3_rdma_init_attr { u32 ird; u64 qp_dma_addr; u32 qp_dma_size; - u32 flags; + enum rdma_init_rtr_types rtr_type; + u16 flags; + u16 rqe_count; u32 irs; }; @@ -309,8 +322,8 @@ struct t3_rdma_init_wr { u8 mpaattrs; /* 5 */ u8 qpcaps; __be16 ulpdu_size; - __be32 flags; /* bits 31-1 - reservered */ - /* bit 0 - set if RECV posted */ + __be16 flags_rtr_type; + __be16 rqe_count; __be32 ord; /* 6 */ __be32 ird; __be64 qp_dma_addr; /* 7 */ @@ -324,7 +337,7 @@ struct t3_genbit { }; enum rdma_init_wr_flags { - RECVS_POSTED = (1<<0), + MPA_INITIATOR = (1<<0), PRIV_QP = (1<<1), }; diff --git a/drivers/infiniband/hw/cxgb3/iwch.c b/drivers/infiniband/hw/cxgb3/iwch.c index 6ba4138c8ec3..71554eacb13c 100644 --- a/drivers/infiniband/hw/cxgb3/iwch.c +++ b/drivers/infiniband/hw/cxgb3/iwch.c @@ -83,6 +83,7 @@ static void rnic_init(struct iwch_dev *rnicp) rnicp->attr.max_phys_buf_entries = T3_MAX_PBL_SIZE; rnicp->attr.max_pds = T3_MAX_NUM_PD - 1; rnicp->attr.mem_pgsizes_bitmask = 0x7FFF; /* 4KB-128MB */ + rnicp->attr.max_mr_size = T3_MAX_MR_SIZE; rnicp->attr.can_resize_wq = 0; rnicp->attr.max_rdma_reads_per_qp = 8; rnicp->attr.max_rdma_read_resources = diff --git a/drivers/infiniband/hw/cxgb3/iwch.h b/drivers/infiniband/hw/cxgb3/iwch.h index 9ad9b1e7c8c1..d2409a505e8d 100644 --- a/drivers/infiniband/hw/cxgb3/iwch.h +++ b/drivers/infiniband/hw/cxgb3/iwch.h @@ -66,6 +66,7 @@ struct iwch_rnic_attributes { * size (4k)^i. Phys block list mode unsupported. */ u32 mem_pgsizes_bitmask; + u64 max_mr_size; u8 can_resize_wq; /* diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index 72ca360c3dbc..d44a6df9ad8c 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -63,6 +63,10 @@ static char *states[] = { NULL, }; +int peer2peer = 0; +module_param(peer2peer, int, 0644); +MODULE_PARM_DESC(peer2peer, "Support peer2peer ULPs (default=0)"); + static int ep_timeout_secs = 10; module_param(ep_timeout_secs, int, 0644); MODULE_PARM_DESC(ep_timeout_secs, "CM Endpoint operation timeout " @@ -125,6 +129,12 @@ static void start_ep_timer(struct iwch_ep *ep) static void stop_ep_timer(struct iwch_ep *ep) { PDBG("%s ep %p\n", __func__, ep); + if (!timer_pending(&ep->timer)) { + printk(KERN_ERR "%s timer stopped when its not running! ep %p state %u\n", + __func__, ep, ep->com.state); + WARN_ON(1); + return; + } del_timer_sync(&ep->timer); put_ep(&ep->com); } @@ -508,7 +518,7 @@ static void send_mpa_req(struct iwch_ep *ep, struct sk_buff *skb) skb_reset_transport_header(skb); len = skb->len; req = (struct tx_data_wr *) skb_push(skb, sizeof(*req)); - req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)); + req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)|F_WR_COMPL); req->wr_lo = htonl(V_WR_TID(ep->hwtid)); req->len = htonl(len); req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) | @@ -559,7 +569,7 @@ static int send_mpa_reject(struct iwch_ep *ep, const void *pdata, u8 plen) set_arp_failure_handler(skb, arp_failure_discard); skb_reset_transport_header(skb); req = (struct tx_data_wr *) skb_push(skb, sizeof(*req)); - req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)); + req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)|F_WR_COMPL); req->wr_lo = htonl(V_WR_TID(ep->hwtid)); req->len = htonl(mpalen); req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) | @@ -611,7 +621,7 @@ static int send_mpa_reply(struct iwch_ep *ep, const void *pdata, u8 plen) skb_reset_transport_header(skb); len = skb->len; req = (struct tx_data_wr *) skb_push(skb, sizeof(*req)); - req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)); + req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)|F_WR_COMPL); req->wr_lo = htonl(V_WR_TID(ep->hwtid)); req->len = htonl(len); req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) | @@ -879,6 +889,7 @@ static void process_mpa_reply(struct iwch_ep *ep, struct sk_buff *skb) * the MPA header is valid. */ state_set(&ep->com, FPDU_MODE); + ep->mpa_attr.initiator = 1; ep->mpa_attr.crc_enabled = (mpa->flags & MPA_CRC) | crc_enabled ? 1 : 0; ep->mpa_attr.recv_marker_enabled = markers_enabled; ep->mpa_attr.xmit_marker_enabled = mpa->flags & MPA_MARKERS ? 1 : 0; @@ -901,8 +912,14 @@ static void process_mpa_reply(struct iwch_ep *ep, struct sk_buff *skb) /* bind QP and TID with INIT_WR */ err = iwch_modify_qp(ep->com.qp->rhp, ep->com.qp, mask, &attrs, 1); - if (!err) - goto out; + if (err) + goto err; + + if (peer2peer && iwch_rqes_posted(ep->com.qp) == 0) { + iwch_post_zb_read(ep->com.qp); + } + + goto out; err: abort_connection(ep, skb, GFP_KERNEL); out: @@ -995,6 +1012,7 @@ static void process_mpa_request(struct iwch_ep *ep, struct sk_buff *skb) * If we get here we have accumulated the entire mpa * start reply message including private data. */ + ep->mpa_attr.initiator = 0; ep->mpa_attr.crc_enabled = (mpa->flags & MPA_CRC) | crc_enabled ? 1 : 0; ep->mpa_attr.recv_marker_enabled = markers_enabled; ep->mpa_attr.xmit_marker_enabled = mpa->flags & MPA_MARKERS ? 1 : 0; @@ -1065,17 +1083,33 @@ static int tx_ack(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) PDBG("%s ep %p credits %u\n", __func__, ep, credits); - if (credits == 0) + if (credits == 0) { + PDBG(KERN_ERR "%s 0 credit ack ep %p state %u\n", + __func__, ep, state_read(&ep->com)); return CPL_RET_BUF_DONE; + } + BUG_ON(credits != 1); - BUG_ON(ep->mpa_skb == NULL); - kfree_skb(ep->mpa_skb); - ep->mpa_skb = NULL; dst_confirm(ep->dst); - if (state_read(&ep->com) == MPA_REP_SENT) { - ep->com.rpl_done = 1; - PDBG("waking up ep %p\n", ep); - wake_up(&ep->com.waitq); + if (!ep->mpa_skb) { + PDBG("%s rdma_init wr_ack ep %p state %u\n", + __func__, ep, state_read(&ep->com)); + if (ep->mpa_attr.initiator) { + PDBG("%s initiator ep %p state %u\n", + __func__, ep, state_read(&ep->com)); + if (peer2peer) + iwch_post_zb_read(ep->com.qp); + } else { + PDBG("%s responder ep %p state %u\n", + __func__, ep, state_read(&ep->com)); + ep->com.rpl_done = 1; + wake_up(&ep->com.waitq); + } + } else { + PDBG("%s lsm ack ep %p state %u freeing skb\n", + __func__, ep, state_read(&ep->com)); + kfree_skb(ep->mpa_skb); + ep->mpa_skb = NULL; } return CPL_RET_BUF_DONE; } @@ -1083,8 +1117,11 @@ static int tx_ack(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) static int abort_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) { struct iwch_ep *ep = ctx; + unsigned long flags; + int release = 0; PDBG("%s ep %p\n", __func__, ep); + BUG_ON(!ep); /* * We get 2 abort replies from the HW. The first one must @@ -1095,9 +1132,22 @@ static int abort_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) return CPL_RET_BUF_DONE; } - close_complete_upcall(ep); - state_set(&ep->com, DEAD); - release_ep_resources(ep); + spin_lock_irqsave(&ep->com.lock, flags); + switch (ep->com.state) { + case ABORTING: + close_complete_upcall(ep); + __state_set(&ep->com, DEAD); + release = 1; + break; + default: + printk(KERN_ERR "%s ep %p state %d\n", + __func__, ep, ep->com.state); + break; + } + spin_unlock_irqrestore(&ep->com.lock, flags); + + if (release) + release_ep_resources(ep); return CPL_RET_BUF_DONE; } @@ -1470,7 +1520,8 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) struct sk_buff *rpl_skb; struct iwch_qp_attributes attrs; int ret; - int state; + int release = 0; + unsigned long flags; if (is_neg_adv_abort(req->status)) { PDBG("%s neg_adv_abort ep %p tid %d\n", __func__, ep, @@ -1488,9 +1539,9 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) return CPL_RET_BUF_DONE; } - state = state_read(&ep->com); - PDBG("%s ep %p state %u\n", __func__, ep, state); - switch (state) { + spin_lock_irqsave(&ep->com.lock, flags); + PDBG("%s ep %p state %u\n", __func__, ep, ep->com.state); + switch (ep->com.state) { case CONNECTING: break; case MPA_REQ_WAIT: @@ -1536,21 +1587,25 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) break; case DEAD: PDBG("%s PEER_ABORT IN DEAD STATE!!!!\n", __func__); + spin_unlock_irqrestore(&ep->com.lock, flags); return CPL_RET_BUF_DONE; default: BUG_ON(1); break; } dst_confirm(ep->dst); + if (ep->com.state != ABORTING) { + __state_set(&ep->com, DEAD); + release = 1; + } + spin_unlock_irqrestore(&ep->com.lock, flags); rpl_skb = get_skb(skb, sizeof(*rpl), GFP_KERNEL); if (!rpl_skb) { printk(KERN_ERR MOD "%s - cannot allocate skb!\n", __func__); - dst_release(ep->dst); - l2t_release(L2DATA(ep->com.tdev), ep->l2t); - put_ep(&ep->com); - return CPL_RET_BUF_DONE; + release = 1; + goto out; } rpl_skb->priority = CPL_PRIORITY_DATA; rpl = (struct cpl_abort_rpl *) skb_put(rpl_skb, sizeof(*rpl)); @@ -1559,10 +1614,9 @@ static int peer_abort(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, ep->hwtid)); rpl->cmd = CPL_ABORT_NO_RST; cxgb3_ofld_send(ep->com.tdev, rpl_skb); - if (state != ABORTING) { - state_set(&ep->com, DEAD); +out: + if (release) release_ep_resources(ep); - } return CPL_RET_BUF_DONE; } @@ -1661,15 +1715,18 @@ static void ep_timeout(unsigned long arg) struct iwch_ep *ep = (struct iwch_ep *)arg; struct iwch_qp_attributes attrs; unsigned long flags; + int abort = 1; spin_lock_irqsave(&ep->com.lock, flags); PDBG("%s ep %p tid %u state %d\n", __func__, ep, ep->hwtid, ep->com.state); switch (ep->com.state) { case MPA_REQ_SENT: + __state_set(&ep->com, ABORTING); connect_reply_upcall(ep, -ETIMEDOUT); break; case MPA_REQ_WAIT: + __state_set(&ep->com, ABORTING); break; case CLOSING: case MORIBUND: @@ -1679,13 +1736,17 @@ static void ep_timeout(unsigned long arg) ep->com.qp, IWCH_QP_ATTR_NEXT_STATE, &attrs, 1); } + __state_set(&ep->com, ABORTING); break; default: - BUG(); + printk(KERN_ERR "%s unexpected state ep %p state %u\n", + __func__, ep, ep->com.state); + WARN_ON(1); + abort = 0; } - __state_set(&ep->com, CLOSING); spin_unlock_irqrestore(&ep->com.lock, flags); - abort_connection(ep, NULL, GFP_ATOMIC); + if (abort) + abort_connection(ep, NULL, GFP_ATOMIC); put_ep(&ep->com); } @@ -1762,16 +1823,19 @@ int iwch_accept_cr(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) if (err) goto err; + /* if needed, wait for wr_ack */ + if (iwch_rqes_posted(qp)) { + wait_event(ep->com.waitq, ep->com.rpl_done); + err = ep->com.rpl_err; + if (err) + goto err; + } + err = send_mpa_reply(ep, conn_param->private_data, conn_param->private_data_len); if (err) goto err; - /* wait for wr_ack */ - wait_event(ep->com.waitq, ep->com.rpl_done); - err = ep->com.rpl_err; - if (err) - goto err; state_set(&ep->com, FPDU_MODE); established_upcall(ep); @@ -1968,40 +2032,39 @@ int iwch_ep_disconnect(struct iwch_ep *ep, int abrupt, gfp_t gfp) PDBG("%s ep %p state %s, abrupt %d\n", __func__, ep, states[ep->com.state], abrupt); - if (ep->com.state == DEAD) { - PDBG("%s already dead ep %p\n", __func__, ep); - goto out; - } - - if (abrupt) { - if (ep->com.state != ABORTING) { - ep->com.state = ABORTING; - close = 1; - } - goto out; - } - switch (ep->com.state) { case MPA_REQ_WAIT: case MPA_REQ_SENT: case MPA_REQ_RCVD: case MPA_REP_SENT: case FPDU_MODE: - start_ep_timer(ep); - ep->com.state = CLOSING; close = 1; + if (abrupt) + ep->com.state = ABORTING; + else { + ep->com.state = CLOSING; + start_ep_timer(ep); + } break; case CLOSING: - ep->com.state = MORIBUND; close = 1; + if (abrupt) { + stop_ep_timer(ep); + ep->com.state = ABORTING; + } else + ep->com.state = MORIBUND; break; case MORIBUND: + case ABORTING: + case DEAD: + PDBG("%s ignoring disconnect ep %p state %u\n", + __func__, ep, ep->com.state); break; default: BUG(); break; } -out: + spin_unlock_irqrestore(&ep->com.lock, flags); if (close) { if (abrupt) diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.h b/drivers/infiniband/hw/cxgb3/iwch_cm.h index 2bb7fbdb3ff4..d7c7e09f0996 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.h +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.h @@ -56,6 +56,7 @@ #define put_ep(ep) { \ PDBG("put_ep (via %s:%u) ep %p refcnt %d\n", __func__, __LINE__, \ ep, atomic_read(&((ep)->kref.refcount))); \ + WARN_ON(atomic_read(&((ep)->kref.refcount)) < 1); \ kref_put(&((ep)->kref), __free_ep); \ } @@ -225,5 +226,6 @@ int iwch_ep_redirect(void *ctx, struct dst_entry *old, struct dst_entry *new, st int __init iwch_cm_init(void); void __exit iwch_cm_term(void); +extern int peer2peer; #endif /* _IWCH_CM_H_ */ diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index ab4695c1dd56..d07d3a377b5f 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -602,7 +602,7 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, if (!mhp) return ERR_PTR(-ENOMEM); - mhp->umem = ib_umem_get(pd->uobject->context, start, length, acc); + mhp->umem = ib_umem_get(pd->uobject->context, start, length, acc, 0); if (IS_ERR(mhp->umem)) { err = PTR_ERR(mhp->umem); kfree(mhp); @@ -998,7 +998,7 @@ static int iwch_query_device(struct ib_device *ibdev, props->device_cap_flags = dev->device_cap_flags; props->vendor_id = (u32)dev->rdev.rnic_info.pdev->vendor; props->vendor_part_id = (u32)dev->rdev.rnic_info.pdev->device; - props->max_mr_size = ~0ull; + props->max_mr_size = dev->attr.max_mr_size; props->max_qp = dev->attr.max_qps; props->max_qp_wr = dev->attr.max_wrs; props->max_sge = dev->attr.max_sge_per_wr; diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.h b/drivers/infiniband/hw/cxgb3/iwch_provider.h index 61356f91109d..db5100d27ca2 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.h +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.h @@ -118,6 +118,7 @@ enum IWCH_QP_FLAGS { }; struct iwch_mpa_attributes { + u8 initiator; u8 recv_marker_enabled; u8 xmit_marker_enabled; /* iWARP: enable inbound Read Resp. */ u8 crc_enabled; @@ -322,6 +323,7 @@ enum iwch_qp_query_flags { IWCH_QP_QUERY_TEST_USERWRITE = 0x32 /* Test special */ }; +u16 iwch_rqes_posted(struct iwch_qp *qhp); int iwch_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, struct ib_send_wr **bad_wr); int iwch_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, @@ -331,6 +333,7 @@ int iwch_bind_mw(struct ib_qp *qp, struct ib_mw_bind *mw_bind); int iwch_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc); int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg); +int iwch_post_zb_read(struct iwch_qp *qhp); int iwch_register_device(struct iwch_dev *dev); void iwch_unregister_device(struct iwch_dev *dev); int iwch_quiesce_qps(struct iwch_cq *chp); diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c index 8891c3b0a3d5..9b4be889c58e 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_qp.c +++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c @@ -586,6 +586,36 @@ static inline void build_term_codes(struct respQ_msg_t *rsp_msg, } } +int iwch_post_zb_read(struct iwch_qp *qhp) +{ + union t3_wr *wqe; + struct sk_buff *skb; + u8 flit_cnt = sizeof(struct t3_rdma_read_wr) >> 3; + + PDBG("%s enter\n", __func__); + skb = alloc_skb(40, GFP_KERNEL); + if (!skb) { + printk(KERN_ERR "%s cannot send zb_read!!\n", __func__); + return -ENOMEM; + } + wqe = (union t3_wr *)skb_put(skb, sizeof(struct t3_rdma_read_wr)); + memset(wqe, 0, sizeof(struct t3_rdma_read_wr)); + wqe->read.rdmaop = T3_READ_REQ; + wqe->read.reserved[0] = 0; + wqe->read.reserved[1] = 0; + wqe->read.reserved[2] = 0; + wqe->read.rem_stag = cpu_to_be32(1); + wqe->read.rem_to = cpu_to_be64(1); + wqe->read.local_stag = cpu_to_be32(1); + wqe->read.local_len = cpu_to_be32(0); + wqe->read.local_to = cpu_to_be64(1); + wqe->send.wrh.op_seop_flags = cpu_to_be32(V_FW_RIWR_OP(T3_WR_READ)); + wqe->send.wrh.gen_tid_len = cpu_to_be32(V_FW_RIWR_TID(qhp->ep->hwtid)| + V_FW_RIWR_LEN(flit_cnt)); + skb->priority = CPL_PRIORITY_DATA; + return cxgb3_ofld_send(qhp->rhp->rdev.t3cdev_p, skb); +} + /* * This posts a TERMINATE with layer=RDMA, type=catastrophic. */ @@ -671,11 +701,18 @@ static void flush_qp(struct iwch_qp *qhp, unsigned long *flag) /* - * Return non zero if at least one RECV was pre-posted. + * Return count of RECV WRs posted */ -static int rqes_posted(struct iwch_qp *qhp) +u16 iwch_rqes_posted(struct iwch_qp *qhp) { - return fw_riwrh_opcode((struct fw_riwrh *)qhp->wq.queue) == T3_WR_RCV; + union t3_wr *wqe = qhp->wq.queue; + u16 count = 0; + while ((count+1) != 0 && fw_riwrh_opcode((struct fw_riwrh *)wqe) == T3_WR_RCV) { + count++; + wqe++; + } + PDBG("%s qhp %p count %u\n", __func__, qhp, count); + return count; } static int rdma_init(struct iwch_dev *rhp, struct iwch_qp *qhp, @@ -716,8 +753,17 @@ static int rdma_init(struct iwch_dev *rhp, struct iwch_qp *qhp, init_attr.ird = qhp->attr.max_ird; init_attr.qp_dma_addr = qhp->wq.dma_addr; init_attr.qp_dma_size = (1UL << qhp->wq.size_log2); - init_attr.flags = rqes_posted(qhp) ? RECVS_POSTED : 0; + init_attr.rqe_count = iwch_rqes_posted(qhp); + init_attr.flags = qhp->attr.mpa_attr.initiator ? MPA_INITIATOR : 0; init_attr.flags |= capable(CAP_NET_BIND_SERVICE) ? PRIV_QP : 0; + if (peer2peer) { + init_attr.rtr_type = RTR_READ; + if (init_attr.ord == 0 && qhp->attr.mpa_attr.initiator) + init_attr.ord = 1; + if (init_attr.ird == 0 && !qhp->attr.mpa_attr.initiator) + init_attr.ird = 1; + } else + init_attr.rtr_type = 0; init_attr.irs = qhp->ep->rcv_seq; PDBG("%s init_attr.rq_addr 0x%x init_attr.rq_size = %d " "flags 0x%x qpcaps 0x%x\n", __func__, @@ -832,6 +878,7 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp, abort=0; disconnect = 1; ep = qhp->ep; + get_ep(&ep->com); } flush_qp(qhp, &flag); break; @@ -848,6 +895,7 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp, abort=1; disconnect = 1; ep = qhp->ep; + get_ep(&ep->com); } goto err; break; @@ -929,8 +977,10 @@ out: * on the EP. This can be a normal close (RTS->CLOSING) or * an abnormal close (RTS/CLOSING->ERROR). */ - if (disconnect) + if (disconnect) { iwch_ep_disconnect(ep, abort, GFP_KERNEL); + put_ep(&ep->com); + } /* * If free is 1, then we've disassociated the EP from the QP diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h index 3d6d9461c31d..00bab60f6de4 100644 --- a/drivers/infiniband/hw/ehca/ehca_classes.h +++ b/drivers/infiniband/hw/ehca/ehca_classes.h @@ -66,6 +66,7 @@ struct ehca_av; #include "ehca_irq.h" #define EHCA_EQE_CACHE_SIZE 20 +#define EHCA_MAX_NUM_QUEUES 0xffff struct ehca_eqe_cache_entry { struct ehca_eqe *eqe; @@ -127,6 +128,8 @@ struct ehca_shca { /* MR pgsize: bit 0-3 means 4K, 64K, 1M, 16M respectively */ u32 hca_cap_mr_pgsize; int max_mtu; + atomic_t num_cqs; + atomic_t num_qps; }; struct ehca_pd { @@ -344,6 +347,8 @@ extern int ehca_use_hp_mr; extern int ehca_scaling_code; extern int ehca_lock_hcalls; extern int ehca_nr_ports; +extern int ehca_max_cq; +extern int ehca_max_qp; struct ipzu_queue_resp { u32 qe_size; /* queue entry size */ diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c index ec0cfcf3073f..5540b276a33c 100644 --- a/drivers/infiniband/hw/ehca/ehca_cq.c +++ b/drivers/infiniband/hw/ehca/ehca_cq.c @@ -132,10 +132,19 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe, int comp_vector, if (cqe >= 0xFFFFFFFF - 64 - additional_cqe) return ERR_PTR(-EINVAL); + if (!atomic_add_unless(&shca->num_cqs, 1, ehca_max_cq)) { + ehca_err(device, "Unable to create CQ, max number of %i " + "CQs reached.", ehca_max_cq); + ehca_err(device, "To increase the maximum number of CQs " + "use the number_of_cqs module parameter.\n"); + return ERR_PTR(-ENOSPC); + } + my_cq = kmem_cache_zalloc(cq_cache, GFP_KERNEL); if (!my_cq) { ehca_err(device, "Out of memory for ehca_cq struct device=%p", device); + atomic_dec(&shca->num_cqs); return ERR_PTR(-ENOMEM); } @@ -305,6 +314,7 @@ create_cq_exit2: create_cq_exit1: kmem_cache_free(cq_cache, my_cq); + atomic_dec(&shca->num_cqs); return cq; } @@ -359,6 +369,7 @@ int ehca_destroy_cq(struct ib_cq *cq) ipz_queue_dtor(NULL, &my_cq->ipz_queue); kmem_cache_free(cq_cache, my_cq); + atomic_dec(&shca->num_cqs); return 0; } diff --git a/drivers/infiniband/hw/ehca/ehca_eq.c b/drivers/infiniband/hw/ehca/ehca_eq.c index b4ac617a70e6..49660dfa1867 100644 --- a/drivers/infiniband/hw/ehca/ehca_eq.c +++ b/drivers/infiniband/hw/ehca/ehca_eq.c @@ -54,7 +54,8 @@ int ehca_create_eq(struct ehca_shca *shca, struct ehca_eq *eq, const enum ehca_eq_type type, const u32 length) { - u64 ret; + int ret; + u64 h_ret; u32 nr_pages; u32 i; void *vpage; @@ -73,15 +74,15 @@ int ehca_create_eq(struct ehca_shca *shca, return -EINVAL; } - ret = hipz_h_alloc_resource_eq(shca->ipz_hca_handle, - &eq->pf, - type, - length, - &eq->ipz_eq_handle, - &eq->length, - &nr_pages, &eq->ist); + h_ret = hipz_h_alloc_resource_eq(shca->ipz_hca_handle, + &eq->pf, + type, + length, + &eq->ipz_eq_handle, + &eq->length, + &nr_pages, &eq->ist); - if (ret != H_SUCCESS) { + if (h_ret != H_SUCCESS) { ehca_err(ib_dev, "Can't allocate EQ/NEQ. eq=%p", eq); return -EINVAL; } @@ -97,24 +98,22 @@ int ehca_create_eq(struct ehca_shca *shca, u64 rpage; vpage = ipz_qpageit_get_inc(&eq->ipz_queue); - if (!vpage) { - ret = H_RESOURCE; + if (!vpage) goto create_eq_exit2; - } rpage = virt_to_abs(vpage); - ret = hipz_h_register_rpage_eq(shca->ipz_hca_handle, - eq->ipz_eq_handle, - &eq->pf, - 0, 0, rpage, 1); + h_ret = hipz_h_register_rpage_eq(shca->ipz_hca_handle, + eq->ipz_eq_handle, + &eq->pf, + 0, 0, rpage, 1); if (i == (nr_pages - 1)) { /* last page */ vpage = ipz_qpageit_get_inc(&eq->ipz_queue); - if (ret != H_SUCCESS || vpage) + if (h_ret != H_SUCCESS || vpage) goto create_eq_exit2; } else { - if (ret != H_PAGE_REGISTERED || !vpage) + if (h_ret != H_PAGE_REGISTERED || !vpage) goto create_eq_exit2; } } diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index 65048976198c..482103eb6eac 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -68,6 +68,8 @@ int ehca_port_act_time = 30; int ehca_static_rate = -1; int ehca_scaling_code = 0; int ehca_lock_hcalls = -1; +int ehca_max_cq = -1; +int ehca_max_qp = -1; module_param_named(open_aqp1, ehca_open_aqp1, bool, S_IRUGO); module_param_named(debug_level, ehca_debug_level, int, S_IRUGO); @@ -79,6 +81,8 @@ module_param_named(poll_all_eqs, ehca_poll_all_eqs, bool, S_IRUGO); module_param_named(static_rate, ehca_static_rate, int, S_IRUGO); module_param_named(scaling_code, ehca_scaling_code, bool, S_IRUGO); module_param_named(lock_hcalls, ehca_lock_hcalls, bool, S_IRUGO); +module_param_named(number_of_cqs, ehca_max_cq, int, S_IRUGO); +module_param_named(number_of_qps, ehca_max_qp, int, S_IRUGO); MODULE_PARM_DESC(open_aqp1, "Open AQP1 on startup (default: no)"); @@ -104,6 +108,12 @@ MODULE_PARM_DESC(scaling_code, MODULE_PARM_DESC(lock_hcalls, "Serialize all hCalls made by the driver " "(default: autodetect)"); +MODULE_PARM_DESC(number_of_cqs, + "Max number of CQs which can be allocated " + "(default: autodetect)"); +MODULE_PARM_DESC(number_of_qps, + "Max number of QPs which can be allocated " + "(default: autodetect)"); DEFINE_RWLOCK(ehca_qp_idr_lock); DEFINE_RWLOCK(ehca_cq_idr_lock); @@ -355,6 +365,25 @@ static int ehca_sense_attributes(struct ehca_shca *shca) if (rblock->memory_page_size_supported & pgsize_map[i]) shca->hca_cap_mr_pgsize |= pgsize_map[i + 1]; + /* Set maximum number of CQs and QPs to calculate EQ size */ + if (ehca_max_qp == -1) + ehca_max_qp = min_t(int, rblock->max_qp, EHCA_MAX_NUM_QUEUES); + else if (ehca_max_qp < 1 || ehca_max_qp > rblock->max_qp) { + ehca_gen_err("Requested number of QPs is out of range (1 - %i) " + "specified by HW", rblock->max_qp); + ret = -EINVAL; + goto sense_attributes1; + } + + if (ehca_max_cq == -1) + ehca_max_cq = min_t(int, rblock->max_cq, EHCA_MAX_NUM_QUEUES); + else if (ehca_max_cq < 1 || ehca_max_cq > rblock->max_cq) { + ehca_gen_err("Requested number of CQs is out of range (1 - %i) " + "specified by HW", rblock->max_cq); + ret = -EINVAL; + goto sense_attributes1; + } + /* query max MTU from first port -- it's the same for all ports */ port = (struct hipz_query_port *)rblock; h_ret = hipz_h_query_port(shca->ipz_hca_handle, 1, port); @@ -684,7 +713,7 @@ static int __devinit ehca_probe(struct of_device *dev, struct ehca_shca *shca; const u64 *handle; struct ib_pd *ibpd; - int ret, i; + int ret, i, eq_size; handle = of_get_property(dev->node, "ibm,hca-handle", NULL); if (!handle) { @@ -705,6 +734,8 @@ static int __devinit ehca_probe(struct of_device *dev, return -ENOMEM; } mutex_init(&shca->modify_mutex); + atomic_set(&shca->num_cqs, 0); + atomic_set(&shca->num_qps, 0); for (i = 0; i < ARRAY_SIZE(shca->sport); i++) spin_lock_init(&shca->sport[i].mod_sqp_lock); @@ -724,8 +755,9 @@ static int __devinit ehca_probe(struct of_device *dev, goto probe1; } + eq_size = 2 * ehca_max_cq + 4 * ehca_max_qp; /* create event queues */ - ret = ehca_create_eq(shca, &shca->eq, EHCA_EQ, 2048); + ret = ehca_create_eq(shca, &shca->eq, EHCA_EQ, eq_size); if (ret) { ehca_err(&shca->ib_device, "Cannot create EQ."); goto probe1; diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c index 46ae4eb2c4e1..f974367cad40 100644 --- a/drivers/infiniband/hw/ehca/ehca_mrmw.c +++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c @@ -323,7 +323,7 @@ struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, } e_mr->umem = ib_umem_get(pd->uobject->context, start, length, - mr_access_flags); + mr_access_flags, 0); if (IS_ERR(e_mr->umem)) { ib_mr = (void *)e_mr->umem; goto reg_user_mr_exit1; diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c index 57bef1152cc2..18fba92fa7ae 100644 --- a/drivers/infiniband/hw/ehca/ehca_qp.c +++ b/drivers/infiniband/hw/ehca/ehca_qp.c @@ -421,8 +421,18 @@ static struct ehca_qp *internal_create_qp( u32 swqe_size = 0, rwqe_size = 0, ib_qp_num; unsigned long flags; - if (init_attr->create_flags) + if (!atomic_add_unless(&shca->num_qps, 1, ehca_max_qp)) { + ehca_err(pd->device, "Unable to create QP, max number of %i " + "QPs reached.", ehca_max_qp); + ehca_err(pd->device, "To increase the maximum number of QPs " + "use the number_of_qps module parameter.\n"); + return ERR_PTR(-ENOSPC); + } + + if (init_attr->create_flags) { + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); + } memset(&parms, 0, sizeof(parms)); qp_type = init_attr->qp_type; @@ -431,6 +441,7 @@ static struct ehca_qp *internal_create_qp( init_attr->sq_sig_type != IB_SIGNAL_ALL_WR) { ehca_err(pd->device, "init_attr->sg_sig_type=%x not allowed", init_attr->sq_sig_type); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); } @@ -455,6 +466,7 @@ static struct ehca_qp *internal_create_qp( if (is_llqp && has_srq) { ehca_err(pd->device, "LLQPs can't have an SRQ"); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); } @@ -466,6 +478,7 @@ static struct ehca_qp *internal_create_qp( ehca_err(pd->device, "no more than three SGEs " "supported for SRQ pd=%p max_sge=%x", pd, init_attr->cap.max_recv_sge); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); } } @@ -477,6 +490,7 @@ static struct ehca_qp *internal_create_qp( qp_type != IB_QPT_SMI && qp_type != IB_QPT_GSI) { ehca_err(pd->device, "wrong QP Type=%x", qp_type); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); } @@ -490,6 +504,7 @@ static struct ehca_qp *internal_create_qp( "or max_rq_wr=%x for RC LLQP", init_attr->cap.max_send_wr, init_attr->cap.max_recv_wr); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); } break; @@ -497,6 +512,7 @@ static struct ehca_qp *internal_create_qp( if (!EHCA_BMASK_GET(HCA_CAP_UD_LL_QP, shca->hca_cap)) { ehca_err(pd->device, "UD LLQP not supported " "by this adapter"); + atomic_dec(&shca->num_qps); return ERR_PTR(-ENOSYS); } if (!(init_attr->cap.max_send_sge <= 5 @@ -508,20 +524,22 @@ static struct ehca_qp *internal_create_qp( "or max_recv_sge=%x for UD LLQP", init_attr->cap.max_send_sge, init_attr->cap.max_recv_sge); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); } else if (init_attr->cap.max_send_wr > 255) { ehca_err(pd->device, "Invalid Number of " "max_send_wr=%x for UD QP_TYPE=%x", init_attr->cap.max_send_wr, qp_type); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); } break; default: ehca_err(pd->device, "unsupported LL QP Type=%x", qp_type); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); - break; } } else { int max_sge = (qp_type == IB_QPT_UD || qp_type == IB_QPT_SMI @@ -533,6 +551,7 @@ static struct ehca_qp *internal_create_qp( "send_sge=%x recv_sge=%x max_sge=%x", init_attr->cap.max_send_sge, init_attr->cap.max_recv_sge, max_sge); + atomic_dec(&shca->num_qps); return ERR_PTR(-EINVAL); } } @@ -543,6 +562,7 @@ static struct ehca_qp *internal_create_qp( my_qp = kmem_cache_zalloc(qp_cache, GFP_KERNEL); if (!my_qp) { ehca_err(pd->device, "pd=%p not enough memory to alloc qp", pd); + atomic_dec(&shca->num_qps); return ERR_PTR(-ENOMEM); } @@ -823,6 +843,7 @@ create_qp_exit1: create_qp_exit0: kmem_cache_free(qp_cache, my_qp); + atomic_dec(&shca->num_qps); return ERR_PTR(ret); } @@ -1948,6 +1969,7 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp, if (HAS_SQ(my_qp)) ipz_queue_dtor(my_pd, &my_qp->ipz_squeue); kmem_cache_free(qp_cache, my_qp); + atomic_dec(&shca->num_qps); return 0; } diff --git a/drivers/infiniband/hw/ipath/ipath_mr.c b/drivers/infiniband/hw/ipath/ipath_mr.c index db4ba92f79fc..9d343b7c2f3b 100644 --- a/drivers/infiniband/hw/ipath/ipath_mr.c +++ b/drivers/infiniband/hw/ipath/ipath_mr.c @@ -195,7 +195,8 @@ struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, goto bail; } - umem = ib_umem_get(pd->uobject->context, start, length, mr_access_flags); + umem = ib_umem_get(pd->uobject->context, start, length, + mr_access_flags, 0); if (IS_ERR(umem)) return (void *) umem; diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c index 5e570bb0bb6f..2f199c5c4a72 100644 --- a/drivers/infiniband/hw/mlx4/cq.c +++ b/drivers/infiniband/hw/mlx4/cq.c @@ -137,7 +137,7 @@ static int mlx4_ib_get_cq_umem(struct mlx4_ib_dev *dev, struct ib_ucontext *cont int err; *umem = ib_umem_get(context, buf_addr, cqe * sizeof (struct mlx4_cqe), - IB_ACCESS_LOCAL_WRITE); + IB_ACCESS_LOCAL_WRITE, 1); if (IS_ERR(*umem)) return PTR_ERR(*umem); @@ -221,7 +221,7 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector } err = mlx4_cq_alloc(dev->dev, entries, &cq->buf.mtt, uar, - cq->db.dma, &cq->mcq); + cq->db.dma, &cq->mcq, 0); if (err) goto err_dbmap; diff --git a/drivers/infiniband/hw/mlx4/doorbell.c b/drivers/infiniband/hw/mlx4/doorbell.c index 8e342cc9baec..8aee4233b388 100644 --- a/drivers/infiniband/hw/mlx4/doorbell.c +++ b/drivers/infiniband/hw/mlx4/doorbell.c @@ -63,7 +63,7 @@ int mlx4_ib_db_map_user(struct mlx4_ib_ucontext *context, unsigned long virt, page->user_virt = (virt & PAGE_MASK); page->refcnt = 0; page->umem = ib_umem_get(&context->ibucontext, virt & PAGE_MASK, - PAGE_SIZE, 0); + PAGE_SIZE, 0, 0); if (IS_ERR(page->umem)) { err = PTR_ERR(page->umem); kfree(page); diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c index fe2c2e94a5f8..68e92485fc76 100644 --- a/drivers/infiniband/hw/mlx4/mr.c +++ b/drivers/infiniband/hw/mlx4/mr.c @@ -132,7 +132,8 @@ struct ib_mr *mlx4_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, if (!mr) return ERR_PTR(-ENOMEM); - mr->umem = ib_umem_get(pd->uobject->context, start, length, access_flags); + mr->umem = ib_umem_get(pd->uobject->context, start, length, + access_flags, 0); if (IS_ERR(mr->umem)) { err = PTR_ERR(mr->umem); goto err_free; diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index 80ea8b9e7761..8e02ecfec188 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -482,7 +482,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, goto err; qp->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr, - qp->buf_size, 0); + qp->buf_size, 0, 0); if (IS_ERR(qp->umem)) { err = PTR_ERR(qp->umem); goto err; diff --git a/drivers/infiniband/hw/mlx4/srq.c b/drivers/infiniband/hw/mlx4/srq.c index 204619702f9d..12d6bc6f8007 100644 --- a/drivers/infiniband/hw/mlx4/srq.c +++ b/drivers/infiniband/hw/mlx4/srq.c @@ -109,7 +109,7 @@ struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd, } srq->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr, - buf_size, 0); + buf_size, 0, 0); if (IS_ERR(srq->umem)) { err = PTR_ERR(srq->umem); goto err_srq; diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c index 3538da16e3fe..820205dec560 100644 --- a/drivers/infiniband/hw/mthca/mthca_mr.c +++ b/drivers/infiniband/hw/mthca/mthca_mr.c @@ -818,15 +818,9 @@ int mthca_arbel_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, void mthca_tavor_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr) { - u32 key; - if (!fmr->maps) return; - key = tavor_key_to_hw_index(fmr->ibmr.lkey); - key &= dev->limits.num_mpts - 1; - fmr->ibmr.lkey = fmr->ibmr.rkey = tavor_hw_index_to_key(key); - fmr->maps = 0; writeb(MTHCA_MPT_STATUS_SW, fmr->mem.tavor.mpt); @@ -834,16 +828,9 @@ void mthca_tavor_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr) void mthca_arbel_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr) { - u32 key; - if (!fmr->maps) return; - key = arbel_key_to_hw_index(fmr->ibmr.lkey); - key &= dev->limits.num_mpts - 1; - key = adjust_key(dev, key); - fmr->ibmr.lkey = fmr->ibmr.rkey = arbel_hw_index_to_key(key); - fmr->maps = 0; *(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_SW; diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 696e1f302332..be34f99ca625 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -39,6 +39,8 @@ #include <rdma/ib_smi.h> #include <rdma/ib_umem.h> #include <rdma/ib_user_verbs.h> + +#include <linux/sched.h> #include <linux/mm.h> #include "mthca_dev.h" @@ -367,6 +369,8 @@ static struct ib_ucontext *mthca_alloc_ucontext(struct ib_device *ibdev, return ERR_PTR(-EFAULT); } + context->reg_mr_warned = 0; + return &context->ibucontext; } @@ -1006,17 +1010,31 @@ static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, struct mthca_dev *dev = to_mdev(pd->device); struct ib_umem_chunk *chunk; struct mthca_mr *mr; + struct mthca_reg_mr ucmd; u64 *pages; int shift, n, len; int i, j, k; int err = 0; int write_mtt_size; + if (udata->inlen - sizeof (struct ib_uverbs_cmd_hdr) < sizeof ucmd) { + if (!to_mucontext(pd->uobject->context)->reg_mr_warned) { + mthca_warn(dev, "Process '%s' did not pass in MR attrs.\n", + current->comm); + mthca_warn(dev, " Update libmthca to fix this.\n"); + } + ++to_mucontext(pd->uobject->context)->reg_mr_warned; + ucmd.mr_attrs = 0; + } else if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd)) + return ERR_PTR(-EFAULT); + mr = kmalloc(sizeof *mr, GFP_KERNEL); if (!mr) return ERR_PTR(-ENOMEM); - mr->umem = ib_umem_get(pd->uobject->context, start, length, acc); + mr->umem = ib_umem_get(pd->uobject->context, start, length, acc, + ucmd.mr_attrs & MTHCA_MR_DMASYNC); + if (IS_ERR(mr->umem)) { err = PTR_ERR(mr->umem); goto err; diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h index 262616c8ebb6..934bf9544037 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.h +++ b/drivers/infiniband/hw/mthca/mthca_provider.h @@ -67,6 +67,7 @@ struct mthca_ucontext { struct ib_ucontext ibucontext; struct mthca_uar uar; struct mthca_user_db_table *db_tab; + int reg_mr_warned; }; struct mthca_mtt; diff --git a/drivers/infiniband/hw/mthca/mthca_user.h b/drivers/infiniband/hw/mthca/mthca_user.h index 02cc0a766f3a..e1262c942db8 100644 --- a/drivers/infiniband/hw/mthca/mthca_user.h +++ b/drivers/infiniband/hw/mthca/mthca_user.h @@ -61,6 +61,16 @@ struct mthca_alloc_pd_resp { __u32 reserved; }; +struct mthca_reg_mr { +/* + * Mark the memory region with a DMA attribute that causes + * in-flight DMA to be flushed when the region is written to: + */ +#define MTHCA_MR_DMASYNC 0x1 + __u32 mr_attrs; + __u32 reserved; +}; + struct mthca_create_cq { __u32 lkey; __u32 pdn; diff --git a/drivers/infiniband/hw/nes/Kconfig b/drivers/infiniband/hw/nes/Kconfig index 2aeb7ac972a9..d449eb6ec78e 100644 --- a/drivers/infiniband/hw/nes/Kconfig +++ b/drivers/infiniband/hw/nes/Kconfig @@ -2,6 +2,7 @@ config INFINIBAND_NES tristate "NetEffect RNIC Driver" depends on PCI && INET && INFINIBAND select LIBCRC32C + select INET_LRO ---help--- This is a low-level driver for NetEffect RDMA enabled Network Interface Cards (RNIC). diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c index a4e9269a29bd..9f7364a9096d 100644 --- a/drivers/infiniband/hw/nes/nes.c +++ b/drivers/infiniband/hw/nes/nes.c @@ -91,6 +91,10 @@ unsigned int nes_debug_level = 0; module_param_named(debug_level, nes_debug_level, uint, 0644); MODULE_PARM_DESC(debug_level, "Enable debug output level"); +unsigned int nes_lro_max_aggr = NES_LRO_MAX_AGGR; +module_param(nes_lro_max_aggr, int, NES_LRO_MAX_AGGR); +MODULE_PARM_DESC(nes_mro_max_aggr, " nic LRO MAX packet aggregation"); + LIST_HEAD(nes_adapter_list); static LIST_HEAD(nes_dev_list); diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h index cdf2e9ad62f7..1f9f7bf73862 100644 --- a/drivers/infiniband/hw/nes/nes.h +++ b/drivers/infiniband/hw/nes/nes.h @@ -173,6 +173,7 @@ extern int disable_mpa_crc; extern unsigned int send_first; extern unsigned int nes_drv_opt; extern unsigned int nes_debug_level; +extern unsigned int nes_lro_max_aggr; extern struct list_head nes_adapter_list; @@ -535,8 +536,8 @@ int nes_register_ofa_device(struct nes_ib_device *); int nes_read_eeprom_values(struct nes_device *, struct nes_adapter *); void nes_write_1G_phy_reg(struct nes_device *, u8, u8, u16); void nes_read_1G_phy_reg(struct nes_device *, u8, u8, u16 *); -void nes_write_10G_phy_reg(struct nes_device *, u16, u8, u16); -void nes_read_10G_phy_reg(struct nes_device *, u16, u8); +void nes_write_10G_phy_reg(struct nes_device *, u16, u8, u16, u16); +void nes_read_10G_phy_reg(struct nes_device *, u8, u8, u16); struct nes_cqp_request *nes_get_cqp_request(struct nes_device *); void nes_post_cqp_request(struct nes_device *, struct nes_cqp_request *, int); int nes_arp_table(struct nes_device *, u32, u8 *, u32); diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index d940fc27129a..9a4b40fae40d 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -594,7 +594,7 @@ static void nes_cm_timer_tick(unsigned long pass) continue; } /* this seems like the correct place, but leave send entry unprotected */ - // spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); + /* spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); */ atomic_inc(&send_entry->skb->users); cm_packets_retrans++; nes_debug(NES_DBG_CM, "Retransmitting send_entry %p for node %p," @@ -1335,7 +1335,7 @@ static int process_packet(struct nes_cm_node *cm_node, struct sk_buff *skb, cm_node->loc_addr, cm_node->loc_port, cm_node->rem_addr, cm_node->rem_port, cm_node->state, atomic_read(&cm_node->ref_count)); - // create event + /* create event */ cm_node->state = NES_CM_STATE_CLOSED; create_event(cm_node, NES_CM_EVENT_ABORTED); @@ -1669,7 +1669,7 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core, if (!cm_node) return NULL; - // set our node side to client (active) side + /* set our node side to client (active) side */ cm_node->tcp_cntxt.client = 1; cm_node->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE; @@ -1694,7 +1694,7 @@ static struct nes_cm_node *mini_cm_connect(struct nes_cm_core *cm_core, loopbackremotenode->mpa_frame_size = mpa_frame_size - sizeof(struct ietf_mpa_frame); - // we are done handling this state, set node to a TSA state + /* we are done handling this state, set node to a TSA state */ cm_node->state = NES_CM_STATE_TSA; cm_node->tcp_cntxt.rcv_nxt = loopbackremotenode->tcp_cntxt.loc_seq_num; loopbackremotenode->tcp_cntxt.rcv_nxt = cm_node->tcp_cntxt.loc_seq_num; diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 08964cc7e98a..8dc70f9bad2f 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -38,6 +38,7 @@ #include <linux/ip.h> #include <linux/tcp.h> #include <linux/if_vlan.h> +#include <linux/inet_lro.h> #include "nes.h" @@ -832,7 +833,7 @@ static void nes_init_csr_ne020(struct nes_device *nesdev, u8 hw_rev, u8 port_cou nes_write_indexed(nesdev, 0x00000900, 0x20000001); nes_write_indexed(nesdev, 0x000060C0, 0x0000028e); nes_write_indexed(nesdev, 0x000060C8, 0x00000020); - // + nes_write_indexed(nesdev, 0x000001EC, 0x7b2625a0); /* nes_write_indexed(nesdev, 0x000001EC, 0x5f2625a0); */ @@ -1207,11 +1208,16 @@ int nes_init_phy(struct nes_device *nesdev) { struct nes_adapter *nesadapter = nesdev->nesadapter; u32 counter = 0; + u32 sds_common_control0; u32 mac_index = nesdev->mac_index; - u32 tx_config; + u32 tx_config = 0; u16 phy_data; + u32 temp_phy_data = 0; + u32 temp_phy_data2 = 0; + u32 i = 0; - if (nesadapter->OneG_Mode) { + if ((nesadapter->OneG_Mode) && + (nesadapter->phy_type[mac_index] != NES_PHY_TYPE_PUMA_1G)) { nes_debug(NES_DBG_PHY, "1G PHY, mac_index = %d.\n", mac_index); if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_1G) { printk(PFX "%s: Programming mdc config for 1G\n", __func__); @@ -1223,7 +1229,7 @@ int nes_init_phy(struct nes_device *nesdev) nes_read_1G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index], &phy_data); nes_debug(NES_DBG_PHY, "Phy data from register 1 phy address %u = 0x%X.\n", nesadapter->phy_index[mac_index], phy_data); - nes_write_1G_phy_reg(nesdev, 23, nesadapter->phy_index[mac_index], 0xb000); + nes_write_1G_phy_reg(nesdev, 23, nesadapter->phy_index[mac_index], 0xb000); /* Reset the PHY */ nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], 0x8000); @@ -1277,12 +1283,126 @@ int nes_init_phy(struct nes_device *nesdev) nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], &phy_data); nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], phy_data | 0x0300); } else { - if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_IRIS) { + if ((nesadapter->phy_type[mac_index] == NES_PHY_TYPE_IRIS) || + (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_ARGUS)) { /* setup 10G MDIO operation */ tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG); tx_config |= 0x14; nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config); } + if ((nesadapter->phy_type[mac_index] == NES_PHY_TYPE_ARGUS)) { + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7ee); + + temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + mdelay(10); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7ee); + temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + + /* + * if firmware is already running (like from a + * driver un-load/load, don't do anything. + */ + if (temp_phy_data == temp_phy_data2) { + /* configure QT2505 AMCC PHY */ + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0x0000, 0x8000); + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc300, 0x0000); + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc302, 0x0044); + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc318, 0x0052); + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc319, 0x0008); + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc31a, 0x0098); + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0026, 0x0E00); + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0027, 0x0000); + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0028, 0xA528); + + /* + * remove micro from reset; chip boots from ROM, + * uploads EEPROM f/w image, uC executes f/w + */ + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc300, 0x0002); + + /* + * wait for heart beat to start to + * know loading is done + */ + counter = 0; + do { + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7ee); + temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + if (counter++ > 1000) { + nes_debug(NES_DBG_PHY, "AMCC PHY- breaking from heartbeat check <this is bad!!!> \n"); + break; + } + mdelay(100); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7ee); + temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + } while ((temp_phy_data2 == temp_phy_data)); + + /* + * wait for tracking to start to know + * f/w is good to go + */ + counter = 0; + do { + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7fd); + temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + if (counter++ > 1000) { + nes_debug(NES_DBG_PHY, "AMCC PHY- breaking from status check <this is bad!!!> \n"); + break; + } + mdelay(1000); + /* + * nes_debug(NES_DBG_PHY, "AMCC PHY- phy_status not ready yet = 0x%02X\n", + * temp_phy_data); + */ + } while (((temp_phy_data & 0xff) != 0x50) && ((temp_phy_data & 0xff) != 0x70)); + + /* set LOS Control invert RXLOSB_I_PADINV */ + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xd003, 0x0000); + /* set LOS Control to mask of RXLOSB_I */ + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc314, 0x0042); + /* set LED1 to input mode (LED1 and LED2 share same LED) */ + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xd006, 0x0007); + /* set LED2 to RX link_status and activity */ + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xd007, 0x000A); + /* set LED3 to RX link_status */ + nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xd008, 0x0009); + + /* + * reset the res-calibration on t2 + * serdes; ensures it is stable after + * the amcc phy is stable + */ + + sds_common_control0 = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0); + sds_common_control0 |= 0x1; + nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, sds_common_control0); + + /* release the res-calibration reset */ + sds_common_control0 &= 0xfffffffe; + nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, sds_common_control0); + + i = 0; + while (((nes_read32(nesdev->regs + NES_SOFTWARE_RESET) & 0x00000040) != 0x00000040) + && (i++ < 5000)) { + /* mdelay(1); */ + } + + /* + * wait for link train done before moving on, + * or will get an interupt storm + */ + counter = 0; + do { + temp_phy_data = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + + (0x200 * (nesdev->mac_index & 1))); + if (counter++ > 1000) { + nes_debug(NES_DBG_PHY, "AMCC PHY- breaking from link train wait <this is bad, link didnt train!!!>\n"); + break; + } + mdelay(1); + } while (((temp_phy_data & 0x0f1f0000) != 0x0f0f0000)); + } + } } return 0; } @@ -1375,6 +1495,25 @@ static void nes_rq_wqes_timeout(unsigned long parm) } +static int nes_lro_get_skb_hdr(struct sk_buff *skb, void **iphdr, + void **tcph, u64 *hdr_flags, void *priv) +{ + unsigned int ip_len; + struct iphdr *iph; + skb_reset_network_header(skb); + iph = ip_hdr(skb); + if (iph->protocol != IPPROTO_TCP) + return -1; + ip_len = ip_hdrlen(skb); + skb_set_transport_header(skb, ip_len); + *tcph = tcp_hdr(skb); + + *hdr_flags = LRO_IPV4 | LRO_TCP; + *iphdr = iph; + return 0; +} + + /** * nes_init_nic_qp */ @@ -1520,10 +1659,10 @@ int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev) } u64temp = (u64)nesvnic->nic.sq_pbase; - nic_context->context_words[NES_NIC_CTX_SQ_LOW_IDX] = cpu_to_le32((u32)u64temp); + nic_context->context_words[NES_NIC_CTX_SQ_LOW_IDX] = cpu_to_le32((u32)u64temp); nic_context->context_words[NES_NIC_CTX_SQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32)); u64temp = (u64)nesvnic->nic.rq_pbase; - nic_context->context_words[NES_NIC_CTX_RQ_LOW_IDX] = cpu_to_le32((u32)u64temp); + nic_context->context_words[NES_NIC_CTX_RQ_LOW_IDX] = cpu_to_le32((u32)u64temp); nic_context->context_words[NES_NIC_CTX_RQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32)); cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_CREATE_QP | @@ -1575,7 +1714,7 @@ int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev) nic_rqe = &nesvnic->nic.rq_vbase[counter]; nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] = cpu_to_le32(nesvnic->max_frame_size); nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_3_2_IDX] = 0; - nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] = cpu_to_le32((u32)pmem); + nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] = cpu_to_le32((u32)pmem); nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX] = cpu_to_le32((u32)((u64)pmem >> 32)); nesvnic->nic.rx_skb[counter] = skb; } @@ -1592,15 +1731,21 @@ int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev) nesvnic->rq_wqes_timer.function = nes_rq_wqes_timeout; nesvnic->rq_wqes_timer.data = (unsigned long)nesvnic; nes_debug(NES_DBG_INIT, "NAPI support Enabled\n"); - if (nesdev->nesadapter->et_use_adaptive_rx_coalesce) { nes_nic_init_timer(nesdev); if (netdev->mtu > 1500) jumbomode = 1; - nes_nic_init_timer_defaults(nesdev, jumbomode); - } - + nes_nic_init_timer_defaults(nesdev, jumbomode); + } + nesvnic->lro_mgr.max_aggr = NES_LRO_MAX_AGGR; + nesvnic->lro_mgr.max_desc = NES_MAX_LRO_DESCRIPTORS; + nesvnic->lro_mgr.lro_arr = nesvnic->lro_desc; + nesvnic->lro_mgr.get_skb_header = nes_lro_get_skb_hdr; + nesvnic->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID; + nesvnic->lro_mgr.dev = netdev; + nesvnic->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY; + nesvnic->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; return 0; } @@ -1620,8 +1765,8 @@ void nes_destroy_nic_qp(struct nes_vnic *nesvnic) /* Free remaining NIC receive buffers */ while (nesvnic->nic.rq_head != nesvnic->nic.rq_tail) { - nic_rqe = &nesvnic->nic.rq_vbase[nesvnic->nic.rq_tail]; - wqe_frag = (u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]); + nic_rqe = &nesvnic->nic.rq_vbase[nesvnic->nic.rq_tail]; + wqe_frag = (u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]); wqe_frag |= ((u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX])) << 32; pci_unmap_single(nesdev->pcidev, (dma_addr_t)wqe_frag, nesvnic->max_frame_size, PCI_DMA_FROMDEVICE); @@ -1704,17 +1849,17 @@ int nes_napi_isr(struct nes_device *nesdev) /* iff NIC, process here, else wait for DPC */ if ((int_stat) && ((int_stat & 0x0000ff00) == int_stat)) { nesdev->napi_isr_ran = 0; - nes_write32(nesdev->regs+NES_INT_STAT, - (int_stat & - ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3))); + nes_write32(nesdev->regs + NES_INT_STAT, + (int_stat & + ~(NES_INT_INTF | NES_INT_TIMER | NES_INT_MAC0 | NES_INT_MAC1 | NES_INT_MAC2 | NES_INT_MAC3))); /* Process the CEQs */ nes_process_ceq(nesdev, &nesdev->nesadapter->ceq[nesdev->nic_ceq_index]); if (unlikely((((nesadapter->et_rx_coalesce_usecs_irq) && - (!nesadapter->et_use_adaptive_rx_coalesce)) || - ((nesadapter->et_use_adaptive_rx_coalesce) && - (nesdev->deepcq_count > nesadapter->et_pkt_rate_low)))) ) { + (!nesadapter->et_use_adaptive_rx_coalesce)) || + ((nesadapter->et_use_adaptive_rx_coalesce) && + (nesdev->deepcq_count > nesadapter->et_pkt_rate_low))))) { if ((nesdev->int_req & NES_INT_TIMER) == 0) { /* Enable Periodic timer interrupts */ nesdev->int_req |= NES_INT_TIMER; @@ -1792,12 +1937,12 @@ void nes_dpc(unsigned long param) } if (int_stat) { - if (int_stat & ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0| - NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3)) { + if (int_stat & ~(NES_INT_INTF | NES_INT_TIMER | NES_INT_MAC0| + NES_INT_MAC1|NES_INT_MAC2 | NES_INT_MAC3)) { /* Ack the interrupts */ nes_write32(nesdev->regs+NES_INT_STAT, - (int_stat & ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0| - NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3))); + (int_stat & ~(NES_INT_INTF | NES_INT_TIMER | NES_INT_MAC0| + NES_INT_MAC1 | NES_INT_MAC2 | NES_INT_MAC3))); } temp_int_stat = int_stat; @@ -1862,8 +2007,8 @@ void nes_dpc(unsigned long param) } } /* Don't use the interface interrupt bit stay in loop */ - int_stat &= ~NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0| - NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3; + int_stat &= ~NES_INT_INTF | NES_INT_TIMER | NES_INT_MAC0 | + NES_INT_MAC1 | NES_INT_MAC2 | NES_INT_MAC3; } while ((int_stat != 0) && (loop_counter++ < MAX_DPC_ITERATIONS)); if (timer_ints == 1) { @@ -1874,9 +2019,9 @@ void nes_dpc(unsigned long param) nesdev->timer_only_int_count = 0; nesdev->int_req &= ~NES_INT_TIMER; nes_write32(nesdev->regs + NES_INTF_INT_MASK, ~(nesdev->intf_int_req)); - nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req); + nes_write32(nesdev->regs + NES_INT_MASK, ~nesdev->int_req); } else { - nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff|(~nesdev->int_req)); + nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff | (~nesdev->int_req)); } } else { if (unlikely(nesadapter->et_use_adaptive_rx_coalesce)) @@ -1884,7 +2029,7 @@ void nes_dpc(unsigned long param) nes_nic_init_timer(nesdev); } nesdev->timer_only_int_count = 0; - nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff|(~nesdev->int_req)); + nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff | (~nesdev->int_req)); } } else { nesdev->timer_only_int_count = 0; @@ -1933,7 +2078,7 @@ static void nes_process_ceq(struct nes_device *nesdev, struct nes_hw_ceq *ceq) do { if (le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX]) & NES_CEQE_VALID) { - u64temp = (((u64)(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX])))<<32) | + u64temp = (((u64)(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX]))) << 32) | ((u64)(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_LOW_IDX]))); u64temp <<= 1; cq = *((struct nes_hw_cq **)&u64temp); @@ -1961,7 +2106,7 @@ static void nes_process_ceq(struct nes_device *nesdev, struct nes_hw_ceq *ceq) */ static void nes_process_aeq(struct nes_device *nesdev, struct nes_hw_aeq *aeq) { -// u64 u64temp; + /* u64 u64temp; */ u32 head; u32 aeq_size; u32 aeqe_misc; @@ -1980,8 +2125,10 @@ static void nes_process_aeq(struct nes_device *nesdev, struct nes_hw_aeq *aeq) if (aeqe_misc & (NES_AEQE_QP|NES_AEQE_CQ)) { if (aeqe_cq_id >= NES_FIRST_QPN) { /* dealing with an accelerated QP related AE */ -// u64temp = (((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])))<<32) | -// ((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]))); + /* + * u64temp = (((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX]))) << 32) | + * ((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]))); + */ nes_process_iwarp_aeqe(nesdev, (struct nes_hw_aeqe *)aeqe); } else { /* TODO: dealing with a CQP related AE */ @@ -2081,6 +2228,8 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) u32 u32temp; u16 phy_data; u16 temp_phy_data; + u32 pcs_val = 0x0f0f0000; + u32 pcs_mask = 0x0f1f0000; spin_lock_irqsave(&nesadapter->phy_lock, flags); if (nesadapter->mac_sw_state[mac_number] != NES_MAC_SW_IDLE) { @@ -2144,13 +2293,30 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) nes_debug(NES_DBG_PHY, "Eth SERDES Common Status: 0=0x%08X, 1=0x%08X\n", nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0), nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0+0x200)); - pcs_control_status = nes_read_indexed(nesdev, - NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index&1)*0x200)); - pcs_control_status = nes_read_indexed(nesdev, - NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index&1)*0x200)); + + if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_PUMA_1G) { + switch (mac_index) { + case 1: + case 3: + pcs_control_status = nes_read_indexed(nesdev, + NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200); + break; + default: + pcs_control_status = nes_read_indexed(nesdev, + NES_IDX_PHY_PCS_CONTROL_STATUS0); + break; + } + } else { + pcs_control_status = nes_read_indexed(nesdev, + NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index & 1) * 0x200)); + pcs_control_status = nes_read_indexed(nesdev, + NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index & 1) * 0x200)); + } + nes_debug(NES_DBG_PHY, "PCS PHY Control/Status%u: 0x%08X\n", mac_index, pcs_control_status); - if (nesadapter->OneG_Mode) { + if ((nesadapter->OneG_Mode) && + (nesadapter->phy_type[mac_index] != NES_PHY_TYPE_PUMA_1G)) { u32temp = 0x01010000; if (nesadapter->port_count > 2) { u32temp |= 0x02020000; @@ -2159,24 +2325,59 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) phy_data = 0; nes_debug(NES_DBG_PHY, "PCS says the link is down\n"); } - } else if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_IRIS) { - nes_read_10G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index]); - temp_phy_data = (u16)nes_read_indexed(nesdev, - NES_IDX_MAC_MDIO_CONTROL); - u32temp = 20; - do { - nes_read_10G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index]); - phy_data = (u16)nes_read_indexed(nesdev, - NES_IDX_MAC_MDIO_CONTROL); - if ((phy_data == temp_phy_data) || (!(--u32temp))) - break; - temp_phy_data = phy_data; - } while (1); - nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n", - __func__, phy_data, nesadapter->mac_link_down ? "DOWN" : "UP"); - } else { - phy_data = (0x0f0f0000 == (pcs_control_status & 0x0f1f0000)) ? 4 : 0; + switch (nesadapter->phy_type[mac_index]) { + case NES_PHY_TYPE_IRIS: + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1); + temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + u32temp = 20; + do { + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1); + phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + if ((phy_data == temp_phy_data) || (!(--u32temp))) + break; + temp_phy_data = phy_data; + } while (1); + nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n", + __func__, phy_data, nesadapter->mac_link_down[mac_index] ? "DOWN" : "UP"); + break; + + case NES_PHY_TYPE_ARGUS: + /* clear the alarms */ + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0x0008); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc001); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc002); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc005); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc006); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9003); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9004); + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9005); + /* check link status */ + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1); + temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + u32temp = 100; + do { + nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1); + + phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); + if ((phy_data == temp_phy_data) || (!(--u32temp))) + break; + temp_phy_data = phy_data; + } while (1); + nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n", + __func__, phy_data, nesadapter->mac_link_down ? "DOWN" : "UP"); + break; + + case NES_PHY_TYPE_PUMA_1G: + if (mac_index < 2) + pcs_val = pcs_mask = 0x01010000; + else + pcs_val = pcs_mask = 0x02020000; + /* fall through */ + default: + phy_data = (pcs_val == (pcs_control_status & pcs_mask)) ? 0x4 : 0x0; + break; + } } if (phy_data & 0x0004) { @@ -2185,8 +2386,8 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) nes_debug(NES_DBG_PHY, "The Link is UP!!. linkup was %d\n", nesvnic->linkup); if (nesvnic->linkup == 0) { - printk(PFX "The Link is now up for port %u, netdev %p.\n", - mac_index, nesvnic->netdev); + printk(PFX "The Link is now up for port %s, netdev %p.\n", + nesvnic->netdev->name, nesvnic->netdev); if (netif_queue_stopped(nesvnic->netdev)) netif_start_queue(nesvnic->netdev); nesvnic->linkup = 1; @@ -2199,8 +2400,8 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number) nes_debug(NES_DBG_PHY, "The Link is Down!!. linkup was %d\n", nesvnic->linkup); if (nesvnic->linkup == 1) { - printk(PFX "The Link is now down for port %u, netdev %p.\n", - mac_index, nesvnic->netdev); + printk(PFX "The Link is now down for port %s, netdev %p.\n", + nesvnic->netdev->name, nesvnic->netdev); if (!(netif_queue_stopped(nesvnic->netdev))) netif_stop_queue(nesvnic->netdev); nesvnic->linkup = 0; @@ -2254,10 +2455,13 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) u16 pkt_type; u16 rqes_processed = 0; u8 sq_cqes = 0; + u8 nes_use_lro = 0; head = cq->cq_head; cq_size = cq->cq_size; cq->cqes_pending = 1; + if (nesvnic->netdev->features & NETIF_F_LRO) + nes_use_lro = 1; do { if (le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX]) & NES_NIC_CQE_VALID) { @@ -2272,8 +2476,10 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) /* bump past the vlan tag */ wqe_fragment_length++; if (le16_to_cpu(wqe_fragment_length[wqe_fragment_index]) != 0) { - u64temp = (u64) le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX+wqe_fragment_index*2]); - u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX+wqe_fragment_index*2]))<<32; + u64temp = (u64) le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX + + wqe_fragment_index * 2]); + u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX + + wqe_fragment_index * 2])) << 32; bus_address = (dma_addr_t)u64temp; if (test_and_clear_bit(nesnic->sq_tail, nesnic->first_frag_overflow)) { pci_unmap_single(nesdev->pcidev, @@ -2283,8 +2489,10 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) } for (; wqe_fragment_index < 5; wqe_fragment_index++) { if (wqe_fragment_length[wqe_fragment_index]) { - u64temp = le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX+wqe_fragment_index*2]); - u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX+wqe_fragment_index*2]))<<32; + u64temp = le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX + + wqe_fragment_index * 2]); + u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX + + wqe_fragment_index * 2])) <<32; bus_address = (dma_addr_t)u64temp; pci_unmap_page(nesdev->pcidev, bus_address, @@ -2331,7 +2539,7 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) if (atomic_read(&nesvnic->rx_skbs_needed) > (nesvnic->nic.rq_size>>1)) { nes_write32(nesdev->regs+NES_CQE_ALLOC, cq->cq_number | (cqe_count << 16)); -// nesadapter->tune_timer.cq_count += cqe_count; + /* nesadapter->tune_timer.cq_count += cqe_count; */ nesdev->currcq_count += cqe_count; cqe_count = 0; nes_replenish_nic_rq(nesvnic); @@ -2379,9 +2587,16 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) >> 16); nes_debug(NES_DBG_CQ, "%s: Reporting stripped VLAN packet. Tag = 0x%04X\n", nesvnic->netdev->name, vlan_tag); - nes_vlan_rx(rx_skb, nesvnic->vlan_grp, vlan_tag); + if (nes_use_lro) + lro_vlan_hwaccel_receive_skb(&nesvnic->lro_mgr, rx_skb, + nesvnic->vlan_grp, vlan_tag, NULL); + else + nes_vlan_rx(rx_skb, nesvnic->vlan_grp, vlan_tag); } else { - nes_netif_rx(rx_skb); + if (nes_use_lro) + lro_receive_skb(&nesvnic->lro_mgr, rx_skb, NULL); + else + nes_netif_rx(rx_skb); } } @@ -2399,7 +2614,7 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) /* Replenish Nic CQ */ nes_write32(nesdev->regs+NES_CQE_ALLOC, cq->cq_number | (cqe_count << 16)); -// nesdev->nesadapter->tune_timer.cq_count += cqe_count; + /* nesdev->nesadapter->tune_timer.cq_count += cqe_count; */ nesdev->currcq_count += cqe_count; cqe_count = 0; } @@ -2413,26 +2628,27 @@ void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq) } while (1); + if (nes_use_lro) + lro_flush_all(&nesvnic->lro_mgr); if (sq_cqes) { barrier(); /* restart the queue if it had been stopped */ if (netif_queue_stopped(nesvnic->netdev)) netif_wake_queue(nesvnic->netdev); } - cq->cq_head = head; /* nes_debug(NES_DBG_CQ, "CQ%u Processed = %u cqes, new head = %u.\n", cq->cq_number, cqe_count, cq->cq_head); */ cq->cqe_allocs_pending = cqe_count; if (unlikely(nesadapter->et_use_adaptive_rx_coalesce)) { -// nesdev->nesadapter->tune_timer.cq_count += cqe_count; + /* nesdev->nesadapter->tune_timer.cq_count += cqe_count; */ nesdev->currcq_count += cqe_count; nes_nic_tune_timer(nesdev); } if (atomic_read(&nesvnic->rx_skbs_needed)) nes_replenish_nic_rq(nesvnic); - } +} /** @@ -2461,7 +2677,7 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq) if (le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]) & NES_CQE_VALID) { u64temp = (((u64)(le32_to_cpu(cq->cq_vbase[head]. - cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX])))<<32) | + cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX]))) << 32) | ((u64)(le32_to_cpu(cq->cq_vbase[head]. cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]))); cqp = *((struct nes_hw_cqp **)&u64temp); @@ -2478,7 +2694,7 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq) } u64temp = (((u64)(le32_to_cpu(nesdev->cqp.sq_vbase[cqp->sq_tail]. - wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX])))<<32) | + wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX]))) << 32) | ((u64)(le32_to_cpu(nesdev->cqp.sq_vbase[cqp->sq_tail]. wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX]))); cqp_request = *((struct nes_cqp_request **)&u64temp); @@ -2515,7 +2731,7 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq) } else { nes_debug(NES_DBG_CQP, "CQP request %p (opcode 0x%02X) freed.\n", cqp_request, - le32_to_cpu(cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_OPCODE_IDX])&0x3f); + le32_to_cpu(cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_OPCODE_IDX]) & 0x3f); if (cqp_request->dynamic) { kfree(cqp_request); } else { @@ -2529,7 +2745,7 @@ static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq) } cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0; - nes_write32(nesdev->regs+NES_CQE_ALLOC, cq->cq_number | (1 << 16)); + nes_write32(nesdev->regs + NES_CQE_ALLOC, cq->cq_number | (1 << 16)); if (++cqp->sq_tail >= cqp->sq_size) cqp->sq_tail = 0; @@ -2598,13 +2814,13 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, nes_debug(NES_DBG_AEQ, "\n"); aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]); if ((NES_AEQE_INBOUND_RDMA&aeq_info) || (!(NES_AEQE_QP&aeq_info))) { - context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]); + context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]); context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32; } else { aeqe_context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]); aeqe_context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32; context = (unsigned long)nesadapter->qp_table[le32_to_cpu( - aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN]; + aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]) - NES_FIRST_QPN]; BUG_ON(!context); } @@ -2617,7 +2833,6 @@ static void nes_process_iwarp_aeqe(struct nes_device *nesdev, le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]), aeqe, nes_tcp_state_str[tcp_state], nes_iwarp_state_str[iwarp_state]); - switch (async_event_id) { case NES_AEQE_AEID_LLP_FIN_RECEIVED: nesqp = *((struct nes_qp **)&context); @@ -3021,7 +3236,7 @@ void nes_manage_arp_cache(struct net_device *netdev, unsigned char *mac_addr, cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |= cpu_to_le32(NES_CQP_ARP_VALID); cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX] = cpu_to_le32( (((u32)mac_addr[2]) << 24) | (((u32)mac_addr[3]) << 16) | - (((u32)mac_addr[4]) << 8) | (u32)mac_addr[5]); + (((u32)mac_addr[4]) << 8) | (u32)mac_addr[5]); cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_HIGH_IDX] = cpu_to_le32( (((u32)mac_addr[0]) << 16) | (u32)mac_addr[1]); } else { diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h index 8f36e231bdf5..745bf94f3f07 100644 --- a/drivers/infiniband/hw/nes/nes_hw.h +++ b/drivers/infiniband/hw/nes/nes_hw.h @@ -33,8 +33,12 @@ #ifndef __NES_HW_H #define __NES_HW_H -#define NES_PHY_TYPE_1G 2 -#define NES_PHY_TYPE_IRIS 3 +#include <linux/inet_lro.h> + +#define NES_PHY_TYPE_1G 2 +#define NES_PHY_TYPE_IRIS 3 +#define NES_PHY_TYPE_ARGUS 4 +#define NES_PHY_TYPE_PUMA_1G 5 #define NES_PHY_TYPE_PUMA_10G 6 #define NES_MULTICAST_PF_MAX 8 @@ -965,7 +969,7 @@ struct nes_arp_entry { #define NES_NIC_CQ_DOWNWARD_TREND 16 struct nes_hw_tune_timer { - //u16 cq_count; + /* u16 cq_count; */ u16 threshold_low; u16 threshold_target; u16 threshold_high; @@ -982,8 +986,10 @@ struct nes_hw_tune_timer { #define NES_TIMER_INT_LIMIT 2 #define NES_TIMER_INT_LIMIT_DYNAMIC 10 #define NES_TIMER_ENABLE_LIMIT 4 -#define NES_MAX_LINK_INTERRUPTS 128 -#define NES_MAX_LINK_CHECK 200 +#define NES_MAX_LINK_INTERRUPTS 128 +#define NES_MAX_LINK_CHECK 200 +#define NES_MAX_LRO_DESCRIPTORS 32 +#define NES_LRO_MAX_AGGR 64 struct nes_adapter { u64 fw_ver; @@ -1183,6 +1189,9 @@ struct nes_vnic { u8 of_device_registered; u8 rdma_enabled; u8 rx_checksum_disabled; + u32 lro_max_aggr; + struct net_lro_mgr lro_mgr; + struct net_lro_desc lro_desc[NES_MAX_LRO_DESCRIPTORS]; }; struct nes_ib_device { diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index e5366b013c1a..1b0938c87774 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -185,12 +185,13 @@ static int nes_netdev_open(struct net_device *netdev) nic_active |= nic_active_bit; nes_write_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON, nic_active); - macaddr_high = ((u16)netdev->dev_addr[0]) << 8; + macaddr_high = ((u16)netdev->dev_addr[0]) << 8; macaddr_high += (u16)netdev->dev_addr[1]; - macaddr_low = ((u32)netdev->dev_addr[2]) << 24; - macaddr_low += ((u32)netdev->dev_addr[3]) << 16; - macaddr_low += ((u32)netdev->dev_addr[4]) << 8; - macaddr_low += (u32)netdev->dev_addr[5]; + + macaddr_low = ((u32)netdev->dev_addr[2]) << 24; + macaddr_low += ((u32)netdev->dev_addr[3]) << 16; + macaddr_low += ((u32)netdev->dev_addr[4]) << 8; + macaddr_low += (u32)netdev->dev_addr[5]; /* Program the various MAC regs */ for (i = 0; i < NES_MAX_PORT_COUNT; i++) { @@ -451,7 +452,7 @@ static int nes_netdev_start_xmit(struct sk_buff *skb, struct net_device *netdev) __le16 *wqe_fragment_length; u32 nr_frags; u32 original_first_length; -// u64 *wqe_fragment_address; + /* u64 *wqe_fragment_address; */ /* first fragment (0) is used by copy buffer */ u16 wqe_fragment_index=1; u16 hoffset; @@ -461,11 +462,12 @@ static int nes_netdev_start_xmit(struct sk_buff *skb, struct net_device *netdev) u32 old_head; u32 wqe_misc; - /* nes_debug(NES_DBG_NIC_TX, "%s Request to tx NIC packet length %u, headlen %u," - " (%u frags), tso_size=%u\n", - netdev->name, skb->len, skb_headlen(skb), - skb_shinfo(skb)->nr_frags, skb_is_gso(skb)); - */ + /* + * nes_debug(NES_DBG_NIC_TX, "%s Request to tx NIC packet length %u, headlen %u," + * " (%u frags), tso_size=%u\n", + * netdev->name, skb->len, skb_headlen(skb), + * skb_shinfo(skb)->nr_frags, skb_is_gso(skb)); + */ if (!netif_carrier_ok(netdev)) return NETDEV_TX_OK; @@ -795,12 +797,12 @@ static int nes_netdev_set_mac_address(struct net_device *netdev, void *p) memcpy(netdev->dev_addr, mac_addr->sa_data, netdev->addr_len); printk(PFX "%s: Address length = %d, Address = %s\n", __func__, netdev->addr_len, print_mac(mac, mac_addr->sa_data)); - macaddr_high = ((u16)netdev->dev_addr[0]) << 8; + macaddr_high = ((u16)netdev->dev_addr[0]) << 8; macaddr_high += (u16)netdev->dev_addr[1]; - macaddr_low = ((u32)netdev->dev_addr[2]) << 24; - macaddr_low += ((u32)netdev->dev_addr[3]) << 16; - macaddr_low += ((u32)netdev->dev_addr[4]) << 8; - macaddr_low += (u32)netdev->dev_addr[5]; + macaddr_low = ((u32)netdev->dev_addr[2]) << 24; + macaddr_low += ((u32)netdev->dev_addr[3]) << 16; + macaddr_low += ((u32)netdev->dev_addr[4]) << 8; + macaddr_low += (u32)netdev->dev_addr[5]; for (i = 0; i < NES_MAX_PORT_COUNT; i++) { if (nesvnic->qp_nic_index[i] == 0xf) { @@ -881,12 +883,12 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev) print_mac(mac, multicast_addr->dmi_addr), perfect_filter_register_address+(mc_index * 8), mc_nic_index); - macaddr_high = ((u16)multicast_addr->dmi_addr[0]) << 8; + macaddr_high = ((u16)multicast_addr->dmi_addr[0]) << 8; macaddr_high += (u16)multicast_addr->dmi_addr[1]; - macaddr_low = ((u32)multicast_addr->dmi_addr[2]) << 24; - macaddr_low += ((u32)multicast_addr->dmi_addr[3]) << 16; - macaddr_low += ((u32)multicast_addr->dmi_addr[4]) << 8; - macaddr_low += (u32)multicast_addr->dmi_addr[5]; + macaddr_low = ((u32)multicast_addr->dmi_addr[2]) << 24; + macaddr_low += ((u32)multicast_addr->dmi_addr[3]) << 16; + macaddr_low += ((u32)multicast_addr->dmi_addr[4]) << 8; + macaddr_low += (u32)multicast_addr->dmi_addr[5]; nes_write_indexed(nesdev, perfect_filter_register_address+(mc_index * 8), macaddr_low); @@ -910,23 +912,23 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev) /** * nes_netdev_change_mtu */ -static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu) +static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu) { struct nes_vnic *nesvnic = netdev_priv(netdev); - struct nes_device *nesdev = nesvnic->nesdev; - int ret = 0; - u8 jumbomode=0; + struct nes_device *nesdev = nesvnic->nesdev; + int ret = 0; + u8 jumbomode = 0; - if ((new_mtu < ETH_ZLEN) || (new_mtu > max_mtu)) + if ((new_mtu < ETH_ZLEN) || (new_mtu > max_mtu)) return -EINVAL; - netdev->mtu = new_mtu; + netdev->mtu = new_mtu; nesvnic->max_frame_size = new_mtu + VLAN_ETH_HLEN; if (netdev->mtu > 1500) { jumbomode=1; } - nes_nic_init_timer_defaults(nesdev, jumbomode); + nes_nic_init_timer_defaults(nesdev, jumbomode); if (netif_running(netdev)) { nes_netdev_stop(netdev); @@ -936,8 +938,7 @@ static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu) return ret; } -#define NES_ETHTOOL_STAT_COUNT 55 -static const char nes_ethtool_stringset[NES_ETHTOOL_STAT_COUNT][ETH_GSTRING_LEN] = { +static const char nes_ethtool_stringset[][ETH_GSTRING_LEN] = { "Link Change Interrupts", "Linearized SKBs", "T/GSO Requests", @@ -993,8 +994,12 @@ static const char nes_ethtool_stringset[NES_ETHTOOL_STAT_COUNT][ETH_GSTRING_LEN] "CQ Depth 32", "CQ Depth 128", "CQ Depth 256", + "LRO aggregated", + "LRO flushed", + "LRO no_desc", }; +#define NES_ETHTOOL_STAT_COUNT ARRAY_SIZE(nes_ethtool_stringset) /** * nes_netdev_get_rx_csum @@ -1189,6 +1194,9 @@ static void nes_netdev_get_ethtool_stats(struct net_device *netdev, target_stat_values[52] = int_mod_cq_depth_32; target_stat_values[53] = int_mod_cq_depth_128; target_stat_values[54] = int_mod_cq_depth_256; + target_stat_values[55] = nesvnic->lro_mgr.stats.aggregated; + target_stat_values[56] = nesvnic->lro_mgr.stats.flushed; + target_stat_values[57] = nesvnic->lro_mgr.stats.no_desc; } @@ -1219,14 +1227,14 @@ static int nes_netdev_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *et_coalesce) { struct nes_vnic *nesvnic = netdev_priv(netdev); - struct nes_device *nesdev = nesvnic->nesdev; + struct nes_device *nesdev = nesvnic->nesdev; struct nes_adapter *nesadapter = nesdev->nesadapter; struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer; unsigned long flags; - spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags); + spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags); if (et_coalesce->rx_max_coalesced_frames_low) { - shared_timer->threshold_low = et_coalesce->rx_max_coalesced_frames_low; + shared_timer->threshold_low = et_coalesce->rx_max_coalesced_frames_low; } if (et_coalesce->rx_max_coalesced_frames_irq) { shared_timer->threshold_target = et_coalesce->rx_max_coalesced_frames_irq; @@ -1246,14 +1254,14 @@ static int nes_netdev_set_coalesce(struct net_device *netdev, nesadapter->et_rx_coalesce_usecs_irq = et_coalesce->rx_coalesce_usecs_irq; if (et_coalesce->use_adaptive_rx_coalesce) { nesadapter->et_use_adaptive_rx_coalesce = 1; - nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT_DYNAMIC; + nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT_DYNAMIC; nesadapter->et_rx_coalesce_usecs_irq = 0; if (et_coalesce->pkt_rate_low) { - nesadapter->et_pkt_rate_low = et_coalesce->pkt_rate_low; + nesadapter->et_pkt_rate_low = et_coalesce->pkt_rate_low; } } else { nesadapter->et_use_adaptive_rx_coalesce = 0; - nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT; + nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT; if (nesadapter->et_rx_coalesce_usecs_irq) { nes_write32(nesdev->regs+NES_PERIODIC_CONTROL, 0x80000000 | ((u32)(nesadapter->et_rx_coalesce_usecs_irq*8))); @@ -1270,28 +1278,28 @@ static int nes_netdev_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *et_coalesce) { struct nes_vnic *nesvnic = netdev_priv(netdev); - struct nes_device *nesdev = nesvnic->nesdev; + struct nes_device *nesdev = nesvnic->nesdev; struct nes_adapter *nesadapter = nesdev->nesadapter; struct ethtool_coalesce temp_et_coalesce; struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer; unsigned long flags; memset(&temp_et_coalesce, 0, sizeof(temp_et_coalesce)); - temp_et_coalesce.rx_coalesce_usecs_irq = nesadapter->et_rx_coalesce_usecs_irq; - temp_et_coalesce.use_adaptive_rx_coalesce = nesadapter->et_use_adaptive_rx_coalesce; - temp_et_coalesce.rate_sample_interval = nesadapter->et_rate_sample_interval; + temp_et_coalesce.rx_coalesce_usecs_irq = nesadapter->et_rx_coalesce_usecs_irq; + temp_et_coalesce.use_adaptive_rx_coalesce = nesadapter->et_use_adaptive_rx_coalesce; + temp_et_coalesce.rate_sample_interval = nesadapter->et_rate_sample_interval; temp_et_coalesce.pkt_rate_low = nesadapter->et_pkt_rate_low; spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags); - temp_et_coalesce.rx_max_coalesced_frames_low = shared_timer->threshold_low; - temp_et_coalesce.rx_max_coalesced_frames_irq = shared_timer->threshold_target; + temp_et_coalesce.rx_max_coalesced_frames_low = shared_timer->threshold_low; + temp_et_coalesce.rx_max_coalesced_frames_irq = shared_timer->threshold_target; temp_et_coalesce.rx_max_coalesced_frames_high = shared_timer->threshold_high; - temp_et_coalesce.rx_coalesce_usecs_low = shared_timer->timer_in_use_min; + temp_et_coalesce.rx_coalesce_usecs_low = shared_timer->timer_in_use_min; temp_et_coalesce.rx_coalesce_usecs_high = shared_timer->timer_in_use_max; if (nesadapter->et_use_adaptive_rx_coalesce) { temp_et_coalesce.rx_coalesce_usecs_irq = shared_timer->timer_in_use; } spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags); - memcpy(et_coalesce, &temp_et_coalesce, sizeof(*et_coalesce)); + memcpy(et_coalesce, &temp_et_coalesce, sizeof(*et_coalesce)); return 0; } @@ -1370,30 +1378,38 @@ static int nes_netdev_get_settings(struct net_device *netdev, struct ethtool_cmd u16 phy_data; et_cmd->duplex = DUPLEX_FULL; - et_cmd->port = PORT_MII; + et_cmd->port = PORT_MII; + if (nesadapter->OneG_Mode) { - et_cmd->supported = SUPPORTED_1000baseT_Full|SUPPORTED_Autoneg; - et_cmd->advertising = ADVERTISED_1000baseT_Full|ADVERTISED_Autoneg; et_cmd->speed = SPEED_1000; - nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index], - &phy_data); - if (phy_data&0x1000) { - et_cmd->autoneg = AUTONEG_ENABLE; + if (nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_PUMA_1G) { + et_cmd->supported = SUPPORTED_1000baseT_Full; + et_cmd->advertising = ADVERTISED_1000baseT_Full; + et_cmd->autoneg = AUTONEG_DISABLE; + et_cmd->transceiver = XCVR_INTERNAL; + et_cmd->phy_address = nesdev->mac_index; } else { - et_cmd->autoneg = AUTONEG_DISABLE; + et_cmd->supported = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg; + et_cmd->advertising = ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg; + nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index], &phy_data); + if (phy_data & 0x1000) + et_cmd->autoneg = AUTONEG_ENABLE; + else + et_cmd->autoneg = AUTONEG_DISABLE; + et_cmd->transceiver = XCVR_EXTERNAL; + et_cmd->phy_address = nesadapter->phy_index[nesdev->mac_index]; } - et_cmd->transceiver = XCVR_EXTERNAL; - et_cmd->phy_address = nesadapter->phy_index[nesdev->mac_index]; } else { - if (nesadapter->phy_type[nesvnic->logical_port] == NES_PHY_TYPE_IRIS) { + if ((nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_IRIS) || + (nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_ARGUS)) { et_cmd->transceiver = XCVR_EXTERNAL; - et_cmd->port = PORT_FIBRE; - et_cmd->supported = SUPPORTED_FIBRE; + et_cmd->port = PORT_FIBRE; + et_cmd->supported = SUPPORTED_FIBRE; et_cmd->advertising = ADVERTISED_FIBRE; et_cmd->phy_address = nesadapter->phy_index[nesdev->mac_index]; } else { et_cmd->transceiver = XCVR_INTERNAL; - et_cmd->supported = SUPPORTED_10000baseT_Full; + et_cmd->supported = SUPPORTED_10000baseT_Full; et_cmd->advertising = ADVERTISED_10000baseT_Full; et_cmd->phy_address = nesdev->mac_index; } @@ -1416,14 +1432,15 @@ static int nes_netdev_set_settings(struct net_device *netdev, struct ethtool_cmd struct nes_adapter *nesadapter = nesdev->nesadapter; u16 phy_data; - if (nesadapter->OneG_Mode) { + if ((nesadapter->OneG_Mode) && + (nesadapter->phy_type[nesdev->mac_index] != NES_PHY_TYPE_PUMA_1G)) { nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index], &phy_data); if (et_cmd->autoneg) { /* Turn on Full duplex, Autoneg, and restart autonegotiation */ phy_data |= 0x1300; } else { - // Turn off autoneg + /* Turn off autoneg */ phy_data &= ~0x1000; } nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index], @@ -1454,6 +1471,8 @@ static struct ethtool_ops nes_ethtool_ops = { .set_sg = ethtool_op_set_sg, .get_tso = ethtool_op_get_tso, .set_tso = ethtool_op_set_tso, + .get_flags = ethtool_op_get_flags, + .set_flags = ethtool_op_set_flags, }; @@ -1607,27 +1626,34 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, list_add_tail(&nesvnic->list, &nesdev->nesadapter->nesvnic_list[nesdev->mac_index]); if ((nesdev->netdev_count == 0) && - (PCI_FUNC(nesdev->pcidev->devfn) == nesdev->mac_index)) { - nes_debug(NES_DBG_INIT, "Setting up PHY interrupt mask. Using register index 0x%04X\n", - NES_IDX_PHY_PCS_CONTROL_STATUS0+(0x200*(nesvnic->logical_port&1))); + ((PCI_FUNC(nesdev->pcidev->devfn) == nesdev->mac_index) || + ((nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_PUMA_1G) && + (((PCI_FUNC(nesdev->pcidev->devfn) == 1) && (nesdev->mac_index == 2)) || + ((PCI_FUNC(nesdev->pcidev->devfn) == 2) && (nesdev->mac_index == 1)))))) { + /* + * nes_debug(NES_DBG_INIT, "Setting up PHY interrupt mask. Using register index 0x%04X\n", + * NES_IDX_PHY_PCS_CONTROL_STATUS0 + (0x200 * (nesvnic->logical_port & 1))); + */ u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + - (0x200*(nesvnic->logical_port&1))); - u32temp |= 0x00200000; - nes_write_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + - (0x200*(nesvnic->logical_port&1)), u32temp); + (0x200 * (nesdev->mac_index & 1))); + if (nesdev->nesadapter->phy_type[nesdev->mac_index] != NES_PHY_TYPE_PUMA_1G) { + u32temp |= 0x00200000; + nes_write_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + + (0x200 * (nesdev->mac_index & 1)), u32temp); + } + u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + - (0x200*(nesvnic->logical_port&1)) ); + (0x200 * (nesdev->mac_index & 1))); + if ((u32temp&0x0f1f0000) == 0x0f0f0000) { - if (nesdev->nesadapter->phy_type[nesvnic->logical_port] == NES_PHY_TYPE_IRIS) { + if (nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_IRIS) { nes_init_phy(nesdev); - nes_read_10G_phy_reg(nesdev, 1, - nesdev->nesadapter->phy_index[nesvnic->logical_port]); + nes_read_10G_phy_reg(nesdev, nesdev->nesadapter->phy_index[nesdev->mac_index], 1, 1); temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); u32temp = 20; do { - nes_read_10G_phy_reg(nesdev, 1, - nesdev->nesadapter->phy_index[nesvnic->logical_port]); + nes_read_10G_phy_reg(nesdev, nesdev->nesadapter->phy_index[nesdev->mac_index], 1, 1); phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL); if ((phy_data == temp_phy_data) || (!(--u32temp))) @@ -1644,6 +1670,14 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, nes_debug(NES_DBG_INIT, "The Link is UP!!.\n"); nesvnic->linkup = 1; } + } else if (nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_PUMA_1G) { + nes_debug(NES_DBG_INIT, "mac_index=%d, logical_port=%d, u32temp=0x%04X, PCI_FUNC=%d\n", + nesdev->mac_index, nesvnic->logical_port, u32temp, PCI_FUNC(nesdev->pcidev->devfn)); + if (((nesdev->mac_index < 2) && ((u32temp&0x01010000) == 0x01010000)) || + ((nesdev->mac_index > 1) && ((u32temp&0x02020000) == 0x02020000))) { + nes_debug(NES_DBG_INIT, "The Link is UP!!.\n"); + nesvnic->linkup = 1; + } } /* clear the MAC interrupt status, assumes direct logical to physical mapping */ u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (0x200 * nesdev->mac_index)); diff --git a/drivers/infiniband/hw/nes/nes_utils.c b/drivers/infiniband/hw/nes/nes_utils.c index c6d5631a6995..fe83d1b2b177 100644 --- a/drivers/infiniband/hw/nes/nes_utils.c +++ b/drivers/infiniband/hw/nes/nes_utils.c @@ -444,15 +444,13 @@ void nes_read_1G_phy_reg(struct nes_device *nesdev, u8 phy_reg, u8 phy_addr, u16 /** * nes_write_10G_phy_reg */ -void nes_write_10G_phy_reg(struct nes_device *nesdev, u16 phy_reg, - u8 phy_addr, u16 data) +void nes_write_10G_phy_reg(struct nes_device *nesdev, u16 phy_addr, u8 dev_addr, u16 phy_reg, + u16 data) { - u32 dev_addr; u32 port_addr; u32 u32temp; u32 counter; - dev_addr = 1; port_addr = phy_addr; /* set address */ @@ -492,14 +490,12 @@ void nes_write_10G_phy_reg(struct nes_device *nesdev, u16 phy_reg, * This routine only issues the read, the data must be read * separately. */ -void nes_read_10G_phy_reg(struct nes_device *nesdev, u16 phy_reg, u8 phy_addr) +void nes_read_10G_phy_reg(struct nes_device *nesdev, u8 phy_addr, u8 dev_addr, u16 phy_reg) { - u32 dev_addr; u32 port_addr; u32 u32temp; u32 counter; - dev_addr = 1; port_addr = phy_addr; /* set address */ diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index ee74f7c7a6da..99b3c4ae86eb 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -1266,7 +1266,7 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd, sq_size = init_attr->cap.max_send_wr; rq_size = init_attr->cap.max_recv_wr; - // check if the encoded sizes are OK or not... + /* check if the encoded sizes are OK or not... */ sq_encoded_size = nes_get_encoded_size(&sq_size); rq_encoded_size = nes_get_encoded_size(&rq_size); @@ -2377,7 +2377,7 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u8 single_page = 1; u8 stag_key; - region = ib_umem_get(pd->uobject->context, start, length, acc); + region = ib_umem_get(pd->uobject->context, start, length, acc, 0); if (IS_ERR(region)) { return (struct ib_mr *)region; } diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index f1f142dc64b1..9044f8803532 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -95,6 +95,8 @@ enum { IPOIB_MCAST_FLAG_SENDONLY = 1, IPOIB_MCAST_FLAG_BUSY = 2, /* joining or already joined */ IPOIB_MCAST_FLAG_ATTACHED = 3, + + MAX_SEND_CQE = 16, }; #define IPOIB_OP_RECV (1ul << 31) @@ -285,7 +287,8 @@ struct ipoib_dev_priv { u16 pkey_index; struct ib_pd *pd; struct ib_mr *mr; - struct ib_cq *cq; + struct ib_cq *recv_cq; + struct ib_cq *send_cq; struct ib_qp *qp; u32 qkey; @@ -305,6 +308,7 @@ struct ipoib_dev_priv { struct ib_sge tx_sge[MAX_SKB_FRAGS + 1]; struct ib_send_wr tx_wr; unsigned tx_outstanding; + struct ib_wc send_wc[MAX_SEND_CQE]; struct ib_recv_wr rx_wr; struct ib_sge rx_sge[IPOIB_UD_RX_SG]; @@ -662,7 +666,6 @@ static inline int ipoib_register_debugfs(void) { return 0; } static inline void ipoib_unregister_debugfs(void) { } #endif - #define ipoib_printk(level, priv, format, arg...) \ printk(level "%s: " format, ((struct ipoib_dev_priv *) priv)->dev->name , ## arg) #define ipoib_warn(priv, format, arg...) \ diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 9db7b0bd9134..97e67d36378f 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -249,8 +249,8 @@ static struct ib_qp *ipoib_cm_create_rx_qp(struct net_device *dev, struct ipoib_dev_priv *priv = netdev_priv(dev); struct ib_qp_init_attr attr = { .event_handler = ipoib_cm_rx_event_handler, - .send_cq = priv->cq, /* For drain WR */ - .recv_cq = priv->cq, + .send_cq = priv->recv_cq, /* For drain WR */ + .recv_cq = priv->recv_cq, .srq = priv->cm.srq, .cap.max_send_wr = 1, /* For drain WR */ .cap.max_send_sge = 1, /* FIXME: 0 Seems not to work */ @@ -951,8 +951,8 @@ static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ipoib_ { struct ipoib_dev_priv *priv = netdev_priv(dev); struct ib_qp_init_attr attr = { - .send_cq = priv->cq, - .recv_cq = priv->cq, + .send_cq = priv->recv_cq, + .recv_cq = priv->recv_cq, .srq = priv->cm.srq, .cap.max_send_wr = ipoib_sendq_size, .cap.max_send_sge = 1, diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c index 9a47428366c9..10279b79c44d 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c @@ -71,7 +71,7 @@ static int ipoib_set_coalesce(struct net_device *dev, coal->rx_max_coalesced_frames > 0xffff) return -EINVAL; - ret = ib_modify_cq(priv->cq, coal->rx_max_coalesced_frames, + ret = ib_modify_cq(priv->recv_cq, coal->rx_max_coalesced_frames, coal->rx_coalesce_usecs); if (ret && ret != -ENOSYS) { ipoib_warn(priv, "failed modifying CQ (%d)\n", ret); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 7cf1fa7074ab..97b815c1a3fc 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -364,7 +364,6 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc) struct ipoib_dev_priv *priv = netdev_priv(dev); unsigned int wr_id = wc->wr_id; struct ipoib_tx_buf *tx_req; - unsigned long flags; ipoib_dbg_data(priv, "send completion: id %d, status: %d\n", wr_id, wc->status); @@ -384,13 +383,11 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc) dev_kfree_skb_any(tx_req->skb); - spin_lock_irqsave(&priv->tx_lock, flags); ++priv->tx_tail; if (unlikely(--priv->tx_outstanding == ipoib_sendq_size >> 1) && netif_queue_stopped(dev) && test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) netif_wake_queue(dev); - spin_unlock_irqrestore(&priv->tx_lock, flags); if (wc->status != IB_WC_SUCCESS && wc->status != IB_WC_WR_FLUSH_ERR) @@ -399,6 +396,17 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc) wc->status, wr_id, wc->vendor_err); } +static int poll_tx(struct ipoib_dev_priv *priv) +{ + int n, i; + + n = ib_poll_cq(priv->send_cq, MAX_SEND_CQE, priv->send_wc); + for (i = 0; i < n; ++i) + ipoib_ib_handle_tx_wc(priv->dev, priv->send_wc + i); + + return n == MAX_SEND_CQE; +} + int ipoib_poll(struct napi_struct *napi, int budget) { struct ipoib_dev_priv *priv = container_of(napi, struct ipoib_dev_priv, napi); @@ -414,7 +422,7 @@ poll_more: int max = (budget - done); t = min(IPOIB_NUM_WC, max); - n = ib_poll_cq(priv->cq, t, priv->ibwc); + n = ib_poll_cq(priv->recv_cq, t, priv->ibwc); for (i = 0; i < n; i++) { struct ib_wc *wc = priv->ibwc + i; @@ -425,12 +433,8 @@ poll_more: ipoib_cm_handle_rx_wc(dev, wc); else ipoib_ib_handle_rx_wc(dev, wc); - } else { - if (wc->wr_id & IPOIB_OP_CM) - ipoib_cm_handle_tx_wc(dev, wc); - else - ipoib_ib_handle_tx_wc(dev, wc); - } + } else + ipoib_cm_handle_tx_wc(priv->dev, wc); } if (n != t) @@ -439,7 +443,7 @@ poll_more: if (done < budget) { netif_rx_complete(dev, napi); - if (unlikely(ib_req_notify_cq(priv->cq, + if (unlikely(ib_req_notify_cq(priv->recv_cq, IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS)) && netif_rx_reschedule(dev, napi)) @@ -562,12 +566,16 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb, address->last_send = priv->tx_head; ++priv->tx_head; + skb_orphan(skb); if (++priv->tx_outstanding == ipoib_sendq_size) { ipoib_dbg(priv, "TX ring full, stopping kernel net queue\n"); netif_stop_queue(dev); } } + + if (unlikely(priv->tx_outstanding > MAX_SEND_CQE)) + poll_tx(priv); } static void __ipoib_reap_ah(struct net_device *dev) @@ -714,7 +722,7 @@ void ipoib_drain_cq(struct net_device *dev) struct ipoib_dev_priv *priv = netdev_priv(dev); int i, n; do { - n = ib_poll_cq(priv->cq, IPOIB_NUM_WC, priv->ibwc); + n = ib_poll_cq(priv->recv_cq, IPOIB_NUM_WC, priv->ibwc); for (i = 0; i < n; ++i) { /* * Convert any successful completions to flush @@ -729,14 +737,13 @@ void ipoib_drain_cq(struct net_device *dev) ipoib_cm_handle_rx_wc(dev, priv->ibwc + i); else ipoib_ib_handle_rx_wc(dev, priv->ibwc + i); - } else { - if (priv->ibwc[i].wr_id & IPOIB_OP_CM) - ipoib_cm_handle_tx_wc(dev, priv->ibwc + i); - else - ipoib_ib_handle_tx_wc(dev, priv->ibwc + i); - } + } else + ipoib_cm_handle_tx_wc(dev, priv->ibwc + i); } } while (n == IPOIB_NUM_WC); + + while (poll_tx(priv)) + ; /* nothing */ } int ipoib_ib_dev_stop(struct net_device *dev, int flush) @@ -826,7 +833,7 @@ timeout: msleep(1); } - ib_req_notify_cq(priv->cq, IB_CQ_NEXT_COMP); + ib_req_notify_cq(priv->recv_cq, IB_CQ_NEXT_COMP); return 0; } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 7a4ed9d3d844..2442090ac8d1 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1298,7 +1298,8 @@ static int __init ipoib_init_module(void) ipoib_sendq_size = roundup_pow_of_two(ipoib_sendq_size); ipoib_sendq_size = min(ipoib_sendq_size, IPOIB_MAX_QUEUE_SIZE); - ipoib_sendq_size = max(ipoib_sendq_size, IPOIB_MIN_QUEUE_SIZE); + ipoib_sendq_size = max(ipoib_sendq_size, max(2 * MAX_SEND_CQE, + IPOIB_MIN_QUEUE_SIZE)); #ifdef CONFIG_INFINIBAND_IPOIB_CM ipoib_max_conn_qp = min(ipoib_max_conn_qp, IPOIB_CM_MAX_CONN_QP); #endif diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c index 07c03f178a49..c1e7ece1fd44 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c @@ -171,26 +171,33 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) goto out_free_pd; } - size = ipoib_sendq_size + ipoib_recvq_size + 1; + size = ipoib_recvq_size + 1; ret = ipoib_cm_dev_init(dev); if (!ret) { + size += ipoib_sendq_size; if (ipoib_cm_has_srq(dev)) size += ipoib_recvq_size + 1; /* 1 extra for rx_drain_qp */ else size += ipoib_recvq_size * ipoib_max_conn_qp; } - priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size, 0); - if (IS_ERR(priv->cq)) { - printk(KERN_WARNING "%s: failed to create CQ\n", ca->name); + priv->recv_cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size, 0); + if (IS_ERR(priv->recv_cq)) { + printk(KERN_WARNING "%s: failed to create receive CQ\n", ca->name); goto out_free_mr; } - if (ib_req_notify_cq(priv->cq, IB_CQ_NEXT_COMP)) - goto out_free_cq; + priv->send_cq = ib_create_cq(priv->ca, NULL, NULL, dev, ipoib_sendq_size, 0); + if (IS_ERR(priv->send_cq)) { + printk(KERN_WARNING "%s: failed to create send CQ\n", ca->name); + goto out_free_recv_cq; + } + + if (ib_req_notify_cq(priv->recv_cq, IB_CQ_NEXT_COMP)) + goto out_free_send_cq; - init_attr.send_cq = priv->cq; - init_attr.recv_cq = priv->cq; + init_attr.send_cq = priv->send_cq; + init_attr.recv_cq = priv->recv_cq; if (priv->hca_caps & IB_DEVICE_UD_TSO) init_attr.create_flags = IB_QP_CREATE_IPOIB_UD_LSO; @@ -201,7 +208,7 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) priv->qp = ib_create_qp(priv->pd, &init_attr); if (IS_ERR(priv->qp)) { printk(KERN_WARNING "%s: failed to create QP\n", ca->name); - goto out_free_cq; + goto out_free_send_cq; } priv->dev->dev_addr[1] = (priv->qp->qp_num >> 16) & 0xff; @@ -230,8 +237,11 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) return 0; -out_free_cq: - ib_destroy_cq(priv->cq); +out_free_send_cq: + ib_destroy_cq(priv->send_cq); + +out_free_recv_cq: + ib_destroy_cq(priv->recv_cq); out_free_mr: ib_dereg_mr(priv->mr); @@ -254,8 +264,11 @@ void ipoib_transport_dev_cleanup(struct net_device *dev) clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); } - if (ib_destroy_cq(priv->cq)) - ipoib_warn(priv, "ib_cq_destroy failed\n"); + if (ib_destroy_cq(priv->send_cq)) + ipoib_warn(priv, "ib_cq_destroy (send) failed\n"); + + if (ib_destroy_cq(priv->recv_cq)) + ipoib_warn(priv, "ib_cq_destroy (recv) failed\n"); ipoib_cm_dev_cleanup(dev); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c index 431fdeaa2dc4..1cdb5cfb0ff1 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c @@ -90,6 +90,9 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey) } priv->max_ib_mtu = ppriv->max_ib_mtu; + /* MTU will be reset when mcast join happens */ + priv->dev->mtu = IPOIB_UD_MTU(priv->max_ib_mtu); + priv->mcast_mtu = priv->admin_mtu = priv->dev->mtu; set_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags); priv->pkey = pkey; diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index be1b9fbd416d..aeb58cae9a3f 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -473,13 +473,15 @@ iscsi_iser_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *s stats->r2t_pdus = conn->r2t_pdus_cnt; /* always 0 */ stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt; stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt; - stats->custom_length = 3; + stats->custom_length = 4; strcpy(stats->custom[0].desc, "qp_tx_queue_full"); stats->custom[0].value = 0; /* TB iser_conn->qp_tx_queue_full; */ strcpy(stats->custom[1].desc, "fmr_map_not_avail"); stats->custom[1].value = 0; /* TB iser_conn->fmr_map_not_avail */; strcpy(stats->custom[2].desc, "eh_abort_cnt"); stats->custom[2].value = conn->eh_abort_cnt; + strcpy(stats->custom[3].desc, "fmr_unalign_cnt"); + stats->custom[3].value = conn->fmr_unalign_cnt; } static int diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index 1ee867b1b341..a8c1b300e34d 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -71,6 +71,13 @@ #define iser_dbg(fmt, arg...) \ do { \ + if (iser_debug_level > 1) \ + printk(KERN_DEBUG PFX "%s:" fmt,\ + __func__ , ## arg); \ + } while (0) + +#define iser_warn(fmt, arg...) \ + do { \ if (iser_debug_level > 0) \ printk(KERN_DEBUG PFX "%s:" fmt,\ __func__ , ## arg); \ diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index 4a17743a639f..cac50c4dc159 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -334,8 +334,11 @@ static void iser_data_buf_dump(struct iser_data_buf *data, struct scatterlist *sg; int i; + if (iser_debug_level == 0) + return; + for_each_sg(sgl, sg, data->dma_nents, i) - iser_err("sg[%d] dma_addr:0x%lX page:0x%p " + iser_warn("sg[%d] dma_addr:0x%lX page:0x%p " "off:0x%x sz:0x%x dma_len:0x%x\n", i, (unsigned long)ib_sg_dma_address(ibdev, sg), sg_page(sg), sg->offset, @@ -420,6 +423,7 @@ void iser_dma_unmap_task_data(struct iscsi_iser_cmd_task *iser_ctask) int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *iser_ctask, enum iser_data_dir cmd_dir) { + struct iscsi_conn *iscsi_conn = iser_ctask->iser_conn->iscsi_conn; struct iser_conn *ib_conn = iser_ctask->iser_conn->ib_conn; struct iser_device *device = ib_conn->device; struct ib_device *ibdev = device->ib_device; @@ -434,7 +438,8 @@ int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *iser_ctask, aligned_len = iser_data_buf_aligned_len(mem, ibdev); if (aligned_len != mem->dma_nents) { - iser_err("rdma alignment violation %d/%d aligned\n", + iscsi_conn->fmr_unalign_cnt++; + iser_warn("rdma alignment violation %d/%d aligned\n", aligned_len, mem->size); iser_data_buf_dump(mem, ibdev); diff --git a/drivers/input/input.c b/drivers/input/input.c index f02c242c3114..27006fc18305 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -898,30 +898,26 @@ static int __init input_proc_init(void) { struct proc_dir_entry *entry; - proc_bus_input_dir = proc_mkdir("input", proc_bus); + proc_bus_input_dir = proc_mkdir("bus/input", NULL); if (!proc_bus_input_dir) return -ENOMEM; proc_bus_input_dir->owner = THIS_MODULE; - entry = create_proc_entry("devices", 0, proc_bus_input_dir); + entry = proc_create("devices", 0, proc_bus_input_dir, + &input_devices_fileops); if (!entry) goto fail1; - entry->owner = THIS_MODULE; - entry->proc_fops = &input_devices_fileops; - - entry = create_proc_entry("handlers", 0, proc_bus_input_dir); + entry = proc_create("handlers", 0, proc_bus_input_dir, + &input_handlers_fileops); if (!entry) goto fail2; - entry->owner = THIS_MODULE; - entry->proc_fops = &input_handlers_fileops; - return 0; fail2: remove_proc_entry("devices", proc_bus_input_dir); - fail1: remove_proc_entry("input", proc_bus); + fail1: remove_proc_entry("bus/input", NULL); return -ENOMEM; } @@ -929,7 +925,7 @@ static void input_proc_exit(void) { remove_proc_entry("devices", proc_bus_input_dir); remove_proc_entry("handlers", proc_bus_input_dir); - remove_proc_entry("input", proc_bus); + remove_proc_entry("bus/input", NULL); } #else /* !CONFIG_PROC_FS */ diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index e1a3a79ab3f9..7ff71ba7b7c9 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -46,7 +46,7 @@ struct serport { static int serport_serio_write(struct serio *serio, unsigned char data) { struct serport *serport = serio->port_data; - return -(serport->tty->driver->write(serport->tty, &data, 1) != 1); + return -(serport->tty->ops->write(serport->tty, &data, 1) != 1); } static int serport_serio_open(struct serio *serio) diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c index 1d759f6f8076..55c1134d6137 100644 --- a/drivers/input/tablet/aiptek.c +++ b/drivers/input/tablet/aiptek.c @@ -528,9 +528,9 @@ static void aiptek_irq(struct urb *urb) (aiptek->curSetting.pointerMode)) { aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED; } else { - x = le16_to_cpu(get_unaligned((__le16 *) (data + 1))); - y = le16_to_cpu(get_unaligned((__le16 *) (data + 3))); - z = le16_to_cpu(get_unaligned((__le16 *) (data + 6))); + x = get_unaligned_le16(data + 1); + y = get_unaligned_le16(data + 3); + z = get_unaligned_le16(data + 6); dv = (data[5] & 0x01) != 0 ? 1 : 0; p = (data[5] & 0x02) != 0 ? 1 : 0; @@ -613,8 +613,8 @@ static void aiptek_irq(struct urb *urb) (aiptek->curSetting.pointerMode)) { aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED; } else { - x = le16_to_cpu(get_unaligned((__le16 *) (data + 1))); - y = le16_to_cpu(get_unaligned((__le16 *) (data + 3))); + x = get_unaligned_le16(data + 1); + y = get_unaligned_le16(data + 3); jitterable = data[5] & 0x1c; @@ -679,7 +679,7 @@ static void aiptek_irq(struct urb *urb) pck = (data[1] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0; macro = dv && p && tip && !(data[3] & 1) ? (data[3] >> 1) : -1; - z = le16_to_cpu(get_unaligned((__le16 *) (data + 4))); + z = get_unaligned_le16(data + 4); if (dv) { /* If the selected tool changed, reset the old @@ -757,7 +757,7 @@ static void aiptek_irq(struct urb *urb) * hat switches (which just so happen to be the macroKeys.) */ else if (data[0] == 6) { - macro = le16_to_cpu(get_unaligned((__le16 *) (data + 1))); + macro = get_unaligned_le16(data + 1); if (macro > 0) { input_report_key(inputdev, macroKeyEvents[macro - 1], 0); @@ -952,7 +952,7 @@ aiptek_query(struct aiptek *aiptek, unsigned char command, unsigned char data) buf[0], buf[1], buf[2]); ret = -EIO; } else { - ret = le16_to_cpu(get_unaligned((__le16 *) (buf + 1))); + ret = get_unaligned_le16(buf + 1); } kfree(buf); return ret; diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c index f66ca215cdec..c5a8661a1baa 100644 --- a/drivers/input/tablet/gtco.c +++ b/drivers/input/tablet/gtco.c @@ -245,11 +245,11 @@ static void parse_hid_report_descriptor(struct gtco *device, char * report, data = report[i]; break; case 2: - data16 = le16_to_cpu(get_unaligned((__le16 *)&report[i])); + data16 = get_unaligned_le16(&report[i]); break; case 3: size = 4; - data32 = le32_to_cpu(get_unaligned((__le32 *)&report[i])); + data32 = get_unaligned_le32(&report[i]); break; } @@ -695,10 +695,10 @@ static void gtco_urb_callback(struct urb *urbinfo) /* Fall thru */ case 1: /* All reports have X and Y coords in the same place */ - val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[1])); + val = get_unaligned_le16(&device->buffer[1]); input_report_abs(inputdev, ABS_X, val); - val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[3])); + val = get_unaligned_le16(&device->buffer[3]); input_report_abs(inputdev, ABS_Y, val); /* Ditto for proximity bit */ @@ -762,7 +762,7 @@ static void gtco_urb_callback(struct urb *urbinfo) le_buffer[1] = (u8)(device->buffer[4] >> 1); le_buffer[1] |= (u8)((device->buffer[5] & 0x1) << 7); - val = le16_to_cpu(get_unaligned((__le16 *)le_buffer)); + val = get_unaligned_le16(le_buffer); input_report_abs(inputdev, ABS_Y, val); /* @@ -772,10 +772,10 @@ static void gtco_urb_callback(struct urb *urbinfo) buttonbyte = device->buffer[5] >> 1; } else { - val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[1])); + val = get_unaligned_le16(&device->buffer[1]); input_report_abs(inputdev, ABS_X, val); - val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[3])); + val = get_unaligned_le16(&device->buffer[3]); input_report_abs(inputdev, ABS_Y, val); buttonbyte = device->buffer[5]; diff --git a/drivers/input/tablet/kbtab.c b/drivers/input/tablet/kbtab.c index 1182fc133167..f23f5a97fb38 100644 --- a/drivers/input/tablet/kbtab.c +++ b/drivers/input/tablet/kbtab.c @@ -63,8 +63,8 @@ static void kbtab_irq(struct urb *urb) goto exit; } - kbtab->x = le16_to_cpu(get_unaligned((__le16 *) &data[1])); - kbtab->y = le16_to_cpu(get_unaligned((__le16 *) &data[3])); + kbtab->x = get_unaligned_le16(&data[1]); + kbtab->y = get_unaligned_le16(&data[3]); kbtab->pressure = (data[5]); diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c index 24c6b7ca62be..6ca0bb949ad3 100644 --- a/drivers/isdn/capi/capi.c +++ b/drivers/isdn/capi/capi.c @@ -1111,11 +1111,12 @@ static int capinc_tty_write(struct tty_struct * tty, return count; } -static void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch) +static int capinc_tty_put_char(struct tty_struct *tty, unsigned char ch) { struct capiminor *mp = (struct capiminor *)tty->driver_data; struct sk_buff *skb; unsigned long flags; + int ret = 1; #ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_put_char(%u)\n", ch); @@ -1125,7 +1126,7 @@ static void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch) #ifdef _DEBUG_TTYFUNCS printk(KERN_DEBUG "capinc_tty_put_char: mp or mp->ncci NULL\n"); #endif - return; + return 0; } spin_lock_irqsave(&workaround_lock, flags); @@ -1134,7 +1135,7 @@ static void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch) if (skb_tailroom(skb) > 0) { *(skb_put(skb, 1)) = ch; spin_unlock_irqrestore(&workaround_lock, flags); - return; + return 1; } mp->ttyskb = NULL; skb_queue_tail(&mp->outqueue, skb); @@ -1148,8 +1149,10 @@ static void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch) mp->ttyskb = skb; } else { printk(KERN_ERR "capinc_put_char: char %u lost\n", ch); + ret = 0; } spin_unlock_irqrestore(&workaround_lock, flags); + return ret; } static void capinc_tty_flush_chars(struct tty_struct *tty) diff --git a/drivers/isdn/capi/kcapi_proc.c b/drivers/isdn/capi/kcapi_proc.c index 845a797b0030..c29208bd7521 100644 --- a/drivers/isdn/capi/kcapi_proc.c +++ b/drivers/isdn/capi/kcapi_proc.c @@ -114,6 +114,7 @@ static int seq_contrstats_open(struct inode *inode, struct file *file) } static const struct file_operations proc_controller_ops = { + .owner = THIS_MODULE, .open = seq_controller_open, .read = seq_read, .llseek = seq_lseek, @@ -121,6 +122,7 @@ static const struct file_operations proc_controller_ops = { }; static const struct file_operations proc_contrstats_ops = { + .owner = THIS_MODULE, .open = seq_contrstats_open, .read = seq_read, .llseek = seq_lseek, @@ -219,6 +221,7 @@ seq_applstats_open(struct inode *inode, struct file *file) } static const struct file_operations proc_applications_ops = { + .owner = THIS_MODULE, .open = seq_applications_open, .read = seq_read, .llseek = seq_lseek, @@ -226,21 +229,13 @@ static const struct file_operations proc_applications_ops = { }; static const struct file_operations proc_applstats_ops = { + .owner = THIS_MODULE, .open = seq_applstats_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; -static void -create_seq_entry(char *name, mode_t mode, const struct file_operations *f) -{ - struct proc_dir_entry *entry; - entry = create_proc_entry(name, mode, NULL); - if (entry) - entry->proc_fops = f; -} - // --------------------------------------------------------------------------- static void *capi_driver_start(struct seq_file *seq, loff_t *pos) @@ -283,6 +278,7 @@ seq_capi_driver_open(struct inode *inode, struct file *file) } static const struct file_operations proc_driver_ops = { + .owner = THIS_MODULE, .open = seq_capi_driver_open, .read = seq_read, .llseek = seq_lseek, @@ -296,11 +292,11 @@ kcapi_proc_init(void) { proc_mkdir("capi", NULL); proc_mkdir("capi/controllers", NULL); - create_seq_entry("capi/controller", 0, &proc_controller_ops); - create_seq_entry("capi/contrstats", 0, &proc_contrstats_ops); - create_seq_entry("capi/applications", 0, &proc_applications_ops); - create_seq_entry("capi/applstats", 0, &proc_applstats_ops); - create_seq_entry("capi/driver", 0, &proc_driver_ops); + proc_create("capi/controller", 0, NULL, &proc_controller_ops); + proc_create("capi/contrstats", 0, NULL, &proc_contrstats_ops); + proc_create("capi/applications", 0, NULL, &proc_applications_ops); + proc_create("capi/applstats", 0, NULL, &proc_applstats_ops); + proc_create("capi/driver", 0, NULL, &proc_driver_ops); } void __exit diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c index 4fd4c46892e3..8b256a617c8a 100644 --- a/drivers/isdn/divert/divert_procfs.c +++ b/drivers/isdn/divert/divert_procfs.c @@ -288,13 +288,12 @@ divert_dev_init(void) isdn_proc_entry = proc_mkdir("isdn", init_net.proc_net); if (!isdn_proc_entry) return (-1); - isdn_divert_entry = create_proc_entry("divert", S_IFREG | S_IRUGO, isdn_proc_entry); + isdn_divert_entry = proc_create("divert", S_IFREG | S_IRUGO, + isdn_proc_entry, &isdn_fops); if (!isdn_divert_entry) { remove_proc_entry("isdn", init_net.proc_net); return (-1); } - isdn_divert_entry->proc_fops = &isdn_fops; - isdn_divert_entry->owner = THIS_MODULE; #endif /* CONFIG_PROC_FS */ return (0); diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c index fceeb1d57682..45d1ee93cd39 100644 --- a/drivers/isdn/gigaset/ser-gigaset.c +++ b/drivers/isdn/gigaset/ser-gigaset.c @@ -68,10 +68,10 @@ static int write_modem(struct cardstate *cs) struct tty_struct *tty = cs->hw.ser->tty; struct bc_state *bcs = &cs->bcs[0]; /* only one channel */ struct sk_buff *skb = bcs->tx_skb; - int sent; + int sent = -EOPNOTSUPP; if (!tty || !tty->driver || !skb) - return -EFAULT; + return -EINVAL; if (!skb->len) { dev_kfree_skb_any(skb); @@ -80,7 +80,8 @@ static int write_modem(struct cardstate *cs) } set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - sent = tty->driver->write(tty, skb->data, skb->len); + if (tty->ops->write) + sent = tty->ops->write(tty, skb->data, skb->len); gig_dbg(DEBUG_OUTPUT, "write_modem: sent %d", sent); if (sent < 0) { /* error */ @@ -120,7 +121,7 @@ static int send_cb(struct cardstate *cs) if (cb->len) { set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - sent = tty->driver->write(tty, cb->buf + cb->offset, cb->len); + sent = tty->ops->write(tty, cb->buf + cb->offset, cb->len); if (sent < 0) { /* error */ gig_dbg(DEBUG_OUTPUT, "send_cb: write error %d", sent); @@ -440,14 +441,14 @@ static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state, unsi struct tty_struct *tty = cs->hw.ser->tty; unsigned int set, clear; - if (!tty || !tty->driver || !tty->driver->tiocmset) - return -EFAULT; + if (!tty || !tty->driver || !tty->ops->tiocmset) + return -EINVAL; set = new_state & ~old_state; clear = old_state & ~new_state; if (!set && !clear) return 0; gig_dbg(DEBUG_IF, "tiocmset set %x clear %x", set, clear); - return tty->driver->tiocmset(tty, NULL, set, clear); + return tty->ops->tiocmset(tty, NULL, set, clear); } static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag) diff --git a/drivers/isdn/hardware/eicon/divasproc.c b/drivers/isdn/hardware/eicon/divasproc.c index 0632a2606998..fae895828a17 100644 --- a/drivers/isdn/hardware/eicon/divasproc.c +++ b/drivers/isdn/hardware/eicon/divasproc.c @@ -125,15 +125,11 @@ static const struct file_operations divas_fops = { int create_divas_proc(void) { - divas_proc_entry = create_proc_entry(divas_proc_name, - S_IFREG | S_IRUGO, - proc_net_eicon); + proc_create(divas_proc_name, S_IFREG | S_IRUGO, proc_net_eicon, + &divas_fops); if (!divas_proc_entry) return (0); - divas_proc_entry->proc_fops = &divas_fops; - divas_proc_entry->owner = THIS_MODULE; - return (1); } diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c index 27d890b48f88..877be9922c3d 100644 --- a/drivers/isdn/hysdn/hysdn_procconf.c +++ b/drivers/isdn/hysdn/hysdn_procconf.c @@ -370,6 +370,7 @@ hysdn_conf_close(struct inode *ino, struct file *filep) /******************************************************/ static const struct file_operations conf_fops = { + .owner = THIS_MODULE, .llseek = no_llseek, .read = hysdn_conf_read, .write = hysdn_conf_write, @@ -402,11 +403,9 @@ hysdn_procconf_init(void) while (card) { sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid); - if ((card->procconf = (void *) create_proc_entry(conf_name, - S_IFREG | S_IRUGO | S_IWUSR, - hysdn_proc_entry)) != NULL) { - ((struct proc_dir_entry *) card->procconf)->proc_fops = &conf_fops; - ((struct proc_dir_entry *) card->procconf)->owner = THIS_MODULE; + if ((card->procconf = (void *) proc_create(conf_name, + S_IFREG | S_IRUGO | S_IWUSR, + hysdn_proc_entry)) != NULL) { hysdn_proclog_init(card); /* init the log file entry */ } card = card->next; /* next entry */ diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c index 27b3991fb0ec..8991d2c8ee4a 100644 --- a/drivers/isdn/hysdn/hysdn_proclog.c +++ b/drivers/isdn/hysdn/hysdn_proclog.c @@ -380,6 +380,7 @@ hysdn_log_poll(struct file *file, poll_table * wait) /**************************************************/ static const struct file_operations log_fops = { + .owner = THIS_MODULE, .llseek = no_llseek, .read = hysdn_log_read, .write = hysdn_log_write, @@ -402,10 +403,9 @@ hysdn_proclog_init(hysdn_card * card) if ((pd = kzalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) { sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid); - if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) { - pd->log->proc_fops = &log_fops; - pd->log->owner = THIS_MODULE; - } + pd->log = proc_create(pd->log_name, + S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry, + &log_fops); init_waitqueue_head(&(pd->rd_queue)); diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 8af0df1d5b8c..1a2222cbb805 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1352,12 +1352,14 @@ isdn_tty_tiocmget(struct tty_struct *tty, struct file *file) if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; + lock_kernel(); #ifdef ISDN_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line); #endif control = info->mcr; status = info->msr; + unlock_kernel(); return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) @@ -1381,6 +1383,7 @@ isdn_tty_tiocmset(struct tty_struct *tty, struct file *file, printk(KERN_DEBUG "ttyI%d ioctl TIOCMxxx: %x %x\n", info->line, set, clear); #endif + lock_kernel(); if (set & TIOCM_RTS) info->mcr |= UART_MCR_RTS; if (set & TIOCM_DTR) { @@ -1402,6 +1405,7 @@ isdn_tty_tiocmset(struct tty_struct *tty, struct file *file, isdn_tty_modem_hup(info, 1); } } + unlock_kernel(); return 0; } @@ -1435,21 +1439,6 @@ isdn_tty_ioctl(struct tty_struct *tty, struct file *file, return retval; tty_wait_until_sent(tty, 0); return 0; - case TIOCGSOFTCAR: -#ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "ttyI%d ioctl TIOCGSOFTCAR\n", info->line); -#endif - return put_user(C_CLOCAL(tty) ? 1 : 0, (ulong __user *) arg); - case TIOCSSOFTCAR: -#ifdef ISDN_DEBUG_MODEM_IOCTL - printk(KERN_DEBUG "ttyI%d ioctl TIOCSSOFTCAR\n", info->line); -#endif - if (get_user(arg, (ulong __user *) arg)) - return -EFAULT; - tty->termios->c_cflag = - ((tty->termios->c_cflag & ~CLOCAL) | - (arg ? CLOCAL : 0)); - return 0; case TIOCSERGETLSR: /* Get line status register */ #ifdef ISDN_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line); @@ -1472,13 +1461,14 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) if (!old_termios) isdn_tty_change_speed(info); else { - if (tty->termios->c_cflag == old_termios->c_cflag) + if (tty->termios->c_cflag == old_termios->c_cflag && + tty->termios->c_ispeed == old_termios->c_ispeed && + tty->termios->c_ospeed == old_termios->c_ospeed) return; isdn_tty_change_speed(info); if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { + !(tty->termios->c_cflag & CRTSCTS)) tty->hw_stopped = 0; - } } } @@ -1718,9 +1708,7 @@ isdn_tty_close(struct tty_struct *tty, struct file *filp) } dev->modempoll--; isdn_tty_shutdown(info); - - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + isdn_tty_flush_buffer(tty); tty_ldisc_flush(tty); info->tty = NULL; info->ncarrier = 0; diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index ac05a928f764..b3c54be74556 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -105,7 +105,7 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) led_cdev->dev = device_create(leds_class, parent, 0, "%s", led_cdev->name); - if (unlikely(IS_ERR(led_cdev->dev))) + if (IS_ERR(led_cdev->dev)) return PTR_ERR(led_cdev->dev); dev_set_drvdata(led_cdev->dev, led_cdev); diff --git a/drivers/mca/mca-legacy.c b/drivers/mca/mca-legacy.c index 0c7bfa74c8ef..494f0c2001f5 100644 --- a/drivers/mca/mca-legacy.c +++ b/drivers/mca/mca-legacy.c @@ -282,24 +282,6 @@ void mca_set_adapter_name(int slot, char* name) EXPORT_SYMBOL(mca_set_adapter_name); /** - * mca_is_adapter_used - check if claimed by driver - * @slot: slot to check - * - * Returns 1 if the slot has been claimed by a driver - */ - -int mca_is_adapter_used(int slot) -{ - struct mca_device *mca_dev = mca_find_device_by_slot(slot); - - if(!mca_dev) - return 0; - - return mca_device_claimed(mca_dev); -} -EXPORT_SYMBOL(mca_is_adapter_used); - -/** * mca_mark_as_used - claim an MCA device * @slot: slot to claim * FIXME: should we make this threadsafe diff --git a/drivers/mca/mca-proc.c b/drivers/mca/mca-proc.c index 33d5e0820cc5..81ea0d377bf4 100644 --- a/drivers/mca/mca-proc.c +++ b/drivers/mca/mca-proc.c @@ -183,7 +183,7 @@ void __init mca_do_proc_init(void) struct proc_dir_entry* node = NULL; struct mca_device *mca_dev; - proc_mca = proc_mkdir("mca", &proc_root); + proc_mca = proc_mkdir("mca", NULL); create_proc_read_entry("pos",0,proc_mca,get_mca_info,NULL); create_proc_read_entry("machine",0,proc_mca,get_mca_machine_info,NULL); diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c index 6b91b9ab1d41..3ea5ad4b7805 100644 --- a/drivers/md/dm-emc.c +++ b/drivers/md/dm-emc.c @@ -110,8 +110,6 @@ static struct request *get_failover_req(struct emc_handler *h, memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); rq->sense_len = 0; - memset(&rq->cmd, 0, BLK_MAX_CDB); - rq->timeout = EMC_FAILOVER_TIMEOUT; rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE; diff --git a/drivers/md/dm-mpath-hp-sw.c b/drivers/md/dm-mpath-hp-sw.c index 204bf42c9449..b63a0ab37c53 100644 --- a/drivers/md/dm-mpath-hp-sw.c +++ b/drivers/md/dm-mpath-hp-sw.c @@ -137,7 +137,6 @@ static struct request *hp_sw_get_request(struct dm_path *path) req->sense = h->sense; memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE); - memset(&req->cmd, 0, BLK_MAX_CDB); req->cmd[0] = START_STOP; req->cmd[4] = 1; req->cmd_len = COMMAND_SIZE(req->cmd[0]); diff --git a/drivers/md/dm-mpath-rdac.c b/drivers/md/dm-mpath-rdac.c index e04eb5c697fb..95e77734880a 100644 --- a/drivers/md/dm-mpath-rdac.c +++ b/drivers/md/dm-mpath-rdac.c @@ -284,7 +284,6 @@ static struct request *get_rdac_req(struct rdac_handler *h, return NULL; } - memset(&rq->cmd, 0, BLK_MAX_CDB); rq->sense = h->sense; memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); rq->sense_len = 0; diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 51be53344214..94116eaf4709 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -873,10 +873,11 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q) q->max_hw_sectors = t->limits.max_hw_sectors; q->seg_boundary_mask = t->limits.seg_boundary_mask; q->bounce_pfn = t->limits.bounce_pfn; + if (t->limits.no_cluster) - q->queue_flags &= ~(1 << QUEUE_FLAG_CLUSTER); + queue_flag_clear_unlocked(QUEUE_FLAG_CLUSTER, q); else - q->queue_flags |= (1 << QUEUE_FLAG_CLUSTER); + queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, q); } diff --git a/drivers/md/md.c b/drivers/md/md.c index 87620b705bee..83eb78b00137 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -276,13 +276,15 @@ static mddev_t * mddev_find(dev_t unit) init_waitqueue_head(&new->sb_wait); new->reshape_position = MaxSector; new->resync_max = MaxSector; + new->level = LEVEL_NONE; new->queue = blk_alloc_queue(GFP_KERNEL); if (!new->queue) { kfree(new); return NULL; } - set_bit(QUEUE_FLAG_CLUSTER, &new->queue->queue_flags); + /* Can be unlocked because the queue is new: no concurrency */ + queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, new->queue); blk_queue_make_request(new->queue, md_fail_request); @@ -1368,6 +1370,11 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev) MD_BUG(); return -EINVAL; } + + /* prevent duplicates */ + if (find_rdev(mddev, rdev->bdev->bd_dev)) + return -EEXIST; + /* make sure rdev->size exceeds mddev->size */ if (rdev->size && (mddev->size == 0 || rdev->size < mddev->size)) { if (mddev->pers) { @@ -1651,6 +1658,8 @@ static void md_update_sb(mddev_t * mddev, int force_change) int sync_req; int nospares = 0; + if (mddev->external) + return; repeat: spin_lock_irq(&mddev->write_lock); @@ -1819,6 +1828,10 @@ state_show(mdk_rdev_t *rdev, char *page) len += sprintf(page+len, "%swrite_mostly",sep); sep = ","; } + if (test_bit(Blocked, &rdev->flags)) { + len += sprintf(page+len, "%sblocked", sep); + sep = ","; + } if (!test_bit(Faulty, &rdev->flags) && !test_bit(In_sync, &rdev->flags)) { len += sprintf(page+len, "%sspare", sep); @@ -1835,6 +1848,8 @@ state_store(mdk_rdev_t *rdev, const char *buf, size_t len) * remove - disconnects the device * writemostly - sets write_mostly * -writemostly - clears write_mostly + * blocked - sets the Blocked flag + * -blocked - clears the Blocked flag */ int err = -EINVAL; if (cmd_match(buf, "faulty") && rdev->mddev->pers) { @@ -1857,6 +1872,16 @@ state_store(mdk_rdev_t *rdev, const char *buf, size_t len) } else if (cmd_match(buf, "-writemostly")) { clear_bit(WriteMostly, &rdev->flags); err = 0; + } else if (cmd_match(buf, "blocked")) { + set_bit(Blocked, &rdev->flags); + err = 0; + } else if (cmd_match(buf, "-blocked")) { + clear_bit(Blocked, &rdev->flags); + wake_up(&rdev->blocked_wait); + set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery); + md_wakeup_thread(rdev->mddev->thread); + + err = 0; } return err ? err : len; } @@ -2096,7 +2121,7 @@ rdev_attr_store(struct kobject *kobj, struct attribute *attr, rv = -EBUSY; else rv = entry->store(rdev, page, length); - mddev_unlock(rdev->mddev); + mddev_unlock(mddev); } return rv; } @@ -2185,7 +2210,9 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi goto abort_free; } } + INIT_LIST_HEAD(&rdev->same_set); + init_waitqueue_head(&rdev->blocked_wait); return rdev; @@ -2456,7 +2483,6 @@ resync_start_show(mddev_t *mddev, char *page) static ssize_t resync_start_store(mddev_t *mddev, const char *buf, size_t len) { - /* can only set chunk_size if array is not yet active */ char *e; unsigned long long n = simple_strtoull(buf, &e, 10); @@ -2590,15 +2616,20 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len) err = do_md_stop(mddev, 1); else { mddev->ro = 1; + set_disk_ro(mddev->gendisk, 1); err = do_md_run(mddev); } break; case read_auto: - /* stopping an active array */ if (mddev->pers) { - err = do_md_stop(mddev, 1); - if (err == 0) - mddev->ro = 2; /* FIXME mark devices writable */ + if (mddev->ro != 1) + err = do_md_stop(mddev, 1); + else + err = restart_array(mddev); + if (err == 0) { + mddev->ro = 2; + set_disk_ro(mddev->gendisk, 0); + } } else { mddev->ro = 2; err = do_md_run(mddev); @@ -2611,6 +2642,8 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len) if (atomic_read(&mddev->writes_pending) == 0) { if (mddev->in_sync == 0) { mddev->in_sync = 1; + if (mddev->safemode == 1) + mddev->safemode = 0; if (mddev->persistent) set_bit(MD_CHANGE_CLEAN, &mddev->flags); @@ -2634,6 +2667,7 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len) err = 0; } else { mddev->ro = 0; + set_disk_ro(mddev->gendisk, 0); err = do_md_run(mddev); } break; @@ -3711,6 +3745,30 @@ static int do_md_stop(mddev_t * mddev, int mode) mddev->reshape_position = MaxSector; mddev->external = 0; mddev->persistent = 0; + mddev->level = LEVEL_NONE; + mddev->clevel[0] = 0; + mddev->flags = 0; + mddev->ro = 0; + mddev->metadata_type[0] = 0; + mddev->chunk_size = 0; + mddev->ctime = mddev->utime = 0; + mddev->layout = 0; + mddev->max_disks = 0; + mddev->events = 0; + mddev->delta_disks = 0; + mddev->new_level = LEVEL_NONE; + mddev->new_layout = 0; + mddev->new_chunk = 0; + mddev->curr_resync = 0; + mddev->resync_mismatches = 0; + mddev->suspend_lo = mddev->suspend_hi = 0; + mddev->sync_speed_min = mddev->sync_speed_max = 0; + mddev->recovery = 0; + mddev->in_sync = 0; + mddev->changed = 0; + mddev->degraded = 0; + mddev->barriers_work = 0; + mddev->safemode = 0; } else if (mddev->pers) printk(KERN_INFO "md: %s switched to read-only mode.\n", @@ -4918,6 +4976,9 @@ void md_error(mddev_t *mddev, mdk_rdev_t *rdev) if (!rdev || test_bit(Faulty, &rdev->flags)) return; + + if (mddev->external) + set_bit(Blocked, &rdev->flags); /* dprintk("md_error dev:%s, rdev:(%d:%d), (caller: %p,%p,%p,%p).\n", mdname(mddev), @@ -5364,6 +5425,8 @@ void md_write_start(mddev_t *mddev, struct bio *bi) md_wakeup_thread(mddev->sync_thread); } atomic_inc(&mddev->writes_pending); + if (mddev->safemode == 1) + mddev->safemode = 0; if (mddev->in_sync) { spin_lock_irq(&mddev->write_lock); if (mddev->in_sync) { @@ -5718,7 +5781,7 @@ static int remove_and_add_spares(mddev_t *mddev) rdev_for_each(rdev, rtmp, mddev) if (rdev->raid_disk >= 0 && - !mddev->external && + !test_bit(Blocked, &rdev->flags) && (test_bit(Faulty, &rdev->flags) || ! test_bit(In_sync, &rdev->flags)) && atomic_read(&rdev->nr_pending)==0) { @@ -5788,7 +5851,7 @@ void md_check_recovery(mddev_t *mddev) return; if (signal_pending(current)) { - if (mddev->pers->sync_request) { + if (mddev->pers->sync_request && !mddev->external) { printk(KERN_INFO "md: %s in immediate safe mode\n", mdname(mddev)); mddev->safemode = 2; @@ -5800,7 +5863,7 @@ void md_check_recovery(mddev_t *mddev) (mddev->flags && !mddev->external) || test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) || test_bit(MD_RECOVERY_DONE, &mddev->recovery) || - (mddev->safemode == 1) || + (mddev->external == 0 && mddev->safemode == 1) || (mddev->safemode == 2 && ! atomic_read(&mddev->writes_pending) && !mddev->in_sync && mddev->recovery_cp == MaxSector) )) @@ -5809,16 +5872,20 @@ void md_check_recovery(mddev_t *mddev) if (mddev_trylock(mddev)) { int spares = 0; - spin_lock_irq(&mddev->write_lock); - if (mddev->safemode && !atomic_read(&mddev->writes_pending) && - !mddev->in_sync && mddev->recovery_cp == MaxSector) { - mddev->in_sync = 1; - if (mddev->persistent) - set_bit(MD_CHANGE_CLEAN, &mddev->flags); + if (!mddev->external) { + spin_lock_irq(&mddev->write_lock); + if (mddev->safemode && + !atomic_read(&mddev->writes_pending) && + !mddev->in_sync && + mddev->recovery_cp == MaxSector) { + mddev->in_sync = 1; + if (mddev->persistent) + set_bit(MD_CHANGE_CLEAN, &mddev->flags); + } + if (mddev->safemode == 1) + mddev->safemode = 0; + spin_unlock_irq(&mddev->write_lock); } - if (mddev->safemode == 1) - mddev->safemode = 0; - spin_unlock_irq(&mddev->write_lock); if (mddev->flags) md_update_sb(mddev, 0); @@ -5913,6 +5980,16 @@ void md_check_recovery(mddev_t *mddev) } } +void md_wait_for_blocked_rdev(mdk_rdev_t *rdev, mddev_t *mddev) +{ + sysfs_notify(&rdev->kobj, NULL, "state"); + wait_event_timeout(rdev->blocked_wait, + !test_bit(Blocked, &rdev->flags), + msecs_to_jiffies(5000)); + rdev_dec_pending(rdev, mddev); +} +EXPORT_SYMBOL(md_wait_for_blocked_rdev); + static int md_notify_reboot(struct notifier_block *this, unsigned long code, void *x) { @@ -5947,13 +6024,9 @@ static struct notifier_block md_notifier = { static void md_geninit(void) { - struct proc_dir_entry *p; - dprintk("md: sizeof(mdp_super_t) = %d\n", (int)sizeof(mdp_super_t)); - p = create_proc_entry("mdstat", S_IRUGO, NULL); - if (p) - p->proc_fops = &md_seq_fops; + proc_create("mdstat", S_IRUGO, NULL, &md_seq_fops); } static int __init md_init(void) diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 9fd473a6dbf5..6778b7cb39bd 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -773,7 +773,6 @@ static int make_request(struct request_queue *q, struct bio * bio) r1bio_t *r1_bio; struct bio *read_bio; int i, targets = 0, disks; - mdk_rdev_t *rdev; struct bitmap *bitmap = mddev->bitmap; unsigned long flags; struct bio_list bl; @@ -781,6 +780,7 @@ static int make_request(struct request_queue *q, struct bio * bio) const int rw = bio_data_dir(bio); const int do_sync = bio_sync(bio); int do_barriers; + mdk_rdev_t *blocked_rdev; /* * Register the new request and wait if the reconstruction @@ -862,10 +862,17 @@ static int make_request(struct request_queue *q, struct bio * bio) first = 0; } #endif + retry_write: + blocked_rdev = NULL; rcu_read_lock(); for (i = 0; i < disks; i++) { - if ((rdev=rcu_dereference(conf->mirrors[i].rdev)) != NULL && - !test_bit(Faulty, &rdev->flags)) { + mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev); + if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) { + atomic_inc(&rdev->nr_pending); + blocked_rdev = rdev; + break; + } + if (rdev && !test_bit(Faulty, &rdev->flags)) { atomic_inc(&rdev->nr_pending); if (test_bit(Faulty, &rdev->flags)) { rdev_dec_pending(rdev, mddev); @@ -878,6 +885,20 @@ static int make_request(struct request_queue *q, struct bio * bio) } rcu_read_unlock(); + if (unlikely(blocked_rdev)) { + /* Wait for this device to become unblocked */ + int j; + + for (j = 0; j < i; j++) + if (r1_bio->bios[j]) + rdev_dec_pending(conf->mirrors[j].rdev, mddev); + + allow_barrier(conf); + md_wait_for_blocked_rdev(blocked_rdev, mddev); + wait_barrier(conf); + goto retry_write; + } + BUG_ON(targets == 0); /* we never fail the last device */ if (targets < conf->raid_disks) { diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 1e96aa3ff513..5938fa962922 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -790,6 +790,7 @@ static int make_request(struct request_queue *q, struct bio * bio) const int do_sync = bio_sync(bio); struct bio_list bl; unsigned long flags; + mdk_rdev_t *blocked_rdev; if (unlikely(bio_barrier(bio))) { bio_endio(bio, -EOPNOTSUPP); @@ -879,17 +880,23 @@ static int make_request(struct request_queue *q, struct bio * bio) /* * WRITE: */ - /* first select target devices under spinlock and + /* first select target devices under rcu_lock and * inc refcount on their rdev. Record them by setting * bios[x] to bio */ raid10_find_phys(conf, r10_bio); + retry_write: + blocked_rdev = 0; rcu_read_lock(); for (i = 0; i < conf->copies; i++) { int d = r10_bio->devs[i].devnum; mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[d].rdev); - if (rdev && - !test_bit(Faulty, &rdev->flags)) { + if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) { + atomic_inc(&rdev->nr_pending); + blocked_rdev = rdev; + break; + } + if (rdev && !test_bit(Faulty, &rdev->flags)) { atomic_inc(&rdev->nr_pending); r10_bio->devs[i].bio = bio; } else { @@ -899,6 +906,22 @@ static int make_request(struct request_queue *q, struct bio * bio) } rcu_read_unlock(); + if (unlikely(blocked_rdev)) { + /* Have to wait for this device to get unblocked, then retry */ + int j; + int d; + + for (j = 0; j < i; j++) + if (r10_bio->devs[j].bio) { + d = r10_bio->devs[j].devnum; + rdev_dec_pending(conf->mirrors[d].rdev, mddev); + } + allow_barrier(conf); + md_wait_for_blocked_rdev(blocked_rdev, mddev); + wait_barrier(conf); + goto retry_write; + } + atomic_set(&r10_bio->remaining, 0); bio_list_init(&bl); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 968dacaced6d..087eee0cb809 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -2607,6 +2607,7 @@ static void handle_stripe_expansion(raid5_conf_t *conf, struct stripe_head *sh, } } + /* * handle_stripe - do things to a stripe. * @@ -2632,6 +2633,7 @@ static void handle_stripe5(struct stripe_head *sh) struct stripe_head_state s; struct r5dev *dev; unsigned long pending = 0; + mdk_rdev_t *blocked_rdev = NULL; memset(&s, 0, sizeof(s)); pr_debug("handling stripe %llu, state=%#lx cnt=%d, pd_idx=%d " @@ -2691,6 +2693,11 @@ static void handle_stripe5(struct stripe_head *sh) if (dev->written) s.written++; rdev = rcu_dereference(conf->disks[i].rdev); + if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) { + blocked_rdev = rdev; + atomic_inc(&rdev->nr_pending); + break; + } if (!rdev || !test_bit(In_sync, &rdev->flags)) { /* The ReadError flag will just be confusing now */ clear_bit(R5_ReadError, &dev->flags); @@ -2705,6 +2712,11 @@ static void handle_stripe5(struct stripe_head *sh) } rcu_read_unlock(); + if (unlikely(blocked_rdev)) { + set_bit(STRIPE_HANDLE, &sh->state); + goto unlock; + } + if (s.to_fill && !test_and_set_bit(STRIPE_OP_BIOFILL, &sh->ops.pending)) sh->ops.count++; @@ -2894,8 +2906,13 @@ static void handle_stripe5(struct stripe_head *sh) if (sh->ops.count) pending = get_stripe_work(sh); + unlock: spin_unlock(&sh->lock); + /* wait for this device to become unblocked */ + if (unlikely(blocked_rdev)) + md_wait_for_blocked_rdev(blocked_rdev, conf->mddev); + if (pending) raid5_run_ops(sh, pending); @@ -2912,6 +2929,7 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page) struct stripe_head_state s; struct r6_state r6s; struct r5dev *dev, *pdev, *qdev; + mdk_rdev_t *blocked_rdev = NULL; r6s.qd_idx = raid6_next_disk(pd_idx, disks); pr_debug("handling stripe %llu, state=%#lx cnt=%d, " @@ -2975,6 +2993,11 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page) if (dev->written) s.written++; rdev = rcu_dereference(conf->disks[i].rdev); + if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) { + blocked_rdev = rdev; + atomic_inc(&rdev->nr_pending); + break; + } if (!rdev || !test_bit(In_sync, &rdev->flags)) { /* The ReadError flag will just be confusing now */ clear_bit(R5_ReadError, &dev->flags); @@ -2989,6 +3012,11 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page) set_bit(R5_Insync, &dev->flags); } rcu_read_unlock(); + + if (unlikely(blocked_rdev)) { + set_bit(STRIPE_HANDLE, &sh->state); + goto unlock; + } pr_debug("locked=%d uptodate=%d to_read=%d" " to_write=%d failed=%d failed_num=%d,%d\n", s.locked, s.uptodate, s.to_read, s.to_write, s.failed, @@ -3094,8 +3122,13 @@ static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page) !test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending)) handle_stripe_expansion(conf, sh, &r6s); + unlock: spin_unlock(&sh->lock); + /* wait for this device to become unblocked */ + if (unlikely(blocked_rdev)) + md_wait_for_blocked_rdev(blocked_rdev, conf->mddev); + return_io(return_bi); for (i=disks; i-- ;) { diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 128bb9cd5755..ddf57e135c6c 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -5,16 +5,20 @@ menu "Multimedia devices" depends on HAS_IOMEM +comment "Multimedia core support" + +# +# V4L core and enabled API's +# + config VIDEO_DEV tristate "Video For Linux" ---help--- - Support for audio/video capture and overlay devices and FM radio - cards. The exact capabilities of each device vary. + V4L core support for video capture and overlay devices, webcams and + AM/FM radio cards. This kernel includes support for the new Video for Linux Two API, - (V4L2) as well as the original system. Drivers and applications - need to be rewritten to use V4L2, but drivers for popular cards - and applications for most video capture functions already exist. + (V4L2). Additional info and docs are available on the web at <http://linuxtv.org> @@ -36,8 +40,11 @@ config VIDEO_ALLOW_V4L1 default VIDEO_DEV && VIDEO_V4L2_COMMON select VIDEO_V4L1_COMPAT ---help--- - Enables a compatibility API used by most V4L2 devices to allow - its usage with legacy applications that supports only V4L1 api. + Enables drivers based on the legacy V4L1 API. + + This api were developed to be used at Kernel 2.2 and 2.4, but + lacks support for several video standards. There are several + drivers at kernel that still depends on it. If you are unsure as to whether this is required, answer Y. @@ -46,9 +53,8 @@ config VIDEO_V4L1_COMPAT depends on VIDEO_DEV default VIDEO_DEV ---help--- - This api were developed to be used at Kernel 2.2 and 2.4, but - lacks support for several video standards. There are several - drivers at kernel that still depends on it. + Enables a compatibility API used by most V4L2 devices to allow + its usage with legacy applications that supports only V4L1 api. Documentation for the original API is included in the file <Documentation/video4linux/API.html>. @@ -58,135 +64,57 @@ config VIDEO_V4L1_COMPAT If you are unsure as to whether this is required, answer Y. -config VIDEO_V4L2 - tristate - depends on VIDEO_DEV && VIDEO_V4L2_COMMON - default VIDEO_DEV && VIDEO_V4L2_COMMON - -config VIDEO_V4L1 - tristate - depends on VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1 - default VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1 - -source "drivers/media/video/Kconfig" - -source "drivers/media/radio/Kconfig" - -source "drivers/media/dvb/Kconfig" - -source "drivers/media/common/Kconfig" +# +# DVB Core +# -config VIDEO_TUNER - tristate - depends on I2C - select TUNER_XC2028 if !VIDEO_TUNER_CUSTOMIZE - select TUNER_MT20XX if !VIDEO_TUNER_CUSTOMIZE - select TUNER_TDA8290 if !VIDEO_TUNER_CUSTOMIZE - select TUNER_TEA5761 if !VIDEO_TUNER_CUSTOMIZE - select TUNER_TEA5767 if !VIDEO_TUNER_CUSTOMIZE - select TUNER_SIMPLE if !VIDEO_TUNER_CUSTOMIZE - select TUNER_TDA9887 if !VIDEO_TUNER_CUSTOMIZE - -menuconfig VIDEO_TUNER_CUSTOMIZE - bool "Customize analog tuner modules to build" - depends on VIDEO_TUNER +config DVB_CORE + tristate "DVB for Linux" + depends on NET && INET + select CRC32 help - This allows the user to deselect tuner drivers unnecessary - for their hardware from the build. Use this option with care - as deselecting tuner drivers which are in fact necessary will - result in V4L devices which cannot be tuned due to lack of - driver support + DVB core utility functions for device handling, software fallbacks etc. - If unsure say N. - -if VIDEO_TUNER_CUSTOMIZE - -config TUNER_XC2028 - tristate "XCeive xc2028/xc3028 tuners" - depends on I2C && FW_LOADER - default m if VIDEO_TUNER_CUSTOMIZE - help - Say Y here to include support for the xc2028/xc3028 tuners. + Enable this if you own a DVB/ATSC adapter and want to use it or if + you compile Linux for a digital SetTopBox. -config TUNER_MT20XX - tristate "Microtune 2032 / 2050 tuners" - depends on I2C - default m if VIDEO_TUNER_CUSTOMIZE - help - Say Y here to include support for the MT2032 / MT2050 tuner. - -config TUNER_TDA8290 - tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo" - depends on I2C - select DVB_TDA827X - select DVB_TDA18271 - default m if VIDEO_TUNER_CUSTOMIZE - help - Say Y here to include support for Philips TDA8290+8275(a) tuner. + Say Y when you have a DVB or an ATSC card and want to use it. -config TUNER_TEA5761 - tristate "TEA 5761 radio tuner (EXPERIMENTAL)" - depends on I2C && EXPERIMENTAL - default m if VIDEO_TUNER_CUSTOMIZE - help - Say Y here to include support for the Philips TEA5761 radio tuner. + API specs and user tools are available from <http://www.linuxtv.org/>. -config TUNER_TEA5767 - tristate "TEA 5767 radio tuner" - depends on I2C - default m if VIDEO_TUNER_CUSTOMIZE - help - Say Y here to include support for the Philips TEA5767 radio tuner. + Please report problems regarding this support to the LinuxDVB + mailing list. -config TUNER_SIMPLE - tristate "Simple tuner support" - depends on I2C - select TUNER_TDA9887 - default m if VIDEO_TUNER_CUSTOMIZE - help - Say Y here to include support for various simple tuners. + If unsure say N. -config TUNER_TDA9887 - tristate "TDA 9885/6/7 analog IF demodulator" - depends on I2C - default m if VIDEO_TUNER_CUSTOMIZE - help - Say Y here to include support for Philips TDA9885/6/7 - analog IF demodulator. +config VIDEO_MEDIA + tristate + default DVB_CORE || VIDEO_DEV + depends on DVB_CORE || VIDEO_DEV -endif # VIDEO_TUNER_CUSTOMIZE +comment "Multimedia drivers" -config VIDEOBUF_GEN - tristate +source "drivers/media/common/Kconfig" -config VIDEOBUF_DMA_SG - depends on HAS_DMA - select VIDEOBUF_GEN - tristate +# +# Tuner drivers for DVB and V4L +# -config VIDEOBUF_VMALLOC - select VIDEOBUF_GEN - tristate +source "drivers/media/common/tuners/Kconfig" -config VIDEOBUF_DVB - tristate - select VIDEOBUF_GEN - select VIDEOBUF_DMA_SG +# +# Video/Radio/Hybrid adapters +# -config VIDEO_BTCX - tristate +source "drivers/media/video/Kconfig" -config VIDEO_IR_I2C - tristate +source "drivers/media/radio/Kconfig" -config VIDEO_IR - tristate - depends on INPUT - select VIDEO_IR_I2C if I2C +# +# DVB adapters +# -config VIDEO_TVEEPROM - tristate - depends on I2C +source "drivers/media/dvb/Kconfig" config DAB boolean "DAB adapters" diff --git a/drivers/media/Makefile b/drivers/media/Makefile index 7b8bb6949f5e..73f742c7e818 100644 --- a/drivers/media/Makefile +++ b/drivers/media/Makefile @@ -2,10 +2,10 @@ # Makefile for the kernel multimedia device drivers. # -obj-y := common/ -obj-y += video/ +obj-$(CONFIG_VIDEO_MEDIA) += common/ + +# Since hybrid devices are here, should be compiled if DVB and/or V4L +obj-$(CONFIG_VIDEO_MEDIA) += video/ + obj-$(CONFIG_VIDEO_DEV) += radio/ obj-$(CONFIG_DVB_CORE) += dvb/ -ifeq ($(CONFIG_DVB_CORE),) - obj-$(CONFIG_VIDEO_TUNER) += dvb/frontends/ -endif diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile index 8e7448230643..351b98b9b302 100644 --- a/drivers/media/common/Makefile +++ b/drivers/media/common/Makefile @@ -2,6 +2,7 @@ saa7146-objs := saa7146_i2c.o saa7146_core.o saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o ir-common-objs := ir-functions.o ir-keymaps.o +obj-y += tuners/ obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o obj-$(CONFIG_VIDEO_SAA7146_VV) += saa7146_vv.o obj-$(CONFIG_VIDEO_IR) += ir-common.o diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig new file mode 100644 index 000000000000..5be85ff53e12 --- /dev/null +++ b/drivers/media/common/tuners/Kconfig @@ -0,0 +1,151 @@ +config MEDIA_ATTACH + bool "Load and attach frontend and tuner driver modules as needed" + depends on DVB_CORE + depends on MODULES + help + Remove the static dependency of DVB card drivers on all + frontend modules for all possible card variants. Instead, + allow the card drivers to only load the frontend modules + they require. + + Also, tuner module will automatically load a tuner driver + when needed, for analog mode. + + This saves several KBytes of memory. + + Note: You will need module-init-tools v3.2 or later for this feature. + + If unsure say Y. + +config MEDIA_TUNER + tristate + default DVB_CORE || VIDEO_DEV + depends on DVB_CORE || VIDEO_DEV + select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMIZE + +menuconfig MEDIA_TUNER_CUSTOMIZE + bool "Customize analog and hybrid tuner modules to build" + depends on MEDIA_TUNER + help + This allows the user to deselect tuner drivers unnecessary + for their hardware from the build. Use this option with care + as deselecting tuner drivers which are in fact necessary will + result in V4L/DVB devices which cannot be tuned due to lack of + driver support + + If unsure say N. + +if MEDIA_TUNER_CUSTOMIZE + +config MEDIA_TUNER_SIMPLE + tristate "Simple tuner support" + depends on I2C + select MEDIA_TUNER_TDA9887 + default m if MEDIA_TUNER_CUSTOMIZE + help + Say Y here to include support for various simple tuners. + +config MEDIA_TUNER_TDA8290 + tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo" + depends on I2C + select MEDIA_TUNER_TDA827X + select MEDIA_TUNER_TDA18271 + default m if MEDIA_TUNER_CUSTOMIZE + help + Say Y here to include support for Philips TDA8290+8275(a) tuner. + +config MEDIA_TUNER_TDA827X + tristate "Philips TDA827X silicon tuner" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-T silicon tuner module. Say Y when you want to support this tuner. + +config MEDIA_TUNER_TDA18271 + tristate "NXP TDA18271 silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A silicon tuner module. Say Y when you want to support this tuner. + +config MEDIA_TUNER_TDA9887 + tristate "TDA 9885/6/7 analog IF demodulator" + depends on I2C + default m if MEDIA_TUNER_CUSTOMIZE + help + Say Y here to include support for Philips TDA9885/6/7 + analog IF demodulator. + +config MEDIA_TUNER_TEA5761 + tristate "TEA 5761 radio tuner (EXPERIMENTAL)" + depends on I2C && EXPERIMENTAL + default m if MEDIA_TUNER_CUSTOMIZE + help + Say Y here to include support for the Philips TEA5761 radio tuner. + +config MEDIA_TUNER_TEA5767 + tristate "TEA 5767 radio tuner" + depends on I2C + default m if MEDIA_TUNER_CUSTOMIZE + help + Say Y here to include support for the Philips TEA5767 radio tuner. + +config MEDIA_TUNER_MT20XX + tristate "Microtune 2032 / 2050 tuners" + depends on I2C + default m if MEDIA_TUNER_CUSTOMIZE + help + Say Y here to include support for the MT2032 / MT2050 tuner. + +config MEDIA_TUNER_MT2060 + tristate "Microtune MT2060 silicon IF tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon IF tuner MT2060 from Microtune. + +config MEDIA_TUNER_MT2266 + tristate "Microtune MT2266 silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon baseband tuner MT2266 from Microtune. + +config MEDIA_TUNER_MT2131 + tristate "Microtune MT2131 silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon baseband tuner MT2131 from Microtune. + +config MEDIA_TUNER_QT1010 + tristate "Quantek QT1010 silicon tuner" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon tuner QT1010 from Quantek. + +config MEDIA_TUNER_XC2028 + tristate "XCeive xc2028/xc3028 tuners" + depends on I2C && FW_LOADER + default m if MEDIA_TUNER_CUSTOMIZE + help + Say Y here to include support for the xc2028/xc3028 tuners. + +config MEDIA_TUNER_XC5000 + tristate "Xceive XC5000 silicon tuner" + depends on I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon tuner XC5000 from Xceive. + This device is only used inside a SiP called togther with a + demodulator for now. + +endif # MEDIA_TUNER_CUSTOMIZE diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile new file mode 100644 index 000000000000..236d9932fd92 --- /dev/null +++ b/drivers/media/common/tuners/Makefile @@ -0,0 +1,25 @@ +# +# Makefile for common V4L/DVB tuners +# + +tda18271-objs := tda18271-maps.o tda18271-common.o tda18271-fe.o + +obj-$(CONFIG_MEDIA_TUNER_XC2028) += tuner-xc2028.o +obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-simple.o +# tuner-types will be merged into tuner-simple, in the future +obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-types.o +obj-$(CONFIG_MEDIA_TUNER_MT20XX) += mt20xx.o +obj-$(CONFIG_MEDIA_TUNER_TDA8290) += tda8290.o +obj-$(CONFIG_MEDIA_TUNER_TEA5767) += tea5767.o +obj-$(CONFIG_MEDIA_TUNER_TEA5761) += tea5761.o +obj-$(CONFIG_MEDIA_TUNER_TDA9887) += tda9887.o +obj-$(CONFIG_MEDIA_TUNER_TDA827X) += tda827x.o +obj-$(CONFIG_MEDIA_TUNER_TDA18271) += tda18271.o +obj-$(CONFIG_MEDIA_TUNER_XC5000) += xc5000.o +obj-$(CONFIG_MEDIA_TUNER_MT2060) += mt2060.o +obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o +obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o +obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/dvb/frontends/mt2060.c b/drivers/media/common/tuners/mt2060.c index 1305b0e63ce5..1305b0e63ce5 100644 --- a/drivers/media/dvb/frontends/mt2060.c +++ b/drivers/media/common/tuners/mt2060.c diff --git a/drivers/media/dvb/frontends/mt2060.h b/drivers/media/common/tuners/mt2060.h index acba0058f519..cb60caffb6b6 100644 --- a/drivers/media/dvb/frontends/mt2060.h +++ b/drivers/media/common/tuners/mt2060.h @@ -30,7 +30,7 @@ struct mt2060_config { u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ }; -#if defined(CONFIG_DVB_TUNER_MT2060) || (defined(CONFIG_DVB_TUNER_MT2060_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_MT2060) || (defined(CONFIG_MEDIA_TUNER_MT2060_MODULE) && defined(MODULE)) extern struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1); #else static inline struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1) @@ -38,6 +38,6 @@ static inline struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struc printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -#endif // CONFIG_DVB_TUNER_MT2060 +#endif // CONFIG_MEDIA_TUNER_MT2060 #endif diff --git a/drivers/media/dvb/frontends/mt2060_priv.h b/drivers/media/common/tuners/mt2060_priv.h index 5eaccdefd0b0..5eaccdefd0b0 100644 --- a/drivers/media/dvb/frontends/mt2060_priv.h +++ b/drivers/media/common/tuners/mt2060_priv.h diff --git a/drivers/media/video/mt20xx.c b/drivers/media/common/tuners/mt20xx.c index fbcb28233737..fbcb28233737 100644 --- a/drivers/media/video/mt20xx.c +++ b/drivers/media/common/tuners/mt20xx.c diff --git a/drivers/media/video/mt20xx.h b/drivers/media/common/tuners/mt20xx.h index aa848e14ce5e..259553a24903 100644 --- a/drivers/media/video/mt20xx.h +++ b/drivers/media/common/tuners/mt20xx.h @@ -20,7 +20,7 @@ #include <linux/i2c.h> #include "dvb_frontend.h" -#if defined(CONFIG_TUNER_MT20XX) || (defined(CONFIG_TUNER_MT20XX_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_MT20XX) || (defined(CONFIG_MEDIA_TUNER_MT20XX_MODULE) && defined(MODULE)) extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, struct i2c_adapter* i2c_adap, u8 i2c_addr); diff --git a/drivers/media/dvb/frontends/mt2131.c b/drivers/media/common/tuners/mt2131.c index e254bcfc2efb..e254bcfc2efb 100644 --- a/drivers/media/dvb/frontends/mt2131.c +++ b/drivers/media/common/tuners/mt2131.c diff --git a/drivers/media/dvb/frontends/mt2131.h b/drivers/media/common/tuners/mt2131.h index 606d8576bc98..cd8376f6f7b4 100644 --- a/drivers/media/dvb/frontends/mt2131.h +++ b/drivers/media/common/tuners/mt2131.h @@ -30,7 +30,7 @@ struct mt2131_config { u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ }; -#if defined(CONFIG_DVB_TUNER_MT2131) || (defined(CONFIG_DVB_TUNER_MT2131_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_MT2131) || (defined(CONFIG_MEDIA_TUNER_MT2131_MODULE) && defined(MODULE)) extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2131_config *cfg, @@ -44,7 +44,7 @@ static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -#endif /* CONFIG_DVB_TUNER_MT2131 */ +#endif /* CONFIG_MEDIA_TUNER_MT2131 */ #endif /* __MT2131_H__ */ diff --git a/drivers/media/dvb/frontends/mt2131_priv.h b/drivers/media/common/tuners/mt2131_priv.h index e930759c2c00..e930759c2c00 100644 --- a/drivers/media/dvb/frontends/mt2131_priv.h +++ b/drivers/media/common/tuners/mt2131_priv.h diff --git a/drivers/media/dvb/frontends/mt2266.c b/drivers/media/common/tuners/mt2266.c index 54b18f94b14b..54b18f94b14b 100644 --- a/drivers/media/dvb/frontends/mt2266.c +++ b/drivers/media/common/tuners/mt2266.c diff --git a/drivers/media/dvb/frontends/mt2266.h b/drivers/media/common/tuners/mt2266.h index c5113efe333c..4d083882d044 100644 --- a/drivers/media/dvb/frontends/mt2266.h +++ b/drivers/media/common/tuners/mt2266.h @@ -24,7 +24,7 @@ struct mt2266_config { u8 i2c_address; }; -#if defined(CONFIG_DVB_TUNER_MT2266) || (defined(CONFIG_DVB_TUNER_MT2266_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_MT2266) || (defined(CONFIG_MEDIA_TUNER_MT2266_MODULE) && defined(MODULE)) extern struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg); #else static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg) @@ -32,6 +32,6 @@ static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struc printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -#endif // CONFIG_DVB_TUNER_MT2266 +#endif // CONFIG_MEDIA_TUNER_MT2266 #endif diff --git a/drivers/media/dvb/frontends/qt1010.c b/drivers/media/common/tuners/qt1010.c index 825aa1412e6f..825aa1412e6f 100644 --- a/drivers/media/dvb/frontends/qt1010.c +++ b/drivers/media/common/tuners/qt1010.c diff --git a/drivers/media/dvb/frontends/qt1010.h b/drivers/media/common/tuners/qt1010.h index cff6a7ca5380..807fb7b6146b 100644 --- a/drivers/media/dvb/frontends/qt1010.h +++ b/drivers/media/common/tuners/qt1010.h @@ -36,7 +36,7 @@ struct qt1010_config { * @param cfg tuner hw based configuration * @return fe pointer on success, NULL on failure */ -#if defined(CONFIG_DVB_TUNER_QT1010) || (defined(CONFIG_DVB_TUNER_QT1010_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_QT1010) || (defined(CONFIG_MEDIA_TUNER_QT1010_MODULE) && defined(MODULE)) extern struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct qt1010_config *cfg); @@ -48,6 +48,6 @@ static inline struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe, printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -#endif // CONFIG_DVB_TUNER_QT1010 +#endif // CONFIG_MEDIA_TUNER_QT1010 #endif diff --git a/drivers/media/dvb/frontends/qt1010_priv.h b/drivers/media/common/tuners/qt1010_priv.h index 090cf475f099..090cf475f099 100644 --- a/drivers/media/dvb/frontends/qt1010_priv.h +++ b/drivers/media/common/tuners/qt1010_priv.h diff --git a/drivers/media/dvb/frontends/tda18271-common.c b/drivers/media/common/tuners/tda18271-common.c index e27a7620a32f..e27a7620a32f 100644 --- a/drivers/media/dvb/frontends/tda18271-common.c +++ b/drivers/media/common/tuners/tda18271-common.c diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c index b262100ae897..b262100ae897 100644 --- a/drivers/media/dvb/frontends/tda18271-fe.c +++ b/drivers/media/common/tuners/tda18271-fe.c diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/common/tuners/tda18271-maps.c index 83e7561960c1..83e7561960c1 100644 --- a/drivers/media/dvb/frontends/tda18271-tables.c +++ b/drivers/media/common/tuners/tda18271-maps.c diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/common/tuners/tda18271-priv.h index 2bc5eb368ea2..2bc5eb368ea2 100644 --- a/drivers/media/dvb/frontends/tda18271-priv.h +++ b/drivers/media/common/tuners/tda18271-priv.h diff --git a/drivers/media/dvb/frontends/tda18271.h b/drivers/media/common/tuners/tda18271.h index 0e7af8d05a38..7db9831c0cb0 100644 --- a/drivers/media/dvb/frontends/tda18271.h +++ b/drivers/media/common/tuners/tda18271.h @@ -81,7 +81,7 @@ struct tda18271_config { unsigned int small_i2c:1; }; -#if defined(CONFIG_DVB_TDA18271) || (defined(CONFIG_DVB_TDA18271_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_TDA18271) || (defined(CONFIG_MEDIA_TUNER_TDA18271_MODULE) && defined(MODULE)) extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, struct i2c_adapter *i2c, struct tda18271_config *cfg); diff --git a/drivers/media/dvb/frontends/tda827x.c b/drivers/media/common/tuners/tda827x.c index d30d2c9094d9..d30d2c9094d9 100644 --- a/drivers/media/dvb/frontends/tda827x.c +++ b/drivers/media/common/tuners/tda827x.c diff --git a/drivers/media/dvb/frontends/tda827x.h b/drivers/media/common/tuners/tda827x.h index b73c23570dab..7850a9a1dc8f 100644 --- a/drivers/media/dvb/frontends/tda827x.h +++ b/drivers/media/common/tuners/tda827x.h @@ -51,7 +51,7 @@ struct tda827x_config * @param cfg optional callback function pointers. * @return FE pointer on success, NULL on failure. */ -#if defined(CONFIG_DVB_TDA827X) || (defined(CONFIG_DVB_TDA827X_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_TDA827X) || (defined(CONFIG_MEDIA_TUNER_TDA827X_MODULE) && defined(MODULE)) extern struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c, struct tda827x_config *cfg); @@ -64,6 +64,6 @@ static inline struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -#endif // CONFIG_DVB_TDA827X +#endif // CONFIG_MEDIA_TUNER_TDA827X #endif // __DVB_TDA827X_H__ diff --git a/drivers/media/video/tda8290.c b/drivers/media/common/tuners/tda8290.c index 0ebb5b525e57..91204d3f282d 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/common/tuners/tda8290.c @@ -578,16 +578,16 @@ static int tda829x_find_tuner(struct dvb_frontend *fe) if ((data == 0x83) || (data == 0x84)) { priv->ver |= TDA18271; - tda18271_attach(fe, priv->tda827x_addr, - priv->i2c_props.adap, - &tda829x_tda18271_config); + dvb_attach(tda18271_attach, fe, priv->tda827x_addr, + priv->i2c_props.adap, &tda829x_tda18271_config); } else { if ((data & 0x3c) == 0) priv->ver |= TDA8275; else priv->ver |= TDA8275A; - tda827x_attach(fe, priv->tda827x_addr, priv->i2c_props.adap, &priv->cfg); + dvb_attach(tda827x_attach, fe, priv->tda827x_addr, + priv->i2c_props.adap, &priv->cfg); priv->cfg.switch_addr = priv->i2c_props.addr; } if (fe->ops.tuner_ops.init) diff --git a/drivers/media/video/tda8290.h b/drivers/media/common/tuners/tda8290.h index d3bbf276a469..aa074f3f0c07 100644 --- a/drivers/media/video/tda8290.h +++ b/drivers/media/common/tuners/tda8290.h @@ -29,7 +29,7 @@ struct tda829x_config { #define TDA829X_DONT_PROBE 1 }; -#if defined(CONFIG_TUNER_TDA8290) || (defined(CONFIG_TUNER_TDA8290_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_TDA8290) || (defined(CONFIG_MEDIA_TUNER_TDA8290_MODULE) && defined(MODULE)) extern int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr); extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, diff --git a/drivers/media/video/tda9887.c b/drivers/media/common/tuners/tda9887.c index a0545ba957b0..a0545ba957b0 100644 --- a/drivers/media/video/tda9887.c +++ b/drivers/media/common/tuners/tda9887.c diff --git a/drivers/media/video/tda9887.h b/drivers/media/common/tuners/tda9887.h index be49dcbfc70e..acc419e8c4fc 100644 --- a/drivers/media/video/tda9887.h +++ b/drivers/media/common/tuners/tda9887.h @@ -21,7 +21,7 @@ #include "dvb_frontend.h" /* ------------------------------------------------------------------------ */ -#if defined(CONFIG_TUNER_TDA9887) || (defined(CONFIG_TUNER_TDA9887_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_TDA9887) || (defined(CONFIG_MEDIA_TUNER_TDA9887_MODULE) && defined(MODULE)) extern struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c_adap, u8 i2c_addr); diff --git a/drivers/media/video/tea5761.c b/drivers/media/common/tuners/tea5761.c index b93cdef9ac73..b93cdef9ac73 100644 --- a/drivers/media/video/tea5761.c +++ b/drivers/media/common/tuners/tea5761.c diff --git a/drivers/media/video/tea5761.h b/drivers/media/common/tuners/tea5761.h index 8eb62722b988..2e2ff82c95a4 100644 --- a/drivers/media/video/tea5761.h +++ b/drivers/media/common/tuners/tea5761.h @@ -20,7 +20,7 @@ #include <linux/i2c.h> #include "dvb_frontend.h" -#if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE)) extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, diff --git a/drivers/media/video/tea5767.c b/drivers/media/common/tuners/tea5767.c index f6e7d7ad8424..f6e7d7ad8424 100644 --- a/drivers/media/video/tea5767.c +++ b/drivers/media/common/tuners/tea5767.c diff --git a/drivers/media/video/tea5767.h b/drivers/media/common/tuners/tea5767.h index 7b547c092e25..d30ab1b483de 100644 --- a/drivers/media/video/tea5767.h +++ b/drivers/media/common/tuners/tea5767.h @@ -39,7 +39,7 @@ struct tea5767_ctrl { enum tea5767_xtal xtal_freq; }; -#if defined(CONFIG_TUNER_TEA5767) || (defined(CONFIG_TUNER_TEA5767_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_TEA5767) || (defined(CONFIG_MEDIA_TUNER_TEA5767_MODULE) && defined(MODULE)) extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, diff --git a/drivers/media/video/tuner-i2c.h b/drivers/media/common/tuners/tuner-i2c.h index 3ad6c8e0b04c..3ad6c8e0b04c 100644 --- a/drivers/media/video/tuner-i2c.h +++ b/drivers/media/common/tuners/tuner-i2c.h diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/common/tuners/tuner-simple.c index be8d903171b7..be8d903171b7 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/common/tuners/tuner-simple.c diff --git a/drivers/media/video/tuner-simple.h b/drivers/media/common/tuners/tuner-simple.h index e46cf0121e03..381fa5d35a9b 100644 --- a/drivers/media/video/tuner-simple.h +++ b/drivers/media/common/tuners/tuner-simple.h @@ -20,7 +20,7 @@ #include <linux/i2c.h> #include "dvb_frontend.h" -#if defined(CONFIG_TUNER_SIMPLE) || (defined(CONFIG_TUNER_SIMPLE_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_SIMPLE) || (defined(CONFIG_MEDIA_TUNER_SIMPLE_MODULE) && defined(MODULE)) extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c_adap, u8 i2c_addr, diff --git a/drivers/media/video/tuner-types.c b/drivers/media/common/tuners/tuner-types.c index 10dddca8b5d1..10dddca8b5d1 100644 --- a/drivers/media/video/tuner-types.c +++ b/drivers/media/common/tuners/tuner-types.c diff --git a/drivers/media/video/tuner-xc2028-types.h b/drivers/media/common/tuners/tuner-xc2028-types.h index 74dc46a71f64..74dc46a71f64 100644 --- a/drivers/media/video/tuner-xc2028-types.h +++ b/drivers/media/common/tuners/tuner-xc2028-types.h diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c index 9e9003cffc7f..9e9003cffc7f 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/common/tuners/tuner-xc2028.c diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/common/tuners/tuner-xc2028.h index fc2f132a5541..216025cf5d4b 100644 --- a/drivers/media/video/tuner-xc2028.h +++ b/drivers/media/common/tuners/tuner-xc2028.h @@ -47,7 +47,7 @@ struct xc2028_config { #define XC2028_TUNER_RESET 0 #define XC2028_RESET_CLK 1 -#if defined(CONFIG_TUNER_XC2028) || (defined(CONFIG_TUNER_XC2028_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_XC2028) || (defined(CONFIG_MEDIA_TUNER_XC2028_MODULE) && defined(MODULE)) extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, struct xc2028_config *cfg); #else diff --git a/drivers/media/dvb/frontends/xc5000.c b/drivers/media/common/tuners/xc5000.c index 43d35bdb221f..43d35bdb221f 100644 --- a/drivers/media/dvb/frontends/xc5000.c +++ b/drivers/media/common/tuners/xc5000.c diff --git a/drivers/media/dvb/frontends/xc5000.h b/drivers/media/common/tuners/xc5000.h index b890883a0cdc..0ee80f9d19b8 100644 --- a/drivers/media/dvb/frontends/xc5000.h +++ b/drivers/media/common/tuners/xc5000.h @@ -45,8 +45,8 @@ struct xc5000_config { /* xc5000 callback command */ #define XC5000_TUNER_RESET 0 -#if defined(CONFIG_DVB_TUNER_XC5000) || \ - (defined(CONFIG_DVB_TUNER_XC5000_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_XC5000) || \ + (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE)) extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct xc5000_config *cfg); @@ -58,6 +58,6 @@ static inline struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe, printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -#endif // CONFIG_DVB_TUNER_XC5000 +#endif // CONFIG_MEDIA_TUNER_XC5000 #endif // __XC5000_H__ diff --git a/drivers/media/dvb/frontends/xc5000_priv.h b/drivers/media/common/tuners/xc5000_priv.h index 13b2d19341da..13b2d19341da 100644 --- a/drivers/media/dvb/frontends/xc5000_priv.h +++ b/drivers/media/common/tuners/xc5000_priv.h diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index 03ef88acd9b8..7b21b49f1945 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig @@ -1,9 +1,7 @@ # -# Multimedia device configuration +# DVB device configuration # -source "drivers/media/dvb/dvb-core/Kconfig" - menuconfig DVB_CAPTURE_DRIVERS bool "DVB/ATSC adapters" depends on DVB_CORE diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig index 6ec5afba1ca7..73dc2ee9b014 100644 --- a/drivers/media/dvb/b2c2/Kconfig +++ b/drivers/media/dvb/b2c2/Kconfig @@ -9,7 +9,7 @@ config DVB_B2C2_FLEXCOP select DVB_STV0297 if !DVB_FE_CUSTOMISE select DVB_BCM3510 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select TUNER_SIMPLE if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE select DVB_S5H1420 if !DVB_FE_CUSTOMISE select DVB_TUNER_ITD1000 if !DVB_FE_CUSTOMISE select DVB_ISL6421 if !DVB_FE_CUSTOMISE diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile index 870e2848c296..d9db066f9854 100644 --- a/drivers/media/dvb/b2c2/Makefile +++ b/drivers/media/dvb/b2c2/Makefile @@ -14,4 +14,4 @@ b2c2-flexcop-usb-objs = flexcop-usb.o obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ -EXTRA_CFLAGS += -Idrivers/media/video/ +EXTRA_CFLAGS += -Idrivers/media/common/tuners/ diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig index 902c762e0b7f..d1239b8342f8 100644 --- a/drivers/media/dvb/bt8xx/Kconfig +++ b/drivers/media/dvb/bt8xx/Kconfig @@ -8,7 +8,7 @@ config DVB_BT8XX select DVB_OR51211 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select TUNER_SIMPLE if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE select FW_LOADER help Support for PCI cards based on the Bt8xx PCI bridge. Examples are diff --git a/drivers/media/dvb/bt8xx/Makefile b/drivers/media/dvb/bt8xx/Makefile index 9d3e68b5d6eb..d98f1d49ffa8 100644 --- a/drivers/media/dvb/bt8xx/Makefile +++ b/drivers/media/dvb/bt8xx/Makefile @@ -3,4 +3,4 @@ obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends EXTRA_CFLAGS += -Idrivers/media/video/bt8xx -EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index 75711bde23ad..a7637562e742 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -1714,7 +1714,7 @@ static void dst_release(struct dvb_frontend *fe) struct dst_state *state = fe->demodulator_priv; if (state->dst_ca) { dvb_unregister_device(state->dst_ca); -#ifdef CONFIG_DVB_CORE_ATTACH +#ifdef CONFIG_MEDIA_ATTACH symbol_put(dst_ca_attach); #endif } diff --git a/drivers/media/dvb/dvb-core/Kconfig b/drivers/media/dvb/dvb-core/Kconfig deleted file mode 100644 index e3e6839f8073..000000000000 --- a/drivers/media/dvb/dvb-core/Kconfig +++ /dev/null @@ -1,34 +0,0 @@ -config DVB_CORE - tristate "DVB for Linux" - depends on NET && INET - select CRC32 - help - Support Digital Video Broadcasting hardware. Enable this if you - own a DVB adapter and want to use it or if you compile Linux for - a digital SetTopBox. - - DVB core utility functions for device handling, software fallbacks etc. - Say Y when you have a DVB card and want to use it. Say Y if your want - to build your drivers outside the kernel, but need the DVB core. All - in-kernel drivers will select this automatically if needed. - - API specs and user tools are available from <http://www.linuxtv.org/>. - - Please report problems regarding this driver to the LinuxDVB - mailing list. - - If unsure say N. - -config DVB_CORE_ATTACH - bool "Load and attach frontend modules as needed" - depends on DVB_CORE - depends on MODULES - help - Remove the static dependency of DVB card drivers on all - frontend modules for all possible card variants. Instead, - allow the card drivers to only load the frontend modules - they require. This saves several KBytes of memory. - - Note: You will need module-init-tools v3.2 or later for this feature. - - If unsure say Y. diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index 2dddd08c5445..8cbdb218952f 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1189,7 +1189,7 @@ int dvb_unregister_frontend(struct dvb_frontend* fe) } EXPORT_SYMBOL(dvb_unregister_frontend); -#ifdef CONFIG_DVB_CORE_ATTACH +#ifdef CONFIG_MEDIA_ATTACH void dvb_frontend_detach(struct dvb_frontend* fe) { void *ptr; diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h index 5f9a737c6de1..89d12dc477a7 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.h +++ b/drivers/media/dvb/dvb-core/dvbdev.h @@ -115,7 +115,7 @@ extern int dvb_usercopy(struct inode *inode, struct file *file, unsigned int cmd, void *arg)); /** generic DVB attach function. */ -#ifdef CONFIG_DVB_CORE_ATTACH +#ifdef CONFIG_MEDIA_ATTACH #define dvb_attach(FUNCTION, ARGS...) ({ \ void *__r = NULL; \ typeof(&FUNCTION) __a = symbol_request(FUNCTION); \ diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index 3c8493d2026d..4c1cff9feb2e 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -25,7 +25,7 @@ config DVB_USB_A800 tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)" depends on DVB_USB select DVB_DIB3000MC - select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE select DVB_PLL if !DVB_FE_CUSTOMISE help Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver. @@ -35,7 +35,7 @@ config DVB_USB_DIBUSB_MB depends on DVB_USB select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_DIB3000MB - select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE help Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator. @@ -56,7 +56,7 @@ config DVB_USB_DIBUSB_MC tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)" depends on DVB_USB select DVB_DIB3000MC - select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE help Support for USB2.0 DVB-T receivers based on reference designs made by DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator. @@ -73,8 +73,8 @@ config DVB_USB_DIB0700 select DVB_DIB7000P select DVB_DIB7000M select DVB_DIB3000MC - select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE - select DVB_TUNER_MT2266 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2266 if !DVB_FE_CUSTOMISE select DVB_TUNER_DIB0070 help Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The @@ -93,7 +93,7 @@ config DVB_USB_UMT_010 depends on DVB_USB select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_DIB3000MC - select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE help Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver. @@ -105,7 +105,7 @@ config DVB_USB_CXUSB select DVB_LGDT330X if !DVB_FE_CUSTOMISE select DVB_MT352 if !DVB_FE_CUSTOMISE select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select TUNER_SIMPLE if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE help Say Y here to support the Conexant USB2.0 hybrid reference design. Currently, only DVB and ATSC modes are supported, analog mode @@ -118,7 +118,7 @@ config DVB_USB_M920X tristate "Uli m920x DVB-T USB2.0 support" depends on DVB_USB select DVB_MT352 if !DVB_FE_CUSTOMISE - select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE help Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver. Currently, only devices with a product id of @@ -129,7 +129,7 @@ config DVB_USB_GL861 tristate "Genesys Logic GL861 USB2.0 support" depends on DVB_USB select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE help Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0 receiver with USB ID 0db0:5581. @@ -138,7 +138,7 @@ config DVB_USB_AU6610 tristate "Alcor Micro AU6610 USB2.0 support" depends on DVB_USB select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE help Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver. @@ -190,7 +190,7 @@ config DVB_USB_NOVA_T_USB2 tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support" depends on DVB_USB select DVB_DIB3000MC - select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE select DVB_PLL if !DVB_FE_CUSTOMISE help Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver. @@ -227,8 +227,8 @@ config DVB_USB_OPERA1 config DVB_USB_AF9005 tristate "Afatech AF9005 DVB-T USB1.1 support" depends on DVB_USB && EXPERIMENTAL - select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE - select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE help Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver and the TerraTec Cinergy T USB XE (Rev.1) diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 60a910052c16..c6511a6c0ab8 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -63,5 +63,5 @@ obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ # due to tuner-xc3028 -EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index f5fceb3cdb3c..6d2384605927 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -15,22 +15,36 @@ config DVB_FE_CUSTOMISE comment "DVB-S (satellite) frontends" depends on DVB_CORE -config DVB_STV0299 - tristate "ST STV0299 based" +config DVB_CX24110 + tristate "Conexant CX24110 based" depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE help A DVB-S tuner module. Say Y when you want to support this frontend. -config DVB_CX24110 - tristate "Conexant CX24110 based" +config DVB_CX24123 + tristate "Conexant CX24123 based" depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE help A DVB-S tuner module. Say Y when you want to support this frontend. -config DVB_CX24123 - tristate "Conexant CX24123 based" +config DVB_MT312 + tristate "Zarlink VP310/MT312 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + +config DVB_S5H1420 + tristate "Samsung S5H1420 based" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + +config DVB_STV0299 + tristate "ST STV0299 based" depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE help @@ -43,8 +57,8 @@ config DVB_TDA8083 help A DVB-S tuner module. Say Y when you want to support this frontend. -config DVB_MT312 - tristate "Zarlink VP310/MT312 based" +config DVB_TDA10086 + tristate "Philips TDA10086 based" depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE help @@ -57,19 +71,26 @@ config DVB_VES1X93 help A DVB-S tuner module. Say Y when you want to support this frontend. -config DVB_S5H1420 - tristate "Samsung S5H1420 based" +config DVB_TUNER_ITD1000 + tristate "Integrant ITD1000 Zero IF tuner for DVB-S/DSS" depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE help A DVB-S tuner module. Say Y when you want to support this frontend. -config DVB_TDA10086 - tristate "Philips TDA10086 based" +config DVB_TDA826X + tristate "Philips TDA826X silicon tuner" depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE help - A DVB-S tuner module. Say Y when you want to support this frontend. + A DVB-S silicon tuner module. Say Y when you want to support this tuner. + +config DVB_TUA6100 + tristate "Infineon TUA6100 PLL" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DVB-S PLL chip. comment "DVB-T (terrestrial) frontends" depends on DVB_CORE @@ -315,7 +336,7 @@ config DVB_S5H1411 An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. -comment "Tuners/PLL support" +comment "Digital terrestrial only tuners/PLL" depends on DVB_CORE config DVB_PLL @@ -326,55 +347,6 @@ config DVB_PLL This module drives a number of tuners based on PLL chips with a common I2C interface. Say Y when you want to support these tuners. -config DVB_TDA826X - tristate "Philips TDA826X silicon tuner" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-S silicon tuner module. Say Y when you want to support this tuner. - -config DVB_TDA827X - tristate "Philips TDA827X silicon tuner" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVB-T silicon tuner module. Say Y when you want to support this tuner. - -config DVB_TDA18271 - tristate "NXP TDA18271 silicon tuner" - depends on I2C - default m if DVB_FE_CUSTOMISE - help - A silicon tuner module. Say Y when you want to support this tuner. - -config DVB_TUNER_QT1010 - tristate "Quantek QT1010 silicon tuner" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A driver for the silicon tuner QT1010 from Quantek. - -config DVB_TUNER_MT2060 - tristate "Microtune MT2060 silicon IF tuner" - depends on I2C - default m if DVB_FE_CUSTOMISE - help - A driver for the silicon IF tuner MT2060 from Microtune. - -config DVB_TUNER_MT2266 - tristate "Microtune MT2266 silicon tuner" - depends on I2C - default m if DVB_FE_CUSTOMISE - help - A driver for the silicon baseband tuner MT2266 from Microtune. - -config DVB_TUNER_MT2131 - tristate "Microtune MT2131 silicon tuner" - depends on I2C - default m if DVB_FE_CUSTOMISE - help - A driver for the silicon baseband tuner MT2131 from Microtune. - config DVB_TUNER_DIB0070 tristate "DiBcom DiB0070 silicon base-band tuner" depends on I2C @@ -384,21 +356,7 @@ config DVB_TUNER_DIB0070 This device is only used inside a SiP called togther with a demodulator for now. -config DVB_TUNER_XC5000 - tristate "Xceive XC5000 silicon tuner" - depends on I2C - default m if DVB_FE_CUSTOMISE - help - A driver for the silicon tuner XC5000 from Xceive. - This device is only used inside a SiP called togther with a - demodulator for now. - -config DVB_TUNER_ITD1000 - tristate "Integrant ITD1000 Zero IF tuner for DVB-S/DSS" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - -comment "Miscellaneous devices" +comment "SEC control devices for DVB-S" depends on DVB_CORE config DVB_LNBP21 @@ -422,11 +380,4 @@ config DVB_ISL6421 help An SEC control chip. -config DVB_TUA6100 - tristate "TUA6100 PLL" - depends on DVB_CORE && I2C - default m if DVB_FE_CUSTOMISE - help - A DVBS PLL chip. - endmenu diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 9747c73dc826..a89dc0fc4c6f 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -3,9 +3,7 @@ # EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -EXTRA_CFLAGS += -Idrivers/media/video/ - -tda18271-objs := tda18271-tables.o tda18271-common.o tda18271-fe.o +EXTRA_CFLAGS += -Idrivers/media/common/tuners/ obj-$(CONFIG_DVB_PLL) += dvb-pll.o obj-$(CONFIG_DVB_STV0299) += stv0299.o @@ -42,16 +40,9 @@ obj-$(CONFIG_DVB_ISL6405) += isl6405.o obj-$(CONFIG_DVB_ISL6421) += isl6421.o obj-$(CONFIG_DVB_TDA10086) += tda10086.o obj-$(CONFIG_DVB_TDA826X) += tda826x.o -obj-$(CONFIG_DVB_TDA827X) += tda827x.o -obj-$(CONFIG_DVB_TDA18271) += tda18271.o -obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o -obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o -obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o obj-$(CONFIG_DVB_TUA6100) += tua6100.o -obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o obj-$(CONFIG_DVB_S5H1409) += s5h1409.o -obj-$(CONFIG_DVB_TUNER_XC5000) += xc5000.o obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o obj-$(CONFIG_DVB_AU8522) += au8522.o obj-$(CONFIG_DVB_TDA10048) += tda10048.o diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c index 281e1cb2edc6..720ed9ff7c5f 100644 --- a/drivers/media/dvb/frontends/s5h1420.c +++ b/drivers/media/dvb/frontends/s5h1420.c @@ -481,7 +481,7 @@ static void s5h1420_setsymbolrate(struct s5h1420_state* state, val *= 2; do_div(val, (state->fclk / 1000)); - dprintk("symbol rate register: %06llx\n", val); + dprintk("symbol rate register: %06llx\n", (unsigned long long)val); v = s5h1420_readreg(state, Loop01); s5h1420_writereg(state, Loop01, v & 0x7f); diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index fe9a4cc14141..fe743aa7f645 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -1,4 +1,50 @@ # +# Generic video config states +# + +config VIDEO_V4L2 + tristate + depends on VIDEO_DEV && VIDEO_V4L2_COMMON + default VIDEO_DEV && VIDEO_V4L2_COMMON + +config VIDEO_V4L1 + tristate + depends on VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1 + default VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1 + +config VIDEOBUF_GEN + tristate + +config VIDEOBUF_DMA_SG + depends on HAS_DMA + select VIDEOBUF_GEN + tristate + +config VIDEOBUF_VMALLOC + select VIDEOBUF_GEN + tristate + +config VIDEOBUF_DVB + tristate + select VIDEOBUF_GEN + select VIDEOBUF_DMA_SG + +config VIDEO_BTCX + tristate + +config VIDEO_IR_I2C + tristate + +config VIDEO_IR + tristate + depends on INPUT + select VIDEO_IR_I2C if I2C + +config VIDEO_TVEEPROM + tristate + depends on I2C + +# # Multimedia Video device configuration # @@ -644,7 +690,7 @@ config VIDEO_MXB tristate "Siemens-Nixdorf 'Multimedia eXtension Board'" depends on PCI && VIDEO_V4L1 && I2C select VIDEO_SAA7146_VV - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO select VIDEO_TDA9840 if VIDEO_HELPER_CHIPS_AUTO select VIDEO_TEA6415C if VIDEO_HELPER_CHIPS_AUTO @@ -702,6 +748,8 @@ source "drivers/media/video/au0828/Kconfig" source "drivers/media/video/ivtv/Kconfig" +source "drivers/media/video/cx18/Kconfig" + config VIDEO_M32R_AR tristate "AR devices" depends on M32R && VIDEO_V4L1 diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index be14227f3726..a352c6e31f0c 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -84,17 +84,7 @@ obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o obj-$(CONFIG_VIDEO_DPC) += dpc7146.o obj-$(CONFIG_TUNER_3036) += tuner-3036.o -obj-$(CONFIG_VIDEO_TUNER) += tuner.o - -obj-$(CONFIG_TUNER_XC2028) += tuner-xc2028.o -obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o -# tuner-types will be merged into tuner-simple, in the future -obj-$(CONFIG_TUNER_SIMPLE) += tuner-types.o -obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o -obj-$(CONFIG_TUNER_TDA8290) += tda8290.o -obj-$(CONFIG_TUNER_TEA5767) += tea5767.o -obj-$(CONFIG_TUNER_TEA5761) += tea5761.o -obj-$(CONFIG_TUNER_TDA9887) += tda9887.o +obj-$(CONFIG_MEDIA_TUNER) += tuner.o obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o @@ -134,6 +124,7 @@ obj-$(CONFIG_USB_VICAM) += usbvideo/ obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/ obj-$(CONFIG_VIDEO_IVTV) += ivtv/ +obj-$(CONFIG_VIDEO_CX18) += cx18/ obj-$(CONFIG_VIDEO_VIVI) += vivi.o obj-$(CONFIG_VIDEO_CX23885) += cx23885/ @@ -147,3 +138,4 @@ obj-$(CONFIG_VIDEO_AU0828) += au0828/ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/video/au0828/Kconfig b/drivers/media/video/au0828/Kconfig index 41708267e7a4..cab277fafa63 100644 --- a/drivers/media/video/au0828/Kconfig +++ b/drivers/media/video/au0828/Kconfig @@ -4,7 +4,7 @@ config VIDEO_AU0828 depends on VIDEO_DEV && I2C && INPUT && DVB_CORE select I2C_ALGOBIT select DVB_AU8522 if !DVB_FE_CUSTOMIZE - select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE ---help--- This is a video4linux driver for Auvitek's USB device. diff --git a/drivers/media/video/au0828/Makefile b/drivers/media/video/au0828/Makefile index 9f4f572c89c5..cd2c58281b4e 100644 --- a/drivers/media/video/au0828/Makefile +++ b/drivers/media/video/au0828/Makefile @@ -2,7 +2,7 @@ au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o obj-$(CONFIG_VIDEO_AU0828) += au0828.o -EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig index cfc822bb502a..7431ef6de9f1 100644 --- a/drivers/media/video/bt8xx/Kconfig +++ b/drivers/media/video/bt8xx/Kconfig @@ -6,7 +6,7 @@ config VIDEO_BT848 select VIDEO_BTCX select VIDEOBUF_DMA_SG select VIDEO_IR - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_TVEEPROM select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO select VIDEO_TVAUDIO if VIDEO_HELPER_CHIPS_AUTO diff --git a/drivers/media/video/bt8xx/Makefile b/drivers/media/video/bt8xx/Makefile index 924d216d9570..e415f6fc447c 100644 --- a/drivers/media/video/bt8xx/Makefile +++ b/drivers/media/video/bt8xx/Makefile @@ -9,4 +9,5 @@ bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \ obj-$(CONFIG_VIDEO_BT848) += bttv.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h index 03816b73f847..27da7b423275 100644 --- a/drivers/media/video/bt8xx/bttvp.h +++ b/drivers/media/video/bt8xx/bttvp.h @@ -81,8 +81,6 @@ /* Limits scaled width, which must be a multiple of 4. */ #define MAX_HACTIVE (0x3FF & -4) -#define clamp(x, low, high) min (max (low, x), high) - #define BTTV_NORMS (\ V4L2_STD_PAL | V4L2_STD_PAL_N | \ V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \ diff --git a/drivers/media/video/cs5345.c b/drivers/media/video/cs5345.c index fae469ce16f5..2a429f9e32cd 100644 --- a/drivers/media/video/cs5345.c +++ b/drivers/media/video/cs5345.c @@ -142,7 +142,8 @@ static int cs5345_command(struct i2c_client *client, unsigned cmd, void *arg) /* ----------------------------------------------------------------------- */ -static int cs5345_probe(struct i2c_client *client) +static int cs5345_probe(struct i2c_client *client, + const struct i2c_device_id *id) { /* Check if the adapter supports the needed features */ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c index f41bfde045fe..2dfd0afc62db 100644 --- a/drivers/media/video/cs53l32a.c +++ b/drivers/media/video/cs53l32a.c @@ -135,7 +135,8 @@ static int cs53l32a_command(struct i2c_client *client, unsigned cmd, void *arg) * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static int cs53l32a_probe(struct i2c_client *client) +static int cs53l32a_probe(struct i2c_client *client, + const struct i2c_device_id *id) { int i; diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig new file mode 100644 index 000000000000..acc4b47f1d1d --- /dev/null +++ b/drivers/media/video/cx18/Kconfig @@ -0,0 +1,20 @@ +config VIDEO_CX18 + tristate "Conexant cx23418 MPEG encoder support" + depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL + select I2C_ALGOBIT + select FW_LOADER + select VIDEO_IR + select MEDIA_TUNER + select VIDEO_TVEEPROM + select VIDEO_CX2341X + select VIDEO_CS5345 + select DVB_S5H1409 + ---help--- + This is a video4linux driver for Conexant cx23418 based + PCI combo video recorder devices. + + This is used in devices such as the Hauppauge HVR-1600 + cards. + + To compile this driver as a module, choose M here: the + module will be called cx18. diff --git a/drivers/media/video/cx18/Makefile b/drivers/media/video/cx18/Makefile new file mode 100644 index 000000000000..b23d2e26120f --- /dev/null +++ b/drivers/media/video/cx18/Makefile @@ -0,0 +1,11 @@ +cx18-objs := cx18-driver.o cx18-cards.o cx18-i2c.o cx18-firmware.o cx18-gpio.o \ + cx18-queue.o cx18-streams.o cx18-fileops.o cx18-ioctl.o cx18-controls.o \ + cx18-mailbox.o cx18-vbi.o cx18-audio.o cx18-video.o cx18-irq.o \ + cx18-av-core.o cx18-av-audio.o cx18-av-firmware.o cx18-av-vbi.o cx18-scb.o \ + cx18-dvb.o + +obj-$(CONFIG_VIDEO_CX18) += cx18.o + +EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core +EXTRA_CFLAGS += -Idrivers/media/dvb/frontends +EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/video/cx18/cx18-audio.c b/drivers/media/video/cx18/cx18-audio.c new file mode 100644 index 000000000000..1adc404d955e --- /dev/null +++ b/drivers/media/video/cx18/cx18-audio.c @@ -0,0 +1,73 @@ +/* + * cx18 audio-related functions + * + * Derived from ivtv-audio.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-i2c.h" +#include "cx18-cards.h" +#include "cx18-audio.h" + +/* Selects the audio input and output according to the current + settings. */ +int cx18_audio_set_io(struct cx18 *cx) +{ + struct v4l2_routing route; + u32 audio_input; + int mux_input; + + /* Determine which input to use */ + if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { + audio_input = cx->card->radio_input.audio_input; + mux_input = cx->card->radio_input.muxer_input; + } else { + audio_input = + cx->card->audio_inputs[cx->audio_input].audio_input; + mux_input = + cx->card->audio_inputs[cx->audio_input].muxer_input; + } + + /* handle muxer chips */ + route.input = mux_input; + route.output = 0; + cx18_i2c_hw(cx, cx->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route); + + route.input = audio_input; + return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, + VIDIOC_INT_S_AUDIO_ROUTING, &route); +} + +void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route) +{ + cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, + VIDIOC_INT_S_AUDIO_ROUTING, route); +} + +void cx18_audio_set_audio_clock_freq(struct cx18 *cx, u8 freq) +{ + static u32 freqs[3] = { 44100, 48000, 32000 }; + + /* The audio clock of the digitizer must match the codec sample + rate otherwise you get some very strange effects. */ + if (freq > 2) + return; + cx18_call_i2c_clients(cx, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[freq]); +} diff --git a/drivers/media/video/cx18/cx18-audio.h b/drivers/media/video/cx18/cx18-audio.h new file mode 100644 index 000000000000..cb569a69379c --- /dev/null +++ b/drivers/media/video/cx18/cx18-audio.h @@ -0,0 +1,26 @@ +/* + * cx18 audio-related functions + * + * Derived from ivtv-audio.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 + */ + +int cx18_audio_set_io(struct cx18 *cx); +void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route); +void cx18_audio_set_audio_clock_freq(struct cx18 *cx, u8 freq); diff --git a/drivers/media/video/cx18/cx18-av-audio.c b/drivers/media/video/cx18/cx18-av-audio.c new file mode 100644 index 000000000000..2dc3a5dd170e --- /dev/null +++ b/drivers/media/video/cx18/cx18-av-audio.c @@ -0,0 +1,361 @@ +/* + * cx18 ADEC audio functions + * + * Derived from cx25840-audio.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "cx18-driver.h" + +static int set_audclk_freq(struct cx18 *cx, u32 freq) +{ + struct cx18_av_state *state = &cx->av_state; + + if (freq != 32000 && freq != 44100 && freq != 48000) + return -EINVAL; + + /* common for all inputs and rates */ + /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */ + cx18_av_write(cx, 0x127, 0x50); + + if (state->aud_input != CX18_AV_AUDIO_SERIAL) { + switch (freq) { + case 32000: + /* VID_PLL and AUX_PLL */ + cx18_av_write4(cx, 0x108, 0x1006040f); + + /* AUX_PLL_FRAC */ + cx18_av_write4(cx, 0x110, 0x01bb39ee); + + /* src3/4/6_ctl = 0x0801f77f */ + cx18_av_write4(cx, 0x900, 0x0801f77f); + cx18_av_write4(cx, 0x904, 0x0801f77f); + cx18_av_write4(cx, 0x90c, 0x0801f77f); + break; + + case 44100: + /* VID_PLL and AUX_PLL */ + cx18_av_write4(cx, 0x108, 0x1009040f); + + /* AUX_PLL_FRAC */ + cx18_av_write4(cx, 0x110, 0x00ec6bd6); + + /* src3/4/6_ctl = 0x08016d59 */ + cx18_av_write4(cx, 0x900, 0x08016d59); + cx18_av_write4(cx, 0x904, 0x08016d59); + cx18_av_write4(cx, 0x90c, 0x08016d59); + break; + + case 48000: + /* VID_PLL and AUX_PLL */ + cx18_av_write4(cx, 0x108, 0x100a040f); + + /* AUX_PLL_FRAC */ + cx18_av_write4(cx, 0x110, 0x0098d6e5); + + /* src3/4/6_ctl = 0x08014faa */ + cx18_av_write4(cx, 0x900, 0x08014faa); + cx18_av_write4(cx, 0x904, 0x08014faa); + cx18_av_write4(cx, 0x90c, 0x08014faa); + break; + } + } else { + switch (freq) { + case 32000: + /* VID_PLL and AUX_PLL */ + cx18_av_write4(cx, 0x108, 0x1e08040f); + + /* AUX_PLL_FRAC */ + cx18_av_write4(cx, 0x110, 0x012a0869); + + /* src1_ctl = 0x08010000 */ + cx18_av_write4(cx, 0x8f8, 0x08010000); + + /* src3/4/6_ctl = 0x08020000 */ + cx18_av_write4(cx, 0x900, 0x08020000); + cx18_av_write4(cx, 0x904, 0x08020000); + cx18_av_write4(cx, 0x90c, 0x08020000); + + /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */ + cx18_av_write(cx, 0x127, 0x54); + break; + + case 44100: + /* VID_PLL and AUX_PLL */ + cx18_av_write4(cx, 0x108, 0x1809040f); + + /* AUX_PLL_FRAC */ + cx18_av_write4(cx, 0x110, 0x00ec6bd6); + + /* src1_ctl = 0x08010000 */ + cx18_av_write4(cx, 0x8f8, 0x080160cd); + + /* src3/4/6_ctl = 0x08020000 */ + cx18_av_write4(cx, 0x900, 0x08017385); + cx18_av_write4(cx, 0x904, 0x08017385); + cx18_av_write4(cx, 0x90c, 0x08017385); + break; + + case 48000: + /* VID_PLL and AUX_PLL */ + cx18_av_write4(cx, 0x108, 0x180a040f); + + /* AUX_PLL_FRAC */ + cx18_av_write4(cx, 0x110, 0x0098d6e5); + + /* src1_ctl = 0x08010000 */ + cx18_av_write4(cx, 0x8f8, 0x08018000); + + /* src3/4/6_ctl = 0x08020000 */ + cx18_av_write4(cx, 0x900, 0x08015555); + cx18_av_write4(cx, 0x904, 0x08015555); + cx18_av_write4(cx, 0x90c, 0x08015555); + break; + } + } + + state->audclk_freq = freq; + + return 0; +} + +void cx18_av_audio_set_path(struct cx18 *cx) +{ + struct cx18_av_state *state = &cx->av_state; + + /* stop microcontroller */ + cx18_av_and_or(cx, 0x803, ~0x10, 0); + + /* assert soft reset */ + cx18_av_and_or(cx, 0x810, ~0x1, 0x01); + + /* Mute everything to prevent the PFFT! */ + cx18_av_write(cx, 0x8d3, 0x1f); + + if (state->aud_input == CX18_AV_AUDIO_SERIAL) { + /* Set Path1 to Serial Audio Input */ + cx18_av_write4(cx, 0x8d0, 0x01011012); + + /* The microcontroller should not be started for the + * non-tuner inputs: autodetection is specific for + * TV audio. */ + } else { + /* Set Path1 to Analog Demod Main Channel */ + cx18_av_write4(cx, 0x8d0, 0x1f063870); + } + + set_audclk_freq(cx, state->audclk_freq); + + /* deassert soft reset */ + cx18_av_and_or(cx, 0x810, ~0x1, 0x00); + + if (state->aud_input != CX18_AV_AUDIO_SERIAL) { + /* When the microcontroller detects the + * audio format, it will unmute the lines */ + cx18_av_and_or(cx, 0x803, ~0x10, 0x10); + } +} + +static int get_volume(struct cx18 *cx) +{ + /* Volume runs +18dB to -96dB in 1/2dB steps + * change to fit the msp3400 -114dB to +12dB range */ + + /* check PATH1_VOLUME */ + int vol = 228 - cx18_av_read(cx, 0x8d4); + vol = (vol / 2) + 23; + return vol << 9; +} + +static void set_volume(struct cx18 *cx, int volume) +{ + /* First convert the volume to msp3400 values (0-127) */ + int vol = volume >> 9; + /* now scale it up to cx18_av values + * -114dB to -96dB maps to 0 + * this should be 19, but in my testing that was 4dB too loud */ + if (vol <= 23) + vol = 0; + else + vol -= 23; + + /* PATH1_VOLUME */ + cx18_av_write(cx, 0x8d4, 228 - (vol * 2)); +} + +static int get_bass(struct cx18 *cx) +{ + /* bass is 49 steps +12dB to -12dB */ + + /* check PATH1_EQ_BASS_VOL */ + int bass = cx18_av_read(cx, 0x8d9) & 0x3f; + bass = (((48 - bass) * 0xffff) + 47) / 48; + return bass; +} + +static void set_bass(struct cx18 *cx, int bass) +{ + /* PATH1_EQ_BASS_VOL */ + cx18_av_and_or(cx, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff)); +} + +static int get_treble(struct cx18 *cx) +{ + /* treble is 49 steps +12dB to -12dB */ + + /* check PATH1_EQ_TREBLE_VOL */ + int treble = cx18_av_read(cx, 0x8db) & 0x3f; + treble = (((48 - treble) * 0xffff) + 47) / 48; + return treble; +} + +static void set_treble(struct cx18 *cx, int treble) +{ + /* PATH1_EQ_TREBLE_VOL */ + cx18_av_and_or(cx, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff)); +} + +static int get_balance(struct cx18 *cx) +{ + /* balance is 7 bit, 0 to -96dB */ + + /* check PATH1_BAL_LEVEL */ + int balance = cx18_av_read(cx, 0x8d5) & 0x7f; + /* check PATH1_BAL_LEFT */ + if ((cx18_av_read(cx, 0x8d5) & 0x80) == 0) + balance = 0x80 - balance; + else + balance = 0x80 + balance; + return balance << 8; +} + +static void set_balance(struct cx18 *cx, int balance) +{ + int bal = balance >> 8; + if (bal > 0x80) { + /* PATH1_BAL_LEFT */ + cx18_av_and_or(cx, 0x8d5, 0x7f, 0x80); + /* PATH1_BAL_LEVEL */ + cx18_av_and_or(cx, 0x8d5, ~0x7f, bal & 0x7f); + } else { + /* PATH1_BAL_LEFT */ + cx18_av_and_or(cx, 0x8d5, 0x7f, 0x00); + /* PATH1_BAL_LEVEL */ + cx18_av_and_or(cx, 0x8d5, ~0x7f, 0x80 - bal); + } +} + +static int get_mute(struct cx18 *cx) +{ + /* check SRC1_MUTE_EN */ + return cx18_av_read(cx, 0x8d3) & 0x2 ? 1 : 0; +} + +static void set_mute(struct cx18 *cx, int mute) +{ + struct cx18_av_state *state = &cx->av_state; + + if (state->aud_input != CX18_AV_AUDIO_SERIAL) { + /* Must turn off microcontroller in order to mute sound. + * Not sure if this is the best method, but it does work. + * If the microcontroller is running, then it will undo any + * changes to the mute register. */ + if (mute) { + /* disable microcontroller */ + cx18_av_and_or(cx, 0x803, ~0x10, 0x00); + cx18_av_write(cx, 0x8d3, 0x1f); + } else { + /* enable microcontroller */ + cx18_av_and_or(cx, 0x803, ~0x10, 0x10); + } + } else { + /* SRC1_MUTE_EN */ + cx18_av_and_or(cx, 0x8d3, ~0x2, mute ? 0x02 : 0x00); + } +} + +int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg) +{ + struct cx18_av_state *state = &cx->av_state; + struct v4l2_control *ctrl = arg; + int retval; + + switch (cmd) { + case VIDIOC_INT_AUDIO_CLOCK_FREQ: + if (state->aud_input != CX18_AV_AUDIO_SERIAL) { + cx18_av_and_or(cx, 0x803, ~0x10, 0); + cx18_av_write(cx, 0x8d3, 0x1f); + } + cx18_av_and_or(cx, 0x810, ~0x1, 1); + retval = set_audclk_freq(cx, *(u32 *)arg); + cx18_av_and_or(cx, 0x810, ~0x1, 0); + if (state->aud_input != CX18_AV_AUDIO_SERIAL) + cx18_av_and_or(cx, 0x803, ~0x10, 0x10); + return retval; + + case VIDIOC_G_CTRL: + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = get_volume(cx); + break; + case V4L2_CID_AUDIO_BASS: + ctrl->value = get_bass(cx); + break; + case V4L2_CID_AUDIO_TREBLE: + ctrl->value = get_treble(cx); + break; + case V4L2_CID_AUDIO_BALANCE: + ctrl->value = get_balance(cx); + break; + case V4L2_CID_AUDIO_MUTE: + ctrl->value = get_mute(cx); + break; + default: + return -EINVAL; + } + break; + + case VIDIOC_S_CTRL: + switch (ctrl->id) { + case V4L2_CID_AUDIO_VOLUME: + set_volume(cx, ctrl->value); + break; + case V4L2_CID_AUDIO_BASS: + set_bass(cx, ctrl->value); + break; + case V4L2_CID_AUDIO_TREBLE: + set_treble(cx, ctrl->value); + break; + case V4L2_CID_AUDIO_BALANCE: + set_balance(cx, ctrl->value); + break; + case V4L2_CID_AUDIO_MUTE: + set_mute(cx, ctrl->value); + break; + default: + return -EINVAL; + } + break; + + default: + return -EINVAL; + } + + return 0; +} diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c new file mode 100644 index 000000000000..66864904c99b --- /dev/null +++ b/drivers/media/video/cx18/cx18-av-core.c @@ -0,0 +1,879 @@ +/* + * cx18 ADEC audio functions + * + * Derived from cx25840-core.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "cx18-driver.h" + +int cx18_av_write(struct cx18 *cx, u16 addr, u8 value) +{ + u32 x = readl(cx->reg_mem + 0xc40000 + (addr & ~3)); + u32 mask = 0xff; + int shift = (addr & 3) * 8; + + x = (x & ~(mask << shift)) | ((u32)value << shift); + writel(x, cx->reg_mem + 0xc40000 + (addr & ~3)); + return 0; +} + +int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value) +{ + writel(value, cx->reg_mem + 0xc40000 + addr); + return 0; +} + +u8 cx18_av_read(struct cx18 *cx, u16 addr) +{ + u32 x = readl(cx->reg_mem + 0xc40000 + (addr & ~3)); + int shift = (addr & 3) * 8; + + return (x >> shift) & 0xff; +} + +u32 cx18_av_read4(struct cx18 *cx, u16 addr) +{ + return readl(cx->reg_mem + 0xc40000 + addr); +} + +int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned and_mask, + u8 or_value) +{ + return cx18_av_write(cx, addr, + (cx18_av_read(cx, addr) & and_mask) | + or_value); +} + +int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask, + u32 or_value) +{ + return cx18_av_write4(cx, addr, + (cx18_av_read4(cx, addr) & and_mask) | + or_value); +} + +/* ----------------------------------------------------------------------- */ + +static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input, + enum cx18_av_audio_input aud_input); +static void log_audio_status(struct cx18 *cx); +static void log_video_status(struct cx18 *cx); + +/* ----------------------------------------------------------------------- */ + +static void cx18_av_initialize(struct cx18 *cx) +{ + u32 v; + + cx18_av_loadfw(cx); + /* Stop 8051 code execution */ + cx18_av_write4(cx, CXADEC_DL_CTL, 0x03000000); + + /* initallize the PLL by toggling sleep bit */ + v = cx18_av_read4(cx, CXADEC_HOST_REG1); + /* enable sleep mode */ + cx18_av_write4(cx, CXADEC_HOST_REG1, v | 1); + /* disable sleep mode */ + cx18_av_write4(cx, CXADEC_HOST_REG1, v & 0xfffe); + + /* initialize DLLs */ + v = cx18_av_read4(cx, CXADEC_DLL1_DIAG_CTRL) & 0xE1FFFEFF; + /* disable FLD */ + cx18_av_write4(cx, CXADEC_DLL1_DIAG_CTRL, v); + /* enable FLD */ + cx18_av_write4(cx, CXADEC_DLL1_DIAG_CTRL, v | 0x10000100); + + v = cx18_av_read4(cx, CXADEC_DLL2_DIAG_CTRL) & 0xE1FFFEFF; + /* disable FLD */ + cx18_av_write4(cx, CXADEC_DLL2_DIAG_CTRL, v); + /* enable FLD */ + cx18_av_write4(cx, CXADEC_DLL2_DIAG_CTRL, v | 0x06000100); + + /* set analog bias currents. Set Vreg to 1.20V. */ + cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL1, 0x000A1802); + + v = cx18_av_read4(cx, CXADEC_AFE_DIAG_CTRL3) | 1; + /* enable TUNE_FIL_RST */ + cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL3, v); + /* disable TUNE_FIL_RST */ + cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL3, v & 0xFFFFFFFE); + + /* enable 656 output */ + cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x040C00); + + /* video output drive strength */ + cx18_av_and_or4(cx, CXADEC_PIN_CTRL2, ~0, 0x2); + + /* reset video */ + cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0x8000); + cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0); + + /* set video to auto-detect */ + /* Clear bits 11-12 to enable slow locking mode. Set autodetect mode */ + /* set the comb notch = 1 */ + cx18_av_and_or4(cx, CXADEC_MODE_CTRL, 0xFFF7E7F0, 0x02040800); + + /* Enable wtw_en in CRUSH_CTRL (Set bit 22) */ + /* Enable maj_sel in CRUSH_CTRL (Set bit 20) */ + cx18_av_and_or4(cx, CXADEC_CRUSH_CTRL, ~0, 0x00500000); + + /* Set VGA_TRACK_RANGE to 0x20 */ + cx18_av_and_or4(cx, CXADEC_DFE_CTRL2, 0xFFFF00FF, 0x00002000); + + /* Enable VBI capture */ + cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253F); + /* cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253E); */ + + /* Set the video input. + The setting in MODE_CTRL gets lost when we do the above setup */ + /* EncSetSignalStd(dwDevNum, pEnc->dwSigStd); */ + /* EncSetVideoInput(dwDevNum, pEnc->VidIndSelection); */ + + v = cx18_av_read4(cx, CXADEC_AFE_CTRL); + v &= 0xFFFBFFFF; /* turn OFF bit 18 for droop_comp_ch1 */ + v &= 0xFFFF7FFF; /* turn OFF bit 9 for clamp_sel_ch1 */ + v &= 0xFFFFFFFE; /* turn OFF bit 0 for 12db_ch1 */ + /* v |= 0x00000001;*/ /* turn ON bit 0 for 12db_ch1 */ + cx18_av_write4(cx, CXADEC_AFE_CTRL, v); + +/* if(dwEnable && dw3DCombAvailable) { */ +/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x7728021F); */ +/* } else { */ +/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */ +/* } */ + cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F); +} + +/* ----------------------------------------------------------------------- */ + +static void input_change(struct cx18 *cx) +{ + struct cx18_av_state *state = &cx->av_state; + v4l2_std_id std = state->std; + + /* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */ + if (std & V4L2_STD_SECAM) + cx18_av_write(cx, 0x402, 0); + else { + cx18_av_write(cx, 0x402, 0x04); + cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11); + } + cx18_av_and_or(cx, 0x401, ~0x60, 0); + cx18_av_and_or(cx, 0x401, ~0x60, 0x60); + + if (std & V4L2_STD_525_60) { + if (std == V4L2_STD_NTSC_M_JP) { + /* Japan uses EIAJ audio standard */ + cx18_av_write(cx, 0x808, 0xf7); + } else if (std == V4L2_STD_NTSC_M_KR) { + /* South Korea uses A2 audio standard */ + cx18_av_write(cx, 0x808, 0xf8); + } else { + /* Others use the BTSC audio standard */ + cx18_av_write(cx, 0x808, 0xf6); + } + cx18_av_write(cx, 0x80b, 0x00); + } else if (std & V4L2_STD_PAL) { + /* Follow tuner change procedure for PAL */ + cx18_av_write(cx, 0x808, 0xff); + cx18_av_write(cx, 0x80b, 0x03); + } else if (std & V4L2_STD_SECAM) { + /* Select autodetect for SECAM */ + cx18_av_write(cx, 0x808, 0xff); + cx18_av_write(cx, 0x80b, 0x03); + } + + if (cx18_av_read(cx, 0x803) & 0x10) { + /* restart audio decoder microcontroller */ + cx18_av_and_or(cx, 0x803, ~0x10, 0x00); + cx18_av_and_or(cx, 0x803, ~0x10, 0x10); + } +} + +static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input, + enum cx18_av_audio_input aud_input) +{ + struct cx18_av_state *state = &cx->av_state; + u8 is_composite = (vid_input >= CX18_AV_COMPOSITE1 && + vid_input <= CX18_AV_COMPOSITE8); + u8 reg; + + CX18_DEBUG_INFO("decoder set video input %d, audio input %d\n", + vid_input, aud_input); + + if (is_composite) { + reg = 0xf0 + (vid_input - CX18_AV_COMPOSITE1); + } else { + int luma = vid_input & 0xf0; + int chroma = vid_input & 0xf00; + + if ((vid_input & ~0xff0) || + luma < CX18_AV_SVIDEO_LUMA1 || + luma > CX18_AV_SVIDEO_LUMA4 || + chroma < CX18_AV_SVIDEO_CHROMA4 || + chroma > CX18_AV_SVIDEO_CHROMA8) { + CX18_ERR("0x%04x is not a valid video input!\n", + vid_input); + return -EINVAL; + } + reg = 0xf0 + ((luma - CX18_AV_SVIDEO_LUMA1) >> 4); + if (chroma >= CX18_AV_SVIDEO_CHROMA7) { + reg &= 0x3f; + reg |= (chroma - CX18_AV_SVIDEO_CHROMA7) >> 2; + } else { + reg &= 0xcf; + reg |= (chroma - CX18_AV_SVIDEO_CHROMA4) >> 4; + } + } + + switch (aud_input) { + case CX18_AV_AUDIO_SERIAL: + /* do nothing, use serial audio input */ + break; + case CX18_AV_AUDIO4: reg &= ~0x30; break; + case CX18_AV_AUDIO5: reg &= ~0x30; reg |= 0x10; break; + case CX18_AV_AUDIO6: reg &= ~0x30; reg |= 0x20; break; + case CX18_AV_AUDIO7: reg &= ~0xc0; break; + case CX18_AV_AUDIO8: reg &= ~0xc0; reg |= 0x40; break; + + default: + CX18_ERR("0x%04x is not a valid audio input!\n", aud_input); + return -EINVAL; + } + + cx18_av_write(cx, 0x103, reg); + /* Set INPUT_MODE to Composite (0) or S-Video (1) */ + cx18_av_and_or(cx, 0x401, ~0x6, is_composite ? 0 : 0x02); + /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ + cx18_av_and_or(cx, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0); + /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */ + if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30) + cx18_av_and_or(cx, 0x102, ~0x4, 4); + else + cx18_av_and_or(cx, 0x102, ~0x4, 0); + /*cx18_av_and_or4(cx, 0x104, ~0x001b4180, 0x00004180);*/ + + state->vid_input = vid_input; + state->aud_input = aud_input; + cx18_av_audio_set_path(cx); + input_change(cx); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static int set_v4lstd(struct cx18 *cx) +{ + struct cx18_av_state *state = &cx->av_state; + u8 fmt = 0; /* zero is autodetect */ + u8 pal_m = 0; + + /* First tests should be against specific std */ + if (state->std == V4L2_STD_NTSC_M_JP) { + fmt = 0x2; + } else if (state->std == V4L2_STD_NTSC_443) { + fmt = 0x3; + } else if (state->std == V4L2_STD_PAL_M) { + pal_m = 1; + fmt = 0x5; + } else if (state->std == V4L2_STD_PAL_N) { + fmt = 0x6; + } else if (state->std == V4L2_STD_PAL_Nc) { + fmt = 0x7; + } else if (state->std == V4L2_STD_PAL_60) { + fmt = 0x8; + } else { + /* Then, test against generic ones */ + if (state->std & V4L2_STD_NTSC) + fmt = 0x1; + else if (state->std & V4L2_STD_PAL) + fmt = 0x4; + else if (state->std & V4L2_STD_SECAM) + fmt = 0xc; + } + + CX18_DEBUG_INFO("changing video std to fmt %i\n", fmt); + + /* Follow step 9 of section 3.16 in the cx18_av datasheet. + Without this PAL may display a vertical ghosting effect. + This happens for example with the Yuan MPC622. */ + if (fmt >= 4 && fmt < 8) { + /* Set format to NTSC-M */ + cx18_av_and_or(cx, 0x400, ~0xf, 1); + /* Turn off LCOMB */ + cx18_av_and_or(cx, 0x47b, ~6, 0); + } + cx18_av_and_or(cx, 0x400, ~0xf, fmt); + cx18_av_and_or(cx, 0x403, ~0x3, pal_m); + cx18_av_vbi_setup(cx); + input_change(cx); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static int set_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + if (ctrl->value < 0 || ctrl->value > 255) { + CX18_ERR("invalid brightness setting %d\n", + ctrl->value); + return -ERANGE; + } + + cx18_av_write(cx, 0x414, ctrl->value - 128); + break; + + case V4L2_CID_CONTRAST: + if (ctrl->value < 0 || ctrl->value > 127) { + CX18_ERR("invalid contrast setting %d\n", + ctrl->value); + return -ERANGE; + } + + cx18_av_write(cx, 0x415, ctrl->value << 1); + break; + + case V4L2_CID_SATURATION: + if (ctrl->value < 0 || ctrl->value > 127) { + CX18_ERR("invalid saturation setting %d\n", + ctrl->value); + return -ERANGE; + } + + cx18_av_write(cx, 0x420, ctrl->value << 1); + cx18_av_write(cx, 0x421, ctrl->value << 1); + break; + + case V4L2_CID_HUE: + if (ctrl->value < -127 || ctrl->value > 127) { + CX18_ERR("invalid hue setting %d\n", ctrl->value); + return -ERANGE; + } + + cx18_av_write(cx, 0x422, ctrl->value); + break; + + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_MUTE: + return cx18_av_audio(cx, VIDIOC_S_CTRL, ctrl); + + default: + return -EINVAL; + } + + return 0; +} + +static int get_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + ctrl->value = (s8)cx18_av_read(cx, 0x414) + 128; + break; + case V4L2_CID_CONTRAST: + ctrl->value = cx18_av_read(cx, 0x415) >> 1; + break; + case V4L2_CID_SATURATION: + ctrl->value = cx18_av_read(cx, 0x420) >> 1; + break; + case V4L2_CID_HUE: + ctrl->value = (s8)cx18_av_read(cx, 0x422); + break; + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_MUTE: + return cx18_av_audio(cx, VIDIOC_G_CTRL, ctrl); + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static int get_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt) +{ + switch (fmt->type) { + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + return cx18_av_vbi(cx, VIDIOC_G_FMT, fmt); + default: + return -EINVAL; + } + + return 0; +} + +static int set_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt) +{ + struct cx18_av_state *state = &cx->av_state; + struct v4l2_pix_format *pix; + int HSC, VSC, Vsrc, Hsrc, filter, Vlines; + int is_50Hz = !(state->std & V4L2_STD_525_60); + + switch (fmt->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + pix = &(fmt->fmt.pix); + + Vsrc = (cx18_av_read(cx, 0x476) & 0x3f) << 4; + Vsrc |= (cx18_av_read(cx, 0x475) & 0xf0) >> 4; + + Hsrc = (cx18_av_read(cx, 0x472) & 0x3f) << 4; + Hsrc |= (cx18_av_read(cx, 0x471) & 0xf0) >> 4; + + Vlines = pix->height + (is_50Hz ? 4 : 7); + + if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) || + (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) { + CX18_ERR("%dx%d is not a valid size!\n", + pix->width, pix->height); + return -ERANGE; + } + + HSC = (Hsrc * (1 << 20)) / pix->width - (1 << 20); + VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); + VSC &= 0x1fff; + + if (pix->width >= 385) + filter = 0; + else if (pix->width > 192) + filter = 1; + else if (pix->width > 96) + filter = 2; + else + filter = 3; + + CX18_DEBUG_INFO("decoder set size %dx%d -> scale %ux%u\n", + pix->width, pix->height, HSC, VSC); + + /* HSCALE=HSC */ + cx18_av_write(cx, 0x418, HSC & 0xff); + cx18_av_write(cx, 0x419, (HSC >> 8) & 0xff); + cx18_av_write(cx, 0x41a, HSC >> 16); + /* VSCALE=VSC */ + cx18_av_write(cx, 0x41c, VSC & 0xff); + cx18_av_write(cx, 0x41d, VSC >> 8); + /* VS_INTRLACE=1 VFILT=filter */ + cx18_av_write(cx, 0x41e, 0x8 | filter); + break; + + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + return cx18_av_vbi(cx, VIDIOC_S_FMT, fmt); + + case V4L2_BUF_TYPE_VBI_CAPTURE: + return cx18_av_vbi(cx, VIDIOC_S_FMT, fmt); + + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg) +{ + struct cx18_av_state *state = &cx->av_state; + struct v4l2_tuner *vt = arg; + struct v4l2_routing *route = arg; + + /* ignore these commands */ + switch (cmd) { + case TUNER_SET_TYPE_ADDR: + return 0; + } + + if (!state->is_initialized) { + CX18_DEBUG_INFO("cmd %08x triggered fw load\n", cmd); + /* initialize on first use */ + state->is_initialized = 1; + cx18_av_initialize(cx); + } + + switch (cmd) { + case VIDIOC_INT_DECODE_VBI_LINE: + return cx18_av_vbi(cx, cmd, arg); + + case VIDIOC_INT_AUDIO_CLOCK_FREQ: + return cx18_av_audio(cx, cmd, arg); + + case VIDIOC_STREAMON: + CX18_DEBUG_INFO("enable output\n"); + cx18_av_write(cx, 0x115, 0x8c); + cx18_av_write(cx, 0x116, 0x07); + break; + + case VIDIOC_STREAMOFF: + CX18_DEBUG_INFO("disable output\n"); + cx18_av_write(cx, 0x115, 0x00); + cx18_av_write(cx, 0x116, 0x00); + break; + + case VIDIOC_LOG_STATUS: + log_video_status(cx); + log_audio_status(cx); + break; + + case VIDIOC_G_CTRL: + return get_v4lctrl(cx, (struct v4l2_control *)arg); + + case VIDIOC_S_CTRL: + return set_v4lctrl(cx, (struct v4l2_control *)arg); + + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *qc = arg; + + switch (qc->id) { + case V4L2_CID_BRIGHTNESS: + case V4L2_CID_CONTRAST: + case V4L2_CID_SATURATION: + case V4L2_CID_HUE: + return v4l2_ctrl_query_fill_std(qc); + default: + break; + } + + switch (qc->id) { + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_MUTE: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + return v4l2_ctrl_query_fill_std(qc); + default: + return -EINVAL; + } + return -EINVAL; + } + + case VIDIOC_G_STD: + *(v4l2_std_id *)arg = state->std; + break; + + case VIDIOC_S_STD: + if (state->radio == 0 && state->std == *(v4l2_std_id *)arg) + return 0; + state->radio = 0; + state->std = *(v4l2_std_id *)arg; + return set_v4lstd(cx); + + case AUDC_SET_RADIO: + state->radio = 1; + break; + + case VIDIOC_INT_G_VIDEO_ROUTING: + route->input = state->vid_input; + route->output = 0; + break; + + case VIDIOC_INT_S_VIDEO_ROUTING: + return set_input(cx, route->input, state->aud_input); + + case VIDIOC_INT_G_AUDIO_ROUTING: + route->input = state->aud_input; + route->output = 0; + break; + + case VIDIOC_INT_S_AUDIO_ROUTING: + return set_input(cx, state->vid_input, route->input); + + case VIDIOC_S_FREQUENCY: + input_change(cx); + break; + + case VIDIOC_G_TUNER: + { + u8 vpres = cx18_av_read(cx, 0x40e) & 0x20; + u8 mode; + int val = 0; + + if (state->radio) + break; + + vt->signal = vpres ? 0xffff : 0x0; + + vt->capability |= + V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | + V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; + + mode = cx18_av_read(cx, 0x804); + + /* get rxsubchans and audmode */ + if ((mode & 0xf) == 1) + val |= V4L2_TUNER_SUB_STEREO; + else + val |= V4L2_TUNER_SUB_MONO; + + if (mode == 2 || mode == 4) + val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + + if (mode & 0x10) + val |= V4L2_TUNER_SUB_SAP; + + vt->rxsubchans = val; + vt->audmode = state->audmode; + break; + } + + case VIDIOC_S_TUNER: + if (state->radio) + break; + + switch (vt->audmode) { + case V4L2_TUNER_MODE_MONO: + /* mono -> mono + stereo -> mono + bilingual -> lang1 */ + cx18_av_and_or(cx, 0x809, ~0xf, 0x00); + break; + case V4L2_TUNER_MODE_STEREO: + case V4L2_TUNER_MODE_LANG1: + /* mono -> mono + stereo -> stereo + bilingual -> lang1 */ + cx18_av_and_or(cx, 0x809, ~0xf, 0x04); + break; + case V4L2_TUNER_MODE_LANG1_LANG2: + /* mono -> mono + stereo -> stereo + bilingual -> lang1/lang2 */ + cx18_av_and_or(cx, 0x809, ~0xf, 0x07); + break; + case V4L2_TUNER_MODE_LANG2: + /* mono -> mono + stereo -> stereo + bilingual -> lang2 */ + cx18_av_and_or(cx, 0x809, ~0xf, 0x01); + break; + default: + return -EINVAL; + } + state->audmode = vt->audmode; + break; + + case VIDIOC_G_FMT: + return get_v4lfmt(cx, (struct v4l2_format *)arg); + + case VIDIOC_S_FMT: + return set_v4lfmt(cx, (struct v4l2_format *)arg); + + case VIDIOC_INT_RESET: + cx18_av_initialize(cx); + break; + + default: + return -EINVAL; + } + + return 0; +} + +/* ----------------------------------------------------------------------- */ + +/* ----------------------------------------------------------------------- */ + +static void log_video_status(struct cx18 *cx) +{ + static const char *const fmt_strs[] = { + "0x0", + "NTSC-M", "NTSC-J", "NTSC-4.43", + "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60", + "0x9", "0xA", "0xB", + "SECAM", + "0xD", "0xE", "0xF" + }; + + struct cx18_av_state *state = &cx->av_state; + u8 vidfmt_sel = cx18_av_read(cx, 0x400) & 0xf; + u8 gen_stat1 = cx18_av_read(cx, 0x40d); + u8 gen_stat2 = cx18_av_read(cx, 0x40e); + int vid_input = state->vid_input; + + CX18_INFO("Video signal: %spresent\n", + (gen_stat2 & 0x20) ? "" : "not "); + CX18_INFO("Detected format: %s\n", + fmt_strs[gen_stat1 & 0xf]); + + CX18_INFO("Specified standard: %s\n", + vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); + + if (vid_input >= CX18_AV_COMPOSITE1 && + vid_input <= CX18_AV_COMPOSITE8) { + CX18_INFO("Specified video input: Composite %d\n", + vid_input - CX18_AV_COMPOSITE1 + 1); + } else { + CX18_INFO("Specified video input: S-Video (Luma In%d, Chroma In%d)\n", + (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); + } + + CX18_INFO("Specified audioclock freq: %d Hz\n", state->audclk_freq); +} + +/* ----------------------------------------------------------------------- */ + +static void log_audio_status(struct cx18 *cx) +{ + struct cx18_av_state *state = &cx->av_state; + u8 download_ctl = cx18_av_read(cx, 0x803); + u8 mod_det_stat0 = cx18_av_read(cx, 0x805); + u8 mod_det_stat1 = cx18_av_read(cx, 0x804); + u8 audio_config = cx18_av_read(cx, 0x808); + u8 pref_mode = cx18_av_read(cx, 0x809); + u8 afc0 = cx18_av_read(cx, 0x80b); + u8 mute_ctl = cx18_av_read(cx, 0x8d3); + int aud_input = state->aud_input; + char *p; + + switch (mod_det_stat0) { + case 0x00: p = "mono"; break; + case 0x01: p = "stereo"; break; + case 0x02: p = "dual"; break; + case 0x04: p = "tri"; break; + case 0x10: p = "mono with SAP"; break; + case 0x11: p = "stereo with SAP"; break; + case 0x12: p = "dual with SAP"; break; + case 0x14: p = "tri with SAP"; break; + case 0xfe: p = "forced mode"; break; + default: p = "not defined"; + } + CX18_INFO("Detected audio mode: %s\n", p); + + switch (mod_det_stat1) { + case 0x00: p = "BTSC"; break; + case 0x01: p = "EIAJ"; break; + case 0x02: p = "A2-M"; break; + case 0x03: p = "A2-BG"; break; + case 0x04: p = "A2-DK1"; break; + case 0x05: p = "A2-DK2"; break; + case 0x06: p = "A2-DK3"; break; + case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; + case 0x08: p = "AM-L"; break; + case 0x09: p = "NICAM-BG"; break; + case 0x0a: p = "NICAM-DK"; break; + case 0x0b: p = "NICAM-I"; break; + case 0x0c: p = "NICAM-L"; break; + case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; + case 0xff: p = "no detected audio standard"; break; + default: p = "not defined"; + } + CX18_INFO("Detected audio standard: %s\n", p); + CX18_INFO("Audio muted: %s\n", + (mute_ctl & 0x2) ? "yes" : "no"); + CX18_INFO("Audio microcontroller: %s\n", + (download_ctl & 0x10) ? "running" : "stopped"); + + switch (audio_config >> 4) { + case 0x00: p = "BTSC"; break; + case 0x01: p = "EIAJ"; break; + case 0x02: p = "A2-M"; break; + case 0x03: p = "A2-BG"; break; + case 0x04: p = "A2-DK1"; break; + case 0x05: p = "A2-DK2"; break; + case 0x06: p = "A2-DK3"; break; + case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; + case 0x08: p = "AM-L"; break; + case 0x09: p = "NICAM-BG"; break; + case 0x0a: p = "NICAM-DK"; break; + case 0x0b: p = "NICAM-I"; break; + case 0x0c: p = "NICAM-L"; break; + case 0x0d: p = "FM radio"; break; + case 0x0f: p = "automatic detection"; break; + default: p = "undefined"; + } + CX18_INFO("Configured audio standard: %s\n", p); + + if ((audio_config >> 4) < 0xF) { + switch (audio_config & 0xF) { + case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break; + case 0x01: p = "MONO2 (LANGUAGE B)"; break; + case 0x02: p = "MONO3 (STEREO forced MONO)"; break; + case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; + case 0x04: p = "STEREO"; break; + case 0x05: p = "DUAL1 (AB)"; break; + case 0x06: p = "DUAL2 (AC) (FM)"; break; + case 0x07: p = "DUAL3 (BC) (FM)"; break; + case 0x08: p = "DUAL4 (AC) (AM)"; break; + case 0x09: p = "DUAL5 (BC) (AM)"; break; + case 0x0a: p = "SAP"; break; + default: p = "undefined"; + } + CX18_INFO("Configured audio mode: %s\n", p); + } else { + switch (audio_config & 0xF) { + case 0x00: p = "BG"; break; + case 0x01: p = "DK1"; break; + case 0x02: p = "DK2"; break; + case 0x03: p = "DK3"; break; + case 0x04: p = "I"; break; + case 0x05: p = "L"; break; + case 0x06: p = "BTSC"; break; + case 0x07: p = "EIAJ"; break; + case 0x08: p = "A2-M"; break; + case 0x09: p = "FM Radio"; break; + case 0x0f: p = "automatic standard and mode detection"; break; + default: p = "undefined"; + } + CX18_INFO("Configured audio system: %s\n", p); + } + + if (aud_input) + CX18_INFO("Specified audio input: Tuner (In%d)\n", + aud_input); + else + CX18_INFO("Specified audio input: External\n"); + + switch (pref_mode & 0xf) { + case 0: p = "mono/language A"; break; + case 1: p = "language B"; break; + case 2: p = "language C"; break; + case 3: p = "analog fallback"; break; + case 4: p = "stereo"; break; + case 5: p = "language AC"; break; + case 6: p = "language BC"; break; + case 7: p = "language AB"; break; + default: p = "undefined"; + } + CX18_INFO("Preferred audio mode: %s\n", p); + + if ((audio_config & 0xf) == 0xf) { + switch ((afc0 >> 2) & 0x1) { + case 0: p = "system DK"; break; + case 1: p = "system L"; break; + } + CX18_INFO("Selected 65 MHz format: %s\n", p); + + switch (afc0 & 0x3) { + case 0: p = "BTSC"; break; + case 1: p = "EIAJ"; break; + case 2: p = "A2-M"; break; + default: p = "undefined"; + } + CX18_INFO("Selected 45 MHz format: %s\n", p); + } +} diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h new file mode 100644 index 000000000000..786901d72e9a --- /dev/null +++ b/drivers/media/video/cx18/cx18-av-core.h @@ -0,0 +1,318 @@ +/* + * cx18 ADEC header + * + * Derived from cx25840-core.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#ifndef _CX18_AV_CORE_H_ +#define _CX18_AV_CORE_H_ + +struct cx18; + +enum cx18_av_video_input { + /* Composite video inputs In1-In8 */ + CX18_AV_COMPOSITE1 = 1, + CX18_AV_COMPOSITE2, + CX18_AV_COMPOSITE3, + CX18_AV_COMPOSITE4, + CX18_AV_COMPOSITE5, + CX18_AV_COMPOSITE6, + CX18_AV_COMPOSITE7, + CX18_AV_COMPOSITE8, + + /* S-Video inputs consist of one luma input (In1-In4) ORed with one + chroma input (In5-In8) */ + CX18_AV_SVIDEO_LUMA1 = 0x10, + CX18_AV_SVIDEO_LUMA2 = 0x20, + CX18_AV_SVIDEO_LUMA3 = 0x30, + CX18_AV_SVIDEO_LUMA4 = 0x40, + CX18_AV_SVIDEO_CHROMA4 = 0x400, + CX18_AV_SVIDEO_CHROMA5 = 0x500, + CX18_AV_SVIDEO_CHROMA6 = 0x600, + CX18_AV_SVIDEO_CHROMA7 = 0x700, + CX18_AV_SVIDEO_CHROMA8 = 0x800, + + /* S-Video aliases for common luma/chroma combinations */ + CX18_AV_SVIDEO1 = 0x510, + CX18_AV_SVIDEO2 = 0x620, + CX18_AV_SVIDEO3 = 0x730, + CX18_AV_SVIDEO4 = 0x840, +}; + +enum cx18_av_audio_input { + /* Audio inputs: serial or In4-In8 */ + CX18_AV_AUDIO_SERIAL, + CX18_AV_AUDIO4 = 4, + CX18_AV_AUDIO5, + CX18_AV_AUDIO6, + CX18_AV_AUDIO7, + CX18_AV_AUDIO8, +}; + +struct cx18_av_state { + int radio; + v4l2_std_id std; + enum cx18_av_video_input vid_input; + enum cx18_av_audio_input aud_input; + u32 audclk_freq; + int audmode; + int vbi_line_offset; + u32 id; + u32 rev; + int is_initialized; +}; + + +/* Registers */ +#define CXADEC_CHIP_TYPE_TIGER 0x837 +#define CXADEC_CHIP_TYPE_MAKO 0x843 + +#define CXADEC_HOST_REG1 0x000 +#define CXADEC_HOST_REG2 0x001 + +#define CXADEC_CHIP_CTRL 0x100 +#define CXADEC_AFE_CTRL 0x104 +#define CXADEC_PLL_CTRL1 0x108 +#define CXADEC_VID_PLL_FRAC 0x10C +#define CXADEC_AUX_PLL_FRAC 0x110 +#define CXADEC_PIN_CTRL1 0x114 +#define CXADEC_PIN_CTRL2 0x118 +#define CXADEC_PIN_CFG1 0x11C +#define CXADEC_PIN_CFG2 0x120 + +#define CXADEC_PIN_CFG3 0x124 +#define CXADEC_I2S_MCLK 0x127 + +#define CXADEC_AUD_LOCK1 0x128 +#define CXADEC_AUD_LOCK2 0x12C +#define CXADEC_POWER_CTRL 0x130 +#define CXADEC_AFE_DIAG_CTRL1 0x134 +#define CXADEC_AFE_DIAG_CTRL2 0x138 +#define CXADEC_AFE_DIAG_CTRL3 0x13C +#define CXADEC_PLL_DIAG_CTRL 0x140 +#define CXADEC_TEST_CTRL1 0x144 +#define CXADEC_TEST_CTRL2 0x148 +#define CXADEC_BIST_STAT 0x14C +#define CXADEC_DLL1_DIAG_CTRL 0x158 +#define CXADEC_DLL2_DIAG_CTRL 0x15C + +/* IR registers */ +#define CXADEC_IR_CTRL_REG 0x200 +#define CXADEC_IR_TXCLK_REG 0x204 +#define CXADEC_IR_RXCLK_REG 0x208 +#define CXADEC_IR_CDUTY_REG 0x20C +#define CXADEC_IR_STAT_REG 0x210 +#define CXADEC_IR_IRQEN_REG 0x214 +#define CXADEC_IR_FILTER_REG 0x218 +#define CXADEC_IR_FIFO_REG 0x21C + +/* Video Registers */ +#define CXADEC_MODE_CTRL 0x400 +#define CXADEC_OUT_CTRL1 0x404 +#define CXADEC_OUT_CTRL2 0x408 +#define CXADEC_GEN_STAT 0x40C +#define CXADEC_INT_STAT_MASK 0x410 +#define CXADEC_LUMA_CTRL 0x414 + +#define CXADEC_BRIGHTNESS_CTRL_BYTE 0x414 +#define CXADEC_CONTRAST_CTRL_BYTE 0x415 +#define CXADEC_LUMA_CTRL_BYTE_3 0x416 + +#define CXADEC_HSCALE_CTRL 0x418 +#define CXADEC_VSCALE_CTRL 0x41C + +#define CXADEC_CHROMA_CTRL 0x420 + +#define CXADEC_USAT_CTRL_BYTE 0x420 +#define CXADEC_VSAT_CTRL_BYTE 0x421 +#define CXADEC_HUE_CTRL_BYTE 0x422 + +#define CXADEC_VBI_LINE_CTRL1 0x424 +#define CXADEC_VBI_LINE_CTRL2 0x428 +#define CXADEC_VBI_LINE_CTRL3 0x42C +#define CXADEC_VBI_LINE_CTRL4 0x430 +#define CXADEC_VBI_LINE_CTRL5 0x434 +#define CXADEC_VBI_FC_CFG 0x438 +#define CXADEC_VBI_MISC_CFG1 0x43C +#define CXADEC_VBI_MISC_CFG2 0x440 +#define CXADEC_VBI_PAY1 0x444 +#define CXADEC_VBI_PAY2 0x448 +#define CXADEC_VBI_CUST1_CFG1 0x44C +#define CXADEC_VBI_CUST1_CFG2 0x450 +#define CXADEC_VBI_CUST1_CFG3 0x454 +#define CXADEC_VBI_CUST2_CFG1 0x458 +#define CXADEC_VBI_CUST2_CFG2 0x45C +#define CXADEC_VBI_CUST2_CFG3 0x460 +#define CXADEC_VBI_CUST3_CFG1 0x464 +#define CXADEC_VBI_CUST3_CFG2 0x468 +#define CXADEC_VBI_CUST3_CFG3 0x46C +#define CXADEC_HORIZ_TIM_CTRL 0x470 +#define CXADEC_VERT_TIM_CTRL 0x474 +#define CXADEC_SRC_COMB_CFG 0x478 +#define CXADEC_CHROMA_VBIOFF_CFG 0x47C +#define CXADEC_FIELD_COUNT 0x480 +#define CXADEC_MISC_TIM_CTRL 0x484 +#define CXADEC_DFE_CTRL1 0x488 +#define CXADEC_DFE_CTRL2 0x48C +#define CXADEC_DFE_CTRL3 0x490 +#define CXADEC_PLL_CTRL2 0x494 +#define CXADEC_HTL_CTRL 0x498 +#define CXADEC_COMB_CTRL 0x49C +#define CXADEC_CRUSH_CTRL 0x4A0 +#define CXADEC_SOFT_RST_CTRL 0x4A4 +#define CXADEC_MV_DT_CTRL2 0x4A8 +#define CXADEC_MV_DT_CTRL3 0x4AC +#define CXADEC_MISC_DIAG_CTRL 0x4B8 + +#define CXADEC_DL_CTL 0x800 +#define CXADEC_DL_CTL_ADDRESS_LOW 0x800 /* Byte 1 in DL_CTL */ +#define CXADEC_DL_CTL_ADDRESS_HIGH 0x801 /* Byte 2 in DL_CTL */ +#define CXADEC_DL_CTL_DATA 0x802 /* Byte 3 in DL_CTL */ +#define CXADEC_DL_CTL_CONTROL 0x803 /* Byte 4 in DL_CTL */ + +#define CXADEC_STD_DET_STATUS 0x804 + +#define CXADEC_STD_DET_CTL 0x808 +#define CXADEC_STD_DET_CTL_AUD_CTL 0x808 /* Byte 1 in STD_DET_CTL */ +#define CXADEC_STD_DET_CTL_PREF_MODE 0x809 /* Byte 2 in STD_DET_CTL */ + +#define CXADEC_DW8051_INT 0x80C +#define CXADEC_GENERAL_CTL 0x810 +#define CXADEC_AAGC_CTL 0x814 +#define CXADEC_IF_SRC_CTL 0x818 +#define CXADEC_ANLOG_DEMOD_CTL 0x81C +#define CXADEC_ROT_FREQ_CTL 0x820 +#define CXADEC_FM1_CTL 0x824 +#define CXADEC_PDF_CTL 0x828 +#define CXADEC_DFT1_CTL1 0x82C +#define CXADEC_DFT1_CTL2 0x830 +#define CXADEC_DFT_STATUS 0x834 +#define CXADEC_DFT2_CTL1 0x838 +#define CXADEC_DFT2_CTL2 0x83C +#define CXADEC_DFT2_STATUS 0x840 +#define CXADEC_DFT3_CTL1 0x844 +#define CXADEC_DFT3_CTL2 0x848 +#define CXADEC_DFT3_STATUS 0x84C +#define CXADEC_DFT4_CTL1 0x850 +#define CXADEC_DFT4_CTL2 0x854 +#define CXADEC_DFT4_STATUS 0x858 +#define CXADEC_AM_MTS_DET 0x85C +#define CXADEC_ANALOG_MUX_CTL 0x860 +#define CXADEC_DIG_PLL_CTL1 0x864 +#define CXADEC_DIG_PLL_CTL2 0x868 +#define CXADEC_DIG_PLL_CTL3 0x86C +#define CXADEC_DIG_PLL_CTL4 0x870 +#define CXADEC_DIG_PLL_CTL5 0x874 +#define CXADEC_DEEMPH_GAIN_CTL 0x878 +#define CXADEC_DEEMPH_COEF1 0x87C +#define CXADEC_DEEMPH_COEF2 0x880 +#define CXADEC_DBX1_CTL1 0x884 +#define CXADEC_DBX1_CTL2 0x888 +#define CXADEC_DBX1_STATUS 0x88C +#define CXADEC_DBX2_CTL1 0x890 +#define CXADEC_DBX2_CTL2 0x894 +#define CXADEC_DBX2_STATUS 0x898 +#define CXADEC_AM_FM_DIFF 0x89C + +/* NICAM registers go here */ +#define CXADEC_NICAM_STATUS 0x8C8 +#define CXADEC_DEMATRIX_CTL 0x8CC + +#define CXADEC_PATH1_CTL1 0x8D0 +#define CXADEC_PATH1_VOL_CTL 0x8D4 +#define CXADEC_PATH1_EQ_CTL 0x8D8 +#define CXADEC_PATH1_SC_CTL 0x8DC + +#define CXADEC_PATH2_CTL1 0x8E0 +#define CXADEC_PATH2_VOL_CTL 0x8E4 +#define CXADEC_PATH2_EQ_CTL 0x8E8 +#define CXADEC_PATH2_SC_CTL 0x8EC + +#define CXADEC_SRC_CTL 0x8F0 +#define CXADEC_SRC_LF_COEF 0x8F4 +#define CXADEC_SRC1_CTL 0x8F8 +#define CXADEC_SRC2_CTL 0x8FC +#define CXADEC_SRC3_CTL 0x900 +#define CXADEC_SRC4_CTL 0x904 +#define CXADEC_SRC5_CTL 0x908 +#define CXADEC_SRC6_CTL 0x90C + +#define CXADEC_BASEBAND_OUT_SEL 0x910 +#define CXADEC_I2S_IN_CTL 0x914 +#define CXADEC_I2S_OUT_CTL 0x918 +#define CXADEC_AC97_CTL 0x91C +#define CXADEC_QAM_PDF 0x920 +#define CXADEC_QAM_CONST_DEC 0x924 +#define CXADEC_QAM_ROTATOR_FREQ 0x948 + +/* Bit defintions / settings used in Mako Audio */ +#define CXADEC_PREF_MODE_MONO_LANGA 0 +#define CXADEC_PREF_MODE_MONO_LANGB 1 +#define CXADEC_PREF_MODE_MONO_LANGC 2 +#define CXADEC_PREF_MODE_FALLBACK 3 +#define CXADEC_PREF_MODE_STEREO 4 +#define CXADEC_PREF_MODE_DUAL_LANG_AC 5 +#define CXADEC_PREF_MODE_DUAL_LANG_BC 6 +#define CXADEC_PREF_MODE_DUAL_LANG_AB 7 + + +#define CXADEC_DETECT_STEREO 1 +#define CXADEC_DETECT_DUAL 2 +#define CXADEC_DETECT_TRI 4 +#define CXADEC_DETECT_SAP 0x10 +#define CXADEC_DETECT_NO_SIGNAL 0xFF + +#define CXADEC_SELECT_AUDIO_STANDARD_BG 0xF0 /* NICAM BG and A2 BG */ +#define CXADEC_SELECT_AUDIO_STANDARD_DK1 0xF1 /* NICAM DK and A2 DK */ +#define CXADEC_SELECT_AUDIO_STANDARD_DK2 0xF2 +#define CXADEC_SELECT_AUDIO_STANDARD_DK3 0xF3 +#define CXADEC_SELECT_AUDIO_STANDARD_I 0xF4 /* NICAM I and A1 */ +#define CXADEC_SELECT_AUDIO_STANDARD_L 0xF5 /* NICAM L and System L AM */ +#define CXADEC_SELECT_AUDIO_STANDARD_BTSC 0xF6 +#define CXADEC_SELECT_AUDIO_STANDARD_EIAJ 0xF7 +#define CXADEC_SELECT_AUDIO_STANDARD_A2_M 0xF8 /* A2 M */ +#define CXADEC_SELECT_AUDIO_STANDARD_FM 0xF9 /* FM radio */ +#define CXADEC_SELECT_AUDIO_STANDARD_AUTO 0xFF /* Auto detect */ + +/* ----------------------------------------------------------------------- */ +/* cx18_av-core.c */ +int cx18_av_write(struct cx18 *cx, u16 addr, u8 value); +int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value); +u8 cx18_av_read(struct cx18 *cx, u16 addr); +u32 cx18_av_read4(struct cx18 *cx, u16 addr); +int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value); +int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value); +int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg); + +/* ----------------------------------------------------------------------- */ +/* cx18_av-firmware.c */ +int cx18_av_loadfw(struct cx18 *cx); + +/* ----------------------------------------------------------------------- */ +/* cx18_av-audio.c */ +int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg); +void cx18_av_audio_set_path(struct cx18 *cx); + +/* ----------------------------------------------------------------------- */ +/* cx18_av-vbi.c */ +void cx18_av_vbi_setup(struct cx18 *cx); +int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg); + +#endif diff --git a/drivers/media/video/cx18/cx18-av-firmware.c b/drivers/media/video/cx18/cx18-av-firmware.c new file mode 100644 index 000000000000..526e142156cd --- /dev/null +++ b/drivers/media/video/cx18/cx18-av-firmware.c @@ -0,0 +1,120 @@ +/* + * cx18 ADEC firmware functions + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include "cx18-driver.h" +#include <linux/firmware.h> + +#define FWFILE "v4l-cx23418-dig.fw" + +int cx18_av_loadfw(struct cx18 *cx) +{ + const struct firmware *fw = NULL; + u32 size; + u32 v; + u8 *ptr; + int i; + + if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) { + CX18_ERR("unable to open firmware %s\n", FWFILE); + return -EINVAL; + } + + cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000); + cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6); /* Byte 0 */ + + /* Reset the Mako core (Register is undocumented.) */ + cx18_av_write4(cx, 0x8100, 0x00010000); + + /* Put the 8051 in reset and enable firmware upload */ + cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000); + + ptr = fw->data; + size = fw->size; + + for (i = 0; i < size; i++) { + u32 dl_control = 0x0F000000 | ((u32)ptr[i] << 16); + u32 value = 0; + int retries; + + for (retries = 0; retries < 5; retries++) { + cx18_av_write4(cx, CXADEC_DL_CTL, dl_control); + value = cx18_av_read4(cx, CXADEC_DL_CTL); + if ((value & 0x3F00) == (dl_control & 0x3F00)) + break; + } + if (retries >= 5) { + CX18_ERR("unable to load firmware %s\n", FWFILE); + release_firmware(fw); + return -EIO; + } + } + + cx18_av_write4(cx, CXADEC_DL_CTL, 0x13000000 | fw->size); + + /* Output to the 416 */ + cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x78000); + + /* Audio input control 1 set to Sony mode */ + /* Audio output input 2 is 0 for slave operation input */ + /* 0xC4000914[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */ + /* 0xC4000914[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge + after WS transition for first bit of audio word. */ + cx18_av_write4(cx, CXADEC_I2S_IN_CTL, 0x000000A0); + + /* Audio output control 1 is set to Sony mode */ + /* Audio output control 2 is set to 1 for master mode */ + /* 0xC4000918[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */ + /* 0xC4000918[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge + after WS transition for first bit of audio word. */ + /* 0xC4000918[8]: 0 = slave operation, 1 = master (SCK_OUT and WS_OUT + are generated) */ + cx18_av_write4(cx, CXADEC_I2S_OUT_CTL, 0x000001A0); + + /* set alt I2s master clock to /16 and enable alt divider i2s + passthrough */ + cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5000B687); + + cx18_av_write4(cx, CXADEC_STD_DET_CTL, 0x000000F6); + /* CxDevWrReg(CXADEC_STD_DET_CTL, 0x000000FF); */ + + /* Set bit 0 in register 0x9CC to signify that this is MiniMe. */ + /* Register 0x09CC is defined by the Merlin firmware, and doesn't + have a name in the spec. */ + cx18_av_write4(cx, 0x09CC, 1); + +#define CX18_AUDIO_ENABLE 0xc72014 + v = read_reg(CX18_AUDIO_ENABLE); + /* If bit 11 is 1 */ + if (v & 0x800) + write_reg(v & 0xFFFFFBFF, CX18_AUDIO_ENABLE); /* Clear bit 10 */ + + /* Enable WW auto audio standard detection */ + v = cx18_av_read4(cx, CXADEC_STD_DET_CTL); + v |= 0xFF; /* Auto by default */ + v |= 0x400; /* Stereo by default */ + v |= 0x14000000; + cx18_av_write4(cx, CXADEC_STD_DET_CTL, v); + + release_firmware(fw); + + CX18_INFO("loaded %s firmware (%d bytes)\n", FWFILE, size); + return 0; +} diff --git a/drivers/media/video/cx18/cx18-av-vbi.c b/drivers/media/video/cx18/cx18-av-vbi.c new file mode 100644 index 000000000000..d09f1daf4ebf --- /dev/null +++ b/drivers/media/video/cx18/cx18-av-vbi.c @@ -0,0 +1,413 @@ +/* + * cx18 ADEC VBI functions + * + * Derived from cx25840-vbi.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + + +#include "cx18-driver.h" + +static int odd_parity(u8 c) +{ + c ^= (c >> 4); + c ^= (c >> 2); + c ^= (c >> 1); + + return c & 1; +} + +static int decode_vps(u8 *dst, u8 *p) +{ + static const u8 biphase_tbl[] = { + 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, + 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, + 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96, + 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2, + 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94, + 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0, + 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, + 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, + 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5, + 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1, + 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87, + 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3, + 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85, + 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1, + 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5, + 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1, + 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4, + 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0, + 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86, + 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2, + 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84, + 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0, + 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4, + 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0, + 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, + 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, + 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96, + 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2, + 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94, + 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0, + 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, + 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, + }; + + u8 c, err = 0; + int i; + + for (i = 0; i < 2 * 13; i += 2) { + err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]]; + c = (biphase_tbl[p[i + 1]] & 0xf) | + ((biphase_tbl[p[i]] & 0xf) << 4); + dst[i / 2] = c; + } + + return err & 0xf0; +} + +void cx18_av_vbi_setup(struct cx18 *cx) +{ + struct cx18_av_state *state = &cx->av_state; + v4l2_std_id std = state->std; + int hblank, hactive, burst, vblank, vactive, sc; + int vblank656, src_decimation; + int luma_lpf, uv_lpf, comb; + u32 pll_int, pll_frac, pll_post; + + /* datasheet startup, step 8d */ + if (std & ~V4L2_STD_NTSC) + cx18_av_write(cx, 0x49f, 0x11); + else + cx18_av_write(cx, 0x49f, 0x14); + + if (std & V4L2_STD_625_50) { + hblank = 0x084; + hactive = 0x2d0; + burst = 0x5d; + vblank = 0x024; + vactive = 0x244; + vblank656 = 0x28; + src_decimation = 0x21f; + + luma_lpf = 2; + if (std & V4L2_STD_SECAM) { + uv_lpf = 0; + comb = 0; + sc = 0x0a425f; + } else if (std == V4L2_STD_PAL_Nc) { + uv_lpf = 1; + comb = 0x20; + sc = 556453; + } else { + uv_lpf = 1; + comb = 0x20; + sc = 0x0a8263; + } + } else { + hactive = 720; + hblank = 122; + vactive = 487; + luma_lpf = 1; + uv_lpf = 1; + + src_decimation = 0x21f; + if (std == V4L2_STD_PAL_60) { + vblank = 26; + vblank656 = 26; + burst = 0x5b; + luma_lpf = 2; + comb = 0x20; + sc = 0x0a8263; + } else if (std == V4L2_STD_PAL_M) { + vblank = 20; + vblank656 = 24; + burst = 0x61; + comb = 0x20; + + sc = 555452; + } else { + vblank = 26; + vblank656 = 26; + burst = 0x5b; + comb = 0x66; + sc = 556063; + } + } + + /* DEBUG: Displays configured PLL frequency */ + pll_int = cx18_av_read(cx, 0x108); + pll_frac = cx18_av_read4(cx, 0x10c) & 0x1ffffff; + pll_post = cx18_av_read(cx, 0x109); + CX18_DEBUG_INFO("PLL regs = int: %u, frac: %u, post: %u\n", + pll_int, pll_frac, pll_post); + + if (pll_post) { + int fin, fsc; + int pll = 28636363L * ((((u64)pll_int) << 25) + pll_frac); + + pll >>= 25; + pll /= pll_post; + CX18_DEBUG_INFO("PLL = %d.%06d MHz\n", + pll / 1000000, pll % 1000000); + CX18_DEBUG_INFO("PLL/8 = %d.%06d MHz\n", + pll / 8000000, (pll / 8) % 1000000); + + fin = ((u64)src_decimation * pll) >> 12; + CX18_DEBUG_INFO("ADC Sampling freq = %d.%06d MHz\n", + fin / 1000000, fin % 1000000); + + fsc = (((u64)sc) * pll) >> 24L; + CX18_DEBUG_INFO("Chroma sub-carrier freq = %d.%06d MHz\n", + fsc / 1000000, fsc % 1000000); + + CX18_DEBUG_INFO("hblank %i, hactive %i, " + "vblank %i , vactive %i, vblank656 %i, src_dec %i," + "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x," + " sc 0x%06x\n", + hblank, hactive, vblank, vactive, vblank656, + src_decimation, burst, luma_lpf, uv_lpf, comb, sc); + } + + /* Sets horizontal blanking delay and active lines */ + cx18_av_write(cx, 0x470, hblank); + cx18_av_write(cx, 0x471, 0xff & (((hblank >> 8) & 0x3) | + (hactive << 4))); + cx18_av_write(cx, 0x472, hactive >> 4); + + /* Sets burst gate delay */ + cx18_av_write(cx, 0x473, burst); + + /* Sets vertical blanking delay and active duration */ + cx18_av_write(cx, 0x474, vblank); + cx18_av_write(cx, 0x475, 0xff & (((vblank >> 8) & 0x3) | + (vactive << 4))); + cx18_av_write(cx, 0x476, vactive >> 4); + cx18_av_write(cx, 0x477, vblank656); + + /* Sets src decimation rate */ + cx18_av_write(cx, 0x478, 0xff & src_decimation); + cx18_av_write(cx, 0x479, 0xff & (src_decimation >> 8)); + + /* Sets Luma and UV Low pass filters */ + cx18_av_write(cx, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30)); + + /* Enables comb filters */ + cx18_av_write(cx, 0x47b, comb); + + /* Sets SC Step*/ + cx18_av_write(cx, 0x47c, sc); + cx18_av_write(cx, 0x47d, 0xff & sc >> 8); + cx18_av_write(cx, 0x47e, 0xff & sc >> 16); + + /* Sets VBI parameters */ + if (std & V4L2_STD_625_50) { + cx18_av_write(cx, 0x47f, 0x01); + state->vbi_line_offset = 5; + } else { + cx18_av_write(cx, 0x47f, 0x00); + state->vbi_line_offset = 8; + } +} + +int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg) +{ + struct cx18_av_state *state = &cx->av_state; + struct v4l2_format *fmt; + struct v4l2_sliced_vbi_format *svbi; + + switch (cmd) { + case VIDIOC_G_FMT: + { + static u16 lcr2vbi[] = { + 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */ + 0, V4L2_SLICED_WSS_625, 0, /* 4 */ + V4L2_SLICED_CAPTION_525, /* 6 */ + 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */ + 0, 0, 0, 0 + }; + int is_pal = !(state->std & V4L2_STD_525_60); + int i; + + fmt = arg; + if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) + return -EINVAL; + svbi = &fmt->fmt.sliced; + memset(svbi, 0, sizeof(*svbi)); + /* we're done if raw VBI is active */ + if ((cx18_av_read(cx, 0x404) & 0x10) == 0) + break; + + if (is_pal) { + for (i = 7; i <= 23; i++) { + u8 v = cx18_av_read(cx, 0x424 + i - 7); + + svbi->service_lines[0][i] = lcr2vbi[v >> 4]; + svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; + svbi->service_set |= svbi->service_lines[0][i] | + svbi->service_lines[1][i]; + } + } else { + for (i = 10; i <= 21; i++) { + u8 v = cx18_av_read(cx, 0x424 + i - 10); + + svbi->service_lines[0][i] = lcr2vbi[v >> 4]; + svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; + svbi->service_set |= svbi->service_lines[0][i] | + svbi->service_lines[1][i]; + } + } + break; + } + + case VIDIOC_S_FMT: + { + int is_pal = !(state->std & V4L2_STD_525_60); + int vbi_offset = is_pal ? 1 : 0; + int i, x; + u8 lcr[24]; + + fmt = arg; + if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) + return -EINVAL; + svbi = &fmt->fmt.sliced; + if (svbi->service_set == 0) { + /* raw VBI */ + memset(svbi, 0, sizeof(*svbi)); + + /* Setup VBI */ + cx18_av_vbi_setup(cx); + + /* VBI Offset */ + cx18_av_write(cx, 0x47f, vbi_offset); + cx18_av_write(cx, 0x404, 0x2e); + break; + } + + for (x = 0; x <= 23; x++) + lcr[x] = 0x00; + + /* Setup VBI */ + cx18_av_vbi_setup(cx); + + /* Sliced VBI */ + cx18_av_write(cx, 0x404, 0x32); /* Ancillary data */ + cx18_av_write(cx, 0x406, 0x13); + cx18_av_write(cx, 0x47f, vbi_offset); + + if (is_pal) { + for (i = 0; i <= 6; i++) + svbi->service_lines[0][i] = + svbi->service_lines[1][i] = 0; + } else { + for (i = 0; i <= 9; i++) + svbi->service_lines[0][i] = + svbi->service_lines[1][i] = 0; + + for (i = 22; i <= 23; i++) + svbi->service_lines[0][i] = + svbi->service_lines[1][i] = 0; + } + + for (i = 7; i <= 23; i++) { + for (x = 0; x <= 1; x++) { + switch (svbi->service_lines[1-x][i]) { + case V4L2_SLICED_TELETEXT_B: + lcr[i] |= 1 << (4 * x); + break; + case V4L2_SLICED_WSS_625: + lcr[i] |= 4 << (4 * x); + break; + case V4L2_SLICED_CAPTION_525: + lcr[i] |= 6 << (4 * x); + break; + case V4L2_SLICED_VPS: + lcr[i] |= 9 << (4 * x); + break; + } + } + } + + if (is_pal) { + for (x = 1, i = 0x424; i <= 0x434; i++, x++) + cx18_av_write(cx, i, lcr[6 + x]); + } else { + for (x = 1, i = 0x424; i <= 0x430; i++, x++) + cx18_av_write(cx, i, lcr[9 + x]); + for (i = 0x431; i <= 0x434; i++) + cx18_av_write(cx, i, 0); + } + + cx18_av_write(cx, 0x43c, 0x16); + cx18_av_write(cx, 0x474, is_pal ? 0x2a : 0x22); + break; + } + + case VIDIOC_INT_DECODE_VBI_LINE: + { + struct v4l2_decode_vbi_line *vbi = arg; + u8 *p = vbi->p; + int id1, id2, l, err = 0; + + if (p[0] || p[1] != 0xff || p[2] != 0xff || + (p[3] != 0x55 && p[3] != 0x91)) { + vbi->line = vbi->type = 0; + break; + } + + p += 4; + id1 = p[-1]; + id2 = p[0] & 0xf; + l = p[2] & 0x3f; + l += state->vbi_line_offset; + p += 4; + + switch (id2) { + case 1: + id2 = V4L2_SLICED_TELETEXT_B; + break; + case 4: + id2 = V4L2_SLICED_WSS_625; + break; + case 6: + id2 = V4L2_SLICED_CAPTION_525; + err = !odd_parity(p[0]) || !odd_parity(p[1]); + break; + case 9: + id2 = V4L2_SLICED_VPS; + if (decode_vps(p, p) != 0) + err = 1; + break; + default: + id2 = 0; + err = 1; + break; + } + + vbi->type = err ? 0 : id2; + vbi->line = err ? 0 : l; + vbi->is_second_field = err ? 0 : (id1 == 0x55); + vbi->p = p; + break; + } + } + + return 0; +} diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c new file mode 100644 index 000000000000..f5e3ba1f5354 --- /dev/null +++ b/drivers/media/video/cx18/cx18-cards.c @@ -0,0 +1,277 @@ +/* + * cx18 functions to query card hardware + * + * Derived from ivtv-cards.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-cards.h" +#include "cx18-i2c.h" +#include <media/cs5345.h> + +/********************** card configuration *******************************/ + +/* usual i2c tuner addresses to probe */ +static struct cx18_card_tuner_i2c cx18_i2c_std = { + .radio = { I2C_CLIENT_END }, + .demod = { 0x43, I2C_CLIENT_END }, + .tv = { 0x61, 0x60, I2C_CLIENT_END }, +}; + +/* Please add new PCI IDs to: http://pci-ids.ucw.cz/iii + This keeps the PCI ID database up to date. Note that the entries + must be added under vendor 0x4444 (Conexant) as subsystem IDs. + New vendor IDs should still be added to the vendor ID list. */ + +/* Hauppauge HVR-1600 cards */ + +/* Note: for Hauppauge cards the tveeprom information is used instead + of PCI IDs */ +static const struct cx18_card cx18_card_hvr1600_esmt = { + .type = CX18_CARD_HVR_1600_ESMT, + .name = "Hauppauge HVR-1600", + .comment = "DVB & VBI are not yet supported\n", + .v4l2_capabilities = CX18_CAP_ENCODER, + .hw_audio_ctrl = CX18_HW_CX23418, + .hw_muxer = CX18_HW_CS5345, + .hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER | CX18_HW_CS5345, + .video_inputs = { + { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 }, + { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 }, + { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 }, + { CX18_CARD_INPUT_SVIDEO2, 2, CX23418_SVIDEO2 }, + { CX18_CARD_INPUT_COMPOSITE2, 2, CX23418_COMPOSITE4 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, + CX23418_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 }, + { CX18_CARD_INPUT_LINE_IN1, + CX23418_AUDIO_SERIAL, CS5345_IN_2 }, + { CX18_CARD_INPUT_LINE_IN2, + CX23418_AUDIO_SERIAL, CS5345_IN_2 }, + }, + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, + CX23418_AUDIO_SERIAL, 0 }, + .ddr = { + /* ESMT M13S128324A-5B memory */ + .chip_config = 0x003, + .refresh = 0x30c, + .timing1 = 0x44220e82, + .timing2 = 0x08, + .tune_lane = 0, + .initial_emrs = 0, + }, + .gpio_init.initial_value = 0x3001, + .gpio_init.direction = 0x3001, + .i2c = &cx18_i2c_std, +}; + +static const struct cx18_card cx18_card_hvr1600_samsung = { + .type = CX18_CARD_HVR_1600_SAMSUNG, + .name = "Hauppauge HVR-1600 (Preproduction)", + .comment = "DVB & VBI are not yet supported\n", + .v4l2_capabilities = CX18_CAP_ENCODER, + .hw_audio_ctrl = CX18_HW_CX23418, + .hw_muxer = CX18_HW_CS5345, + .hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER | CX18_HW_CS5345, + .video_inputs = { + { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 }, + { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 }, + { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 }, + { CX18_CARD_INPUT_SVIDEO2, 2, CX23418_SVIDEO2 }, + { CX18_CARD_INPUT_COMPOSITE2, 2, CX23418_COMPOSITE4 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, + CX23418_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 }, + { CX18_CARD_INPUT_LINE_IN1, + CX23418_AUDIO_SERIAL, CS5345_IN_2 }, + { CX18_CARD_INPUT_LINE_IN2, + CX23418_AUDIO_SERIAL, CS5345_IN_2 }, + }, + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, + CX23418_AUDIO_SERIAL, 0 }, + .ddr = { + /* Samsung K4D263238G-VC33 memory */ + .chip_config = 0x003, + .refresh = 0x30c, + .timing1 = 0x23230b73, + .timing2 = 0x08, + .tune_lane = 0, + .initial_emrs = 2, + }, + .gpio_init.initial_value = 0x3001, + .gpio_init.direction = 0x3001, + .i2c = &cx18_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* Compro VideoMate H900: not working at the moment! */ + +static const struct cx18_card_pci_info cx18_pci_h900[] = { + { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_COMPRO, 0xe100 }, + { 0, 0, 0 } +}; + +static const struct cx18_card cx18_card_h900 = { + .type = CX18_CARD_COMPRO_H900, + .name = "Compro VideoMate H900", + .comment = "Not yet supported!\n", + .v4l2_capabilities = 0, + .hw_audio_ctrl = CX18_HW_CX23418, + .hw_all = CX18_HW_TUNER, + .video_inputs = { + { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 }, + { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 }, + { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, + CX23418_AUDIO8, 0 }, + { CX18_CARD_INPUT_LINE_IN1, + CX23418_AUDIO_SERIAL, 0 }, + }, + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, + CX23418_AUDIO_SERIAL, 0 }, + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, + .ddr = { + /* EtronTech EM6A9160TS-5G memory */ + .chip_config = 0x50003, + .refresh = 0x753, + .timing1 = 0x24330e84, + .timing2 = 0x1f, + .tune_lane = 0, + .initial_emrs = 0, + }, + .pci_list = cx18_pci_h900, + .i2c = &cx18_i2c_std, +}; + +/* ------------------------------------------------------------------------- */ + +/* Yuan MPC718: not working at the moment! */ + +static const struct cx18_card_pci_info cx18_pci_mpc718[] = { + { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_YUAN, 0x0718 }, + { 0, 0, 0 } +}; + +static const struct cx18_card cx18_card_mpc718 = { + .type = CX18_CARD_YUAN_MPC718, + .name = "Yuan MPC718", + .comment = "Not yet supported!\n", + .v4l2_capabilities = 0, + .hw_audio_ctrl = CX18_HW_CX23418, + .hw_all = CX18_HW_TUNER, + .video_inputs = { + { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 }, + { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 }, + { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 }, + }, + .audio_inputs = { + { CX18_CARD_INPUT_AUD_TUNER, + CX23418_AUDIO8, 0 }, + { CX18_CARD_INPUT_LINE_IN1, + CX23418_AUDIO_SERIAL, 0 }, + }, + .radio_input = { CX18_CARD_INPUT_AUD_TUNER, + CX23418_AUDIO_SERIAL, 0 }, + .tuners = { + /* XC3028 tuner */ + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, + /* tuner reset */ + .gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, + .ddr = { + /* Probably Samsung K4D263238G-VC33 memory */ + .chip_config = 0x003, + .refresh = 0x30c, + .timing1 = 0x23230b73, + .timing2 = 0x08, + .tune_lane = 0, + .initial_emrs = 2, + }, + .pci_list = cx18_pci_mpc718, + .i2c = &cx18_i2c_std, +}; + +static const struct cx18_card *cx18_card_list[] = { + &cx18_card_hvr1600_esmt, + &cx18_card_hvr1600_samsung, + &cx18_card_h900, + &cx18_card_mpc718, +}; + +const struct cx18_card *cx18_get_card(u16 index) +{ + if (index >= ARRAY_SIZE(cx18_card_list)) + return NULL; + return cx18_card_list[index]; +} + +int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input) +{ + const struct cx18_card_video_input *card_input = + cx->card->video_inputs + index; + static const char * const input_strs[] = { + "Tuner 1", + "S-Video 1", + "S-Video 2", + "Composite 1", + "Composite 2", + "Composite 3" + }; + + memset(input, 0, sizeof(*input)); + if (index >= cx->nof_inputs) + return -EINVAL; + input->index = index; + strlcpy(input->name, input_strs[card_input->video_type - 1], + sizeof(input->name)); + input->type = (card_input->video_type == CX18_CARD_INPUT_VID_TUNER ? + V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA); + input->audioset = (1 << cx->nof_audio_inputs) - 1; + input->std = (input->type == V4L2_INPUT_TYPE_TUNER) ? + cx->tuner_std : V4L2_STD_ALL; + return 0; +} + +int cx18_get_audio_input(struct cx18 *cx, u16 index, struct v4l2_audio *audio) +{ + const struct cx18_card_audio_input *aud_input = + cx->card->audio_inputs + index; + static const char * const input_strs[] = { + "Tuner 1", + "Line In 1", + "Line In 2" + }; + + memset(audio, 0, sizeof(*audio)); + if (index >= cx->nof_audio_inputs) + return -EINVAL; + strlcpy(audio->name, input_strs[aud_input->audio_type - 1], + sizeof(audio->name)); + audio->index = index; + audio->capability = V4L2_AUDCAP_STEREO; + return 0; +} diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h new file mode 100644 index 000000000000..bca249bdd337 --- /dev/null +++ b/drivers/media/video/cx18/cx18-cards.h @@ -0,0 +1,170 @@ +/* + * cx18 functions to query card hardware + * + * Derived from ivtv-cards.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 + */ + +/* hardware flags */ +#define CX18_HW_TUNER (1 << 0) +#define CX18_HW_TVEEPROM (1 << 1) +#define CX18_HW_CS5345 (1 << 2) +#define CX18_HW_GPIO (1 << 3) +#define CX18_HW_CX23418 (1 << 4) +#define CX18_HW_DVB (1 << 5) + +/* video inputs */ +#define CX18_CARD_INPUT_VID_TUNER 1 +#define CX18_CARD_INPUT_SVIDEO1 2 +#define CX18_CARD_INPUT_SVIDEO2 3 +#define CX18_CARD_INPUT_COMPOSITE1 4 +#define CX18_CARD_INPUT_COMPOSITE2 5 +#define CX18_CARD_INPUT_COMPOSITE3 6 + +enum cx34180_video_input { + /* Composite video inputs In1-In8 */ + CX23418_COMPOSITE1 = 1, + CX23418_COMPOSITE2, + CX23418_COMPOSITE3, + CX23418_COMPOSITE4, + CX23418_COMPOSITE5, + CX23418_COMPOSITE6, + CX23418_COMPOSITE7, + CX23418_COMPOSITE8, + + /* S-Video inputs consist of one luma input (In1-In4) ORed with one + chroma input (In5-In8) */ + CX23418_SVIDEO_LUMA1 = 0x10, + CX23418_SVIDEO_LUMA2 = 0x20, + CX23418_SVIDEO_LUMA3 = 0x30, + CX23418_SVIDEO_LUMA4 = 0x40, + CX23418_SVIDEO_CHROMA4 = 0x400, + CX23418_SVIDEO_CHROMA5 = 0x500, + CX23418_SVIDEO_CHROMA6 = 0x600, + CX23418_SVIDEO_CHROMA7 = 0x700, + CX23418_SVIDEO_CHROMA8 = 0x800, + + /* S-Video aliases for common luma/chroma combinations */ + CX23418_SVIDEO1 = 0x510, + CX23418_SVIDEO2 = 0x620, + CX23418_SVIDEO3 = 0x730, + CX23418_SVIDEO4 = 0x840, +}; + +/* audio inputs */ +#define CX18_CARD_INPUT_AUD_TUNER 1 +#define CX18_CARD_INPUT_LINE_IN1 2 +#define CX18_CARD_INPUT_LINE_IN2 3 + +#define CX18_CARD_MAX_VIDEO_INPUTS 6 +#define CX18_CARD_MAX_AUDIO_INPUTS 3 +#define CX18_CARD_MAX_TUNERS 2 + +enum cx23418_audio_input { + /* Audio inputs: serial or In4-In8 */ + CX23418_AUDIO_SERIAL, + CX23418_AUDIO4 = 4, + CX23418_AUDIO5, + CX23418_AUDIO6, + CX23418_AUDIO7, + CX23418_AUDIO8, +}; + +/* V4L2 capability aliases */ +#define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \ + V4L2_CAP_AUDIO | V4L2_CAP_READWRITE) +/* | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE) not yet */ + +struct cx18_card_video_input { + u8 video_type; /* video input type */ + u8 audio_index; /* index in cx18_card_audio_input array */ + u16 video_input; /* hardware video input */ +}; + +struct cx18_card_audio_input { + u8 audio_type; /* audio input type */ + u32 audio_input; /* hardware audio input */ + u16 muxer_input; /* hardware muxer input for boards with a + multiplexer chip */ +}; + +struct cx18_card_pci_info { + u16 device; + u16 subsystem_vendor; + u16 subsystem_device; +}; + +/* GPIO definitions */ + +/* The mask is the set of bits used by the operation */ + +struct cx18_gpio_init { /* set initial GPIO DIR and OUT values */ + u16 direction; /* DIR setting. Leave to 0 if no init is needed */ + u16 initial_value; +}; + +struct cx18_card_tuner { + v4l2_std_id std; /* standard for which the tuner is suitable */ + int tuner; /* tuner ID (from tuner.h) */ +}; + +struct cx18_card_tuner_i2c { + unsigned short radio[2];/* radio tuner i2c address to probe */ + unsigned short demod[2];/* demodulator i2c address to probe */ + unsigned short tv[4]; /* tv tuner i2c addresses to probe */ +}; + +struct cx18_ddr { /* DDR config data */ + u32 chip_config; + u32 refresh; + u32 timing1; + u32 timing2; + u32 tune_lane; + u32 initial_emrs; +}; + +/* for card information/parameters */ +struct cx18_card { + int type; + char *name; + char *comment; + u32 v4l2_capabilities; + u32 hw_audio_ctrl; /* hardware used for the V4L2 controls (only + 1 dev allowed) */ + u32 hw_muxer; /* hardware used to multiplex audio input */ + u32 hw_all; /* all hardware used by the board */ + struct cx18_card_video_input video_inputs[CX18_CARD_MAX_VIDEO_INPUTS]; + struct cx18_card_audio_input audio_inputs[CX18_CARD_MAX_AUDIO_INPUTS]; + struct cx18_card_audio_input radio_input; + + /* GPIO card-specific settings */ + struct cx18_gpio_init gpio_init; + + struct cx18_card_tuner tuners[CX18_CARD_MAX_TUNERS]; + struct cx18_card_tuner_i2c *i2c; + + struct cx18_ddr ddr; + + /* list of device and subsystem vendor/devices that + correspond to this card type. */ + const struct cx18_card_pci_info *pci_list; +}; + +int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input); +int cx18_get_audio_input(struct cx18 *cx, u16 index, struct v4l2_audio *input); +const struct cx18_card *cx18_get_card(u16 index); diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c new file mode 100644 index 000000000000..2bdac5ebbb0d --- /dev/null +++ b/drivers/media/video/cx18/cx18-controls.c @@ -0,0 +1,306 @@ +/* + * cx18 ioctl control functions + * + * Derived from ivtv-controls.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-av-core.h" +#include "cx18-cards.h" +#include "cx18-ioctl.h" +#include "cx18-audio.h" +#include "cx18-i2c.h" +#include "cx18-mailbox.h" +#include "cx18-controls.h" + +static const u32 user_ctrls[] = { + V4L2_CID_USER_CLASS, + V4L2_CID_BRIGHTNESS, + V4L2_CID_CONTRAST, + V4L2_CID_SATURATION, + V4L2_CID_HUE, + V4L2_CID_AUDIO_VOLUME, + V4L2_CID_AUDIO_BALANCE, + V4L2_CID_AUDIO_BASS, + V4L2_CID_AUDIO_TREBLE, + V4L2_CID_AUDIO_MUTE, + V4L2_CID_AUDIO_LOUDNESS, + 0 +}; + +static const u32 *ctrl_classes[] = { + user_ctrls, + cx2341x_mpeg_ctrls, + NULL +}; + +static int cx18_queryctrl(struct cx18 *cx, struct v4l2_queryctrl *qctrl) +{ + const char *name; + + CX18_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id); + + qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); + if (qctrl->id == 0) + return -EINVAL; + + switch (qctrl->id) { + /* Standard V4L2 controls */ + case V4L2_CID_BRIGHTNESS: + case V4L2_CID_HUE: + case V4L2_CID_SATURATION: + case V4L2_CID_CONTRAST: + if (cx18_av_cmd(cx, VIDIOC_QUERYCTRL, qctrl)) + qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; + return 0; + + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_MUTE: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + case V4L2_CID_AUDIO_LOUDNESS: + if (cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_QUERYCTRL, qctrl)) + qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; + return 0; + + default: + if (cx2341x_ctrl_query(&cx->params, qctrl)) + qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; + return 0; + } + strncpy(qctrl->name, name, sizeof(qctrl->name) - 1); + qctrl->name[sizeof(qctrl->name) - 1] = 0; + return 0; +} + +static int cx18_querymenu(struct cx18 *cx, struct v4l2_querymenu *qmenu) +{ + struct v4l2_queryctrl qctrl; + + qctrl.id = qmenu->id; + cx18_queryctrl(cx, &qctrl); + return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id)); +} + +static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl) +{ + s32 v = vctrl->value; + + CX18_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v); + + switch (vctrl->id) { + /* Standard V4L2 controls */ + case V4L2_CID_BRIGHTNESS: + case V4L2_CID_HUE: + case V4L2_CID_SATURATION: + case V4L2_CID_CONTRAST: + return cx18_av_cmd(cx, VIDIOC_S_CTRL, vctrl); + + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_MUTE: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + case V4L2_CID_AUDIO_LOUDNESS: + return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl); + + default: + CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id); + return -EINVAL; + } + return 0; +} + +static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl) +{ + CX18_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id); + + switch (vctrl->id) { + /* Standard V4L2 controls */ + case V4L2_CID_BRIGHTNESS: + case V4L2_CID_HUE: + case V4L2_CID_SATURATION: + case V4L2_CID_CONTRAST: + return cx18_av_cmd(cx, VIDIOC_G_CTRL, vctrl); + + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_AUDIO_MUTE: + case V4L2_CID_AUDIO_BALANCE: + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + case V4L2_CID_AUDIO_LOUDNESS: + return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl); + default: + CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id); + return -EINVAL; + } + return 0; +} + +static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt) +{ + if (!(cx->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE)) + return -EINVAL; + if (atomic_read(&cx->capturing) > 0) + return -EBUSY; + + /* First try to allocate sliced VBI buffers if needed. */ + if (fmt && cx->vbi.sliced_mpeg_data[0] == NULL) { + int i; + + for (i = 0; i < CX18_VBI_FRAMES; i++) { + /* Yuck, hardcoded. Needs to be a define */ + cx->vbi.sliced_mpeg_data[i] = kmalloc(2049, GFP_KERNEL); + if (cx->vbi.sliced_mpeg_data[i] == NULL) { + while (--i >= 0) { + kfree(cx->vbi.sliced_mpeg_data[i]); + cx->vbi.sliced_mpeg_data[i] = NULL; + } + return -ENOMEM; + } + } + } + + cx->vbi.insert_mpeg = fmt; + + if (cx->vbi.insert_mpeg == 0) + return 0; + /* Need sliced data for mpeg insertion */ + if (cx18_get_service_set(cx->vbi.sliced_in) == 0) { + if (cx->is_60hz) + cx->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525; + else + cx->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625; + cx18_expand_service_set(cx->vbi.sliced_in, cx->is_50hz); + } + return 0; +} + +int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg) +{ + struct v4l2_control ctrl; + + switch (cmd) { + case VIDIOC_QUERYMENU: + CX18_DEBUG_IOCTL("VIDIOC_QUERYMENU\n"); + return cx18_querymenu(cx, arg); + + case VIDIOC_QUERYCTRL: + return cx18_queryctrl(cx, arg); + + case VIDIOC_S_CTRL: + return cx18_s_ctrl(cx, arg); + + case VIDIOC_G_CTRL: + return cx18_g_ctrl(cx, arg); + + case VIDIOC_S_EXT_CTRLS: + { + struct v4l2_ext_controls *c = arg; + + if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { + int i; + int err = 0; + + for (i = 0; i < c->count; i++) { + ctrl.id = c->controls[i].id; + ctrl.value = c->controls[i].value; + err = cx18_s_ctrl(cx, &ctrl); + c->controls[i].value = ctrl.value; + if (err) { + c->error_idx = i; + break; + } + } + return err; + } + CX18_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n"); + if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) { + struct cx2341x_mpeg_params p = cx->params; + int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->capturing), arg, cmd); + + if (err) + return err; + + if (p.video_encoding != cx->params.video_encoding) { + int is_mpeg1 = p.video_encoding == + V4L2_MPEG_VIDEO_ENCODING_MPEG_1; + struct v4l2_format fmt; + + /* fix videodecoder resolution */ + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fmt.fmt.pix.width = cx->params.width / (is_mpeg1 ? 2 : 1); + fmt.fmt.pix.height = cx->params.height; + cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt); + } + err = cx2341x_update(cx, cx18_api_func, &cx->params, &p); + if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt) + err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt); + cx->params = p; + cx->dualwatch_stereo_mode = p.audio_properties & 0x0300; + cx18_audio_set_audio_clock_freq(cx, p.audio_properties & 0x03); + return err; + } + return -EINVAL; + } + + case VIDIOC_G_EXT_CTRLS: + { + struct v4l2_ext_controls *c = arg; + + if (c->ctrl_class == V4L2_CTRL_CLASS_USER) { + int i; + int err = 0; + + for (i = 0; i < c->count; i++) { + ctrl.id = c->controls[i].id; + ctrl.value = c->controls[i].value; + err = cx18_g_ctrl(cx, &ctrl); + c->controls[i].value = ctrl.value; + if (err) { + c->error_idx = i; + break; + } + } + return err; + } + CX18_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n"); + if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) + return cx2341x_ext_ctrls(&cx->params, 0, arg, cmd); + return -EINVAL; + } + + case VIDIOC_TRY_EXT_CTRLS: + { + struct v4l2_ext_controls *c = arg; + + CX18_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n"); + if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) + return cx2341x_ext_ctrls(&cx->params, + atomic_read(&cx->capturing), arg, cmd); + return -EINVAL; + } + + default: + return -EINVAL; + } + return 0; +} diff --git a/drivers/media/video/cx18/cx18-controls.h b/drivers/media/video/cx18/cx18-controls.h new file mode 100644 index 000000000000..6e985cf422a0 --- /dev/null +++ b/drivers/media/video/cx18/cx18-controls.h @@ -0,0 +1,24 @@ +/* + * cx18 ioctl control functions + * + * Derived from ivtv-controls.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + + * 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 + */ + +int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg); diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c new file mode 100644 index 000000000000..8f5ed9b4bf83 --- /dev/null +++ b/drivers/media/video/cx18/cx18-driver.c @@ -0,0 +1,971 @@ +/* + * cx18 driver initialization and card probing + * + * Derived from ivtv-driver.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-version.h" +#include "cx18-cards.h" +#include "cx18-i2c.h" +#include "cx18-irq.h" +#include "cx18-gpio.h" +#include "cx18-firmware.h" +#include "cx18-streams.h" +#include "cx18-av-core.h" +#include "cx18-scb.h" +#include "cx18-mailbox.h" +#include "cx18-ioctl.h" +#include "tuner-xc2028.h" + +#include <media/tveeprom.h> + + +/* var to keep track of the number of array elements in use */ +int cx18_cards_active; + +/* If you have already X v4l cards, then set this to X. This way + the device numbers stay matched. Example: you have a WinTV card + without radio and a Compro H900 with. Normally this would give a + video1 device together with a radio0 device for the Compro. By + setting this to 1 you ensure that radio0 is now also radio1. */ +int cx18_first_minor; + +/* Master variable for all cx18 info */ +struct cx18 *cx18_cards[CX18_MAX_CARDS]; + +/* Protects cx18_cards_active */ +DEFINE_SPINLOCK(cx18_cards_lock); + +/* add your revision and whatnot here */ +static struct pci_device_id cx18_pci_tbl[] __devinitdata = { + {PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0,} +}; + +MODULE_DEVICE_TABLE(pci, cx18_pci_tbl); + +/* Parameter declarations */ +static int cardtype[CX18_MAX_CARDS]; +static int tuner[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; +static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 }; + +static int cardtype_c = 1; +static int tuner_c = 1; +static int radio_c = 1; +static char pal[] = "--"; +static char secam[] = "--"; +static char ntsc[] = "-"; + +/* Buffers */ +static int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS; +static int enc_ts_buffers = CX18_DEFAULT_ENC_TS_BUFFERS; +static int enc_yuv_buffers = CX18_DEFAULT_ENC_YUV_BUFFERS; +static int enc_vbi_buffers = CX18_DEFAULT_ENC_VBI_BUFFERS; +static int enc_pcm_buffers = CX18_DEFAULT_ENC_PCM_BUFFERS; + +static int cx18_pci_latency = 1; + +int cx18_debug; + +module_param_array(tuner, int, &tuner_c, 0644); +module_param_array(radio, bool, &radio_c, 0644); +module_param_array(cardtype, int, &cardtype_c, 0644); +module_param_string(pal, pal, sizeof(pal), 0644); +module_param_string(secam, secam, sizeof(secam), 0644); +module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); +module_param_named(debug, cx18_debug, int, 0644); +module_param(cx18_pci_latency, int, 0644); +module_param(cx18_first_minor, int, 0644); + +module_param(enc_mpg_buffers, int, 0644); +module_param(enc_ts_buffers, int, 0644); +module_param(enc_yuv_buffers, int, 0644); +module_param(enc_vbi_buffers, int, 0644); +module_param(enc_pcm_buffers, int, 0644); + +MODULE_PARM_DESC(tuner, "Tuner type selection,\n" + "\t\t\tsee tuner.h for values"); +MODULE_PARM_DESC(radio, + "Enable or disable the radio. Use only if autodetection\n" + "\t\t\tfails. 0 = disable, 1 = enable"); +MODULE_PARM_DESC(cardtype, + "Only use this option if your card is not detected properly.\n" + "\t\tSpecify card type:\n" + "\t\t\t 1 = Hauppauge HVR 1600 (ESMT memory)\n" + "\t\t\t 2 = Hauppauge HVR 1600 (Samsung memory)\n" + "\t\t\t 3 = Compro VideoMate H900\n" + "\t\t\t 4 = Yuan MPC718\n" + "\t\t\t 0 = Autodetect (default)\n" + "\t\t\t-1 = Ignore this card\n\t\t"); +MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); +MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC"); +MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K"); +MODULE_PARM_DESC(debug, + "Debug level (bitmask). Default: 0\n" + "\t\t\t 1/0x0001: warning\n" + "\t\t\t 2/0x0002: info\n" + "\t\t\t 4/0x0004: mailbox\n" + "\t\t\t 8/0x0008: dma\n" + "\t\t\t 16/0x0010: ioctl\n" + "\t\t\t 32/0x0020: file\n" + "\t\t\t 64/0x0040: i2c\n" + "\t\t\t128/0x0080: irq\n" + "\t\t\t256/0x0100: high volume\n"); +MODULE_PARM_DESC(cx18_pci_latency, + "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n" + "\t\t\tDefault: Yes"); +MODULE_PARM_DESC(enc_mpg_buffers, + "Encoder MPG Buffers (in MB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS)); +MODULE_PARM_DESC(enc_ts_buffers, + "Encoder TS Buffers (in MB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFFERS)); +MODULE_PARM_DESC(enc_yuv_buffers, + "Encoder YUV Buffers (in MB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS)); +MODULE_PARM_DESC(enc_vbi_buffers, + "Encoder VBI Buffers (in MB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_VBI_BUFFERS)); +MODULE_PARM_DESC(enc_pcm_buffers, + "Encoder PCM buffers (in MB)\n" + "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS)); + +MODULE_PARM_DESC(cx18_first_minor, "Set minor assigned to first card"); + +MODULE_AUTHOR("Hans Verkuil"); +MODULE_DESCRIPTION("CX23418 driver"); +MODULE_SUPPORTED_DEVICE("CX23418 MPEG2 encoder"); +MODULE_LICENSE("GPL"); + +MODULE_VERSION(CX18_VERSION); + +int cx18_waitq(wait_queue_head_t *waitq) +{ + DEFINE_WAIT(wait); + + prepare_to_wait(waitq, &wait, TASK_INTERRUPTIBLE); + schedule(); + finish_wait(waitq, &wait); + return signal_pending(current) ? -EINTR : 0; +} + +/* Generic utility functions */ +int cx18_msleep_timeout(unsigned int msecs, int intr) +{ + int timeout = msecs_to_jiffies(msecs); + int sig; + + do { + set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); + timeout = schedule_timeout(timeout); + sig = intr ? signal_pending(current) : 0; + } while (!sig && timeout); + return sig; +} + +/* Release ioremapped memory */ +static void cx18_iounmap(struct cx18 *cx) +{ + if (cx == NULL) + return; + + /* Release io memory */ + if (cx->enc_mem != NULL) { + CX18_DEBUG_INFO("releasing enc_mem\n"); + iounmap(cx->enc_mem); + cx->enc_mem = NULL; + } +} + +/* Hauppauge card? get values from tveeprom */ +void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv) +{ + u8 eedata[256]; + + cx->i2c_client[0].addr = 0xA0 >> 1; + tveeprom_read(&cx->i2c_client[0], eedata, sizeof(eedata)); + tveeprom_hauppauge_analog(&cx->i2c_client[0], tv, eedata); +} + +static void cx18_process_eeprom(struct cx18 *cx) +{ + struct tveeprom tv; + + cx18_read_eeprom(cx, &tv); + + /* Many thanks to Steven Toth from Hauppauge for providing the + model numbers */ + switch (tv.model) { + case 74000 ... 74099: + cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); + break; + case 74700 ... 74799: + cx->card = cx18_get_card(CX18_CARD_HVR_1600_SAMSUNG); + break; + case 0: + CX18_ERR("Invalid EEPROM\n"); + return; + default: + CX18_ERR("Unknown model %d, defaulting to HVR-1600\n", tv.model); + cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); + break; + } + + cx->v4l2_cap = cx->card->v4l2_capabilities; + cx->card_name = cx->card->name; + cx->card_i2c = cx->card->i2c; + + CX18_INFO("Autodetected %s\n", cx->card_name); + + if (tv.tuner_type == TUNER_ABSENT) + CX18_ERR("tveeprom cannot autodetect tuner!"); + + if (cx->options.tuner == -1) + cx->options.tuner = tv.tuner_type; + if (cx->options.radio == -1) + cx->options.radio = (tv.has_radio != 0); + + if (cx->std != 0) + /* user specified tuner standard */ + return; + + /* autodetect tuner standard */ + if (tv.tuner_formats & V4L2_STD_PAL) { + CX18_DEBUG_INFO("PAL tuner detected\n"); + cx->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H; + } else if (tv.tuner_formats & V4L2_STD_NTSC) { + CX18_DEBUG_INFO("NTSC tuner detected\n"); + cx->std |= V4L2_STD_NTSC_M; + } else if (tv.tuner_formats & V4L2_STD_SECAM) { + CX18_DEBUG_INFO("SECAM tuner detected\n"); + cx->std |= V4L2_STD_SECAM_L; + } else { + CX18_INFO("No tuner detected, default to NTSC-M\n"); + cx->std |= V4L2_STD_NTSC_M; + } +} + +static v4l2_std_id cx18_parse_std(struct cx18 *cx) +{ + switch (pal[0]) { + case '6': + return V4L2_STD_PAL_60; + case 'b': + case 'B': + case 'g': + case 'G': + return V4L2_STD_PAL_BG; + case 'h': + case 'H': + return V4L2_STD_PAL_H; + case 'n': + case 'N': + if (pal[1] == 'c' || pal[1] == 'C') + return V4L2_STD_PAL_Nc; + return V4L2_STD_PAL_N; + case 'i': + case 'I': + return V4L2_STD_PAL_I; + case 'd': + case 'D': + case 'k': + case 'K': + return V4L2_STD_PAL_DK; + case 'M': + case 'm': + return V4L2_STD_PAL_M; + case '-': + break; + default: + CX18_WARN("pal= argument not recognised\n"); + return 0; + } + + switch (secam[0]) { + case 'b': + case 'B': + case 'g': + case 'G': + case 'h': + case 'H': + return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H; + case 'd': + case 'D': + case 'k': + case 'K': + return V4L2_STD_SECAM_DK; + case 'l': + case 'L': + if (secam[1] == 'C' || secam[1] == 'c') + return V4L2_STD_SECAM_LC; + return V4L2_STD_SECAM_L; + case '-': + break; + default: + CX18_WARN("secam= argument not recognised\n"); + return 0; + } + + switch (ntsc[0]) { + case 'm': + case 'M': + return V4L2_STD_NTSC_M; + case 'j': + case 'J': + return V4L2_STD_NTSC_M_JP; + case 'k': + case 'K': + return V4L2_STD_NTSC_M_KR; + case '-': + break; + default: + CX18_WARN("ntsc= argument not recognised\n"); + return 0; + } + + /* no match found */ + return 0; +} + +static void cx18_process_options(struct cx18 *cx) +{ + int i, j; + + cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers; + cx->options.megabytes[CX18_ENC_STREAM_TYPE_TS] = enc_ts_buffers; + cx->options.megabytes[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers; + cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers; + cx->options.megabytes[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers; + cx->options.cardtype = cardtype[cx->num]; + cx->options.tuner = tuner[cx->num]; + cx->options.radio = radio[cx->num]; + + cx->std = cx18_parse_std(cx); + if (cx->options.cardtype == -1) { + CX18_INFO("Ignore card\n"); + return; + } + cx->card = cx18_get_card(cx->options.cardtype - 1); + if (cx->card) + CX18_INFO("User specified %s card\n", cx->card->name); + else if (cx->options.cardtype != 0) + CX18_ERR("Unknown user specified type, trying to autodetect card\n"); + if (cx->card == NULL) { + if (cx->dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) { + cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); + CX18_INFO("Autodetected Hauppauge card\n"); + } + } + if (cx->card == NULL) { + for (i = 0; (cx->card = cx18_get_card(i)); i++) { + if (cx->card->pci_list == NULL) + continue; + for (j = 0; cx->card->pci_list[j].device; j++) { + if (cx->dev->device != + cx->card->pci_list[j].device) + continue; + if (cx->dev->subsystem_vendor != + cx->card->pci_list[j].subsystem_vendor) + continue; + if (cx->dev->subsystem_device != + cx->card->pci_list[j].subsystem_device) + continue; + CX18_INFO("Autodetected %s card\n", cx->card->name); + goto done; + } + } + } +done: + + if (cx->card == NULL) { + cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); + CX18_ERR("Unknown card: vendor/device: %04x/%04x\n", + cx->dev->vendor, cx->dev->device); + CX18_ERR(" subsystem vendor/device: %04x/%04x\n", + cx->dev->subsystem_vendor, cx->dev->subsystem_device); + CX18_ERR("Defaulting to %s card\n", cx->card->name); + CX18_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n"); + CX18_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n"); + CX18_ERR("Prefix your subject line with [UNKNOWN CX18 CARD].\n"); + } + cx->v4l2_cap = cx->card->v4l2_capabilities; + cx->card_name = cx->card->name; + cx->card_i2c = cx->card->i2c; +} + +/* Precondition: the cx18 structure has been memset to 0. Only + the dev and num fields have been filled in. + No assumptions on the card type may be made here (see cx18_init_struct2 + for that). + */ +static int __devinit cx18_init_struct1(struct cx18 *cx) +{ + cx->base_addr = pci_resource_start(cx->dev, 0); + + mutex_init(&cx->serialize_lock); + mutex_init(&cx->i2c_bus_lock[0]); + mutex_init(&cx->i2c_bus_lock[1]); + + spin_lock_init(&cx->lock); + spin_lock_init(&cx->dma_reg_lock); + + /* start counting open_id at 1 */ + cx->open_id = 1; + + /* Initial settings */ + cx2341x_fill_defaults(&cx->params); + cx->temporal_strength = cx->params.video_temporal_filter; + cx->spatial_strength = cx->params.video_spatial_filter; + cx->filter_mode = cx->params.video_spatial_filter_mode | + (cx->params.video_temporal_filter_mode << 1) | + (cx->params.video_median_filter_type << 2); + cx->params.port = CX2341X_PORT_MEMORY; + cx->params.capabilities = CX2341X_CAP_HAS_SLICED_VBI; + init_waitqueue_head(&cx->cap_w); + init_waitqueue_head(&cx->mb_apu_waitq); + init_waitqueue_head(&cx->mb_cpu_waitq); + init_waitqueue_head(&cx->mb_epu_waitq); + init_waitqueue_head(&cx->mb_hpu_waitq); + init_waitqueue_head(&cx->dma_waitq); + + /* VBI */ + cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; + cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced; + cx->vbi.raw_size = 1456; + cx->vbi.raw_decoder_line_size = 1456; + cx->vbi.raw_decoder_sav_odd_field = 0x20; + cx->vbi.raw_decoder_sav_even_field = 0x60; + cx->vbi.sliced_decoder_line_size = 272; + cx->vbi.sliced_decoder_sav_odd_field = 0xB0; + cx->vbi.sliced_decoder_sav_even_field = 0xF0; + return 0; +} + +/* Second initialization part. Here the card type has been + autodetected. */ +static void __devinit cx18_init_struct2(struct cx18 *cx) +{ + int i; + + for (i = 0; i < CX18_CARD_MAX_VIDEO_INPUTS; i++) + if (cx->card->video_inputs[i].video_type == 0) + break; + cx->nof_inputs = i; + for (i = 0; i < CX18_CARD_MAX_AUDIO_INPUTS; i++) + if (cx->card->audio_inputs[i].audio_type == 0) + break; + cx->nof_audio_inputs = i; + + /* Find tuner input */ + for (i = 0; i < cx->nof_inputs; i++) { + if (cx->card->video_inputs[i].video_type == + CX18_CARD_INPUT_VID_TUNER) + break; + } + if (i == cx->nof_inputs) + i = 0; + cx->active_input = i; + cx->audio_input = cx->card->video_inputs[i].audio_index; + cx->av_state.vid_input = CX18_AV_COMPOSITE7; + cx->av_state.aud_input = CX18_AV_AUDIO8; + cx->av_state.audclk_freq = 48000; + cx->av_state.audmode = V4L2_TUNER_MODE_LANG1; + cx->av_state.vbi_line_offset = 8; +} + +static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *dev, + const struct pci_device_id *pci_id) +{ + u16 cmd; + unsigned char pci_latency; + + CX18_DEBUG_INFO("Enabling pci device\n"); + + if (pci_enable_device(dev)) { + CX18_ERR("Can't enable device %d!\n", cx->num); + return -EIO; + } + if (pci_set_dma_mask(dev, 0xffffffff)) { + CX18_ERR("No suitable DMA available on card %d.\n", cx->num); + return -EIO; + } + if (!request_mem_region(cx->base_addr, CX18_MEM_SIZE, "cx18 encoder")) { + CX18_ERR("Cannot request encoder memory region on card %d.\n", cx->num); + return -EIO; + } + + /* Check for bus mastering */ + pci_read_config_word(dev, PCI_COMMAND, &cmd); + cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; + pci_write_config_word(dev, PCI_COMMAND, cmd); + + pci_read_config_byte(dev, PCI_CLASS_REVISION, &cx->card_rev); + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency); + + if (pci_latency < 64 && cx18_pci_latency) { + CX18_INFO("Unreasonably low latency timer, " + "setting to 64 (was %d)\n", pci_latency); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64); + pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency); + } + /* This config space value relates to DMA latencies. The + default value 0x8080 is too low however and will lead + to DMA errors. 0xffff is the max value which solves + these problems. */ + pci_write_config_dword(dev, 0x40, 0xffff); + + CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, " + "irq: %d, latency: %d, memory: 0x%lx\n", + cx->dev->device, cx->card_rev, dev->bus->number, + PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), + cx->dev->irq, pci_latency, (unsigned long)cx->base_addr); + + return 0; +} + +static u32 cx18_request_module(struct cx18 *cx, u32 hw, + const char *name, u32 id) +{ + if ((hw & id) == 0) + return hw; + if (request_module(name) != 0) { + CX18_ERR("Failed to load module %s\n", name); + return hw & ~id; + } + CX18_DEBUG_INFO("Loaded module %s\n", name); + return hw; +} + +static void cx18_load_and_init_modules(struct cx18 *cx) +{ + u32 hw = cx->card->hw_all; + int i; + + /* load modules */ +#ifndef CONFIG_MEDIA_TUNER + hw = cx18_request_module(cx, hw, "tuner", CX18_HW_TUNER); +#endif +#ifndef CONFIG_VIDEO_CS5345 + hw = cx18_request_module(cx, hw, "cs5345", CX18_HW_CS5345); +#endif + + /* check which i2c devices are actually found */ + for (i = 0; i < 32; i++) { + u32 device = 1 << i; + + if (!(device & hw)) + continue; + if (device == CX18_HW_GPIO || device == CX18_HW_TVEEPROM || + device == CX18_HW_CX23418 || device == CX18_HW_DVB) { + /* These 'devices' do not use i2c probing */ + cx->hw_flags |= device; + continue; + } + cx18_i2c_register(cx, i); + if (cx18_i2c_hw_addr(cx, device) > 0) + cx->hw_flags |= device; + } + + hw = cx->hw_flags; +} + +static int __devinit cx18_probe(struct pci_dev *dev, + const struct pci_device_id *pci_id) +{ + int retval = 0; + int vbi_buf_size; + u32 devtype; + struct cx18 *cx; + + spin_lock(&cx18_cards_lock); + + /* Make sure we've got a place for this card */ + if (cx18_cards_active == CX18_MAX_CARDS) { + printk(KERN_ERR "cx18: Maximum number of cards detected (%d).\n", + cx18_cards_active); + spin_unlock(&cx18_cards_lock); + return -ENOMEM; + } + + cx = kzalloc(sizeof(struct cx18), GFP_ATOMIC); + if (cx == 0) { + spin_unlock(&cx18_cards_lock); + return -ENOMEM; + } + cx18_cards[cx18_cards_active] = cx; + cx->dev = dev; + cx->num = cx18_cards_active++; + snprintf(cx->name, sizeof(cx->name) - 1, "cx18-%d", cx->num); + CX18_INFO("Initializing card #%d\n", cx->num); + + spin_unlock(&cx18_cards_lock); + + cx18_process_options(cx); + if (cx->options.cardtype == -1) { + retval = -ENODEV; + goto err; + } + if (cx18_init_struct1(cx)) { + retval = -ENOMEM; + goto err; + } + + CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr); + + /* PCI Device Setup */ + retval = cx18_setup_pci(cx, dev, pci_id); + if (retval != 0) { + if (retval == -EIO) + goto free_workqueue; + else if (retval == -ENXIO) + goto free_mem; + } + /* save cx in the pci struct for later use */ + pci_set_drvdata(dev, cx); + + /* map io memory */ + CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n", + cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE); + cx->enc_mem = ioremap_nocache(cx->base_addr + CX18_MEM_OFFSET, + CX18_MEM_SIZE); + if (!cx->enc_mem) { + CX18_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n"); + CX18_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n"); + retval = -ENOMEM; + goto free_mem; + } + cx->reg_mem = cx->enc_mem + CX18_REG_OFFSET; + devtype = read_reg(0xC72028); + switch (devtype & 0xff000000) { + case 0xff000000: + CX18_INFO("cx23418 revision %08x (A)\n", devtype); + break; + case 0x01000000: + CX18_INFO("cx23418 revision %08x (B)\n", devtype); + break; + default: + CX18_INFO("cx23418 revision %08x (Unknown)\n", devtype); + break; + } + + cx18_init_power(cx, 1); + cx18_init_memory(cx); + + cx->scb = (struct cx18_scb *)(cx->enc_mem + SCB_OFFSET); + cx18_init_scb(cx); + + cx18_gpio_init(cx); + + /* active i2c */ + CX18_DEBUG_INFO("activating i2c...\n"); + if (init_cx18_i2c(cx)) { + CX18_ERR("Could not initialize i2c\n"); + goto free_map; + } + + CX18_DEBUG_INFO("Active card count: %d.\n", cx18_cards_active); + + if (cx->card->hw_all & CX18_HW_TVEEPROM) { + /* Based on the model number the cardtype may be changed. + The PCI IDs are not always reliable. */ + cx18_process_eeprom(cx); + } + if (cx->card->comment) + CX18_INFO("%s", cx->card->comment); + if (cx->card->v4l2_capabilities == 0) { + retval = -ENODEV; + goto free_i2c; + } + cx18_init_memory(cx); + + /* Register IRQ */ + retval = request_irq(cx->dev->irq, cx18_irq_handler, + IRQF_SHARED | IRQF_DISABLED, cx->name, (void *)cx); + if (retval) { + CX18_ERR("Failed to register irq %d\n", retval); + goto free_i2c; + } + + if (cx->std == 0) + cx->std = V4L2_STD_NTSC_M; + + if (cx->options.tuner == -1) { + int i; + + for (i = 0; i < CX18_CARD_MAX_TUNERS; i++) { + if ((cx->std & cx->card->tuners[i].std) == 0) + continue; + cx->options.tuner = cx->card->tuners[i].tuner; + break; + } + } + /* if no tuner was found, then pick the first tuner in the card list */ + if (cx->options.tuner == -1 && cx->card->tuners[0].std) { + cx->std = cx->card->tuners[0].std; + cx->options.tuner = cx->card->tuners[0].tuner; + } + if (cx->options.radio == -1) + cx->options.radio = (cx->card->radio_input.audio_type != 0); + + /* The card is now fully identified, continue with card-specific + initialization. */ + cx18_init_struct2(cx); + + cx18_load_and_init_modules(cx); + + if (cx->std & V4L2_STD_525_60) { + cx->is_60hz = 1; + cx->is_out_60hz = 1; + } else { + cx->is_50hz = 1; + cx->is_out_50hz = 1; + } + cx->params.video_gop_size = cx->is_60hz ? 15 : 12; + + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = 0x08000; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = 0x08000; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = 0x01200; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = 0x20000; + vbi_buf_size = cx->vbi.raw_size * (cx->is_60hz ? 24 : 36) / 2; + cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_buf_size; + + if (cx->options.radio > 0) + cx->v4l2_cap |= V4L2_CAP_RADIO; + + retval = cx18_streams_setup(cx); + if (retval) { + CX18_ERR("Error %d setting up streams\n", retval); + goto free_irq; + } + retval = cx18_streams_register(cx); + if (retval) { + CX18_ERR("Error %d registering devices\n", retval); + goto free_streams; + } + + if (cx->options.tuner > -1) { + struct tuner_setup setup; + + setup.addr = ADDR_UNSET; + setup.type = cx->options.tuner; + setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ + setup.tuner_callback = (setup.type == TUNER_XC2028) ? + cx18_reset_tuner_gpio : NULL; + cx18_call_i2c_clients(cx, TUNER_SET_TYPE_ADDR, &setup); + if (setup.type == TUNER_XC2028) { + static struct xc2028_ctrl ctrl = { + .fname = XC2028_DEFAULT_FIRMWARE, + .max_len = 64, + }; + struct v4l2_priv_tun_config cfg = { + .tuner = cx->options.tuner, + .priv = &ctrl, + }; + cx18_call_i2c_clients(cx, TUNER_SET_CONFIG, &cfg); + } + } + + /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) + are not. */ + cx->tuner_std = cx->std; + + cx18_init_on_first_open(cx); + + CX18_INFO("Initialized card #%d: %s\n", cx->num, cx->card_name); + + return 0; + +free_streams: + cx18_streams_cleanup(cx); +free_irq: + free_irq(cx->dev->irq, (void *)cx); +free_i2c: + exit_cx18_i2c(cx); +free_map: + cx18_iounmap(cx); +free_mem: + release_mem_region(cx->base_addr, CX18_MEM_SIZE); +free_workqueue: +err: + if (retval == 0) + retval = -ENODEV; + CX18_ERR("Error %d on initialization\n", retval); + + kfree(cx18_cards[cx18_cards_active]); + cx18_cards[cx18_cards_active] = NULL; + return retval; +} + +int cx18_init_on_first_open(struct cx18 *cx) +{ + int video_input; + int fw_retry_count = 3; + struct v4l2_frequency vf; + + if (test_bit(CX18_F_I_FAILED, &cx->i_flags)) + return -ENXIO; + + if (test_and_set_bit(CX18_F_I_INITED, &cx->i_flags)) + return 0; + + while (--fw_retry_count > 0) { + /* load firmware */ + if (cx18_firmware_init(cx) == 0) + break; + if (fw_retry_count > 1) + CX18_WARN("Retry loading firmware\n"); + } + + if (fw_retry_count == 0) { + set_bit(CX18_F_I_FAILED, &cx->i_flags); + return -ENXIO; + } + set_bit(CX18_F_I_LOADED_FW, &cx->i_flags); + + /* Init the firmware twice to work around a silicon bug + * transport related. */ + + fw_retry_count = 3; + while (--fw_retry_count > 0) { + /* load firmware */ + if (cx18_firmware_init(cx) == 0) + break; + if (fw_retry_count > 1) + CX18_WARN("Retry loading firmware\n"); + } + + if (fw_retry_count == 0) { + set_bit(CX18_F_I_FAILED, &cx->i_flags); + return -ENXIO; + } + + vf.tuner = 0; + vf.type = V4L2_TUNER_ANALOG_TV; + vf.frequency = 6400; /* the tuner 'baseline' frequency */ + + /* Set initial frequency. For PAL/SECAM broadcasts no + 'default' channel exists AFAIK. */ + if (cx->std == V4L2_STD_NTSC_M_JP) + vf.frequency = 1460; /* ch. 1 91250*16/1000 */ + else if (cx->std & V4L2_STD_NTSC_M) + vf.frequency = 1076; /* ch. 4 67250*16/1000 */ + + video_input = cx->active_input; + cx->active_input++; /* Force update of input */ + cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_INPUT, &video_input); + + /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code + in one place. */ + cx->std++; /* Force full standard initialization */ + cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_STD, &cx->tuner_std); + cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_FREQUENCY, &vf); + return 0; +} + +static void cx18_remove(struct pci_dev *pci_dev) +{ + struct cx18 *cx = pci_get_drvdata(pci_dev); + + CX18_DEBUG_INFO("Removing Card #%d\n", cx->num); + + /* Stop all captures */ + CX18_DEBUG_INFO("Stopping all streams\n"); + if (atomic_read(&cx->capturing) > 0) + cx18_stop_all_captures(cx); + + /* Interrupts */ + sw1_irq_disable(IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU); + sw2_irq_disable(IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); + + cx18_halt_firmware(cx); + + cx18_streams_cleanup(cx); + + exit_cx18_i2c(cx); + + free_irq(cx->dev->irq, (void *)cx); + + if (cx->dev) + cx18_iounmap(cx); + + release_mem_region(cx->base_addr, CX18_MEM_SIZE); + + pci_disable_device(cx->dev); + + CX18_INFO("Removed %s, card #%d\n", cx->card_name, cx->num); +} + +/* define a pci_driver for card detection */ +static struct pci_driver cx18_pci_driver = { + .name = "cx18", + .id_table = cx18_pci_tbl, + .probe = cx18_probe, + .remove = cx18_remove, +}; + +static int module_start(void) +{ + printk(KERN_INFO "cx18: Start initialization, version %s\n", CX18_VERSION); + + memset(cx18_cards, 0, sizeof(cx18_cards)); + + /* Validate parameters */ + if (cx18_first_minor < 0 || cx18_first_minor >= CX18_MAX_CARDS) { + printk(KERN_ERR "cx18: Exiting, ivtv_first_minor must be between 0 and %d\n", + CX18_MAX_CARDS - 1); + return -1; + } + + if (cx18_debug < 0 || cx18_debug > 511) { + cx18_debug = 0; + printk(KERN_INFO "cx18: Debug value must be >= 0 and <= 511!\n"); + } + + if (pci_register_driver(&cx18_pci_driver)) { + printk(KERN_ERR "cx18: Error detecting PCI card\n"); + return -ENODEV; + } + printk(KERN_INFO "cx18: End initialization\n"); + return 0; +} + +static void module_cleanup(void) +{ + int i; + + pci_unregister_driver(&cx18_pci_driver); + + for (i = 0; i < cx18_cards_active; i++) { + if (cx18_cards[i] == NULL) + continue; + kfree(cx18_cards[i]); + } +} + +module_init(module_start); +module_exit(module_cleanup); diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h new file mode 100644 index 000000000000..2ee939193bb7 --- /dev/null +++ b/drivers/media/video/cx18/cx18-driver.h @@ -0,0 +1,500 @@ +/* + * cx18 driver internal defines and structures + * + * Derived from ivtv-driver.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 CX18_DRIVER_H +#define CX18_DRIVER_H + +#include <linux/version.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/spinlock.h> +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> +#include <linux/list.h> +#include <linux/unistd.h> +#include <linux/byteorder/swab.h> +#include <linux/pagemap.h> +#include <linux/workqueue.h> +#include <linux/mutex.h> + +#include <linux/dvb/video.h> +#include <linux/dvb/audio.h> +#include <media/v4l2-common.h> +#include <media/tuner.h> +#include "cx18-mailbox.h" +#include "cx18-av-core.h" +#include "cx23418.h" + +/* DVB */ +#include "demux.h" +#include "dmxdev.h" +#include "dvb_demux.h" +#include "dvb_frontend.h" +#include "dvb_net.h" +#include "dvbdev.h" + +#ifndef CONFIG_PCI +# error "This driver requires kernel PCI support." +#endif + +#define CX18_MEM_OFFSET 0x00000000 +#define CX18_MEM_SIZE 0x04000000 +#define CX18_REG_OFFSET 0x02000000 + +/* Maximum cx18 driver instances. */ +#define CX18_MAX_CARDS 32 + +/* Supported cards */ +#define CX18_CARD_HVR_1600_ESMT 0 /* Hauppauge HVR 1600 (ESMT memory) */ +#define CX18_CARD_HVR_1600_SAMSUNG 1 /* Hauppauge HVR 1600 (Samsung memory) */ +#define CX18_CARD_COMPRO_H900 2 /* Compro VideoMate H900 */ +#define CX18_CARD_YUAN_MPC718 3 /* Yuan MPC718 */ +#define CX18_CARD_LAST 3 + +#define CX18_ENC_STREAM_TYPE_MPG 0 +#define CX18_ENC_STREAM_TYPE_TS 1 +#define CX18_ENC_STREAM_TYPE_YUV 2 +#define CX18_ENC_STREAM_TYPE_VBI 3 +#define CX18_ENC_STREAM_TYPE_PCM 4 +#define CX18_ENC_STREAM_TYPE_IDX 5 +#define CX18_ENC_STREAM_TYPE_RAD 6 +#define CX18_MAX_STREAMS 7 + +/* system vendor and device IDs */ +#define PCI_VENDOR_ID_CX 0x14f1 +#define PCI_DEVICE_ID_CX23418 0x5b7a + +/* subsystem vendor ID */ +#define CX18_PCI_ID_HAUPPAUGE 0x0070 +#define CX18_PCI_ID_COMPRO 0x185b +#define CX18_PCI_ID_YUAN 0x12ab + +/* ======================================================================== */ +/* ========================== START USER SETTABLE DMA VARIABLES =========== */ +/* ======================================================================== */ + +/* DMA Buffers, Default size in MB allocated */ +#define CX18_DEFAULT_ENC_TS_BUFFERS 1 +#define CX18_DEFAULT_ENC_MPG_BUFFERS 2 +#define CX18_DEFAULT_ENC_IDX_BUFFERS 1 +#define CX18_DEFAULT_ENC_YUV_BUFFERS 2 +#define CX18_DEFAULT_ENC_VBI_BUFFERS 1 +#define CX18_DEFAULT_ENC_PCM_BUFFERS 1 + +/* i2c stuff */ +#define I2C_CLIENTS_MAX 16 + +/* debugging */ + +/* Flag to turn on high volume debugging */ +#define CX18_DBGFLG_WARN (1 << 0) +#define CX18_DBGFLG_INFO (1 << 1) +#define CX18_DBGFLG_API (1 << 2) +#define CX18_DBGFLG_DMA (1 << 3) +#define CX18_DBGFLG_IOCTL (1 << 4) +#define CX18_DBGFLG_FILE (1 << 5) +#define CX18_DBGFLG_I2C (1 << 6) +#define CX18_DBGFLG_IRQ (1 << 7) +/* Flag to turn on high volume debugging */ +#define CX18_DBGFLG_HIGHVOL (1 << 8) + +/* NOTE: extra space before comma in 'cx->num , ## args' is required for + gcc-2.95, otherwise it won't compile. */ +#define CX18_DEBUG(x, type, fmt, args...) \ + do { \ + if ((x) & cx18_debug) \ + printk(KERN_INFO "cx18-%d " type ": " fmt, cx->num , ## args); \ + } while (0) +#define CX18_DEBUG_WARN(fmt, args...) CX18_DEBUG(CX18_DBGFLG_WARN, "warning", fmt , ## args) +#define CX18_DEBUG_INFO(fmt, args...) CX18_DEBUG(CX18_DBGFLG_INFO, "info", fmt , ## args) +#define CX18_DEBUG_API(fmt, args...) CX18_DEBUG(CX18_DBGFLG_API, "api", fmt , ## args) +#define CX18_DEBUG_DMA(fmt, args...) CX18_DEBUG(CX18_DBGFLG_DMA, "dma", fmt , ## args) +#define CX18_DEBUG_IOCTL(fmt, args...) CX18_DEBUG(CX18_DBGFLG_IOCTL, "ioctl", fmt , ## args) +#define CX18_DEBUG_FILE(fmt, args...) CX18_DEBUG(CX18_DBGFLG_FILE, "file", fmt , ## args) +#define CX18_DEBUG_I2C(fmt, args...) CX18_DEBUG(CX18_DBGFLG_I2C, "i2c", fmt , ## args) +#define CX18_DEBUG_IRQ(fmt, args...) CX18_DEBUG(CX18_DBGFLG_IRQ, "irq", fmt , ## args) + +#define CX18_DEBUG_HIGH_VOL(x, type, fmt, args...) \ + do { \ + if (((x) & cx18_debug) && (cx18_debug & CX18_DBGFLG_HIGHVOL)) \ + printk(KERN_INFO "cx18%d " type ": " fmt, cx->num , ## args); \ + } while (0) +#define CX18_DEBUG_HI_WARN(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_WARN, "warning", fmt , ## args) +#define CX18_DEBUG_HI_INFO(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_INFO, "info", fmt , ## args) +#define CX18_DEBUG_HI_API(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_API, "api", fmt , ## args) +#define CX18_DEBUG_HI_DMA(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_DMA, "dma", fmt , ## args) +#define CX18_DEBUG_HI_IOCTL(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_IOCTL, "ioctl", fmt , ## args) +#define CX18_DEBUG_HI_FILE(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_FILE, "file", fmt , ## args) +#define CX18_DEBUG_HI_I2C(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_I2C, "i2c", fmt , ## args) +#define CX18_DEBUG_HI_IRQ(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_IRQ, "irq", fmt , ## args) + +/* Standard kernel messages */ +#define CX18_ERR(fmt, args...) printk(KERN_ERR "cx18-%d: " fmt, cx->num , ## args) +#define CX18_WARN(fmt, args...) printk(KERN_WARNING "cx18-%d: " fmt, cx->num , ## args) +#define CX18_INFO(fmt, args...) printk(KERN_INFO "cx18-%d: " fmt, cx->num , ## args) + +/* Values for CX18_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */ +#define MPEG_FRAME_TYPE_IFRAME 1 +#define MPEG_FRAME_TYPE_IFRAME_PFRAME 3 +#define MPEG_FRAME_TYPE_ALL 7 + +#define CX18_MAX_PGM_INDEX (400) + +extern int cx18_debug; + + +struct cx18_options { + int megabytes[CX18_MAX_STREAMS]; /* Size in megabytes of each stream */ + int cardtype; /* force card type on load */ + int tuner; /* set tuner on load */ + int radio; /* enable/disable radio */ +}; + +/* per-buffer bit flags */ +#define CX18_F_B_NEED_BUF_SWAP 0 /* this buffer should be byte swapped */ + +/* per-stream, s_flags */ +#define CX18_F_S_CLAIMED 3 /* this stream is claimed */ +#define CX18_F_S_STREAMING 4 /* the fw is decoding/encoding this stream */ +#define CX18_F_S_INTERNAL_USE 5 /* this stream is used internally (sliced VBI processing) */ +#define CX18_F_S_STREAMOFF 7 /* signal end of stream EOS */ +#define CX18_F_S_APPL_IO 8 /* this stream is used read/written by an application */ + +/* per-cx18, i_flags */ +#define CX18_F_I_LOADED_FW 0 /* Loaded the firmware the first time */ +#define CX18_F_I_EOS 4 /* End of encoder stream reached */ +#define CX18_F_I_RADIO_USER 5 /* The radio tuner is selected */ +#define CX18_F_I_ENC_PAUSED 13 /* the encoder is paused */ +#define CX18_F_I_INITED 21 /* set after first open */ +#define CX18_F_I_FAILED 22 /* set if first open failed */ + +/* These are the VBI types as they appear in the embedded VBI private packets. */ +#define CX18_SLICED_TYPE_TELETEXT_B (1) +#define CX18_SLICED_TYPE_CAPTION_525 (4) +#define CX18_SLICED_TYPE_WSS_625 (5) +#define CX18_SLICED_TYPE_VPS (7) + +struct cx18_buffer { + struct list_head list; + dma_addr_t dma_handle; + u32 id; + unsigned long b_flags; + char *buf; + + u32 bytesused; + u32 readpos; +}; + +struct cx18_queue { + struct list_head list; + u32 buffers; + u32 length; + u32 bytesused; +}; + +struct cx18_dvb { + struct dmx_frontend hw_frontend; + struct dmx_frontend mem_frontend; + struct dmxdev dmxdev; + struct dvb_adapter dvb_adapter; + struct dvb_demux demux; + struct dvb_frontend *fe; + struct dvb_net dvbnet; + int enabled; + int feeding; + + struct mutex feedlock; + +}; + +struct cx18; /* forward reference */ +struct cx18_scb; /* forward reference */ + +struct cx18_stream { + /* These first four fields are always set, even if the stream + is not actually created. */ + struct video_device *v4l2dev; /* NULL when stream not created */ + struct cx18 *cx; /* for ease of use */ + const char *name; /* name of the stream */ + int type; /* stream type */ + u32 handle; /* task handle */ + unsigned mdl_offset; + + u32 id; + spinlock_t qlock; /* locks access to the queues */ + unsigned long s_flags; /* status flags, see above */ + int dma; /* can be PCI_DMA_TODEVICE, + PCI_DMA_FROMDEVICE or + PCI_DMA_NONE */ + u64 dma_pts; + wait_queue_head_t waitq; + + /* Buffer Stats */ + u32 buffers; + u32 buf_size; + u32 buffers_stolen; + + /* Buffer Queues */ + struct cx18_queue q_free; /* free buffers */ + struct cx18_queue q_full; /* full buffers */ + struct cx18_queue q_io; /* waiting for I/O */ + + /* DVB / Digital Transport */ + struct cx18_dvb dvb; +}; + +struct cx18_open_id { + u32 open_id; + int type; + enum v4l2_priority prio; + struct cx18 *cx; +}; + +/* forward declaration of struct defined in cx18-cards.h */ +struct cx18_card; + + +#define CX18_VBI_FRAMES 32 + +/* VBI data */ +struct vbi_info { + u32 enc_size; + u32 frame; + u8 cc_data_odd[256]; + u8 cc_data_even[256]; + int cc_pos; + u8 cc_no_update; + u8 vps[5]; + u8 vps_found; + int wss; + u8 wss_found; + u8 wss_no_update; + u32 raw_decoder_line_size; + u8 raw_decoder_sav_odd_field; + u8 raw_decoder_sav_even_field; + u32 sliced_decoder_line_size; + u8 sliced_decoder_sav_odd_field; + u8 sliced_decoder_sav_even_field; + struct v4l2_format in; + /* convenience pointer to sliced struct in vbi_in union */ + struct v4l2_sliced_vbi_format *sliced_in; + u32 service_set_in; + int insert_mpeg; + + /* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines. + One for /dev/vbi0 and one for /dev/vbi8 */ + struct v4l2_sliced_vbi_data sliced_data[36]; + + /* Buffer for VBI data inserted into MPEG stream. + The first byte is a dummy byte that's never used. + The next 16 bytes contain the MPEG header for the VBI data, + the remainder is the actual VBI data. + The max size accepted by the MPEG VBI reinsertion turns out + to be 1552 bytes, which happens to be 4 + (1 + 42) * (2 * 18) bytes, + where 4 is a four byte header, 42 is the max sliced VBI payload, 1 is + a single line header byte and 2 * 18 is the number of VBI lines per frame. + + However, it seems that the data must be 1K aligned, so we have to + pad the data until the 1 or 2 K boundary. + + This pointer array will allocate 2049 bytes to store each VBI frame. */ + u8 *sliced_mpeg_data[CX18_VBI_FRAMES]; + u32 sliced_mpeg_size[CX18_VBI_FRAMES]; + struct cx18_buffer sliced_mpeg_buf; + u32 inserted_frame; + + u32 start[2], count; + u32 raw_size; + u32 sliced_size; +}; + +/* Per cx23418, per I2C bus private algo callback data */ +struct cx18_i2c_algo_callback_data { + struct cx18 *cx; + int bus_index; /* 0 or 1 for the cx23418's 1st or 2nd I2C bus */ +}; + +/* Struct to hold info about cx18 cards */ +struct cx18 { + int num; /* board number, -1 during init! */ + char name[8]; /* board name for printk and interrupts (e.g. 'cx180') */ + struct pci_dev *dev; /* PCI device */ + const struct cx18_card *card; /* card information */ + const char *card_name; /* full name of the card */ + const struct cx18_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */ + u8 is_50hz; + u8 is_60hz; + u8 is_out_50hz; + u8 is_out_60hz; + u8 nof_inputs; /* number of video inputs */ + u8 nof_audio_inputs; /* number of audio inputs */ + u16 buffer_id; /* buffer ID counter */ + u32 v4l2_cap; /* V4L2 capabilities of card */ + u32 hw_flags; /* Hardware description of the board */ + unsigned mdl_offset; + struct cx18_scb *scb; /* pointer to SCB */ + + struct cx18_av_state av_state; + + /* codec settings */ + struct cx2341x_mpeg_params params; + u32 filter_mode; + u32 temporal_strength; + u32 spatial_strength; + + /* dualwatch */ + unsigned long dualwatch_jiffies; + u16 dualwatch_stereo_mode; + + /* Digitizer type */ + int digitizer; /* 0x00EF = saa7114 0x00FO = saa7115 0x0106 = mic */ + + struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */ + struct cx18_options options; /* User options */ + int stream_buf_size[CX18_MAX_STREAMS]; /* Stream buffer size */ + struct cx18_stream streams[CX18_MAX_STREAMS]; /* Stream data */ + unsigned long i_flags; /* global cx18 flags */ + atomic_t capturing; /* count number of active capture streams */ + spinlock_t lock; /* lock access to this struct */ + int search_pack_header; + + spinlock_t dma_reg_lock; /* lock access to DMA engine registers */ + + int open_id; /* incremented each time an open occurs, used as + unique ID. Starts at 1, so 0 can be used as + uninitialized value in the stream->id. */ + + u32 base_addr; + struct v4l2_prio_state prio; + + u8 card_rev; + void __iomem *enc_mem, *reg_mem; + + struct vbi_info vbi; + + u32 pgm_info_offset; + u32 pgm_info_num; + u32 pgm_info_write_idx; + u32 pgm_info_read_idx; + struct v4l2_enc_idx_entry pgm_info[CX18_MAX_PGM_INDEX]; + + u64 mpg_data_received; + u64 vbi_data_inserted; + + wait_queue_head_t mb_apu_waitq; + wait_queue_head_t mb_cpu_waitq; + wait_queue_head_t mb_epu_waitq; + wait_queue_head_t mb_hpu_waitq; + wait_queue_head_t cap_w; + /* when the current DMA is finished this queue is woken up */ + wait_queue_head_t dma_waitq; + + /* i2c */ + struct i2c_adapter i2c_adap[2]; + struct i2c_algo_bit_data i2c_algo[2]; + struct cx18_i2c_algo_callback_data i2c_algo_cb_data[2]; + struct i2c_client i2c_client[2]; + struct mutex i2c_bus_lock[2]; + struct i2c_client *i2c_clients[I2C_CLIENTS_MAX]; + + /* v4l2 and User settings */ + + /* codec settings */ + u32 audio_input; + u32 active_input; + u32 active_output; + v4l2_std_id std; + v4l2_std_id tuner_std; /* The norm of the tuner (fixed) */ +}; + +/* Globals */ +extern struct cx18 *cx18_cards[]; +extern int cx18_cards_active; +extern int cx18_first_minor; +extern spinlock_t cx18_cards_lock; + +/*==============Prototypes==================*/ + +/* Return non-zero if a signal is pending */ +int cx18_msleep_timeout(unsigned int msecs, int intr); + +/* Wait on queue, returns -EINTR if interrupted */ +int cx18_waitq(wait_queue_head_t *waitq); + +/* Read Hauppauge eeprom */ +struct tveeprom; /* forward reference */ +void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv); + +/* First-open initialization: load firmware, etc. */ +int cx18_init_on_first_open(struct cx18 *cx); + +/* This is a PCI post thing, where if the pci register is not read, then + the write doesn't always take effect right away. By reading back the + register any pending PCI writes will be performed (in order), and so + you can be sure that the writes are guaranteed to be done. + + Rarely needed, only in some timing sensitive cases. + Apparently if this is not done some motherboards seem + to kill the firmware and get into the broken state until computer is + rebooted. */ +#define write_sync(val, reg) \ + do { writel(val, reg); readl(reg); } while (0) + +#define read_reg(reg) readl(cx->reg_mem + (reg)) +#define write_reg(val, reg) writel(val, cx->reg_mem + (reg)) +#define write_reg_sync(val, reg) \ + do { write_reg(val, reg); read_reg(reg); } while (0) + +#define read_enc(addr) readl(cx->enc_mem + (u32)(addr)) +#define write_enc(val, addr) writel(val, cx->enc_mem + (u32)(addr)) +#define write_enc_sync(val, addr) \ + do { write_enc(val, addr); read_enc(addr); } while (0) + +#define sw1_irq_enable(val) do { \ + write_reg(val, SW1_INT_STATUS); \ + write_reg(read_reg(SW1_INT_ENABLE_PCI) | (val), SW1_INT_ENABLE_PCI); \ +} while (0) + +#define sw1_irq_disable(val) \ + write_reg(read_reg(SW1_INT_ENABLE_PCI) & ~(val), SW1_INT_ENABLE_PCI); + +#define sw2_irq_enable(val) do { \ + write_reg(val, SW2_INT_STATUS); \ + write_reg(read_reg(SW2_INT_ENABLE_PCI) | (val), SW2_INT_ENABLE_PCI); \ +} while (0) + +#define sw2_irq_disable(val) \ + write_reg(read_reg(SW2_INT_ENABLE_PCI) & ~(val), SW2_INT_ENABLE_PCI); + +#define setup_page(addr) do { \ + u32 val = read_reg(0xD000F8) & ~0x1f00; \ + write_reg(val | (((addr) >> 17) & 0x1f00), 0xD000F8); \ +} while (0) + +#endif /* CX18_DRIVER_H */ diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c new file mode 100644 index 000000000000..65efe69d939a --- /dev/null +++ b/drivers/media/video/cx18/cx18-dvb.c @@ -0,0 +1,288 @@ +/* + * cx18 functions for DVB support + * + * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "cx18-version.h" +#include "cx18-dvb.h" +#include "cx18-streams.h" +#include "cx18-cards.h" +#include "s5h1409.h" + +/* Wait until the MXL500X driver is merged */ +#ifdef HAVE_MXL500X +#include "mxl500x.h" +#endif + +DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + +#define CX18_REG_DMUX_NUM_PORT_0_CONTROL 0xd5a000 + +#ifdef HAVE_MXL500X +static struct mxl500x_config hauppauge_hvr1600_tuner = { + .delsys = MXL500x_MODE_ATSC, + .octf = MXL500x_OCTF_CH, + .xtal_freq = 16000000, + .iflo_freq = 5380000, + .ref_freq = 322800000, + .rssi_ena = MXL_RSSI_ENABLE, + .addr = 0xC6 >> 1, +}; + +static struct s5h1409_config hauppauge_hvr1600_config = { + .demod_address = 0x32 >> 1, + .output_mode = S5H1409_SERIAL_OUTPUT, + .gpio = S5H1409_GPIO_ON, + .qam_if = 44000, + .inversion = S5H1409_INVERSION_OFF, + .status_mode = S5H1409_DEMODLOCKING, + .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK + +}; +#endif + +static int dvb_register(struct cx18_stream *stream); + +/* Kernel DVB framework calls this when the feed needs to start. + * The CX18 framework should enable the transport DMA handling + * and queue processing. + */ +static int cx18_dvb_start_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct cx18_stream *stream = (struct cx18_stream *) demux->priv; + struct cx18 *cx = stream->cx; + int ret = -EINVAL; + u32 v; + + CX18_DEBUG_INFO("Start feed: pid = 0x%x index = %d\n", + feed->pid, feed->index); + switch (cx->card->type) { + case CX18_CARD_HVR_1600_ESMT: + case CX18_CARD_HVR_1600_SAMSUNG: + v = read_reg(CX18_REG_DMUX_NUM_PORT_0_CONTROL); + v |= 0x00400000; /* Serial Mode */ + v |= 0x00002000; /* Data Length - Byte */ + v |= 0x00010000; /* Error - Polarity */ + v |= 0x00020000; /* Error - Passthru */ + v |= 0x000c0000; /* Error - Ignore */ + write_reg(v, CX18_REG_DMUX_NUM_PORT_0_CONTROL); + break; + + default: + /* Assumption - Parallel transport - Signalling + * undefined or default. + */ + break; + } + + if (!demux->dmx.frontend) + return -EINVAL; + + if (stream) { + mutex_lock(&stream->dvb.feedlock); + if (stream->dvb.feeding++ == 0) { + CX18_DEBUG_INFO("Starting Transport DMA\n"); + ret = cx18_start_v4l2_encode_stream(stream); + } else + ret = 0; + mutex_unlock(&stream->dvb.feedlock); + } + + return ret; +} + +/* Kernel DVB framework calls this when the feed needs to stop. */ +static int cx18_dvb_stop_feed(struct dvb_demux_feed *feed) +{ + struct dvb_demux *demux = feed->demux; + struct cx18_stream *stream = (struct cx18_stream *)demux->priv; + struct cx18 *cx = stream->cx; + int ret = -EINVAL; + + CX18_DEBUG_INFO("Stop feed: pid = 0x%x index = %d\n", + feed->pid, feed->index); + + if (stream) { + mutex_lock(&stream->dvb.feedlock); + if (--stream->dvb.feeding == 0) { + CX18_DEBUG_INFO("Stopping Transport DMA\n"); + ret = cx18_stop_v4l2_encode_stream(stream, 0); + } else + ret = 0; + mutex_unlock(&stream->dvb.feedlock); + } + + return ret; +} + +int cx18_dvb_register(struct cx18_stream *stream) +{ + struct cx18 *cx = stream->cx; + struct cx18_dvb *dvb = &stream->dvb; + struct dvb_adapter *dvb_adapter; + struct dvb_demux *dvbdemux; + struct dmx_demux *dmx; + int ret; + + if (!dvb) + return -EINVAL; + + ret = dvb_register_adapter(&dvb->dvb_adapter, + CX18_DRIVER_NAME, + THIS_MODULE, &cx->dev->dev, adapter_nr); + if (ret < 0) + goto err_out; + + dvb_adapter = &dvb->dvb_adapter; + + dvbdemux = &dvb->demux; + + dvbdemux->priv = (void *)stream; + + dvbdemux->filternum = 256; + dvbdemux->feednum = 256; + dvbdemux->start_feed = cx18_dvb_start_feed; + dvbdemux->stop_feed = cx18_dvb_stop_feed; + dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | + DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); + ret = dvb_dmx_init(dvbdemux); + if (ret < 0) + goto err_dvb_unregister_adapter; + + dmx = &dvbdemux->dmx; + + dvb->hw_frontend.source = DMX_FRONTEND_0; + dvb->mem_frontend.source = DMX_MEMORY_FE; + dvb->dmxdev.filternum = 256; + dvb->dmxdev.demux = dmx; + + ret = dvb_dmxdev_init(&dvb->dmxdev, dvb_adapter); + if (ret < 0) + goto err_dvb_dmx_release; + + ret = dmx->add_frontend(dmx, &dvb->hw_frontend); + if (ret < 0) + goto err_dvb_dmxdev_release; + + ret = dmx->add_frontend(dmx, &dvb->mem_frontend); + if (ret < 0) + goto err_remove_hw_frontend; + + ret = dmx->connect_frontend(dmx, &dvb->hw_frontend); + if (ret < 0) + goto err_remove_mem_frontend; + + ret = dvb_register(stream); + if (ret < 0) + goto err_disconnect_frontend; + + dvb_net_init(dvb_adapter, &dvb->dvbnet, dmx); + + CX18_INFO("DVB Frontend registered\n"); + mutex_init(&dvb->feedlock); + dvb->enabled = 1; + return ret; + +err_disconnect_frontend: + dmx->disconnect_frontend(dmx); +err_remove_mem_frontend: + dmx->remove_frontend(dmx, &dvb->mem_frontend); +err_remove_hw_frontend: + dmx->remove_frontend(dmx, &dvb->hw_frontend); +err_dvb_dmxdev_release: + dvb_dmxdev_release(&dvb->dmxdev); +err_dvb_dmx_release: + dvb_dmx_release(dvbdemux); +err_dvb_unregister_adapter: + dvb_unregister_adapter(dvb_adapter); +err_out: + return ret; +} + +void cx18_dvb_unregister(struct cx18_stream *stream) +{ + struct cx18 *cx = stream->cx; + struct cx18_dvb *dvb = &stream->dvb; + struct dvb_adapter *dvb_adapter; + struct dvb_demux *dvbdemux; + struct dmx_demux *dmx; + + CX18_INFO("unregister DVB\n"); + + dvb_adapter = &dvb->dvb_adapter; + dvbdemux = &dvb->demux; + dmx = &dvbdemux->dmx; + + dmx->close(dmx); + dvb_net_release(&dvb->dvbnet); + dmx->remove_frontend(dmx, &dvb->mem_frontend); + dmx->remove_frontend(dmx, &dvb->hw_frontend); + dvb_dmxdev_release(&dvb->dmxdev); + dvb_dmx_release(dvbdemux); + dvb_unregister_frontend(dvb->fe); + dvb_frontend_detach(dvb->fe); + dvb_unregister_adapter(dvb_adapter); +} + +/* All the DVB attach calls go here, this function get's modified + * for each new card. No other function in this file needs + * to change. + */ +static int dvb_register(struct cx18_stream *stream) +{ + struct cx18_dvb *dvb = &stream->dvb; + struct cx18 *cx = stream->cx; + int ret = 0; + + switch (cx->card->type) { +/* Wait until the MXL500X driver is merged */ +#ifdef HAVE_MXL500X + case CX18_CARD_HVR_1600_ESMT: + case CX18_CARD_HVR_1600_SAMSUNG: + dvb->fe = dvb_attach(s5h1409_attach, + &hauppauge_hvr1600_config, + &cx->i2c_adap[0]); + if (dvb->fe != NULL) { + dvb_attach(mxl500x_attach, dvb->fe, + &hauppauge_hvr1600_tuner, + &cx->i2c_adap[0]); + ret = 0; + } + break; +#endif + default: + /* No Digital Tv Support */ + break; + } + + if (dvb->fe == NULL) { + CX18_ERR("frontend initialization failed\n"); + return -1; + } + + ret = dvb_register_frontend(&dvb->dvb_adapter, dvb->fe); + if (ret < 0) { + if (dvb->fe->ops.release) + dvb->fe->ops.release(dvb->fe); + return ret; + } + + return ret; +} diff --git a/drivers/media/video/cx18/cx18-dvb.h b/drivers/media/video/cx18/cx18-dvb.h new file mode 100644 index 000000000000..d6a6ccda79a9 --- /dev/null +++ b/drivers/media/video/cx18/cx18-dvb.h @@ -0,0 +1,25 @@ +/* + * cx18 functions for DVB support + * + * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include "cx18-driver.h" + +int cx18_dvb_register(struct cx18_stream *stream); +void cx18_dvb_unregister(struct cx18_stream *stream); diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c new file mode 100644 index 000000000000..69303065a294 --- /dev/null +++ b/drivers/media/video/cx18/cx18-fileops.c @@ -0,0 +1,711 @@ +/* + * cx18 file operation functions + * + * Derived from ivtv-fileops.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-fileops.h" +#include "cx18-i2c.h" +#include "cx18-queue.h" +#include "cx18-vbi.h" +#include "cx18-audio.h" +#include "cx18-mailbox.h" +#include "cx18-scb.h" +#include "cx18-streams.h" +#include "cx18-controls.h" +#include "cx18-ioctl.h" +#include "cx18-cards.h" + +/* This function tries to claim the stream for a specific file descriptor. + If no one else is using this stream then the stream is claimed and + associated VBI streams are also automatically claimed. + Possible error returns: -EBUSY if someone else has claimed + the stream or 0 on success. */ +int cx18_claim_stream(struct cx18_open_id *id, int type) +{ + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[type]; + struct cx18_stream *s_vbi; + int vbi_type; + + if (test_and_set_bit(CX18_F_S_CLAIMED, &s->s_flags)) { + /* someone already claimed this stream */ + if (s->id == id->open_id) { + /* yes, this file descriptor did. So that's OK. */ + return 0; + } + if (s->id == -1 && type == CX18_ENC_STREAM_TYPE_VBI) { + /* VBI is handled already internally, now also assign + the file descriptor to this stream for external + reading of the stream. */ + s->id = id->open_id; + CX18_DEBUG_INFO("Start Read VBI\n"); + return 0; + } + /* someone else is using this stream already */ + CX18_DEBUG_INFO("Stream %d is busy\n", type); + return -EBUSY; + } + s->id = id->open_id; + + /* CX18_DEC_STREAM_TYPE_MPG needs to claim CX18_DEC_STREAM_TYPE_VBI, + CX18_ENC_STREAM_TYPE_MPG needs to claim CX18_ENC_STREAM_TYPE_VBI + (provided VBI insertion is on and sliced VBI is selected), for all + other streams we're done */ + if (type == CX18_ENC_STREAM_TYPE_MPG && + cx->vbi.insert_mpeg && cx->vbi.sliced_in->service_set) { + vbi_type = CX18_ENC_STREAM_TYPE_VBI; + } else { + return 0; + } + s_vbi = &cx->streams[vbi_type]; + + set_bit(CX18_F_S_CLAIMED, &s_vbi->s_flags); + + /* mark that it is used internally */ + set_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags); + return 0; +} + +/* This function releases a previously claimed stream. It will take into + account associated VBI streams. */ +void cx18_release_stream(struct cx18_stream *s) +{ + struct cx18 *cx = s->cx; + struct cx18_stream *s_vbi; + + s->id = -1; + if (s->type == CX18_ENC_STREAM_TYPE_VBI && + test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) { + /* this stream is still in use internally */ + return; + } + if (!test_and_clear_bit(CX18_F_S_CLAIMED, &s->s_flags)) { + CX18_DEBUG_WARN("Release stream %s not in use!\n", s->name); + return; + } + + cx18_flush_queues(s); + + /* CX18_ENC_STREAM_TYPE_MPG needs to release CX18_ENC_STREAM_TYPE_VBI, + for all other streams we're done */ + if (s->type == CX18_ENC_STREAM_TYPE_MPG) + s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; + else + return; + + /* clear internal use flag */ + if (!test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags)) { + /* was already cleared */ + return; + } + if (s_vbi->id != -1) { + /* VBI stream still claimed by a file descriptor */ + return; + } + clear_bit(CX18_F_S_CLAIMED, &s_vbi->s_flags); + cx18_flush_queues(s_vbi); +} + +static void cx18_dualwatch(struct cx18 *cx) +{ + struct v4l2_tuner vt; + u16 new_bitmap; + u16 new_stereo_mode; + const u16 stereo_mask = 0x0300; + const u16 dual = 0x0200; + + new_stereo_mode = cx->params.audio_properties & stereo_mask; + memset(&vt, 0, sizeof(vt)); + cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, &vt); + if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && + (vt.rxsubchans & V4L2_TUNER_SUB_LANG2)) + new_stereo_mode = dual; + + if (new_stereo_mode == cx->dualwatch_stereo_mode) + return; + + new_bitmap = new_stereo_mode | (cx->params.audio_properties & ~stereo_mask); + + CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. new audio_bitmask=0x%ux\n", + cx->dualwatch_stereo_mode, new_stereo_mode, new_bitmap); + + if (cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2, + cx18_find_handle(cx), new_bitmap) == 0) { + cx->dualwatch_stereo_mode = new_stereo_mode; + return; + } + CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n"); +} + + +static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block, int *err) +{ + struct cx18 *cx = s->cx; + struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; + struct cx18_buffer *buf; + DEFINE_WAIT(wait); + + *err = 0; + while (1) { + if (s->type == CX18_ENC_STREAM_TYPE_MPG) { + + if (time_after(jiffies, cx->dualwatch_jiffies + msecs_to_jiffies(1000))) { + cx->dualwatch_jiffies = jiffies; + cx18_dualwatch(cx); + } + if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) && + !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { + while ((buf = cx18_dequeue(s_vbi, &s_vbi->q_full))) { + /* byteswap and process VBI data */ +/* cx18_process_vbi_data(cx, buf, s_vbi->dma_pts, s_vbi->type); */ + cx18_enqueue(s_vbi, buf, &s_vbi->q_free); + } + } + buf = &cx->vbi.sliced_mpeg_buf; + if (buf->readpos != buf->bytesused) + return buf; + } + + /* do we have leftover data? */ + buf = cx18_dequeue(s, &s->q_io); + if (buf) + return buf; + + /* do we have new data? */ + buf = cx18_dequeue(s, &s->q_full); + if (buf) { + if (!test_and_clear_bit(CX18_F_B_NEED_BUF_SWAP, + &buf->b_flags)) + return buf; + if (s->type == CX18_ENC_STREAM_TYPE_MPG) + /* byteswap MPG data */ + cx18_buf_swap(buf); + else { + /* byteswap and process VBI data */ + cx18_process_vbi_data(cx, buf, + s->dma_pts, s->type); + } + return buf; + } + + /* return if end of stream */ + if (!test_bit(CX18_F_S_STREAMING, &s->s_flags)) { + CX18_DEBUG_INFO("EOS %s\n", s->name); + return NULL; + } + + /* return if file was opened with O_NONBLOCK */ + if (non_block) { + *err = -EAGAIN; + return NULL; + } + + /* wait for more data to arrive */ + prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); + /* New buffers might have become available before we were added + to the waitqueue */ + if (!s->q_full.buffers) + schedule(); + finish_wait(&s->waitq, &wait); + if (signal_pending(current)) { + /* return if a signal was received */ + CX18_DEBUG_INFO("User stopped %s\n", s->name); + *err = -EINTR; + return NULL; + } + } +} + +static void cx18_setup_sliced_vbi_buf(struct cx18 *cx) +{ + int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; + + cx->vbi.sliced_mpeg_buf.buf = cx->vbi.sliced_mpeg_data[idx]; + cx->vbi.sliced_mpeg_buf.bytesused = cx->vbi.sliced_mpeg_size[idx]; + cx->vbi.sliced_mpeg_buf.readpos = 0; +} + +static size_t cx18_copy_buf_to_user(struct cx18_stream *s, + struct cx18_buffer *buf, char __user *ubuf, size_t ucount) +{ + struct cx18 *cx = s->cx; + size_t len = buf->bytesused - buf->readpos; + + if (len > ucount) + len = ucount; + if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG && + cx->vbi.sliced_in->service_set && buf != &cx->vbi.sliced_mpeg_buf) { + const char *start = buf->buf + buf->readpos; + const char *p = start + 1; + const u8 *q; + u8 ch = cx->search_pack_header ? 0xba : 0xe0; + int stuffing, i; + + while (start + len > p) { + q = memchr(p, 0, start + len - p); + if (q == NULL) + break; + p = q + 1; + if ((char *)q + 15 >= buf->buf + buf->bytesused || + q[1] != 0 || q[2] != 1 || q[3] != ch) + continue; + if (!cx->search_pack_header) { + if ((q[6] & 0xc0) != 0x80) + continue; + if (((q[7] & 0xc0) == 0x80 && + (q[9] & 0xf0) == 0x20) || + ((q[7] & 0xc0) == 0xc0 && + (q[9] & 0xf0) == 0x30)) { + ch = 0xba; + cx->search_pack_header = 1; + p = q + 9; + } + continue; + } + stuffing = q[13] & 7; + /* all stuffing bytes must be 0xff */ + for (i = 0; i < stuffing; i++) + if (q[14 + i] != 0xff) + break; + if (i == stuffing && + (q[4] & 0xc4) == 0x44 && + (q[12] & 3) == 3 && + q[14 + stuffing] == 0 && + q[15 + stuffing] == 0 && + q[16 + stuffing] == 1) { + cx->search_pack_header = 0; + len = (char *)q - start; + cx18_setup_sliced_vbi_buf(cx); + break; + } + } + } + if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) { + CX18_DEBUG_WARN("copy %zd bytes to user failed for %s\n", + len, s->name); + return -EFAULT; + } + buf->readpos += len; + if (s->type == CX18_ENC_STREAM_TYPE_MPG && + buf != &cx->vbi.sliced_mpeg_buf) + cx->mpg_data_received += len; + return len; +} + +static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf, + size_t tot_count, int non_block) +{ + struct cx18 *cx = s->cx; + size_t tot_written = 0; + int single_frame = 0; + + if (atomic_read(&cx->capturing) == 0 && s->id == -1) { + /* shouldn't happen */ + CX18_DEBUG_WARN("Stream %s not initialized before read\n", + s->name); + return -EIO; + } + + /* Each VBI buffer is one frame, the v4l2 API says that for VBI the + frames should arrive one-by-one, so make sure we never output more + than one VBI frame at a time */ + if (s->type == CX18_ENC_STREAM_TYPE_VBI && + cx->vbi.sliced_in->service_set) + single_frame = 1; + + for (;;) { + struct cx18_buffer *buf; + int rc; + + buf = cx18_get_buffer(s, non_block, &rc); + /* if there is no data available... */ + if (buf == NULL) { + /* if we got data, then return that regardless */ + if (tot_written) + break; + /* EOS condition */ + if (rc == 0) { + clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); + clear_bit(CX18_F_S_APPL_IO, &s->s_flags); + cx18_release_stream(s); + } + /* set errno */ + return rc; + } + + rc = cx18_copy_buf_to_user(s, buf, ubuf + tot_written, + tot_count - tot_written); + + if (buf != &cx->vbi.sliced_mpeg_buf) { + if (buf->readpos == buf->bytesused) { + cx18_buf_sync_for_device(s, buf); + cx18_enqueue(s, buf, &s->q_free); + cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, + s->handle, + (void *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, + 1, buf->id, s->buf_size); + } else + cx18_enqueue(s, buf, &s->q_io); + } else if (buf->readpos == buf->bytesused) { + int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; + + cx->vbi.sliced_mpeg_size[idx] = 0; + cx->vbi.inserted_frame++; + cx->vbi_data_inserted += buf->bytesused; + } + if (rc < 0) + return rc; + tot_written += rc; + + if (tot_written == tot_count || single_frame) + break; + } + return tot_written; +} + +static ssize_t cx18_read_pos(struct cx18_stream *s, char __user *ubuf, + size_t count, loff_t *pos, int non_block) +{ + ssize_t rc = count ? cx18_read(s, ubuf, count, non_block) : 0; + struct cx18 *cx = s->cx; + + CX18_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc); + if (rc > 0) + pos += rc; + return rc; +} + +int cx18_start_capture(struct cx18_open_id *id) +{ + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + struct cx18_stream *s_vbi; + + if (s->type == CX18_ENC_STREAM_TYPE_RAD) { + /* you cannot read from these stream types. */ + return -EPERM; + } + + /* Try to claim this stream. */ + if (cx18_claim_stream(id, s->type)) + return -EBUSY; + + /* If capture is already in progress, then we also have to + do nothing extra. */ + if (test_bit(CX18_F_S_STREAMOFF, &s->s_flags) || + test_and_set_bit(CX18_F_S_STREAMING, &s->s_flags)) { + set_bit(CX18_F_S_APPL_IO, &s->s_flags); + return 0; + } + + /* Start VBI capture if required */ + s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; + if (s->type == CX18_ENC_STREAM_TYPE_MPG && + test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) && + !test_and_set_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) { + /* Note: the CX18_ENC_STREAM_TYPE_VBI is claimed + automatically when the MPG stream is claimed. + We only need to start the VBI capturing. */ + if (cx18_start_v4l2_encode_stream(s_vbi)) { + CX18_DEBUG_WARN("VBI capture start failed\n"); + + /* Failure, clean up and return an error */ + clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags); + clear_bit(CX18_F_S_STREAMING, &s->s_flags); + /* also releases the associated VBI stream */ + cx18_release_stream(s); + return -EIO; + } + CX18_DEBUG_INFO("VBI insertion started\n"); + } + + /* Tell the card to start capturing */ + if (!cx18_start_v4l2_encode_stream(s)) { + /* We're done */ + set_bit(CX18_F_S_APPL_IO, &s->s_flags); + /* Resume a possibly paused encoder */ + if (test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) + cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, s->handle); + return 0; + } + + /* failure, clean up */ + CX18_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name); + + /* Note: the CX18_ENC_STREAM_TYPE_VBI is released + automatically when the MPG stream is released. + We only need to stop the VBI capturing. */ + if (s->type == CX18_ENC_STREAM_TYPE_MPG && + test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) { + cx18_stop_v4l2_encode_stream(s_vbi, 0); + clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags); + } + clear_bit(CX18_F_S_STREAMING, &s->s_flags); + cx18_release_stream(s); + return -EIO; +} + +ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count, + loff_t *pos) +{ + struct cx18_open_id *id = filp->private_data; + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + int rc; + + CX18_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name); + + mutex_lock(&cx->serialize_lock); + rc = cx18_start_capture(id); + mutex_unlock(&cx->serialize_lock); + if (rc) + return rc; + return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); +} + +unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait) +{ + struct cx18_open_id *id = filp->private_data; + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags); + + /* Start a capture if there is none */ + if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) { + int rc; + + mutex_lock(&cx->serialize_lock); + rc = cx18_start_capture(id); + mutex_unlock(&cx->serialize_lock); + if (rc) { + CX18_DEBUG_INFO("Could not start capture for %s (%d)\n", + s->name, rc); + return POLLERR; + } + CX18_DEBUG_FILE("Encoder poll started capture\n"); + } + + /* add stream's waitq to the poll list */ + CX18_DEBUG_HI_FILE("Encoder poll\n"); + poll_wait(filp, &s->waitq, wait); + + if (s->q_full.length || s->q_io.length) + return POLLIN | POLLRDNORM; + if (eof) + return POLLHUP; + return 0; +} + +void cx18_stop_capture(struct cx18_open_id *id, int gop_end) +{ + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + + CX18_DEBUG_IOCTL("close() of %s\n", s->name); + + /* 'Unclaim' this stream */ + + /* Stop capturing */ + if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) { + struct cx18_stream *s_vbi = + &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; + + CX18_DEBUG_INFO("close stopping capture\n"); + /* Special case: a running VBI capture for VBI insertion + in the mpeg stream. Need to stop that too. */ + if (id->type == CX18_ENC_STREAM_TYPE_MPG && + test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) && + !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { + CX18_DEBUG_INFO("close stopping embedded VBI capture\n"); + cx18_stop_v4l2_encode_stream(s_vbi, 0); + } + if (id->type == CX18_ENC_STREAM_TYPE_VBI && + test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) + /* Also used internally, don't stop capturing */ + s->id = -1; + else + cx18_stop_v4l2_encode_stream(s, gop_end); + } + if (!gop_end) { + clear_bit(CX18_F_S_APPL_IO, &s->s_flags); + clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); + cx18_release_stream(s); + } +} + +int cx18_v4l2_close(struct inode *inode, struct file *filp) +{ + struct cx18_open_id *id = filp->private_data; + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + + CX18_DEBUG_IOCTL("close() of %s\n", s->name); + + v4l2_prio_close(&cx->prio, &id->prio); + + /* Easy case first: this stream was never claimed by us */ + if (s->id != id->open_id) { + kfree(id); + return 0; + } + + /* 'Unclaim' this stream */ + + /* Stop radio */ + mutex_lock(&cx->serialize_lock); + if (id->type == CX18_ENC_STREAM_TYPE_RAD) { + /* Closing radio device, return to TV mode */ + cx18_mute(cx); + /* Mark that the radio is no longer in use */ + clear_bit(CX18_F_I_RADIO_USER, &cx->i_flags); + /* Switch tuner to TV */ + cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std); + /* Select correct audio input (i.e. TV tuner or Line in) */ + cx18_audio_set_io(cx); + if (atomic_read(&cx->capturing) > 0) { + /* Undo video mute */ + cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, + cx->params.video_mute | + (cx->params.video_mute_yuv << 8)); + } + /* Done! Unmute and continue. */ + cx18_unmute(cx); + cx18_release_stream(s); + } else { + cx18_stop_capture(id, 0); + } + kfree(id); + mutex_unlock(&cx->serialize_lock); + return 0; +} + +static int cx18_serialized_open(struct cx18_stream *s, struct file *filp) +{ + struct cx18 *cx = s->cx; + struct cx18_open_id *item; + + CX18_DEBUG_FILE("open %s\n", s->name); + + /* Allocate memory */ + item = kmalloc(sizeof(struct cx18_open_id), GFP_KERNEL); + if (NULL == item) { + CX18_DEBUG_WARN("nomem on v4l2 open\n"); + return -ENOMEM; + } + item->cx = cx; + item->type = s->type; + v4l2_prio_open(&cx->prio, &item->prio); + + item->open_id = cx->open_id++; + filp->private_data = item; + + if (item->type == CX18_ENC_STREAM_TYPE_RAD) { + /* Try to claim this stream */ + if (cx18_claim_stream(item, item->type)) { + /* No, it's already in use */ + kfree(item); + return -EBUSY; + } + + if (!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { + if (atomic_read(&cx->capturing) > 0) { + /* switching to radio while capture is + in progress is not polite */ + cx18_release_stream(s); + kfree(item); + return -EBUSY; + } + } + + /* Mark that the radio is being used. */ + set_bit(CX18_F_I_RADIO_USER, &cx->i_flags); + /* We have the radio */ + cx18_mute(cx); + /* Switch tuner to radio */ + cx18_call_i2c_clients(cx, AUDC_SET_RADIO, NULL); + /* Select the correct audio input (i.e. radio tuner) */ + cx18_audio_set_io(cx); + /* Done! Unmute and continue. */ + cx18_unmute(cx); + } + return 0; +} + +int cx18_v4l2_open(struct inode *inode, struct file *filp) +{ + int res, x, y = 0; + struct cx18 *cx = NULL; + struct cx18_stream *s = NULL; + int minor = iminor(inode); + + /* Find which card this open was on */ + spin_lock(&cx18_cards_lock); + for (x = 0; cx == NULL && x < cx18_cards_active; x++) { + /* find out which stream this open was on */ + for (y = 0; y < CX18_MAX_STREAMS; y++) { + s = &cx18_cards[x]->streams[y]; + if (s->v4l2dev && s->v4l2dev->minor == minor) { + cx = cx18_cards[x]; + break; + } + } + } + spin_unlock(&cx18_cards_lock); + + if (cx == NULL) { + /* Couldn't find a device registered + on that minor, shouldn't happen! */ + printk(KERN_WARNING "No cx18 device found on minor %d\n", + minor); + return -ENXIO; + } + + mutex_lock(&cx->serialize_lock); + if (cx18_init_on_first_open(cx)) { + CX18_ERR("Failed to initialize on minor %d\n", minor); + mutex_unlock(&cx->serialize_lock); + return -ENXIO; + } + res = cx18_serialized_open(s, filp); + mutex_unlock(&cx->serialize_lock); + return res; +} + +void cx18_mute(struct cx18 *cx) +{ + if (atomic_read(&cx->capturing)) + cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, + cx18_find_handle(cx), 1); + CX18_DEBUG_INFO("Mute\n"); +} + +void cx18_unmute(struct cx18 *cx) +{ + if (atomic_read(&cx->capturing)) { + cx18_msleep_timeout(100, 0); + cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, + cx18_find_handle(cx), 12); + cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, + cx18_find_handle(cx), 0); + } + CX18_DEBUG_INFO("Unmute\n"); +} diff --git a/drivers/media/video/cx18/cx18-fileops.h b/drivers/media/video/cx18/cx18-fileops.h new file mode 100644 index 000000000000..16cdafbd24c5 --- /dev/null +++ b/drivers/media/video/cx18/cx18-fileops.h @@ -0,0 +1,45 @@ +/* + * cx18 file operation functions + * + * Derived from ivtv-fileops.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 + */ + +/* Testing/Debugging */ +int cx18_v4l2_open(struct inode *inode, struct file *filp); +ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count, + loff_t *pos); +ssize_t cx18_v4l2_write(struct file *filp, const char __user *buf, size_t count, + loff_t *pos); +int cx18_v4l2_close(struct inode *inode, struct file *filp); +unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait); +int cx18_start_capture(struct cx18_open_id *id); +void cx18_stop_capture(struct cx18_open_id *id, int gop_end); +void cx18_mute(struct cx18 *cx); +void cx18_unmute(struct cx18 *cx); + +/* Utilities */ + +/* Try to claim a stream for the filehandle. Return 0 on success, + -EBUSY if stream already claimed. Once a stream is claimed, it + remains claimed until the associated filehandle is closed. */ +int cx18_claim_stream(struct cx18_open_id *id, int type); + +/* Release a previously claimed stream. */ +void cx18_release_stream(struct cx18_stream *s); diff --git a/drivers/media/video/cx18/cx18-firmware.c b/drivers/media/video/cx18/cx18-firmware.c new file mode 100644 index 000000000000..2694ce350631 --- /dev/null +++ b/drivers/media/video/cx18/cx18-firmware.c @@ -0,0 +1,373 @@ +/* + * cx18 firmware functions + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-scb.h" +#include "cx18-irq.h" +#include "cx18-firmware.h" +#include "cx18-cards.h" +#include <linux/firmware.h> + +#define CX18_PROC_SOFT_RESET 0xc70010 +#define CX18_DDR_SOFT_RESET 0xc70014 +#define CX18_CLOCK_SELECT1 0xc71000 +#define CX18_CLOCK_SELECT2 0xc71004 +#define CX18_HALF_CLOCK_SELECT1 0xc71008 +#define CX18_HALF_CLOCK_SELECT2 0xc7100C +#define CX18_CLOCK_POLARITY1 0xc71010 +#define CX18_CLOCK_POLARITY2 0xc71014 +#define CX18_ADD_DELAY_ENABLE1 0xc71018 +#define CX18_ADD_DELAY_ENABLE2 0xc7101C +#define CX18_CLOCK_ENABLE1 0xc71020 +#define CX18_CLOCK_ENABLE2 0xc71024 + +#define CX18_REG_BUS_TIMEOUT_EN 0xc72024 + +#define CX18_AUDIO_ENABLE 0xc72014 +#define CX18_REG_BUS_TIMEOUT_EN 0xc72024 + +#define CX18_FAST_CLOCK_PLL_INT 0xc78000 +#define CX18_FAST_CLOCK_PLL_FRAC 0xc78004 +#define CX18_FAST_CLOCK_PLL_POST 0xc78008 +#define CX18_FAST_CLOCK_PLL_PRESCALE 0xc7800C +#define CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH 0xc78010 + +#define CX18_SLOW_CLOCK_PLL_INT 0xc78014 +#define CX18_SLOW_CLOCK_PLL_FRAC 0xc78018 +#define CX18_SLOW_CLOCK_PLL_POST 0xc7801C +#define CX18_MPEG_CLOCK_PLL_INT 0xc78040 +#define CX18_MPEG_CLOCK_PLL_FRAC 0xc78044 +#define CX18_MPEG_CLOCK_PLL_POST 0xc78048 +#define CX18_PLL_POWER_DOWN 0xc78088 +#define CX18_SW1_INT_STATUS 0xc73104 +#define CX18_SW1_INT_ENABLE_PCI 0xc7311C +#define CX18_SW2_INT_SET 0xc73140 +#define CX18_SW2_INT_STATUS 0xc73144 +#define CX18_ADEC_CONTROL 0xc78120 + +#define CX18_DDR_REQUEST_ENABLE 0xc80000 +#define CX18_DDR_CHIP_CONFIG 0xc80004 +#define CX18_DDR_REFRESH 0xc80008 +#define CX18_DDR_TIMING1 0xc8000C +#define CX18_DDR_TIMING2 0xc80010 +#define CX18_DDR_POWER_REG 0xc8001C + +#define CX18_DDR_TUNE_LANE 0xc80048 +#define CX18_DDR_INITIAL_EMRS 0xc80054 +#define CX18_DDR_MB_PER_ROW_7 0xc8009C +#define CX18_DDR_BASE_63_ADDR 0xc804FC + +#define CX18_WMB_CLIENT02 0xc90108 +#define CX18_WMB_CLIENT05 0xc90114 +#define CX18_WMB_CLIENT06 0xc90118 +#define CX18_WMB_CLIENT07 0xc9011C +#define CX18_WMB_CLIENT08 0xc90120 +#define CX18_WMB_CLIENT09 0xc90124 +#define CX18_WMB_CLIENT10 0xc90128 +#define CX18_WMB_CLIENT11 0xc9012C +#define CX18_WMB_CLIENT12 0xc90130 +#define CX18_WMB_CLIENT13 0xc90134 +#define CX18_WMB_CLIENT14 0xc90138 + +#define CX18_DSP0_INTERRUPT_MASK 0xd0004C + +/* Encoder/decoder firmware sizes */ +#define CX18_FW_CPU_SIZE (174716) +#define CX18_FW_APU_SIZE (141200) + +#define APU_ROM_SYNC1 0x6D676553 /* "mgeS" */ +#define APU_ROM_SYNC2 0x72646548 /* "rdeH" */ + +struct cx18_apu_rom_seghdr { + u32 sync1; + u32 sync2; + u32 addr; + u32 size; +}; + +static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx, long size) +{ + const struct firmware *fw = NULL; + int retries = 3; + int i, j; + u32 __iomem *dst = (u32 __iomem *)mem; + const u32 *src; + +retry: + if (!retries || request_firmware(&fw, fn, &cx->dev->dev)) { + CX18_ERR("Unable to open firmware %s (must be %ld bytes)\n", + fn, size); + CX18_ERR("Did you put the firmware in the hotplug firmware directory?\n"); + return -ENOMEM; + } + + src = (const u32 *)fw->data; + + if (fw->size != size) { + /* Due to race conditions in firmware loading (esp. with + udev <0.95) the wrong file was sometimes loaded. So we check + filesizes to see if at least the right-sized file was + loaded. If not, then we retry. */ + CX18_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n", + fn, size, fw->size); + release_firmware(fw); + retries--; + goto retry; + } + for (i = 0; i < fw->size; i += 4096) { + setup_page(i); + for (j = i; j < fw->size && j < i + 4096; j += 4) { + /* no need for endianness conversion on the ppc */ + __raw_writel(*src, dst); + if (__raw_readl(dst) != *src) { + CX18_ERR("Mismatch at offset %x\n", i); + release_firmware(fw); + return -EIO; + } + dst++; + src++; + } + } + if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) + CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size); + release_firmware(fw); + return size; +} + +static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, long size) +{ + const struct firmware *fw = NULL; + int retries = 3; + int i, j; + const u32 *src; + struct cx18_apu_rom_seghdr seghdr; + const u8 *vers; + u32 offset = 0; + u32 apu_version = 0; + int sz; + +retry: + if (!retries || request_firmware(&fw, fn, &cx->dev->dev)) { + CX18_ERR("unable to open firmware %s (must be %ld bytes)\n", + fn, size); + CX18_ERR("did you put the firmware in the hotplug firmware directory?\n"); + return -ENOMEM; + } + + src = (const u32 *)fw->data; + vers = fw->data + sizeof(seghdr); + sz = fw->size; + + if (fw->size != size) { + /* Due to race conditions in firmware loading (esp. with + udev <0.95) the wrong file was sometimes loaded. So we check + filesizes to see if at least the right-sized file was + loaded. If not, then we retry. */ + CX18_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n", + fn, size, fw->size); + release_firmware(fw); + retries--; + goto retry; + } + apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32]; + while (offset + sizeof(seghdr) < size) { + /* TODO: byteswapping */ + memcpy(&seghdr, src + offset / 4, sizeof(seghdr)); + offset += sizeof(seghdr); + if (seghdr.sync1 != APU_ROM_SYNC1 || + seghdr.sync2 != APU_ROM_SYNC2) { + offset += seghdr.size; + continue; + } + CX18_DEBUG_INFO("load segment %x-%x\n", seghdr.addr, + seghdr.addr + seghdr.size - 1); + if (offset + seghdr.size > sz) + break; + for (i = 0; i < seghdr.size; i += 4096) { + setup_page(offset + i); + for (j = i; j < seghdr.size && j < i + 4096; j += 4) { + /* no need for endianness conversion on the ppc */ + __raw_writel(src[(offset + j) / 4], dst + seghdr.addr + j); + if (__raw_readl(dst + seghdr.addr + j) != src[(offset + j) / 4]) { + CX18_ERR("Mismatch at offset %x\n", offset + j); + release_firmware(fw); + return -EIO; + } + } + } + offset += seghdr.size; + } + if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) + CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n", + fn, apu_version, fw->size); + release_firmware(fw); + /* Clear bit0 for APU to start from 0 */ + write_reg(read_reg(0xc72030) & ~1, 0xc72030); + return size; +} + +void cx18_halt_firmware(struct cx18 *cx) +{ + CX18_DEBUG_INFO("Preparing for firmware halt.\n"); + write_reg(0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */ + write_reg(0x00020002, CX18_ADEC_CONTROL); +} + +void cx18_init_power(struct cx18 *cx, int lowpwr) +{ + /* power-down Spare and AOM PLLs */ + /* power-up fast, slow and mpeg PLLs */ + write_reg(0x00000008, CX18_PLL_POWER_DOWN); + + /* ADEC out of sleep */ + write_reg(0x00020000, CX18_ADEC_CONTROL); + + /* The fast clock is at 200/245 MHz */ + write_reg(lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT); + write_reg(lowpwr ? 0x1EFBF37 : 0x038E3D7, CX18_FAST_CLOCK_PLL_FRAC); + + write_reg(2, CX18_FAST_CLOCK_PLL_POST); + write_reg(1, CX18_FAST_CLOCK_PLL_PRESCALE); + write_reg(4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH); + + /* set slow clock to 125/120 MHz */ + write_reg(lowpwr ? 0x11 : 0x10, CX18_SLOW_CLOCK_PLL_INT); + write_reg(lowpwr ? 0xEBAF05 : 0x18618A8, CX18_SLOW_CLOCK_PLL_FRAC); + write_reg(4, CX18_SLOW_CLOCK_PLL_POST); + + /* mpeg clock pll 54MHz */ + write_reg(0xF, CX18_MPEG_CLOCK_PLL_INT); + write_reg(0x2BCFEF, CX18_MPEG_CLOCK_PLL_FRAC); + write_reg(8, CX18_MPEG_CLOCK_PLL_POST); + + /* Defaults */ + /* APU = SC or SC/2 = 125/62.5 */ + /* EPU = SC = 125 */ + /* DDR = FC = 180 */ + /* ENC = SC = 125 */ + /* AI1 = SC = 125 */ + /* VIM2 = disabled */ + /* PCI = FC/2 = 90 */ + /* AI2 = disabled */ + /* DEMUX = disabled */ + /* AO = SC/2 = 62.5 */ + /* SER = 54MHz */ + /* VFC = disabled */ + /* USB = disabled */ + + write_reg(lowpwr ? 0xFFFF0020 : 0x00060004, CX18_CLOCK_SELECT1); + write_reg(lowpwr ? 0xFFFF0004 : 0x00060006, CX18_CLOCK_SELECT2); + + write_reg(0xFFFF0002, CX18_HALF_CLOCK_SELECT1); + write_reg(0xFFFF0104, CX18_HALF_CLOCK_SELECT2); + + write_reg(0xFFFF9026, CX18_CLOCK_ENABLE1); + write_reg(0xFFFF3105, CX18_CLOCK_ENABLE2); +} + +void cx18_init_memory(struct cx18 *cx) +{ + cx18_msleep_timeout(10, 0); + write_reg(0x10000, CX18_DDR_SOFT_RESET); + cx18_msleep_timeout(10, 0); + + write_reg(cx->card->ddr.chip_config, CX18_DDR_CHIP_CONFIG); + + cx18_msleep_timeout(10, 0); + + write_reg(cx->card->ddr.refresh, CX18_DDR_REFRESH); + write_reg(cx->card->ddr.timing1, CX18_DDR_TIMING1); + write_reg(cx->card->ddr.timing2, CX18_DDR_TIMING2); + + cx18_msleep_timeout(10, 0); + + /* Initialize DQS pad time */ + write_reg(cx->card->ddr.tune_lane, CX18_DDR_TUNE_LANE); + write_reg(cx->card->ddr.initial_emrs, CX18_DDR_INITIAL_EMRS); + + cx18_msleep_timeout(10, 0); + + write_reg(0x20000, CX18_DDR_SOFT_RESET); + cx18_msleep_timeout(10, 0); + + /* use power-down mode when idle */ + write_reg(0x00000010, CX18_DDR_POWER_REG); + + write_reg(0x10001, CX18_REG_BUS_TIMEOUT_EN); + + write_reg(0x48, CX18_DDR_MB_PER_ROW_7); + write_reg(0xE0000, CX18_DDR_BASE_63_ADDR); + + write_reg(0x00000101, CX18_WMB_CLIENT02); /* AO */ + write_reg(0x00000101, CX18_WMB_CLIENT09); /* AI2 */ + write_reg(0x00000101, CX18_WMB_CLIENT05); /* VIM1 */ + write_reg(0x00000101, CX18_WMB_CLIENT06); /* AI1 */ + write_reg(0x00000101, CX18_WMB_CLIENT07); /* 3D comb */ + write_reg(0x00000101, CX18_WMB_CLIENT10); /* ME */ + write_reg(0x00000101, CX18_WMB_CLIENT12); /* ENC */ + write_reg(0x00000101, CX18_WMB_CLIENT13); /* PK */ + write_reg(0x00000101, CX18_WMB_CLIENT11); /* RC */ + write_reg(0x00000101, CX18_WMB_CLIENT14); /* AVO */ +} + +int cx18_firmware_init(struct cx18 *cx) +{ + /* Allow chip to control CLKRUN */ + write_reg(0x5, CX18_DSP0_INTERRUPT_MASK); + + write_reg(0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */ + + cx18_msleep_timeout(1, 0); + + sw1_irq_enable(IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU); + sw2_irq_enable(IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); + + /* Only if the processor is not running */ + if (read_reg(CX18_PROC_SOFT_RESET) & 8) { + int sz = load_apu_fw_direct("v4l-cx23418-apu.fw", + cx->enc_mem, cx, CX18_FW_APU_SIZE); + + sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw", + cx->enc_mem, cx, CX18_FW_CPU_SIZE); + + if (sz > 0) { + int retries = 0; + + /* start the CPU */ + write_reg(0x00080000, CX18_PROC_SOFT_RESET); + while (retries++ < 50) { /* Loop for max 500mS */ + if ((read_reg(CX18_PROC_SOFT_RESET) & 1) == 0) + break; + cx18_msleep_timeout(10, 0); + } + cx18_msleep_timeout(200, 0); + if (retries == 51) { + CX18_ERR("Could not start the CPU\n"); + return -EIO; + } + } + if (sz <= 0) + return -EIO; + } + /* initialize GPIO */ + write_reg(0x14001400, 0xC78110); + return 0; +} diff --git a/drivers/media/video/cx18/cx18-firmware.h b/drivers/media/video/cx18/cx18-firmware.h new file mode 100644 index 000000000000..38d4c05e8499 --- /dev/null +++ b/drivers/media/video/cx18/cx18-firmware.h @@ -0,0 +1,25 @@ +/* + * cx18 firmware functions + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 + */ + +int cx18_firmware_init(struct cx18 *cx); +void cx18_halt_firmware(struct cx18 *cx); +void cx18_init_memory(struct cx18 *cx); +void cx18_init_power(struct cx18 *cx, int lowpwr); diff --git a/drivers/media/video/cx18/cx18-gpio.c b/drivers/media/video/cx18/cx18-gpio.c new file mode 100644 index 000000000000..19253e6b8673 --- /dev/null +++ b/drivers/media/video/cx18/cx18-gpio.c @@ -0,0 +1,74 @@ +/* + * cx18 gpio functions + * + * Derived from ivtv-gpio.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-cards.h" +#include "cx18-gpio.h" +#include "tuner-xc2028.h" + +/********************* GPIO stuffs *********************/ + +/* GPIO registers */ +#define CX18_REG_GPIO_IN 0xc72010 +#define CX18_REG_GPIO_OUT1 0xc78100 +#define CX18_REG_GPIO_DIR1 0xc78108 +#define CX18_REG_GPIO_OUT2 0xc78104 +#define CX18_REG_GPIO_DIR2 0xc7810c + +/* + * HVR-1600 GPIO pins, courtesy of Hauppauge: + * + * gpio0: zilog ir process reset pin + * gpio1: zilog programming pin (you should never use this) + * gpio12: cx24227 reset pin + * gpio13: cs5345 reset pin +*/ + +void cx18_gpio_init(struct cx18 *cx) +{ + if (cx->card->gpio_init.direction == 0) + return; + + CX18_DEBUG_INFO("GPIO initial dir: %08x out: %08x\n", + read_reg(CX18_REG_GPIO_DIR1), read_reg(CX18_REG_GPIO_OUT1)); + + /* init output data then direction */ + write_reg(cx->card->gpio_init.direction << 16, CX18_REG_GPIO_DIR1); + write_reg(0, CX18_REG_GPIO_DIR2); + write_reg((cx->card->gpio_init.direction << 16) | + cx->card->gpio_init.initial_value, CX18_REG_GPIO_OUT1); + write_reg(0, CX18_REG_GPIO_OUT2); +} + +/* Xceive tuner reset function */ +int cx18_reset_tuner_gpio(void *dev, int cmd, int value) +{ + struct i2c_algo_bit_data *algo = dev; + struct cx18 *cx = algo->data; +/* int curdir, curout;*/ + + if (cmd != XC2028_TUNER_RESET) + return 0; + CX18_DEBUG_INFO("Resetting tuner\n"); + return 0; +} diff --git a/drivers/media/video/cx18/cx18-gpio.h b/drivers/media/video/cx18/cx18-gpio.h new file mode 100644 index 000000000000..41bac8856b50 --- /dev/null +++ b/drivers/media/video/cx18/cx18-gpio.h @@ -0,0 +1,24 @@ +/* + * cx18 gpio functions + * + * Derived from ivtv-gpio.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 + */ + +void cx18_gpio_init(struct cx18 *cx); +int cx18_reset_tuner_gpio(void *dev, int cmd, int value); diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c new file mode 100644 index 000000000000..18c88d1e4833 --- /dev/null +++ b/drivers/media/video/cx18/cx18-i2c.c @@ -0,0 +1,431 @@ +/* + * cx18 I2C functions + * + * Derived from ivtv-i2c.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-cards.h" +#include "cx18-gpio.h" +#include "cx18-av-core.h" + +#include <media/ir-kbd-i2c.h> + +#define CX18_REG_I2C_1_WR 0xf15000 +#define CX18_REG_I2C_1_RD 0xf15008 +#define CX18_REG_I2C_2_WR 0xf25100 +#define CX18_REG_I2C_2_RD 0xf25108 + +#define SETSCL_BIT 0x0001 +#define SETSDL_BIT 0x0002 +#define GETSCL_BIT 0x0004 +#define GETSDL_BIT 0x0008 + +#ifndef I2C_ADAP_CLASS_TV_ANALOG +#define I2C_ADAP_CLASS_TV_ANALOG I2C_CLASS_TV_ANALOG +#endif + +#define CX18_CS5345_I2C_ADDR 0x4c + +/* This array should match the CX18_HW_ defines */ +static const u8 hw_driverids[] = { + I2C_DRIVERID_TUNER, + I2C_DRIVERID_TVEEPROM, + I2C_DRIVERID_CS5345, + 0, /* CX18_HW_GPIO dummy driver ID */ + 0 /* CX18_HW_CX23418 dummy driver ID */ +}; + +/* This array should match the CX18_HW_ defines */ +static const u8 hw_addrs[] = { + 0, + 0, + CX18_CS5345_I2C_ADDR, + 0, /* CX18_HW_GPIO dummy driver ID */ + 0, /* CX18_HW_CX23418 dummy driver ID */ +}; + +/* This array should match the CX18_HW_ defines */ +/* This might well become a card-specific array */ +static const u8 hw_bus[] = { + 0, + 0, + 0, + 0, /* CX18_HW_GPIO dummy driver ID */ + 0, /* CX18_HW_CX23418 dummy driver ID */ +}; + +/* This array should match the CX18_HW_ defines */ +static const char * const hw_drivernames[] = { + "tuner", + "tveeprom", + "cs5345", + "gpio", + "cx23418", +}; + +int cx18_i2c_register(struct cx18 *cx, unsigned idx) +{ + struct i2c_board_info info; + struct i2c_client *c; + u8 id, bus; + int i; + + CX18_DEBUG_I2C("i2c client register\n"); + if (idx >= ARRAY_SIZE(hw_driverids) || hw_driverids[idx] == 0) + return -1; + id = hw_driverids[idx]; + bus = hw_bus[idx]; + memset(&info, 0, sizeof(info)); + strlcpy(info.driver_name, hw_drivernames[idx], + sizeof(info.driver_name)); + info.addr = hw_addrs[idx]; + for (i = 0; i < I2C_CLIENTS_MAX; i++) + if (cx->i2c_clients[i] == NULL) + break; + + if (i == I2C_CLIENTS_MAX) { + CX18_ERR("insufficient room for new I2C client!\n"); + return -ENOMEM; + } + + if (id != I2C_DRIVERID_TUNER) { + c = i2c_new_device(&cx->i2c_adap[bus], &info); + if (c->driver == NULL) + i2c_unregister_device(c); + else + cx->i2c_clients[i] = c; + return cx->i2c_clients[i] ? 0 : -ENODEV; + } + + /* special tuner handling */ + c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->radio); + if (c && c->driver == NULL) + i2c_unregister_device(c); + else if (c) + cx->i2c_clients[i++] = c; + c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->demod); + if (c && c->driver == NULL) + i2c_unregister_device(c); + else if (c) + cx->i2c_clients[i++] = c; + c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->tv); + if (c && c->driver == NULL) + i2c_unregister_device(c); + else if (c) + cx->i2c_clients[i++] = c; + return 0; +} + +static int attach_inform(struct i2c_client *client) +{ + return 0; +} + +static int detach_inform(struct i2c_client *client) +{ + int i; + struct cx18 *cx = (struct cx18 *)i2c_get_adapdata(client->adapter); + + CX18_DEBUG_I2C("i2c client detach\n"); + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + if (cx->i2c_clients[i] == client) { + cx->i2c_clients[i] = NULL; + break; + } + } + CX18_DEBUG_I2C("i2c detach [client=%s,%s]\n", + client->name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed"); + + return 0; +} + +static void cx18_setscl(void *data, int state) +{ + struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; + int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index; + u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR; + u32 r = read_reg(addr); + + if (state) + write_reg_sync(r | SETSCL_BIT, addr); + else + write_reg_sync(r & ~SETSCL_BIT, addr); +} + +static void cx18_setsda(void *data, int state) +{ + struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; + int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index; + u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR; + u32 r = read_reg(addr); + + if (state) + write_reg_sync(r | SETSDL_BIT, addr); + else + write_reg_sync(r & ~SETSDL_BIT, addr); +} + +static int cx18_getscl(void *data) +{ + struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; + int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index; + u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD; + + return read_reg(addr) & GETSCL_BIT; +} + +static int cx18_getsda(void *data) +{ + struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; + int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index; + u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD; + + return read_reg(addr) & GETSDL_BIT; +} + +/* template for i2c-bit-algo */ +static struct i2c_adapter cx18_i2c_adap_template = { + .name = "cx18 i2c driver", + .id = I2C_HW_B_CX2341X, + .algo = NULL, /* set by i2c-algo-bit */ + .algo_data = NULL, /* filled from template */ + .client_register = attach_inform, + .client_unregister = detach_inform, + .owner = THIS_MODULE, +}; + +#define CX18_SCL_PERIOD (10) /* usecs. 10 usec is period for a 100 KHz clock */ +#define CX18_ALGO_BIT_TIMEOUT (2) /* seconds */ + +static struct i2c_algo_bit_data cx18_i2c_algo_template = { + .setsda = cx18_setsda, + .setscl = cx18_setscl, + .getsda = cx18_getsda, + .getscl = cx18_getscl, + .udelay = CX18_SCL_PERIOD/2, /* 1/2 clock period in usec*/ + .timeout = CX18_ALGO_BIT_TIMEOUT*HZ /* jiffies */ +}; + +static struct i2c_client cx18_i2c_client_template = { + .name = "cx18 internal", +}; + +int cx18_call_i2c_client(struct cx18 *cx, int addr, unsigned cmd, void *arg) +{ + struct i2c_client *client; + int retval; + int i; + + CX18_DEBUG_I2C("call_i2c_client addr=%02x\n", addr); + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + client = cx->i2c_clients[i]; + if (client == NULL || client->driver == NULL || + client->driver->command == NULL) + continue; + if (addr == client->addr) { + retval = client->driver->command(client, cmd, arg); + return retval; + } + } + if (cmd != VIDIOC_G_CHIP_IDENT) + CX18_ERR("i2c addr 0x%02x not found for cmd 0x%x!\n", + addr, cmd); + return -ENODEV; +} + +/* Find the i2c device based on the driver ID and return + its i2c address or -ENODEV if no matching device was found. */ +static int cx18_i2c_id_addr(struct cx18 *cx, u32 id) +{ + struct i2c_client *client; + int retval = -ENODEV; + int i; + + for (i = 0; i < I2C_CLIENTS_MAX; i++) { + client = cx->i2c_clients[i]; + if (client == NULL || client->driver == NULL) + continue; + if (id == client->driver->id) { + retval = client->addr; + break; + } + } + return retval; +} + +/* Find the i2c device name matching the DRIVERID */ +static const char *cx18_i2c_id_name(u32 id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) + if (hw_driverids[i] == id) + return hw_drivernames[i]; + return "unknown device"; +} + +/* Find the i2c device name matching the CX18_HW_ flag */ +static const char *cx18_i2c_hw_name(u32 hw) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) + if (1 << i == hw) + return hw_drivernames[i]; + return "unknown device"; +} + +/* Find the i2c device matching the CX18_HW_ flag and return + its i2c address or -ENODEV if no matching device was found. */ +int cx18_i2c_hw_addr(struct cx18 *cx, u32 hw) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(hw_driverids); i++) + if (1 << i == hw) + return cx18_i2c_id_addr(cx, hw_driverids[i]); + return -ENODEV; +} + +/* Calls i2c device based on CX18_HW_ flag. If hw == 0, then do nothing. + If hw == CX18_HW_GPIO then call the gpio handler. */ +int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg) +{ + int addr; + + if (hw == CX18_HW_GPIO || hw == 0) + return 0; + if (hw == CX18_HW_CX23418) + return cx18_av_cmd(cx, cmd, arg); + + addr = cx18_i2c_hw_addr(cx, hw); + if (addr < 0) { + CX18_ERR("i2c hardware 0x%08x (%s) not found for cmd 0x%x!\n", + hw, cx18_i2c_hw_name(hw), cmd); + return addr; + } + return cx18_call_i2c_client(cx, addr, cmd, arg); +} + +/* Calls i2c device based on I2C driver ID. */ +int cx18_i2c_id(struct cx18 *cx, u32 id, unsigned int cmd, void *arg) +{ + int addr; + + addr = cx18_i2c_id_addr(cx, id); + if (addr < 0) { + if (cmd != VIDIOC_G_CHIP_IDENT) + CX18_ERR("i2c ID 0x%08x (%s) not found for cmd 0x%x!\n", + id, cx18_i2c_id_name(id), cmd); + return addr; + } + return cx18_call_i2c_client(cx, addr, cmd, arg); +} + +/* broadcast cmd for all I2C clients and for the gpio subsystem */ +void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg) +{ + if (cx->i2c_adap[0].algo == NULL || cx->i2c_adap[1].algo == NULL) { + CX18_ERR("adapter is not set\n"); + return; + } + cx18_av_cmd(cx, cmd, arg); + i2c_clients_command(&cx->i2c_adap[0], cmd, arg); + i2c_clients_command(&cx->i2c_adap[1], cmd, arg); +} + +/* init + register i2c algo-bit adapter */ +int init_cx18_i2c(struct cx18 *cx) +{ + int i; + CX18_DEBUG_I2C("i2c init\n"); + + for (i = 0; i < 2; i++) { + memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template, + sizeof(struct i2c_adapter)); + memcpy(&cx->i2c_algo[i], &cx18_i2c_algo_template, + sizeof(struct i2c_algo_bit_data)); + cx->i2c_algo_cb_data[i].cx = cx; + cx->i2c_algo_cb_data[i].bus_index = i; + cx->i2c_algo[i].data = &cx->i2c_algo_cb_data[i]; + cx->i2c_adap[i].algo_data = &cx->i2c_algo[i]; + + sprintf(cx->i2c_adap[i].name + strlen(cx->i2c_adap[i].name), + " #%d-%d", cx->num, i); + i2c_set_adapdata(&cx->i2c_adap[i], cx); + + memcpy(&cx->i2c_client[i], &cx18_i2c_client_template, + sizeof(struct i2c_client)); + sprintf(cx->i2c_client[i].name + + strlen(cx->i2c_client[i].name), "%d", i); + cx->i2c_client[i].adapter = &cx->i2c_adap[i]; + cx->i2c_adap[i].dev.parent = &cx->dev->dev; + } + + if (read_reg(CX18_REG_I2C_2_WR) != 0x0003c02f) { + /* Reset/Unreset I2C hardware block */ + write_reg(0x10000000, 0xc71004); /* Clock select 220MHz */ + write_reg_sync(0x10001000, 0xc71024); /* Clock Enable */ + } + /* courtesy of Steven Toth <stoth@hauppauge.com> */ + write_reg_sync(0x00c00000, 0xc7001c); + mdelay(10); + write_reg_sync(0x00c000c0, 0xc7001c); + mdelay(10); + write_reg_sync(0x00c00000, 0xc7001c); + + write_reg_sync(0x00c00000, 0xc730c8); /* Set to edge-triggered intrs. */ + write_reg_sync(0x00c00000, 0xc730c4); /* Clear any stale intrs */ + + /* Hw I2C1 Clock Freq ~100kHz */ + write_reg_sync(0x00021c0f & ~4, CX18_REG_I2C_1_WR); + cx18_setscl(&cx->i2c_algo_cb_data[0], 1); + cx18_setsda(&cx->i2c_algo_cb_data[0], 1); + + /* Hw I2C2 Clock Freq ~100kHz */ + write_reg_sync(0x00021c0f & ~4, CX18_REG_I2C_2_WR); + cx18_setscl(&cx->i2c_algo_cb_data[1], 1); + cx18_setsda(&cx->i2c_algo_cb_data[1], 1); + + return i2c_bit_add_bus(&cx->i2c_adap[0]) || + i2c_bit_add_bus(&cx->i2c_adap[1]); +} + +void exit_cx18_i2c(struct cx18 *cx) +{ + int i; + CX18_DEBUG_I2C("i2c exit\n"); + write_reg(read_reg(CX18_REG_I2C_1_WR) | 4, CX18_REG_I2C_1_WR); + write_reg(read_reg(CX18_REG_I2C_2_WR) | 4, CX18_REG_I2C_2_WR); + + for (i = 0; i < 2; i++) { + i2c_del_adapter(&cx->i2c_adap[i]); + } +} + +/* + Hauppauge HVR1600 should have: + 32 cx24227 + 98 unknown + a0 eeprom + c2 tuner + e? zilog ir + */ diff --git a/drivers/media/video/cx18/cx18-i2c.h b/drivers/media/video/cx18/cx18-i2c.h new file mode 100644 index 000000000000..113c3f9a2cc0 --- /dev/null +++ b/drivers/media/video/cx18/cx18-i2c.h @@ -0,0 +1,33 @@ +/* + * cx18 I2C functions + * + * Derived from ivtv-i2c.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 + */ + +int cx18_i2c_hw_addr(struct cx18 *cx, u32 hw); +int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg); +int cx18_i2c_id(struct cx18 *cx, u32 id, unsigned int cmd, void *arg); +int cx18_call_i2c_client(struct cx18 *cx, int addr, unsigned cmd, void *arg); +void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg); +int cx18_i2c_register(struct cx18 *cx, unsigned idx); + +/* init + register i2c algo-bit adapter */ +int init_cx18_i2c(struct cx18 *cx); +void exit_cx18_i2c(struct cx18 *cx); diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c new file mode 100644 index 000000000000..dbdcb86ec5aa --- /dev/null +++ b/drivers/media/video/cx18/cx18-ioctl.c @@ -0,0 +1,851 @@ +/* + * cx18 ioctl system call + * + * Derived from ivtv-ioctl.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-version.h" +#include "cx18-mailbox.h" +#include "cx18-i2c.h" +#include "cx18-queue.h" +#include "cx18-fileops.h" +#include "cx18-vbi.h" +#include "cx18-audio.h" +#include "cx18-video.h" +#include "cx18-streams.h" +#include "cx18-ioctl.h" +#include "cx18-gpio.h" +#include "cx18-controls.h" +#include "cx18-cards.h" +#include "cx18-av-core.h" +#include <media/tveeprom.h> +#include <media/v4l2-chip-ident.h> +#include <linux/i2c-id.h> + +u16 cx18_service2vbi(int type) +{ + switch (type) { + case V4L2_SLICED_TELETEXT_B: + return CX18_SLICED_TYPE_TELETEXT_B; + case V4L2_SLICED_CAPTION_525: + return CX18_SLICED_TYPE_CAPTION_525; + case V4L2_SLICED_WSS_625: + return CX18_SLICED_TYPE_WSS_625; + case V4L2_SLICED_VPS: + return CX18_SLICED_TYPE_VPS; + default: + return 0; + } +} + +static int valid_service_line(int field, int line, int is_pal) +{ + return (is_pal && line >= 6 && (line != 23 || field == 0)) || + (!is_pal && line >= 10 && line < 22); +} + +static u16 select_service_from_set(int field, int line, u16 set, int is_pal) +{ + u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525); + int i; + + set = set & valid_set; + if (set == 0 || !valid_service_line(field, line, is_pal)) + return 0; + if (!is_pal) { + if (line == 21 && (set & V4L2_SLICED_CAPTION_525)) + return V4L2_SLICED_CAPTION_525; + } else { + if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS)) + return V4L2_SLICED_VPS; + if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625)) + return V4L2_SLICED_WSS_625; + if (line == 23) + return 0; + } + for (i = 0; i < 32; i++) { + if ((1 << i) & set) + return 1 << i; + } + return 0; +} + +void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) +{ + u16 set = fmt->service_set; + int f, l; + + fmt->service_set = 0; + for (f = 0; f < 2; f++) { + for (l = 0; l < 24; l++) + fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal); + } +} + +static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) +{ + int f, l; + u16 set = 0; + + for (f = 0; f < 2; f++) { + for (l = 0; l < 24; l++) { + fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal); + set |= fmt->service_lines[f][l]; + } + } + return set != 0; +} + +u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt) +{ + int f, l; + u16 set = 0; + + for (f = 0; f < 2; f++) { + for (l = 0; l < 24; l++) + set |= fmt->service_lines[f][l]; + } + return set; +} + +static const struct { + v4l2_std_id std; + char *name; +} enum_stds[] = { + { V4L2_STD_PAL_BG | V4L2_STD_PAL_H, "PAL-BGH" }, + { V4L2_STD_PAL_DK, "PAL-DK" }, + { V4L2_STD_PAL_I, "PAL-I" }, + { V4L2_STD_PAL_M, "PAL-M" }, + { V4L2_STD_PAL_N, "PAL-N" }, + { V4L2_STD_PAL_Nc, "PAL-Nc" }, + { V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, "SECAM-BGH" }, + { V4L2_STD_SECAM_DK, "SECAM-DK" }, + { V4L2_STD_SECAM_L, "SECAM-L" }, + { V4L2_STD_SECAM_LC, "SECAM-L'" }, + { V4L2_STD_NTSC_M, "NTSC-M" }, + { V4L2_STD_NTSC_M_JP, "NTSC-J" }, + { V4L2_STD_NTSC_M_KR, "NTSC-K" }, +}; + +static const struct v4l2_standard cx18_std_60hz = { + .frameperiod = {.numerator = 1001, .denominator = 30000}, + .framelines = 525, +}; + +static const struct v4l2_standard cx18_std_50hz = { + .frameperiod = { .numerator = 1, .denominator = 25 }, + .framelines = 625, +}; + +static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg) +{ + struct v4l2_register *regs = arg; + unsigned long flags; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (regs->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE) + return -EINVAL; + + spin_lock_irqsave(&cx18_cards_lock, flags); + if (cmd == VIDIOC_DBG_G_REGISTER) + regs->val = read_enc(regs->reg); + else + write_enc(regs->val, regs->reg); + spin_unlock_irqrestore(&cx18_cards_lock, flags); + return 0; +} + +static int cx18_get_fmt(struct cx18 *cx, int streamtype, struct v4l2_format *fmt) +{ + switch (fmt->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + fmt->fmt.pix.width = cx->params.width; + fmt->fmt.pix.height = cx->params.height; + fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; + if (streamtype == CX18_ENC_STREAM_TYPE_YUV) { + fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12; + /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */ + fmt->fmt.pix.sizeimage = + fmt->fmt.pix.height * fmt->fmt.pix.width + + fmt->fmt.pix.height * (fmt->fmt.pix.width / 2); + } else { + fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; + fmt->fmt.pix.sizeimage = 128 * 1024; + } + break; + + case V4L2_BUF_TYPE_VBI_CAPTURE: + fmt->fmt.vbi.sampling_rate = 27000000; + fmt->fmt.vbi.offset = 248; + fmt->fmt.vbi.samples_per_line = cx->vbi.raw_decoder_line_size - 4; + fmt->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; + fmt->fmt.vbi.start[0] = cx->vbi.start[0]; + fmt->fmt.vbi.start[1] = cx->vbi.start[1]; + fmt->fmt.vbi.count[0] = fmt->fmt.vbi.count[1] = cx->vbi.count; + break; + + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + { + struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; + + vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; + memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved)); + memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines)); + + cx18_av_cmd(cx, VIDIOC_G_FMT, fmt); + vbifmt->service_set = cx18_get_service_set(vbifmt); + break; + } + default: + return -EINVAL; + } + return 0; +} + +static int cx18_try_or_set_fmt(struct cx18 *cx, int streamtype, + struct v4l2_format *fmt, int set_fmt) +{ + struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; + u16 set; + + /* set window size */ + if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + int w = fmt->fmt.pix.width; + int h = fmt->fmt.pix.height; + + if (w > 720) + w = 720; + else if (w < 1) + w = 1; + if (h > (cx->is_50hz ? 576 : 480)) + h = (cx->is_50hz ? 576 : 480); + else if (h < 2) + h = 2; + cx18_get_fmt(cx, streamtype, fmt); + fmt->fmt.pix.width = w; + fmt->fmt.pix.height = h; + + if (!set_fmt || (cx->params.width == w && cx->params.height == h)) + return 0; + if (atomic_read(&cx->capturing) > 0) + return -EBUSY; + + cx->params.width = w; + cx->params.height = h; + if (w != 720 || h != (cx->is_50hz ? 576 : 480)) + cx->params.video_temporal_filter = 0; + else + cx->params.video_temporal_filter = 8; + cx18_av_cmd(cx, VIDIOC_S_FMT, fmt); + return cx18_get_fmt(cx, streamtype, fmt); + } + + /* set raw VBI format */ + if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) { + if (set_fmt && streamtype == CX18_ENC_STREAM_TYPE_VBI && + cx->vbi.sliced_in->service_set && + atomic_read(&cx->capturing) > 0) + return -EBUSY; + if (set_fmt) { + cx->vbi.sliced_in->service_set = 0; + cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in); + } + return cx18_get_fmt(cx, streamtype, fmt); + } + + /* any else but sliced VBI capture is an error */ + if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) + return -EINVAL; + + /* TODO: implement sliced VBI, for now silently return 0 */ + return 0; + + /* set sliced VBI capture format */ + vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; + memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved)); + + if (vbifmt->service_set) + cx18_expand_service_set(vbifmt, cx->is_50hz); + set = check_service_set(vbifmt, cx->is_50hz); + vbifmt->service_set = cx18_get_service_set(vbifmt); + + if (!set_fmt) + return 0; + if (set == 0) + return -EINVAL; + if (atomic_read(&cx->capturing) > 0 && cx->vbi.sliced_in->service_set == 0) + return -EBUSY; + cx18_av_cmd(cx, VIDIOC_S_FMT, fmt); + memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in)); + return 0; +} + +static int cx18_debug_ioctls(struct file *filp, unsigned int cmd, void *arg) +{ + struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data; + struct cx18 *cx = id->cx; + struct v4l2_register *reg = arg; + + switch (cmd) { + /* ioctls to allow direct access to the encoder registers for testing */ + case VIDIOC_DBG_G_REGISTER: + if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return cx18_cxc(cx, cmd, arg); + if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) + return cx18_i2c_id(cx, reg->match_chip, cmd, arg); + return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg); + + case VIDIOC_DBG_S_REGISTER: + if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return cx18_cxc(cx, cmd, arg); + if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) + return cx18_i2c_id(cx, reg->match_chip, cmd, arg); + return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg); + + case VIDIOC_G_CHIP_IDENT: { + struct v4l2_chip_ident *chip = arg; + + chip->ident = V4L2_IDENT_NONE; + chip->revision = 0; + if (reg->match_type == V4L2_CHIP_MATCH_HOST) { + if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) { + struct v4l2_chip_ident *chip = arg; + + chip->ident = V4L2_IDENT_CX23418; + } + return 0; + } + if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER) + return cx18_i2c_id(cx, reg->match_chip, cmd, arg); + if (reg->match_type == V4L2_CHIP_MATCH_I2C_ADDR) + return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg); + return -EINVAL; + } + + case VIDIOC_INT_S_AUDIO_ROUTING: { + struct v4l2_routing *route = arg; + + cx18_audio_set_route(cx, route); + break; + } + + default: + return -EINVAL; + } + return 0; +} + +int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, void *arg) +{ + struct cx18_open_id *id = NULL; + + if (filp) + id = (struct cx18_open_id *)filp->private_data; + + switch (cmd) { + case VIDIOC_G_PRIORITY: + { + enum v4l2_priority *p = arg; + + *p = v4l2_prio_max(&cx->prio); + break; + } + + case VIDIOC_S_PRIORITY: + { + enum v4l2_priority *prio = arg; + + return v4l2_prio_change(&cx->prio, &id->prio, *prio); + } + + case VIDIOC_QUERYCAP:{ + struct v4l2_capability *vcap = arg; + + memset(vcap, 0, sizeof(*vcap)); + strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver)); + strlcpy(vcap->card, cx->card_name, sizeof(vcap->card)); + strlcpy(vcap->bus_info, pci_name(cx->dev), sizeof(vcap->bus_info)); + vcap->version = CX18_DRIVER_VERSION; /* version */ + vcap->capabilities = cx->v4l2_cap; /* capabilities */ + + /* reserved.. must set to 0! */ + vcap->reserved[0] = vcap->reserved[1] = + vcap->reserved[2] = vcap->reserved[3] = 0; + break; + } + + case VIDIOC_ENUMAUDIO:{ + struct v4l2_audio *vin = arg; + + return cx18_get_audio_input(cx, vin->index, vin); + } + + case VIDIOC_G_AUDIO:{ + struct v4l2_audio *vin = arg; + + vin->index = cx->audio_input; + return cx18_get_audio_input(cx, vin->index, vin); + } + + case VIDIOC_S_AUDIO:{ + struct v4l2_audio *vout = arg; + + if (vout->index >= cx->nof_audio_inputs) + return -EINVAL; + cx->audio_input = vout->index; + cx18_audio_set_io(cx); + break; + } + + case VIDIOC_ENUMINPUT:{ + struct v4l2_input *vin = arg; + + /* set it to defaults from our table */ + return cx18_get_input(cx, vin->index, vin); + } + + case VIDIOC_TRY_FMT: + case VIDIOC_S_FMT: { + struct v4l2_format *fmt = arg; + + return cx18_try_or_set_fmt(cx, id->type, fmt, cmd == VIDIOC_S_FMT); + } + + case VIDIOC_G_FMT: { + struct v4l2_format *fmt = arg; + int type = fmt->type; + + memset(fmt, 0, sizeof(*fmt)); + fmt->type = type; + return cx18_get_fmt(cx, id->type, fmt); + } + + case VIDIOC_CROPCAP: { + struct v4l2_cropcap *cropcap = arg; + + if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + cropcap->bounds.top = cropcap->bounds.left = 0; + cropcap->bounds.width = 720; + cropcap->bounds.height = cx->is_50hz ? 576 : 480; + cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10; + cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11; + cropcap->defrect = cropcap->bounds; + return 0; + } + + case VIDIOC_S_CROP: { + struct v4l2_crop *crop = arg; + + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + return cx18_av_cmd(cx, VIDIOC_S_CROP, arg); + } + + case VIDIOC_G_CROP: { + struct v4l2_crop *crop = arg; + + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + return cx18_av_cmd(cx, VIDIOC_G_CROP, arg); + } + + case VIDIOC_ENUM_FMT: { + static struct v4l2_fmtdesc formats[] = { + { 0, 0, 0, + "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, + { 0, 0, 0, 0 } + }, + { 1, 0, V4L2_FMT_FLAG_COMPRESSED, + "MPEG", V4L2_PIX_FMT_MPEG, + { 0, 0, 0, 0 } + } + }; + struct v4l2_fmtdesc *fmt = arg; + enum v4l2_buf_type type = fmt->type; + + switch (type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + break; + default: + return -EINVAL; + } + if (fmt->index > 1) + return -EINVAL; + *fmt = formats[fmt->index]; + fmt->type = type; + return 0; + } + + case VIDIOC_G_INPUT:{ + *(int *)arg = cx->active_input; + break; + } + + case VIDIOC_S_INPUT:{ + int inp = *(int *)arg; + + if (inp < 0 || inp >= cx->nof_inputs) + return -EINVAL; + + if (inp == cx->active_input) { + CX18_DEBUG_INFO("Input unchanged\n"); + break; + } + CX18_DEBUG_INFO("Changing input from %d to %d\n", + cx->active_input, inp); + + cx->active_input = inp; + /* Set the audio input to whatever is appropriate for the + input type. */ + cx->audio_input = cx->card->video_inputs[inp].audio_index; + + /* prevent others from messing with the streams until + we're finished changing inputs. */ + cx18_mute(cx); + cx18_video_set_io(cx); + cx18_audio_set_io(cx); + cx18_unmute(cx); + break; + } + + case VIDIOC_G_FREQUENCY:{ + struct v4l2_frequency *vf = arg; + + if (vf->tuner != 0) + return -EINVAL; + cx18_call_i2c_clients(cx, cmd, arg); + break; + } + + case VIDIOC_S_FREQUENCY:{ + struct v4l2_frequency vf = *(struct v4l2_frequency *)arg; + + if (vf.tuner != 0) + return -EINVAL; + + cx18_mute(cx); + CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf.frequency); + cx18_call_i2c_clients(cx, cmd, &vf); + cx18_unmute(cx); + break; + } + + case VIDIOC_ENUMSTD:{ + struct v4l2_standard *vs = arg; + int idx = vs->index; + + if (idx < 0 || idx >= ARRAY_SIZE(enum_stds)) + return -EINVAL; + + *vs = (enum_stds[idx].std & V4L2_STD_525_60) ? + cx18_std_60hz : cx18_std_50hz; + vs->index = idx; + vs->id = enum_stds[idx].std; + strlcpy(vs->name, enum_stds[idx].name, sizeof(vs->name)); + break; + } + + case VIDIOC_G_STD:{ + *(v4l2_std_id *) arg = cx->std; + break; + } + + case VIDIOC_S_STD: { + v4l2_std_id std = *(v4l2_std_id *) arg; + + if ((std & V4L2_STD_ALL) == 0) + return -EINVAL; + + if (std == cx->std) + break; + + if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) || + atomic_read(&cx->capturing) > 0) { + /* Switching standard would turn off the radio or mess + with already running streams, prevent that by + returning EBUSY. */ + return -EBUSY; + } + + cx->std = std; + cx->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0; + cx->params.is_50hz = cx->is_50hz = !cx->is_60hz; + cx->params.width = 720; + cx->params.height = cx->is_50hz ? 576 : 480; + cx->vbi.count = cx->is_50hz ? 18 : 12; + cx->vbi.start[0] = cx->is_50hz ? 6 : 10; + cx->vbi.start[1] = cx->is_50hz ? 318 : 273; + cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284; + CX18_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)cx->std); + + /* Tuner */ + cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std); + break; + } + + case VIDIOC_S_TUNER: { /* Setting tuner can only set audio mode */ + struct v4l2_tuner *vt = arg; + + if (vt->index != 0) + return -EINVAL; + + cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt); + break; + } + + case VIDIOC_G_TUNER: { + struct v4l2_tuner *vt = arg; + + if (vt->index != 0) + return -EINVAL; + + memset(vt, 0, sizeof(*vt)); + cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt); + + if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { + strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name)); + vt->type = V4L2_TUNER_RADIO; + } else { + strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name)); + vt->type = V4L2_TUNER_ANALOG_TV; + } + break; + } + + case VIDIOC_G_SLICED_VBI_CAP: { + struct v4l2_sliced_vbi_cap *cap = arg; + int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; + int f, l; + enum v4l2_buf_type type = cap->type; + + memset(cap, 0, sizeof(*cap)); + cap->type = type; + if (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { + for (f = 0; f < 2; f++) { + for (l = 0; l < 24; l++) { + if (valid_service_line(f, l, cx->is_50hz)) + cap->service_lines[f][l] = set; + } + } + return 0; + } + return -EINVAL; + } + + case VIDIOC_ENCODER_CMD: + case VIDIOC_TRY_ENCODER_CMD: { + struct v4l2_encoder_cmd *enc = arg; + int try = cmd == VIDIOC_TRY_ENCODER_CMD; + + memset(&enc->raw, 0, sizeof(enc->raw)); + switch (enc->cmd) { + case V4L2_ENC_CMD_START: + enc->flags = 0; + if (try) + return 0; + return cx18_start_capture(id); + + case V4L2_ENC_CMD_STOP: + enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; + if (try) + return 0; + cx18_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END); + return 0; + + case V4L2_ENC_CMD_PAUSE: + enc->flags = 0; + if (try) + return 0; + if (!atomic_read(&cx->capturing)) + return -EPERM; + if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) + return 0; + cx18_mute(cx); + cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, cx18_find_handle(cx)); + break; + + case V4L2_ENC_CMD_RESUME: + enc->flags = 0; + if (try) + return 0; + if (!atomic_read(&cx->capturing)) + return -EPERM; + if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) + return 0; + cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, cx18_find_handle(cx)); + cx18_unmute(cx); + break; + default: + return -EINVAL; + } + break; + } + + case VIDIOC_LOG_STATUS: + { + struct v4l2_input vidin; + struct v4l2_audio audin; + int i; + + CX18_INFO("================= START STATUS CARD #%d =================\n", cx->num); + if (cx->hw_flags & CX18_HW_TVEEPROM) { + struct tveeprom tv; + + cx18_read_eeprom(cx, &tv); + } + cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL); + cx18_get_input(cx, cx->active_input, &vidin); + cx18_get_audio_input(cx, cx->audio_input, &audin); + CX18_INFO("Video Input: %s\n", vidin.name); + CX18_INFO("Audio Input: %s\n", audin.name); + CX18_INFO("Tuner: %s\n", + test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ? + "Radio" : "TV"); + cx2341x_log_status(&cx->params, cx->name); + CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags); + for (i = 0; i < CX18_MAX_STREAMS; i++) { + struct cx18_stream *s = &cx->streams[i]; + + if (s->v4l2dev == NULL || s->buffers == 0) + continue; + CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", + s->name, s->s_flags, + (s->buffers - s->q_free.buffers) * 100 / s->buffers, + (s->buffers * s->buf_size) / 1024, s->buffers); + } + CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n", + (long long)cx->mpg_data_received, + (long long)cx->vbi_data_inserted); + CX18_INFO("================== END STATUS CARD #%d ==================\n", cx->num); + break; + } + + default: + return -EINVAL; + } + return 0; +} + +static int cx18_v4l2_do_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, void *arg) +{ + struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data; + struct cx18 *cx = id->cx; + int ret; + + /* check priority */ + switch (cmd) { + case VIDIOC_S_CTRL: + case VIDIOC_S_STD: + case VIDIOC_S_INPUT: + case VIDIOC_S_TUNER: + case VIDIOC_S_FREQUENCY: + case VIDIOC_S_FMT: + case VIDIOC_S_CROP: + case VIDIOC_S_EXT_CTRLS: + ret = v4l2_prio_check(&cx->prio, &id->prio); + if (ret) + return ret; + } + + switch (cmd) { + case VIDIOC_DBG_G_REGISTER: + case VIDIOC_DBG_S_REGISTER: + case VIDIOC_G_CHIP_IDENT: + case VIDIOC_INT_S_AUDIO_ROUTING: + case VIDIOC_INT_RESET: + if (cx18_debug & CX18_DBGFLG_IOCTL) { + printk(KERN_INFO "cx18%d ioctl: ", cx->num); + v4l_printk_ioctl(cmd); + } + return cx18_debug_ioctls(filp, cmd, arg); + + case VIDIOC_G_PRIORITY: + case VIDIOC_S_PRIORITY: + case VIDIOC_QUERYCAP: + case VIDIOC_ENUMINPUT: + case VIDIOC_G_INPUT: + case VIDIOC_S_INPUT: + case VIDIOC_G_FMT: + case VIDIOC_S_FMT: + case VIDIOC_TRY_FMT: + case VIDIOC_ENUM_FMT: + case VIDIOC_CROPCAP: + case VIDIOC_G_CROP: + case VIDIOC_S_CROP: + case VIDIOC_G_FREQUENCY: + case VIDIOC_S_FREQUENCY: + case VIDIOC_ENUMSTD: + case VIDIOC_G_STD: + case VIDIOC_S_STD: + case VIDIOC_S_TUNER: + case VIDIOC_G_TUNER: + case VIDIOC_ENUMAUDIO: + case VIDIOC_S_AUDIO: + case VIDIOC_G_AUDIO: + case VIDIOC_G_SLICED_VBI_CAP: + case VIDIOC_LOG_STATUS: + case VIDIOC_G_ENC_INDEX: + case VIDIOC_ENCODER_CMD: + case VIDIOC_TRY_ENCODER_CMD: + if (cx18_debug & CX18_DBGFLG_IOCTL) { + printk(KERN_INFO "cx18%d ioctl: ", cx->num); + v4l_printk_ioctl(cmd); + } + return cx18_v4l2_ioctls(cx, filp, cmd, arg); + + case VIDIOC_QUERYMENU: + case VIDIOC_QUERYCTRL: + case VIDIOC_S_CTRL: + case VIDIOC_G_CTRL: + case VIDIOC_S_EXT_CTRLS: + case VIDIOC_G_EXT_CTRLS: + case VIDIOC_TRY_EXT_CTRLS: + if (cx18_debug & CX18_DBGFLG_IOCTL) { + printk(KERN_INFO "cx18%d ioctl: ", cx->num); + v4l_printk_ioctl(cmd); + } + return cx18_control_ioctls(cx, cmd, arg); + + case 0x00005401: /* Handle isatty() calls */ + return -EINVAL; + default: + return v4l_compat_translate_ioctl(inode, filp, cmd, arg, + cx18_v4l2_do_ioctl); + } + return 0; +} + +int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data; + struct cx18 *cx = id->cx; + int res; + + mutex_lock(&cx->serialize_lock); + res = video_usercopy(inode, filp, cmd, arg, cx18_v4l2_do_ioctl); + mutex_unlock(&cx->serialize_lock); + return res; +} diff --git a/drivers/media/video/cx18/cx18-ioctl.h b/drivers/media/video/cx18/cx18-ioctl.h new file mode 100644 index 000000000000..9f4c7eb2897f --- /dev/null +++ b/drivers/media/video/cx18/cx18-ioctl.h @@ -0,0 +1,30 @@ +/* + * cx18 ioctl system call + * + * Derived from ivtv-ioctl.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 + */ + +u16 cx18_service2vbi(int type); +void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); +u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt); +int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg); +int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, + void *arg); diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/video/cx18/cx18-irq.c new file mode 100644 index 000000000000..6e14f8bda559 --- /dev/null +++ b/drivers/media/video/cx18/cx18-irq.c @@ -0,0 +1,179 @@ +/* + * cx18 interrupt handling + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-firmware.h" +#include "cx18-fileops.h" +#include "cx18-queue.h" +#include "cx18-irq.h" +#include "cx18-ioctl.h" +#include "cx18-mailbox.h" +#include "cx18-vbi.h" +#include "cx18-scb.h" + +#define DMA_MAGIC_COOKIE 0x000001fe + +static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb) +{ + u32 handle = mb->args[0]; + struct cx18_stream *s = NULL; + struct cx18_buffer *buf; + u32 off; + int i; + int id; + + for (i = 0; i < CX18_MAX_STREAMS; i++) { + s = &cx->streams[i]; + if ((handle == s->handle) && (s->dvb.enabled)) + break; + if (s->v4l2dev && handle == s->handle) + break; + } + if (i == CX18_MAX_STREAMS) { + CX18_WARN("DMA done for unknown handle %d for stream %s\n", + handle, s->name); + mb->error = CXERR_NOT_OPEN; + mb->cmd = 0; + cx18_mb_ack(cx, mb); + return; + } + + off = mb->args[1]; + if (mb->args[2] != 1) + CX18_WARN("Ack struct = %d for %s\n", + mb->args[2], s->name); + id = read_enc(off); + buf = cx18_queue_find_buf(s, id, read_enc(off + 4)); + CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id); + if (buf) { + cx18_buf_sync_for_cpu(s, buf); + if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) { + /* process the buffer here */ + CX18_DEBUG_HI_DMA("TS recv and sent bytesused=%d\n", + buf->bytesused); + + dvb_dmx_swfilter(&s->dvb.demux, buf->buf, + buf->bytesused); + + cx18_buf_sync_for_device(s, buf); + cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, + (void *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, + 1, buf->id, s->buf_size); + } else + set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags); + } else { + CX18_WARN("Could not find buf %d for stream %s\n", + read_enc(off), s->name); + } + mb->error = 0; + mb->cmd = 0; + cx18_mb_ack(cx, mb); + wake_up(&cx->dma_waitq); + if (s->id != -1) + wake_up(&s->waitq); +} + +static void epu_debug(struct cx18 *cx, struct cx18_mailbox *mb) +{ + char str[256] = { 0 }; + char *p; + + if (mb->args[1]) { + setup_page(mb->args[1]); + memcpy_fromio(str, cx->enc_mem + mb->args[1], 252); + str[252] = 0; + } + cx18_mb_ack(cx, mb); + CX18_DEBUG_INFO("%x %s\n", mb->args[0], str); + p = strchr(str, '.'); + if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str) + CX18_INFO("FW version: %s\n", p - 1); +} + +static void hpu_cmd(struct cx18 *cx, u32 sw1) +{ + struct cx18_mailbox mb; + + if (sw1 & IRQ_CPU_TO_EPU) { + memcpy_fromio(&mb, &cx->scb->cpu2epu_mb, sizeof(mb)); + mb.error = 0; + + switch (mb.cmd) { + case CX18_EPU_DMA_DONE: + epu_dma_done(cx, &mb); + break; + case CX18_EPU_DEBUG: + epu_debug(cx, &mb); + break; + default: + CX18_WARN("Unexpected mailbox command %08x\n", mb.cmd); + break; + } + } + if (sw1 & (IRQ_APU_TO_EPU | IRQ_HPU_TO_EPU)) + CX18_WARN("Unexpected interrupt %08x\n", sw1); +} + +irqreturn_t cx18_irq_handler(int irq, void *dev_id) +{ + struct cx18 *cx = (struct cx18 *)dev_id; + u32 sw1, sw1_mask; + u32 sw2, sw2_mask; + u32 hw2, hw2_mask; + + spin_lock(&cx->dma_reg_lock); + + hw2_mask = read_reg(HW2_INT_MASK5_PCI); + hw2 = read_reg(HW2_INT_CLR_STATUS) & hw2_mask; + sw2_mask = read_reg(SW2_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU_ACK; + sw2 = read_reg(SW2_INT_STATUS) & sw2_mask; + sw1_mask = read_reg(SW1_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU; + sw1 = read_reg(SW1_INT_STATUS) & sw1_mask; + + write_reg(sw2&sw2_mask, SW2_INT_STATUS); + write_reg(sw1&sw1_mask, SW1_INT_STATUS); + write_reg(hw2&hw2_mask, HW2_INT_CLR_STATUS); + + if (sw1 || sw2 || hw2) + CX18_DEBUG_HI_IRQ("SW1: %x SW2: %x HW2: %x\n", sw1, sw2, hw2); + + /* To do: interrupt-based I2C handling + if (hw2 & 0x00c00000) { + } + */ + + if (sw2) { + if (sw2 & (cx->scb->cpu2hpu_irq_ack | cx->scb->cpu2epu_irq_ack)) + wake_up(&cx->mb_cpu_waitq); + if (sw2 & (cx->scb->apu2hpu_irq_ack | cx->scb->apu2epu_irq_ack)) + wake_up(&cx->mb_apu_waitq); + if (sw2 & cx->scb->epu2hpu_irq_ack) + wake_up(&cx->mb_epu_waitq); + if (sw2 & cx->scb->hpu2epu_irq_ack) + wake_up(&cx->mb_hpu_waitq); + } + + if (sw1) + hpu_cmd(cx, sw1); + spin_unlock(&cx->dma_reg_lock); + + return (hw2 | sw1 | sw2) ? IRQ_HANDLED : IRQ_NONE; +} diff --git a/drivers/media/video/cx18/cx18-irq.h b/drivers/media/video/cx18/cx18-irq.h new file mode 100644 index 000000000000..379f704f5cba --- /dev/null +++ b/drivers/media/video/cx18/cx18-irq.h @@ -0,0 +1,37 @@ +/* + * cx18 interrupt handling + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 + */ + +#define HW2_I2C1_INT (1 << 22) +#define HW2_I2C2_INT (1 << 23) +#define HW2_INT_CLR_STATUS 0xc730c4 +#define HW2_INT_MASK5_PCI 0xc730e4 +#define SW1_INT_SET 0xc73100 +#define SW1_INT_STATUS 0xc73104 +#define SW1_INT_ENABLE_PCI 0xc7311c +#define SW2_INT_SET 0xc73140 +#define SW2_INT_STATUS 0xc73144 +#define SW2_INT_ENABLE_PCI 0xc7315c + +irqreturn_t cx18_irq_handler(int irq, void *dev_id); + +void cx18_irq_work_handler(struct work_struct *work); +void cx18_dma_stream_dec_prepare(struct cx18_stream *s, u32 offset, int lock); +void cx18_unfinished_dma(unsigned long arg); diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c new file mode 100644 index 000000000000..0c5f328bca54 --- /dev/null +++ b/drivers/media/video/cx18/cx18-mailbox.c @@ -0,0 +1,372 @@ +/* + * cx18 mailbox functions + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 <stdarg.h> + +#include "cx18-driver.h" +#include "cx18-scb.h" +#include "cx18-irq.h" +#include "cx18-mailbox.h" + +#define API_FAST (1 << 2) /* Short timeout */ +#define API_SLOW (1 << 3) /* Additional 300ms timeout */ + +#define APU 0 +#define CPU 1 +#define EPU 2 +#define HPU 3 + +struct cx18_api_info { + u32 cmd; + u8 flags; /* Flags, see above */ + u8 rpu; /* Processing unit */ + const char *name; /* The name of the command */ +}; + +#define API_ENTRY(rpu, x, f) { (x), (f), (rpu), #x } + +static const struct cx18_api_info api_info[] = { + /* MPEG encoder API */ + API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0), + API_ENTRY(CPU, CX18_EPU_DEBUG, 0), + API_ENTRY(CPU, CX18_CREATE_TASK, 0), + API_ENTRY(CPU, CX18_DESTROY_TASK, 0), + API_ENTRY(CPU, CX18_CPU_CAPTURE_START, API_SLOW), + API_ENTRY(CPU, CX18_CPU_CAPTURE_STOP, API_SLOW), + API_ENTRY(CPU, CX18_CPU_CAPTURE_PAUSE, 0), + API_ENTRY(CPU, CX18_CPU_CAPTURE_RESUME, 0), + API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0), + API_ENTRY(CPU, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 0), + API_ENTRY(CPU, CX18_CPU_SET_VIDEO_IN, 0), + API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RATE, 0), + API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RESOLUTION, 0), + API_ENTRY(CPU, CX18_CPU_SET_FILTER_PARAM, 0), + API_ENTRY(CPU, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 0), + API_ENTRY(CPU, CX18_CPU_SET_MEDIAN_CORING, 0), + API_ENTRY(CPU, CX18_CPU_SET_INDEXTABLE, 0), + API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PARAMETERS, 0), + API_ENTRY(CPU, CX18_CPU_SET_VIDEO_MUTE, 0), + API_ENTRY(CPU, CX18_CPU_SET_AUDIO_MUTE, 0), + API_ENTRY(CPU, CX18_CPU_SET_MISC_PARAMETERS, 0), + API_ENTRY(CPU, CX18_CPU_SET_RAW_VBI_PARAM, API_SLOW), + API_ENTRY(CPU, CX18_CPU_SET_CAPTURE_LINE_NO, 0), + API_ENTRY(CPU, CX18_CPU_SET_COPYRIGHT, 0), + API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PID, 0), + API_ENTRY(CPU, CX18_CPU_SET_VIDEO_PID, 0), + API_ENTRY(CPU, CX18_CPU_SET_VER_CROP_LINE, 0), + API_ENTRY(CPU, CX18_CPU_SET_GOP_STRUCTURE, 0), + API_ENTRY(CPU, CX18_CPU_SET_SCENE_CHANGE_DETECTION, 0), + API_ENTRY(CPU, CX18_CPU_SET_ASPECT_RATIO, 0), + API_ENTRY(CPU, CX18_CPU_SET_SKIP_INPUT_FRAME, 0), + API_ENTRY(CPU, CX18_CPU_SET_SLICED_VBI_PARAM, 0), + API_ENTRY(CPU, CX18_CPU_SET_USERDATA_PLACE_HOLDER, 0), + API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0), + API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0), + API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST), + API_ENTRY(0, 0, 0), +}; + +static const struct cx18_api_info *find_api_info(u32 cmd) +{ + int i; + + for (i = 0; api_info[i].cmd; i++) + if (api_info[i].cmd == cmd) + return &api_info[i]; + return NULL; +} + +static struct cx18_mailbox *cx18_mb_is_complete(struct cx18 *cx, int rpu, + u32 *state, u32 *irq, u32 *req) +{ + struct cx18_mailbox *mb = NULL; + int wait_count = 0; + u32 ack; + + switch (rpu) { + case APU: + mb = &cx->scb->epu2apu_mb; + *state = readl(&cx->scb->apu_state); + *irq = readl(&cx->scb->epu2apu_irq); + break; + + case CPU: + mb = &cx->scb->epu2cpu_mb; + *state = readl(&cx->scb->cpu_state); + *irq = readl(&cx->scb->epu2cpu_irq); + break; + + case HPU: + mb = &cx->scb->epu2hpu_mb; + *state = readl(&cx->scb->hpu_state); + *irq = readl(&cx->scb->epu2hpu_irq); + break; + } + + if (mb == NULL) + return mb; + + do { + *req = readl(&mb->request); + ack = readl(&mb->ack); + wait_count++; + } while (*req != ack && wait_count < 600); + + if (*req == ack) { + (*req)++; + if (*req == 0 || *req == 0xffffffff) + *req = 1; + return mb; + } + return NULL; +} + +long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb) +{ + const struct cx18_api_info *info = find_api_info(mb->cmd); + struct cx18_mailbox *ack_mb; + u32 ack_irq; + u8 rpu = CPU; + + if (info == NULL && mb->cmd) { + CX18_WARN("Cannot ack unknown command %x\n", mb->cmd); + return -EINVAL; + } + if (info) + rpu = info->rpu; + + switch (rpu) { + case HPU: + ack_irq = IRQ_EPU_TO_HPU_ACK; + ack_mb = &cx->scb->hpu2epu_mb; + break; + case APU: + ack_irq = IRQ_EPU_TO_APU_ACK; + ack_mb = &cx->scb->apu2epu_mb; + break; + case CPU: + ack_irq = IRQ_EPU_TO_CPU_ACK; + ack_mb = &cx->scb->cpu2epu_mb; + break; + default: + CX18_WARN("Unknown RPU for command %x\n", mb->cmd); + return -EINVAL; + } + + setup_page(SCB_OFFSET); + write_sync(mb->request, &ack_mb->ack); + write_reg(ack_irq, SW2_INT_SET); + return 0; +} + + +static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) +{ + const struct cx18_api_info *info = find_api_info(cmd); + u32 state = 0, irq = 0, req, oldreq, err; + struct cx18_mailbox *mb; + wait_queue_head_t *waitq; + int timeout = 100; + int cnt = 0; + int sig = 0; + int i; + + if (info == NULL) { + CX18_WARN("unknown cmd %x\n", cmd); + return -EINVAL; + } + + if (cmd == CX18_CPU_DE_SET_MDL) + CX18_DEBUG_HI_API("%s\n", info->name); + else + CX18_DEBUG_API("%s\n", info->name); + setup_page(SCB_OFFSET); + mb = cx18_mb_is_complete(cx, info->rpu, &state, &irq, &req); + + if (mb == NULL) { + CX18_ERR("mb %s busy\n", info->name); + return -EBUSY; + } + + oldreq = req - 1; + writel(cmd, &mb->cmd); + for (i = 0; i < args; i++) + writel(data[i], &mb->args[i]); + writel(0, &mb->error); + writel(req, &mb->request); + + switch (info->rpu) { + case APU: waitq = &cx->mb_apu_waitq; break; + case CPU: waitq = &cx->mb_cpu_waitq; break; + case EPU: waitq = &cx->mb_epu_waitq; break; + case HPU: waitq = &cx->mb_hpu_waitq; break; + default: return -EINVAL; + } + if (info->flags & API_FAST) + timeout /= 2; + write_reg(irq, SW1_INT_SET); + + while (!sig && readl(&mb->ack) != readl(&mb->request) && cnt < 660) { + if (cnt > 200 && !in_atomic()) + sig = cx18_msleep_timeout(10, 1); + cnt++; + } + if (sig) + return -EINTR; + if (cnt == 660) { + writel(oldreq, &mb->request); + CX18_ERR("mb %s failed\n", info->name); + return -EINVAL; + } + for (i = 0; i < MAX_MB_ARGUMENTS; i++) + data[i] = readl(&mb->args[i]); + err = readl(&mb->error); + if (!in_atomic() && (info->flags & API_SLOW)) + cx18_msleep_timeout(300, 0); + if (err) + CX18_DEBUG_API("mailbox error %08x for command %s\n", err, + info->name); + return err ? -EIO : 0; +} + +int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]) +{ + int res = cx18_api_call(cx, cmd, args, data); + + /* Allow a single retry, probably already too late though. + If there is no free mailbox then that is usually an indication + of a more serious problem. */ + return (res == -EBUSY) ? cx18_api_call(cx, cmd, args, data) : res; +} + +static int cx18_set_filter_param(struct cx18_stream *s) +{ + struct cx18 *cx = s->cx; + u32 mode; + int ret; + + mode = (cx->filter_mode & 1) ? 2 : (cx->spatial_strength ? 1 : 0); + ret = cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4, + s->handle, 1, mode, cx->spatial_strength); + mode = (cx->filter_mode & 2) ? 2 : (cx->temporal_strength ? 1 : 0); + ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4, + s->handle, 0, mode, cx->temporal_strength); + ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4, + s->handle, 2, cx->filter_mode >> 2, 0); + return ret; +} + +int cx18_api_func(void *priv, u32 cmd, int in, int out, + u32 data[CX2341X_MBOX_MAX_DATA]) +{ + struct cx18 *cx = priv; + struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_MPG]; + + switch (cmd) { + case CX2341X_ENC_SET_OUTPUT_PORT: + return 0; + case CX2341X_ENC_SET_FRAME_RATE: + return cx18_vapi(cx, CX18_CPU_SET_VIDEO_IN, 6, + s->handle, 0, 0, 0, 0, data[0]); + case CX2341X_ENC_SET_FRAME_SIZE: + return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RESOLUTION, 3, + s->handle, data[1], data[0]); + case CX2341X_ENC_SET_STREAM_TYPE: + return cx18_vapi(cx, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 2, + s->handle, data[0]); + case CX2341X_ENC_SET_ASPECT_RATIO: + return cx18_vapi(cx, CX18_CPU_SET_ASPECT_RATIO, 2, + s->handle, data[0]); + + case CX2341X_ENC_SET_GOP_PROPERTIES: + return cx18_vapi(cx, CX18_CPU_SET_GOP_STRUCTURE, 3, + s->handle, data[0], data[1]); + case CX2341X_ENC_SET_GOP_CLOSURE: + return 0; + case CX2341X_ENC_SET_AUDIO_PROPERTIES: + return cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2, + s->handle, data[0]); + case CX2341X_ENC_MUTE_AUDIO: + return cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, + s->handle, data[0]); + case CX2341X_ENC_SET_BIT_RATE: + return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RATE, 5, + s->handle, data[0], data[1], data[2], data[3]); + case CX2341X_ENC_MUTE_VIDEO: + return cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, + s->handle, data[0]); + case CX2341X_ENC_SET_FRAME_DROP_RATE: + return cx18_vapi(cx, CX18_CPU_SET_SKIP_INPUT_FRAME, 2, + s->handle, data[0]); + case CX2341X_ENC_MISC: + return cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 4, + s->handle, data[0], data[1], data[2]); + case CX2341X_ENC_SET_DNR_FILTER_MODE: + cx->filter_mode = (data[0] & 3) | (data[1] << 2); + return cx18_set_filter_param(s); + case CX2341X_ENC_SET_DNR_FILTER_PROPS: + cx->spatial_strength = data[0]; + cx->temporal_strength = data[1]; + return cx18_set_filter_param(s); + case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE: + return cx18_vapi(cx, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 3, + s->handle, data[0], data[1]); + case CX2341X_ENC_SET_CORING_LEVELS: + return cx18_vapi(cx, CX18_CPU_SET_MEDIAN_CORING, 5, + s->handle, data[0], data[1], data[2], data[3]); + } + CX18_WARN("Unknown cmd %x\n", cmd); + return 0; +} + +int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], + u32 cmd, int args, ...) +{ + va_list ap; + int i; + + va_start(ap, args); + for (i = 0; i < args; i++) + data[i] = va_arg(ap, u32); + va_end(ap); + return cx18_api(cx, cmd, args, data); +} + +int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...) +{ + u32 data[MAX_MB_ARGUMENTS]; + va_list ap; + int i; + + if (cx == NULL) { + CX18_ERR("cx == NULL (cmd=%x)\n", cmd); + return 0; + } + if (args > MAX_MB_ARGUMENTS) { + CX18_ERR("args too big (cmd=%x)\n", cmd); + args = MAX_MB_ARGUMENTS; + } + va_start(ap, args); + for (i = 0; i < args; i++) + data[i] = va_arg(ap, u32); + va_end(ap); + return cx18_api(cx, cmd, args, data); +} diff --git a/drivers/media/video/cx18/cx18-mailbox.h b/drivers/media/video/cx18/cx18-mailbox.h new file mode 100644 index 000000000000..d995641536b3 --- /dev/null +++ b/drivers/media/video/cx18/cx18-mailbox.h @@ -0,0 +1,73 @@ +/* + * cx18 mailbox functions + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 _CX18_MAILBOX_H_ +#define _CX18_MAILBOX_H_ + +/* mailbox max args */ +#define MAX_MB_ARGUMENTS 6 +/* compatibility, should be same as the define in cx2341x.h */ +#define CX2341X_MBOX_MAX_DATA 16 + +#define MB_RESERVED_HANDLE_0 0 +#define MB_RESERVED_HANDLE_1 0xFFFFFFFF + +struct cx18; + +/* The cx18_mailbox struct is the mailbox structure which is used for passing + messages between processors */ +struct cx18_mailbox { + /* The sender sets a handle in 'request' after he fills the command. The + 'request' should be different than 'ack'. The sender, also, generates + an interrupt on XPU2YPU_irq where XPU is the sender and YPU is the + receiver. */ + u32 request; + /* The receiver detects a new command when 'req' is different than 'ack'. + He sets 'ack' to the same value as 'req' to clear the command. He, also, + generates an interrupt on YPU2XPU_irq where XPU is the sender and YPU + is the receiver. */ + u32 ack; + u32 reserved[6]; + /* 'cmd' identifies the command. The list of these commands are in + cx23418.h */ + u32 cmd; + /* Each command can have up to 6 arguments */ + u32 args[MAX_MB_ARGUMENTS]; + /* The return code can be one of the codes in the file cx23418.h. If the + command is completed successfuly, the error will be ERR_SYS_SUCCESS. + If it is pending, the code is ERR_SYS_PENDING. If it failed, the error + code would indicate the task from which the error originated and will + be one of the errors in cx23418.h. In that case, the following + applies ((error & 0xff) != 0). + If the command is pending, the return will be passed in a MB from the + receiver to the sender. 'req' will be returned in args[0] */ + u32 error; +}; + +int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]); +int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd, + int args, ...); +int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...); +int cx18_api_func(void *priv, u32 cmd, int in, int out, + u32 data[CX2341X_MBOX_MAX_DATA]); +long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb); + +#endif diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c new file mode 100644 index 000000000000..65af1bb507ca --- /dev/null +++ b/drivers/media/video/cx18/cx18-queue.c @@ -0,0 +1,282 @@ +/* + * cx18 buffer queues + * + * Derived from ivtv-queue.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-streams.h" +#include "cx18-queue.h" +#include "cx18-scb.h" + +int cx18_buf_copy_from_user(struct cx18_stream *s, struct cx18_buffer *buf, + const char __user *src, int copybytes) +{ + if (s->buf_size - buf->bytesused < copybytes) + copybytes = s->buf_size - buf->bytesused; + if (copy_from_user(buf->buf + buf->bytesused, src, copybytes)) + return -EFAULT; + buf->bytesused += copybytes; + return copybytes; +} + +void cx18_buf_swap(struct cx18_buffer *buf) +{ + int i; + + for (i = 0; i < buf->bytesused; i += 4) + swab32s((u32 *)(buf->buf + i)); +} + +void cx18_queue_init(struct cx18_queue *q) +{ + INIT_LIST_HEAD(&q->list); + q->buffers = 0; + q->length = 0; + q->bytesused = 0; +} + +void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, + struct cx18_queue *q) +{ + unsigned long flags = 0; + + /* clear the buffer if it is going to be enqueued to the free queue */ + if (q == &s->q_free) { + buf->bytesused = 0; + buf->readpos = 0; + buf->b_flags = 0; + } + spin_lock_irqsave(&s->qlock, flags); + list_add_tail(&buf->list, &q->list); + q->buffers++; + q->length += s->buf_size; + q->bytesused += buf->bytesused - buf->readpos; + spin_unlock_irqrestore(&s->qlock, flags); +} + +struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) +{ + struct cx18_buffer *buf = NULL; + unsigned long flags = 0; + + spin_lock_irqsave(&s->qlock, flags); + if (!list_empty(&q->list)) { + buf = list_entry(q->list.next, struct cx18_buffer, list); + list_del_init(q->list.next); + q->buffers--; + q->length -= s->buf_size; + q->bytesused -= buf->bytesused - buf->readpos; + } + spin_unlock_irqrestore(&s->qlock, flags); + return buf; +} + +struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id, + u32 bytesused) +{ + struct cx18 *cx = s->cx; + struct list_head *p; + + list_for_each(p, &s->q_free.list) { + struct cx18_buffer *buf = + list_entry(p, struct cx18_buffer, list); + + if (buf->id != id) + continue; + buf->bytesused = bytesused; + /* the transport buffers are handled differently, + so there is no need to move them to the full queue */ + if (s->type == CX18_ENC_STREAM_TYPE_TS) + return buf; + s->q_free.buffers--; + s->q_free.length -= s->buf_size; + s->q_full.buffers++; + s->q_full.length += s->buf_size; + s->q_full.bytesused += buf->bytesused; + list_move_tail(&buf->list, &s->q_full.list); + return buf; + } + CX18_ERR("Cannot find buffer %d for stream %s\n", id, s->name); + return NULL; +} + +static void cx18_queue_move_buf(struct cx18_stream *s, struct cx18_queue *from, + struct cx18_queue *to, int clear, int full) +{ + struct cx18_buffer *buf = + list_entry(from->list.next, struct cx18_buffer, list); + + list_move_tail(from->list.next, &to->list); + from->buffers--; + from->length -= s->buf_size; + from->bytesused -= buf->bytesused - buf->readpos; + /* special handling for q_free */ + if (clear) + buf->bytesused = buf->readpos = buf->b_flags = 0; + else if (full) { + /* special handling for stolen buffers, assume + all bytes are used. */ + buf->bytesused = s->buf_size; + buf->readpos = buf->b_flags = 0; + } + to->buffers++; + to->length += s->buf_size; + to->bytesused += buf->bytesused - buf->readpos; +} + +/* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'. + If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'. + If 'steal' != NULL, then buffers may also taken from that queue if + needed. + + The buffer is automatically cleared if it goes to the free queue. It is + also cleared if buffers need to be taken from the 'steal' queue and + the 'from' queue is the free queue. + + When 'from' is q_free, then needed_bytes is compared to the total + available buffer length, otherwise needed_bytes is compared to the + bytesused value. For the 'steal' queue the total available buffer + length is always used. + + -ENOMEM is returned if the buffers could not be obtained, 0 if all + buffers where obtained from the 'from' list and if non-zero then + the number of stolen buffers is returned. */ +int cx18_queue_move(struct cx18_stream *s, struct cx18_queue *from, + struct cx18_queue *steal, struct cx18_queue *to, int needed_bytes) +{ + unsigned long flags; + int rc = 0; + int from_free = from == &s->q_free; + int to_free = to == &s->q_free; + int bytes_available; + + spin_lock_irqsave(&s->qlock, flags); + if (needed_bytes == 0) { + from_free = 1; + needed_bytes = from->length; + } + + bytes_available = from_free ? from->length : from->bytesused; + bytes_available += steal ? steal->length : 0; + + if (bytes_available < needed_bytes) { + spin_unlock_irqrestore(&s->qlock, flags); + return -ENOMEM; + } + if (from_free) { + u32 old_length = to->length; + + while (to->length - old_length < needed_bytes) { + if (list_empty(&from->list)) + from = steal; + if (from == steal) + rc++; /* keep track of 'stolen' buffers */ + cx18_queue_move_buf(s, from, to, 1, 0); + } + } else { + u32 old_bytesused = to->bytesused; + + while (to->bytesused - old_bytesused < needed_bytes) { + if (list_empty(&from->list)) + from = steal; + if (from == steal) + rc++; /* keep track of 'stolen' buffers */ + cx18_queue_move_buf(s, from, to, to_free, rc); + } + } + spin_unlock_irqrestore(&s->qlock, flags); + return rc; +} + +void cx18_flush_queues(struct cx18_stream *s) +{ + cx18_queue_move(s, &s->q_io, NULL, &s->q_free, 0); + cx18_queue_move(s, &s->q_full, NULL, &s->q_free, 0); +} + +int cx18_stream_alloc(struct cx18_stream *s) +{ + struct cx18 *cx = s->cx; + int i; + + if (s->buffers == 0) + return 0; + + CX18_DEBUG_INFO("Allocate %s stream: %d x %d buffers (%dkB total)\n", + s->name, s->buffers, s->buf_size, + s->buffers * s->buf_size / 1024); + + if (((char *)&cx->scb->cpu_mdl[cx->mdl_offset + s->buffers] - + (char *)cx->scb) > SCB_RESERVED_SIZE) { + unsigned bufsz = (((char *)cx->scb) + SCB_RESERVED_SIZE - + ((char *)cx->scb->cpu_mdl)); + + CX18_ERR("Too many buffers, cannot fit in SCB area\n"); + CX18_ERR("Max buffers = %zd\n", + bufsz / sizeof(struct cx18_mdl)); + return -ENOMEM; + } + + s->mdl_offset = cx->mdl_offset; + + /* allocate stream buffers. Initially all buffers are in q_free. */ + for (i = 0; i < s->buffers; i++) { + struct cx18_buffer *buf = + kzalloc(sizeof(struct cx18_buffer), GFP_KERNEL); + + if (buf == NULL) + break; + buf->buf = kmalloc(s->buf_size, GFP_KERNEL); + if (buf->buf == NULL) { + kfree(buf); + break; + } + buf->id = cx->buffer_id++; + INIT_LIST_HEAD(&buf->list); + buf->dma_handle = pci_map_single(s->cx->dev, + buf->buf, s->buf_size, s->dma); + cx18_buf_sync_for_cpu(s, buf); + cx18_enqueue(s, buf, &s->q_free); + } + if (i == s->buffers) { + cx->mdl_offset += s->buffers; + return 0; + } + CX18_ERR("Couldn't allocate buffers for %s stream\n", s->name); + cx18_stream_free(s); + return -ENOMEM; +} + +void cx18_stream_free(struct cx18_stream *s) +{ + struct cx18_buffer *buf; + + /* move all buffers to q_free */ + cx18_flush_queues(s); + + /* empty q_free */ + while ((buf = cx18_dequeue(s, &s->q_free))) { + pci_unmap_single(s->cx->dev, buf->dma_handle, + s->buf_size, s->dma); + kfree(buf->buf); + kfree(buf); + } +} diff --git a/drivers/media/video/cx18/cx18-queue.h b/drivers/media/video/cx18/cx18-queue.h new file mode 100644 index 000000000000..f86c8a6fa6e7 --- /dev/null +++ b/drivers/media/video/cx18/cx18-queue.h @@ -0,0 +1,59 @@ +/* + * cx18 buffer queues + * + * Derived from ivtv-queue.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 + */ + +#define CX18_DMA_UNMAPPED ((u32) -1) + +/* cx18_buffer utility functions */ + +static inline void cx18_buf_sync_for_cpu(struct cx18_stream *s, + struct cx18_buffer *buf) +{ + pci_dma_sync_single_for_cpu(s->cx->dev, buf->dma_handle, + s->buf_size, s->dma); +} + +static inline void cx18_buf_sync_for_device(struct cx18_stream *s, + struct cx18_buffer *buf) +{ + pci_dma_sync_single_for_device(s->cx->dev, buf->dma_handle, + s->buf_size, s->dma); +} + +int cx18_buf_copy_from_user(struct cx18_stream *s, struct cx18_buffer *buf, + const char __user *src, int copybytes); +void cx18_buf_swap(struct cx18_buffer *buf); + +/* cx18_queue utility functions */ +void cx18_queue_init(struct cx18_queue *q); +void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, + struct cx18_queue *q); +struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q); +int cx18_queue_move(struct cx18_stream *s, struct cx18_queue *from, + struct cx18_queue *steal, struct cx18_queue *to, int needed_bytes); +struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id, + u32 bytesused); +void cx18_flush_queues(struct cx18_stream *s); + +/* cx18_stream utility functions */ +int cx18_stream_alloc(struct cx18_stream *s); +void cx18_stream_free(struct cx18_stream *s); diff --git a/drivers/media/video/cx18/cx18-scb.c b/drivers/media/video/cx18/cx18-scb.c new file mode 100644 index 000000000000..30bc803e30da --- /dev/null +++ b/drivers/media/video/cx18/cx18-scb.c @@ -0,0 +1,121 @@ +/* + * cx18 System Control Block initialization + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-scb.h" + +void cx18_init_scb(struct cx18 *cx) +{ + setup_page(SCB_OFFSET); + memset_io(cx->scb, 0, 0x10000); + + writel(IRQ_APU_TO_CPU, &cx->scb->apu2cpu_irq); + writel(IRQ_CPU_TO_APU_ACK, &cx->scb->cpu2apu_irq_ack); + writel(IRQ_HPU_TO_CPU, &cx->scb->hpu2cpu_irq); + writel(IRQ_CPU_TO_HPU_ACK, &cx->scb->cpu2hpu_irq_ack); + writel(IRQ_PPU_TO_CPU, &cx->scb->ppu2cpu_irq); + writel(IRQ_CPU_TO_PPU_ACK, &cx->scb->cpu2ppu_irq_ack); + writel(IRQ_EPU_TO_CPU, &cx->scb->epu2cpu_irq); + writel(IRQ_CPU_TO_EPU_ACK, &cx->scb->cpu2epu_irq_ack); + + writel(IRQ_CPU_TO_APU, &cx->scb->cpu2apu_irq); + writel(IRQ_APU_TO_CPU_ACK, &cx->scb->apu2cpu_irq_ack); + writel(IRQ_HPU_TO_APU, &cx->scb->hpu2apu_irq); + writel(IRQ_APU_TO_HPU_ACK, &cx->scb->apu2hpu_irq_ack); + writel(IRQ_PPU_TO_APU, &cx->scb->ppu2apu_irq); + writel(IRQ_APU_TO_PPU_ACK, &cx->scb->apu2ppu_irq_ack); + writel(IRQ_EPU_TO_APU, &cx->scb->epu2apu_irq); + writel(IRQ_APU_TO_EPU_ACK, &cx->scb->apu2epu_irq_ack); + + writel(IRQ_CPU_TO_HPU, &cx->scb->cpu2hpu_irq); + writel(IRQ_HPU_TO_CPU_ACK, &cx->scb->hpu2cpu_irq_ack); + writel(IRQ_APU_TO_HPU, &cx->scb->apu2hpu_irq); + writel(IRQ_HPU_TO_APU_ACK, &cx->scb->hpu2apu_irq_ack); + writel(IRQ_PPU_TO_HPU, &cx->scb->ppu2hpu_irq); + writel(IRQ_HPU_TO_PPU_ACK, &cx->scb->hpu2ppu_irq_ack); + writel(IRQ_EPU_TO_HPU, &cx->scb->epu2hpu_irq); + writel(IRQ_HPU_TO_EPU_ACK, &cx->scb->hpu2epu_irq_ack); + + writel(IRQ_CPU_TO_PPU, &cx->scb->cpu2ppu_irq); + writel(IRQ_PPU_TO_CPU_ACK, &cx->scb->ppu2cpu_irq_ack); + writel(IRQ_APU_TO_PPU, &cx->scb->apu2ppu_irq); + writel(IRQ_PPU_TO_APU_ACK, &cx->scb->ppu2apu_irq_ack); + writel(IRQ_HPU_TO_PPU, &cx->scb->hpu2ppu_irq); + writel(IRQ_PPU_TO_HPU_ACK, &cx->scb->ppu2hpu_irq_ack); + writel(IRQ_EPU_TO_PPU, &cx->scb->epu2ppu_irq); + writel(IRQ_PPU_TO_EPU_ACK, &cx->scb->ppu2epu_irq_ack); + + writel(IRQ_CPU_TO_EPU, &cx->scb->cpu2epu_irq); + writel(IRQ_EPU_TO_CPU_ACK, &cx->scb->epu2cpu_irq_ack); + writel(IRQ_APU_TO_EPU, &cx->scb->apu2epu_irq); + writel(IRQ_EPU_TO_APU_ACK, &cx->scb->epu2apu_irq_ack); + writel(IRQ_HPU_TO_EPU, &cx->scb->hpu2epu_irq); + writel(IRQ_EPU_TO_HPU_ACK, &cx->scb->epu2hpu_irq_ack); + writel(IRQ_PPU_TO_EPU, &cx->scb->ppu2epu_irq); + writel(IRQ_EPU_TO_PPU_ACK, &cx->scb->epu2ppu_irq_ack); + + writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2cpu_mb), + &cx->scb->apu2cpu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2cpu_mb), + &cx->scb->hpu2cpu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2cpu_mb), + &cx->scb->ppu2cpu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2cpu_mb), + &cx->scb->epu2cpu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2apu_mb), + &cx->scb->cpu2apu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2apu_mb), + &cx->scb->hpu2apu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2apu_mb), + &cx->scb->ppu2apu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2apu_mb), + &cx->scb->epu2apu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2hpu_mb), + &cx->scb->cpu2hpu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2hpu_mb), + &cx->scb->apu2hpu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2hpu_mb), + &cx->scb->ppu2hpu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2hpu_mb), + &cx->scb->epu2hpu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2ppu_mb), + &cx->scb->cpu2ppu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2ppu_mb), + &cx->scb->apu2ppu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2ppu_mb), + &cx->scb->hpu2ppu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2ppu_mb), + &cx->scb->epu2ppu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2epu_mb), + &cx->scb->cpu2epu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2epu_mb), + &cx->scb->apu2epu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2epu_mb), + &cx->scb->hpu2epu_mb_offset); + writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2epu_mb), + &cx->scb->ppu2epu_mb_offset); + + writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu_state), + &cx->scb->ipc_offset); + + writel(1, &cx->scb->hpu_state); + writel(1, &cx->scb->epu_state); +} diff --git a/drivers/media/video/cx18/cx18-scb.h b/drivers/media/video/cx18/cx18-scb.h new file mode 100644 index 000000000000..86b4cb15d163 --- /dev/null +++ b/drivers/media/video/cx18/cx18-scb.h @@ -0,0 +1,285 @@ +/* + * cx18 System Control Block initialization + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 CX18_SCB_H +#define CX18_SCB_H + +#include "cx18-mailbox.h" + +/* NOTE: All ACK interrupts are in the SW2 register. All non-ACK interrupts + are in the SW1 register. */ + +#define IRQ_APU_TO_CPU 0x00000001 +#define IRQ_CPU_TO_APU_ACK 0x00000001 +#define IRQ_HPU_TO_CPU 0x00000002 +#define IRQ_CPU_TO_HPU_ACK 0x00000002 +#define IRQ_PPU_TO_CPU 0x00000004 +#define IRQ_CPU_TO_PPU_ACK 0x00000004 +#define IRQ_EPU_TO_CPU 0x00000008 +#define IRQ_CPU_TO_EPU_ACK 0x00000008 + +#define IRQ_CPU_TO_APU 0x00000010 +#define IRQ_APU_TO_CPU_ACK 0x00000010 +#define IRQ_HPU_TO_APU 0x00000020 +#define IRQ_APU_TO_HPU_ACK 0x00000020 +#define IRQ_PPU_TO_APU 0x00000040 +#define IRQ_APU_TO_PPU_ACK 0x00000040 +#define IRQ_EPU_TO_APU 0x00000080 +#define IRQ_APU_TO_EPU_ACK 0x00000080 + +#define IRQ_CPU_TO_HPU 0x00000100 +#define IRQ_HPU_TO_CPU_ACK 0x00000100 +#define IRQ_APU_TO_HPU 0x00000200 +#define IRQ_HPU_TO_APU_ACK 0x00000200 +#define IRQ_PPU_TO_HPU 0x00000400 +#define IRQ_HPU_TO_PPU_ACK 0x00000400 +#define IRQ_EPU_TO_HPU 0x00000800 +#define IRQ_HPU_TO_EPU_ACK 0x00000800 + +#define IRQ_CPU_TO_PPU 0x00001000 +#define IRQ_PPU_TO_CPU_ACK 0x00001000 +#define IRQ_APU_TO_PPU 0x00002000 +#define IRQ_PPU_TO_APU_ACK 0x00002000 +#define IRQ_HPU_TO_PPU 0x00004000 +#define IRQ_PPU_TO_HPU_ACK 0x00004000 +#define IRQ_EPU_TO_PPU 0x00008000 +#define IRQ_PPU_TO_EPU_ACK 0x00008000 + +#define IRQ_CPU_TO_EPU 0x00010000 +#define IRQ_EPU_TO_CPU_ACK 0x00010000 +#define IRQ_APU_TO_EPU 0x00020000 +#define IRQ_EPU_TO_APU_ACK 0x00020000 +#define IRQ_HPU_TO_EPU 0x00040000 +#define IRQ_EPU_TO_HPU_ACK 0x00040000 +#define IRQ_PPU_TO_EPU 0x00080000 +#define IRQ_EPU_TO_PPU_ACK 0x00080000 + +#define SCB_OFFSET 0xDC0000 + +/* If Firmware uses fixed memory map, it shall not allocate the area + between SCB_OFFSET and SCB_OFFSET+SCB_RESERVED_SIZE-1 inclusive */ +#define SCB_RESERVED_SIZE 0x10000 + + +/* This structure is used by EPU to provide memory descriptors in its memory */ +struct cx18_mdl { + u32 paddr; /* Physical address of a buffer segment */ + u32 length; /* Length of the buffer segment */ +}; + +/* This structure is used by CPU to provide completed buffers information */ +struct cx18_mdl_ack { + u32 id; /* ID of a completed MDL */ + u32 data_used; /* Total data filled in the MDL for buffer 'id' */ +}; + +struct cx18_scb { + /* These fields form the System Control Block which is used at boot time + for localizing the IPC data as well as the code positions for all + processors. The offsets are from the start of this struct. */ + + /* Offset where to find the Inter-Processor Communication data */ + u32 ipc_offset; + u32 reserved01[7]; + /* Offset where to find the start of the CPU code */ + u32 cpu_code_offset; + u32 reserved02[3]; + /* Offset where to find the start of the APU code */ + u32 apu_code_offset; + u32 reserved03[3]; + /* Offset where to find the start of the HPU code */ + u32 hpu_code_offset; + u32 reserved04[3]; + /* Offset where to find the start of the PPU code */ + u32 ppu_code_offset; + u32 reserved05[3]; + + /* These fields form Inter-Processor Communication data which is used + by all processors to locate the information needed for communicating + with other processors */ + + /* Fields for CPU: */ + + /* bit 0: 1/0 processor ready/not ready. Set other bits to 0. */ + u32 cpu_state; + u32 reserved1[7]; + /* Offset to the mailbox used for sending commands from APU to CPU */ + u32 apu2cpu_mb_offset; + /* Value to write to register SW1 register set (0xC7003100) after the + command is ready */ + u32 apu2cpu_irq; + /* Value to write to register SW2 register set (0xC7003140) after the + command is cleared */ + u32 apu2cpu_irq_ack; + u32 reserved2[13]; + + u32 hpu2cpu_mb_offset; + u32 hpu2cpu_irq; + u32 hpu2cpu_irq_ack; + u32 reserved3[13]; + + u32 ppu2cpu_mb_offset; + u32 ppu2cpu_irq; + u32 ppu2cpu_irq_ack; + u32 reserved4[13]; + + u32 epu2cpu_mb_offset; + u32 epu2cpu_irq; + u32 epu2cpu_irq_ack; + u32 reserved5[13]; + u32 reserved6[8]; + + /* Fields for APU: */ + + u32 apu_state; + u32 reserved11[7]; + u32 cpu2apu_mb_offset; + u32 cpu2apu_irq; + u32 cpu2apu_irq_ack; + u32 reserved12[13]; + + u32 hpu2apu_mb_offset; + u32 hpu2apu_irq; + u32 hpu2apu_irq_ack; + u32 reserved13[13]; + + u32 ppu2apu_mb_offset; + u32 ppu2apu_irq; + u32 ppu2apu_irq_ack; + u32 reserved14[13]; + + u32 epu2apu_mb_offset; + u32 epu2apu_irq; + u32 epu2apu_irq_ack; + u32 reserved15[13]; + u32 reserved16[8]; + + /* Fields for HPU: */ + + u32 hpu_state; + u32 reserved21[7]; + u32 cpu2hpu_mb_offset; + u32 cpu2hpu_irq; + u32 cpu2hpu_irq_ack; + u32 reserved22[13]; + + u32 apu2hpu_mb_offset; + u32 apu2hpu_irq; + u32 apu2hpu_irq_ack; + u32 reserved23[13]; + + u32 ppu2hpu_mb_offset; + u32 ppu2hpu_irq; + u32 ppu2hpu_irq_ack; + u32 reserved24[13]; + + u32 epu2hpu_mb_offset; + u32 epu2hpu_irq; + u32 epu2hpu_irq_ack; + u32 reserved25[13]; + u32 reserved26[8]; + + /* Fields for PPU: */ + + u32 ppu_state; + u32 reserved31[7]; + u32 cpu2ppu_mb_offset; + u32 cpu2ppu_irq; + u32 cpu2ppu_irq_ack; + u32 reserved32[13]; + + u32 apu2ppu_mb_offset; + u32 apu2ppu_irq; + u32 apu2ppu_irq_ack; + u32 reserved33[13]; + + u32 hpu2ppu_mb_offset; + u32 hpu2ppu_irq; + u32 hpu2ppu_irq_ack; + u32 reserved34[13]; + + u32 epu2ppu_mb_offset; + u32 epu2ppu_irq; + u32 epu2ppu_irq_ack; + u32 reserved35[13]; + u32 reserved36[8]; + + /* Fields for EPU: */ + + u32 epu_state; + u32 reserved41[7]; + u32 cpu2epu_mb_offset; + u32 cpu2epu_irq; + u32 cpu2epu_irq_ack; + u32 reserved42[13]; + + u32 apu2epu_mb_offset; + u32 apu2epu_irq; + u32 apu2epu_irq_ack; + u32 reserved43[13]; + + u32 hpu2epu_mb_offset; + u32 hpu2epu_irq; + u32 hpu2epu_irq_ack; + u32 reserved44[13]; + + u32 ppu2epu_mb_offset; + u32 ppu2epu_irq; + u32 ppu2epu_irq_ack; + u32 reserved45[13]; + u32 reserved46[8]; + + u32 semaphores[8]; /* Semaphores */ + + u32 reserved50[32]; /* Reserved for future use */ + + struct cx18_mailbox apu2cpu_mb; + struct cx18_mailbox hpu2cpu_mb; + struct cx18_mailbox ppu2cpu_mb; + struct cx18_mailbox epu2cpu_mb; + + struct cx18_mailbox cpu2apu_mb; + struct cx18_mailbox hpu2apu_mb; + struct cx18_mailbox ppu2apu_mb; + struct cx18_mailbox epu2apu_mb; + + struct cx18_mailbox cpu2hpu_mb; + struct cx18_mailbox apu2hpu_mb; + struct cx18_mailbox ppu2hpu_mb; + struct cx18_mailbox epu2hpu_mb; + + struct cx18_mailbox cpu2ppu_mb; + struct cx18_mailbox apu2ppu_mb; + struct cx18_mailbox hpu2ppu_mb; + struct cx18_mailbox epu2ppu_mb; + + struct cx18_mailbox cpu2epu_mb; + struct cx18_mailbox apu2epu_mb; + struct cx18_mailbox hpu2epu_mb; + struct cx18_mailbox ppu2epu_mb; + + struct cx18_mdl_ack cpu_mdl_ack[CX18_MAX_STREAMS][2]; + struct cx18_mdl cpu_mdl[1]; +}; + +void cx18_init_scb(struct cx18 *cx); + +#endif diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c new file mode 100644 index 000000000000..afb141b2027a --- /dev/null +++ b/drivers/media/video/cx18/cx18-streams.c @@ -0,0 +1,566 @@ +/* + * cx18 init/start/stop/exit stream functions + * + * Derived from ivtv-streams.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-fileops.h" +#include "cx18-mailbox.h" +#include "cx18-i2c.h" +#include "cx18-queue.h" +#include "cx18-ioctl.h" +#include "cx18-streams.h" +#include "cx18-cards.h" +#include "cx18-scb.h" +#include "cx18-av-core.h" +#include "cx18-dvb.h" + +#define CX18_DSP0_INTERRUPT_MASK 0xd0004C + +static struct file_operations cx18_v4l2_enc_fops = { + .owner = THIS_MODULE, + .read = cx18_v4l2_read, + .open = cx18_v4l2_open, + .ioctl = cx18_v4l2_ioctl, + .release = cx18_v4l2_close, + .poll = cx18_v4l2_enc_poll, +}; + +/* offset from 0 to register ts v4l2 minors on */ +#define CX18_V4L2_ENC_TS_OFFSET 16 +/* offset from 0 to register pcm v4l2 minors on */ +#define CX18_V4L2_ENC_PCM_OFFSET 24 +/* offset from 0 to register yuv v4l2 minors on */ +#define CX18_V4L2_ENC_YUV_OFFSET 32 + +static struct { + const char *name; + int vfl_type; + int minor_offset; + int dma; + enum v4l2_buf_type buf_type; + struct file_operations *fops; +} cx18_stream_info[] = { + { /* CX18_ENC_STREAM_TYPE_MPG */ + "encoder MPEG", + VFL_TYPE_GRABBER, 0, + PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE, + &cx18_v4l2_enc_fops + }, + { /* CX18_ENC_STREAM_TYPE_TS */ + "TS", + VFL_TYPE_GRABBER, -1, + PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE, + &cx18_v4l2_enc_fops + }, + { /* CX18_ENC_STREAM_TYPE_YUV */ + "encoder YUV", + VFL_TYPE_GRABBER, CX18_V4L2_ENC_YUV_OFFSET, + PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE, + &cx18_v4l2_enc_fops + }, + { /* CX18_ENC_STREAM_TYPE_VBI */ + "encoder VBI", + VFL_TYPE_VBI, 0, + PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VBI_CAPTURE, + &cx18_v4l2_enc_fops + }, + { /* CX18_ENC_STREAM_TYPE_PCM */ + "encoder PCM audio", + VFL_TYPE_GRABBER, CX18_V4L2_ENC_PCM_OFFSET, + PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_PRIVATE, + &cx18_v4l2_enc_fops + }, + { /* CX18_ENC_STREAM_TYPE_IDX */ + "encoder IDX", + VFL_TYPE_GRABBER, -1, + PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE, + &cx18_v4l2_enc_fops + }, + { /* CX18_ENC_STREAM_TYPE_RAD */ + "encoder radio", + VFL_TYPE_RADIO, 0, + PCI_DMA_NONE, V4L2_BUF_TYPE_PRIVATE, + &cx18_v4l2_enc_fops + }, +}; + +static void cx18_stream_init(struct cx18 *cx, int type) +{ + struct cx18_stream *s = &cx->streams[type]; + struct video_device *dev = s->v4l2dev; + u32 max_size = cx->options.megabytes[type] * 1024 * 1024; + + /* we need to keep v4l2dev, so restore it afterwards */ + memset(s, 0, sizeof(*s)); + s->v4l2dev = dev; + + /* initialize cx18_stream fields */ + s->cx = cx; + s->type = type; + s->name = cx18_stream_info[type].name; + s->handle = 0xffffffff; + + s->dma = cx18_stream_info[type].dma; + s->buf_size = cx->stream_buf_size[type]; + if (s->buf_size) + s->buffers = max_size / s->buf_size; + if (s->buffers > 63) { + /* Each stream has a maximum of 63 buffers, + ensure we do not exceed that. */ + s->buffers = 63; + s->buf_size = (max_size / s->buffers) & ~0xfff; + } + spin_lock_init(&s->qlock); + init_waitqueue_head(&s->waitq); + s->id = -1; + cx18_queue_init(&s->q_free); + cx18_queue_init(&s->q_full); + cx18_queue_init(&s->q_io); +} + +static int cx18_prep_dev(struct cx18 *cx, int type) +{ + struct cx18_stream *s = &cx->streams[type]; + u32 cap = cx->v4l2_cap; + int minor_offset = cx18_stream_info[type].minor_offset; + int minor; + + /* These four fields are always initialized. If v4l2dev == NULL, then + this stream is not in use. In that case no other fields but these + four can be used. */ + s->v4l2dev = NULL; + s->cx = cx; + s->type = type; + s->name = cx18_stream_info[type].name; + + /* Check whether the radio is supported */ + if (type == CX18_ENC_STREAM_TYPE_RAD && !(cap & V4L2_CAP_RADIO)) + return 0; + + /* Check whether VBI is supported */ + if (type == CX18_ENC_STREAM_TYPE_VBI && + !(cap & (V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE))) + return 0; + + /* card number + user defined offset + device offset */ + minor = cx->num + cx18_first_minor + minor_offset; + + /* User explicitly selected 0 buffers for these streams, so don't + create them. */ + if (cx18_stream_info[type].dma != PCI_DMA_NONE && + cx->options.megabytes[type] == 0) { + CX18_INFO("Disabled %s device\n", cx18_stream_info[type].name); + return 0; + } + + cx18_stream_init(cx, type); + + if (minor_offset == -1) + return 0; + + /* allocate and initialize the v4l2 video device structure */ + s->v4l2dev = video_device_alloc(); + if (s->v4l2dev == NULL) { + CX18_ERR("Couldn't allocate v4l2 video_device for %s\n", + s->name); + return -ENOMEM; + } + + s->v4l2dev->type = + VID_TYPE_CAPTURE | VID_TYPE_TUNER | VID_TYPE_TELETEXT | + VID_TYPE_CLIPPING | VID_TYPE_SCALES | VID_TYPE_MPEG_ENCODER; + snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18%d %s", + cx->num, s->name); + + s->v4l2dev->minor = minor; + s->v4l2dev->dev = &cx->dev->dev; + s->v4l2dev->fops = cx18_stream_info[type].fops; + s->v4l2dev->release = video_device_release; + + return 0; +} + +/* Initialize v4l2 variables and register v4l2 devices */ +int cx18_streams_setup(struct cx18 *cx) +{ + int type; + + /* Setup V4L2 Devices */ + for (type = 0; type < CX18_MAX_STREAMS; type++) { + /* Prepare device */ + if (cx18_prep_dev(cx, type)) + break; + + /* Allocate Stream */ + if (cx18_stream_alloc(&cx->streams[type])) + break; + } + if (type == CX18_MAX_STREAMS) + return 0; + + /* One or more streams could not be initialized. Clean 'em all up. */ + cx18_streams_cleanup(cx); + return -ENOMEM; +} + +static int cx18_reg_dev(struct cx18 *cx, int type) +{ + struct cx18_stream *s = &cx->streams[type]; + int vfl_type = cx18_stream_info[type].vfl_type; + int minor; + + /* TODO: Shouldn't this be a VFL_TYPE_TRANSPORT or something? + * We need a VFL_TYPE_TS defined. + */ + if (strcmp("TS", s->name) == 0) { + /* just return if no DVB is supported */ + if ((cx->card->hw_all & CX18_HW_DVB) == 0) + return 0; + if (cx18_dvb_register(s) < 0) { + CX18_ERR("DVB failed to register\n"); + return -EINVAL; + } + } + + if (s->v4l2dev == NULL) + return 0; + + minor = s->v4l2dev->minor; + + /* Register device. First try the desired minor, then any free one. */ + if (video_register_device(s->v4l2dev, vfl_type, minor) && + video_register_device(s->v4l2dev, vfl_type, -1)) { + CX18_ERR("Couldn't register v4l2 device for %s minor %d\n", + s->name, minor); + video_device_release(s->v4l2dev); + s->v4l2dev = NULL; + return -ENOMEM; + } + minor = s->v4l2dev->minor; + + switch (vfl_type) { + case VFL_TYPE_GRABBER: + CX18_INFO("Registered device video%d for %s (%d MB)\n", + minor, s->name, cx->options.megabytes[type]); + break; + + case VFL_TYPE_RADIO: + CX18_INFO("Registered device radio%d for %s\n", + minor - MINOR_VFL_TYPE_RADIO_MIN, s->name); + break; + + case VFL_TYPE_VBI: + if (cx->options.megabytes[type]) + CX18_INFO("Registered device vbi%d for %s (%d MB)\n", + minor - MINOR_VFL_TYPE_VBI_MIN, + s->name, cx->options.megabytes[type]); + else + CX18_INFO("Registered device vbi%d for %s\n", + minor - MINOR_VFL_TYPE_VBI_MIN, s->name); + break; + } + + return 0; +} + +/* Register v4l2 devices */ +int cx18_streams_register(struct cx18 *cx) +{ + int type; + int err = 0; + + /* Register V4L2 devices */ + for (type = 0; type < CX18_MAX_STREAMS; type++) + err |= cx18_reg_dev(cx, type); + + if (err == 0) + return 0; + + /* One or more streams could not be initialized. Clean 'em all up. */ + cx18_streams_cleanup(cx); + return -ENOMEM; +} + +/* Unregister v4l2 devices */ +void cx18_streams_cleanup(struct cx18 *cx) +{ + struct video_device *vdev; + int type; + + /* Teardown all streams */ + for (type = 0; type < CX18_MAX_STREAMS; type++) { + if (cx->streams[type].dvb.enabled) + cx18_dvb_unregister(&cx->streams[type]); + + vdev = cx->streams[type].v4l2dev; + + cx->streams[type].v4l2dev = NULL; + if (vdev == NULL) + continue; + + cx18_stream_free(&cx->streams[type]); + + /* Unregister device */ + video_unregister_device(vdev); + } +} + +static void cx18_vbi_setup(struct cx18_stream *s) +{ + struct cx18 *cx = s->cx; + int raw = cx->vbi.sliced_in->service_set == 0; + u32 data[CX2341X_MBOX_MAX_DATA]; + int lines; + + if (cx->is_60hz) { + cx->vbi.count = 12; + cx->vbi.start[0] = 10; + cx->vbi.start[1] = 273; + } else { /* PAL/SECAM */ + cx->vbi.count = 18; + cx->vbi.start[0] = 6; + cx->vbi.start[1] = 318; + } + + /* setup VBI registers */ + cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in); + + /* determine number of lines and total number of VBI bytes. + A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1 + The '- 1' byte is probably an unused U or V byte. Or something... + A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal + header, 42 data bytes + checksum (to be confirmed) */ + if (raw) { + lines = cx->vbi.count * 2; + } else { + lines = cx->is_60hz ? 24 : 38; + if (cx->is_60hz) + lines += 2; + } + + cx->vbi.enc_size = lines * + (raw ? cx->vbi.raw_size : cx->vbi.sliced_size); + + data[0] = s->handle; + /* Lines per field */ + data[1] = (lines / 2) | ((lines / 2) << 16); + /* bytes per line */ + data[2] = (raw ? cx->vbi.raw_size : cx->vbi.sliced_size); + /* Every X number of frames a VBI interrupt arrives + (frames as in 25 or 30 fps) */ + data[3] = 1; + /* Setup VBI for the cx25840 digitizer */ + if (raw) { + data[4] = 0x20602060; + data[5] = 0x30703070; + } else { + data[4] = 0xB0F0B0F0; + data[5] = 0xA0E0A0E0; + } + + CX18_DEBUG_INFO("Setup VBI h: %d lines %x bpl %d fr %d %x %x\n", + data[0], data[1], data[2], data[3], data[4], data[5]); + + if (s->type == CX18_ENC_STREAM_TYPE_VBI) + cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data); +} + +int cx18_start_v4l2_encode_stream(struct cx18_stream *s) +{ + u32 data[MAX_MB_ARGUMENTS]; + struct cx18 *cx = s->cx; + struct list_head *p; + int ts = 0; + int captype = 0; + + if (s->v4l2dev == NULL && s->dvb.enabled == 0) + return -EINVAL; + + CX18_DEBUG_INFO("Start encoder stream %s\n", s->name); + + switch (s->type) { + case CX18_ENC_STREAM_TYPE_MPG: + captype = CAPTURE_CHANNEL_TYPE_MPEG; + cx->mpg_data_received = cx->vbi_data_inserted = 0; + cx->dualwatch_jiffies = jiffies; + cx->dualwatch_stereo_mode = cx->params.audio_properties & 0x300; + cx->search_pack_header = 0; + break; + + case CX18_ENC_STREAM_TYPE_TS: + captype = CAPTURE_CHANNEL_TYPE_TS; + ts = 1; + break; + case CX18_ENC_STREAM_TYPE_YUV: + captype = CAPTURE_CHANNEL_TYPE_YUV; + break; + case CX18_ENC_STREAM_TYPE_PCM: + captype = CAPTURE_CHANNEL_TYPE_PCM; + break; + case CX18_ENC_STREAM_TYPE_VBI: + captype = cx->vbi.sliced_in->service_set ? + CAPTURE_CHANNEL_TYPE_SLICED_VBI : CAPTURE_CHANNEL_TYPE_VBI; + cx->vbi.frame = 0; + cx->vbi.inserted_frame = 0; + memset(cx->vbi.sliced_mpeg_size, + 0, sizeof(cx->vbi.sliced_mpeg_size)); + break; + default: + return -EINVAL; + } + s->buffers_stolen = 0; + + /* mute/unmute video */ + cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, + s->handle, !!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)); + + /* Clear Streamoff flags in case left from last capture */ + clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); + + cx18_vapi_result(cx, data, CX18_CREATE_TASK, 1, CPU_CMD_MASK_CAPTURE); + s->handle = data[0]; + cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype); + + if (atomic_read(&cx->capturing) == 0 && !ts) { + /* Stuff from Windows, we don't know what it is */ + cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0); + cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 3, 1); + cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 8, 0); + cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 4, 1); + cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, s->handle, 12); + + cx18_vapi(cx, CX18_CPU_SET_CAPTURE_LINE_NO, 3, + s->handle, cx->digitizer, cx->digitizer); + + /* Setup VBI */ + if (cx->v4l2_cap & V4L2_CAP_VBI_CAPTURE) + cx18_vbi_setup(s); + + /* assign program index info. + Mask 7: select I/P/B, Num_req: 400 max */ + cx18_vapi_result(cx, data, CX18_CPU_SET_INDEXTABLE, 1, 0); + + /* Setup API for Stream */ + cx2341x_update(cx, cx18_api_func, NULL, &cx->params); + } + + if (atomic_read(&cx->capturing) == 0) { + clear_bit(CX18_F_I_EOS, &cx->i_flags); + write_reg(7, CX18_DSP0_INTERRUPT_MASK); + } + + cx18_vapi(cx, CX18_CPU_DE_SET_MDL_ACK, 3, s->handle, + (void *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem, + (void *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem); + + list_for_each(p, &s->q_free.list) { + struct cx18_buffer *buf = list_entry(p, struct cx18_buffer, list); + + writel(buf->dma_handle, &cx->scb->cpu_mdl[buf->id].paddr); + writel(s->buf_size, &cx->scb->cpu_mdl[buf->id].length); + cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, + (void *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, 1, + buf->id, s->buf_size); + } + /* begin_capture */ + if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) { + CX18_DEBUG_WARN("Error starting capture!\n"); + cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); + return -EINVAL; + } + + /* you're live! sit back and await interrupts :) */ + atomic_inc(&cx->capturing); + return 0; +} + +void cx18_stop_all_captures(struct cx18 *cx) +{ + int i; + + for (i = CX18_MAX_STREAMS - 1; i >= 0; i--) { + struct cx18_stream *s = &cx->streams[i]; + + if (s->v4l2dev == NULL && s->dvb.enabled == 0) + continue; + if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) + cx18_stop_v4l2_encode_stream(s, 0); + } +} + +int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end) +{ + struct cx18 *cx = s->cx; + unsigned long then; + + if (s->v4l2dev == NULL && s->dvb.enabled == 0) + return -EINVAL; + + /* This function assumes that you are allowed to stop the capture + and that we are actually capturing */ + + CX18_DEBUG_INFO("Stop Capture\n"); + + if (atomic_read(&cx->capturing) == 0) + return 0; + + if (s->type == CX18_ENC_STREAM_TYPE_MPG) + cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, !gop_end); + else + cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle); + + then = jiffies; + + if (s->type == CX18_ENC_STREAM_TYPE_MPG && gop_end) { + CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n"); + } + + atomic_dec(&cx->capturing); + + /* Clear capture and no-read bits */ + clear_bit(CX18_F_S_STREAMING, &s->s_flags); + + cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); + s->handle = 0xffffffff; + + if (atomic_read(&cx->capturing) > 0) + return 0; + + write_reg(5, CX18_DSP0_INTERRUPT_MASK); + wake_up(&s->waitq); + + return 0; +} + +u32 cx18_find_handle(struct cx18 *cx) +{ + int i; + + /* find first available handle to be used for global settings */ + for (i = 0; i < CX18_MAX_STREAMS; i++) { + struct cx18_stream *s = &cx->streams[i]; + + if (s->v4l2dev && s->handle) + return s->handle; + } + return 0; +} diff --git a/drivers/media/video/cx18/cx18-streams.h b/drivers/media/video/cx18/cx18-streams.h new file mode 100644 index 000000000000..8c7ba7d2fa79 --- /dev/null +++ b/drivers/media/video/cx18/cx18-streams.h @@ -0,0 +1,33 @@ +/* + * cx18 init/start/stop/exit stream functions + * + * Derived from ivtv-streams.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 + */ + +u32 cx18_find_handle(struct cx18 *cx); +int cx18_streams_setup(struct cx18 *cx); +int cx18_streams_register(struct cx18 *cx); +void cx18_streams_cleanup(struct cx18 *cx); + +/* Capture related */ +int cx18_start_v4l2_encode_stream(struct cx18_stream *s); +int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end); + +void cx18_stop_all_captures(struct cx18 *cx); diff --git a/drivers/media/video/cx18/cx18-vbi.c b/drivers/media/video/cx18/cx18-vbi.c new file mode 100644 index 000000000000..22e76ee3f447 --- /dev/null +++ b/drivers/media/video/cx18/cx18-vbi.c @@ -0,0 +1,208 @@ +/* + * cx18 Vertical Blank Interval support functions + * + * Derived from ivtv-vbi.c + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-vbi.h" +#include "cx18-ioctl.h" +#include "cx18-queue.h" +#include "cx18-av-core.h" + +static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp) +{ + int line = 0; + int i; + u32 linemask[2] = { 0, 0 }; + unsigned short size; + static const u8 mpeg_hdr_data[] = { + 0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x0c, 0x66, + 0x24, 0x01, 0x01, 0xd1, 0xd3, 0xfa, 0xff, 0xff, + 0x00, 0x00, 0x01, 0xbd, 0x00, 0x1a, 0x84, 0x80, + 0x07, 0x21, 0x00, 0x5d, 0x63, 0xa7, 0xff, 0xff + }; + const int sd = sizeof(mpeg_hdr_data); /* start of vbi data */ + int idx = cx->vbi.frame % CX18_VBI_FRAMES; + u8 *dst = &cx->vbi.sliced_mpeg_data[idx][0]; + + for (i = 0; i < lines; i++) { + struct v4l2_sliced_vbi_data *sdata = cx->vbi.sliced_data + i; + int f, l; + + if (sdata->id == 0) + continue; + + l = sdata->line - 6; + f = sdata->field; + if (f) + l += 18; + if (l < 32) + linemask[0] |= (1 << l); + else + linemask[1] |= (1 << (l - 32)); + dst[sd + 12 + line * 43] = cx18_service2vbi(sdata->id); + memcpy(dst + sd + 12 + line * 43 + 1, sdata->data, 42); + line++; + } + memcpy(dst, mpeg_hdr_data, sizeof(mpeg_hdr_data)); + if (line == 36) { + /* All lines are used, so there is no space for the linemask + (the max size of the VBI data is 36 * 43 + 4 bytes). + So in this case we use the magic number 'ITV0'. */ + memcpy(dst + sd, "ITV0", 4); + memcpy(dst + sd + 4, dst + sd + 12, line * 43); + size = 4 + ((43 * line + 3) & ~3); + } else { + memcpy(dst + sd, "cx0", 4); + memcpy(dst + sd + 4, &linemask[0], 8); + size = 12 + ((43 * line + 3) & ~3); + } + dst[4+16] = (size + 10) >> 8; + dst[5+16] = (size + 10) & 0xff; + dst[9+16] = 0x21 | ((pts_stamp >> 29) & 0x6); + dst[10+16] = (pts_stamp >> 22) & 0xff; + dst[11+16] = 1 | ((pts_stamp >> 14) & 0xff); + dst[12+16] = (pts_stamp >> 7) & 0xff; + dst[13+16] = 1 | ((pts_stamp & 0x7f) << 1); + cx->vbi.sliced_mpeg_size[idx] = sd + size; +} + +/* Compress raw VBI format, removes leading SAV codes and surplus space + after the field. + Returns new compressed size. */ +static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size) +{ + u32 line_size = cx->vbi.raw_decoder_line_size; + u32 lines = cx->vbi.count; + u8 sav1 = cx->vbi.raw_decoder_sav_odd_field; + u8 sav2 = cx->vbi.raw_decoder_sav_even_field; + u8 *q = buf; + u8 *p; + int i; + + for (i = 0; i < lines; i++) { + p = buf + i * line_size; + + /* Look for SAV code */ + if (p[0] != 0xff || p[1] || p[2] || + (p[3] != sav1 && p[3] != sav2)) + break; + memcpy(q, p + 4, line_size - 4); + q += line_size - 4; + } + return lines * (line_size - 4); +} + + +/* Compressed VBI format, all found sliced blocks put next to one another + Returns new compressed size */ +static u32 compress_sliced_buf(struct cx18 *cx, u32 line, u8 *buf, + u32 size, u8 sav) +{ + u32 line_size = cx->vbi.sliced_decoder_line_size; + struct v4l2_decode_vbi_line vbi; + int i; + + /* find the first valid line */ + for (i = 0; i < size; i++, buf++) { + if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav) + break; + } + + size -= i; + if (size < line_size) + return line; + for (i = 0; i < size / line_size; i++) { + u8 *p = buf + i * line_size; + + /* Look for SAV code */ + if (p[0] != 0xff || p[1] || p[2] || p[3] != sav) + continue; + vbi.p = p + 4; + cx18_av_cmd(cx, VIDIOC_INT_DECODE_VBI_LINE, &vbi); + if (vbi.type) { + cx->vbi.sliced_data[line].id = vbi.type; + cx->vbi.sliced_data[line].field = vbi.is_second_field; + cx->vbi.sliced_data[line].line = vbi.line; + memcpy(cx->vbi.sliced_data[line].data, vbi.p, 42); + line++; + } + } + return line; +} + +void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf, + u64 pts_stamp, int streamtype) +{ + u8 *p = (u8 *) buf->buf; + u32 size = buf->bytesused; + int lines; + + if (streamtype != CX18_ENC_STREAM_TYPE_VBI) + return; + + /* Raw VBI data */ + if (cx->vbi.sliced_in->service_set == 0) { + u8 type; + + cx18_buf_swap(buf); + + type = p[3]; + + size = buf->bytesused = compress_raw_buf(cx, p, size); + + /* second field of the frame? */ + if (type == cx->vbi.raw_decoder_sav_even_field) { + /* Dirty hack needed for backwards + compatibility of old VBI software. */ + p += size - 4; + memcpy(p, &cx->vbi.frame, 4); + cx->vbi.frame++; + } + return; + } + + /* Sliced VBI data with data insertion */ + cx18_buf_swap(buf); + + /* first field */ + lines = compress_sliced_buf(cx, 0, p, size / 2, + cx->vbi.sliced_decoder_sav_odd_field); + /* second field */ + /* experimentation shows that the second half does not always + begin at the exact address. So start a bit earlier + (hence 32). */ + lines = compress_sliced_buf(cx, lines, p + size / 2 - 32, + size / 2 + 32, cx->vbi.sliced_decoder_sav_even_field); + /* always return at least one empty line */ + if (lines == 0) { + cx->vbi.sliced_data[0].id = 0; + cx->vbi.sliced_data[0].line = 0; + cx->vbi.sliced_data[0].field = 0; + lines = 1; + } + buf->bytesused = size = lines * sizeof(cx->vbi.sliced_data[0]); + memcpy(p, &cx->vbi.sliced_data[0], size); + + if (cx->vbi.insert_mpeg) + copy_vbi_data(cx, lines, pts_stamp); + cx->vbi.frame++; +} diff --git a/drivers/media/video/cx18/cx18-vbi.h b/drivers/media/video/cx18/cx18-vbi.h new file mode 100644 index 000000000000..c56ff7d28f20 --- /dev/null +++ b/drivers/media/video/cx18/cx18-vbi.h @@ -0,0 +1,26 @@ +/* + * cx18 Vertical Blank Interval support functions + * + * Derived from ivtv-vbi.h + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 + */ + +void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf, + u64 pts_stamp, int streamtype); +int cx18_used_line(struct cx18 *cx, int line, int field); diff --git a/drivers/media/video/cx18/cx18-version.h b/drivers/media/video/cx18/cx18-version.h new file mode 100644 index 000000000000..d5c7a6f968dd --- /dev/null +++ b/drivers/media/video/cx18/cx18-version.h @@ -0,0 +1,34 @@ +/* + * cx18 driver version information + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 CX18_VERSION_H +#define CX18_VERSION_H + +#define CX18_DRIVER_NAME "cx18" +#define CX18_DRIVER_VERSION_MAJOR 1 +#define CX18_DRIVER_VERSION_MINOR 0 +#define CX18_DRIVER_VERSION_PATCHLEVEL 0 + +#define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL) +#define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \ + CX18_DRIVER_VERSION_MINOR, CX18_DRIVER_VERSION_PATCHLEVEL) + +#endif diff --git a/drivers/media/video/cx18/cx18-video.c b/drivers/media/video/cx18/cx18-video.c new file mode 100644 index 000000000000..2e5c41939330 --- /dev/null +++ b/drivers/media/video/cx18/cx18-video.c @@ -0,0 +1,45 @@ +/* + * cx18 video interface functions + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 "cx18-driver.h" +#include "cx18-video.h" +#include "cx18-av-core.h" +#include "cx18-cards.h" + +void cx18_video_set_io(struct cx18 *cx) +{ + struct v4l2_routing route; + int inp = cx->active_input; + u32 type; + + route.input = cx->card->video_inputs[inp].video_input; + route.output = 0; + cx18_av_cmd(cx, VIDIOC_INT_S_VIDEO_ROUTING, &route); + + type = cx->card->video_inputs[inp].video_type; + + if (type == CX18_CARD_INPUT_VID_TUNER) + route.input = 0; /* Tuner */ + else if (type < CX18_CARD_INPUT_COMPOSITE1) + route.input = 2; /* S-Video */ + else + route.input = 1; /* Composite */ +} diff --git a/drivers/media/video/cx18/cx18-video.h b/drivers/media/video/cx18/cx18-video.h new file mode 100644 index 000000000000..529006a06e5c --- /dev/null +++ b/drivers/media/video/cx18/cx18-video.h @@ -0,0 +1,22 @@ +/* + * cx18 video interface functions + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 + */ + +void cx18_video_set_io(struct cx18 *cx); diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h new file mode 100644 index 000000000000..33f78da9dba8 --- /dev/null +++ b/drivers/media/video/cx18/cx23418.h @@ -0,0 +1,458 @@ +/* + * cx18 header containing common defines. + * + * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * + * 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 CX23418_H +#define CX23418_H + +#include <media/cx2341x.h> + +#define MGR_CMD_MASK 0x40000000 +/* The MSB of the command code indicates that this is the completion of a + command */ +#define MGR_CMD_MASK_ACK (MGR_CMD_MASK | 0x80000000) + +/* Description: This command creates a new instance of a certain task + IN[0] - Task ID. This is one of the XPU_CMD_MASK_YYY where XPU is + the processor on which the task YYY will be created + OUT[0] - Task handle. This handle is passed along with commands to + dispatch to the right instance of the task + ReturnCode - One of the ERR_SYS_... */ +#define CX18_CREATE_TASK (MGR_CMD_MASK | 0x0001) + +/* Description: This command destroys an instance of a task + IN[0] - Task handle. Hanlde of the task to destroy + ReturnCode - One of the ERR_SYS_... */ +#define CX18_DESTROY_TASK (MGR_CMD_MASK | 0x0002) + +/* All commands for CPU have the following mask set */ +#define CPU_CMD_MASK 0x20000000 +#define CPU_CMD_MASK_ACK (CPU_CMD_MASK | 0x80000000) +#define CPU_CMD_MASK_CAPTURE (CPU_CMD_MASK | 0x00020000) +#define CPU_CMD_MASK_TS (CPU_CMD_MASK | 0x00040000) + +#define EPU_CMD_MASK 0x02000000 +#define EPU_CMD_MASK_DEBUG (EPU_CMD_MASK | 0x000000) +#define EPU_CMD_MASK_DE (EPU_CMD_MASK | 0x040000) + +/* Description: This command indicates that a Memory Descriptor List has been + filled with the requested channel type + IN[0] - Task handle. Handle of the task + IN[1] - Offset of the MDL_ACK from the beginning of the local DDR. + IN[2] - Number of CNXT_MDL_ACK structures in the array pointed to by IN[1] + ReturnCode - One of the ERR_DE_... */ +#define CX18_EPU_DMA_DONE (EPU_CMD_MASK_DE | 0x0001) + +/* Something interesting happened + IN[0] - A value to log + IN[1] - An offset of a string in the MiniMe memory; + 0/zero/NULL means "I have nothing to say" */ +#define CX18_EPU_DEBUG (EPU_CMD_MASK_DEBUG | 0x0003) + +/* Description: This command starts streaming with the set channel type + IN[0] - Task handle. Handle of the task to start + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_CAPTURE_START (CPU_CMD_MASK_CAPTURE | 0x0002) + +/* Description: This command stops streaming with the set channel type + IN[0] - Task handle. Handle of the task to stop + IN[1] - 0 = stop at end of GOP, 1 = stop at end of frame (MPEG only) + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_CAPTURE_STOP (CPU_CMD_MASK_CAPTURE | 0x0003) + +/* Description: This command pauses streaming with the set channel type + IN[0] - Task handle. Handle of the task to pause + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_CAPTURE_PAUSE (CPU_CMD_MASK_CAPTURE | 0x0007) + +/* Description: This command resumes streaming with the set channel type + IN[0] - Task handle. Handle of the task to resume + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_CAPTURE_RESUME (CPU_CMD_MASK_CAPTURE | 0x0008) + +#define CAPTURE_CHANNEL_TYPE_NONE 0 +#define CAPTURE_CHANNEL_TYPE_MPEG 1 +#define CAPTURE_CHANNEL_TYPE_INDEX 2 +#define CAPTURE_CHANNEL_TYPE_YUV 3 +#define CAPTURE_CHANNEL_TYPE_PCM 4 +#define CAPTURE_CHANNEL_TYPE_VBI 5 +#define CAPTURE_CHANNEL_TYPE_SLICED_VBI 6 +#define CAPTURE_CHANNEL_TYPE_TS 7 +#define CAPTURE_CHANNEL_TYPE_MAX 15 + +/* Description: This command sets the channel type. This can only be done + when stopped. + IN[0] - Task handle. Handle of the task to start + IN[1] - Channel Type. See Below. + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_CHANNEL_TYPE (CPU_CMD_MASK_CAPTURE + 1) + +/* Description: Set stream output type + IN[0] - task handle. Handle of the task to start + IN[1] - type + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_STREAM_OUTPUT_TYPE (CPU_CMD_MASK_CAPTURE | 0x0012) + +/* Description: Set video input resolution and frame rate + IN[0] - task handle + IN[1] - reserved + IN[2] - reserved + IN[3] - reserved + IN[4] - reserved + IN[5] - frame rate, 0 - 29.97f/s, 1 - 25f/s + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_VIDEO_IN (CPU_CMD_MASK_CAPTURE | 0x0004) + +/* Description: Set video frame rate + IN[0] - task handle. Handle of the task to start + IN[1] - video bit rate mode + IN[2] - video average rate + IN[3] - video peak rate + IN[4] - system mux rate + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_VIDEO_RATE (CPU_CMD_MASK_CAPTURE | 0x0005) + +/* Description: Set video output resolution + IN[0] - task handle + IN[1] - horizontal size + IN[2] - vertical size + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_VIDEO_RESOLUTION (CPU_CMD_MASK_CAPTURE | 0x0006) + +/* Description: This command set filter parameters + IN[0] - Task handle. Handle of the task + IN[1] - type, 0 - temporal, 1 - spatial, 2 - median + IN[2] - mode, temporal/spatial: 0 - disable, 1 - static, 2 - dynamic + median: 0 = disable, 1 = horizontal, 2 = vertical, + 3 = horizontal/vertical, 4 = diagonal + IN[3] - strength, temporal 0 - 31, spatial 0 - 15 + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_FILTER_PARAM (CPU_CMD_MASK_CAPTURE | 0x0009) + +/* Description: This command set spatial filter type + IN[0] - Task handle. + IN[1] - luma type: 0 = disable, 1 = 1D horizontal only, 2 = 1D vertical only, + 3 = 2D H/V separable, 4 = 2D symmetric non-separable + IN[2] - chroma type: 0 - diable, 1 = 1D horizontal + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_SPATIAL_FILTER_TYPE (CPU_CMD_MASK_CAPTURE | 0x000C) + +/* Description: This command set coring levels for median filter + IN[0] - Task handle. + IN[1] - luma_high + IN[2] - luma_low + IN[3] - chroma_high + IN[4] - chroma_low + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_MEDIAN_CORING (CPU_CMD_MASK_CAPTURE | 0x000E) + +/* Description: This command set the picture type mask for index file + IN[0] - 0 = disable index file output + 1 = output I picture + 2 = P picture + 4 = B picture + other = illegal */ +#define CX18_CPU_SET_INDEXTABLE (CPU_CMD_MASK_CAPTURE | 0x0010) + +/* Description: Set audio parameters + IN[0] - task handle. Handle of the task to start + IN[1] - audio parameter + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_AUDIO_PARAMETERS (CPU_CMD_MASK_CAPTURE | 0x0011) + +/* Description: Set video mute + IN[0] - task handle. Handle of the task to start + IN[1] - bit31-24: muteYvalue + bit23-16: muteUvalue + bit15-8: muteVvalue + bit0: 1:mute, 0: unmute + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_VIDEO_MUTE (CPU_CMD_MASK_CAPTURE | 0x0013) + +/* Description: Set audio mute + IN[0] - task handle. Handle of the task to start + IN[1] - mute/unmute + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_AUDIO_MUTE (CPU_CMD_MASK_CAPTURE | 0x0014) + +/* Description: Set stream output type + IN[0] - task handle. Handle of the task to start + IN[1] - subType + SET_INITIAL_SCR 1 + SET_QUALITY_MODE 2 + SET_VIM_PROTECT_MODE 3 + SET_PTS_CORRECTION 4 + SET_USB_FLUSH_MODE 5 + SET_MERAQPAR_ENABLE 6 + SET_NAV_PACK_INSERTION 7 + SET_SCENE_CHANGE_ENABLE 8 + IN[2] - parameter 1 + IN[3] - parameter 2 + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_MISC_PARAMETERS (CPU_CMD_MASK_CAPTURE | 0x0015) + +/* Description: Set raw VBI parameters + IN[0] - Task handle + IN[1] - No. of input lines per field: + bit[15:0]: field 1, + bit[31:16]: field 2 + IN[2] - No. of input bytes per line + IN[3] - No. of output frames per transfer + IN[4] - start code + IN[5] - stop code + ReturnCode */ +#define CX18_CPU_SET_RAW_VBI_PARAM (CPU_CMD_MASK_CAPTURE | 0x0016) + +/* Description: Set capture line No. + IN[0] - task handle. Handle of the task to start + IN[1] - height1 + IN[2] - height2 + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_CAPTURE_LINE_NO (CPU_CMD_MASK_CAPTURE | 0x0017) + +/* Description: Set copyright + IN[0] - task handle. Handle of the task to start + IN[1] - copyright + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_COPYRIGHT (CPU_CMD_MASK_CAPTURE | 0x0018) + +/* Description: Set audio PID + IN[0] - task handle. Handle of the task to start + IN[1] - PID + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_AUDIO_PID (CPU_CMD_MASK_CAPTURE | 0x0019) + +/* Description: Set video PID + IN[0] - task handle. Handle of the task to start + IN[1] - PID + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_VIDEO_PID (CPU_CMD_MASK_CAPTURE | 0x001A) + +/* Description: Set Vertical Crop Line + IN[0] - task handle. Handle of the task to start + IN[1] - Line + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_VER_CROP_LINE (CPU_CMD_MASK_CAPTURE | 0x001B) + +/* Description: Set COP structure + IN[0] - task handle. Handle of the task to start + IN[1] - M + IN[2] - N + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_GOP_STRUCTURE (CPU_CMD_MASK_CAPTURE | 0x001C) + +/* Description: Set Scene Change Detection + IN[0] - task handle. Handle of the task to start + IN[1] - scene change + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_SCENE_CHANGE_DETECTION (CPU_CMD_MASK_CAPTURE | 0x001D) + +/* Description: Set Aspect Ratio + IN[0] - task handle. Handle of the task to start + IN[1] - AspectRatio + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_ASPECT_RATIO (CPU_CMD_MASK_CAPTURE | 0x001E) + +/* Description: Set Skip Input Frame + IN[0] - task handle. Handle of the task to start + IN[1] - skip input frames + ReturnCode - One of the ERR_CAPTURE_... */ +#define CX18_CPU_SET_SKIP_INPUT_FRAME (CPU_CMD_MASK_CAPTURE | 0x001F) + +/* Description: Set sliced VBI parameters - + Note This API will only apply to MPEG and Sliced VBI Channels + IN[0] - Task handle + IN[1] - output type, 0 - CC, 1 - Moji, 2 - Teletext + IN[2] - start / stop line + bit[15:0] start line number + bit[31:16] stop line number + IN[3] - number of output frames per interrupt + IN[4] - VBI insertion mode + bit 0: output user data, 1 - enable + bit 1: output private stream, 1 - enable + bit 2: mux option, 0 - in GOP, 1 - in picture + bit[7:0] private stream ID + IN[5] - insertion period while mux option is in picture + ReturnCode - VBI data offset */ +#define CX18_CPU_SET_SLICED_VBI_PARAM (CPU_CMD_MASK_CAPTURE | 0x0020) + +/* Description: Set the user data place holder + IN[0] - type of data (0 for user) + IN[1] - Stuffing period + IN[2] - ID data size in word (less than 10) + IN[3] - Pointer to ID buffer */ +#define CX18_CPU_SET_USERDATA_PLACE_HOLDER (CPU_CMD_MASK_CAPTURE | 0x0021) + + +/* Description: + In[0] Task Handle + return parameter: + Out[0] Reserved + Out[1] Video PTS bit[32:2] of last output video frame. + Out[2] Video PTS bit[ 1:0] of last output video frame. + Out[3] Hardware Video PTS counter bit[31:0], + these bits get incremented on every 90kHz clock tick. + Out[4] Hardware Video PTS counter bit32, + these bits get incremented on every 90kHz clock tick. + ReturnCode */ +#define CX18_CPU_GET_ENC_PTS (CPU_CMD_MASK_CAPTURE | 0x0022) + +/* Below is the list of commands related to the data exchange */ +#define CPU_CMD_MASK_DE (CPU_CMD_MASK | 0x040000) + +/* Description: This command provides the physical base address of the local + DDR as viewed by EPU + IN[0] - Physical offset where EPU has the local DDR mapped + ReturnCode - One of the ERR_DE_... */ +#define CPU_CMD_DE_SetBase (CPU_CMD_MASK_DE | 0x0001) + +/* Description: This command provides the offsets in the device memory where + the 2 cx18_mdl_ack blocks reside + IN[0] - Task handle. Handle of the task to start + IN[1] - Offset of the first cx18_mdl_ack from the beginning of the + local DDR. + IN[2] - Offset of the second cx18_mdl_ack from the beginning of the + local DDR. + ReturnCode - One of the ERR_DE_... */ +#define CX18_CPU_DE_SET_MDL_ACK (CPU_CMD_MASK_DE | 0x0002) + +/* Description: This command provides the offset to a Memory Descriptor List + IN[0] - Task handle. Handle of the task to start + IN[1] - Offset of the MDL from the beginning of the local DDR. + IN[2] - Number of cx18_mdl structures in the array pointed to by IN[1] + IN[3] - Buffer ID + IN[4] - Total buffer length + ReturnCode - One of the ERR_DE_... */ +#define CX18_CPU_DE_SET_MDL (CPU_CMD_MASK_DE | 0x0005) + +/* Description: This command requests return of all current Memory + Descriptor Lists to the driver + IN[0] - Task handle. Handle of the task to start + ReturnCode - One of the ERR_DE_... */ +/* #define CX18_CPU_DE_ReleaseMDL (CPU_CMD_MASK_DE | 0x0006) */ + +/* Description: This command signals the cpu that the dat buffer has been + consumed and ready for re-use. + IN[0] - Task handle. Handle of the task + IN[1] - Offset of the data block from the beginning of the local DDR. + IN[2] - Number of bytes in the data block + ReturnCode - One of the ERR_DE_... */ +/* #define CX18_CPU_DE_RELEASE_BUFFER (CPU_CMD_MASK_DE | 0x0007) */ + +/* No Error / Success */ +#define CNXT_OK 0x000000 + +/* Received unknown command */ +#define CXERR_UNK_CMD 0x000001 + +/* First parameter in the command is invalid */ +#define CXERR_INVALID_PARAM1 0x000002 + +/* Second parameter in the command is invalid */ +#define CXERR_INVALID_PARAM2 0x000003 + +/* Device interface is not open/found */ +#define CXERR_DEV_NOT_FOUND 0x000004 + +/* Requested function is not implemented/available */ +#define CXERR_NOTSUPPORTED 0x000005 + +/* Invalid pointer is provided */ +#define CXERR_BADPTR 0x000006 + +/* Unable to allocate memory */ +#define CXERR_NOMEM 0x000007 + +/* Object/Link not found */ +#define CXERR_LINK 0x000008 + +/* Device busy, command cannot be executed */ +#define CXERR_BUSY 0x000009 + +/* File/device/handle is not open. */ +#define CXERR_NOT_OPEN 0x00000A + +/* Value is out of range */ +#define CXERR_OUTOFRANGE 0x00000B + +/* Buffer overflow */ +#define CXERR_OVERFLOW 0x00000C + +/* Version mismatch */ +#define CXERR_BADVER 0x00000D + +/* Operation timed out */ +#define CXERR_TIMEOUT 0x00000E + +/* Operation aborted */ +#define CXERR_ABORT 0x00000F + +/* Specified I2C device not found for read/write */ +#define CXERR_I2CDEV_NOTFOUND 0x000010 + +/* Error in I2C data xfer (but I2C device is present) */ +#define CXERR_I2CDEV_XFERERR 0x000011 + +/* Chanel changing component not ready */ +#define CXERR_CHANNELNOTREADY 0x000012 + +/* PPU (Presensation/Decoder) mail box is corrupted */ +#define CXERR_PPU_MB_CORRUPT 0x000013 + +/* CPU (Capture/Encoder) mail box is corrupted */ +#define CXERR_CPU_MB_CORRUPT 0x000014 + +/* APU (Audio) mail box is corrupted */ +#define CXERR_APU_MB_CORRUPT 0x000015 + +/* Unable to open file for reading */ +#define CXERR_FILE_OPEN_READ 0x000016 + +/* Unable to open file for writing */ +#define CXERR_FILE_OPEN_WRITE 0x000017 + +/* Unable to find the I2C section specified */ +#define CXERR_I2C_BADSECTION 0x000018 + +/* Error in I2C data xfer (but I2C device is present) */ +#define CXERR_I2CDEV_DATALOW 0x000019 + +/* Error in I2C data xfer (but I2C device is present) */ +#define CXERR_I2CDEV_CLOCKLOW 0x00001A + +/* No Interrupt received from HW (for I2C access) */ +#define CXERR_NO_HW_I2C_INTR 0x00001B + +/* RPU is not ready to accept commands! */ +#define CXERR_RPU_NOT_READY 0x00001C + +/* RPU is not ready to accept commands! */ +#define CXERR_RPU_NO_ACK 0x00001D + +/* The are no buffers ready. Try again soon! */ +#define CXERR_NODATA_AGAIN 0x00001E + +/* The stream is stopping. Function not alllowed now! */ +#define CXERR_STOPPING_STATUS 0x00001F + +/* Trying to access hardware when the power is turned OFF */ +#define CXERR_DEVPOWER_OFF 0x000020 + +#endif /* CX23418_H */ diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig index ca5fbce3a909..cadf936c3673 100644 --- a/drivers/media/video/cx23885/Kconfig +++ b/drivers/media/video/cx23885/Kconfig @@ -4,19 +4,19 @@ config VIDEO_CX23885 select I2C_ALGOBIT select FW_LOADER select VIDEO_BTCX - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_TVEEPROM select VIDEO_IR select VIDEOBUF_DVB select VIDEO_CX25840 - select DVB_TUNER_MT2131 if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_MT2131 if !DVB_FE_CUSTOMISE select DVB_S5H1409 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE select DVB_PLL if !DVB_FE_CUSTOMISE - select TUNER_XC2028 if !DVB_FE_CUSTOMIZE - select TUNER_TDA8290 if !DVB_FE_CUSTOMIZE - select DVB_TDA18271 if !DVB_FE_CUSTOMIZE - select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE select DVB_TDA10048 if !DVB_FE_CUSTOMIZE ---help--- This is a video4linux driver for Conexant 23885 based diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile index d7b0721af062..29c23b44c13c 100644 --- a/drivers/media/video/cx23885/Makefile +++ b/drivers/media/video/cx23885/Makefile @@ -3,6 +3,7 @@ cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o cx23885-core.o cx2 obj-$(CONFIG_VIDEO_CX23885) += cx23885.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 7fde678b2c4a..88823810497c 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -1209,7 +1209,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, /* ----------------------------------------------------------------------- */ -static int cx25840_probe(struct i2c_client *client) +static int cx25840_probe(struct i2c_client *client, + const struct i2c_device_id *did) { struct cx25840_state *state; u32 id; diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index 27635cdcbaf2..b0d7d6a7a4cc 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig @@ -5,7 +5,7 @@ config VIDEO_CX88 select FW_LOADER select VIDEO_BTCX select VIDEOBUF_DMA_SG - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_TVEEPROM select VIDEO_IR select VIDEO_WM8775 if VIDEO_HELPER_CHIPS_AUTO @@ -57,7 +57,7 @@ config VIDEO_CX88_DVB select DVB_NXT200X if !DVB_FE_CUSTOMISE select DVB_CX24123 if !DVB_FE_CUSTOMISE select DVB_ISL6421 if !DVB_FE_CUSTOMISE - select TUNER_SIMPLE if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE select DVB_S5H1411 if !DVB_FE_CUSTOMISE ---help--- This adds support for DVB/ATSC cards based on the diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile index 532cee35eb3c..6ec30f242578 100644 --- a/drivers/media/video/cx88/Makefile +++ b/drivers/media/video/cx88/Makefile @@ -10,5 +10,6 @@ obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 2b6b283cda15..aeba26dc0a37 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -57,6 +57,9 @@ MODULE_PARM_DESC(latency,"pci latency timer"); /* ------------------------------------------------------------------ */ /* board config info */ +/* If radio_type !=UNSET, radio_addr should be specified + */ + static const struct cx88_board cx88_boards[] = { [CX88_BOARD_UNKNOWN] = { .name = "UNKNOWN/GENERIC", @@ -2446,25 +2449,31 @@ EXPORT_SYMBOL_GPL(cx88_setup_xc3028); static void cx88_card_setup(struct cx88_core *core) { static u8 eeprom[256]; + struct tuner_setup tun_setup; + unsigned int mode_mask = T_RADIO | + T_ANALOG_TV | + T_DIGITAL_TV; + + memset(&tun_setup, 0, sizeof(tun_setup)); if (0 == core->i2c_rc) { core->i2c_client.addr = 0xa0 >> 1; - tveeprom_read(&core->i2c_client,eeprom,sizeof(eeprom)); + tveeprom_read(&core->i2c_client, eeprom, sizeof(eeprom)); } switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE: case CX88_BOARD_HAUPPAUGE_ROSLYN: if (0 == core->i2c_rc) - hauppauge_eeprom(core,eeprom+8); + hauppauge_eeprom(core, eeprom+8); break; case CX88_BOARD_GDI: if (0 == core->i2c_rc) - gdi_eeprom(core,eeprom); + gdi_eeprom(core, eeprom); break; case CX88_BOARD_WINFAST2000XP_EXPERT: if (0 == core->i2c_rc) - leadtek_eeprom(core,eeprom); + leadtek_eeprom(core, eeprom); break; case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: @@ -2474,7 +2483,7 @@ static void cx88_card_setup(struct cx88_core *core) case CX88_BOARD_HAUPPAUGE_HVR3000: case CX88_BOARD_HAUPPAUGE_HVR1300: if (0 == core->i2c_rc) - hauppauge_eeprom(core,eeprom); + hauppauge_eeprom(core, eeprom); break; case CX88_BOARD_KWORLD_DVBS_100: cx_write(MO_GP0_IO, 0x000007f8); @@ -2555,6 +2564,35 @@ static void cx88_card_setup(struct cx88_core *core) cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tea5767_cfg); } + } /*end switch() */ + + + /* Setup tuners */ + if ((core->board.radio_type != UNSET)) { + tun_setup.mode_mask = T_RADIO; + tun_setup.type = core->board.radio_type; + tun_setup.addr = core->board.radio_addr; + tun_setup.tuner_callback = cx88_tuner_callback; + cx88_call_i2c_clients(core, TUNER_SET_TYPE_ADDR, &tun_setup); + mode_mask &= ~T_RADIO; + } + + if (core->board.tuner_type != TUNER_ABSENT) { + tun_setup.mode_mask = mode_mask; + tun_setup.type = core->board.tuner_type; + tun_setup.addr = core->board.tuner_addr; + tun_setup.tuner_callback = cx88_tuner_callback; + + cx88_call_i2c_clients(core, TUNER_SET_TYPE_ADDR, &tun_setup); + } + + if (core->board.tda9887_conf) { + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &core->board.tda9887_conf; + + cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tda9887_cfg); } if (core->board.tuner_type == TUNER_XC2028) { @@ -2572,6 +2610,7 @@ static void cx88_card_setup(struct cx88_core *core) ctl.fname); cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &xc2028_cfg); } + cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL); } /* ------------------------------------------------------------------ */ @@ -2710,7 +2749,6 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) if (TUNER_ABSENT != core->board.tuner_type) request_module("tuner"); - cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL); cx88_card_setup(core); cx88_ir_init(core, pci); diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c index c6b44732a082..cb6a096069c7 100644 --- a/drivers/media/video/cx88/cx88-i2c.c +++ b/drivers/media/video/cx88/cx88-i2c.c @@ -99,42 +99,11 @@ static int cx8800_bit_getsda(void *data) static int attach_inform(struct i2c_client *client) { - struct tuner_setup tun_setup; struct cx88_core *core = i2c_get_adapdata(client->adapter); dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n", client->driver->driver.name, client->addr, client->name); - if (!client->driver->command) - return 0; - - if (core->board.radio_type != UNSET) { - if ((core->board.radio_addr==ADDR_UNSET)||(core->board.radio_addr==client->addr)) { - tun_setup.mode_mask = T_RADIO; - tun_setup.type = core->board.radio_type; - tun_setup.addr = core->board.radio_addr; - tun_setup.tuner_callback = cx88_tuner_callback; - client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup); - } - } - if (core->board.tuner_type != UNSET) { - if ((core->board.tuner_addr==ADDR_UNSET)||(core->board.tuner_addr==client->addr)) { - - tun_setup.mode_mask = T_ANALOG_TV; - tun_setup.type = core->board.tuner_type; - tun_setup.addr = core->board.tuner_addr; - tun_setup.tuner_callback = cx88_tuner_callback; - client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup); - } - } - - if (core->board.tda9887_conf) { - struct v4l2_priv_tun_config tda9887_cfg; - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &core->board.tda9887_conf; - - client->driver->command(client, TUNER_SET_CONFIG, &tda9887_cfg); - } return 0; } diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig index 9caffed2b6b8..c7c2896bbd8b 100644 --- a/drivers/media/video/em28xx/Kconfig +++ b/drivers/media/video/em28xx/Kconfig @@ -1,7 +1,7 @@ config VIDEO_EM28XX tristate "Empia EM28xx USB video capture support" depends on VIDEO_DEV && I2C && INPUT - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_TVEEPROM select VIDEO_IR select VIDEOBUF_VMALLOC diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile index 3d1c3cc337fe..8137a8c94bfc 100644 --- a/drivers/media/video/em28xx/Makefile +++ b/drivers/media/video/em28xx/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig index b6171702c4d0..eec115bf9517 100644 --- a/drivers/media/video/ivtv/Kconfig +++ b/drivers/media/video/ivtv/Kconfig @@ -4,7 +4,7 @@ config VIDEO_IVTV select I2C_ALGOBIT select FW_LOADER select VIDEO_IR - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_TVEEPROM select VIDEO_CX2341X select VIDEO_CX25840 diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile index a0389014fa88..26ce0d6eaee1 100644 --- a/drivers/media/video/ivtv/Makefile +++ b/drivers/media/video/ivtv/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_VIDEO_IVTV) += ivtv.o obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c index e908649ea37c..4fb8faefe2ce 100644 --- a/drivers/media/video/ivtv/ivtv-cards.c +++ b/drivers/media/video/ivtv/ivtv-cards.c @@ -40,6 +40,8 @@ #define MSP_MONO MSP_INPUT(MSP_IN_MONO, MSP_IN_TUNER1, \ MSP_DSP_IN_SCART, MSP_DSP_IN_SCART) +#define V4L2_STD_NOT_MN (V4L2_STD_PAL|V4L2_STD_SECAM) + /* usual i2c tuner addresses to probe */ static struct ivtv_card_tuner_i2c ivtv_i2c_std = { .radio = { I2C_CLIENT_END }, @@ -298,7 +300,7 @@ static const struct ivtv_card ivtv_card_mpg600 = { .gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 }, .tuners = { /* The PAL tuner is confirmed */ - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_mpg600, @@ -339,7 +341,7 @@ static const struct ivtv_card ivtv_card_mpg160 = { .lang1 = 0x0004, .lang2 = 0x0000, .both = 0x0008 }, .gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 }, .tuners = { - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_mpg160, @@ -375,7 +377,7 @@ static const struct ivtv_card ivtv_card_pg600 = { { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL }, }, .tuners = { - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_pg600, @@ -416,7 +418,7 @@ static const struct ivtv_card ivtv_card_avc2410 = { on the country/region setting of the user to decide which tuner is available. */ .tuners = { - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, { .std = V4L2_STD_ALL - V4L2_STD_NTSC_M_JP, .tuner = TUNER_PHILIPS_FM1236_MK3 }, { .std = V4L2_STD_NTSC_M_JP, .tuner = TUNER_PHILIPS_FQ1286 }, @@ -490,7 +492,7 @@ static const struct ivtv_card ivtv_card_tg5000tv = { .gpio_video_input = { .mask = 0x0030, .tuner = 0x0000, .composite = 0x0010, .svideo = 0x0020 }, .tuners = { - { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, + { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_tg5000tv, .i2c = &ivtv_i2c_std, @@ -521,7 +523,7 @@ static const struct ivtv_card ivtv_card_va2000 = { { IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER }, }, .tuners = { - { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, + { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_va2000, .i2c = &ivtv_i2c_std, @@ -565,7 +567,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc = { .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, .f44100 = 0x4000, .f48000 = 0x8000 }, .tuners = { - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, .pci_list = ivtv_pci_cx23416gyc, @@ -597,7 +599,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogr = { .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, .f44100 = 0x4000, .f48000 = 0x8000 }, .tuners = { - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, .i2c = &ivtv_i2c_std, @@ -627,7 +629,7 @@ static const struct ivtv_card ivtv_card_cx23416gyc_nogrycs = { .gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000, .f44100 = 0x4000, .f48000 = 0x8000 }, .tuners = { - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, .i2c = &ivtv_i2c_std, @@ -667,7 +669,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx = { .gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 }, .tuners = { /* This card has the Panasonic VP27 tuner */ - { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 }, + { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 }, }, .pci_list = ivtv_pci_gv_mvprx, .i2c = &ivtv_i2c_std, @@ -704,7 +706,7 @@ static const struct ivtv_card ivtv_card_gv_mvprx2e = { .gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 }, .tuners = { /* This card has the Panasonic VP27 tuner */ - { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 }, + { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 }, }, .pci_list = ivtv_pci_gv_mvprx2e, .i2c = &ivtv_i2c_std, @@ -739,7 +741,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd = { .gpio_init = { .direction = 0xf000, .initial_value = 0xA000 }, .tuners = { /* This card has a Philips FQ1216ME MK3 tuner */ - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, }, .pci_list = ivtv_pci_gotview_pci_dvd, .i2c = &ivtv_i2c_std, @@ -778,7 +780,7 @@ static const struct ivtv_card ivtv_card_gotview_pci_dvd2 = { .gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 }, .tuners = { /* This card has a Philips FQ1216ME MK5 tuner */ - { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, + { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, }, .pci_list = ivtv_pci_gotview_pci_dvd2, .i2c = &ivtv_i2c_std, @@ -856,7 +858,7 @@ static const struct ivtv_card ivtv_card_dctmvtvp1 = { .gpio_video_input = { .mask = 0x0030, .tuner = 0x0000, .composite = 0x0010, .svideo = 0x0020}, .tuners = { - { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 }, + { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 }, }, .pci_list = ivtv_pci_dctmvtvp1, .i2c = &ivtv_i2c_std, @@ -875,6 +877,7 @@ static const struct ivtv_card_pci_info ivtv_pci_pg600v2[] = { static const struct ivtv_card ivtv_card_pg600v2 = { .type = IVTV_CARD_PG600V2, .name = "Yuan PG600-2, GotView PCI DVD Lite", + .comment = "only Composite and S-Video inputs are supported, not the tuner\n", .v4l2_capabilities = IVTV_CAP_ENCODER, .hw_video = IVTV_HW_CX25840, .hw_audio = IVTV_HW_CX25840, @@ -921,6 +924,7 @@ static const struct ivtv_card ivtv_card_club3d = { }, .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, .gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */ + .xceive_pin = 12, .tuners = { { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, }, @@ -944,15 +948,22 @@ static const struct ivtv_card ivtv_card_avertv_mce116 = { .hw_video = IVTV_HW_CX25840, .hw_audio = IVTV_HW_CX25840, .hw_audio_ctrl = IVTV_HW_CX25840, - .hw_all = IVTV_HW_CX25840 | IVTV_HW_WM8739, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739, .video_inputs = { - { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 }, - { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 }, + { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 }, + { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO3 }, + { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 }, }, .audio_inputs = { + { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 }, { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, }, - .gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, /* enable line-in */ + /* enable line-in */ + .gpio_init = { .direction = 0xe400, .initial_value = 0x4400 }, + .xceive_pin = 10, + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, .pci_list = ivtv_pci_avertv_mce116, .i2c = &ivtv_i2c_std, }; @@ -990,7 +1001,7 @@ static const struct ivtv_card ivtv_card_aver_pvr150 = { .gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 }, .tuners = { /* This card has a Partsnic PTI-5NF05 tuner */ - { .std = V4L2_STD_525_60, .tuner = TUNER_TCL_2002N }, + { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_TCL_2002N }, }, .pci_list = ivtv_pci_aver_pvr150, .i2c = &ivtv_i2c_radio, @@ -1058,12 +1069,48 @@ static const struct ivtv_card ivtv_card_asus_falcon2 = { }, .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, M52790_IN_TUNER }, .tuners = { - { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FM1236_MK3 }, + { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FM1236_MK3 }, }, .pci_list = ivtv_pci_asus_falcon2, .i2c = &ivtv_i2c_std, }; +/* ------------------------------------------------------------------------- */ + +/* AVerMedia M104 miniPCI card */ + +static const struct ivtv_card_pci_info ivtv_pci_aver_m104[] = { + { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc136 }, + { 0, 0, 0 } +}; + +static const struct ivtv_card ivtv_card_aver_m104 = { + .type = IVTV_CARD_AVER_M104, + .name = "AVerMedia M104", + .comment = "Not yet supported!\n", + .v4l2_capabilities = 0, /*IVTV_CAP_ENCODER,*/ + .hw_video = IVTV_HW_CX25840, + .hw_audio = IVTV_HW_CX25840, + .hw_audio_ctrl = IVTV_HW_CX25840, + .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739, + .video_inputs = { + { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 }, + { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 }, + }, + .audio_inputs = { + { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 }, + }, + .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 }, + /* enable line-in + reset tuner */ + .gpio_init = { .direction = 0xe400, .initial_value = 0x4000 }, + .xceive_pin = 10, + .tuners = { + { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, + }, + .pci_list = ivtv_pci_aver_m104, + .i2c = &ivtv_i2c_std, +}; + static const struct ivtv_card *ivtv_card_list[] = { &ivtv_card_pvr250, &ivtv_card_pvr350, @@ -1089,6 +1136,7 @@ static const struct ivtv_card *ivtv_card_list[] = { &ivtv_card_asus_falcon2, &ivtv_card_aver_pvr150, &ivtv_card_aver_ezmaker, + &ivtv_card_aver_m104, /* Variations of standard cards but with the same PCI IDs. These cards must come last in this list. */ @@ -1120,7 +1168,8 @@ int ivtv_get_input(struct ivtv *itv, u16 index, struct v4l2_input *input) if (index >= itv->nof_inputs) return -EINVAL; input->index = index; - strcpy(input->name, input_strs[card_input->video_type - 1]); + strlcpy(input->name, input_strs[card_input->video_type - 1], + sizeof(input->name)); input->type = (card_input->video_type == IVTV_CARD_INPUT_VID_TUNER ? V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA); input->audioset = (1 << itv->nof_audio_inputs) - 1; @@ -1137,7 +1186,7 @@ int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output) if (index >= itv->card->nof_outputs) return -EINVAL; output->index = index; - strcpy(output->name, card_output->name); + strlcpy(output->name, card_output->name, sizeof(output->name)); output->type = V4L2_OUTPUT_TYPE_ANALOG; output->audioset = 1; output->std = V4L2_STD_ALL; @@ -1156,7 +1205,8 @@ int ivtv_get_audio_input(struct ivtv *itv, u16 index, struct v4l2_audio *audio) memset(audio, 0, sizeof(*audio)); if (index >= itv->nof_audio_inputs) return -EINVAL; - strcpy(audio->name, input_strs[aud_input->audio_type - 1]); + strlcpy(audio->name, input_strs[aud_input->audio_type - 1], + sizeof(audio->name)); audio->index = index; audio->capability = V4L2_AUDCAP_STEREO; return 0; @@ -1167,6 +1217,6 @@ int ivtv_get_audio_output(struct ivtv *itv, u16 index, struct v4l2_audioout *aud memset(aud_output, 0, sizeof(*aud_output)); if (itv->card->video_outputs == NULL || index != 0) return -EINVAL; - strcpy(aud_output->name, "A/V Audio Out"); + strlcpy(aud_output->name, "A/V Audio Out", sizeof(aud_output->name)); return 0; } diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h index 9186fa2ee5fc..748485dcebbd 100644 --- a/drivers/media/video/ivtv/ivtv-cards.h +++ b/drivers/media/video/ivtv/ivtv-cards.h @@ -48,7 +48,8 @@ #define IVTV_CARD_ASUS_FALCON2 21 /* ASUS Falcon2 */ #define IVTV_CARD_AVER_PVR150PLUS 22 /* AVerMedia PVR-150 Plus */ #define IVTV_CARD_AVER_EZMAKER 23 /* AVerMedia EZMaker PCI Deluxe */ -#define IVTV_CARD_LAST 23 +#define IVTV_CARD_AVER_M104 24 /* AverMedia M104 miniPCI card */ +#define IVTV_CARD_LAST 24 /* Variants of existing cards but with the same PCI IDs. The driver detects these based on other device information. @@ -244,6 +245,7 @@ struct ivtv_card_tuner_i2c { struct ivtv_card { int type; char *name; + char *comment; u32 v4l2_capabilities; u32 hw_video; /* hardware used to process video */ u32 hw_audio; /* hardware used to process audio */ @@ -256,6 +258,7 @@ struct ivtv_card { int nof_outputs; const struct ivtv_card_output *video_outputs; u8 gr_config; /* config byte for the ghost reduction device */ + u8 xceive_pin; /* XCeive tuner GPIO reset pin */ /* GPIO card-specific settings */ struct ivtv_gpio_init gpio_init; diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c index 065df53f80fd..ed020f722b05 100644 --- a/drivers/media/video/ivtv/ivtv-driver.c +++ b/drivers/media/video/ivtv/ivtv-driver.c @@ -190,6 +190,7 @@ MODULE_PARM_DESC(cardtype, "\t\t\t22 = ASUS Falcon2\n" "\t\t\t23 = AverMedia PVR-150 Plus\n" "\t\t\t24 = AverMedia EZMaker PCI Deluxe\n" + "\t\t\t25 = AverMedia M104 (not yet working)\n" "\t\t\t 0 = Autodetect (default)\n" "\t\t\t-1 = Ignore this card\n\t\t"); MODULE_PARM_DESC(pal, "Set PAL standard: BGH, DK, I, M, N, Nc, 60"); @@ -871,7 +872,7 @@ static void ivtv_load_and_init_modules(struct ivtv *itv) unsigned i; /* load modules */ -#ifndef CONFIG_VIDEO_TUNER +#ifndef CONFIG_MEDIA_TUNER hw = ivtv_request_module(itv, hw, "tuner", IVTV_HW_TUNER); #endif #ifndef CONFIG_VIDEO_CX25840 @@ -1048,7 +1049,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev, IVTV_ENCODER_SIZE); if (!itv->enc_mem) { IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n"); - IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n"); + IVTV_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n"); retval = -ENOMEM; goto free_mem; } @@ -1060,7 +1061,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev, IVTV_DECODER_SIZE); if (!itv->dec_mem) { IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n"); - IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n"); + IVTV_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n"); retval = -ENOMEM; goto free_mem; } @@ -1076,7 +1077,7 @@ static int __devinit ivtv_probe(struct pci_dev *dev, ioremap_nocache(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); if (!itv->reg_mem) { IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n"); - IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n"); + IVTV_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n"); retval = -ENOMEM; goto free_io; } @@ -1097,6 +1098,13 @@ static int __devinit ivtv_probe(struct pci_dev *dev, The PCI IDs are not always reliable. */ ivtv_process_eeprom(itv); } + if (itv->card->comment) + IVTV_INFO("%s", itv->card->comment); + if (itv->card->v4l2_capabilities == 0) { + /* card was detected but is not supported */ + retval = -ENODEV; + goto free_i2c; + } if (itv->std == 0) { itv->std = V4L2_STD_NTSC_M; @@ -1195,13 +1203,6 @@ static int __devinit ivtv_probe(struct pci_dev *dev, ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std); } - retval = ivtv_streams_setup(itv); - if (retval) { - IVTV_ERR("Error %d setting up streams\n", retval); - goto free_i2c; - } - - IVTV_DEBUG_IRQ("Masking interrupts\n"); /* clear interrupt mask, effectively disabling interrupts */ ivtv_set_irq_mask(itv, 0xffffffff); @@ -1210,32 +1211,38 @@ static int __devinit ivtv_probe(struct pci_dev *dev, IRQF_SHARED | IRQF_DISABLED, itv->name, (void *)itv); if (retval) { IVTV_ERR("Failed to register irq %d\n", retval); - goto free_streams; + goto free_i2c; + } + + retval = ivtv_streams_setup(itv); + if (retval) { + IVTV_ERR("Error %d setting up streams\n", retval); + goto free_irq; } retval = ivtv_streams_register(itv); if (retval) { IVTV_ERR("Error %d registering devices\n", retval); - goto free_irq; + goto free_streams; } IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name); return 0; - free_irq: - free_irq(itv->dev->irq, (void *)itv); - free_streams: +free_streams: ivtv_streams_cleanup(itv); - free_i2c: +free_irq: + free_irq(itv->dev->irq, (void *)itv); +free_i2c: exit_ivtv_i2c(itv); - free_io: +free_io: ivtv_iounmap(itv); - free_mem: +free_mem: release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); if (itv->has_cx23415) release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); - free_workqueue: +free_workqueue: destroy_workqueue(itv->irq_work_queues); - err: +err: if (retval == 0) retval = -ENODEV; IVTV_ERR("Error %d on initialization\n", retval); diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c index a7640c49f1d8..2b74b0ab1477 100644 --- a/drivers/media/video/ivtv/ivtv-fileops.c +++ b/drivers/media/video/ivtv/ivtv-fileops.c @@ -755,8 +755,10 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait) IVTV_DEBUG_HI_FILE("Encoder poll\n"); poll_wait(filp, &s->waitq, wait); - if (eof || s->q_full.length || s->q_io.length) + if (s->q_full.length || s->q_io.length) return POLLIN | POLLRDNORM; + if (eof) + return POLLHUP; return 0; } diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c index 688cd3856685..d8ac09f3cce6 100644 --- a/drivers/media/video/ivtv/ivtv-gpio.c +++ b/drivers/media/video/ivtv/ivtv-gpio.c @@ -128,20 +128,17 @@ int ivtv_reset_tuner_gpio(void *dev, int cmd, int value) { struct i2c_algo_bit_data *algo = dev; struct ivtv *itv = algo->data; - int curdir, curout; + u32 curout; if (cmd != XC2028_TUNER_RESET) return 0; IVTV_DEBUG_INFO("Resetting tuner\n"); curout = read_reg(IVTV_REG_GPIO_OUT); - curdir = read_reg(IVTV_REG_GPIO_DIR); - curdir |= (1 << 12); /* GPIO bit 12 */ - - curout &= ~(1 << 12); + curout &= ~(1 << itv->card->xceive_pin); write_reg(curout, IVTV_REG_GPIO_OUT); schedule_timeout_interruptible(msecs_to_jiffies(1)); - curout |= (1 << 12); + curout |= 1 << itv->card->xceive_pin; write_reg(curout, IVTV_REG_GPIO_OUT); schedule_timeout_interruptible(msecs_to_jiffies(1)); return 0; diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c index 9824eafee021..771adf47e944 100644 --- a/drivers/media/video/ivtv/ivtv-i2c.c +++ b/drivers/media/video/ivtv/ivtv-i2c.c @@ -167,7 +167,8 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx) return -1; id = hw_driverids[idx]; memset(&info, 0, sizeof(info)); - strcpy(info.driver_name, hw_drivernames[idx]); + strlcpy(info.driver_name, hw_drivernames[idx], + sizeof(info.driver_name)); info.addr = hw_addrs[idx]; for (i = 0; itv->i2c_clients[i] && i < I2C_CLIENTS_MAX; i++) {} diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c index 15cac1812122..d508b5d0538c 100644 --- a/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/drivers/media/video/ivtv/ivtv-ioctl.c @@ -243,20 +243,31 @@ static int ivtv_validate_speed(int cur_speed, int new_speed) int fact = new_speed < 0 ? -1 : 1; int s; - if (new_speed < 0) new_speed = -new_speed; - if (cur_speed < 0) cur_speed = -cur_speed; + if (cur_speed == 0) + cur_speed = 1000; + if (new_speed < 0) + new_speed = -new_speed; + if (cur_speed < 0) + cur_speed = -cur_speed; if (cur_speed <= new_speed) { - if (new_speed > 1500) return fact * 2000; - if (new_speed > 1000) return fact * 1500; + if (new_speed > 1500) + return fact * 2000; + if (new_speed > 1000) + return fact * 1500; } else { - if (new_speed >= 2000) return fact * 2000; - if (new_speed >= 1500) return fact * 1500; - if (new_speed >= 1000) return fact * 1000; - } - if (new_speed == 0) return 1000; - if (new_speed == 1 || new_speed == 1000) return fact * new_speed; + if (new_speed >= 2000) + return fact * 2000; + if (new_speed >= 1500) + return fact * 1500; + if (new_speed >= 1000) + return fact * 1000; + } + if (new_speed == 0) + return 1000; + if (new_speed == 1 || new_speed == 1000) + return fact * new_speed; s = new_speed; new_speed = 1000 / new_speed; @@ -741,10 +752,9 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void struct v4l2_capability *vcap = arg; memset(vcap, 0, sizeof(*vcap)); - strcpy(vcap->driver, IVTV_DRIVER_NAME); /* driver name */ - strncpy(vcap->card, itv->card_name, - sizeof(vcap->card)-1); /* card type */ - strcpy(vcap->bus_info, pci_name(itv->dev)); /* bus info... */ + strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver)); + strlcpy(vcap->card, itv->card_name, sizeof(vcap->card)); + strlcpy(vcap->bus_info, pci_name(itv->dev), sizeof(vcap->bus_info)); vcap->version = IVTV_DRIVER_VERSION; /* version */ vcap->capabilities = itv->v4l2_cap; /* capabilities */ @@ -1018,7 +1028,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void ivtv_std_60hz : ivtv_std_50hz; vs->index = idx; vs->id = enum_stds[idx].std; - strcpy(vs->name, enum_stds[idx].name); + strlcpy(vs->name, enum_stds[idx].name, sizeof(vs->name)); break; } @@ -1102,10 +1112,10 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, vt); if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) { - strcpy(vt->name, "ivtv Radio Tuner"); + strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name)); vt->type = V4L2_TUNER_RADIO; } else { - strcpy(vt->name, "ivtv TV Tuner"); + strlcpy(vt->name, "ivtv TV Tuner", sizeof(vt->name)); vt->type = V4L2_TUNER_ANALOG_TV; } break; diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c index a329c4689dbf..d8ba3a4a8761 100644 --- a/drivers/media/video/ivtv/ivtv-irq.c +++ b/drivers/media/video/ivtv/ivtv-irq.c @@ -384,7 +384,7 @@ static void ivtv_dma_enc_start_xfer(struct ivtv_stream *s) ivtv_stream_sync_for_device(s); write_reg(s->sg_handle, IVTV_REG_ENCDMAADDR); write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER); - itv->dma_timer.expires = jiffies + msecs_to_jiffies(100); + itv->dma_timer.expires = jiffies + msecs_to_jiffies(300); add_timer(&itv->dma_timer); } @@ -400,7 +400,7 @@ static void ivtv_dma_dec_start_xfer(struct ivtv_stream *s) ivtv_stream_sync_for_device(s); write_reg(s->sg_handle, IVTV_REG_DECDMAADDR); write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER); - itv->dma_timer.expires = jiffies + msecs_to_jiffies(100); + itv->dma_timer.expires = jiffies + msecs_to_jiffies(300); add_timer(&itv->dma_timer); } diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h index 0f1d4cc4b4d9..02c5ab071d1b 100644 --- a/drivers/media/video/ivtv/ivtv-version.h +++ b/drivers/media/video/ivtv/ivtv-version.h @@ -23,7 +23,7 @@ #define IVTV_DRIVER_NAME "ivtv" #define IVTV_DRIVER_VERSION_MAJOR 1 #define IVTV_DRIVER_VERSION_MINOR 2 -#define IVTV_DRIVER_VERSION_PATCHLEVEL 0 +#define IVTV_DRIVER_VERSION_PATCHLEVEL 1 #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL) #define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL) diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c index 3b23fc05f7c4..df789f683e63 100644 --- a/drivers/media/video/ivtv/ivtvfb.c +++ b/drivers/media/video/ivtv/ivtvfb.c @@ -532,7 +532,7 @@ static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix) IVTVFB_DEBUG_INFO("ivtvfb_get_fix\n"); memset(fix, 0, sizeof(struct fb_fix_screeninfo)); - strcpy(fix->id, "cx23415 TV out"); + strlcpy(fix->id, "cx23415 TV out", sizeof(fix->id)); fix->smem_start = oi->video_pbase; fix->smem_len = oi->video_buffer_size; fix->type = FB_TYPE_PACKED_PIXELS; diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c index d4bf14c284ef..5b9dfa2c51b4 100644 --- a/drivers/media/video/m52790.c +++ b/drivers/media/video/m52790.c @@ -126,7 +126,8 @@ static int m52790_command(struct i2c_client *client, unsigned int cmd, /* i2c implementation */ -static int m52790_probe(struct i2c_client *client) +static int m52790_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct m52790_state *state; diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index b73c740f7fb2..e6273162e123 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -805,7 +805,7 @@ static int msp_resume(struct i2c_client *client) /* ----------------------------------------------------------------------- */ -static int msp_probe(struct i2c_client *client) +static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct msp_state *state; int (*thread_func)(void *data) = NULL; diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c index 3fb5f63df1e6..179e47049a45 100644 --- a/drivers/media/video/mt9m001.c +++ b/drivers/media/video/mt9m001.c @@ -372,7 +372,7 @@ static int mt9m001_set_register(struct soc_camera_device *icd, } #endif -const struct v4l2_queryctrl mt9m001_controls[] = { +static const struct v4l2_queryctrl mt9m001_controls[] = { { .id = V4L2_CID_VFLIP, .type = V4L2_CTRL_TYPE_BOOLEAN, @@ -620,7 +620,8 @@ static void mt9m001_video_remove(struct soc_camera_device *icd) soc_camera_video_stop(&mt9m001->icd); } -static int mt9m001_probe(struct i2c_client *client) +static int mt9m001_probe(struct i2c_client *client, + const struct i2c_device_id *did) { struct mt9m001 *mt9m001; struct soc_camera_device *icd; @@ -696,12 +697,19 @@ static int mt9m001_remove(struct i2c_client *client) return 0; } +static const struct i2c_device_id mt9m001_id[] = { + { "mt9m001", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mt9m001_id); + static struct i2c_driver mt9m001_i2c_driver = { .driver = { .name = "mt9m001", }, .probe = mt9m001_probe, .remove = mt9m001_remove, + .id_table = mt9m001_id, }; static int __init mt9m001_mod_init(void) diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c index d4b9e2744343..d1391ac55096 100644 --- a/drivers/media/video/mt9v022.c +++ b/drivers/media/video/mt9v022.c @@ -452,7 +452,7 @@ static int mt9v022_set_register(struct soc_camera_device *icd, } #endif -const struct v4l2_queryctrl mt9v022_controls[] = { +static const struct v4l2_queryctrl mt9v022_controls[] = { { .id = V4L2_CID_VFLIP, .type = V4L2_CTRL_TYPE_BOOLEAN, @@ -745,7 +745,8 @@ static void mt9v022_video_remove(struct soc_camera_device *icd) soc_camera_video_stop(&mt9v022->icd); } -static int mt9v022_probe(struct i2c_client *client) +static int mt9v022_probe(struct i2c_client *client, + const struct i2c_device_id *did) { struct mt9v022 *mt9v022; struct soc_camera_device *icd; @@ -818,12 +819,19 @@ static int mt9v022_remove(struct i2c_client *client) return 0; } +static const struct i2c_device_id mt9v022_id[] = { + { "mt9v022", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mt9v022_id); + static struct i2c_driver mt9v022_i2c_driver = { .driver = { .name = "mt9v022", }, .probe = mt9v022_probe, .remove = mt9v022_remove, + .id_table = mt9v022_id, }; static int __init mt9v022_mod_init(void) diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig index 158b3d0c6532..9620c67fae77 100644 --- a/drivers/media/video/pvrusb2/Kconfig +++ b/drivers/media/video/pvrusb2/Kconfig @@ -1,14 +1,15 @@ config VIDEO_PVRUSB2 tristate "Hauppauge WinTV-PVR USB2 support" - depends on VIDEO_V4L2 && I2C && EXPERIMENTAL + depends on VIDEO_V4L2 && I2C select FW_LOADER - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_TVEEPROM select VIDEO_CX2341X select VIDEO_SAA711X select VIDEO_CX25840 select VIDEO_MSP3400 select VIDEO_WM8775 + select VIDEO_CS53L32A ---help--- This is a video4linux driver for Conexant 23416 based usb2 personal video recorder devices. @@ -16,32 +17,6 @@ config VIDEO_PVRUSB2 To compile this driver as a module, choose M here: the module will be called pvrusb2 -config VIDEO_PVRUSB2_ONAIR_CREATOR - bool "pvrusb2 driver support for OnAir Creator model" - depends on VIDEO_PVRUSB2 && EXPERIMENTAL - select VIDEO_SAA711X - select VIDEO_CS53L32A - ---help--- - - This option enables support for the OnAir Creator USB tuner - device. This is a hybrid device, however currently only - analog mode is supported. - - If you are in doubt, say Y. - -config VIDEO_PVRUSB2_ONAIR_USB2 - bool "pvrusb2 driver support for OnAir USB2 model" - depends on VIDEO_PVRUSB2 && EXPERIMENTAL - select VIDEO_SAA711X - select VIDEO_CS53L32A - ---help--- - - This option enables support for the OnAir USB2 tuner device - (also known as the Sasem tuner). This is a hybrid device, - however currently only analog mode is supported. - - If you are in doubt, say Y. - config VIDEO_PVRUSB2_SYSFS bool "pvrusb2 sysfs support (EXPERIMENTAL)" default y @@ -59,29 +34,23 @@ config VIDEO_PVRUSB2_SYSFS Note: This feature is experimental and subject to change. config VIDEO_PVRUSB2_DVB - bool "pvrusb2 DVB support (EXPERIMENTAL)" - default n + bool "pvrusb2 ATSC/DVB support (EXPERIMENTAL)" + default y depends on VIDEO_PVRUSB2 && DVB_CORE && EXPERIMENTAL select DVB_LGDT330X if !DVB_FE_CUSTOMISE select DVB_S5H1409 if !DVB_FE_CUSTOMISE select DVB_S5H1411 if !DVB_FE_CUSTOMISE select DVB_TDA10048 if !DVB_FE_CUSTOMIZE - select DVB_TDA18271 if !DVB_FE_CUSTOMIZE - select TUNER_SIMPLE if !DVB_FE_CUSTOMISE - select TUNER_TDA8290 if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE ---help--- - This option enables compilation of a DVB interface for the - pvrusb2 driver. Currently this is very very experimental. - It is also limiting - the DVB interface can only access the - digital side of hybrid devices, and there are going to be - issues if you attempt to mess with the V4L side at the same - time. Don't turn this on unless you know what you are - doing. - - If you are in doubt, say N. + This option enables a DVB interface for the pvrusb2 driver. + If your device does not support digital television, this + feature will have no affect on the driver's operation. - Note: This feature is very experimental and might break + If you are in doubt, say Y. config VIDEO_PVRUSB2_DEBUGIFC bool "pvrusb2 debug interface" diff --git a/drivers/media/video/pvrusb2/Makefile b/drivers/media/video/pvrusb2/Makefile index 5b3083c89aa9..4fda2de69ab7 100644 --- a/drivers/media/video/pvrusb2/Makefile +++ b/drivers/media/video/pvrusb2/Makefile @@ -16,5 +16,6 @@ pvrusb2-objs := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \ obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h index 11537ddf8aa3..707d2d9635d7 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-debug.h +++ b/drivers/media/video/pvrusb2/pvrusb2-debug.h @@ -54,6 +54,7 @@ extern int pvrusb2_debug; #define PVR2_TRACE_DATA_FLOW (1 << 25) /* Track data flow */ #define PVR2_TRACE_DEBUGIFC (1 << 26) /* Debug interface actions */ #define PVR2_TRACE_GPIO (1 << 27) /* GPIO state bit changes */ +#define PVR2_TRACE_DVB_FEED (1 << 28) /* DVB transport feed debug */ #endif /* __PVRUSB2_HDW_INTERNAL_H */ diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c index 3a141d93e1a9..5bf6d8fda1f9 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -153,7 +153,6 @@ static const struct pvr2_device_desc pvr2_device_gotview_2d = { -#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR /*------------------------------------------------------------------------*/ /* OnAir Creator */ @@ -212,11 +211,9 @@ static const struct pvr2_device_desc pvr2_device_onair_creator = { .dvb_props = &pvr2_onair_creator_fe_props, #endif }; -#endif -#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2 /*------------------------------------------------------------------------*/ /* OnAir USB 2.0 */ @@ -274,7 +271,6 @@ static const struct pvr2_device_desc pvr2_device_onair_usb2 = { .dvb_props = &pvr2_onair_usb2_fe_props, #endif }; -#endif @@ -497,14 +493,10 @@ struct usb_device_id pvr2_device_table[] = { .driver_info = (kernel_ulong_t)&pvr2_device_gotview_2}, { USB_DEVICE(0x1164, 0x0602), .driver_info = (kernel_ulong_t)&pvr2_device_gotview_2d}, -#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR { USB_DEVICE(0x11ba, 0x1003), .driver_info = (kernel_ulong_t)&pvr2_device_onair_creator}, -#endif -#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2 { USB_DEVICE(0x11ba, 0x1001), .driver_info = (kernel_ulong_t)&pvr2_device_onair_usb2}, -#endif { USB_DEVICE(0x2040, 0x7300), .driver_info = (kernel_ulong_t)&pvr2_device_73xxx}, { USB_DEVICE(0x2040, 0x7500), diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c index 6504c97e0bbc..6ec4bf81fc7f 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c @@ -21,6 +21,7 @@ #include <linux/kthread.h> #include <linux/freezer.h> #include "dvbdev.h" +#include "pvrusb2-debug.h" #include "pvrusb2-hdw-internal.h" #include "pvrusb2-hdw.h" #include "pvrusb2-io.h" @@ -35,7 +36,7 @@ static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap) struct pvr2_buffer *bp; struct pvr2_stream *stream; - printk(KERN_DEBUG "dvb thread started\n"); + pvr2_trace(PVR2_TRACE_DVB_FEED, "dvb feed thread started"); set_freezable(); stream = adap->channel.stream->stream; @@ -82,7 +83,7 @@ static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap) /* If we get here and ret is < 0, then an error has occurred. Probably would be a good idea to communicate that to DVB core... */ - printk(KERN_DEBUG "dvb thread stopped\n"); + pvr2_trace(PVR2_TRACE_DVB_FEED, "dvb feed thread stopped"); return 0; } @@ -210,7 +211,8 @@ static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) do { if (onoff) { if (!adap->feedcount) { - printk(KERN_DEBUG "start feeding\n"); + pvr2_trace(PVR2_TRACE_DVB_FEED, + "start feeding demux"); ret = pvr2_dvb_stream_start(adap); if (ret < 0) break; } @@ -218,7 +220,8 @@ static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) } else if (adap->feedcount > 0) { (adap->feedcount)--; if (!adap->feedcount) { - printk(KERN_DEBUG "stop feeding\n"); + pvr2_trace(PVR2_TRACE_DVB_FEED, + "stop feeding demux"); pvr2_dvb_stream_end(adap); } } @@ -230,15 +233,13 @@ static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) static int pvr2_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed) { - printk(KERN_DEBUG "start pid: 0x%04x, feedtype: %d\n", - dvbdmxfeed->pid, dvbdmxfeed->type); + pvr2_trace(PVR2_TRACE_DVB_FEED, "start pid: 0x%04x", dvbdmxfeed->pid); return pvr2_dvb_ctrl_feed(dvbdmxfeed, 1); } static int pvr2_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) { - printk(KERN_DEBUG "stop pid: 0x%04x, feedtype: %d\n", - dvbdmxfeed->pid, dvbdmxfeed->type); + pvr2_trace(PVR2_TRACE_DVB_FEED, "stop pid: 0x%04x", dvbdmxfeed->pid); return pvr2_dvb_ctrl_feed(dvbdmxfeed, 0); } @@ -259,7 +260,8 @@ static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap) &adap->channel.hdw->usb_dev->dev, adapter_nr); if (ret < 0) { - err("dvb_register_adapter failed: error %d", ret); + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "dvb_register_adapter failed: error %d", ret); goto err; } adap->dvb_adap.priv = adap; @@ -276,7 +278,8 @@ static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap) ret = dvb_dmx_init(&adap->demux); if (ret < 0) { - err("dvb_dmx_init failed: error %d", ret); + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "dvb_dmx_init failed: error %d", ret); goto err_dmx; } @@ -286,7 +289,8 @@ static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap) ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap); if (ret < 0) { - err("dvb_dmxdev_init failed: error %d", ret); + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "dvb_dmxdev_init failed: error %d", ret); goto err_dmx_dev; } @@ -304,7 +308,7 @@ err: static int pvr2_dvb_adapter_exit(struct pvr2_dvb_adapter *adap) { - printk(KERN_DEBUG "unregistering DVB devices\n"); + pvr2_trace(PVR2_TRACE_INFO, "unregistering DVB devices"); dvb_net_release(&adap->dvb_net); adap->demux.dmx.close(&adap->demux.dmx); dvb_dmxdev_release(&adap->dmxdev); @@ -320,7 +324,7 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) int ret = 0; if (dvb_props == NULL) { - err("fe_props not defined!"); + pvr2_trace(PVR2_TRACE_ERROR_LEGS, "fe_props not defined!"); return -EINVAL; } @@ -328,13 +332,15 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) &adap->channel, (1 << PVR2_CVAL_INPUT_DTV)); if (ret) { - err("failed to grab control of dtv input (code=%d)", + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "failed to grab control of dtv input (code=%d)", ret); return ret; } if (dvb_props->frontend_attach == NULL) { - err("frontend_attach not defined!"); + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "frontend_attach not defined!"); ret = -EINVAL; goto done; } @@ -342,7 +348,8 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) if ((dvb_props->frontend_attach(adap) == 0) && (adap->fe)) { if (dvb_register_frontend(&adap->dvb_adap, adap->fe)) { - err("frontend registration failed!"); + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "frontend registration failed!"); dvb_frontend_detach(adap->fe); adap->fe = NULL; ret = -ENODEV; @@ -359,7 +366,8 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) adap->fe->ops.ts_bus_ctrl = pvr2_dvb_bus_ctrl; } else { - err("no frontend was attached!"); + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "no frontend was attached!"); ret = -ENODEV; return ret; } diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index 416d05d4a969..e684108637ad 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -1450,7 +1450,8 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar /* ----------------------------------------------------------------------- */ -static int saa7115_probe(struct i2c_client *client) +static int saa7115_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct saa711x_state *state; int i; diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c index 06c88db656b4..e750cd65c1c3 100644 --- a/drivers/media/video/saa7127.c +++ b/drivers/media/video/saa7127.c @@ -661,7 +661,8 @@ static int saa7127_command(struct i2c_client *client, /* ----------------------------------------------------------------------- */ -static int saa7127_probe(struct i2c_client *client) +static int saa7127_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct saa7127_state *state; struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 }; /* set to disabled */ diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig index e086f14d5663..40e4c3bd2cb9 100644 --- a/drivers/media/video/saa7134/Kconfig +++ b/drivers/media/video/saa7134/Kconfig @@ -3,7 +3,7 @@ config VIDEO_SAA7134 depends on VIDEO_DEV && PCI && I2C && INPUT select VIDEOBUF_DMA_SG select VIDEO_IR - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_TVEEPROM select CRC32 ---help--- @@ -35,9 +35,9 @@ config VIDEO_SAA7134_DVB select DVB_NXT200X if !DVB_FE_CUSTOMISE select DVB_TDA10086 if !DVB_FE_CUSTOMISE select DVB_TDA826X if !DVB_FE_CUSTOMISE - select DVB_TDA827X if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE select DVB_ISL6421 if !DVB_FE_CUSTOMISE - select TUNER_SIMPLE if !DVB_FE_CUSTOMISE + select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE ---help--- This adds support for DVB cards based on the Philips saa7134 chip. diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile index 9aff937ba7a5..3dbaa19a6d00 100644 --- a/drivers/media/video/saa7134/Makefile +++ b/drivers/media/video/saa7134/Makefile @@ -11,5 +11,6 @@ obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 98375955a84b..b111903aa322 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -47,6 +47,9 @@ static char name_svideo[] = "S-Video"; /* ------------------------------------------------------------------ */ /* board config info */ +/* If radio_type !=UNSET, radio_addr should be specified + */ + struct saa7134_board saa7134_boards[] = { [SAA7134_BOARD_UNKNOWN] = { .name = "UNKNOWN/GENERIC", @@ -3087,7 +3090,7 @@ struct saa7134_board saa7134_boards[] = { .tuner_type = TUNER_PHILIPS_TD1316, /* untested */ .radio_type = TUNER_TEA5767, /* untested */ .tuner_addr = ADDR_UNSET, - .radio_addr = ADDR_UNSET, + .radio_addr = 0x60, .tda9887_conf = TDA9887_PRESENT, .mpeg = SAA7134_MPEG_DVB, .inputs = {{ @@ -4247,6 +4250,36 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE1, } }, }, + [SAA7134_BOARD_BEHOLD_H6] = { + /* Igor Kuznetsov <igk@igk.ru> */ + .name = "Beholder BeholdTV H6", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = {{ + .name = name_tv, + .vmux = 3, + .amux = TV, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 1, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + } }, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + /* no DVB support for now */ + /* .mpeg = SAA7134_MPEG_DVB, */ + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -5197,6 +5230,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x5ace, .subdevice = 0x6193, .driver_data = SAA7134_BOARD_BEHOLD_M6, + }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5ace, + .subdevice = 0x6191, + .driver_data = SAA7134_BOARD_BEHOLD_M6, },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, @@ -5246,6 +5285,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subdevice = 0xc900, .driver_data = SAA7134_BOARD_VIDEOMATE_T750, }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5ace, + .subdevice = 0x6290, + .driver_data = SAA7134_BOARD_BEHOLD_H6, + }, { /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, @@ -5577,20 +5622,87 @@ int saa7134_board_init1(struct saa7134_dev *dev) return 0; } +static void saa7134_tuner_setup(struct saa7134_dev *dev) +{ + struct tuner_setup tun_setup; + unsigned int mode_mask = T_RADIO | + T_ANALOG_TV | + T_DIGITAL_TV; + + memset(&tun_setup, 0, sizeof(tun_setup)); + tun_setup.tuner_callback = saa7134_tuner_callback; + + if (saa7134_boards[dev->board].radio_type != UNSET) { + tun_setup.type = saa7134_boards[dev->board].radio_type; + tun_setup.addr = saa7134_boards[dev->board].radio_addr; + + tun_setup.mode_mask = T_RADIO; + + saa7134_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); + mode_mask &= ~T_RADIO; + } + + if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type != UNSET)) { + tun_setup.type = dev->tuner_type; + tun_setup.addr = dev->tuner_addr; + tun_setup.config = saa7134_boards[dev->board].tuner_config; + tun_setup.tuner_callback = saa7134_tuner_callback; + + tun_setup.mode_mask = mode_mask; + + saa7134_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); + } + + if (dev->tda9887_conf) { + struct v4l2_priv_tun_config tda9887_cfg; + + tda9887_cfg.tuner = TUNER_TDA9887; + tda9887_cfg.priv = &dev->tda9887_conf; + + saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, + &tda9887_cfg); + } + + if (dev->tuner_type == TUNER_XC2028) { + struct v4l2_priv_tun_config xc2028_cfg; + struct xc2028_ctrl ctl; + + memset(&xc2028_cfg, 0, sizeof(ctl)); + memset(&ctl, 0, sizeof(ctl)); + + ctl.fname = XC2028_DEFAULT_FIRMWARE; + ctl.max_len = 64; + + switch (dev->board) { + case SAA7134_BOARD_AVERMEDIA_A16D: + ctl.demod = XC3028_FE_ZARLINK456; + break; + default: + ctl.demod = XC3028_FE_OREN538; + ctl.mts = 1; + } + + xc2028_cfg.tuner = TUNER_XC2028; + xc2028_cfg.priv = &ctl; + + saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg); + } +} + /* stuff which needs working i2c */ int saa7134_board_init2(struct saa7134_dev *dev) { unsigned char buf; int board; - struct tuner_setup tun_setup; - tun_setup.config = 0; - tun_setup.tuner_callback = saa7134_tuner_callback; + + dev->tuner_type = saa7134_boards[dev->board].tuner_type; + dev->tuner_addr = saa7134_boards[dev->board].tuner_addr; switch (dev->board) { case SAA7134_BOARD_BMK_MPEX_NOTUNER: case SAA7134_BOARD_BMK_MPEX_TUNER: dev->i2c_client.addr = 0x60; - board = (i2c_master_recv(&dev->i2c_client,&buf,0) < 0) + board = (i2c_master_recv(&dev->i2c_client, &buf, 0) < 0) ? SAA7134_BOARD_BMK_MPEX_NOTUNER : SAA7134_BOARD_BMK_MPEX_TUNER; if (board == dev->board) @@ -5600,21 +5712,9 @@ int saa7134_board_init2(struct saa7134_dev *dev) saa7134_boards[dev->board].name); dev->tuner_type = saa7134_boards[dev->board].tuner_type; - if (TUNER_ABSENT != dev->tuner_type) { - tun_setup.mode_mask = T_RADIO | - T_ANALOG_TV | - T_DIGITAL_TV; - tun_setup.type = dev->tuner_type; - tun_setup.addr = ADDR_UNSET; - tun_setup.tuner_callback = saa7134_tuner_callback; - - saa7134_i2c_call_clients(dev, - TUNER_SET_TYPE_ADDR, - &tun_setup); - } break; case SAA7134_BOARD_MD7134: - { + { u8 subaddr; u8 data[3]; int ret, tuner_t; @@ -5667,30 +5767,8 @@ int saa7134_board_init2(struct saa7134_dev *dev) } printk(KERN_INFO "%s Tuner type is %d\n", dev->name, dev->tuner_type); - if (dev->tuner_type == TUNER_PHILIPS_FMD1216ME_MK3) { - struct v4l2_priv_tun_config tda9887_cfg; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &dev->tda9887_conf; - - dev->tda9887_conf = TDA9887_PRESENT | - TDA9887_PORT1_ACTIVE | - TDA9887_PORT2_ACTIVE; - - saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, - &tda9887_cfg); - } - - tun_setup.mode_mask = T_RADIO | - T_ANALOG_TV | - T_DIGITAL_TV; - tun_setup.type = dev->tuner_type; - tun_setup.addr = ADDR_UNSET; - - saa7134_i2c_call_clients(dev, - TUNER_SET_TYPE_ADDR, &tun_setup); - } break; + } case SAA7134_BOARD_PHILIPS_EUROPA: if (dev->autodetected && (dev->eedata[0x41] == 0x1c)) { /* Reconfigure board as Snake reference design */ @@ -5702,43 +5780,43 @@ int saa7134_board_init2(struct saa7134_dev *dev) } case SAA7134_BOARD_VIDEOMATE_DVBT_300: case SAA7134_BOARD_ASUS_EUROPA2_HYBRID: + { + /* The Philips EUROPA based hybrid boards have the tuner connected through * the channel decoder. We have to make it transparent to find it */ - { u8 data[] = { 0x07, 0x02}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; i2c_transfer(&dev->i2c_adap, &msg, 1); - tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV; - tun_setup.type = dev->tuner_type; - tun_setup.addr = dev->tuner_addr; - - saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup); - } break; + } case SAA7134_BOARD_PHILIPS_TIGER: case SAA7134_BOARD_PHILIPS_TIGER_S: - { + { u8 data[] = { 0x3c, 0x33, 0x60}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; - if(dev->autodetected && (dev->eedata[0x49] == 0x50)) { + if (dev->autodetected && (dev->eedata[0x49] == 0x50)) { dev->board = SAA7134_BOARD_PHILIPS_TIGER_S; printk(KERN_INFO "%s: Reconfigured board as %s\n", dev->name, saa7134_boards[dev->board].name); } - if(dev->board == SAA7134_BOARD_PHILIPS_TIGER_S) { - tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV; - tun_setup.type = TUNER_PHILIPS_TDA8290; - tun_setup.addr = 0x4b; - tun_setup.config = 2; + if (dev->board == SAA7134_BOARD_PHILIPS_TIGER_S) { + dev->tuner_type = TUNER_PHILIPS_TDA8290; + + saa7134_tuner_setup(dev); - saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup); data[2] = 0x68; + i2c_transfer(&dev->i2c_adap, &msg, 1); + + /* Tuner setup is handled before I2C transfer. + Due to that, there's no need to do it later + */ + return 0; } i2c_transfer(&dev->i2c_adap, &msg, 1); - } break; + } case SAA7134_BOARD_HAUPPAUGE_HVR1110: hauppauge_eeprom(dev, dev->eedata+0x80); /* break intentionally omitted */ @@ -5751,52 +5829,55 @@ int saa7134_board_init2(struct saa7134_dev *dev) case SAA7134_BOARD_AVERMEDIA_SUPER_007: case SAA7134_BOARD_TWINHAN_DTV_DVB_3056: case SAA7134_BOARD_CREATIX_CTX953: + { /* this is a hybrid board, initialize to analog mode * and configure firmware eeprom address */ - { u8 data[] = { 0x3c, 0x33, 0x60}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; i2c_transfer(&dev->i2c_adap, &msg, 1); - } break; + } case SAA7134_BOARD_FLYDVB_TRIO: - { + { u8 data[] = { 0x3c, 0x33, 0x62}; struct i2c_msg msg = {.addr=0x09, .flags=0, .buf=data, .len = sizeof(data)}; i2c_transfer(&dev->i2c_adap, &msg, 1); - } break; + } case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS: + { /* initialize analog mode */ - { u8 data[] = { 0x3c, 0x33, 0x6a}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; i2c_transfer(&dev->i2c_adap, &msg, 1); - } break; + } case SAA7134_BOARD_CINERGY_HT_PCMCIA: case SAA7134_BOARD_CINERGY_HT_PCI: + { /* initialize analog mode */ - { u8 data[] = { 0x3c, 0x33, 0x68}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; i2c_transfer(&dev->i2c_adap, &msg, 1); - } break; + } case SAA7134_BOARD_KWORLD_ATSC110: - { - /* enable tuner */ - int i; - static const u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 }; - dev->i2c_client.addr = 0x0a; - for (i = 0; i < 5; i++) - if (2 != i2c_master_send(&dev->i2c_client,&buffer[i*2],2)) - printk(KERN_WARNING "%s: Unable to enable tuner(%i).\n", - dev->name, i); - } + { + /* enable tuner */ + int i; + static const u8 buffer [] = { 0x10, 0x12, 0x13, 0x04, 0x16, + 0x00, 0x14, 0x04, 0x17, 0x00 }; + dev->i2c_client.addr = 0x0a; + for (i = 0; i < 5; i++) + if (2 != i2c_master_send(&dev->i2c_client, + &buffer[i*2], 2)) + printk(KERN_WARNING + "%s: Unable to enable tuner(%i).\n", + dev->name, i); break; + } case SAA7134_BOARD_VIDEOMATE_DVBT_200: case SAA7134_BOARD_VIDEOMATE_DVBT_200A: /* The T200 and the T200A share the same pci id. Consequently, @@ -5821,7 +5902,7 @@ int saa7134_board_init2(struct saa7134_dev *dev) } break; case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM: - { + { struct v4l2_priv_tun_config tea5767_cfg; struct tea5767_ctrl ctl; @@ -5832,34 +5913,11 @@ int saa7134_board_init2(struct saa7134_dev *dev) tea5767_cfg.tuner = TUNER_TEA5767; tea5767_cfg.priv = &ctl; saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &tea5767_cfg); - } break; } + } /* switch() */ - if (dev->tuner_type == TUNER_XC2028) { - struct v4l2_priv_tun_config xc2028_cfg; - struct xc2028_ctrl ctl; - - memset(&xc2028_cfg, 0, sizeof(ctl)); - memset(&ctl, 0, sizeof(ctl)); - - ctl.fname = XC2028_DEFAULT_FIRMWARE; - ctl.max_len = 64; - - switch (dev->board) { - case SAA7134_BOARD_AVERMEDIA_A16D: - ctl.demod = XC3028_FE_ZARLINK456; - break; - default: - ctl.demod = XC3028_FE_OREN538; - ctl.mts = 1; - } - - xc2028_cfg.tuner = TUNER_XC2028; - xc2028_cfg.priv = &ctl; - - saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg); - } + saa7134_tuner_setup(dev); return 0; } diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c index 2ccfaba0c490..d8af3863f2d3 100644 --- a/drivers/media/video/saa7134/saa7134-i2c.c +++ b/drivers/media/video/saa7134/saa7134-i2c.c @@ -324,8 +324,6 @@ static u32 functionality(struct i2c_adapter *adap) static int attach_inform(struct i2c_client *client) { struct saa7134_dev *dev = client->adapter->algo_data; - int tuner = dev->tuner_type; - struct tuner_setup tun_setup; d1printk( "%s i2c attach [addr=0x%x,client=%s]\n", client->driver->driver.name, client->addr, client->name); @@ -346,46 +344,6 @@ static int attach_inform(struct i2c_client *client) } } - if (!client->driver->command) - return 0; - - if (saa7134_boards[dev->board].radio_type != UNSET) { - - tun_setup.type = saa7134_boards[dev->board].radio_type; - tun_setup.addr = saa7134_boards[dev->board].radio_addr; - - if ((tun_setup.addr == ADDR_UNSET) || (tun_setup.addr == client->addr)) { - tun_setup.mode_mask = T_RADIO; - - client->driver->command(client, TUNER_SET_TYPE_ADDR, &tun_setup); - } - } - - if (tuner != UNSET) { - tun_setup.type = tuner; - tun_setup.addr = saa7134_boards[dev->board].tuner_addr; - tun_setup.config = saa7134_boards[dev->board].tuner_config; - tun_setup.tuner_callback = saa7134_tuner_callback; - - if ((tun_setup.addr == ADDR_UNSET)||(tun_setup.addr == client->addr)) { - - tun_setup.mode_mask = T_ANALOG_TV; - - client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_setup); - } - - if (tuner == TUNER_TDA9887) { - struct v4l2_priv_tun_config tda9887_cfg; - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &dev->tda9887_conf; - - client->driver->command(client, TUNER_SET_CONFIG, - &tda9887_cfg); - } - } - - return 0; } diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 767ff30832f2..919632b10aae 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -531,6 +531,7 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir) break; case SAA7134_BOARD_BEHOLD_607_9FM: case SAA7134_BOARD_BEHOLD_M6: + case SAA7134_BOARD_BEHOLD_H6: snprintf(ir->c.name, sizeof(ir->c.name), "BeholdTV"); ir->get_key = get_key_beholdm6xx; ir->ir_codes = ir_codes_behold; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 924ffd13637e..34ff0d4998f3 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -263,6 +263,7 @@ struct saa7134_format { #define SAA7134_BOARD_VIDEOMATE_T750 139 #define SAA7134_BOARD_AVERMEDIA_A700_PRO 140 #define SAA7134_BOARD_AVERMEDIA_A700_HYBRID 141 +#define SAA7134_BOARD_BEHOLD_H6 142 #define SAA7134_MAXBOARDS 8 diff --git a/drivers/media/video/saa717x.c b/drivers/media/video/saa717x.c index 53c5edbcf7ea..72c4081feff5 100644 --- a/drivers/media/video/saa717x.c +++ b/drivers/media/video/saa717x.c @@ -1418,7 +1418,8 @@ static int saa717x_command(struct i2c_client *client, unsigned cmd, void *arg) /* i2c implementation */ /* ----------------------------------------------------------------------- */ -static int saa717x_probe(struct i2c_client *client) +static int saa717x_probe(struct i2c_client *client, + const struct i2c_device_id *did) { struct saa717x_state *decoder; u8 id = 0; diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c index 6943b447a1bd..e57a64605778 100644 --- a/drivers/media/video/tcm825x.c +++ b/drivers/media/video/tcm825x.c @@ -840,7 +840,8 @@ static struct v4l2_int_device tcm825x_int_device = { }, }; -static int tcm825x_probe(struct i2c_client *client) +static int tcm825x_probe(struct i2c_client *client, + const struct i2c_device_id *did) { struct tcm825x_sensor *sensor = &tcm825x; int rval; diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c index dc7b9c220b90..f1db54202dea 100644 --- a/drivers/media/video/tlv320aic23b.c +++ b/drivers/media/video/tlv320aic23b.c @@ -125,7 +125,8 @@ static int tlv320aic23b_command(struct i2c_client *client, * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static int tlv320aic23b_probe(struct i2c_client *client) +static int tlv320aic23b_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct tlv320aic23b_state *state; diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 2b72e10e6b9f..6bf104ea051d 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -33,6 +33,46 @@ #define PREFIX t->i2c->driver->driver.name +/** This macro allows us to probe dynamically, avoiding static links */ +#ifdef CONFIG_MEDIA_ATTACH +#define tuner_symbol_probe(FUNCTION, ARGS...) ({ \ + int __r = -EINVAL; \ + typeof(&FUNCTION) __a = symbol_request(FUNCTION); \ + if (__a) { \ + __r = (int) __a(ARGS); \ + } else { \ + printk(KERN_ERR "TUNER: Unable to find " \ + "symbol "#FUNCTION"()\n"); \ + } \ + symbol_put(FUNCTION); \ + __r; \ +}) + +static void tuner_detach(struct dvb_frontend *fe) +{ + if (fe->ops.tuner_ops.release) { + fe->ops.tuner_ops.release(fe); + symbol_put_addr(fe->ops.tuner_ops.release); + } + if (fe->ops.analog_ops.release) { + fe->ops.analog_ops.release(fe); + symbol_put_addr(fe->ops.analog_ops.release); + } +} +#else +#define tuner_symbol_probe(FUNCTION, ARGS...) ({ \ + FUNCTION(ARGS); \ +}) + +static void tuner_detach(struct dvb_frontend *fe) +{ + if (fe->ops.tuner_ops.release) + fe->ops.tuner_ops.release(fe); + if (fe->ops.analog_ops.release) + fe->ops.analog_ops.release(fe); +} +#endif + struct tuner { /* device */ struct dvb_frontend fe; @@ -56,7 +96,7 @@ struct tuner { /* standard i2c insmod options */ static unsigned short normal_i2c[] = { -#if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE)) +#if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE)) 0x10, #endif 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */ @@ -139,22 +179,6 @@ static void fe_set_params(struct dvb_frontend *fe, fe_tuner_ops->set_analog_params(fe, params); } -static void fe_release(struct dvb_frontend *fe) -{ - if (fe->ops.tuner_ops.release) - fe->ops.tuner_ops.release(fe); - - /* DO NOT kfree(fe->analog_demod_priv) - * - * If we are in this function, analog_demod_priv contains a pointer - * to struct tuner *t. This will be kfree'd in tuner_detach(). - * - * Otherwise, fe->ops.analog_demod_ops->release will - * handle the cleanup for analog demodulator modules. - */ - fe->analog_demod_priv = NULL; -} - static void fe_standby(struct dvb_frontend *fe) { struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; @@ -191,7 +215,6 @@ static void tuner_status(struct dvb_frontend *fe); static struct analog_demod_ops tuner_core_ops = { .set_params = fe_set_params, .standby = fe_standby, - .release = fe_release, .has_signal = fe_has_signal, .set_config = fe_set_config, .tuner_status = tuner_status @@ -323,7 +346,8 @@ static void attach_tda829x(struct tuner *t) .lna_cfg = t->config, .tuner_callback = t->tuner_callback, }; - tda829x_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg); + dvb_attach(tda829x_attach, + &t->fe, t->i2c->adapter, t->i2c->addr, &cfg); } static struct xc5000_config xc5000_cfg; @@ -356,12 +380,13 @@ static void set_type(struct i2c_client *c, unsigned int type, } /* discard private data, in case set_type() was previously called */ - if (analog_ops->release) - analog_ops->release(&t->fe); + tuner_detach(&t->fe); + t->fe.analog_demod_priv = NULL; switch (t->type) { case TUNER_MT2032: - microtune_attach(&t->fe, t->i2c->adapter, t->i2c->addr); + dvb_attach(microtune_attach, + &t->fe, t->i2c->adapter, t->i2c->addr); break; case TUNER_PHILIPS_TDA8290: { @@ -369,12 +394,14 @@ static void set_type(struct i2c_client *c, unsigned int type, break; } case TUNER_TEA5767: - if (!tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr)) + if (!dvb_attach(tea5767_attach, &t->fe, + t->i2c->adapter, t->i2c->addr)) goto attach_failed; t->mode_mask = T_RADIO; break; case TUNER_TEA5761: - if (!tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr)) + if (!dvb_attach(tea5761_attach, &t->fe, + t->i2c->adapter, t->i2c->addr)) goto attach_failed; t->mode_mask = T_RADIO; break; @@ -388,8 +415,8 @@ static void set_type(struct i2c_client *c, unsigned int type, buffer[2] = 0x86; buffer[3] = 0x54; i2c_master_send(c, buffer, 4); - if (!simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr, - t->type)) + if (!dvb_attach(simple_tuner_attach, &t->fe, + t->i2c->adapter, t->i2c->addr, t->type)) goto attach_failed; break; case TUNER_PHILIPS_TD1316: @@ -397,9 +424,9 @@ static void set_type(struct i2c_client *c, unsigned int type, buffer[1] = 0xdc; buffer[2] = 0x86; buffer[3] = 0xa4; - i2c_master_send(c,buffer,4); - if (!simple_tuner_attach(&t->fe, t->i2c->adapter, - t->i2c->addr, t->type)) + i2c_master_send(c, buffer, 4); + if (!dvb_attach(simple_tuner_attach, &t->fe, + t->i2c->adapter, t->i2c->addr, t->type)) goto attach_failed; break; case TUNER_XC2028: @@ -409,12 +436,13 @@ static void set_type(struct i2c_client *c, unsigned int type, .i2c_addr = t->i2c->addr, .callback = t->tuner_callback, }; - if (!xc2028_attach(&t->fe, &cfg)) + if (!dvb_attach(xc2028_attach, &t->fe, &cfg)) goto attach_failed; break; } case TUNER_TDA9887: - tda9887_attach(&t->fe, t->i2c->adapter, t->i2c->addr); + dvb_attach(tda9887_attach, + &t->fe, t->i2c->adapter, t->i2c->addr); break; case TUNER_XC5000: { @@ -424,7 +452,8 @@ static void set_type(struct i2c_client *c, unsigned int type, xc5000_cfg.if_khz = 5380; xc5000_cfg.priv = c->adapter->algo_data; xc5000_cfg.tuner_callback = t->tuner_callback; - if (!xc5000_attach(&t->fe, t->i2c->adapter, &xc5000_cfg)) + if (!dvb_attach(xc5000_attach, + &t->fe, t->i2c->adapter, &xc5000_cfg)) goto attach_failed; xc_tuner_ops = &t->fe.ops.tuner_ops; @@ -433,8 +462,8 @@ static void set_type(struct i2c_client *c, unsigned int type, break; } default: - if (!simple_tuner_attach(&t->fe, t->i2c->adapter, - t->i2c->addr, t->type)) + if (!dvb_attach(simple_tuner_attach, &t->fe, + t->i2c->adapter, t->i2c->addr, t->type)) goto attach_failed; break; @@ -442,12 +471,14 @@ static void set_type(struct i2c_client *c, unsigned int type, if ((NULL == analog_ops->set_params) && (fe_tuner_ops->set_analog_params)) { + strlcpy(t->i2c->name, fe_tuner_ops->info.name, sizeof(t->i2c->name)); t->fe.analog_demod_priv = t; memcpy(analog_ops, &tuner_core_ops, sizeof(struct analog_demod_ops)); + } else { strlcpy(t->i2c->name, analog_ops->info.name, sizeof(t->i2c->name)); @@ -645,8 +676,8 @@ static void tuner_status(struct dvb_frontend *fe) { struct tuner *t = fe->analog_demod_priv; unsigned long freq, freq_fraction; - struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; + struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops; + struct analog_demod_ops *analog_ops = &fe->ops.analog_ops; const char *p; switch (t->mode) { @@ -730,8 +761,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops; struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - if (tuner_debug>1) + if (tuner_debug > 1) { v4l_i2c_print_ioctl(client,cmd); + printk("\n"); + } switch (cmd) { /* --- configuration --- */ @@ -1073,7 +1106,8 @@ static void tuner_lookup(struct i2c_adapter *adap, /* During client attach, set_type is called by adapter's attach_inform callback. set_type must then be completed by tuner_probe. */ -static int tuner_probe(struct i2c_client *client) +static int tuner_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct tuner *t; struct tuner *radio; @@ -1111,8 +1145,9 @@ static int tuner_probe(struct i2c_client *client) if (!no_autodetect) { switch (client->addr) { case 0x10: - if (tea5761_autodetection(t->i2c->adapter, - t->i2c->addr) >= 0) { + if (tuner_symbol_probe(tea5761_autodetection, + t->i2c->adapter, + t->i2c->addr) >= 0) { t->type = TUNER_TEA5761; t->mode_mask = T_RADIO; t->mode = T_STANDBY; @@ -1131,8 +1166,8 @@ static int tuner_probe(struct i2c_client *client) case 0x4b: /* If chip is not tda8290, don't register. since it can be tda9887*/ - if (tda829x_probe(t->i2c->adapter, - t->i2c->addr) == 0) { + if (tuner_symbol_probe(tda829x_probe, t->i2c->adapter, + t->i2c->addr) == 0) { tuner_dbg("tda829x detected\n"); } else { /* Default is being tda9887 */ @@ -1144,7 +1179,8 @@ static int tuner_probe(struct i2c_client *client) } break; case 0x60: - if (tea5767_autodetection(t->i2c->adapter, t->i2c->addr) + if (tuner_symbol_probe(tea5767_autodetection, + t->i2c->adapter, t->i2c->addr) != EINVAL) { t->type = TUNER_TEA5767; t->mode_mask = T_RADIO; @@ -1233,10 +1269,9 @@ static int tuner_legacy_probe(struct i2c_adapter *adap) static int tuner_remove(struct i2c_client *client) { struct tuner *t = i2c_get_clientdata(client); - struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - if (analog_ops->release) - analog_ops->release(&t->fe); + tuner_detach(&t->fe); + t->fe.analog_demod_priv = NULL; list_del(&t->list); kfree(t); diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index f29a2cd0f2f2..6f9945b04e1f 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -1461,7 +1461,7 @@ static struct CHIPDESC chiplist[] = { /* ---------------------------------------------------------------------- */ /* i2c registration */ -static int chip_probe(struct i2c_client *client) +static int chip_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct CHIPSTATE *chip; struct CHIPDESC *desc; diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c index bd201397a2ac..93bfd19dec7d 100644 --- a/drivers/media/video/upd64031a.c +++ b/drivers/media/video/upd64031a.c @@ -195,7 +195,8 @@ static int upd64031a_command(struct i2c_client *client, unsigned cmd, void *arg) /* i2c implementation */ -static int upd64031a_probe(struct i2c_client *client) +static int upd64031a_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct upd64031a_state *state; int i; diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c index 2d9a88f70c85..9ab712a56ce0 100644 --- a/drivers/media/video/upd64083.c +++ b/drivers/media/video/upd64083.c @@ -172,7 +172,8 @@ static int upd64083_command(struct i2c_client *client, unsigned cmd, void *arg) /* i2c implementation */ -static int upd64083_probe(struct i2c_client *client) +static int upd64083_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct upd64083_state *state; int i; diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c index 64819353276a..17f542dfb366 100644 --- a/drivers/media/video/usbvideo/vicam.c +++ b/drivers/media/video/usbvideo/vicam.c @@ -70,12 +70,6 @@ #define VICAM_HEADER_SIZE 64 -#define clamp( x, l, h ) max_t( __typeof__( x ), \ - ( l ), \ - min_t( __typeof__( x ), \ - ( h ), \ - ( x ) ) ) - /* Not sure what all the bytes in these char * arrays do, but they're necessary to make * the camera work. diff --git a/drivers/media/video/usbvision/Kconfig b/drivers/media/video/usbvision/Kconfig index fc24ef05b3f3..74e1d3075a20 100644 --- a/drivers/media/video/usbvision/Kconfig +++ b/drivers/media/video/usbvision/Kconfig @@ -1,7 +1,7 @@ config VIDEO_USBVISION tristate "USB video devices based on Nogatech NT1003/1004/1005" depends on I2C && VIDEO_V4L2 - select VIDEO_TUNER + select MEDIA_TUNER select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO ---help--- There are more than 50 different USB video devices based on diff --git a/drivers/media/video/usbvision/Makefile b/drivers/media/video/usbvision/Makefile index 9ac92a80c645..338718750945 100644 --- a/drivers/media/video/usbvision/Makefile +++ b/drivers/media/video/usbvision/Makefile @@ -3,3 +3,4 @@ usbvision-objs := usbvision-core.o usbvision-video.o usbvision-i2c.o usbvision- obj-$(CONFIG_VIDEO_USBVISION) += usbvision.o EXTRA_CFLAGS += -Idrivers/media/video +EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index 7cc42c1da457..e9dd996fd5df 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -710,7 +710,8 @@ EXPORT_SYMBOL(v4l2_chip_ident_i2c_client); /* Helper function for I2C legacy drivers */ int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver, - const char *name, int (*probe)(struct i2c_client *)) + const char *name, + int (*probe)(struct i2c_client *, const struct i2c_device_id *)) { struct i2c_client *client; int err; @@ -724,7 +725,7 @@ int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver client->driver = driver; strlcpy(client->name, name, sizeof(client->name)); - err = probe(client); + err = probe(client, NULL); if (err == 0) { i2c_attach_client(client); } else { diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c index 282c81403c97..fac0deba24af 100644 --- a/drivers/media/video/vp27smpx.c +++ b/drivers/media/video/vp27smpx.c @@ -121,7 +121,8 @@ static int vp27smpx_command(struct i2c_client *client, unsigned cmd, void *arg) * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static int vp27smpx_probe(struct i2c_client *client) +static int vp27smpx_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct vp27smpx_state *state; diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c index 31795b4f8b63..0f8ed8461fba 100644 --- a/drivers/media/video/wm8739.c +++ b/drivers/media/video/wm8739.c @@ -261,7 +261,8 @@ static int wm8739_command(struct i2c_client *client, unsigned cmd, void *arg) /* i2c implementation */ -static int wm8739_probe(struct i2c_client *client) +static int wm8739_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct wm8739_state *state; diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c index 869f9e7946b6..67a409e60c46 100644 --- a/drivers/media/video/wm8775.c +++ b/drivers/media/video/wm8775.c @@ -159,7 +159,8 @@ static int wm8775_command(struct i2c_client *client, unsigned cmd, void *arg) * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1' */ -static int wm8775_probe(struct i2c_client *client) +static int wm8775_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct wm8775_state *state; diff --git a/drivers/media/video/zoran_procfs.c b/drivers/media/video/zoran_procfs.c index 328ed6e7ac6a..870bc5a70e3f 100644 --- a/drivers/media/video/zoran_procfs.c +++ b/drivers/media/video/zoran_procfs.c @@ -180,6 +180,7 @@ static ssize_t zoran_write(struct file *file, const char __user *buffer, } static const struct file_operations zoran_operations = { + .owner = THIS_MODULE, .open = zoran_open, .read = seq_read, .write = zoran_write, @@ -195,10 +196,8 @@ zoran_proc_init (struct zoran *zr) char name[8]; snprintf(name, 7, "zoran%d", zr->id); - if ((zr->zoran_proc = create_proc_entry(name, 0, NULL))) { - zr->zoran_proc->data = zr; - zr->zoran_proc->owner = THIS_MODULE; - zr->zoran_proc->proc_fops = &zoran_operations; + zr->zoran_proc = proc_create_data(name, 0, NULL, &zoran_operations, zr); + if (zr->zoran_proc != NULL) { dprintk(2, KERN_INFO "%s: procfs entry /proc/%s allocated. data=%p\n", diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index a95314897402..81483de8c0fd 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -371,7 +371,7 @@ static int i2o_block_prep_req_fn(struct request_queue *q, struct request *req) /* connect the i2o_block_request to the request */ if (!req->special) { ireq = i2o_block_request_alloc(); - if (unlikely(IS_ERR(ireq))) { + if (IS_ERR(ireq)) { osm_debug("unable to allocate i2o_block_request!\n"); return BLKPREP_DEFER; } diff --git a/drivers/message/i2o/i2o_proc.c b/drivers/message/i2o/i2o_proc.c index 6fdd072201f9..54a3016ff45d 100644 --- a/drivers/message/i2o/i2o_proc.c +++ b/drivers/message/i2o/i2o_proc.c @@ -1893,13 +1893,11 @@ static int i2o_proc_create_entries(struct proc_dir_entry *dir, struct proc_dir_entry *tmp; while (i2o_pe->name) { - tmp = create_proc_entry(i2o_pe->name, i2o_pe->mode, dir); + tmp = proc_create_data(i2o_pe->name, i2o_pe->mode, dir, + i2o_pe->fops, data); if (!tmp) return -1; - tmp->data = data; - tmp->proc_fops = i2o_pe->fops; - i2o_pe++; } diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index f6f2d960cadb..ef8a492766a7 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -132,7 +132,7 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) if (iter >= MAX_ASIC_ISR_LOOPS) printk(KERN_ERR "%s: interrupt processing overrun\n", - __FUNCTION__); + __func__); } static inline int asic3_irq_to_bank(struct asic3 *asic, int irq) @@ -409,7 +409,7 @@ int asic3_gpio_get_value(struct asic3 *asic, unsigned gpio) return asic3_get_gpio_d(asic, Status) & mask; default: printk(KERN_ERR "%s: invalid GPIO value 0x%x", - __FUNCTION__, gpio); + __func__, gpio); return -EINVAL; } } @@ -437,7 +437,7 @@ void asic3_gpio_set_value(struct asic3 *asic, unsigned gpio, int val) return; default: printk(KERN_ERR "%s: invalid GPIO value 0x%x", - __FUNCTION__, gpio); + __func__, gpio); return; } } diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c index 4edc120a6359..633cbba072f0 100644 --- a/drivers/mfd/htc-pasic3.c +++ b/drivers/mfd/htc-pasic3.c @@ -132,8 +132,9 @@ static struct ds1wm_platform_data ds1wm_pdata = { .disable = ds1wm_disable, }; -static int ds1wm_device_add(struct device *pasic3_dev, int bus_shift) +static int ds1wm_device_add(struct platform_device *pasic3_pdev, int bus_shift) { + struct device *pasic3_dev = &pasic3_pdev->dev; struct pasic3_data *asic = pasic3_dev->driver_data; struct platform_device *pdev; int ret; @@ -144,8 +145,8 @@ static int ds1wm_device_add(struct device *pasic3_dev, int bus_shift) return -ENOMEM; } - ret = platform_device_add_resources(pdev, pdev->resource, - pdev->num_resources); + ret = platform_device_add_resources(pdev, pasic3_pdev->resource, + pasic3_pdev->num_resources); if (ret < 0) { dev_dbg(pasic3_dev, "failed to add DS1WM resources\n"); goto exit_pdev_put; @@ -207,7 +208,7 @@ static int __init pasic3_probe(struct platform_device *pdev) return -ENOMEM; } - ret = ds1wm_device_add(dev, asic->bus_shift); + ret = ds1wm_device_add(pdev, asic->bus_shift); if (ret < 0) dev_warn(dev, "failed to register DS1WM\n"); diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index 6e655b4c6682..2fe64734d8af 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -349,11 +349,11 @@ int sm501_unit_power(struct device *dev, unsigned int unit, unsigned int to) mode &= 3; /* get current power mode */ if (unit >= ARRAY_SIZE(sm->unit_power)) { - dev_err(dev, "%s: bad unit %d\n", __FUNCTION__, unit); + dev_err(dev, "%s: bad unit %d\n", __func__, unit); goto already; } - dev_dbg(sm->dev, "%s: unit %d, cur %d, to %d\n", __FUNCTION__, unit, + dev_dbg(sm->dev, "%s: unit %d, cur %d, to %d\n", __func__, unit, sm->unit_power[unit], to); if (to == 0 && sm->unit_power[unit] == 0) { diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c index 302e92418bbe..ff51ab67231c 100644 --- a/drivers/misc/hdpuftrs/hdpu_cpustate.c +++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c @@ -210,13 +210,10 @@ static int hdpu_cpustate_probe(struct platform_device *pdev) return ret; } - proc_de = create_proc_entry("sky_cpustate", 0666, &proc_root); + proc_de = proc_create("sky_cpustate", 0666, NULL, &proc_cpustate); if (!proc_de) { printk(KERN_WARNING "sky_cpustate: " "Unable to create proc entry\n"); - } else { - proc_de->proc_fops = &proc_cpustate; - proc_de->owner = THIS_MODULE; } printk(KERN_INFO "Sky CPU State Driver v" SKY_CPUSTATE_VERSION "\n"); diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c index 2fa36f7a6eb3..08e26beefe64 100644 --- a/drivers/misc/hdpuftrs/hdpu_nexus.c +++ b/drivers/misc/hdpuftrs/hdpu_nexus.c @@ -102,22 +102,17 @@ static int hdpu_nexus_probe(struct platform_device *pdev) printk(KERN_ERR "sky_nexus: Could not map slot id\n"); } - hdpu_slot_id = create_proc_entry("sky_slot_id", 0666, &proc_root); + hdpu_slot_id = proc_create("sky_slot_id", 0666, NULL, &proc_slot_id); if (!hdpu_slot_id) { printk(KERN_WARNING "sky_nexus: " "Unable to create proc dir entry: sky_slot_id\n"); - } else { - hdpu_slot_id->proc_fops = &proc_slot_id; - hdpu_slot_id->owner = THIS_MODULE; } - hdpu_chassis_id = create_proc_entry("sky_chassis_id", 0666, &proc_root); - if (!hdpu_chassis_id) { + hdpu_chassis_id = proc_create("sky_chassis_id", 0666, NULL, + &proc_chassis_id); + if (!hdpu_chassis_id) printk(KERN_WARNING "sky_nexus: " "Unable to create proc dir entry: sky_chassis_id\n"); - } else { - hdpu_chassis_id->proc_fops = &proc_chassis_id; - hdpu_chassis_id->owner = THIS_MODULE; } return 0; @@ -128,8 +123,8 @@ static int hdpu_nexus_remove(struct platform_device *pdev) slot_id = -1; chassis_id = -1; - remove_proc_entry("sky_slot_id", &proc_root); - remove_proc_entry("sky_chassis_id", &proc_root); + remove_proc_entry("sky_slot_id", NULL); + remove_proc_entry("sky_chassis_id", NULL); hdpu_slot_id = 0; hdpu_chassis_id = 0; diff --git a/drivers/misc/ibmasm/command.c b/drivers/misc/ibmasm/command.c index 1a0e7978226a..276d3fb68094 100644 --- a/drivers/misc/ibmasm/command.c +++ b/drivers/misc/ibmasm/command.c @@ -96,7 +96,7 @@ static inline void do_exec_command(struct service_processor *sp) { char tsbuf[32]; - dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf)); + dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf)); if (ibmasm_send_i2o_message(sp)) { sp->current_command->status = IBMASM_CMD_FAILED; @@ -119,7 +119,7 @@ void ibmasm_exec_command(struct service_processor *sp, struct command *cmd) unsigned long flags; char tsbuf[32]; - dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf)); + dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf)); spin_lock_irqsave(&sp->lock, flags); @@ -139,7 +139,7 @@ static void exec_next_command(struct service_processor *sp) unsigned long flags; char tsbuf[32]; - dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf)); + dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf)); spin_lock_irqsave(&sp->lock, flags); sp->current_command = dequeue_command(sp); diff --git a/drivers/misc/ibmasm/heartbeat.c b/drivers/misc/ibmasm/heartbeat.c index 3036e785b3e4..1bc4306572a4 100644 --- a/drivers/misc/ibmasm/heartbeat.c +++ b/drivers/misc/ibmasm/heartbeat.c @@ -75,9 +75,9 @@ void ibmasm_heartbeat_exit(struct service_processor *sp) { char tsbuf[32]; - dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf)); + dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf)); ibmasm_wait_for_response(sp->heartbeat, IBMASM_CMD_TIMEOUT_NORMAL); - dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf)); + dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf)); suspend_heartbeats = 1; command_put(sp->heartbeat); } @@ -88,7 +88,7 @@ void ibmasm_receive_heartbeat(struct service_processor *sp, void *message, size struct dot_command_header *header = (struct dot_command_header *)cmd->buffer; char tsbuf[32]; - dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf)); + dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf)); if (suspend_heartbeats) return; diff --git a/drivers/misc/intel_menlow.c b/drivers/misc/intel_menlow.c index 0c0bb3093e07..80a136352408 100644 --- a/drivers/misc/intel_menlow.c +++ b/drivers/misc/intel_menlow.c @@ -175,19 +175,17 @@ static int intel_menlow_memory_add(struct acpi_device *device) goto end; } - if (cdev) { - acpi_driver_data(device) = cdev; - result = sysfs_create_link(&device->dev.kobj, - &cdev->device.kobj, "thermal_cooling"); - if (result) - goto unregister; - - result = sysfs_create_link(&cdev->device.kobj, - &device->dev.kobj, "device"); - if (result) { - sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); - goto unregister; - } + acpi_driver_data(device) = cdev; + result = sysfs_create_link(&device->dev.kobj, + &cdev->device.kobj, "thermal_cooling"); + if (result) + goto unregister; + + result = sysfs_create_link(&cdev->device.kobj, + &device->dev.kobj, "device"); + if (result) { + sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); + goto unregister; } end: diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c index 05172d2613d6..6f76573e7c8a 100644 --- a/drivers/misc/ioc4.c +++ b/drivers/misc/ioc4.c @@ -75,7 +75,7 @@ ioc4_register_submodule(struct ioc4_submodule *is) printk(KERN_WARNING "%s: IOC4 submodule %s probe failed " "for pci_dev %s", - __FUNCTION__, module_name(is->is_owner), + __func__, module_name(is->is_owner), pci_name(idd->idd_pdev)); } } @@ -102,7 +102,7 @@ ioc4_unregister_submodule(struct ioc4_submodule *is) printk(KERN_WARNING "%s: IOC4 submodule %s remove failed " "for pci_dev %s.\n", - __FUNCTION__, module_name(is->is_owner), + __func__, module_name(is->is_owner), pci_name(idd->idd_pdev)); } } @@ -282,7 +282,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) if ((ret = pci_enable_device(pdev))) { printk(KERN_WARNING "%s: Failed to enable IOC4 device for pci_dev %s.\n", - __FUNCTION__, pci_name(pdev)); + __func__, pci_name(pdev)); goto out; } pci_set_master(pdev); @@ -292,7 +292,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) if (!idd) { printk(KERN_WARNING "%s: Failed to allocate IOC4 data for pci_dev %s.\n", - __FUNCTION__, pci_name(pdev)); + __func__, pci_name(pdev)); ret = -ENODEV; goto out_idd; } @@ -307,7 +307,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) printk(KERN_WARNING "%s: Unable to find IOC4 misc resource " "for pci_dev %s.\n", - __FUNCTION__, pci_name(idd->idd_pdev)); + __func__, pci_name(idd->idd_pdev)); ret = -ENODEV; goto out_pci; } @@ -316,7 +316,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) printk(KERN_WARNING "%s: Unable to request IOC4 misc region " "for pci_dev %s.\n", - __FUNCTION__, pci_name(idd->idd_pdev)); + __func__, pci_name(idd->idd_pdev)); ret = -ENODEV; goto out_pci; } @@ -326,7 +326,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) printk(KERN_WARNING "%s: Unable to remap IOC4 misc region " "for pci_dev %s.\n", - __FUNCTION__, pci_name(idd->idd_pdev)); + __func__, pci_name(idd->idd_pdev)); ret = -ENODEV; goto out_misc_region; } @@ -372,7 +372,7 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) printk(KERN_WARNING "%s: IOC4 submodule 0x%s probe failed " "for pci_dev %s.\n", - __FUNCTION__, module_name(is->is_owner), + __func__, module_name(is->is_owner), pci_name(idd->idd_pdev)); } } @@ -406,7 +406,7 @@ ioc4_remove(struct pci_dev *pdev) printk(KERN_WARNING "%s: IOC4 submodule 0x%s remove failed " "for pci_dev %s.\n", - __FUNCTION__, module_name(is->is_owner), + __func__, module_name(is->is_owner), pci_name(idd->idd_pdev)); } } @@ -418,7 +418,7 @@ ioc4_remove(struct pci_dev *pdev) printk(KERN_WARNING "%s: Unable to get IOC4 misc mapping for pci_dev %s. " "Device removal may be incomplete.\n", - __FUNCTION__, pci_name(idd->idd_pdev)); + __func__, pci_name(idd->idd_pdev)); } release_mem_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs)); diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c index 7fa61e907e1c..71d1c84e2fa8 100644 --- a/drivers/misc/phantom.c +++ b/drivers/misc/phantom.c @@ -12,6 +12,7 @@ * or alternatively, you might use OpenHaptics provided by Sensable. */ +#include <linux/compat.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/device.h> @@ -91,11 +92,8 @@ static long phantom_ioctl(struct file *file, unsigned int cmd, unsigned long flags; unsigned int i; - if (_IOC_TYPE(cmd) != PH_IOC_MAGIC || - _IOC_NR(cmd) > PH_IOC_MAXNR) - return -ENOTTY; - switch (cmd) { + case PHN_SETREG: case PHN_SET_REG: if (copy_from_user(&r, argp, sizeof(r))) return -EFAULT; @@ -126,6 +124,7 @@ static long phantom_ioctl(struct file *file, unsigned int cmd, phantom_status(dev, dev->status & ~PHB_RUNNING); spin_unlock_irqrestore(&dev->regs_lock, flags); break; + case PHN_SETREGS: case PHN_SET_REGS: if (copy_from_user(&rs, argp, sizeof(rs))) return -EFAULT; @@ -143,6 +142,7 @@ static long phantom_ioctl(struct file *file, unsigned int cmd, } spin_unlock_irqrestore(&dev->regs_lock, flags); break; + case PHN_GETREG: case PHN_GET_REG: if (copy_from_user(&r, argp, sizeof(r))) return -EFAULT; @@ -155,6 +155,7 @@ static long phantom_ioctl(struct file *file, unsigned int cmd, if (copy_to_user(argp, &r, sizeof(r))) return -EFAULT; break; + case PHN_GETREGS: case PHN_GET_REGS: { u32 m; @@ -168,6 +169,7 @@ static long phantom_ioctl(struct file *file, unsigned int cmd, for (i = 0; i < m; i++) if (rs.mask & BIT(i)) rs.values[i] = ioread32(dev->iaddr + i); + atomic_set(&dev->counter, 0); spin_unlock_irqrestore(&dev->regs_lock, flags); if (copy_to_user(argp, &rs, sizeof(rs))) @@ -191,6 +193,20 @@ static long phantom_ioctl(struct file *file, unsigned int cmd, return 0; } +#ifdef CONFIG_COMPAT +static long phantom_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + if (_IOC_NR(cmd) <= 3 && _IOC_SIZE(cmd) == sizeof(compat_uptr_t)) { + cmd &= ~(_IOC_SIZEMASK << _IOC_SIZESHIFT); + cmd |= sizeof(void *) << _IOC_SIZESHIFT; + } + return phantom_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); +} +#else +#define phantom_compat_ioctl NULL +#endif + static int phantom_open(struct inode *inode, struct file *file) { struct phantom_device *dev = container_of(inode->i_cdev, @@ -239,11 +255,12 @@ static unsigned int phantom_poll(struct file *file, poll_table *wait) pr_debug("phantom_poll: %d\n", atomic_read(&dev->counter)); poll_wait(file, &dev->wait, wait); - if (atomic_read(&dev->counter)) { + + if (!(dev->status & PHB_RUNNING)) + mask = POLLERR; + else if (atomic_read(&dev->counter)) mask = POLLIN | POLLRDNORM; - atomic_dec(&dev->counter); - } else if ((dev->status & PHB_RUNNING) == 0) - mask = POLLIN | POLLRDNORM | POLLERR; + pr_debug("phantom_poll end: %x/%d\n", mask, atomic_read(&dev->counter)); return mask; @@ -253,6 +270,7 @@ static struct file_operations phantom_file_ops = { .open = phantom_open, .release = phantom_release, .unlocked_ioctl = phantom_ioctl, + .compat_ioctl = phantom_compat_ioctl, .poll = phantom_poll, }; diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c index 27e200ec5826..acd3fd4285d7 100644 --- a/drivers/misc/sgi-xp/xpc_partition.c +++ b/drivers/misc/sgi-xp/xpc_partition.c @@ -211,7 +211,7 @@ xpc_rsvd_page_init(void) */ amos_page = xpc_vars->amos_page; if (amos_page == NULL) { - amos_page = (AMO_t *)TO_AMO(uncached_alloc_page(0)); + amos_page = (AMO_t *)TO_AMO(uncached_alloc_page(0, 1)); if (amos_page == NULL) { dev_err(xpc_part, "can't allocate page of AMOs\n"); return NULL; @@ -230,7 +230,7 @@ xpc_rsvd_page_init(void) dev_err(xpc_part, "can't change memory " "protections\n"); uncached_free_page(__IA64_UNCACHED_OFFSET | - TO_PHYS((u64)amos_page)); + TO_PHYS((u64)amos_page), 1); return NULL; } } diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c index 02ff3d19b1cc..00e48e2a9c11 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c @@ -961,7 +961,7 @@ static int sony_nc_resume(struct acpi_device *device) ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, item->value, NULL); if (ret < 0) { - printk("%s: %d\n", __FUNCTION__, ret); + printk("%s: %d\n", __func__, ret); break; } } @@ -1453,7 +1453,7 @@ static struct sonypi_eventtypes type4_events[] = { udelay(1); \ if (!n) \ dprintk("command failed at %s : %s (line %d)\n", \ - __FILE__, __FUNCTION__, __LINE__); \ + __FILE__, __func__, __LINE__); \ } static u8 sony_pic_call1(u8 dev) diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index 365024b83d3d..35508584ac2a 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -340,7 +340,7 @@ checkstatus: /* SPI R3, R4, or R7 == R1 + 4 bytes */ case MMC_RSP_SPI_R3: - cmd->resp[1] = be32_to_cpu(get_unaligned((u32 *)cp)); + cmd->resp[1] = get_unaligned_be32(cp); break; /* SPI R1 == just one status byte */ diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 95244a7e7353..626ac083f4e0 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -213,9 +213,10 @@ static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int rema void __iomem *base = host->base; char *ptr = buffer; u32 status; + int host_remain = host->size; do { - int count = host->size - (readl(base + MMCIFIFOCNT) << 2); + int count = host_remain - (readl(base + MMCIFIFOCNT) << 2); if (count > remain) count = remain; @@ -227,6 +228,7 @@ static int mmci_pio_read(struct mmci_host *host, char *buffer, unsigned int rema ptr += count; remain -= count; + host_remain -= count; if (remain == 0) break; diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c index ba6bd03a015f..a637910b02dd 100644 --- a/drivers/net/arm/am79c961a.c +++ b/drivers/net/arm/am79c961a.c @@ -693,11 +693,15 @@ static int __init am79c961_probe(struct platform_device *pdev) * done by the ether bootp loader. */ dev->base_addr = res->start; - dev->irq = platform_get_irq(pdev, 0); + ret = platform_get_irq(pdev, 0); - ret = -ENODEV; - if (dev->irq < 0) + if (ret < 0) { + ret = -ENODEV; goto nodev; + } + dev->irq = ret; + + ret = -ENODEV; if (!request_region(dev->base_addr, 0x18, dev->name)) goto nodev; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 6e91b4b7aabb..6425603bc379 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3282,17 +3282,14 @@ static int bond_create_proc_entry(struct bonding *bond) struct net_device *bond_dev = bond->dev; if (bond_proc_dir) { - bond->proc_entry = create_proc_entry(bond_dev->name, - S_IRUGO, - bond_proc_dir); + bond->proc_entry = proc_create_data(bond_dev->name, + S_IRUGO, bond_proc_dir, + &bond_info_fops, bond); if (bond->proc_entry == NULL) { printk(KERN_WARNING DRV_NAME ": Warning: Cannot create /proc/net/%s/%s\n", DRV_NAME, bond_dev->name); } else { - bond->proc_entry->data = bond; - bond->proc_entry->proc_fops = &bond_info_fops; - bond->proc_entry->owner = THIS_MODULE; memcpy(bond->proc_file_name, bond_dev->name, IFNAMSIZ); } } diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h index 229303ff6a39..a0177fc55e28 100644 --- a/drivers/net/cxgb3/version.h +++ b/drivers/net/cxgb3/version.h @@ -38,7 +38,7 @@ #define DRV_VERSION "1.0-ko" /* Firmware version */ -#define FW_VERSION_MAJOR 5 +#define FW_VERSION_MAJOR 6 #define FW_VERSION_MINOR 0 #define FW_VERSION_MICRO 0 #endif /* __CHELSIO_VERSION_H */ diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 2d139ec79777..f3cba5e24ec5 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1802,7 +1802,7 @@ static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx) * it is protected by the before last buffer's el bit being set */ if (rx->prev->skb) { struct rfd *prev_rfd = (struct rfd *)rx->prev->skb->data; - put_unaligned(cpu_to_le32(rx->dma_addr), &prev_rfd->link); + put_unaligned_le32(rx->dma_addr, &prev_rfd->link); } return 0; diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index b53f6b6491b3..e5c2380f50ca 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -1508,7 +1508,7 @@ static int hamachi_rx(struct net_device *dev) hmp->rx_buf_sz, PCI_DMA_FROMDEVICE); buf_addr = (u8 *) hmp->rx_skbuff[entry]->data; - frame_status = le32_to_cpu(get_unaligned((__le32*)&(buf_addr[data_size - 12]))); + frame_status = get_unaligned_le32(&(buf_addr[data_size - 12])); if (hamachi_debug > 4) printk(KERN_DEBUG " hamachi_rx() status was %8.8x.\n", frame_status); diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 1da55dd2a5a0..9d5721287d6f 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -148,13 +148,13 @@ static void sp_xmit_on_air(unsigned long channel) if (((sp->status1 & SIXP_DCD_MASK) == 0) && (random < sp->persistence)) { sp->led_state = 0x70; - sp->tty->driver->write(sp->tty, &sp->led_state, 1); + sp->tty->ops->write(sp->tty, &sp->led_state, 1); sp->tx_enable = 1; - actual = sp->tty->driver->write(sp->tty, sp->xbuff, sp->status2); + actual = sp->tty->ops->write(sp->tty, sp->xbuff, sp->status2); sp->xleft -= actual; sp->xhead += actual; sp->led_state = 0x60; - sp->tty->driver->write(sp->tty, &sp->led_state, 1); + sp->tty->ops->write(sp->tty, &sp->led_state, 1); sp->status2 = 0; } else mod_timer(&sp->tx_t, jiffies + ((when + 1) * HZ) / 100); @@ -220,13 +220,13 @@ static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len) */ if (sp->duplex == 1) { sp->led_state = 0x70; - sp->tty->driver->write(sp->tty, &sp->led_state, 1); + sp->tty->ops->write(sp->tty, &sp->led_state, 1); sp->tx_enable = 1; - actual = sp->tty->driver->write(sp->tty, sp->xbuff, count); + actual = sp->tty->ops->write(sp->tty, sp->xbuff, count); sp->xleft = count - actual; sp->xhead = sp->xbuff + actual; sp->led_state = 0x60; - sp->tty->driver->write(sp->tty, &sp->led_state, 1); + sp->tty->ops->write(sp->tty, &sp->led_state, 1); } else { sp->xleft = count; sp->xhead = sp->xbuff; @@ -444,7 +444,7 @@ static void sixpack_write_wakeup(struct tty_struct *tty) } if (sp->tx_enable) { - actual = tty->driver->write(tty, sp->xhead, sp->xleft); + actual = tty->ops->write(tty, sp->xhead, sp->xleft); sp->xleft -= actual; sp->xhead += actual; } @@ -491,9 +491,7 @@ static void sixpack_receive_buf(struct tty_struct *tty, sixpack_decode(sp, buf, count1); sp_put(sp); - if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) - && tty->driver->unthrottle) - tty->driver->unthrottle(tty); + tty_unthrottle(tty); } /* @@ -554,8 +552,8 @@ static void resync_tnc(unsigned long channel) /* resync the TNC */ sp->led_state = 0x60; - sp->tty->driver->write(sp->tty, &sp->led_state, 1); - sp->tty->driver->write(sp->tty, &resync_cmd, 1); + sp->tty->ops->write(sp->tty, &sp->led_state, 1); + sp->tty->ops->write(sp->tty, &resync_cmd, 1); /* Start resync timer again -- the TNC might be still absent */ @@ -573,7 +571,7 @@ static inline int tnc_init(struct sixpack *sp) tnc_set_sync_state(sp, TNC_UNSYNC_STARTUP); - sp->tty->driver->write(sp->tty, &inbyte, 1); + sp->tty->ops->write(sp->tty, &inbyte, 1); del_timer(&sp->resync_t); sp->resync_t.data = (unsigned long) sp; @@ -601,6 +599,8 @@ static int sixpack_open(struct tty_struct *tty) if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (tty->ops->write == NULL) + return -EOPNOTSUPP; dev = alloc_netdev(sizeof(struct sixpack), "sp%d", sp_setup); if (!dev) { @@ -914,9 +914,9 @@ static void decode_prio_command(struct sixpack *sp, unsigned char cmd) } else { /* output watchdog char if idle */ if ((sp->status2 != 0) && (sp->duplex == 1)) { sp->led_state = 0x70; - sp->tty->driver->write(sp->tty, &sp->led_state, 1); + sp->tty->ops->write(sp->tty, &sp->led_state, 1); sp->tx_enable = 1; - actual = sp->tty->driver->write(sp->tty, sp->xbuff, sp->status2); + actual = sp->tty->ops->write(sp->tty, sp->xbuff, sp->status2); sp->xleft -= actual; sp->xhead += actual; sp->led_state = 0x60; @@ -926,7 +926,7 @@ static void decode_prio_command(struct sixpack *sp, unsigned char cmd) } /* needed to trigger the TNC watchdog */ - sp->tty->driver->write(sp->tty, &sp->led_state, 1); + sp->tty->ops->write(sp->tty, &sp->led_state, 1); /* if the state byte has been received, the TNC is present, so the resync timer can be reset. */ @@ -956,12 +956,12 @@ static void decode_std_command(struct sixpack *sp, unsigned char cmd) if ((sp->status & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK) { sp->led_state = 0x68; - sp->tty->driver->write(sp->tty, &sp->led_state, 1); + sp->tty->ops->write(sp->tty, &sp->led_state, 1); } } else { sp->led_state = 0x60; /* fill trailing bytes with zeroes */ - sp->tty->driver->write(sp->tty, &sp->led_state, 1); + sp->tty->ops->write(sp->tty, &sp->led_state, 1); rest = sp->rx_count; if (rest != 0) for (i = rest; i <= 3; i++) diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 30c9b3b0d131..65166035aca0 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -516,7 +516,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) spin_unlock_bh(&ax->buflock); set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags); - actual = ax->tty->driver->write(ax->tty, ax->xbuff, count); + actual = ax->tty->ops->write(ax->tty, ax->xbuff, count); ax->stats.tx_packets++; ax->stats.tx_bytes += actual; @@ -546,7 +546,7 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev) } printk(KERN_ERR "mkiss: %s: transmit timed out, %s?\n", dev->name, - (ax->tty->driver->chars_in_buffer(ax->tty) || ax->xleft) ? + (ax->tty->ops->chars_in_buffer(ax->tty) || ax->xleft) ? "bad line quality" : "driver error"); ax->xleft = 0; @@ -736,6 +736,8 @@ static int mkiss_open(struct tty_struct *tty) if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (tty->ops->write == NULL) + return -EOPNOTSUPP; dev = alloc_netdev(sizeof(struct mkiss), "ax%d", ax_setup); if (!dev) { @@ -754,8 +756,7 @@ static int mkiss_open(struct tty_struct *tty) tty->disc_data = ax; tty->receive_room = 65535; - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + tty_driver_flush_buffer(tty); /* Restore default settings */ dev->type = ARPHRD_AX25; @@ -935,9 +936,7 @@ static void mkiss_receive_buf(struct tty_struct *tty, const unsigned char *cp, } mkiss_put(ax); - if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) - && tty->driver->unthrottle) - tty->driver->unthrottle(tty); + tty_unthrottle(tty); } /* @@ -962,7 +961,7 @@ static void mkiss_write_wakeup(struct tty_struct *tty) goto out; } - actual = tty->driver->write(tty, ax->xhead, ax->xleft); + actual = tty->ops->write(tty, ax->xhead, ax->xleft); ax->xleft -= actual; ax->xhead += actual; diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index ce4fc2ec2fe4..00527805e4f1 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1302,13 +1302,10 @@ static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter) if (ibmveth_proc_dir) { char u_addr[10]; sprintf(u_addr, "%x", adapter->vdev->unit_address); - entry = create_proc_entry(u_addr, S_IFREG, ibmveth_proc_dir); - if (!entry) { + entry = proc_create_data(u_addr, S_IFREG, ibmveth_proc_dir, + &ibmveth_proc_fops, adapter); + if (!entry) ibmveth_error_printk("Cannot create adapter proc entry"); - } else { - entry->data = (void *) adapter; - entry->proc_fops = &ibmveth_proc_fops; - } } return; } diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c index fc753d7f674e..e6f40b7f9041 100644 --- a/drivers/net/irda/irtty-sir.c +++ b/drivers/net/irda/irtty-sir.c @@ -64,7 +64,7 @@ static int irtty_chars_in_buffer(struct sir_dev *dev) IRDA_ASSERT(priv != NULL, return -1;); IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;); - return priv->tty->driver->chars_in_buffer(priv->tty); + return tty_chars_in_buffer(priv->tty); } /* Wait (sleep) until underlaying hardware finished transmission @@ -93,10 +93,8 @@ static void irtty_wait_until_sent(struct sir_dev *dev) IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;); tty = priv->tty; - if (tty->driver->wait_until_sent) { - lock_kernel(); - tty->driver->wait_until_sent(tty, msecs_to_jiffies(100)); - unlock_kernel(); + if (tty->ops->wait_until_sent) { + tty->ops->wait_until_sent(tty, msecs_to_jiffies(100)); } else { msleep(USBSERIAL_TX_DONE_DELAY); @@ -125,48 +123,14 @@ static int irtty_change_speed(struct sir_dev *dev, unsigned speed) tty = priv->tty; - lock_kernel(); + mutex_lock(&tty->termios_mutex); old_termios = *(tty->termios); cflag = tty->termios->c_cflag; - - cflag &= ~CBAUD; - - IRDA_DEBUG(2, "%s(), Setting speed to %d\n", __FUNCTION__, speed); - - switch (speed) { - case 1200: - cflag |= B1200; - break; - case 2400: - cflag |= B2400; - break; - case 4800: - cflag |= B4800; - break; - case 19200: - cflag |= B19200; - break; - case 38400: - cflag |= B38400; - break; - case 57600: - cflag |= B57600; - break; - case 115200: - cflag |= B115200; - break; - case 9600: - default: - cflag |= B9600; - break; - } - - tty->termios->c_cflag = cflag; - if (tty->driver->set_termios) - tty->driver->set_termios(tty, &old_termios); - unlock_kernel(); - + tty_encode_baud_rate(tty, speed, speed); + if (tty->ops->set_termios) + tty->ops->set_termios(tty, &old_termios); priv->io.speed = speed; + mutex_unlock(&tty->termios_mutex); return 0; } @@ -202,8 +166,8 @@ static int irtty_set_dtr_rts(struct sir_dev *dev, int dtr, int rts) * This function is not yet defined for all tty driver, so * let's be careful... Jean II */ - IRDA_ASSERT(priv->tty->driver->tiocmset != NULL, return -1;); - priv->tty->driver->tiocmset(priv->tty, NULL, set, clear); + IRDA_ASSERT(priv->tty->ops->tiocmset != NULL, return -1;); + priv->tty->ops->tiocmset(priv->tty, NULL, set, clear); return 0; } @@ -225,17 +189,13 @@ static int irtty_do_write(struct sir_dev *dev, const unsigned char *ptr, size_t IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;); tty = priv->tty; - if (!tty->driver->write) + if (!tty->ops->write) return 0; tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); - if (tty->driver->write_room) { - writelen = tty->driver->write_room(tty); - if (writelen > len) - writelen = len; - } - else + writelen = tty_write_room(tty); + if (writelen > len) writelen = len; - return tty->driver->write(tty, ptr, writelen); + return tty->ops->write(tty, ptr, writelen); } /* ------------------------------------------------------- */ @@ -321,7 +281,7 @@ static inline void irtty_stop_receiver(struct tty_struct *tty, int stop) struct ktermios old_termios; int cflag; - lock_kernel(); + mutex_lock(&tty->termios_mutex); old_termios = *(tty->termios); cflag = tty->termios->c_cflag; @@ -331,9 +291,9 @@ static inline void irtty_stop_receiver(struct tty_struct *tty, int stop) cflag |= CREAD; tty->termios->c_cflag = cflag; - if (tty->driver->set_termios) - tty->driver->set_termios(tty, &old_termios); - unlock_kernel(); + if (tty->ops->set_termios) + tty->ops->set_termios(tty, &old_termios); + mutex_unlock(&tty->termios_mutex); } /*****************************************************************/ @@ -359,8 +319,8 @@ static int irtty_start_dev(struct sir_dev *dev) tty = priv->tty; - if (tty->driver->start) - tty->driver->start(tty); + if (tty->ops->start) + tty->ops->start(tty); /* Make sure we can receive more data */ irtty_stop_receiver(tty, FALSE); @@ -388,8 +348,8 @@ static int irtty_stop_dev(struct sir_dev *dev) /* Make sure we don't receive more data */ irtty_stop_receiver(tty, TRUE); - if (tty->driver->stop) - tty->driver->stop(tty); + if (tty->ops->stop) + tty->ops->stop(tty); mutex_unlock(&irtty_mutex); @@ -483,11 +443,10 @@ static int irtty_open(struct tty_struct *tty) /* stop the underlying driver */ irtty_stop_receiver(tty, TRUE); - if (tty->driver->stop) - tty->driver->stop(tty); + if (tty->ops->stop) + tty->ops->stop(tty); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + tty_driver_flush_buffer(tty); /* apply mtt override */ sir_tty_drv.qos_mtt_bits = qos_mtt_bits; @@ -564,8 +523,8 @@ static void irtty_close(struct tty_struct *tty) /* Stop tty */ irtty_stop_receiver(tty, TRUE); tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - if (tty->driver->stop) - tty->driver->stop(tty); + if (tty->ops->stop) + tty->ops->stop(tty); kfree(priv); diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index 93916cf33f29..ad92d3ff1c40 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -464,7 +464,7 @@ static void mcs_unwrap_fir(struct mcs_cb *mcs, __u8 *buf, int len) } fcs = ~(crc32_le(~0, buf, new_len)); - if(fcs != le32_to_cpu(get_unaligned((__le32 *)(buf+new_len)))) { + if(fcs != get_unaligned_le32(buf + new_len)) { IRDA_ERROR("crc error calc 0x%x len %d\n", fcs, new_len); mcs->stats.rx_errors++; mcs->stats.rx_crc_errors++; diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index e59c485bc497..051963782749 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -329,7 +329,7 @@ static void fir_eof(struct stir_cb *stir) } fcs = ~(crc32_le(~0, rx_buff->data, len)); - if (fcs != le32_to_cpu(get_unaligned((__le32 *)(rx_buff->data+len)))) { + if (fcs != get_unaligned_le32(rx_buff->data + len)) { pr_debug("crc error calc 0x%x len %d\n", fcs, len); stir->stats.rx_errors++; stir->stats.rx_crc_errors++; diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index acd082a96a4f..d15e00b8591e 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -1674,13 +1674,12 @@ vlsi_irda_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (vlsi_proc_root != NULL) { struct proc_dir_entry *ent; - ent = create_proc_entry(ndev->name, S_IFREG|S_IRUGO, vlsi_proc_root); + ent = proc_create_data(ndev->name, S_IFREG|S_IRUGO, + vlsi_proc_root, VLSI_PROC_FOPS, ndev); if (!ent) { IRDA_WARNING("%s: failed to create proc entry\n", __FUNCTION__); } else { - ent->data = ndev; - ent->proc_fops = VLSI_PROC_FOPS; ent->size = 0; } idev->proc_entry = ent; diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c index 6fda0af9d0a6..95e87a2f8896 100644 --- a/drivers/net/mlx4/cq.c +++ b/drivers/net/mlx4/cq.c @@ -188,7 +188,8 @@ int mlx4_cq_resize(struct mlx4_dev *dev, struct mlx4_cq *cq, EXPORT_SYMBOL_GPL(mlx4_cq_resize); int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, - struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq) + struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq, + int collapsed) { struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_cq_table *cq_table = &priv->cq_table; @@ -224,6 +225,7 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt, cq_context = mailbox->buf; memset(cq_context, 0, sizeof *cq_context); + cq_context->flags = cpu_to_be32(!!collapsed << 18); cq_context->logsize_usrpage = cpu_to_be32((ilog2(nent) << 24) | uar->index); cq_context->comp_eqn = priv->eq_table.eq[MLX4_EQ_COMP].eqn; cq_context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT; diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c index 79b317b88c86..cb46446b2691 100644 --- a/drivers/net/mlx4/mr.c +++ b/drivers/net/mlx4/mr.c @@ -607,15 +607,9 @@ EXPORT_SYMBOL_GPL(mlx4_fmr_enable); void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u32 *lkey, u32 *rkey) { - u32 key; - if (!fmr->maps) return; - key = key_to_hw_index(fmr->mr.key); - key &= dev->caps.num_mpts - 1; - *lkey = *rkey = fmr->mr.key = hw_index_to_key(key); - fmr->maps = 0; *(u8 *) fmr->mpt = MLX4_MPT_STATUS_SW; diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index cead81e80f0c..ef63c8d2bd7e 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -2437,7 +2437,7 @@ static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev) int status; segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO6); - if (unlikely(IS_ERR(segs))) + if (IS_ERR(segs)) goto drop; while (segs) { diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c index f023d5b67e6e..f1a52def1241 100644 --- a/drivers/net/ppp_async.c +++ b/drivers/net/ppp_async.c @@ -158,6 +158,9 @@ ppp_asynctty_open(struct tty_struct *tty) struct asyncppp *ap; int err; + if (tty->ops->write == NULL) + return -EOPNOTSUPP; + err = -ENOMEM; ap = kzalloc(sizeof(*ap), GFP_KERNEL); if (!ap) @@ -358,9 +361,7 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf, if (!skb_queue_empty(&ap->rqueue)) tasklet_schedule(&ap->tsk); ap_put(ap); - if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) - && tty->driver->unthrottle) - tty->driver->unthrottle(tty); + tty_unthrottle(tty); } static void @@ -676,7 +677,7 @@ ppp_async_push(struct asyncppp *ap) if (!tty_stuffed && ap->optr < ap->olim) { avail = ap->olim - ap->optr; set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - sent = tty->driver->write(tty, ap->optr, avail); + sent = tty->ops->write(tty, ap->optr, avail); if (sent < 0) goto flush; /* error, e.g. loss of CD */ ap->optr += sent; diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c index 0d80fa546719..b8f0369a71e7 100644 --- a/drivers/net/ppp_synctty.c +++ b/drivers/net/ppp_synctty.c @@ -207,6 +207,9 @@ ppp_sync_open(struct tty_struct *tty) struct syncppp *ap; int err; + if (tty->ops->write == NULL) + return -EOPNOTSUPP; + ap = kzalloc(sizeof(*ap), GFP_KERNEL); err = -ENOMEM; if (!ap) @@ -398,9 +401,7 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf, if (!skb_queue_empty(&ap->rqueue)) tasklet_schedule(&ap->tsk); sp_put(ap); - if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) - && tty->driver->unthrottle) - tty->driver->unthrottle(tty); + tty_unthrottle(tty); } static void @@ -653,7 +654,7 @@ ppp_sync_push(struct syncppp *ap) tty_stuffed = 0; if (!tty_stuffed && ap->tpkt) { set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - sent = tty->driver->write(tty, ap->tpkt->data, ap->tpkt->len); + sent = tty->ops->write(tty, ap->tpkt->data, ap->tpkt->len); if (sent < 0) goto flush; /* error, e.g. loss of CD */ if (sent < ap->tpkt->len) { diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 4fad4ddb3504..58a26a47af29 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -1052,11 +1052,9 @@ static int __init pppoe_proc_init(void) { struct proc_dir_entry *p; - p = create_proc_entry("pppoe", S_IRUGO, init_net.proc_net); + p = proc_net_fops_create(&init_net, "pppoe", S_IRUGO, &pppoe_seq_fops); if (!p) return -ENOMEM; - - p->proc_fops = &pppoe_seq_fops; return 0; } #else /* CONFIG_PROC_FS */ diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index 3d10ca050b79..244d7830c92a 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -2469,12 +2469,12 @@ static int __init pppol2tp_init(void) goto out_unregister_pppol2tp_proto; #ifdef CONFIG_PROC_FS - pppol2tp_proc = create_proc_entry("pppol2tp", 0, init_net.proc_net); + pppol2tp_proc = proc_net_fops_create(&init_net, "pppol2tp", 0, + &pppol2tp_proc_fops); if (!pppol2tp_proc) { err = -ENOMEM; goto out_unregister_pppox_proto; } - pppol2tp_proc->proc_fops = &pppol2tp_proc_fops; #endif /* CONFIG_PROC_FS */ printk(KERN_INFO "PPPoL2TP kernel driver, %s\n", PPPOL2TP_DRV_VERSION); diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 5a55ede352f4..84af68fdb6c2 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -396,14 +396,14 @@ static void sl_encaps(struct slip *sl, unsigned char *icp, int len) /* Order of next two lines is *very* important. * When we are sending a little amount of data, - * the transfer may be completed inside driver.write() + * the transfer may be completed inside the ops->write() * routine, because it's running with interrupts enabled. * In this case we *never* got WRITE_WAKEUP event, * if we did not request it before write operation. * 14 Oct 1994 Dmitry Gorodchanin. */ sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); - actual = sl->tty->driver->write(sl->tty, sl->xbuff, count); + actual = sl->tty->ops->write(sl->tty, sl->xbuff, count); #ifdef SL_CHECK_TRANSMIT sl->dev->trans_start = jiffies; #endif @@ -437,7 +437,7 @@ static void slip_write_wakeup(struct tty_struct *tty) return; } - actual = tty->driver->write(tty, sl->xhead, sl->xleft); + actual = tty->ops->write(tty, sl->xhead, sl->xleft); sl->xleft -= actual; sl->xhead += actual; } @@ -462,7 +462,7 @@ static void sl_tx_timeout(struct net_device *dev) } printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, - (sl->tty->driver->chars_in_buffer(sl->tty) || sl->xleft) ? + (tty_chars_in_buffer(sl->tty) || sl->xleft) ? "bad line quality" : "driver error"); sl->xleft = 0; sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); @@ -830,6 +830,9 @@ static int slip_open(struct tty_struct *tty) if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (tty->ops->write == NULL) + return -EOPNOTSUPP; + /* RTnetlink lock is misused here to serialize concurrent opens of slip channels. There are better ways, but it is the simplest one. @@ -1432,7 +1435,7 @@ static void sl_outfill(unsigned long sls) /* put END into tty queue. Is it right ??? */ if (!netif_queue_stopped(sl->dev)) { /* if device busy no outfill */ - sl->tty->driver->write(sl->tty, &s, 1); + sl->tty->ops->write(sl->tty, &s, 1); } } else set_bit(SLF_OUTWAIT, &sl->flags); diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index e83b166aa6b9..432e837a1760 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -649,7 +649,7 @@ static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd) DBG("%d 0x%x 0x%x\n", data[0], data[1], data[2]); } - if (!capable(CAP_NET_ADMIN)) + if (!capable(CAP_SYS_RAWIO)) return -EPERM; switch (data[0]) { diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index e3f74c9f78bd..b66c75e3b8a1 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -4361,7 +4361,7 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb) } segs = skb_gso_segment(skb, tp->dev->features & ~NETIF_F_TSO); - if (unlikely(IS_ERR(segs))) + if (IS_ERR(segs)) goto tg3_tso_bug_end; do { diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index 6c6fc325c8f9..bc30c6e8fea2 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -482,7 +482,6 @@ static char version[] __devinitdata = "de4x5.c:V0.546 2001/02/22 davies@maniac.ultranet.com\n"; #define c_char const char -#define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((__le16 *)(a))) /* ** MII Information @@ -4405,7 +4404,7 @@ srom_infoleaf_info(struct net_device *dev) } } - lp->infoleaf_offset = TWIDDLE(p+1); + lp->infoleaf_offset = get_unaligned_le16(p + 1); return 0; } @@ -4476,7 +4475,7 @@ srom_exec(struct net_device *dev, u_char *p) while (count--) { gep_wr(((lp->chipset==DC21140) && (lp->ibn!=5) ? - *p++ : TWIDDLE(w++)), dev); + *p++ : get_unaligned_le16(w++)), dev); mdelay(2); /* 2ms per action */ } @@ -4711,10 +4710,10 @@ type1_infoblock(struct net_device *dev, u_char count, u_char *p) lp->active = *p++; lp->phy[lp->active].gep = (*p ? p : NULL); p += (*p + 1); lp->phy[lp->active].rst = (*p ? p : NULL); p += (*p + 1); - lp->phy[lp->active].mc = TWIDDLE(p); p += 2; - lp->phy[lp->active].ana = TWIDDLE(p); p += 2; - lp->phy[lp->active].fdx = TWIDDLE(p); p += 2; - lp->phy[lp->active].ttm = TWIDDLE(p); + lp->phy[lp->active].mc = get_unaligned_le16(p); p += 2; + lp->phy[lp->active].ana = get_unaligned_le16(p); p += 2; + lp->phy[lp->active].fdx = get_unaligned_le16(p); p += 2; + lp->phy[lp->active].ttm = get_unaligned_le16(p); return 0; } else if ((lp->media == INIT) && (lp->timeout < 0)) { lp->ibn = 1; @@ -4751,16 +4750,16 @@ type2_infoblock(struct net_device *dev, u_char count, u_char *p) lp->infoblock_media = (*p) & MEDIA_CODE; if ((*p++) & EXT_FIELD) { - lp->cache.csr13 = TWIDDLE(p); p += 2; - lp->cache.csr14 = TWIDDLE(p); p += 2; - lp->cache.csr15 = TWIDDLE(p); p += 2; + lp->cache.csr13 = get_unaligned_le16(p); p += 2; + lp->cache.csr14 = get_unaligned_le16(p); p += 2; + lp->cache.csr15 = get_unaligned_le16(p); p += 2; } else { lp->cache.csr13 = CSR13; lp->cache.csr14 = CSR14; lp->cache.csr15 = CSR15; } - lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2; - lp->cache.gep = ((s32)(TWIDDLE(p)) << 16); + lp->cache.gepc = ((s32)(get_unaligned_le16(p)) << 16); p += 2; + lp->cache.gep = ((s32)(get_unaligned_le16(p)) << 16); lp->infoblock_csr6 = OMR_SIA; lp->useMII = false; @@ -4792,10 +4791,10 @@ type3_infoblock(struct net_device *dev, u_char count, u_char *p) if (MOTO_SROM_BUG) lp->active = 0; lp->phy[lp->active].gep = (*p ? p : NULL); p += (2 * (*p) + 1); lp->phy[lp->active].rst = (*p ? p : NULL); p += (2 * (*p) + 1); - lp->phy[lp->active].mc = TWIDDLE(p); p += 2; - lp->phy[lp->active].ana = TWIDDLE(p); p += 2; - lp->phy[lp->active].fdx = TWIDDLE(p); p += 2; - lp->phy[lp->active].ttm = TWIDDLE(p); p += 2; + lp->phy[lp->active].mc = get_unaligned_le16(p); p += 2; + lp->phy[lp->active].ana = get_unaligned_le16(p); p += 2; + lp->phy[lp->active].fdx = get_unaligned_le16(p); p += 2; + lp->phy[lp->active].ttm = get_unaligned_le16(p); p += 2; lp->phy[lp->active].mci = *p; return 0; } else if ((lp->media == INIT) && (lp->timeout < 0)) { @@ -4835,8 +4834,8 @@ type4_infoblock(struct net_device *dev, u_char count, u_char *p) lp->cache.csr13 = CSR13; /* Hard coded defaults */ lp->cache.csr14 = CSR14; lp->cache.csr15 = CSR15; - lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2; - lp->cache.gep = ((s32)(TWIDDLE(p)) << 16); p += 2; + lp->cache.gepc = ((s32)(get_unaligned_le16(p)) << 16); p += 2; + lp->cache.gep = ((s32)(get_unaligned_le16(p)) << 16); p += 2; csr6 = *p++; flags = *p++; diff --git a/drivers/net/tulip/de4x5.h b/drivers/net/tulip/de4x5.h index 9fb8d7f07994..f5f33b3eb067 100644 --- a/drivers/net/tulip/de4x5.h +++ b/drivers/net/tulip/de4x5.h @@ -1017,4 +1017,4 @@ struct de4x5_ioctl { #define DE4X5_SET_OMR 0x0d /* Set the OMR Register contents */ #define DE4X5_GET_REG 0x0e /* Get the DE4X5 Registers */ -#define MOTO_SROM_BUG ((lp->active == 8) && (((le32_to_cpu(get_unaligned(((__le32 *)dev->dev_addr))))&0x00ffffff)==0x3e0008)) +#define MOTO_SROM_BUG (lp->active == 8 && (get_unaligned_le32(dev->dev_addr) & 0x00ffffff) == 0x3e0008) diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h index 908422f2f320..92c68a22f16b 100644 --- a/drivers/net/tulip/tulip.h +++ b/drivers/net/tulip/tulip.h @@ -25,6 +25,7 @@ #include <linux/pci.h> #include <asm/io.h> #include <asm/irq.h> +#include <asm/unaligned.h> @@ -304,11 +305,7 @@ enum t21143_csr6_bits { #define RUN_AT(x) (jiffies + (x)) -#if defined(__i386__) /* AKA get_unaligned() */ -#define get_u16(ptr) (*(u16 *)(ptr)) -#else -#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8)) -#endif +#define get_u16(ptr) get_unaligned_le16((ptr)) struct medialeaf { u8 type; diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index fa1c1c329a2d..f9d13fa05d64 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -327,8 +327,8 @@ static void tulip_up(struct net_device *dev) tp->dirty_rx = tp->dirty_tx = 0; if (tp->flags & MC_HASH_ONLY) { - u32 addr_low = le32_to_cpu(get_unaligned((__le32 *)dev->dev_addr)); - u32 addr_high = le16_to_cpu(get_unaligned((__le16 *)(dev->dev_addr+4))); + u32 addr_low = get_unaligned_le32(dev->dev_addr); + u32 addr_high = get_unaligned_le16(dev->dev_addr + 4); if (tp->chip_id == AX88140) { iowrite32(0, ioaddr + CSR13); iowrite32(addr_low, ioaddr + CSR14); @@ -1437,13 +1437,13 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, do value = ioread32(ioaddr + CSR9); while (value < 0 && --boguscnt > 0); - put_unaligned(cpu_to_le16(value), ((__le16*)dev->dev_addr) + i); + put_unaligned_le16(value, ((__le16 *)dev->dev_addr) + i); sum += value & 0xffff; } } else if (chip_idx == COMET) { /* No need to read the EEPROM. */ - put_unaligned(cpu_to_le32(ioread32(ioaddr + 0xA4)), (__le32 *)dev->dev_addr); - put_unaligned(cpu_to_le16(ioread32(ioaddr + 0xA8)), (__le16 *)(dev->dev_addr + 4)); + put_unaligned_le32(ioread32(ioaddr + 0xA4), dev->dev_addr); + put_unaligned_le16(ioread32(ioaddr + 0xA8), dev->dev_addr + 4); for (i = 0; i < 6; i ++) sum += dev->dev_addr[i]; } else { diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c index 63abfd72542d..e03eef2f2282 100644 --- a/drivers/net/wan/pc300_tty.c +++ b/drivers/net/wan/pc300_tty.c @@ -178,6 +178,20 @@ static void cpc_tty_signal_on(pc300dev_t *pc300dev, unsigned char signal) CPC_TTY_UNLOCK(card,flags); } + +static const struct tty_operations pc300_ops = { + .open = cpc_tty_open, + .close = cpc_tty_close, + .write = cpc_tty_write, + .write_room = cpc_tty_write_room, + .chars_in_buffer = cpc_tty_chars_in_buffer, + .tiocmset = pc300_tiocmset, + .tiocmget = pc300_tiocmget, + .flush_buffer = cpc_tty_flush_buffer, + .hangup = cpc_tty_hangup, +}; + + /* * PC300 TTY initialization routine * @@ -225,15 +239,7 @@ void cpc_tty_init(pc300dev_t *pc300dev) serial_drv.flags = TTY_DRIVER_REAL_RAW; /* interface routines from the upper tty layer to the tty driver */ - serial_drv.open = cpc_tty_open; - serial_drv.close = cpc_tty_close; - serial_drv.write = cpc_tty_write; - serial_drv.write_room = cpc_tty_write_room; - serial_drv.chars_in_buffer = cpc_tty_chars_in_buffer; - serial_drv.tiocmset = pc300_tiocmset; - serial_drv.tiocmget = pc300_tiocmget; - serial_drv.flush_buffer = cpc_tty_flush_buffer; - serial_drv.hangup = cpc_tty_hangup; + tty_set_operations(&serial_drv, &pc300_ops); /* register the TTY driver */ if (tty_register_driver(&serial_drv)) { diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c index 0f8aca8a4d43..249e18053d5f 100644 --- a/drivers/net/wan/x25_asy.c +++ b/drivers/net/wan/x25_asy.c @@ -17,7 +17,7 @@ #include <linux/module.h> #include <asm/system.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #include <linux/bitops.h> #include <linux/string.h> #include <linux/mm.h> @@ -95,7 +95,7 @@ static struct x25_asy *x25_asy_alloc(void) x25_asy_devs[i] = dev; return sl; } else { - printk("x25_asy_alloc() - register_netdev() failure.\n"); + printk(KERN_WARNING "x25_asy_alloc() - register_netdev() failure.\n"); free_netdev(dev); } } @@ -112,23 +112,22 @@ static void x25_asy_free(struct x25_asy *sl) kfree(sl->xbuff); sl->xbuff = NULL; - if (!test_and_clear_bit(SLF_INUSE, &sl->flags)) { - printk("%s: x25_asy_free for already free unit.\n", sl->dev->name); - } + if (!test_and_clear_bit(SLF_INUSE, &sl->flags)) + printk(KERN_ERR "%s: x25_asy_free for already free unit.\n", + sl->dev->name); } static int x25_asy_change_mtu(struct net_device *dev, int newmtu) { struct x25_asy *sl = dev->priv; unsigned char *xbuff, *rbuff; - int len = 2* newmtu; + int len = 2 * newmtu; xbuff = kmalloc(len + 4, GFP_ATOMIC); rbuff = kmalloc(len + 4, GFP_ATOMIC); - if (xbuff == NULL || rbuff == NULL) - { - printk("%s: unable to grow X.25 buffers, MTU change cancelled.\n", + if (xbuff == NULL || rbuff == NULL) { + printk(KERN_WARNING "%s: unable to grow X.25 buffers, MTU change cancelled.\n", dev->name); kfree(xbuff); kfree(rbuff); @@ -193,25 +192,23 @@ static void x25_asy_bump(struct x25_asy *sl) int err; count = sl->rcount; - sl->stats.rx_bytes+=count; - + sl->stats.rx_bytes += count; + skb = dev_alloc_skb(count+1); - if (skb == NULL) - { - printk("%s: memory squeeze, dropping packet.\n", sl->dev->name); + if (skb == NULL) { + printk(KERN_WARNING "%s: memory squeeze, dropping packet.\n", + sl->dev->name); sl->stats.rx_dropped++; return; } - skb_push(skb,1); /* LAPB internal control */ - memcpy(skb_put(skb,count), sl->rbuff, count); + skb_push(skb, 1); /* LAPB internal control */ + memcpy(skb_put(skb, count), sl->rbuff, count); skb->protocol = x25_type_trans(skb, sl->dev); - if((err=lapb_data_received(skb->dev, skb))!=LAPB_OK) - { + err = lapb_data_received(skb->dev, skb); + if (err != LAPB_OK) { kfree_skb(skb); - printk(KERN_DEBUG "x25_asy: data received err - %d\n",err); - } - else - { + printk(KERN_DEBUG "x25_asy: data received err - %d\n", err); + } else { netif_rx(skb); sl->dev->last_rx = jiffies; sl->stats.rx_packets++; @@ -224,10 +221,11 @@ static void x25_asy_encaps(struct x25_asy *sl, unsigned char *icp, int len) unsigned char *p; int actual, count, mtu = sl->dev->mtu; - if (len > mtu) - { /* Sigh, shouldn't occur BUT ... */ + if (len > mtu) { + /* Sigh, shouldn't occur BUT ... */ len = mtu; - printk ("%s: truncating oversized transmit packet!\n", sl->dev->name); + printk(KERN_DEBUG "%s: truncating oversized transmit packet!\n", + sl->dev->name); sl->stats.tx_dropped++; x25_asy_unlock(sl); return; @@ -245,7 +243,7 @@ static void x25_asy_encaps(struct x25_asy *sl, unsigned char *icp, int len) * 14 Oct 1994 Dmitry Gorodchanin. */ sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); - actual = sl->tty->driver->write(sl->tty, sl->xbuff, count); + actual = sl->tty->ops->write(sl->tty, sl->xbuff, count); sl->xleft = count - actual; sl->xhead = sl->xbuff + actual; /* VSV */ @@ -265,8 +263,7 @@ static void x25_asy_write_wakeup(struct tty_struct *tty) if (!sl || sl->magic != X25_ASY_MAGIC || !netif_running(sl->dev)) return; - if (sl->xleft <= 0) - { + if (sl->xleft <= 0) { /* Now serial buffer is almost free & we can start * transmission of another packet */ sl->stats.tx_packets++; @@ -275,14 +272,14 @@ static void x25_asy_write_wakeup(struct tty_struct *tty) return; } - actual = tty->driver->write(tty, sl->xhead, sl->xleft); + actual = tty->ops->write(tty, sl->xhead, sl->xleft); sl->xleft -= actual; sl->xhead += actual; } static void x25_asy_timeout(struct net_device *dev) { - struct x25_asy *sl = (struct x25_asy*)(dev->priv); + struct x25_asy *sl = dev->priv; spin_lock(&sl->lock); if (netif_queue_stopped(dev)) { @@ -290,7 +287,7 @@ static void x25_asy_timeout(struct net_device *dev) * 14 Oct 1994 Dmitry Gorodchanin. */ printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, - (sl->tty->driver->chars_in_buffer(sl->tty) || sl->xleft) ? + (tty_chars_in_buffer(sl->tty) || sl->xleft) ? "bad line quality" : "driver error"); sl->xleft = 0; sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); @@ -303,31 +300,34 @@ static void x25_asy_timeout(struct net_device *dev) static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev) { - struct x25_asy *sl = (struct x25_asy*)(dev->priv); + struct x25_asy *sl = dev->priv; int err; if (!netif_running(sl->dev)) { - printk("%s: xmit call when iface is down\n", dev->name); + printk(KERN_ERR "%s: xmit call when iface is down\n", + dev->name); kfree_skb(skb); return 0; } - - switch(skb->data[0]) - { - case 0x00:break; - case 0x01: /* Connection request .. do nothing */ - if((err=lapb_connect_request(dev))!=LAPB_OK) - printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err); - kfree_skb(skb); - return 0; - case 0x02: /* Disconnect request .. do nothing - hang up ?? */ - if((err=lapb_disconnect_request(dev))!=LAPB_OK) - printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err); - default: - kfree_skb(skb); - return 0; + + switch (skb->data[0]) { + case 0x00: + break; + case 0x01: /* Connection request .. do nothing */ + err = lapb_connect_request(dev); + if (err != LAPB_OK) + printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err); + kfree_skb(skb); + return 0; + case 0x02: /* Disconnect request .. do nothing - hang up ?? */ + err = lapb_disconnect_request(dev); + if (err != LAPB_OK) + printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err); + default: + kfree_skb(skb); + return 0; } - skb_pull(skb,1); /* Remove control byte */ + skb_pull(skb, 1); /* Remove control byte */ /* * If we are busy already- too bad. We ought to be able * to queue things at this point, to allow for a little @@ -338,10 +338,10 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev) * So, no queues ! * 14 Oct 1994 Dmitry Gorodchanin. */ - - if((err=lapb_data_request(dev,skb))!=LAPB_OK) - { - printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err); + + err = lapb_data_request(dev, skb); + if (err != LAPB_OK) { + printk(KERN_ERR "x25_asy: lapb_data_request error - %d\n", err); kfree_skb(skb); return 0; } @@ -357,7 +357,7 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev) * Called when I frame data arrives. We did the work above - throw it * at the net layer. */ - + static int x25_asy_data_indication(struct net_device *dev, struct sk_buff *skb) { skb->dev->last_rx = jiffies; @@ -369,24 +369,22 @@ static int x25_asy_data_indication(struct net_device *dev, struct sk_buff *skb) * busy cases too well. Its tricky to see how to do this nicely - * perhaps lapb should allow us to bounce this ? */ - + static void x25_asy_data_transmit(struct net_device *dev, struct sk_buff *skb) { - struct x25_asy *sl=dev->priv; - + struct x25_asy *sl = dev->priv; + spin_lock(&sl->lock); - if (netif_queue_stopped(sl->dev) || sl->tty == NULL) - { + if (netif_queue_stopped(sl->dev) || sl->tty == NULL) { spin_unlock(&sl->lock); printk(KERN_ERR "x25_asy: tbusy drop\n"); kfree_skb(skb); return; } /* We were not busy, so we are now... :-) */ - if (skb != NULL) - { + if (skb != NULL) { x25_asy_lock(sl); - sl->stats.tx_bytes+=skb->len; + sl->stats.tx_bytes += skb->len; x25_asy_encaps(sl, skb->data, skb->len); dev_kfree_skb(skb); } @@ -396,15 +394,16 @@ static void x25_asy_data_transmit(struct net_device *dev, struct sk_buff *skb) /* * LAPB connection establish/down information. */ - + static void x25_asy_connected(struct net_device *dev, int reason) { struct x25_asy *sl = dev->priv; struct sk_buff *skb; unsigned char *ptr; - if ((skb = dev_alloc_skb(1)) == NULL) { - printk(KERN_ERR "lapbeth: out of memory\n"); + skb = dev_alloc_skb(1); + if (skb == NULL) { + printk(KERN_ERR "x25_asy: out of memory\n"); return; } @@ -422,7 +421,8 @@ static void x25_asy_disconnected(struct net_device *dev, int reason) struct sk_buff *skb; unsigned char *ptr; - if ((skb = dev_alloc_skb(1)) == NULL) { + skb = dev_alloc_skb(1); + if (skb == NULL) { printk(KERN_ERR "x25_asy: out of memory\n"); return; } @@ -449,7 +449,7 @@ static struct lapb_register_struct x25_asy_callbacks = { /* Open the low-level part of the X.25 channel. Easy! */ static int x25_asy_open(struct net_device *dev) { - struct x25_asy *sl = (struct x25_asy*)(dev->priv); + struct x25_asy *sl = dev->priv; unsigned long len; int err; @@ -466,13 +466,11 @@ static int x25_asy_open(struct net_device *dev) len = dev->mtu * 2; sl->rbuff = kmalloc(len + 4, GFP_KERNEL); - if (sl->rbuff == NULL) { + if (sl->rbuff == NULL) goto norbuff; - } sl->xbuff = kmalloc(len + 4, GFP_KERNEL); - if (sl->xbuff == NULL) { + if (sl->xbuff == NULL) goto noxbuff; - } sl->buffsize = len; sl->rcount = 0; @@ -480,11 +478,12 @@ static int x25_asy_open(struct net_device *dev) sl->flags &= (1 << SLF_INUSE); /* Clear ESCAPE & ERROR flags */ netif_start_queue(dev); - + /* * Now attach LAPB */ - if((err=lapb_register(dev, &x25_asy_callbacks))==LAPB_OK) + err = lapb_register(dev, &x25_asy_callbacks); + if (err == LAPB_OK) return 0; /* Cleanup */ @@ -499,18 +498,20 @@ norbuff: /* Close the low-level part of the X.25 channel. Easy! */ static int x25_asy_close(struct net_device *dev) { - struct x25_asy *sl = (struct x25_asy*)(dev->priv); + struct x25_asy *sl = dev->priv; int err; spin_lock(&sl->lock); - if (sl->tty) + if (sl->tty) sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); netif_stop_queue(dev); sl->rcount = 0; sl->xleft = 0; - if((err=lapb_unregister(dev))!=LAPB_OK) - printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n",err); + err = lapb_unregister(dev); + if (err != LAPB_OK) + printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n", + err); spin_unlock(&sl->lock); return 0; } @@ -521,8 +522,9 @@ static int x25_asy_close(struct net_device *dev) * a block of X.25 data has been received, which can now be decapsulated * and sent on to some IP layer for further processing. */ - -static void x25_asy_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) + +static void x25_asy_receive_buf(struct tty_struct *tty, + const unsigned char *cp, char *fp, int count) { struct x25_asy *sl = (struct x25_asy *) tty->disc_data; @@ -533,9 +535,8 @@ static void x25_asy_receive_buf(struct tty_struct *tty, const unsigned char *cp, /* Read the characters out of the buffer */ while (count--) { if (fp && *fp++) { - if (!test_and_set_bit(SLF_ERROR, &sl->flags)) { + if (!test_and_set_bit(SLF_ERROR, &sl->flags)) sl->stats.rx_errors++; - } cp++; continue; } @@ -556,31 +557,31 @@ static int x25_asy_open_tty(struct tty_struct *tty) struct x25_asy *sl = (struct x25_asy *) tty->disc_data; int err; + if (tty->ops->write == NULL) + return -EOPNOTSUPP; + /* First make sure we're not already connected. */ - if (sl && sl->magic == X25_ASY_MAGIC) { + if (sl && sl->magic == X25_ASY_MAGIC) return -EEXIST; - } /* OK. Find a free X.25 channel to use. */ - if ((sl = x25_asy_alloc()) == NULL) { + sl = x25_asy_alloc(); + if (sl == NULL) return -ENFILE; - } sl->tty = tty; tty->disc_data = sl; tty->receive_room = 65536; - if (tty->driver->flush_buffer) { - tty->driver->flush_buffer(tty); - } + tty_driver_flush_buffer(tty); tty_ldisc_flush(tty); /* Restore default settings */ sl->dev->type = ARPHRD_X25; - + /* Perform the low-level X.25 async init */ - if ((err = x25_asy_open(sl->dev))) + err = x25_asy_open(sl->dev); + if (err) return err; - /* Done. We have linked the TTY line to a channel. */ return sl->dev->base_addr; } @@ -601,9 +602,7 @@ static void x25_asy_close_tty(struct tty_struct *tty) return; if (sl->dev->flags & IFF_UP) - { - (void) dev_close(sl->dev); - } + dev_close(sl->dev); tty->disc_data = NULL; sl->tty = NULL; @@ -613,8 +612,7 @@ static void x25_asy_close_tty(struct tty_struct *tty) static struct net_device_stats *x25_asy_get_stats(struct net_device *dev) { - struct x25_asy *sl = (struct x25_asy*)(dev->priv); - + struct x25_asy *sl = dev->priv; return &sl->stats; } @@ -641,21 +639,19 @@ int x25_asy_esc(unsigned char *s, unsigned char *d, int len) * character sequence, according to the X.25 protocol. */ - while (len-- > 0) - { - switch(c = *s++) - { - case X25_END: - *ptr++ = X25_ESC; - *ptr++ = X25_ESCAPE(X25_END); - break; - case X25_ESC: - *ptr++ = X25_ESC; - *ptr++ = X25_ESCAPE(X25_ESC); - break; - default: - *ptr++ = c; - break; + while (len-- > 0) { + switch (c = *s++) { + case X25_END: + *ptr++ = X25_ESC; + *ptr++ = X25_ESCAPE(X25_END); + break; + case X25_ESC: + *ptr++ = X25_ESC; + *ptr++ = X25_ESCAPE(X25_ESC); + break; + default: + *ptr++ = c; + break; } } *ptr++ = X25_END; @@ -665,31 +661,25 @@ int x25_asy_esc(unsigned char *s, unsigned char *d, int len) static void x25_asy_unesc(struct x25_asy *sl, unsigned char s) { - switch(s) - { - case X25_END: - if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2)) - { - x25_asy_bump(sl); - } - clear_bit(SLF_ESCAPE, &sl->flags); - sl->rcount = 0; - return; - - case X25_ESC: - set_bit(SLF_ESCAPE, &sl->flags); - return; - - case X25_ESCAPE(X25_ESC): - case X25_ESCAPE(X25_END): - if (test_and_clear_bit(SLF_ESCAPE, &sl->flags)) - s = X25_UNESCAPE(s); - break; - } - if (!test_bit(SLF_ERROR, &sl->flags)) - { - if (sl->rcount < sl->buffsize) - { + switch (s) { + case X25_END: + if (!test_and_clear_bit(SLF_ERROR, &sl->flags) + && sl->rcount > 2) + x25_asy_bump(sl); + clear_bit(SLF_ESCAPE, &sl->flags); + sl->rcount = 0; + return; + case X25_ESC: + set_bit(SLF_ESCAPE, &sl->flags); + return; + case X25_ESCAPE(X25_ESC): + case X25_ESCAPE(X25_END): + if (test_and_clear_bit(SLF_ESCAPE, &sl->flags)) + s = X25_UNESCAPE(s); + break; + } + if (!test_bit(SLF_ERROR, &sl->flags)) { + if (sl->rcount < sl->buffsize) { sl->rbuff[sl->rcount++] = s; return; } @@ -709,7 +699,7 @@ static int x25_asy_ioctl(struct tty_struct *tty, struct file *file, if (!sl || sl->magic != X25_ASY_MAGIC) return -EINVAL; - switch(cmd) { + switch (cmd) { case SIOCGIFNAME: if (copy_to_user((void __user *)arg, sl->dev->name, strlen(sl->dev->name) + 1)) @@ -724,8 +714,8 @@ static int x25_asy_ioctl(struct tty_struct *tty, struct file *file, static int x25_asy_open_dev(struct net_device *dev) { - struct x25_asy *sl = (struct x25_asy*)(dev->priv); - if(sl->tty==NULL) + struct x25_asy *sl = dev->priv; + if (sl->tty == NULL) return -ENODEV; return 0; } @@ -741,9 +731,9 @@ static void x25_asy_setup(struct net_device *dev) set_bit(SLF_INUSE, &sl->flags); /* - * Finish setting up the DEVICE info. + * Finish setting up the DEVICE info. */ - + dev->mtu = SL_MTU; dev->hard_start_xmit = x25_asy_xmit; dev->tx_timeout = x25_asy_timeout; @@ -778,9 +768,10 @@ static int __init init_x25_asy(void) x25_asy_maxdev = 4; /* Sanity */ printk(KERN_INFO "X.25 async: version 0.00 ALPHA " - "(dynamic channels, max=%d).\n", x25_asy_maxdev ); + "(dynamic channels, max=%d).\n", x25_asy_maxdev); - x25_asy_devs = kcalloc(x25_asy_maxdev, sizeof(struct net_device*), GFP_KERNEL); + x25_asy_devs = kcalloc(x25_asy_maxdev, sizeof(struct net_device *), + GFP_KERNEL); if (!x25_asy_devs) { printk(KERN_WARNING "X25 async: Can't allocate x25_asy_ctrls[] " "array! Uaargh! (-> No X.25 available)\n"); @@ -802,7 +793,7 @@ static void __exit exit_x25_asy(void) struct x25_asy *sl = dev->priv; spin_lock_bh(&sl->lock); - if (sl->tty) + if (sl->tty) tty_hangup(sl->tty); spin_unlock_bh(&sl->lock); diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 932d6b1c9d0b..45f47c1c0a35 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -3657,7 +3657,7 @@ void mpi_receive_802_11 (struct airo_info *ai) ptr += hdrlen; if (hdrlen == 24) ptr += 6; - gap = le16_to_cpu(get_unaligned((__le16 *)ptr)); + gap = get_unaligned_le16(ptr); ptr += sizeof(__le16); if (gap) { if (gap <= 8) @@ -4347,24 +4347,28 @@ static int proc_config_open( struct inode *inode, struct file *file ); static int proc_wepkey_open( struct inode *inode, struct file *file ); static const struct file_operations proc_statsdelta_ops = { + .owner = THIS_MODULE, .read = proc_read, .open = proc_statsdelta_open, .release = proc_close }; static const struct file_operations proc_stats_ops = { + .owner = THIS_MODULE, .read = proc_read, .open = proc_stats_open, .release = proc_close }; static const struct file_operations proc_status_ops = { + .owner = THIS_MODULE, .read = proc_read, .open = proc_status_open, .release = proc_close }; static const struct file_operations proc_SSID_ops = { + .owner = THIS_MODULE, .read = proc_read, .write = proc_write, .open = proc_SSID_open, @@ -4372,6 +4376,7 @@ static const struct file_operations proc_SSID_ops = { }; static const struct file_operations proc_BSSList_ops = { + .owner = THIS_MODULE, .read = proc_read, .write = proc_write, .open = proc_BSSList_open, @@ -4379,6 +4384,7 @@ static const struct file_operations proc_BSSList_ops = { }; static const struct file_operations proc_APList_ops = { + .owner = THIS_MODULE, .read = proc_read, .write = proc_write, .open = proc_APList_open, @@ -4386,6 +4392,7 @@ static const struct file_operations proc_APList_ops = { }; static const struct file_operations proc_config_ops = { + .owner = THIS_MODULE, .read = proc_read, .write = proc_write, .open = proc_config_open, @@ -4393,6 +4400,7 @@ static const struct file_operations proc_config_ops = { }; static const struct file_operations proc_wepkey_ops = { + .owner = THIS_MODULE, .read = proc_read, .write = proc_write, .open = proc_wepkey_open, @@ -4411,10 +4419,6 @@ struct proc_data { void (*on_close) (struct inode *, struct file *); }; -#ifndef SETPROC_OPS -#define SETPROC_OPS(entry, ops) (entry)->proc_fops = &(ops) -#endif - static int setup_proc_entry( struct net_device *dev, struct airo_info *apriv ) { struct proc_dir_entry *entry; @@ -4430,100 +4434,76 @@ static int setup_proc_entry( struct net_device *dev, apriv->proc_entry->owner = THIS_MODULE; /* Setup the StatsDelta */ - entry = create_proc_entry("StatsDelta", - S_IFREG | (S_IRUGO&proc_perm), - apriv->proc_entry); + entry = proc_create_data("StatsDelta", + S_IFREG | (S_IRUGO&proc_perm), + apriv->proc_entry, &proc_statsdelta_ops, dev); if (!entry) goto fail_stats_delta; entry->uid = proc_uid; entry->gid = proc_gid; - entry->data = dev; - entry->owner = THIS_MODULE; - SETPROC_OPS(entry, proc_statsdelta_ops); /* Setup the Stats */ - entry = create_proc_entry("Stats", - S_IFREG | (S_IRUGO&proc_perm), - apriv->proc_entry); + entry = proc_create_data("Stats", + S_IFREG | (S_IRUGO&proc_perm), + apriv->proc_entry, &proc_stats_ops, dev); if (!entry) goto fail_stats; entry->uid = proc_uid; entry->gid = proc_gid; - entry->data = dev; - entry->owner = THIS_MODULE; - SETPROC_OPS(entry, proc_stats_ops); /* Setup the Status */ - entry = create_proc_entry("Status", - S_IFREG | (S_IRUGO&proc_perm), - apriv->proc_entry); + entry = proc_create_data("Status", + S_IFREG | (S_IRUGO&proc_perm), + apriv->proc_entry, &proc_status_ops, dev); if (!entry) goto fail_status; entry->uid = proc_uid; entry->gid = proc_gid; - entry->data = dev; - entry->owner = THIS_MODULE; - SETPROC_OPS(entry, proc_status_ops); /* Setup the Config */ - entry = create_proc_entry("Config", - S_IFREG | proc_perm, - apriv->proc_entry); + entry = proc_create_data("Config", + S_IFREG | proc_perm, + apriv->proc_entry, &proc_config_ops, dev); if (!entry) goto fail_config; entry->uid = proc_uid; entry->gid = proc_gid; - entry->data = dev; - entry->owner = THIS_MODULE; - SETPROC_OPS(entry, proc_config_ops); /* Setup the SSID */ - entry = create_proc_entry("SSID", - S_IFREG | proc_perm, - apriv->proc_entry); + entry = proc_create_data("SSID", + S_IFREG | proc_perm, + apriv->proc_entry, &proc_SSID_ops, dev); if (!entry) goto fail_ssid; entry->uid = proc_uid; entry->gid = proc_gid; - entry->data = dev; - entry->owner = THIS_MODULE; - SETPROC_OPS(entry, proc_SSID_ops); /* Setup the APList */ - entry = create_proc_entry("APList", - S_IFREG | proc_perm, - apriv->proc_entry); + entry = proc_create_data("APList", + S_IFREG | proc_perm, + apriv->proc_entry, &proc_APList_ops, dev); if (!entry) goto fail_aplist; entry->uid = proc_uid; entry->gid = proc_gid; - entry->data = dev; - entry->owner = THIS_MODULE; - SETPROC_OPS(entry, proc_APList_ops); /* Setup the BSSList */ - entry = create_proc_entry("BSSList", - S_IFREG | proc_perm, - apriv->proc_entry); + entry = proc_create_data("BSSList", + S_IFREG | proc_perm, + apriv->proc_entry, &proc_BSSList_ops, dev); if (!entry) goto fail_bsslist; entry->uid = proc_uid; entry->gid = proc_gid; - entry->data = dev; - entry->owner = THIS_MODULE; - SETPROC_OPS(entry, proc_BSSList_ops); /* Setup the WepKey */ - entry = create_proc_entry("WepKey", - S_IFREG | proc_perm, - apriv->proc_entry); + entry = proc_create_data("WepKey", + S_IFREG | proc_perm, + apriv->proc_entry, &proc_wepkey_ops, dev); if (!entry) goto fail_wepkey; entry->uid = proc_uid; entry->gid = proc_gid; - entry->data = dev; - entry->owner = THIS_MODULE; - SETPROC_OPS(entry, proc_wepkey_ops); return 0; @@ -5625,9 +5605,9 @@ static int __init airo_init_module( void ) int have_isa_dev = 0; #endif - airo_entry = create_proc_entry("aironet", + airo_entry = create_proc_entry("driver/aironet", S_IFDIR | airo_perm, - proc_root_driver); + NULL); if (airo_entry) { airo_entry->uid = proc_uid; @@ -5651,7 +5631,7 @@ static int __init airo_init_module( void ) airo_print_info("", "Finished probing for PCI adapters"); if (i) { - remove_proc_entry("aironet", proc_root_driver); + remove_proc_entry("driver/aironet", NULL); return i; } #endif @@ -5673,7 +5653,7 @@ static void __exit airo_cleanup_module( void ) #ifdef CONFIG_PCI pci_unregister_driver(&airo_driver); #endif - remove_proc_entry("aironet", proc_root_driver); + remove_proc_entry("driver/aironet", NULL); } /* diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index e18305b781c9..4e5c8fc35200 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -58,10 +58,6 @@ #include "reg.h" #include "debug.h" -/* unaligned little endian access */ -#define LE_READ_2(_p) (le16_to_cpu(get_unaligned((__le16 *)(_p)))) -#define LE_READ_4(_p) (le32_to_cpu(get_unaligned((__le32 *)(_p)))) - enum { ATH_LED_TX, ATH_LED_RX, @@ -2909,9 +2905,9 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, if (!mclist) break; /* calculate XOR of eight 6-bit values */ - val = LE_READ_4(mclist->dmi_addr + 0); + val = get_unaligned_le32(mclist->dmi_addr + 0); pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; - val = LE_READ_4(mclist->dmi_addr + 3); + val = get_unaligned_le32(mclist->dmi_addr + 3); pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val; pos &= 0x3f; mfilt[pos / 32] |= (1 << (pos % 32)); diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 4bf8a99099fe..8c24cd72aaca 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2171,7 +2171,7 @@ static int b43_write_initvals(struct b43_wldev *dev, goto err_format; array_size -= sizeof(iv->data.d32); - value = be32_to_cpu(get_unaligned(&iv->data.d32)); + value = get_unaligned_be32(&iv->data.d32); b43_write32(dev, offset, value); iv = (const struct b43_iv *)((const uint8_t *)iv + diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index ef829ee8ffd4..14a5eea2573e 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -1720,7 +1720,7 @@ static int b43legacy_write_initvals(struct b43legacy_wldev *dev, goto err_format; array_size -= sizeof(iv->data.d32); - value = be32_to_cpu(get_unaligned(&iv->data.d32)); + value = get_unaligned_be32(&iv->data.d32); b43legacy_write32(dev, offset, value); iv = (const struct b43legacy_iv *)((const uint8_t *)iv + diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 598e4eef4f40..d3406830c8e3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -554,40 +554,36 @@ static void iwl3945_add_radiotap(struct iwl3945_priv *priv, iwl3945_rt->rt_hdr.it_pad = 0; /* total header + data */ - put_unaligned(cpu_to_le16(sizeof(*iwl3945_rt)), - &iwl3945_rt->rt_hdr.it_len); + put_unaligned_le16(sizeof(*iwl3945_rt), &iwl3945_rt->rt_hdr.it_len); /* Indicate all the fields we add to the radiotap header */ - put_unaligned(cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | - (1 << IEEE80211_RADIOTAP_FLAGS) | - (1 << IEEE80211_RADIOTAP_RATE) | - (1 << IEEE80211_RADIOTAP_CHANNEL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | - (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | - (1 << IEEE80211_RADIOTAP_ANTENNA)), - &iwl3945_rt->rt_hdr.it_present); + put_unaligned_le32((1 << IEEE80211_RADIOTAP_TSFT) | + (1 << IEEE80211_RADIOTAP_FLAGS) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_CHANNEL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | + (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | + (1 << IEEE80211_RADIOTAP_ANTENNA), + &iwl3945_rt->rt_hdr.it_present); /* Zero the flags, we'll add to them as we go */ iwl3945_rt->rt_flags = 0; - put_unaligned(cpu_to_le64(tsf), &iwl3945_rt->rt_tsf); + put_unaligned_le64(tsf, &iwl3945_rt->rt_tsf); iwl3945_rt->rt_dbmsignal = signal; iwl3945_rt->rt_dbmnoise = noise; /* Convert the channel frequency and set the flags */ - put_unaligned(cpu_to_le16(stats->freq), &iwl3945_rt->rt_channelMHz); + put_unaligned_le16(stats->freq, &iwl3945_rt->rt_channelMHz); if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) - put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | - IEEE80211_CHAN_5GHZ), + put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ, &iwl3945_rt->rt_chbitmask); else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) - put_unaligned(cpu_to_le16(IEEE80211_CHAN_CCK | - IEEE80211_CHAN_2GHZ), + put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ, &iwl3945_rt->rt_chbitmask); else /* 802.11g */ - put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | - IEEE80211_CHAN_2GHZ), + put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ, &iwl3945_rt->rt_chbitmask); if (rate == -1) diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index e72c97a0d6c1..1a409fcc80d3 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -522,7 +522,7 @@ static int lbs_process_bss(struct bss_descriptor *bss, if (*bytesleft >= sizeof(beaconsize)) { /* Extract & convert beacon size from the command buffer */ - beaconsize = le16_to_cpu(get_unaligned((__le16 *)*pbeaconinfo)); + beaconsize = get_unaligned_le16(*pbeaconinfo); *bytesleft -= sizeof(beaconsize); *pbeaconinfo += sizeof(beaconsize); } diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index bced3fe1cf8a..5dd23c93497d 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -768,41 +768,17 @@ static __u8 *UnStuffData(__u8 * src, __u8 * end, __u8 * dst, /* General routines for STRIP */ /* - * get_baud returns the current baud rate, as one of the constants defined in - * termbits.h - * If the user has issued a baud rate override using the 'setserial' command - * and the logical current rate is set to 38.4, then the true baud rate - * currently in effect (57.6 or 115.2) is returned. - */ -static unsigned int get_baud(struct tty_struct *tty) -{ - if (!tty || !tty->termios) - return (0); - if ((tty->termios->c_cflag & CBAUD) == B38400 && tty->driver_data) { - struct async_struct *info = - (struct async_struct *) tty->driver_data; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - return (B57600); - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - return (B115200); - } - return (tty->termios->c_cflag & CBAUD); -} - -/* * set_baud sets the baud rate to the rate defined by baudcode - * Note: The rate B38400 should be avoided, because the user may have - * issued a 'setserial' speed override to map that to a different speed. - * We could achieve a true rate of 38400 if we needed to by cancelling - * any user speed override that is in place, but that might annoy the - * user, so it is simplest to just avoid using 38400. */ -static void set_baud(struct tty_struct *tty, unsigned int baudcode) +static void set_baud(struct tty_struct *tty, speed_t baudrate) { - struct ktermios old_termios = *(tty->termios); - tty->termios->c_cflag &= ~CBAUD; /* Clear the old baud setting */ - tty->termios->c_cflag |= baudcode; /* Set the new baud setting */ - tty->driver->set_termios(tty, &old_termios); + struct ktermios old_termios; + + mutex_lock(&tty->termios_mutex); + old_termios =*(tty->termios); + tty_encode_baud_rate(tty, baudrate, baudrate); + tty->ops->set_termios(tty, &old_termios); + mutex_unlock(&tty->termios_mutex); } /* @@ -1217,7 +1193,7 @@ static void ResetRadio(struct strip *strip_info) strip_info->watchdog_doreset = jiffies + 1 * HZ; /* If the user has selected a baud rate above 38.4 see what magic we have to do */ - if (strip_info->user_baud > B38400) { + if (strip_info->user_baud > 38400) { /* * Subtle stuff: Pay attention :-) * If the serial port is currently at the user's selected (>38.4) rate, @@ -1227,17 +1203,17 @@ static void ResetRadio(struct strip *strip_info) * issued the ATS304 command last time through, so this time we restore * the user's selected rate and issue the normal starmode reset string. */ - if (strip_info->user_baud == get_baud(tty)) { + if (strip_info->user_baud == tty_get_baud_rate(tty)) { static const char b0[] = "ate0q1s304=57600\r"; static const char b1[] = "ate0q1s304=115200\r"; static const StringDescriptor baudstring[2] = { {b0, sizeof(b0) - 1} , {b1, sizeof(b1) - 1} }; - set_baud(tty, B19200); - if (strip_info->user_baud == B57600) + set_baud(tty, 19200); + if (strip_info->user_baud == 57600) s = baudstring[0]; - else if (strip_info->user_baud == B115200) + else if (strip_info->user_baud == 115200) s = baudstring[1]; else s = baudstring[1]; /* For now */ @@ -1245,7 +1221,7 @@ static void ResetRadio(struct strip *strip_info) set_baud(tty, strip_info->user_baud); } - tty->driver->write(tty, s.string, s.length); + tty->ops->write(tty, s.string, s.length); #ifdef EXT_COUNTERS strip_info->tx_ebytes += s.length; #endif @@ -1267,7 +1243,7 @@ static void strip_write_some_more(struct tty_struct *tty) if (strip_info->tx_left > 0) { int num_written = - tty->driver->write(tty, strip_info->tx_head, + tty->ops->write(tty, strip_info->tx_head, strip_info->tx_left); strip_info->tx_left -= num_written; strip_info->tx_head += num_written; @@ -2457,7 +2433,7 @@ static int strip_open_low(struct net_device *dev) strip_info->working = FALSE; strip_info->firmware_level = NoStructure; strip_info->next_command = CompatibilityCommand; - strip_info->user_baud = get_baud(strip_info->tty); + strip_info->user_baud = tty_get_baud_rate(strip_info->tty); printk(KERN_INFO "%s: Initializing Radio.\n", strip_info->dev->name); @@ -2632,6 +2608,13 @@ static int strip_open(struct tty_struct *tty) return -EEXIST; /* + * We need a write method. + */ + + if (tty->ops->write == NULL) + return -EOPNOTSUPP; + + /* * OK. Find a free STRIP channel to use. */ if ((strip_info = strip_alloc()) == NULL) @@ -2652,8 +2635,7 @@ static int strip_open(struct tty_struct *tty) tty->disc_data = strip_info; tty->receive_room = 65536; - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + tty_driver_flush_buffer(tty); /* * Restore default settings diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index e34675c2f8fc..5316074f39f0 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -545,11 +545,11 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer, * be padded. Unaligned access might also happen if the length_info * structure is not present. */ - if (get_unaligned(&length_info->tag) == cpu_to_le16(RX_LENGTH_INFO_TAG)) + if (get_unaligned_le16(&length_info->tag) == RX_LENGTH_INFO_TAG) { unsigned int l, k, n; for (i = 0, l = 0;; i++) { - k = le16_to_cpu(get_unaligned(&length_info->length[i])); + k = get_unaligned_le16(&length_info->length[i]); if (k == 0) return; n = l+k; diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 24640726f8bb..57e1f495b9fc 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -1062,7 +1062,7 @@ static int yellowfin_rx(struct net_device *dev) buf_addr = rx_skb->data; data_size = (le32_to_cpu(desc->dbdma_cmd) - le32_to_cpu(desc->result_status)) & 0xffff; - frame_status = le16_to_cpu(get_unaligned((__le16*)&(buf_addr[data_size - 2]))); + frame_status = get_unaligned_le16(&(buf_addr[data_size - 2])); if (yellowfin_debug > 4) printk(KERN_DEBUG " yellowfin_rx() status was %4.4x.\n", frame_status); diff --git a/drivers/nubus/proc.c b/drivers/nubus/proc.c index e07492be1f4a..208dd12825bc 100644 --- a/drivers/nubus/proc.c +++ b/drivers/nubus/proc.c @@ -21,6 +21,7 @@ #include <linux/kernel.h> #include <linux/nubus.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <linux/init.h> #include <linux/module.h> @@ -28,38 +29,36 @@ #include <asm/byteorder.h> static int -get_nubus_dev_info(char *buf, char **start, off_t pos, int count) +nubus_devices_proc_show(struct seq_file *m, void *v) { struct nubus_dev *dev = nubus_devices; - off_t at = 0; - int len, cnt; - cnt = 0; - while (dev && count > cnt) { - len = sprintf(buf, "%x\t%04x %04x %04x %04x", + while (dev) { + seq_printf(m, "%x\t%04x %04x %04x %04x", dev->board->slot, dev->category, dev->type, dev->dr_sw, dev->dr_hw); - len += sprintf(buf+len, - "\t%08lx", - dev->board->slot_addr); - buf[len++] = '\n'; - at += len; - if (at >= pos) { - if (!*start) { - *start = buf + (pos - (at - len)); - cnt = at - pos; - } else - cnt += len; - buf += len; - } + seq_printf(m, "\t%08lx\n", dev->board->slot_addr); dev = dev->next; } - return (count > cnt) ? cnt : count; + return 0; +} + +static int nubus_devices_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, nubus_devices_proc_show, NULL); } +static const struct file_operations nubus_devices_proc_fops = { + .owner = THIS_MODULE, + .open = nubus_devices_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static struct proc_dir_entry *proc_bus_nubus_dir; static void nubus_proc_subdir(struct nubus_dev* dev, @@ -171,8 +170,7 @@ void __init nubus_proc_init(void) { if (!MACH_IS_MAC) return; - proc_bus_nubus_dir = proc_mkdir("nubus", proc_bus); - create_proc_info_entry("devices", 0, proc_bus_nubus_dir, - get_nubus_dev_info); + proc_bus_nubus_dir = proc_mkdir("bus/nubus", NULL); + proc_create("devices", 0, proc_bus_nubus_dir, &nubus_devices_proc_fops); proc_bus_nubus_add_devices(); } diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index 62db3c3fe4dc..07d2a8d4498f 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -1551,8 +1551,7 @@ static int __init ccio_probe(struct parisc_device *dev) { int i; struct ioc *ioc, **ioc_p = &ioc_list; - struct proc_dir_entry *info_entry, *bitmap_entry; - + ioc = kzalloc(sizeof(struct ioc), GFP_KERNEL); if (ioc == NULL) { printk(KERN_ERR MODULE_NAME ": memory allocation failure\n"); @@ -1580,13 +1579,10 @@ static int __init ccio_probe(struct parisc_device *dev) HBA_DATA(dev->dev.platform_data)->iommu = ioc; if (ioc_count == 0) { - info_entry = create_proc_entry(MODULE_NAME, 0, proc_runway_root); - if (info_entry) - info_entry->proc_fops = &ccio_proc_info_fops; - - bitmap_entry = create_proc_entry(MODULE_NAME"-bitmap", 0, proc_runway_root); - if (bitmap_entry) - bitmap_entry->proc_fops = &ccio_proc_bitmap_fops; + proc_create(MODULE_NAME, 0, proc_runway_root, + &ccio_proc_info_fops); + proc_create(MODULE_NAME"-bitmap", 0, proc_runway_root, + &ccio_proc_bitmap_fops); } ioc_count++; diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 8c4d2c13d5f2..afc849bd3f58 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -1895,7 +1895,9 @@ sba_driver_callback(struct parisc_device *dev) int i; char *version; void __iomem *sba_addr = ioremap_nocache(dev->hpa.start, SBA_FUNC_SIZE); - struct proc_dir_entry *info_entry, *bitmap_entry, *root; +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *root; +#endif sba_dump_ranges(sba_addr); @@ -1973,14 +1975,8 @@ sba_driver_callback(struct parisc_device *dev) break; } - info_entry = create_proc_entry("sba_iommu", 0, root); - bitmap_entry = create_proc_entry("sba_iommu-bitmap", 0, root); - - if (info_entry) - info_entry->proc_fops = &sba_proc_fops; - - if (bitmap_entry) - bitmap_entry->proc_fops = &sba_proc_bitmap_fops; + proc_create("sba_iommu", 0, root, &sba_proc_fops); + proc_create("sba_iommu-bitmap", 0, root, &sba_proc_bitmap_fops); #endif parisc_vmerge_boundary = IOVP_SIZE; diff --git a/drivers/parport/ieee1284.c b/drivers/parport/ieee1284.c index 54a6ef72906e..0338b0912674 100644 --- a/drivers/parport/ieee1284.c +++ b/drivers/parport/ieee1284.c @@ -76,7 +76,7 @@ int parport_wait_event (struct parport *port, signed long timeout) semaphore. */ return 1; - init_timer (&timer); + init_timer_on_stack(&timer); timer.expires = jiffies + timeout; timer.function = timeout_waiting_on_port; port_from_cookie[port->number % PARPORT_MAX] = port; @@ -88,6 +88,8 @@ int parport_wait_event (struct parport *port, signed long timeout) /* Timed out. */ ret = 1; + destroy_timer_on_stack(&timer); + return ret; } diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c index 0e77ae2b71a0..e6a7e847ee80 100644 --- a/drivers/parport/parport_gsc.c +++ b/drivers/parport/parport_gsc.c @@ -365,11 +365,11 @@ static int __devinit parport_init_chip(struct parisc_device *dev) if (boot_cpu_data.cpu_type > pcxt && !pdc_add_valid(port+4)) { /* Initialize bidirectional-mode (0x10) & data-tranfer-mode #1 (0x20) */ - printk("%s: initialize bidirectional-mode.\n", __FUNCTION__); + printk("%s: initialize bidirectional-mode.\n", __func__); parport_writeb ( (0x10 + 0x20), port + 4); } else { - printk("%s: enhanced parport-modes not supported.\n", __FUNCTION__); + printk("%s: enhanced parport-modes not supported.\n", __func__); } p = parport_gsc_probe_port(port, 0, dev->irq, diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index a85808938205..e0c2a4584ec6 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -1415,7 +1415,7 @@ static void __devinit winbond_check(int io, int key) { int devid,devrev,oldid,x_devid,x_devrev,x_oldid; - if (!request_region(io, 3, __FUNCTION__)) + if (!request_region(io, 3, __func__)) return; /* First probe without key */ @@ -1449,7 +1449,7 @@ static void __devinit winbond_check2(int io,int key) { int devid,devrev,oldid,x_devid,x_devrev,x_oldid; - if (!request_region(io, 3, __FUNCTION__)) + if (!request_region(io, 3, __func__)) return; /* First probe without the key */ @@ -1482,7 +1482,7 @@ static void __devinit smsc_check(int io, int key) { int id,rev,oldid,oldrev,x_id,x_rev,x_oldid,x_oldrev; - if (!request_region(io, 3, __FUNCTION__)) + if (!request_region(io, 3, __func__)) return; /* First probe without the key */ @@ -1547,7 +1547,7 @@ static void __devinit detect_and_report_it87(void) u8 r; if (verbose_probing) printk(KERN_DEBUG "IT8705 Super-IO detection, now testing port 2E ...\n"); - if (!request_region(0x2e, 1, __FUNCTION__)) + if (!request_region(0x2e, 1, __func__)) return; outb(0x87, 0x2e); outb(0x01, 0x2e); @@ -3082,6 +3082,7 @@ static struct pci_driver parport_pc_pci_driver; static int __init parport_pc_init_superio(int autoirq, int autodma) {return 0;} #endif /* CONFIG_PCI */ +#ifdef CONFIG_PNP static const struct pnp_device_id parport_pc_pnp_tbl[] = { /* Standard LPT Printer Port */ @@ -3148,6 +3149,9 @@ static struct pnp_driver parport_pc_pnp_driver = { .remove = parport_pc_pnp_remove, }; +#else +static struct pnp_driver parport_pc_pnp_driver; +#endif /* CONFIG_PNP */ static int __devinit parport_pc_platform_probe(struct platform_device *pdev) { diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index f14267e197dd..8264a7680435 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -93,11 +93,10 @@ struct controller { u8 slot_device_offset; u32 first_slot; /* First physical slot number */ /* PCIE only has 1 slot */ u8 slot_bus; /* Bus where the slots handled by this controller sit */ - u8 ctrlcap; + u32 slot_cap; u8 cap_base; struct timer_list poll_timer; volatile int cmd_busy; - spinlock_t lock; }; #define INT_BUTTON_IGNORE 0 @@ -137,13 +136,13 @@ struct controller { #define HP_SUPR_RM_SUP 0x00000020 #define EMI_PRSN 0x00020000 -#define ATTN_BUTTN(cap) (cap & ATTN_BUTTN_PRSN) -#define POWER_CTRL(cap) (cap & PWR_CTRL_PRSN) -#define MRL_SENS(cap) (cap & MRL_SENS_PRSN) -#define ATTN_LED(cap) (cap & ATTN_LED_PRSN) -#define PWR_LED(cap) (cap & PWR_LED_PRSN) -#define HP_SUPR_RM(cap) (cap & HP_SUPR_RM_SUP) -#define EMI(cap) (cap & EMI_PRSN) +#define ATTN_BUTTN(ctrl) ((ctrl)->slot_cap & ATTN_BUTTN_PRSN) +#define POWER_CTRL(ctrl) ((ctrl)->slot_cap & PWR_CTRL_PRSN) +#define MRL_SENS(ctrl) ((ctrl)->slot_cap & MRL_SENS_PRSN) +#define ATTN_LED(ctrl) ((ctrl)->slot_cap & ATTN_LED_PRSN) +#define PWR_LED(ctrl) ((ctrl)->slot_cap & PWR_LED_PRSN) +#define HP_SUPR_RM(ctrl) ((ctrl)->slot_cap & HP_SUPR_RM_SUP) +#define EMI(ctrl) ((ctrl)->slot_cap & EMI_PRSN) extern int pciehp_sysfs_enable_slot(struct slot *slot); extern int pciehp_sysfs_disable_slot(struct slot *slot); diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index aee19f013d84..43d8ddb2d679 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -41,6 +41,7 @@ int pciehp_debug; int pciehp_poll_mode; int pciehp_poll_time; int pciehp_force; +int pciehp_slot_with_bus; struct workqueue_struct *pciehp_wq; #define DRIVER_VERSION "0.4" @@ -55,10 +56,12 @@ module_param(pciehp_debug, bool, 0644); module_param(pciehp_poll_mode, bool, 0644); module_param(pciehp_poll_time, int, 0644); module_param(pciehp_force, bool, 0644); +module_param(pciehp_slot_with_bus, bool, 0644); MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not"); MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not"); MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds"); MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing"); +MODULE_PARM_DESC(pciehp_slot_with_bus, "Use bus number in the slot name"); #define PCIE_MODULE_NAME "pciehp" @@ -193,8 +196,12 @@ static void release_slot(struct hotplug_slot *hotplug_slot) static void make_slot_name(struct slot *slot) { - snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d", - slot->bus, slot->number); + if (pciehp_slot_with_bus) + snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d", + slot->bus, slot->number); + else + snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%d", + slot->number); } static int init_slots(struct controller *ctrl) @@ -251,7 +258,7 @@ static int init_slots(struct controller *ctrl) goto error_info; } /* create additional sysfs entries */ - if (EMI(ctrl->ctrlcap)) { + if (EMI(ctrl)) { retval = sysfs_create_file(&hotplug_slot->kobj, &hotplug_slot_attr_lock.attr); if (retval) { @@ -284,7 +291,7 @@ static void cleanup_slots(struct controller *ctrl) list_for_each_safe(tmp, next, &ctrl->slot_list) { slot = list_entry(tmp, struct slot, slot_list); list_del(&slot->slot_list); - if (EMI(ctrl->ctrlcap)) + if (EMI(ctrl)) sysfs_remove_file(&slot->hotplug_slot->kobj, &hotplug_slot_attr_lock.attr); cancel_delayed_work(&slot->work); @@ -305,7 +312,7 @@ static int set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) hotplug_slot->info->attention_status = status; - if (ATTN_LED(slot->ctrl->ctrlcap)) + if (ATTN_LED(slot->ctrl)) slot->hpc_ops->set_attention_status(slot, status); return 0; @@ -472,7 +479,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_ if (rc) /* -ENODEV: shouldn't happen, but deal with it */ value = 0; } - if ((POWER_CTRL(ctrl->ctrlcap)) && !value) { + if ((POWER_CTRL(ctrl)) && !value) { rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/ if (rc) goto err_out_free_ctrl_slot; diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 0c481f7d2ab3..0a7aa628e955 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -178,7 +178,7 @@ u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl) static void set_slot_off(struct controller *ctrl, struct slot * pslot) { /* turn off slot, turn on Amber LED, turn off Green LED if supported*/ - if (POWER_CTRL(ctrl->ctrlcap)) { + if (POWER_CTRL(ctrl)) { if (pslot->hpc_ops->power_off_slot(pslot)) { err("%s: Issue of Slot Power Off command failed\n", __func__); @@ -186,10 +186,10 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot) } } - if (PWR_LED(ctrl->ctrlcap)) + if (PWR_LED(ctrl)) pslot->hpc_ops->green_led_off(pslot); - if (ATTN_LED(ctrl->ctrlcap)) { + if (ATTN_LED(ctrl)) { if (pslot->hpc_ops->set_attention_status(pslot, 1)) { err("%s: Issue of Set Attention Led command failed\n", __func__); @@ -214,14 +214,14 @@ static int board_added(struct slot *p_slot) __func__, p_slot->device, ctrl->slot_device_offset, p_slot->hp_slot); - if (POWER_CTRL(ctrl->ctrlcap)) { + if (POWER_CTRL(ctrl)) { /* Power on slot */ retval = p_slot->hpc_ops->power_on_slot(p_slot); if (retval) return retval; } - if (PWR_LED(ctrl->ctrlcap)) + if (PWR_LED(ctrl)) p_slot->hpc_ops->green_led_blink(p_slot); /* Wait for ~1 second */ @@ -254,7 +254,7 @@ static int board_added(struct slot *p_slot) */ if (pcie_mch_quirk) pci_fixup_device(pci_fixup_final, ctrl->pci_dev); - if (PWR_LED(ctrl->ctrlcap)) + if (PWR_LED(ctrl)) p_slot->hpc_ops->green_led_on(p_slot); return 0; @@ -279,7 +279,7 @@ static int remove_board(struct slot *p_slot) dbg("In %s, hp_slot = %d\n", __func__, p_slot->hp_slot); - if (POWER_CTRL(ctrl->ctrlcap)) { + if (POWER_CTRL(ctrl)) { /* power off slot */ retval = p_slot->hpc_ops->power_off_slot(p_slot); if (retval) { @@ -289,7 +289,7 @@ static int remove_board(struct slot *p_slot) } } - if (PWR_LED(ctrl->ctrlcap)) + if (PWR_LED(ctrl)) /* turn off Green LED */ p_slot->hpc_ops->green_led_off(p_slot); @@ -327,7 +327,7 @@ static void pciehp_power_thread(struct work_struct *work) case POWERON_STATE: mutex_unlock(&p_slot->lock); if (pciehp_enable_slot(p_slot) && - PWR_LED(p_slot->ctrl->ctrlcap)) + PWR_LED(p_slot->ctrl)) p_slot->hpc_ops->green_led_off(p_slot); mutex_lock(&p_slot->lock); p_slot->state = STATIC_STATE; @@ -409,9 +409,9 @@ static void handle_button_press_event(struct slot *p_slot) "press.\n", p_slot->name); } /* blink green LED and turn off amber */ - if (PWR_LED(ctrl->ctrlcap)) + if (PWR_LED(ctrl)) p_slot->hpc_ops->green_led_blink(p_slot); - if (ATTN_LED(ctrl->ctrlcap)) + if (ATTN_LED(ctrl)) p_slot->hpc_ops->set_attention_status(p_slot, 0); schedule_delayed_work(&p_slot->work, 5*HZ); @@ -427,13 +427,13 @@ static void handle_button_press_event(struct slot *p_slot) dbg("%s: button cancel\n", __func__); cancel_delayed_work(&p_slot->work); if (p_slot->state == BLINKINGOFF_STATE) { - if (PWR_LED(ctrl->ctrlcap)) + if (PWR_LED(ctrl)) p_slot->hpc_ops->green_led_on(p_slot); } else { - if (PWR_LED(ctrl->ctrlcap)) + if (PWR_LED(ctrl)) p_slot->hpc_ops->green_led_off(p_slot); } - if (ATTN_LED(ctrl->ctrlcap)) + if (ATTN_LED(ctrl)) p_slot->hpc_ops->set_attention_status(p_slot, 0); info("PCI slot #%s - action canceled due to button press\n", p_slot->name); @@ -492,16 +492,16 @@ static void interrupt_event_handler(struct work_struct *work) handle_button_press_event(p_slot); break; case INT_POWER_FAULT: - if (!POWER_CTRL(ctrl->ctrlcap)) + if (!POWER_CTRL(ctrl)) break; - if (ATTN_LED(ctrl->ctrlcap)) + if (ATTN_LED(ctrl)) p_slot->hpc_ops->set_attention_status(p_slot, 1); - if (PWR_LED(ctrl->ctrlcap)) + if (PWR_LED(ctrl)) p_slot->hpc_ops->green_led_off(p_slot); break; case INT_PRESENCE_ON: case INT_PRESENCE_OFF: - if (!HP_SUPR_RM(ctrl->ctrlcap)) + if (!HP_SUPR_RM(ctrl)) break; dbg("Surprise Removal\n"); update_slot_info(p_slot); @@ -531,7 +531,7 @@ int pciehp_enable_slot(struct slot *p_slot) mutex_unlock(&p_slot->ctrl->crit_sect); return -ENODEV; } - if (MRL_SENS(p_slot->ctrl->ctrlcap)) { + if (MRL_SENS(p_slot->ctrl)) { rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: latch open on slot(%s)\n", __func__, @@ -541,7 +541,7 @@ int pciehp_enable_slot(struct slot *p_slot) } } - if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { + if (POWER_CTRL(p_slot->ctrl)) { rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (rc || getstatus) { info("%s: already enabled on slot(%s)\n", __func__, @@ -576,7 +576,7 @@ int pciehp_disable_slot(struct slot *p_slot) /* Check to see if (latch closed, card present, power on) */ mutex_lock(&p_slot->ctrl->crit_sect); - if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) { + if (!HP_SUPR_RM(p_slot->ctrl)) { ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus); if (ret || !getstatus) { info("%s: no adapter on slot(%s)\n", __func__, @@ -586,7 +586,7 @@ int pciehp_disable_slot(struct slot *p_slot) } } - if (MRL_SENS(p_slot->ctrl->ctrlcap)) { + if (MRL_SENS(p_slot->ctrl)) { ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); if (ret || getstatus) { info("%s: latch open on slot(%s)\n", __func__, @@ -596,7 +596,7 @@ int pciehp_disable_slot(struct slot *p_slot) } } - if (POWER_CTRL(p_slot->ctrl->ctrlcap)) { + if (POWER_CTRL(p_slot->ctrl)) { ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus); if (ret || !getstatus) { info("%s: already disabled slot(%s)\n", __func__, diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index b4bbd07d1e39..891f81a0400c 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -221,6 +221,32 @@ static void start_int_poll_timer(struct controller *ctrl, int sec) add_timer(&ctrl->poll_timer); } +static inline int pciehp_request_irq(struct controller *ctrl) +{ + int retval, irq = ctrl->pci_dev->irq; + + /* Install interrupt polling timer. Start with 10 sec delay */ + if (pciehp_poll_mode) { + init_timer(&ctrl->poll_timer); + start_int_poll_timer(ctrl, 10); + return 0; + } + + /* Installs the interrupt handler */ + retval = request_irq(irq, pcie_isr, IRQF_SHARED, MY_NAME, ctrl); + if (retval) + err("Cannot get irq %d for the hotplug controller\n", irq); + return retval; +} + +static inline void pciehp_free_irq(struct controller *ctrl) +{ + if (pciehp_poll_mode) + del_timer_sync(&ctrl->poll_timer); + else + free_irq(ctrl->pci_dev->irq, ctrl); +} + static inline int pcie_wait_cmd(struct controller *ctrl) { int retval = 0; @@ -242,17 +268,15 @@ static inline int pcie_wait_cmd(struct controller *ctrl) /** * pcie_write_cmd - Issue controller command - * @slot: slot to which the command is issued + * @ctrl: controller to which the command is issued * @cmd: command value written to slot control register * @mask: bitmask of slot control register to be modified */ -static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask) +static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) { - struct controller *ctrl = slot->ctrl; int retval = 0; u16 slot_status; u16 slot_ctrl; - unsigned long flags; mutex_lock(&ctrl->ctrl_lock); @@ -270,24 +294,24 @@ static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask) __func__); } - spin_lock_irqsave(&ctrl->lock, flags); retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); if (retval) { err("%s: Cannot read SLOTCTRL register\n", __func__); - goto out_spin_unlock; + goto out; } slot_ctrl &= ~mask; - slot_ctrl |= ((cmd & mask) | CMD_CMPL_INTR_ENABLE); + slot_ctrl |= (cmd & mask); + /* Don't enable command completed if caller is changing it. */ + if (!(mask & CMD_CMPL_INTR_ENABLE)) + slot_ctrl |= CMD_CMPL_INTR_ENABLE; ctrl->cmd_busy = 1; + smp_mb(); retval = pciehp_writew(ctrl, SLOTCTRL, slot_ctrl); if (retval) err("%s: Cannot write to SLOTCTRL register\n", __func__); - out_spin_unlock: - spin_unlock_irqrestore(&ctrl->lock, flags); - /* * Wait for command completion. */ @@ -467,12 +491,7 @@ static int hpc_toggle_emi(struct slot *slot) slot_cmd = EMI_CTRL; cmd_mask = EMI_CTRL; - if (!pciehp_poll_mode) { - slot_cmd = slot_cmd | HP_INTR_ENABLE; - cmd_mask = cmd_mask | HP_INTR_ENABLE; - } - - rc = pcie_write_cmd(slot, slot_cmd, cmd_mask); + rc = pcie_write_cmd(slot->ctrl, slot_cmd, cmd_mask); slot->last_emi_toggle = get_seconds(); return rc; @@ -499,12 +518,7 @@ static int hpc_set_attention_status(struct slot *slot, u8 value) default: return -1; } - if (!pciehp_poll_mode) { - slot_cmd = slot_cmd | HP_INTR_ENABLE; - cmd_mask = cmd_mask | HP_INTR_ENABLE; - } - - rc = pcie_write_cmd(slot, slot_cmd, cmd_mask); + rc = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); dbg("%s: SLOTCTRL %x write cmd %x\n", __func__, ctrl->cap_base + SLOTCTRL, slot_cmd); @@ -519,13 +533,7 @@ static void hpc_set_green_led_on(struct slot *slot) slot_cmd = 0x0100; cmd_mask = PWR_LED_CTRL; - if (!pciehp_poll_mode) { - slot_cmd = slot_cmd | HP_INTR_ENABLE; - cmd_mask = cmd_mask | HP_INTR_ENABLE; - } - - pcie_write_cmd(slot, slot_cmd, cmd_mask); - + pcie_write_cmd(ctrl, slot_cmd, cmd_mask); dbg("%s: SLOTCTRL %x write cmd %x\n", __func__, ctrl->cap_base + SLOTCTRL, slot_cmd); } @@ -538,12 +546,7 @@ static void hpc_set_green_led_off(struct slot *slot) slot_cmd = 0x0300; cmd_mask = PWR_LED_CTRL; - if (!pciehp_poll_mode) { - slot_cmd = slot_cmd | HP_INTR_ENABLE; - cmd_mask = cmd_mask | HP_INTR_ENABLE; - } - - pcie_write_cmd(slot, slot_cmd, cmd_mask); + pcie_write_cmd(ctrl, slot_cmd, cmd_mask); dbg("%s: SLOTCTRL %x write cmd %x\n", __func__, ctrl->cap_base + SLOTCTRL, slot_cmd); } @@ -556,23 +559,19 @@ static void hpc_set_green_led_blink(struct slot *slot) slot_cmd = 0x0200; cmd_mask = PWR_LED_CTRL; - if (!pciehp_poll_mode) { - slot_cmd = slot_cmd | HP_INTR_ENABLE; - cmd_mask = cmd_mask | HP_INTR_ENABLE; - } - - pcie_write_cmd(slot, slot_cmd, cmd_mask); - + pcie_write_cmd(ctrl, slot_cmd, cmd_mask); dbg("%s: SLOTCTRL %x write cmd %x\n", __func__, ctrl->cap_base + SLOTCTRL, slot_cmd); } static void hpc_release_ctlr(struct controller *ctrl) { - if (pciehp_poll_mode) - del_timer(&ctrl->poll_timer); - else - free_irq(ctrl->pci_dev->irq, ctrl); + /* Mask Hot-plug Interrupt Enable */ + if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE)) + err("%s: Cannot mask hotplut interrupt enable\n", __func__); + + /* Free interrupt handler or interrupt polling timer */ + pciehp_free_irq(ctrl); /* * If this is the last controller to be released, destroy the @@ -612,19 +611,13 @@ static int hpc_power_on_slot(struct slot * slot) cmd_mask = PWR_CTRL; /* Enable detection that we turned off at slot power-off time */ if (!pciehp_poll_mode) { - slot_cmd = slot_cmd | - PWR_FAULT_DETECT_ENABLE | - MRL_DETECT_ENABLE | - PRSN_DETECT_ENABLE | - HP_INTR_ENABLE; - cmd_mask = cmd_mask | - PWR_FAULT_DETECT_ENABLE | - MRL_DETECT_ENABLE | - PRSN_DETECT_ENABLE | - HP_INTR_ENABLE; + slot_cmd |= (PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE | + PRSN_DETECT_ENABLE); + cmd_mask |= (PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE | + PRSN_DETECT_ENABLE); } - retval = pcie_write_cmd(slot, slot_cmd, cmd_mask); + retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); if (retval) { err("%s: Write %x command failed!\n", __func__, slot_cmd); @@ -697,18 +690,13 @@ static int hpc_power_off_slot(struct slot * slot) * till the slot is powered on again. */ if (!pciehp_poll_mode) { - slot_cmd = (slot_cmd & - ~PWR_FAULT_DETECT_ENABLE & - ~MRL_DETECT_ENABLE & - ~PRSN_DETECT_ENABLE) | HP_INTR_ENABLE; - cmd_mask = cmd_mask | - PWR_FAULT_DETECT_ENABLE | - MRL_DETECT_ENABLE | - PRSN_DETECT_ENABLE | - HP_INTR_ENABLE; + slot_cmd &= ~(PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE | + PRSN_DETECT_ENABLE); + cmd_mask |= (PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE | + PRSN_DETECT_ENABLE); } - retval = pcie_write_cmd(slot, slot_cmd, cmd_mask); + retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask); if (retval) { err("%s: Write command failed!\n", __func__); retval = -1; @@ -733,139 +721,56 @@ static int hpc_power_off_slot(struct slot * slot) static irqreturn_t pcie_isr(int irq, void *dev_id) { struct controller *ctrl = (struct controller *)dev_id; - u16 slot_status, intr_detect, intr_loc; - u16 temp_word; - int hp_slot = 0; /* only 1 slot per PCI Express port */ - int rc = 0; - unsigned long flags; - - rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); - if (rc) { - err("%s: Cannot read SLOTSTATUS register\n", __func__); - return IRQ_NONE; - } - - intr_detect = (ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED | - MRL_SENS_CHANGED | PRSN_DETECT_CHANGED | CMD_COMPLETED); - - intr_loc = slot_status & intr_detect; - - /* Check to see if it was our interrupt */ - if ( !intr_loc ) - return IRQ_NONE; + u16 detected, intr_loc; - dbg("%s: intr_loc %x\n", __func__, intr_loc); - /* Mask Hot-plug Interrupt Enable */ - if (!pciehp_poll_mode) { - spin_lock_irqsave(&ctrl->lock, flags); - rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); - if (rc) { - err("%s: Cannot read SLOT_CTRL register\n", - __func__); - spin_unlock_irqrestore(&ctrl->lock, flags); + /* + * In order to guarantee that all interrupt events are + * serviced, we need to re-inspect Slot Status register after + * clearing what is presumed to be the last pending interrupt. + */ + intr_loc = 0; + do { + if (pciehp_readw(ctrl, SLOTSTATUS, &detected)) { + err("%s: Cannot read SLOTSTATUS\n", __func__); return IRQ_NONE; } - dbg("%s: pciehp_readw(SLOTCTRL) with value %x\n", - __func__, temp_word); - temp_word = (temp_word & ~HP_INTR_ENABLE & - ~CMD_CMPL_INTR_ENABLE) | 0x00; - rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); - if (rc) { - err("%s: Cannot write to SLOTCTRL register\n", - __func__); - spin_unlock_irqrestore(&ctrl->lock, flags); + detected &= (ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED | + MRL_SENS_CHANGED | PRSN_DETECT_CHANGED | + CMD_COMPLETED); + intr_loc |= detected; + if (!intr_loc) return IRQ_NONE; - } - spin_unlock_irqrestore(&ctrl->lock, flags); - - rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); - if (rc) { - err("%s: Cannot read SLOT_STATUS register\n", - __func__); + if (pciehp_writew(ctrl, SLOTSTATUS, detected)) { + err("%s: Cannot write to SLOTSTATUS\n", __func__); return IRQ_NONE; } - dbg("%s: pciehp_readw(SLOTSTATUS) with value %x\n", - __func__, slot_status); + } while (detected); - /* Clear command complete interrupt caused by this write */ - temp_word = 0x1f; - rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); - if (rc) { - err("%s: Cannot write to SLOTSTATUS register\n", - __func__); - return IRQ_NONE; - } - } + dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc); + /* Check Command Complete Interrupt Pending */ if (intr_loc & CMD_COMPLETED) { - /* - * Command Complete Interrupt Pending - */ ctrl->cmd_busy = 0; + smp_mb(); wake_up_interruptible(&ctrl->queue); } + /* Check MRL Sensor Changed */ if (intr_loc & MRL_SENS_CHANGED) - pciehp_handle_switch_change(hp_slot, ctrl); + pciehp_handle_switch_change(0, ctrl); + /* Check Attention Button Pressed */ if (intr_loc & ATTN_BUTTN_PRESSED) - pciehp_handle_attention_button(hp_slot, ctrl); + pciehp_handle_attention_button(0, ctrl); + /* Check Presence Detect Changed */ if (intr_loc & PRSN_DETECT_CHANGED) - pciehp_handle_presence_change(hp_slot, ctrl); + pciehp_handle_presence_change(0, ctrl); + /* Check Power Fault Detected */ if (intr_loc & PWR_FAULT_DETECTED) - pciehp_handle_power_fault(hp_slot, ctrl); - - /* Clear all events after serving them */ - temp_word = 0x1F; - rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); - if (rc) { - err("%s: Cannot write to SLOTSTATUS register\n", __func__); - return IRQ_NONE; - } - /* Unmask Hot-plug Interrupt Enable */ - if (!pciehp_poll_mode) { - spin_lock_irqsave(&ctrl->lock, flags); - rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); - if (rc) { - err("%s: Cannot read SLOTCTRL register\n", - __func__); - spin_unlock_irqrestore(&ctrl->lock, flags); - return IRQ_NONE; - } - - dbg("%s: Unmask Hot-plug Interrupt Enable\n", __func__); - temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE; - - rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); - if (rc) { - err("%s: Cannot write to SLOTCTRL register\n", - __func__); - spin_unlock_irqrestore(&ctrl->lock, flags); - return IRQ_NONE; - } - spin_unlock_irqrestore(&ctrl->lock, flags); - - rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); - if (rc) { - err("%s: Cannot read SLOT_STATUS register\n", - __func__); - return IRQ_NONE; - } - - /* Clear command complete interrupt caused by this write */ - temp_word = 0x1F; - rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); - if (rc) { - err("%s: Cannot write to SLOTSTATUS failed\n", - __func__); - return IRQ_NONE; - } - dbg("%s: pciehp_writew(SLOTSTATUS) with value %x\n", - __func__, temp_word); - } + pciehp_handle_power_fault(0, ctrl); return IRQ_HANDLED; } @@ -1052,7 +957,7 @@ static struct hpc_ops pciehp_hpc_ops = { }; #ifdef CONFIG_ACPI -int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) +static int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) { acpi_status status; acpi_handle chandle, handle = DEVICE_ACPI_HANDLE(&(dev->dev)); @@ -1112,7 +1017,7 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) break; } - err("Cannot get control of hotplug hardware for pci %s\n", + dbg("Cannot get control of hotplug hardware for pci %s\n", pci_name(dev)); kfree(string.pointer); @@ -1123,45 +1028,9 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) static int pcie_init_hardware_part1(struct controller *ctrl, struct pcie_device *dev) { - int rc; - u16 temp_word; - u32 slot_cap; - u16 slot_status; - - rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); - if (rc) { - err("%s: Cannot read SLOTCAP register\n", __func__); - return -1; - } - /* Mask Hot-plug Interrupt Enable */ - rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); - if (rc) { - err("%s: Cannot read SLOTCTRL register\n", __func__); - return -1; - } - - dbg("%s: SLOTCTRL %x value read %x\n", - __func__, ctrl->cap_base + SLOTCTRL, temp_word); - temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | - 0x00; - - rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); - if (rc) { - err("%s: Cannot write to SLOTCTRL register\n", __func__); - return -1; - } - - rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); - if (rc) { - err("%s: Cannot read SLOTSTATUS register\n", __func__); - return -1; - } - - temp_word = 0x1F; /* Clear all events */ - rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); - if (rc) { - err("%s: Cannot write to SLOTSTATUS register\n", __func__); + if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE)) { + err("%s: Cannot mask hotplug interrupt enable\n", __func__); return -1; } return 0; @@ -1169,205 +1038,125 @@ static int pcie_init_hardware_part1(struct controller *ctrl, int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev) { - int rc; - u16 temp_word; - u16 intr_enable = 0; - u32 slot_cap; - u16 slot_status; + u16 cmd, mask; - rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); - if (rc) { - err("%s: Cannot read SLOTCTRL register\n", __func__); - goto abort; - } - - intr_enable = intr_enable | PRSN_DETECT_ENABLE; - - rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); - if (rc) { - err("%s: Cannot read SLOTCAP register\n", __func__); - goto abort; + /* + * We need to clear all events before enabling hotplug interrupt + * notification mechanism in order for hotplug controler to + * generate interrupts. + */ + if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f)) { + err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__); + return -1; } - if (ATTN_BUTTN(slot_cap)) - intr_enable = intr_enable | ATTN_BUTTN_ENABLE; - - if (POWER_CTRL(slot_cap)) - intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE; - - if (MRL_SENS(slot_cap)) - intr_enable = intr_enable | MRL_DETECT_ENABLE; + cmd = PRSN_DETECT_ENABLE; + if (ATTN_BUTTN(ctrl)) + cmd |= ATTN_BUTTN_ENABLE; + if (POWER_CTRL(ctrl)) + cmd |= PWR_FAULT_DETECT_ENABLE; + if (MRL_SENS(ctrl)) + cmd |= MRL_DETECT_ENABLE; + if (!pciehp_poll_mode) + cmd |= HP_INTR_ENABLE; - temp_word = (temp_word & ~intr_enable) | intr_enable; + mask = PRSN_DETECT_ENABLE | ATTN_BUTTN_ENABLE | + PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE | HP_INTR_ENABLE; - if (pciehp_poll_mode) { - temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0; - } else { - temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE; - } - - /* - * Unmask Hot-plug Interrupt Enable for the interrupt - * notification mechanism case. - */ - rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); - if (rc) { - err("%s: Cannot write to SLOTCTRL register\n", __func__); + if (pcie_write_cmd(ctrl, cmd, mask)) { + err("%s: Cannot enable software notification\n", __func__); goto abort; } - rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); - if (rc) { - err("%s: Cannot read SLOTSTATUS register\n", __func__); - goto abort_disable_intr; - } - - temp_word = 0x1F; /* Clear all events */ - rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word); - if (rc) { - err("%s: Cannot write to SLOTSTATUS register\n", __func__); - goto abort_disable_intr; - } - if (pciehp_force) { + if (pciehp_force) dbg("Bypassing BIOS check for pciehp use on %s\n", pci_name(ctrl->pci_dev)); - } else { - rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev); - if (rc) - goto abort_disable_intr; - } + else if (pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev)) + goto abort_disable_intr; return 0; /* We end up here for the many possible ways to fail this API. */ abort_disable_intr: - rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word); - if (!rc) { - temp_word &= ~(intr_enable | HP_INTR_ENABLE); - rc = pciehp_writew(ctrl, SLOTCTRL, temp_word); - } - if (rc) + if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE)) err("%s : disabling interrupts failed\n", __func__); abort: return -1; } -int pcie_init(struct controller *ctrl, struct pcie_device *dev) +static inline void dbg_ctrl(struct controller *ctrl) { - int rc; - u16 cap_reg; - u32 slot_cap; - int cap_base; - u16 slot_status, slot_ctrl; - struct pci_dev *pdev; - - pdev = dev->port; - ctrl->pci_dev = pdev; /* save pci_dev in context */ - - dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n", - __func__, pdev->vendor, pdev->device); + int i; + u16 reg16; + struct pci_dev *pdev = ctrl->pci_dev; - cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP); - if (cap_base == 0) { - dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __func__); - goto abort; - } + if (!pciehp_debug) + return; - ctrl->cap_base = cap_base; + dbg("Hotplug Controller:\n"); + dbg(" Seg/Bus/Dev/Func/IRQ : %s IRQ %d\n", pci_name(pdev), pdev->irq); + dbg(" Vendor ID : 0x%04x\n", pdev->vendor); + dbg(" Device ID : 0x%04x\n", pdev->device); + dbg(" Subsystem ID : 0x%04x\n", pdev->subsystem_device); + dbg(" Subsystem Vendor ID : 0x%04x\n", pdev->subsystem_vendor); + dbg(" PCIe Cap offset : 0x%02x\n", ctrl->cap_base); + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { + if (!pci_resource_len(pdev, i)) + continue; + dbg(" PCI resource [%d] : 0x%llx@0x%llx\n", i, + (unsigned long long)pci_resource_len(pdev, i), + (unsigned long long)pci_resource_start(pdev, i)); + } + dbg("Slot Capabilities : 0x%08x\n", ctrl->slot_cap); + dbg(" Physical Slot Number : %d\n", ctrl->first_slot); + dbg(" Attention Button : %3s\n", ATTN_BUTTN(ctrl) ? "yes" : "no"); + dbg(" Power Controller : %3s\n", POWER_CTRL(ctrl) ? "yes" : "no"); + dbg(" MRL Sensor : %3s\n", MRL_SENS(ctrl) ? "yes" : "no"); + dbg(" Attention Indicator : %3s\n", ATTN_LED(ctrl) ? "yes" : "no"); + dbg(" Power Indicator : %3s\n", PWR_LED(ctrl) ? "yes" : "no"); + dbg(" Hot-Plug Surprise : %3s\n", HP_SUPR_RM(ctrl) ? "yes" : "no"); + dbg(" EMI Present : %3s\n", EMI(ctrl) ? "yes" : "no"); + pciehp_readw(ctrl, SLOTSTATUS, ®16); + dbg("Slot Status : 0x%04x\n", reg16); + pciehp_readw(ctrl, SLOTSTATUS, ®16); + dbg("Slot Control : 0x%04x\n", reg16); +} - dbg("%s: pcie_cap_base %x\n", __func__, cap_base); +int pcie_init(struct controller *ctrl, struct pcie_device *dev) +{ + u32 slot_cap; + struct pci_dev *pdev = dev->port; - rc = pciehp_readw(ctrl, CAPREG, &cap_reg); - if (rc) { - err("%s: Cannot read CAPREG register\n", __func__); - goto abort; - } - dbg("%s: CAPREG offset %x cap_reg %x\n", - __func__, ctrl->cap_base + CAPREG, cap_reg); - - if (((cap_reg & SLOT_IMPL) == 0) || - (((cap_reg & DEV_PORT_TYPE) != 0x0040) - && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) { - dbg("%s : This is not a root port or the port is not " - "connected to a slot\n", __func__); + ctrl->pci_dev = pdev; + ctrl->cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP); + if (!ctrl->cap_base) { + err("%s: Cannot find PCI Express capability\n", __func__); goto abort; } - - rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap); - if (rc) { + if (pciehp_readl(ctrl, SLOTCAP, &slot_cap)) { err("%s: Cannot read SLOTCAP register\n", __func__); goto abort; } - dbg("%s: SLOTCAP offset %x slot_cap %x\n", - __func__, ctrl->cap_base + SLOTCAP, slot_cap); - - if (!(slot_cap & HP_CAP)) { - dbg("%s : This slot is not hot-plug capable\n", __func__); - goto abort; - } - /* For debugging purpose */ - rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status); - if (rc) { - err("%s: Cannot read SLOTSTATUS register\n", __func__); - goto abort; - } - dbg("%s: SLOTSTATUS offset %x slot_status %x\n", - __func__, ctrl->cap_base + SLOTSTATUS, slot_status); - - rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); - if (rc) { - err("%s: Cannot read SLOTCTRL register\n", __func__); - goto abort; - } - dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n", - __func__, ctrl->cap_base + SLOTCTRL, slot_ctrl); - - for (rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++) - if (pci_resource_len(pdev, rc) > 0) - dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc, - (unsigned long long)pci_resource_start(pdev, rc), - (unsigned long long)pci_resource_len(pdev, rc)); - - info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", - pdev->vendor, pdev->device, - pdev->subsystem_vendor, pdev->subsystem_device); + ctrl->slot_cap = slot_cap; + ctrl->first_slot = slot_cap >> 19; + ctrl->slot_device_offset = 0; + ctrl->num_slots = 1; + ctrl->hpc_ops = &pciehp_hpc_ops; mutex_init(&ctrl->crit_sect); mutex_init(&ctrl->ctrl_lock); - spin_lock_init(&ctrl->lock); - - /* setup wait queue */ init_waitqueue_head(&ctrl->queue); + dbg_ctrl(ctrl); - /* return PCI Controller Info */ - ctrl->slot_device_offset = 0; - ctrl->num_slots = 1; - ctrl->first_slot = slot_cap >> 19; - ctrl->ctrlcap = slot_cap & 0x0000007f; + info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", + pdev->vendor, pdev->device, + pdev->subsystem_vendor, pdev->subsystem_device); - rc = pcie_init_hardware_part1(ctrl, dev); - if (rc) + if (pcie_init_hardware_part1(ctrl, dev)) goto abort; - if (pciehp_poll_mode) { - /* Install interrupt polling timer. Start with 10 sec delay */ - init_timer(&ctrl->poll_timer); - start_int_poll_timer(ctrl, 10); - } else { - /* Installs the interrupt handler */ - rc = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED, - MY_NAME, (void *)ctrl); - dbg("%s: request_irq %d for hpc%d (returns %d)\n", - __func__, ctrl->pci_dev->irq, - atomic_read(&pciehp_num_controllers), rc); - if (rc) { - err("Can't get irq %d for the hotplug controller\n", - ctrl->pci_dev->irq); - goto abort; - } - } - dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number, - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq); + if (pciehp_request_irq(ctrl)) + goto abort; /* * If this is the first controller to be initialized, @@ -1376,21 +1165,17 @@ int pcie_init(struct controller *ctrl, struct pcie_device *dev) if (atomic_add_return(1, &pciehp_num_controllers) == 1) { pciehp_wq = create_singlethread_workqueue("pciehpd"); if (!pciehp_wq) { - rc = -ENOMEM; goto abort_free_irq; } } - rc = pcie_init_hardware_part2(ctrl, dev); - if (rc == 0) { - ctrl->hpc_ops = &pciehp_hpc_ops; - return 0; - } + if (pcie_init_hardware_part2(ctrl, dev)) + goto abort_free_irq; + + return 0; + abort_free_irq: - if (pciehp_poll_mode) - del_timer_sync(&ctrl->poll_timer); - else - free_irq(ctrl->pci_dev->irq, ctrl); + pciehp_free_irq(ctrl); abort: return -1; } diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index 43816d4b3c43..1648076600fc 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -39,6 +39,7 @@ int shpchp_debug; int shpchp_poll_mode; int shpchp_poll_time; +int shpchp_slot_with_bus; struct workqueue_struct *shpchp_wq; #define DRIVER_VERSION "0.4" @@ -52,9 +53,11 @@ MODULE_LICENSE("GPL"); module_param(shpchp_debug, bool, 0644); module_param(shpchp_poll_mode, bool, 0644); module_param(shpchp_poll_time, int, 0644); +module_param(shpchp_slot_with_bus, bool, 0644); MODULE_PARM_DESC(shpchp_debug, "Debugging mode enabled or not"); MODULE_PARM_DESC(shpchp_poll_mode, "Using polling mechanism for hot-plug events or not"); MODULE_PARM_DESC(shpchp_poll_time, "Polling mechanism frequency, in seconds"); +MODULE_PARM_DESC(shpchp_slot_with_bus, "Use bus number in the slot name"); #define SHPC_MODULE_NAME "shpchp" @@ -100,8 +103,12 @@ static void release_slot(struct hotplug_slot *hotplug_slot) static void make_slot_name(struct slot *slot) { - snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d", - slot->bus, slot->number); + if (shpchp_slot_with_bus) + snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d", + slot->bus, slot->number); + else + snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%d", + slot->number); } static int init_slots(struct controller *ctrl) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 26938da8f438..8c61304cbb37 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -123,7 +123,7 @@ static void msix_flush_writes(unsigned int irq) } } -static void msi_set_mask_bit(unsigned int irq, int flag) +static void msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag) { struct msi_desc *entry; @@ -137,8 +137,8 @@ static void msi_set_mask_bit(unsigned int irq, int flag) pos = (long)entry->mask_base; pci_read_config_dword(entry->dev, pos, &mask_bits); - mask_bits &= ~(1); - mask_bits |= flag; + mask_bits &= ~(mask); + mask_bits |= flag & mask; pci_write_config_dword(entry->dev, pos, mask_bits); } else { msi_set_enable(entry->dev, !flag); @@ -241,13 +241,13 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg) void mask_msi_irq(unsigned int irq) { - msi_set_mask_bit(irq, 1); + msi_set_mask_bits(irq, 1, 1); msix_flush_writes(irq); } void unmask_msi_irq(unsigned int irq) { - msi_set_mask_bit(irq, 0); + msi_set_mask_bits(irq, 1, 0); msix_flush_writes(irq); } @@ -291,7 +291,8 @@ static void __pci_restore_msi_state(struct pci_dev *dev) msi_set_enable(dev, 0); write_msi_msg(dev->irq, &entry->msg); if (entry->msi_attrib.maskbit) - msi_set_mask_bit(dev->irq, entry->msi_attrib.masked); + msi_set_mask_bits(dev->irq, entry->msi_attrib.maskbits_mask, + entry->msi_attrib.masked); pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); control &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE); @@ -315,7 +316,7 @@ static void __pci_restore_msix_state(struct pci_dev *dev) list_for_each_entry(entry, &dev->msi_list, list) { write_msi_msg(entry->irq, &entry->msg); - msi_set_mask_bit(entry->irq, entry->msi_attrib.masked); + msi_set_mask_bits(entry->irq, 1, entry->msi_attrib.masked); } BUG_ON(list_empty(&dev->msi_list)); @@ -382,6 +383,7 @@ static int msi_capability_init(struct pci_dev *dev) pci_write_config_dword(dev, msi_mask_bits_reg(pos, is_64bit_address(control)), maskbits); + entry->msi_attrib.maskbits_mask = temp; } list_add_tail(&entry->list, &dev->msi_list); @@ -569,10 +571,9 @@ int pci_enable_msi(struct pci_dev* dev) } EXPORT_SYMBOL(pci_enable_msi); -void pci_disable_msi(struct pci_dev* dev) +void pci_msi_shutdown(struct pci_dev* dev) { struct msi_desc *entry; - int default_irq; if (!pci_msi_enable || !dev || !dev->msi_enabled) return; @@ -583,15 +584,31 @@ void pci_disable_msi(struct pci_dev* dev) BUG_ON(list_empty(&dev->msi_list)); entry = list_entry(dev->msi_list.next, struct msi_desc, list); - if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) { - return; + /* Return the the pci reset with msi irqs unmasked */ + if (entry->msi_attrib.maskbit) { + u32 mask = entry->msi_attrib.maskbits_mask; + msi_set_mask_bits(dev->irq, mask, ~mask); } - - default_irq = entry->msi_attrib.default_irq; - msi_free_irqs(dev); + if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) + return; /* Restore dev->irq to its default pin-assertion irq */ - dev->irq = default_irq; + dev->irq = entry->msi_attrib.default_irq; +} +void pci_disable_msi(struct pci_dev* dev) +{ + struct msi_desc *entry; + + if (!pci_msi_enable || !dev || !dev->msi_enabled) + return; + + pci_msi_shutdown(dev); + + entry = list_entry(dev->msi_list.next, struct msi_desc, list); + if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) + return; + + msi_free_irqs(dev); } EXPORT_SYMBOL(pci_disable_msi); @@ -684,7 +701,7 @@ static void msix_free_all_irqs(struct pci_dev *dev) msi_free_irqs(dev); } -void pci_disable_msix(struct pci_dev* dev) +void pci_msix_shutdown(struct pci_dev* dev) { if (!pci_msi_enable || !dev || !dev->msix_enabled) return; @@ -692,6 +709,13 @@ void pci_disable_msix(struct pci_dev* dev) msix_set_enable(dev, 0); pci_intx_for_msi(dev, 1); dev->msix_enabled = 0; +} +void pci_disable_msix(struct pci_dev* dev) +{ + if (!pci_msi_enable || !dev || !dev->msix_enabled) + return; + + pci_msix_shutdown(dev); msix_free_all_irqs(dev); } diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index e8d94fafc280..72cf61ed8f96 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -360,6 +360,8 @@ static void pci_device_shutdown(struct device *dev) if (drv && drv->shutdown) drv->shutdown(pci_dev); + pci_msi_shutdown(pci_dev); + pci_msix_shutdown(pci_dev); } /** diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig index 25b04fb2517d..5a0c6ad53f8e 100644 --- a/drivers/pci/pcie/Kconfig +++ b/drivers/pci/pcie/Kconfig @@ -33,7 +33,7 @@ source "drivers/pci/pcie/aer/Kconfig" config PCIEASPM bool "PCI Express ASPM support(Experimental)" depends on PCI && EXPERIMENTAL && PCIEPORTBUS - default y + default n help This enables PCI Express ASPM (Active State Power Management) and Clock Power Management. ASPM supports state L0/L0s/L1. diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index f991359f0c36..4a55bf380957 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -842,11 +842,14 @@ static void set_pcie_port_type(struct pci_dev *pdev) * reading the dword at 0x100 which must either be 0 or a valid extended * capability header. */ -int pci_cfg_space_size(struct pci_dev *dev) +int pci_cfg_space_size_ext(struct pci_dev *dev, unsigned check_exp_pcix) { int pos; u32 status; + if (!check_exp_pcix) + goto skip; + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); if (!pos) { pos = pci_find_capability(dev, PCI_CAP_ID_PCIX); @@ -858,6 +861,7 @@ int pci_cfg_space_size(struct pci_dev *dev) goto fail; } + skip: if (pci_read_config_dword(dev, 256, &status) != PCIBIOS_SUCCESSFUL) goto fail; if (status == 0xffffffff) @@ -869,6 +873,11 @@ int pci_cfg_space_size(struct pci_dev *dev) return PCI_CFG_SPACE_SIZE; } +int pci_cfg_space_size(struct pci_dev *dev) +{ + return pci_cfg_space_size_ext(dev, 1); +} + static void pci_release_bus_bridge_dev(struct device *dev) { kfree(dev); @@ -964,7 +973,6 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) dev->dev.release = pci_release_dev; pci_dev_get(dev); - set_dev_node(&dev->dev, pcibus_to_node(bus)); dev->dev.dma_mask = &dev->dma_mask; dev->dev.dma_parms = &dev->dma_parms; dev->dev.coherent_dma_mask = 0xffffffffull; @@ -1080,6 +1088,10 @@ unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus) return max; } +void __attribute__((weak)) set_pci_bus_resources_arch_default(struct pci_bus *b) +{ +} + struct pci_bus * pci_create_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata) { @@ -1119,6 +1131,9 @@ struct pci_bus * pci_create_bus(struct device *parent, goto dev_reg_err; b->bridge = get_device(dev); + if (!parent) + set_dev_node(b->bridge, pcibus_to_node(b)); + b->dev.class = &pcibus_class; b->dev.parent = b->bridge; sprintf(b->dev.bus_id, "%04x:%02x", pci_domain_nr(b), bus); @@ -1136,6 +1151,8 @@ struct pci_bus * pci_create_bus(struct device *parent, b->resource[0] = &ioport_resource; b->resource[1] = &iomem_resource; + set_pci_bus_resources_arch_default(b); + return b; dev_create_file_err: diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index ef18fcd641e2..963a97642ae9 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -293,6 +293,7 @@ static int proc_bus_pci_release(struct inode *inode, struct file *file) #endif /* HAVE_PCI_MMAP */ static const struct file_operations proc_bus_pci_operations = { + .owner = THIS_MODULE, .llseek = proc_bus_pci_lseek, .read = proc_bus_pci_read, .write = proc_bus_pci_write, @@ -406,11 +407,10 @@ int pci_proc_attach_device(struct pci_dev *dev) } sprintf(name, "%02x.%x", PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - e = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, bus->procdir); + e = proc_create_data(name, S_IFREG | S_IRUGO | S_IWUSR, bus->procdir, + &proc_bus_pci_operations, dev); if (!e) return -ENOMEM; - e->proc_fops = &proc_bus_pci_operations; - e->data = dev; e->size = dev->cfg_size; dev->procent = e; @@ -462,6 +462,7 @@ static int proc_bus_pci_dev_open(struct inode *inode, struct file *file) return seq_open(file, &proc_bus_pci_devices_op); } static const struct file_operations proc_bus_pci_dev_operations = { + .owner = THIS_MODULE, .open = proc_bus_pci_dev_open, .read = seq_read, .llseek = seq_lseek, @@ -470,12 +471,10 @@ static const struct file_operations proc_bus_pci_dev_operations = { static int __init pci_proc_init(void) { - struct proc_dir_entry *entry; struct pci_dev *dev = NULL; - proc_bus_pci_dir = proc_mkdir("pci", proc_bus); - entry = create_proc_entry("devices", 0, proc_bus_pci_dir); - if (entry) - entry->proc_fops = &proc_bus_pci_dev_operations; + proc_bus_pci_dir = proc_mkdir("bus/pci", NULL); + proc_create("devices", 0, proc_bus_pci_dir, + &proc_bus_pci_dev_operations); proc_initialized = 1; while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_proc_attach_device(dev); diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 06a85d7d5aa2..36379535f9da 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -402,15 +402,6 @@ EXPORT_SYMBOL(pcmcia_replace_cis); ======================================================================*/ -static inline u16 cis_get_u16(void *ptr) -{ - return le16_to_cpu(get_unaligned((__le16 *) ptr)); -} -static inline u32 cis_get_u32(void *ptr) -{ - return le32_to_cpu(get_unaligned((__le32 *) ptr)); -} - typedef struct tuple_flags { u_int link_space:4; u_int has_link:1; @@ -471,7 +462,7 @@ static int follow_link(struct pcmcia_socket *s, tuple_t *tuple) /* Get indirect link from the MFC tuple */ read_cis_cache(s, LINK_SPACE(tuple->Flags), tuple->LinkOffset, 5, link); - ofs = cis_get_u32(link + 1); + ofs = get_unaligned_le32(link + 1); SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR); /* Move to the next indirect link */ tuple->LinkOffset += 5; @@ -679,8 +670,8 @@ static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum) if (tuple->TupleDataLen < 5) return CS_BAD_TUPLE; p = (u_char *) tuple->TupleData; - csum->addr = tuple->CISOffset + cis_get_u16(p) - 2; - csum->len = cis_get_u16(p + 2); + csum->addr = tuple->CISOffset + get_unaligned_le16(p) - 2; + csum->len = get_unaligned_le16(p + 2); csum->sum = *(p + 4); return CS_SUCCESS; } @@ -691,7 +682,7 @@ static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link) { if (tuple->TupleDataLen < 4) return CS_BAD_TUPLE; - link->addr = cis_get_u32(tuple->TupleData); + link->addr = get_unaligned_le32(tuple->TupleData); return CS_SUCCESS; } @@ -710,7 +701,7 @@ static int parse_longlink_mfc(tuple_t *tuple, return CS_BAD_TUPLE; for (i = 0; i < link->nfn; i++) { link->fn[i].space = *p; p++; - link->fn[i].addr = cis_get_u32(p); + link->fn[i].addr = get_unaligned_le32(p); p += 4; } return CS_SUCCESS; @@ -800,8 +791,8 @@ static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m) { if (tuple->TupleDataLen < 4) return CS_BAD_TUPLE; - m->manf = cis_get_u16(tuple->TupleData); - m->card = cis_get_u16(tuple->TupleData + 2); + m->manf = get_unaligned_le16(tuple->TupleData); + m->card = get_unaligned_le16(tuple->TupleData + 2); return CS_SUCCESS; } @@ -1100,7 +1091,7 @@ static int parse_cftable_entry(tuple_t *tuple, break; case 0x20: entry->mem.nwin = 1; - entry->mem.win[0].len = cis_get_u16(p) << 8; + entry->mem.win[0].len = get_unaligned_le16(p) << 8; entry->mem.win[0].card_addr = 0; entry->mem.win[0].host_addr = 0; p += 2; @@ -1108,8 +1099,8 @@ static int parse_cftable_entry(tuple_t *tuple, break; case 0x40: entry->mem.nwin = 1; - entry->mem.win[0].len = cis_get_u16(p) << 8; - entry->mem.win[0].card_addr = cis_get_u16(p + 2) << 8; + entry->mem.win[0].len = get_unaligned_le16(p) << 8; + entry->mem.win[0].card_addr = get_unaligned_le16(p + 2) << 8; entry->mem.win[0].host_addr = 0; p += 4; if (p > q) return CS_BAD_TUPLE; @@ -1146,7 +1137,7 @@ static int parse_bar(tuple_t *tuple, cistpl_bar_t *bar) p = (u_char *)tuple->TupleData; bar->attr = *p; p += 2; - bar->size = cis_get_u32(p); + bar->size = get_unaligned_le32(p); return CS_SUCCESS; } @@ -1159,7 +1150,7 @@ static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config) return CS_BAD_TUPLE; config->last_idx = *(++p); p++; - config->base = cis_get_u32(p); + config->base = get_unaligned_le32(p); config->subtuples = tuple->TupleDataLen - 6; return CS_SUCCESS; } @@ -1275,7 +1266,7 @@ static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2) v2->vers = p[0]; v2->comply = p[1]; - v2->dindex = cis_get_u16(p +2 ); + v2->dindex = get_unaligned_le16(p +2 ); v2->vspec8 = p[6]; v2->vspec9 = p[7]; v2->nhdr = p[8]; @@ -1316,8 +1307,8 @@ static int parse_format(tuple_t *tuple, cistpl_format_t *fmt) fmt->type = p[0]; fmt->edc = p[1]; - fmt->offset = cis_get_u32(p + 2); - fmt->length = cis_get_u32(p + 6); + fmt->offset = get_unaligned_le32(p + 2); + fmt->length = get_unaligned_le32(p + 6); return CS_SUCCESS; } diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index 27523c5f4dad..5f186abca108 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c @@ -787,7 +787,7 @@ void __init pcmcia_setup_ioctl(void) { major_dev = i; #ifdef CONFIG_PROC_FS - proc_pccard = proc_mkdir("pccard", proc_bus); + proc_pccard = proc_mkdir("bus/pccard", NULL); if (proc_pccard) create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL); #endif @@ -798,7 +798,7 @@ void __exit pcmcia_cleanup_ioctl(void) { #ifdef CONFIG_PROC_FS if (proc_pccard) { remove_proc_entry("drivers", proc_pccard); - remove_proc_entry("pccard", proc_bus); + remove_proc_entry("bus/pccard", NULL); } #endif if (major_dev != -1) diff --git a/drivers/pnp/isapnp/proc.c b/drivers/pnp/isapnp/proc.c index 2b8266c3d40f..3f94edab25fa 100644 --- a/drivers/pnp/isapnp/proc.c +++ b/drivers/pnp/isapnp/proc.c @@ -85,6 +85,7 @@ static ssize_t isapnp_proc_bus_read(struct file *file, char __user * buf, } static const struct file_operations isapnp_proc_bus_file_operations = { + .owner = THIS_MODULE, .llseek = isapnp_proc_bus_lseek, .read = isapnp_proc_bus_read, }; @@ -102,12 +103,10 @@ static int isapnp_proc_attach_device(struct pnp_dev *dev) return -ENOMEM; } sprintf(name, "%02x", dev->number); - e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO, de); + e = dev->procent = proc_create_data(name, S_IFREG | S_IRUGO, de, + &isapnp_proc_bus_file_operations, dev); if (!e) return -ENOMEM; - e->proc_fops = &isapnp_proc_bus_file_operations; - e->owner = THIS_MODULE; - e->data = dev; e->size = 256; return 0; } @@ -116,7 +115,7 @@ int __init isapnp_proc_init(void) { struct pnp_dev *dev; - isapnp_proc_bus_dir = proc_mkdir("isapnp", proc_bus); + isapnp_proc_bus_dir = proc_mkdir("bus/isapnp", NULL); protocol_for_each_dev(&isapnp_protocol, dev) { isapnp_proc_attach_device(dev); } diff --git a/drivers/pnp/pnpbios/proc.c b/drivers/pnp/pnpbios/proc.c index bb19bc957bad..46d506f66259 100644 --- a/drivers/pnp/pnpbios/proc.c +++ b/drivers/pnp/pnpbios/proc.c @@ -256,7 +256,7 @@ int pnpbios_interface_attach_device(struct pnp_bios_node *node) */ int __init pnpbios_proc_init(void) { - proc_pnp = proc_mkdir("pnp", proc_bus); + proc_pnp = proc_mkdir("bus/pnp", NULL); if (!proc_pnp) return -EIO; proc_pnp_boot = proc_mkdir("boot", proc_pnp); @@ -294,5 +294,5 @@ void __exit pnpbios_proc_exit(void) remove_proc_entry("configuration_info", proc_pnp); remove_proc_entry("devices", proc_pnp); remove_proc_entry("boot", proc_pnp); - remove_proc_entry("pnp", proc_bus); + remove_proc_entry("bus/pnp", NULL); } diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c index bdb9b7285b3d..71be36f18709 100644 --- a/drivers/power/ds2760_battery.c +++ b/drivers/power/ds2760_battery.c @@ -262,7 +262,7 @@ static void ds2760_battery_work(struct work_struct *work) struct ds2760_device_info, monitor_work.work); const int interval = HZ * 60; - dev_dbg(di->dev, "%s\n", __FUNCTION__); + dev_dbg(di->dev, "%s\n", __func__); ds2760_battery_update_status(di); queue_delayed_work(di->monitor_wqueue, &di->monitor_work, interval); @@ -275,7 +275,7 @@ static void ds2760_battery_external_power_changed(struct power_supply *psy) { struct ds2760_device_info *di = to_ds2760_device_info(psy); - dev_dbg(di->dev, "%s\n", __FUNCTION__); + dev_dbg(di->dev, "%s\n", __func__); cancel_delayed_work(&di->monitor_work); queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ/10); diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c index af7a231092a4..ab1e8289f07f 100644 --- a/drivers/power/olpc_battery.c +++ b/drivers/power/olpc_battery.c @@ -315,7 +315,6 @@ static int __init olpc_bat_init(void) if (ret) goto battery_failed; - olpc_register_battery_callback(&olpc_battery_trigger_uevent); goto success; battery_failed: @@ -328,7 +327,6 @@ success: static void __exit olpc_bat_exit(void) { - olpc_deregister_battery_callback(); power_supply_unregister(&olpc_bat); power_supply_unregister(&olpc_ac); platform_device_unregister(bat_pdev); diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index 03d6a38464ef..138dd76ee347 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c @@ -39,7 +39,7 @@ static void power_supply_changed_work(struct work_struct *work) struct power_supply *psy = container_of(work, struct power_supply, changed_work); - dev_dbg(psy->dev, "%s\n", __FUNCTION__); + dev_dbg(psy->dev, "%s\n", __func__); class_for_each_device(power_supply_class, psy, __power_supply_changed_work); @@ -51,7 +51,7 @@ static void power_supply_changed_work(struct work_struct *work) void power_supply_changed(struct power_supply *psy) { - dev_dbg(psy->dev, "%s\n", __FUNCTION__); + dev_dbg(psy->dev, "%s\n", __func__); schedule_work(&psy->changed_work); } @@ -82,7 +82,7 @@ int power_supply_am_i_supplied(struct power_supply *psy) error = class_for_each_device(power_supply_class, psy, __power_supply_am_i_supplied); - dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, error); + dev_dbg(psy->dev, "%s %d\n", __func__, error); return error; } diff --git a/drivers/power/power_supply_leds.c b/drivers/power/power_supply_leds.c index fa3034f85c38..2dece40c544f 100644 --- a/drivers/power/power_supply_leds.c +++ b/drivers/power/power_supply_leds.c @@ -24,7 +24,7 @@ static void power_supply_update_bat_leds(struct power_supply *psy) if (psy->get_property(psy, POWER_SUPPLY_PROP_STATUS, &status)) return; - dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, status.intval); + dev_dbg(psy->dev, "%s %d\n", __func__, status.intval); switch (status.intval) { case POWER_SUPPLY_STATUS_FULL: @@ -101,7 +101,7 @@ static void power_supply_update_gen_leds(struct power_supply *psy) if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &online)) return; - dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, online.intval); + dev_dbg(psy->dev, "%s %d\n", __func__, online.intval); if (online.intval) led_trigger_event(psy->online_trig, LED_FULL); diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index 4f28045d9ef2..8624f55d0560 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -419,7 +419,7 @@ static int __devinit bfin_rtc_probe(struct platform_device *pdev) return -ENOMEM; rtc->rtc_dev = rtc_device_register(pdev->name, &pdev->dev, &bfin_rtc_ops, THIS_MODULE); - if (unlikely(IS_ERR(rtc))) { + if (IS_ERR(rtc)) { ret = PTR_ERR(rtc->rtc_dev); goto err; } diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index f389a28720d2..bbf97e65202a 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -99,45 +99,38 @@ struct ds1307 { }; struct chip_desc { - char name[9]; unsigned nvram56:1; unsigned alarm:1; - enum ds_type type; }; -static const struct chip_desc chips[] = { { - .name = "ds1307", - .type = ds_1307, +static const struct chip_desc chips[] = { +[ds_1307] = { .nvram56 = 1, -}, { - .name = "ds1337", - .type = ds_1337, +}, +[ds_1337] = { .alarm = 1, -}, { - .name = "ds1338", - .type = ds_1338, +}, +[ds_1338] = { .nvram56 = 1, -}, { - .name = "ds1339", - .type = ds_1339, +}, +[ds_1339] = { .alarm = 1, -}, { - .name = "ds1340", - .type = ds_1340, -}, { - .name = "m41t00", - .type = m41t00, +}, +[ds_1340] = { +}, +[m41t00] = { }, }; -static inline const struct chip_desc *find_chip(const char *s) -{ - unsigned i; - - for (i = 0; i < ARRAY_SIZE(chips); i++) - if (strnicmp(s, chips[i].name, sizeof chips[i].name) == 0) - return &chips[i]; - return NULL; -} +static const struct i2c_device_id ds1307_id[] = { + { "ds1307", ds_1307 }, + { "ds1337", ds_1337 }, + { "ds1338", ds_1338 }, + { "ds1339", ds_1339 }, + { "ds1340", ds_1340 }, + { "m41t00", m41t00 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ds1307_id); static int ds1307_get_time(struct device *dev, struct rtc_time *t) { @@ -326,21 +319,15 @@ static struct bin_attribute nvram = { static struct i2c_driver ds1307_driver; -static int __devinit ds1307_probe(struct i2c_client *client) +static int __devinit ds1307_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct ds1307 *ds1307; int err = -ENODEV; int tmp; - const struct chip_desc *chip; + const struct chip_desc *chip = &chips[id->driver_data]; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); - chip = find_chip(client->name); - if (!chip) { - dev_err(&client->dev, "unknown chip type '%s'\n", - client->name); - return -ENODEV; - } - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) return -EIO; @@ -361,7 +348,7 @@ static int __devinit ds1307_probe(struct i2c_client *client) ds1307->msg[1].len = sizeof(ds1307->regs); ds1307->msg[1].buf = ds1307->regs; - ds1307->type = chip->type; + ds1307->type = id->driver_data; switch (ds1307->type) { case ds_1337: @@ -550,6 +537,7 @@ static struct i2c_driver ds1307_driver = { }, .probe = ds1307_probe, .remove = __devexit_p(ds1307_remove), + .id_table = ds1307_id, }; static int __init ds1307_init(void) diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 45bda186befc..fa2d2f8b3f4d 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -41,6 +41,12 @@ #define DS1374_REG_SR_AF 0x01 /* Alarm Flag */ #define DS1374_REG_TCR 0x09 /* Trickle Charge */ +static const struct i2c_device_id ds1374_id[] = { + { "rtc-ds1374", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ds1374_id); + struct ds1374 { struct i2c_client *client; struct rtc_device *rtc; @@ -355,7 +361,8 @@ static const struct rtc_class_ops ds1374_rtc_ops = { .ioctl = ds1374_ioctl, }; -static int ds1374_probe(struct i2c_client *client) +static int ds1374_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct ds1374 *ds1374; int ret; @@ -429,6 +436,7 @@ static struct i2c_driver ds1374_driver = { }, .probe = ds1374_probe, .remove = __devexit_p(ds1374_remove), + .id_table = ds1374_id, }; static int __init ds1374_init(void) diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index fb15e3fb4ce2..fbb90b1e4098 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -490,7 +490,7 @@ isl1208_sysfs_unregister(struct device *dev) } static int -isl1208_probe(struct i2c_client *client) +isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) { int rc = 0; struct rtc_device *rtc; @@ -545,12 +545,19 @@ isl1208_remove(struct i2c_client *client) return 0; } +static const struct i2c_device_id isl1208_id[] = { + { "isl1208", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, isl1208_id); + static struct i2c_driver isl1208_driver = { .driver = { .name = "rtc-isl1208", }, .probe = isl1208_probe, .remove = isl1208_remove, + .id_table = isl1208_id, }; static int __init diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 1cb33cac1237..316bfaa80872 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -60,48 +60,21 @@ #define DRV_VERSION "0.05" -struct m41t80_chip_info { - const char *name; - u8 features; -}; - -static const struct m41t80_chip_info m41t80_chip_info_tbl[] = { - { - .name = "m41t80", - .features = 0, - }, - { - .name = "m41t81", - .features = M41T80_FEATURE_HT, - }, - { - .name = "m41t81s", - .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, - }, - { - .name = "m41t82", - .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, - }, - { - .name = "m41t83", - .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, - }, - { - .name = "m41st84", - .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, - }, - { - .name = "m41st85", - .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, - }, - { - .name = "m41st87", - .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, - }, +static const struct i2c_device_id m41t80_id[] = { + { "m41t80", 0 }, + { "m41t81", M41T80_FEATURE_HT }, + { "m41t81s", M41T80_FEATURE_HT | M41T80_FEATURE_BL }, + { "m41t82", M41T80_FEATURE_HT | M41T80_FEATURE_BL }, + { "m41t83", M41T80_FEATURE_HT | M41T80_FEATURE_BL }, + { "m41st84", M41T80_FEATURE_HT | M41T80_FEATURE_BL }, + { "m41st85", M41T80_FEATURE_HT | M41T80_FEATURE_BL }, + { "m41st87", M41T80_FEATURE_HT | M41T80_FEATURE_BL }, + { } }; +MODULE_DEVICE_TABLE(i2c, m41t80_id); struct m41t80_data { - const struct m41t80_chip_info *chip; + u8 features; struct rtc_device *rtc; }; @@ -208,7 +181,7 @@ static int m41t80_rtc_proc(struct device *dev, struct seq_file *seq) struct m41t80_data *clientdata = i2c_get_clientdata(client); u8 reg; - if (clientdata->chip->features & M41T80_FEATURE_BL) { + if (clientdata->features & M41T80_FEATURE_BL) { reg = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS); seq_printf(seq, "battery\t\t: %s\n", (reg & M41T80_FLAGS_BATT_LOW) ? "exhausted" : "ok"); @@ -756,12 +729,12 @@ static struct notifier_block wdt_notifier = { * ***************************************************************************** */ -static int m41t80_probe(struct i2c_client *client) +static int m41t80_probe(struct i2c_client *client, + const struct i2c_device_id *id) { - int i, rc = 0; + int rc = 0; struct rtc_device *rtc = NULL; struct rtc_time tm; - const struct m41t80_chip_info *chip; struct m41t80_data *clientdata = NULL; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C @@ -773,19 +746,6 @@ static int m41t80_probe(struct i2c_client *client) dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); - chip = NULL; - for (i = 0; i < ARRAY_SIZE(m41t80_chip_info_tbl); i++) { - if (!strcmp(m41t80_chip_info_tbl[i].name, client->name)) { - chip = &m41t80_chip_info_tbl[i]; - break; - } - } - if (!chip) { - dev_err(&client->dev, "%s is not supported\n", client->name); - rc = -ENODEV; - goto exit; - } - clientdata = kzalloc(sizeof(*clientdata), GFP_KERNEL); if (!clientdata) { rc = -ENOMEM; @@ -801,7 +761,7 @@ static int m41t80_probe(struct i2c_client *client) } clientdata->rtc = rtc; - clientdata->chip = chip; + clientdata->features = id->driver_data; i2c_set_clientdata(client, clientdata); /* Make sure HT (Halt Update) bit is cleared */ @@ -810,7 +770,7 @@ static int m41t80_probe(struct i2c_client *client) goto ht_err; if (rc & M41T80_ALHOUR_HT) { - if (chip->features & M41T80_FEATURE_HT) { + if (clientdata->features & M41T80_FEATURE_HT) { m41t80_get_datetime(client, &tm); dev_info(&client->dev, "HT bit was set!\n"); dev_info(&client->dev, @@ -842,7 +802,7 @@ static int m41t80_probe(struct i2c_client *client) goto exit; #ifdef CONFIG_RTC_DRV_M41T80_WDT - if (chip->features & M41T80_FEATURE_HT) { + if (clientdata->features & M41T80_FEATURE_HT) { rc = misc_register(&wdt_dev); if (rc) goto exit; @@ -878,7 +838,7 @@ static int m41t80_remove(struct i2c_client *client) struct rtc_device *rtc = clientdata->rtc; #ifdef CONFIG_RTC_DRV_M41T80_WDT - if (clientdata->chip->features & M41T80_FEATURE_HT) { + if (clientdata->features & M41T80_FEATURE_HT) { misc_deregister(&wdt_dev); unregister_reboot_notifier(&wdt_notifier); } @@ -896,6 +856,7 @@ static struct i2c_driver m41t80_driver = { }, .probe = m41t80_probe, .remove = m41t80_remove, + .id_table = m41t80_id, }; static int __init m41t80_rtc_init(void) diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index a41681d26eba..0fc4c3630780 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -246,7 +246,8 @@ static const struct rtc_class_ops pcf8563_rtc_ops = { .set_time = pcf8563_rtc_set_time, }; -static int pcf8563_probe(struct i2c_client *client) +static int pcf8563_probe(struct i2c_client *client, + const struct i2c_device_id *id) { struct pcf8563 *pcf8563; @@ -299,12 +300,19 @@ static int pcf8563_remove(struct i2c_client *client) return 0; } +static const struct i2c_device_id pcf8563_id[] = { + { "pcf8563", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pcf8563_id); + static struct i2c_driver pcf8563_driver = { .driver = { .name = "rtc-pcf8563", }, .probe = pcf8563_probe, .remove = pcf8563_remove, + .id_table = pcf8563_id, }; static int __init pcf8563_init(void) diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c index 8d300e6d0d9e..0c6257a034ff 100644 --- a/drivers/rtc/rtc-proc.c +++ b/drivers/rtc/rtc-proc.c @@ -108,12 +108,10 @@ void rtc_proc_add_device(struct rtc_device *rtc) if (rtc->id == 0) { struct proc_dir_entry *ent; - ent = create_proc_entry("driver/rtc", 0, NULL); - if (ent) { - ent->proc_fops = &rtc_proc_fops; + ent = proc_create_data("driver/rtc", 0, NULL, + &rtc_proc_fops, rtc); + if (ent) ent->owner = rtc->owner; - ent->data = rtc; - } } } diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index 7e63074708eb..56caf6b2c3e5 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -69,6 +69,15 @@ enum rtc_type { rtc_rv5c387a, }; +static const struct i2c_device_id rs5c372_id[] = { + { "rs5c372a", rtc_rs5c372a }, + { "rs5c372b", rtc_rs5c372b }, + { "rv5c386", rtc_rv5c386 }, + { "rv5c387a", rtc_rv5c387a }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rs5c372_id); + /* REVISIT: this assumes that: * - we're in the 21st century, so it's safe to ignore the century * bit for rv5c38[67] (REG_MONTH bit 7); @@ -494,7 +503,8 @@ static void rs5c_sysfs_unregister(struct device *dev) static struct i2c_driver rs5c372_driver; -static int rs5c372_probe(struct i2c_client *client) +static int rs5c372_probe(struct i2c_client *client, + const struct i2c_device_id *id) { int err = 0; struct rs5c372 *rs5c372; @@ -514,6 +524,7 @@ static int rs5c372_probe(struct i2c_client *client) rs5c372->client = client; i2c_set_clientdata(client, rs5c372); + rs5c372->type = id->driver_data; /* we read registers 0x0f then 0x00-0x0f; skip the first one */ rs5c372->regs = &rs5c372->buf[1]; @@ -522,19 +533,6 @@ static int rs5c372_probe(struct i2c_client *client) if (err < 0) goto exit_kfree; - if (strcmp(client->name, "rs5c372a") == 0) - rs5c372->type = rtc_rs5c372a; - else if (strcmp(client->name, "rs5c372b") == 0) - rs5c372->type = rtc_rs5c372b; - else if (strcmp(client->name, "rv5c386") == 0) - rs5c372->type = rtc_rv5c386; - else if (strcmp(client->name, "rv5c387a") == 0) - rs5c372->type = rtc_rv5c387a; - else { - rs5c372->type = rtc_rs5c372b; - dev_warn(&client->dev, "assuming rs5c372b\n"); - } - /* clock may be set for am/pm or 24 hr time */ switch (rs5c372->type) { case rtc_rs5c372a: @@ -651,6 +649,7 @@ static struct i2c_driver rs5c372_driver = { }, .probe = rs5c372_probe, .remove = rs5c372_remove, + .id_table = rs5c372_id, }; static __init int rs5c372_init(void) diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c index e8abc90c32c5..29f47bacfc77 100644 --- a/drivers/rtc/rtc-s35390a.c +++ b/drivers/rtc/rtc-s35390a.c @@ -34,6 +34,12 @@ #define S35390A_FLAG_RESET 0x80 #define S35390A_FLAG_TEST 0x01 +static const struct i2c_device_id s35390a_id[] = { + { "s35390a", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, s35390a_id); + struct s35390a { struct i2c_client *client[8]; struct rtc_device *rtc; @@ -195,7 +201,8 @@ static const struct rtc_class_ops s35390a_rtc_ops = { static struct i2c_driver s35390a_driver; -static int s35390a_probe(struct i2c_client *client) +static int s35390a_probe(struct i2c_client *client, + const struct i2c_device_id *id) { int err; unsigned int i; @@ -296,6 +303,7 @@ static struct i2c_driver s35390a_driver = { }, .probe = s35390a_probe, .remove = s35390a_remove, + .id_table = s35390a_id, }; static int __init s35390a_rtc_init(void) diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index 095282f63523..eaf55945f21b 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c @@ -494,7 +494,8 @@ static void x1205_sysfs_unregister(struct device *dev) } -static int x1205_probe(struct i2c_client *client) +static int x1205_probe(struct i2c_client *client, + const struct i2c_device_id *id) { int err = 0; unsigned char sr; @@ -552,12 +553,19 @@ static int x1205_remove(struct i2c_client *client) return 0; } +static const struct i2c_device_id x1205_id[] = { + { "x1205", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, x1205_id); + static struct i2c_driver x1205_driver = { .driver = { .name = "rtc-x1205", }, .probe = x1205_probe, .remove = x1205_remove, + .id_table = x1205_id, }; static int __init x1205_init(void) diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index 556063e8f7a9..03c0e40a92ff 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -157,6 +157,7 @@ static int dasd_devices_open(struct inode *inode, struct file *file) } static const struct file_operations dasd_devices_file_ops = { + .owner = THIS_MODULE, .open = dasd_devices_open, .read = seq_read, .llseek = seq_lseek, @@ -311,17 +312,16 @@ out_error: int dasd_proc_init(void) { - dasd_proc_root_entry = proc_mkdir("dasd", &proc_root); + dasd_proc_root_entry = proc_mkdir("dasd", NULL); if (!dasd_proc_root_entry) goto out_nodasd; dasd_proc_root_entry->owner = THIS_MODULE; - dasd_devices_entry = create_proc_entry("devices", - S_IFREG | S_IRUGO | S_IWUSR, - dasd_proc_root_entry); + dasd_devices_entry = proc_create("devices", + S_IFREG | S_IRUGO | S_IWUSR, + dasd_proc_root_entry, + &dasd_devices_file_ops); if (!dasd_devices_entry) goto out_nodevices; - dasd_devices_entry->proc_fops = &dasd_devices_file_ops; - dasd_devices_entry->owner = THIS_MODULE; dasd_statistics_entry = create_proc_entry("statistics", S_IFREG | S_IRUGO | S_IWUSR, dasd_proc_root_entry); @@ -335,7 +335,7 @@ dasd_proc_init(void) out_nostatistics: remove_proc_entry("devices", dasd_proc_root_entry); out_nodevices: - remove_proc_entry("dasd", &proc_root); + remove_proc_entry("dasd", NULL); out_nodasd: return -ENOENT; } @@ -345,5 +345,5 @@ dasd_proc_exit(void) { remove_proc_entry("devices", dasd_proc_root_entry); remove_proc_entry("statistics", dasd_proc_root_entry); - remove_proc_entry("dasd", &proc_root); + remove_proc_entry("dasd", NULL); } diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 0e1f35c9ed9d..3e5653c92f4b 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -982,15 +982,16 @@ tty3215_write(struct tty_struct * tty, /* * Put character routine for 3215 ttys */ -static void +static int tty3215_put_char(struct tty_struct *tty, unsigned char ch) { struct raw3215_info *raw; if (!tty) - return; + return 0; raw = (struct raw3215_info *) tty->driver_data; raw3215_putchar(raw, ch); + return 1; } static void diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index e3b3d390b4a3..40b11521cd20 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -412,14 +412,14 @@ sclp_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) * - including previous characters from sclp_tty_put_char() and strings from * sclp_write() without final '\n' - will be written. */ -static void +static int sclp_tty_put_char(struct tty_struct *tty, unsigned char ch) { sclp_tty_chars[sclp_tty_chars_count++] = ch; if (ch == '\n' || sclp_tty_chars_count >= SCLP_TTY_BUF_SIZE) { sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count); sclp_tty_chars_count = 0; - } + } return 1; } /* diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index ed507594e62b..35707c04e613 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -524,11 +524,15 @@ sclp_vt220_close(struct tty_struct *tty, struct file *filp) * NOTE: include/linux/tty_driver.h specifies that a character should be * ignored if there is no room in the queue. This driver implements a different * semantic in that it will block when there is no more room left. + * + * FIXME: putchar can currently be called from BH and other non blocking + * handlers so this semantic isn't a good idea. */ -static void +static int sclp_vt220_put_char(struct tty_struct *tty, unsigned char ch) { __sclp_vt220_write(&ch, 1, 0, 0, 1); + return 1; } /* diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c index c9b96d51b28f..e7c888c14e71 100644 --- a/drivers/s390/char/tape_proc.c +++ b/drivers/s390/char/tape_proc.c @@ -111,6 +111,7 @@ static int tape_proc_open(struct inode *inode, struct file *file) static const struct file_operations tape_proc_ops = { + .owner = THIS_MODULE, .open = tape_proc_open, .read = seq_read, .llseek = seq_lseek, @@ -124,14 +125,12 @@ void tape_proc_init(void) { tape_proc_devices = - create_proc_entry ("tapedevices", S_IFREG | S_IRUGO | S_IWUSR, - &proc_root); + proc_create("tapedevices", S_IFREG | S_IRUGO | S_IWUSR, NULL, + &tape_proc_ops); if (tape_proc_devices == NULL) { PRINT_WARN("tape: Cannot register procfs entry tapedevices\n"); return; } - tape_proc_devices->proc_fops = &tape_proc_ops; - tape_proc_devices->owner = THIS_MODULE; } /* @@ -141,5 +140,5 @@ void tape_proc_cleanup(void) { if (tape_proc_devices != NULL) - remove_proc_entry ("tapedevices", &proc_root); + remove_proc_entry ("tapedevices", NULL); } diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index 70b1980a08b6..c1f2adefad41 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -965,7 +965,7 @@ tty3270_write_room(struct tty_struct *tty) * Insert character into the screen at the current position with the * current color and highlight. This function does NOT do cursor movement. */ -static void +static int tty3270_put_character(struct tty3270 *tp, char ch) { struct tty3270_line *line; @@ -986,6 +986,7 @@ tty3270_put_character(struct tty3270 *tp, char ch) cell->character = tp->view.ascebc[(unsigned int) ch]; cell->highlight = tp->highlight; cell->f_color = tp->f_color; + return 1; } /* diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index e8597ec92247..40ef948fcb3a 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -374,13 +374,10 @@ cio_ignore_proc_init (void) { struct proc_dir_entry *entry; - entry = create_proc_entry ("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR, - &proc_root); + entry = proc_create("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR, NULL, + &cio_ignore_proc_fops); if (!entry) return -ENOENT; - - entry->proc_fops = &cio_ignore_proc_fops; - return 0; } diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 10aa1e780801..43876e287370 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -3632,7 +3632,7 @@ qdio_add_procfs_entry(void) { proc_perf_file_registration=0; qdio_perf_proc_file=create_proc_entry(QDIO_PERF, - S_IFREG|0444,&proc_root); + S_IFREG|0444,NULL); if (qdio_perf_proc_file) { qdio_perf_proc_file->read_proc=&qdio_perf_procfile_read; } else proc_perf_file_registration=-1; @@ -3647,7 +3647,7 @@ static void qdio_remove_procfs_entry(void) { if (!proc_perf_file_registration) /* means if it went ok earlier */ - remove_proc_entry(QDIO_PERF,&proc_root); + remove_proc_entry(QDIO_PERF,NULL); } /** diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c index a4e758143665..235703414370 100644 --- a/drivers/sbus/char/cpwatchdog.c +++ b/drivers/sbus/char/cpwatchdog.c @@ -637,7 +637,7 @@ static int wd_inittimer(int whichdog) break; default: printk("%s: %s: invalid watchdog id: %i\n", - WD_OBPNAME, __FUNCTION__, whichdog); + WD_OBPNAME, __func__, whichdog); return(1); } if(0 != misc_register(whichmisc)) diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c index 44d2ef906ac7..383f32c1d347 100644 --- a/drivers/sbus/char/uctrl.c +++ b/drivers/sbus/char/uctrl.c @@ -393,13 +393,13 @@ static int __init ts102_uctrl_init(void) err = request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver); if (err) { printk("%s: unable to register irq %d\n", - __FUNCTION__, driver->irq); + __func__, driver->irq); return err; } if (misc_register(&uctrl_dev)) { printk("%s: unable to get misc minor %d\n", - __FUNCTION__, uctrl_dev.minor); + __func__, uctrl_dev.minor); free_irq(driver->irq, driver); return -ENODEV; } diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index b135a1ed4b2c..18551aaf5e09 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -4996,7 +4996,7 @@ static int __init megaraid_init(void) max_mbox_busy_wait = MBOX_BUSY_WAIT; #ifdef CONFIG_PROC_FS - mega_proc_dir_entry = proc_mkdir("megaraid", &proc_root); + mega_proc_dir_entry = proc_mkdir("megaraid", NULL); if (!mega_proc_dir_entry) { printk(KERN_WARNING "megaraid: failed to create megaraid root\n"); @@ -5005,7 +5005,7 @@ static int __init megaraid_init(void) error = pci_register_driver(&megaraid_pci_driver); if (error) { #ifdef CONFIG_PROC_FS - remove_proc_entry("megaraid", &proc_root); + remove_proc_entry("megaraid", NULL); #endif return error; } @@ -5035,7 +5035,7 @@ static void __exit megaraid_exit(void) pci_unregister_driver(&megaraid_pci_driver); #ifdef CONFIG_PROC_FS - remove_proc_entry("megaraid", &proc_root); + remove_proc_entry("megaraid", NULL); #endif } diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 07103c399fe0..f6600bfb5bde 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -1773,7 +1773,7 @@ static int scsi_debug_slave_alloc(struct scsi_device *sdp) if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n", sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); - set_bit(QUEUE_FLAG_BIDI, &sdp->request_queue->queue_flags); + queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue); return 0; } diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index b8de041bc0ae..a235802f2981 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -449,37 +449,40 @@ int scsi_get_device_flags(struct scsi_device *sdev, } #ifdef CONFIG_SCSI_PROC_FS -/* - * proc_scsi_dev_info_read: dump the scsi_dev_info_list via - * /proc/scsi/device_info - */ -static int proc_scsi_devinfo_read(char *buffer, char **start, - off_t offset, int length) +static int devinfo_seq_show(struct seq_file *m, void *v) { - struct scsi_dev_info_list *devinfo; - int size, len = 0; - off_t begin = 0; - off_t pos = 0; + struct scsi_dev_info_list *devinfo = + list_entry(v, struct scsi_dev_info_list, dev_info_list); - list_for_each_entry(devinfo, &scsi_dev_info_list, dev_info_list) { - size = sprintf(buffer + len, "'%.8s' '%.16s' 0x%x\n", + seq_printf(m, "'%.8s' '%.16s' 0x%x\n", devinfo->vendor, devinfo->model, devinfo->flags); - len += size; - pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - goto stop_output; - } + return 0; +} + +static void * devinfo_seq_start(struct seq_file *m, loff_t *pos) +{ + return seq_list_start(&scsi_dev_info_list, *pos); +} -stop_output: - *start = buffer + (offset - begin); /* Start of wanted data */ - len -= (offset - begin); /* Start slop */ - if (len > length) - len = length; /* Ending slop */ - return (len); +static void * devinfo_seq_next(struct seq_file *m, void *v, loff_t *pos) +{ + return seq_list_next(v, &scsi_dev_info_list, pos); +} + +static void devinfo_seq_stop(struct seq_file *m, void *v) +{ +} + +static const struct seq_operations scsi_devinfo_seq_ops = { + .start = devinfo_seq_start, + .next = devinfo_seq_next, + .stop = devinfo_seq_stop, + .show = devinfo_seq_show, +}; + +static int proc_scsi_devinfo_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &scsi_devinfo_seq_ops); } /* @@ -489,11 +492,12 @@ stop_output: * integer value of flag to the scsi device info list. * To use, echo "vendor:model:flag" > /proc/scsi/device_info */ -static int proc_scsi_devinfo_write(struct file *file, const char __user *buf, - unsigned long length, void *data) +static ssize_t proc_scsi_devinfo_write(struct file *file, + const char __user *buf, + size_t length, loff_t *ppos) { char *buffer; - int err = length; + ssize_t err = length; if (!buf || length>PAGE_SIZE) return -EINVAL; @@ -517,6 +521,15 @@ out: free_page((unsigned long)buffer); return err; } + +static const struct file_operations scsi_devinfo_proc_fops = { + .owner = THIS_MODULE, + .open = proc_scsi_devinfo_open, + .read = seq_read, + .write = proc_scsi_devinfo_write, + .llseek = seq_lseek, + .release = seq_release, +}; #endif /* CONFIG_SCSI_PROC_FS */ module_param_string(dev_flags, scsi_dev_flags, sizeof(scsi_dev_flags), 0); @@ -577,15 +590,13 @@ int __init scsi_init_devinfo(void) } #ifdef CONFIG_SCSI_PROC_FS - p = create_proc_entry("scsi/device_info", 0, NULL); + p = proc_create("scsi/device_info", 0, NULL, &scsi_devinfo_proc_fops); if (!p) { error = -ENOMEM; goto out; } p->owner = THIS_MODULE; - p->get_info = proc_scsi_devinfo_read; - p->write_proc = proc_scsi_devinfo_write; #endif /* CONFIG_SCSI_PROC_FS */ out: diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 221f31e36d26..1eaba6cd80f4 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1771,6 +1771,7 @@ scsi_reset_provider(struct scsi_device *dev, int flag) unsigned long flags; int rtn; + blk_rq_init(NULL, &req); scmd->request = &req; memset(&scmd->eh_timeout, 0, sizeof(scmd->eh_timeout)); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 67f412bb4974..d545ad1cf47a 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -536,6 +536,9 @@ static void scsi_run_queue(struct request_queue *q) !shost->host_blocked && !shost->host_self_blocked && !((shost->can_queue > 0) && (shost->host_busy >= shost->can_queue))) { + + int flagset; + /* * As long as shost is accepting commands and we have * starved queues, call blk_run_queue. scsi_request_fn @@ -549,19 +552,20 @@ static void scsi_run_queue(struct request_queue *q) sdev = list_entry(shost->starved_list.next, struct scsi_device, starved_entry); list_del_init(&sdev->starved_entry); - spin_unlock_irqrestore(shost->host_lock, flags); - + spin_unlock(shost->host_lock); + + spin_lock(sdev->request_queue->queue_lock); + flagset = test_bit(QUEUE_FLAG_REENTER, &q->queue_flags) && + !test_bit(QUEUE_FLAG_REENTER, + &sdev->request_queue->queue_flags); + if (flagset) + queue_flag_set(QUEUE_FLAG_REENTER, sdev->request_queue); + __blk_run_queue(sdev->request_queue); + if (flagset) + queue_flag_clear(QUEUE_FLAG_REENTER, sdev->request_queue); + spin_unlock(sdev->request_queue->queue_lock); - if (test_bit(QUEUE_FLAG_REENTER, &q->queue_flags) && - !test_and_set_bit(QUEUE_FLAG_REENTER, - &sdev->request_queue->queue_flags)) { - blk_run_queue(sdev->request_queue); - clear_bit(QUEUE_FLAG_REENTER, - &sdev->request_queue->queue_flags); - } else - blk_run_queue(sdev->request_queue); - - spin_lock_irqsave(shost->host_lock, flags); + spin_lock(shost->host_lock); if (unlikely(!list_empty(&sdev->starved_entry))) /* * sdev lost a race, and was put back on the @@ -1585,8 +1589,9 @@ struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost, blk_queue_max_segment_size(q, dma_get_max_seg_size(dev)); + /* New queue, no concurrency on queue_flags */ if (!shost->use_clustering) - clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags); + queue_flag_clear_unlocked(QUEUE_FLAG_CLUSTER, q); /* * set a reasonable default alignment on word boundaries: the diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index 3a1c99d5c775..e4a0d2f9b357 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -413,6 +413,7 @@ static int proc_scsi_open(struct inode *inode, struct file *file) } static const struct file_operations proc_scsi_operations = { + .owner = THIS_MODULE, .open = proc_scsi_open, .read = seq_read, .write = proc_scsi_write, @@ -431,10 +432,9 @@ int __init scsi_init_procfs(void) if (!proc_scsi) goto err1; - pde = create_proc_entry("scsi/scsi", 0, NULL); + pde = proc_create("scsi/scsi", 0, NULL, &proc_scsi_operations); if (!pde) goto err2; - pde->proc_fops = &proc_scsi_operations; return 0; diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index fcd7455ffc39..a00eee6f7be9 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1828,7 +1828,7 @@ void scsi_scan_host(struct Scsi_Host *shost) } p = kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no); - if (unlikely(IS_ERR(p))) + if (IS_ERR(p)) do_scan_async(data); } EXPORT_SYMBOL(scsi_scan_host); diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 7899e3dda9bf..f4461d35ffb9 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -248,8 +248,7 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy) else q->queuedata = shost; - set_bit(QUEUE_FLAG_BIDI, &q->queue_flags); - + queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q); return 0; } diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 3cea17dd5dba..01cefbb2d539 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -860,7 +860,6 @@ static int sd_sync_cache(struct scsi_disk *sdkp) static void sd_prepare_flush(struct request_queue *q, struct request *rq) { - memset(rq->cmd, 0, sizeof(rq->cmd)); rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->timeout = SD_TIMEOUT; rq->cmd[0] = SYNCHRONIZE_CACHE; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 2029422bc04d..c9d7f721b9e2 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -2667,7 +2667,6 @@ sg_proc_init(void) { int k, mask; int num_leaves = ARRAY_SIZE(sg_proc_leaf_arr); - struct proc_dir_entry *pdep; struct sg_proc_leaf * leaf; sg_proc_sgp = proc_mkdir(sg_proc_sg_dirname, NULL); @@ -2676,13 +2675,10 @@ sg_proc_init(void) for (k = 0; k < num_leaves; ++k) { leaf = &sg_proc_leaf_arr[k]; mask = leaf->fops->write ? S_IRUGO | S_IWUSR : S_IRUGO; - pdep = create_proc_entry(leaf->name, mask, sg_proc_sgp); - if (pdep) { - leaf->fops->owner = THIS_MODULE, - leaf->fops->read = seq_read, - leaf->fops->llseek = seq_lseek, - pdep->proc_fops = leaf->fops; - } + leaf->fops->owner = THIS_MODULE; + leaf->fops->read = seq_read; + leaf->fops->llseek = seq_lseek; + proc_create(leaf->name, mask, sg_proc_sgp, leaf->fops); } return 0; } diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c index 2b8a410e0959..bbf5bc5892c7 100644 --- a/drivers/serial/68328serial.c +++ b/drivers/serial/68328serial.c @@ -200,7 +200,7 @@ static void rs_stop(struct tty_struct *tty) local_irq_restore(flags); } -static void rs_put_char(char ch) +static int rs_put_char(char ch) { int flags, loops = 0; @@ -214,6 +214,7 @@ static void rs_put_char(char ch) UTX_TXDATA = ch; udelay(5); local_irq_restore(flags); + return 1; } static void rs_start(struct tty_struct *tty) @@ -1017,18 +1018,6 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, tty_wait_until_sent(tty, 0); send_break(info, arg ? arg*(100) : 250); return 0; - case TIOCGSOFTCAR: - error = put_user(C_CLOCAL(tty) ? 1 : 0, - (unsigned long *) arg); - if (error) - return error; - return 0; - case TIOCSSOFTCAR: - get_user(arg, (unsigned long *) arg); - tty->termios->c_cflag = - ((tty->termios->c_cflag & ~CLOCAL) | - (arg ? CLOCAL : 0)); - return 0; case TIOCGSERIAL: if (access_ok(VERIFY_WRITE, (void *) arg, sizeof(struct serial_struct))) @@ -1061,9 +1050,6 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct m68k_serial *info = (struct m68k_serial *)tty->driver_data; - if (tty->termios->c_cflag == old_termios->c_cflag) - return; - change_speed(info); if ((old_termios->c_cflag & CRTSCTS) && @@ -1140,8 +1126,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp) uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK); shutdown(info); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + rs_flush_buffer(tty); tty_ldisc_flush(tty); tty->closing = 0; diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c index f59463601874..d9d4e9552a4d 100644 --- a/drivers/serial/68360serial.c +++ b/drivers/serial/68360serial.c @@ -995,10 +995,10 @@ static void rs_360_put_char(struct tty_struct *tty, unsigned char ch) volatile QUICC_BD *bdp; if (serial_paranoia_check(info, tty->name, "rs_put_char")) - return; + return 0; if (!tty) - return; + return 0; bdp = info->tx_cur; while (bdp->status & BD_SC_READY); @@ -1016,6 +1016,7 @@ static void rs_360_put_char(struct tty_struct *tty, unsigned char ch) bdp++; info->tx_cur = (QUICC_BD *)bdp; + return 1; } @@ -1246,7 +1247,7 @@ static int rs_360_tiocmget(struct tty_struct *tty, struct file *file) #ifdef modem_control unsigned char control, status; - if (serial_paranoia_check(info, tty->name, __FUNCTION__)) + if (serial_paranoia_check(info, tty->name, __func__)) return -ENODEV; if (tty->flags & (1 << TTY_IO_ERROR)) @@ -1277,12 +1278,12 @@ static int rs_360_tiocmset(struct tty_struct *tty, struct file *file, ser_info_t *info = (ser_info_t *)tty->driver_data; unsigned int arg; - if (serial_paranoia_check(info, tty->name, __FUNCTION__)) + if (serial_paranoia_check(info, tty->name, __func__)) return -ENODEV; if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; - + /* FIXME: locking on info->mcr */ if (set & TIOCM_RTS) info->mcr |= UART_MCR_RTS; if (set & TIOCM_DTR) @@ -1436,18 +1437,6 @@ static int rs_360_ioctl(struct tty_struct *tty, struct file * file, return retval; end_break(info); return 0; - case TIOCGSOFTCAR: - /* return put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg); */ - put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg); - return 0; - case TIOCSSOFTCAR: - error = get_user(arg, (unsigned int *) arg); - if (error) - return error; - tty->termios->c_cflag = - ((tty->termios->c_cflag & ~CLOCAL) | - (arg ? CLOCAL : 0)); - return 0; #ifdef maybe case TIOCSERGETLSR: /* Get line status register */ return get_lsr_info(info, (unsigned int *) arg); @@ -1665,8 +1654,7 @@ static void rs_360_close(struct tty_struct *tty, struct file * filp) rs_360_wait_until_sent(tty, info->timeout); } shutdown(info); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + rs_360_flush_buffer(tty); tty_ldisc_flush(tty); tty->closing = 0; info->event = 0; @@ -1717,6 +1705,7 @@ static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout) printk("jiff=%lu...", jiffies); #endif + lock_kernel(); /* We go through the loop at least once because we can't tell * exactly when the last character exits the shifter. There can * be at least two characters waiting to be sent after the buffers @@ -1745,6 +1734,7 @@ static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout) bdp--; } while (bdp->status & BD_SC_READY); current->state = TASK_RUNNING; + unlock_kernel(); #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); #endif diff --git a/drivers/serial/8250_early.c b/drivers/serial/8250_early.c index 38776e8b064b..cd898704ba4f 100644 --- a/drivers/serial/8250_early.c +++ b/drivers/serial/8250_early.c @@ -156,7 +156,7 @@ static int __init parse_options(struct early_serial8250_device *device, port->membase = ioremap(port->mapbase, 64); if (!port->membase) { printk(KERN_ERR "%s: Couldn't ioremap 0x%llx\n", - __FUNCTION__, + __func__, (unsigned long long)port->mapbase); return -ENOMEM; } diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 34b809e3b596..36acbcca2d48 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -1355,4 +1355,47 @@ config SERIAL_SC26XX_CONSOLE help Support for Console on SC2681/SC2692 serial ports. +config SERIAL_BFIN_SPORT + tristate "Blackfin SPORT emulate UART (EXPERIMENTAL)" + depends on BFIN && EXPERIMENTAL + select SERIAL_CORE + help + Enble support SPORT emulate UART on Blackfin series. + + To compile this driver as a module, choose M here: the + module will be called bfin_sport_uart. + +choice + prompt "Baud rate for Blackfin SPORT UART" + depends on SERIAL_BFIN_SPORT + default SERIAL_SPORT_BAUD_RATE_57600 + help + Choose a baud rate for the SPORT UART, other uart settings are + 8 bit, 1 stop bit, no parity, no flow control. + +config SERIAL_SPORT_BAUD_RATE_115200 + bool "115200" + +config SERIAL_SPORT_BAUD_RATE_57600 + bool "57600" + +config SERIAL_SPORT_BAUD_RATE_38400 + bool "38400" + +config SERIAL_SPORT_BAUD_RATE_19200 + bool "19200" + +config SERIAL_SPORT_BAUD_RATE_9600 + bool "9600" +endchoice + +config SPORT_BAUD_RATE + int + depends on SERIAL_BFIN_SPORT + default 115200 if (SERIAL_SPORT_BAUD_RATE_115200) + default 57600 if (SERIAL_SPORT_BAUD_RATE_57600) + default 38400 if (SERIAL_SPORT_BAUD_RATE_38400) + default 19200 if (SERIAL_SPORT_BAUD_RATE_19200) + default 9600 if (SERIAL_SPORT_BAUD_RATE_9600) + endmenu diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index f02ff9fad017..0d9c09b1e836 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_SERIAL_PXA) += pxa.o obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o obj-$(CONFIG_SERIAL_SA1100) += sa1100.o obj-$(CONFIG_SERIAL_BFIN) += bfin_5xx.o +obj-$(CONFIG_SERIAL_BFIN_SPORT) += bfin_sport_uart.o obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c index 5f55534a290b..8a2f6a1baa74 100644 --- a/drivers/serial/bfin_5xx.c +++ b/drivers/serial/bfin_5xx.c @@ -762,7 +762,7 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios, break; default: printk(KERN_ERR "%s: word lengh not supported\n", - __FUNCTION__); + __func__); } if (termios->c_cflag & CSTOPB) @@ -1029,7 +1029,7 @@ bfin_serial_console_get_options(struct bfin_serial_port *uart, int *baud, *baud = get_sclk() / (16*(dll | dlh << 8)); } - pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __FUNCTION__, *baud, *parity, *bits); + pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __func__, *baud, *parity, *bits); } #endif diff --git a/drivers/serial/bfin_sport_uart.c b/drivers/serial/bfin_sport_uart.c new file mode 100644 index 000000000000..aca1240ad808 --- /dev/null +++ b/drivers/serial/bfin_sport_uart.c @@ -0,0 +1,614 @@ +/* + * File: linux/drivers/serial/bfin_sport_uart.c + * + * Based on: drivers/serial/bfin_5xx.c by Aubrey Li. + * Author: Roy Huang <roy.huang@analog.com> + * + * Created: Nov 22, 2006 + * Copyright: (c) 2006-2007 Analog Devices Inc. + * Description: this driver enable SPORTs on Blackfin emulate UART. + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * This driver and the hardware supported are in term of EE-191 of ADI. + * http://www.analog.com/UploadedFiles/Application_Notes/399447663EE191.pdf + * This application note describe how to implement a UART on a Sharc DSP, + * but this driver is implemented on Blackfin Processor. + */ + +/* After reset, there is a prelude of low level pulse when transmit data first + * time. No addtional pulse in following transmit. + * According to document: + * The SPORTs are ready to start transmitting or receiving data no later than + * three serial clock cycles after they are enabled in the SPORTx_TCR1 or + * SPORTx_RCR1 register. No serial clock cycles are lost from this point on. + * The first internal frame sync will occur one frame sync delay after the + * SPORTs are ready. External frame syncs can occur as soon as the SPORT is + * ready. + */ + +/* Thanks to Axel Alatalo <axel@rubico.se> for fixing sport rx bug. Sometimes + * sport receives data incorrectly. The following is Axel's words. + * As EE-191, sport rx samples 3 times of the UART baudrate and takes the + * middle smaple of every 3 samples as the data bit. For a 8-N-1 UART setting, + * 30 samples will be required for a byte. If transmitter sends a 1/3 bit short + * byte due to buadrate drift, then the 30th sample of a byte, this sample is + * also the third sample of the stop bit, will happens on the immediately + * following start bit which will be thrown away and missed. Thus since parts + * of the startbit will be missed and the receiver will begin to drift, the + * effect accumulates over time until synchronization is lost. + * If only require 2 samples of the stopbit (by sampling in total 29 samples), + * then a to short byte as in the case above will be tolerated. Then the 1/3 + * early startbit will trigger a framesync since the last read is complete + * after only 2/3 stopbit and framesync is active during the last 1/3 looking + * for a possible early startbit. */ + +//#define DEBUG + +#include <linux/module.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/console.h> +#include <linux/sysrq.h> +#include <linux/platform_device.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/serial_core.h> + +#include <asm/delay.h> +#include <asm/portmux.h> + +#include "bfin_sport_uart.h" + +unsigned short bfin_uart_pin_req_sport0[] = + {P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, \ + P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0}; + +unsigned short bfin_uart_pin_req_sport1[] = + {P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, \ + P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0}; + +#define DRV_NAME "bfin-sport-uart" + +struct sport_uart_port { + struct uart_port port; + char *name; + + int tx_irq; + int rx_irq; + int err_irq; +}; + +static void sport_uart_tx_chars(struct sport_uart_port *up); +static void sport_stop_tx(struct uart_port *port); + +static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value) +{ + pr_debug("%s value:%x\n", __FUNCTION__, value); + /* Place a Start and Stop bit */ + __asm__ volatile ( + "R2 = b#01111111100;\n\t" + "R3 = b#10000000001;\n\t" + "%0 <<= 2;\n\t" + "%0 = %0 & R2;\n\t" + "%0 = %0 | R3;\n\t" + :"=r"(value) + :"0"(value) + :"R2", "R3"); + pr_debug("%s value:%x\n", __FUNCTION__, value); + + SPORT_PUT_TX(up, value); +} + +static inline unsigned int rx_one_byte(struct sport_uart_port *up) +{ + unsigned int value, extract; + + value = SPORT_GET_RX32(up); + pr_debug("%s value:%x\n", __FUNCTION__, value); + + /* Extract 8 bits data */ + __asm__ volatile ( + "R5 = 0;\n\t" + "P0 = 8;\n\t" + "R1 = 0x1801(Z);\n\t" + "R3 = 0x0300(Z);\n\t" + "R4 = 0;\n\t" + "LSETUP(loop_s, loop_e) LC0 = P0;\nloop_s:\t" + "R2 = extract(%1, R1.L)(Z);\n\t" + "R2 <<= R4;\n\t" + "R5 = R5 | R2;\n\t" + "R1 = R1 - R3;\nloop_e:\t" + "R4 += 1;\n\t" + "%0 = R5;\n\t" + :"=r"(extract) + :"r"(value) + :"P0", "R1", "R2","R3","R4", "R5"); + + pr_debug(" extract:%x\n", extract); + return extract; +} + +static int sport_uart_setup(struct sport_uart_port *up, int sclk, int baud_rate) +{ + int tclkdiv, tfsdiv, rclkdiv; + + /* Set TCR1 and TCR2 */ + SPORT_PUT_TCR1(up, (LTFS | ITFS | TFSR | TLSBIT | ITCLK)); + SPORT_PUT_TCR2(up, 10); + pr_debug("%s TCR1:%x, TCR2:%x\n", __FUNCTION__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up)); + + /* Set RCR1 and RCR2 */ + SPORT_PUT_RCR1(up, (RCKFE | LARFS | LRFS | RFSR | IRCLK)); + SPORT_PUT_RCR2(up, 28); + pr_debug("%s RCR1:%x, RCR2:%x\n", __FUNCTION__, SPORT_GET_RCR1(up), SPORT_GET_RCR2(up)); + + tclkdiv = sclk/(2 * baud_rate) - 1; + tfsdiv = 12; + rclkdiv = sclk/(2 * baud_rate * 3) - 1; + SPORT_PUT_TCLKDIV(up, tclkdiv); + SPORT_PUT_TFSDIV(up, tfsdiv); + SPORT_PUT_RCLKDIV(up, rclkdiv); + SSYNC(); + pr_debug("%s sclk:%d, baud_rate:%d, tclkdiv:%d, tfsdiv:%d, rclkdiv:%d\n", + __FUNCTION__, sclk, baud_rate, tclkdiv, tfsdiv, rclkdiv); + + return 0; +} + +static irqreturn_t sport_uart_rx_irq(int irq, void *dev_id) +{ + struct sport_uart_port *up = dev_id; + struct tty_struct *tty = up->port.info->tty; + unsigned int ch; + + do { + ch = rx_one_byte(up); + up->port.icount.rx++; + + if (uart_handle_sysrq_char(&up->port, ch)) + ; + else + tty_insert_flip_char(tty, ch, TTY_NORMAL); + } while (SPORT_GET_STAT(up) & RXNE); + tty_flip_buffer_push(tty); + + return IRQ_HANDLED; +} + +static irqreturn_t sport_uart_tx_irq(int irq, void *dev_id) +{ + sport_uart_tx_chars(dev_id); + + return IRQ_HANDLED; +} + +static irqreturn_t sport_uart_err_irq(int irq, void *dev_id) +{ + struct sport_uart_port *up = dev_id; + struct tty_struct *tty = up->port.info->tty; + unsigned int stat = SPORT_GET_STAT(up); + + /* Overflow in RX FIFO */ + if (stat & ROVF) { + up->port.icount.overrun++; + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + SPORT_PUT_STAT(up, ROVF); /* Clear ROVF bit */ + } + /* These should not happen */ + if (stat & (TOVF | TUVF | RUVF)) { + printk(KERN_ERR "SPORT Error:%s %s %s\n", + (stat & TOVF)?"TX overflow":"", + (stat & TUVF)?"TX underflow":"", + (stat & RUVF)?"RX underflow":""); + SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN); + SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) & ~RSPEN); + } + SSYNC(); + + return IRQ_HANDLED; +} + +/* Reqeust IRQ, Setup clock */ +static int sport_startup(struct uart_port *port) +{ + struct sport_uart_port *up = (struct sport_uart_port *)port; + char buffer[20]; + int retval; + + pr_debug("%s enter\n", __FUNCTION__); + memset(buffer, 20, '\0'); + snprintf(buffer, 20, "%s rx", up->name); + retval = request_irq(up->rx_irq, sport_uart_rx_irq, IRQF_SAMPLE_RANDOM, buffer, up); + if (retval) { + printk(KERN_ERR "Unable to request interrupt %s\n", buffer); + return retval; + } + + snprintf(buffer, 20, "%s tx", up->name); + retval = request_irq(up->tx_irq, sport_uart_tx_irq, IRQF_SAMPLE_RANDOM, buffer, up); + if (retval) { + printk(KERN_ERR "Unable to request interrupt %s\n", buffer); + goto fail1; + } + + snprintf(buffer, 20, "%s err", up->name); + retval = request_irq(up->err_irq, sport_uart_err_irq, IRQF_SAMPLE_RANDOM, buffer, up); + if (retval) { + printk(KERN_ERR "Unable to request interrupt %s\n", buffer); + goto fail2; + } + + if (port->line) { + if (peripheral_request_list(bfin_uart_pin_req_sport1, DRV_NAME)) + goto fail3; + } else { + if (peripheral_request_list(bfin_uart_pin_req_sport0, DRV_NAME)) + goto fail3; + } + + sport_uart_setup(up, get_sclk(), port->uartclk); + + /* Enable receive interrupt */ + SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) | RSPEN)); + SSYNC(); + + return 0; + + +fail3: + printk(KERN_ERR DRV_NAME + ": Requesting Peripherals failed\n"); + + free_irq(up->err_irq, up); +fail2: + free_irq(up->tx_irq, up); +fail1: + free_irq(up->rx_irq, up); + + return retval; + +} + +static void sport_uart_tx_chars(struct sport_uart_port *up) +{ + struct circ_buf *xmit = &up->port.info->xmit; + + if (SPORT_GET_STAT(up) & TXF) + return; + + if (up->port.x_char) { + tx_one_byte(up, up->port.x_char); + up->port.icount.tx++; + up->port.x_char = 0; + return; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { + sport_stop_tx(&up->port); + return; + } + + while(!(SPORT_GET_STAT(up) & TXF) && !uart_circ_empty(xmit)) { + tx_one_byte(up, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1); + up->port.icount.tx++; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&up->port); +} + +static unsigned int sport_tx_empty(struct uart_port *port) +{ + struct sport_uart_port *up = (struct sport_uart_port *)port; + unsigned int stat; + + stat = SPORT_GET_STAT(up); + pr_debug("%s stat:%04x\n", __FUNCTION__, stat); + if (stat & TXHRE) { + return TIOCSER_TEMT; + } else + return 0; +} + +static unsigned int sport_get_mctrl(struct uart_port *port) +{ + pr_debug("%s enter\n", __FUNCTION__); + return (TIOCM_CTS | TIOCM_CD | TIOCM_DSR); +} + +static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + pr_debug("%s enter\n", __FUNCTION__); +} + +static void sport_stop_tx(struct uart_port *port) +{ + struct sport_uart_port *up = (struct sport_uart_port *)port; + unsigned int stat; + + pr_debug("%s enter\n", __FUNCTION__); + + stat = SPORT_GET_STAT(up); + while(!(stat & TXHRE)) { + udelay(1); + stat = SPORT_GET_STAT(up); + } + /* Although the hold register is empty, last byte is still in shift + * register and not sent out yet. If baud rate is lower than default, + * delay should be longer. For example, if the baud rate is 9600, + * the delay must be at least 2ms by experience */ + udelay(500); + + SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN)); + SSYNC(); + + return; +} + +static void sport_start_tx(struct uart_port *port) +{ + struct sport_uart_port *up = (struct sport_uart_port *)port; + + pr_debug("%s enter\n", __FUNCTION__); + /* Write data into SPORT FIFO before enable SPROT to transmit */ + sport_uart_tx_chars(up); + + /* Enable transmit, then an interrupt will generated */ + SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN)); + SSYNC(); + pr_debug("%s exit\n", __FUNCTION__); +} + +static void sport_stop_rx(struct uart_port *port) +{ + struct sport_uart_port *up = (struct sport_uart_port *)port; + + pr_debug("%s enter\n", __FUNCTION__); + /* Disable sport to stop rx */ + SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) & ~RSPEN)); + SSYNC(); +} + +static void sport_enable_ms(struct uart_port *port) +{ + pr_debug("%s enter\n", __FUNCTION__); +} + +static void sport_break_ctl(struct uart_port *port, int break_state) +{ + pr_debug("%s enter\n", __FUNCTION__); +} + +static void sport_shutdown(struct uart_port *port) +{ + struct sport_uart_port *up = (struct sport_uart_port *)port; + + pr_debug("%s enter\n", __FUNCTION__); + + /* Disable sport */ + SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN)); + SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) & ~RSPEN)); + SSYNC(); + + if (port->line) { + peripheral_free_list(bfin_uart_pin_req_sport1); + } else { + peripheral_free_list(bfin_uart_pin_req_sport0); + } + + free_irq(up->rx_irq, up); + free_irq(up->tx_irq, up); + free_irq(up->err_irq, up); +} + +static void sport_set_termios(struct uart_port *port, + struct termios *termios, struct termios *old) +{ + pr_debug("%s enter, c_cflag:%08x\n", __FUNCTION__, termios->c_cflag); + uart_update_timeout(port, CS8 ,port->uartclk); +} + +static const char *sport_type(struct uart_port *port) +{ + struct sport_uart_port *up = (struct sport_uart_port *)port; + + pr_debug("%s enter\n", __FUNCTION__); + return up->name; +} + +static void sport_release_port(struct uart_port *port) +{ + pr_debug("%s enter\n", __FUNCTION__); +} + +static int sport_request_port(struct uart_port *port) +{ + pr_debug("%s enter\n", __FUNCTION__); + return 0; +} + +static void sport_config_port(struct uart_port *port, int flags) +{ + struct sport_uart_port *up = (struct sport_uart_port *)port; + + pr_debug("%s enter\n", __FUNCTION__); + up->port.type = PORT_BFIN_SPORT; +} + +static int sport_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + pr_debug("%s enter\n", __FUNCTION__); + return 0; +} + +struct uart_ops sport_uart_ops = { + .tx_empty = sport_tx_empty, + .set_mctrl = sport_set_mctrl, + .get_mctrl = sport_get_mctrl, + .stop_tx = sport_stop_tx, + .start_tx = sport_start_tx, + .stop_rx = sport_stop_rx, + .enable_ms = sport_enable_ms, + .break_ctl = sport_break_ctl, + .startup = sport_startup, + .shutdown = sport_shutdown, + .set_termios = sport_set_termios, + .type = sport_type, + .release_port = sport_release_port, + .request_port = sport_request_port, + .config_port = sport_config_port, + .verify_port = sport_verify_port, +}; + +static struct sport_uart_port sport_uart_ports[] = { + { /* SPORT 0 */ + .name = "SPORT0", + .tx_irq = IRQ_SPORT0_TX, + .rx_irq = IRQ_SPORT0_RX, + .err_irq= IRQ_SPORT0_ERROR, + .port = { + .type = PORT_BFIN_SPORT, + .iotype = UPIO_MEM, + .membase = (void __iomem *)SPORT0_TCR1, + .mapbase = SPORT0_TCR1, + .irq = IRQ_SPORT0_RX, + .uartclk = CONFIG_SPORT_BAUD_RATE, + .fifosize = 8, + .ops = &sport_uart_ops, + .line = 0, + }, + }, { /* SPORT 1 */ + .name = "SPORT1", + .tx_irq = IRQ_SPORT1_TX, + .rx_irq = IRQ_SPORT1_RX, + .err_irq= IRQ_SPORT1_ERROR, + .port = { + .type = PORT_BFIN_SPORT, + .iotype = UPIO_MEM, + .membase = (void __iomem *)SPORT1_TCR1, + .mapbase = SPORT1_TCR1, + .irq = IRQ_SPORT1_RX, + .uartclk = CONFIG_SPORT_BAUD_RATE, + .fifosize = 8, + .ops = &sport_uart_ops, + .line = 1, + }, + } +}; + +static struct uart_driver sport_uart_reg = { + .owner = THIS_MODULE, + .driver_name = "SPORT-UART", + .dev_name = "ttySS", + .major = 204, + .minor = 84, + .nr = ARRAY_SIZE(sport_uart_ports), + .cons = NULL, +}; + +static int sport_uart_suspend(struct platform_device *dev, pm_message_t state) +{ + struct sport_uart_port *sport = platform_get_drvdata(dev); + + pr_debug("%s enter\n", __FUNCTION__); + if (sport) + uart_suspend_port(&sport_uart_reg, &sport->port); + + return 0; +} + +static int sport_uart_resume(struct platform_device *dev) +{ + struct sport_uart_port *sport = platform_get_drvdata(dev); + + pr_debug("%s enter\n", __FUNCTION__); + if (sport) + uart_resume_port(&sport_uart_reg, &sport->port); + + return 0; +} + +static int sport_uart_probe(struct platform_device *dev) +{ + pr_debug("%s enter\n", __FUNCTION__); + sport_uart_ports[dev->id].port.dev = &dev->dev; + uart_add_one_port(&sport_uart_reg, &sport_uart_ports[dev->id].port); + platform_set_drvdata(dev, &sport_uart_ports[dev->id]); + + return 0; +} + +static int sport_uart_remove(struct platform_device *dev) +{ + struct sport_uart_port *sport = platform_get_drvdata(dev); + + pr_debug("%s enter\n", __FUNCTION__); + platform_set_drvdata(dev, NULL); + + if (sport) + uart_remove_one_port(&sport_uart_reg, &sport->port); + + return 0; +} + +static struct platform_driver sport_uart_driver = { + .probe = sport_uart_probe, + .remove = sport_uart_remove, + .suspend = sport_uart_suspend, + .resume = sport_uart_resume, + .driver = { + .name = DRV_NAME, + }, +}; + +static int __init sport_uart_init(void) +{ + int ret; + + pr_debug("%s enter\n", __FUNCTION__); + ret = uart_register_driver(&sport_uart_reg); + if (ret != 0) { + printk(KERN_ERR "Failed to register %s:%d\n", + sport_uart_reg.driver_name, ret); + return ret; + } + + ret = platform_driver_register(&sport_uart_driver); + if (ret != 0) { + printk(KERN_ERR "Failed to register sport uart driver:%d\n", ret); + uart_unregister_driver(&sport_uart_reg); + } + + + pr_debug("%s exit\n", __FUNCTION__); + return ret; +} + +static void __exit sport_uart_exit(void) +{ + pr_debug("%s enter\n", __FUNCTION__); + platform_driver_unregister(&sport_uart_driver); + uart_unregister_driver(&sport_uart_reg); +} + +module_init(sport_uart_init); +module_exit(sport_uart_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/serial/bfin_sport_uart.h b/drivers/serial/bfin_sport_uart.h new file mode 100644 index 000000000000..671d41cc1a3f --- /dev/null +++ b/drivers/serial/bfin_sport_uart.h @@ -0,0 +1,63 @@ +/* + * File: linux/drivers/serial/bfin_sport_uart.h + * + * Based on: include/asm-blackfin/mach-533/bfin_serial_5xx.h + * Author: Roy Huang <roy.huang>analog.com> + * + * Created: Nov 22, 2006 + * Copyright: (C) Analog Device Inc. + * Description: this driver enable SPORTs on Blackfin emulate UART. + * + * 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, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#define OFFSET_TCR1 0x00 /* Transmit Configuration 1 Register */ +#define OFFSET_TCR2 0x04 /* Transmit Configuration 2 Register */ +#define OFFSET_TCLKDIV 0x08 /* Transmit Serial Clock Divider Register */ +#define OFFSET_TFSDIV 0x0C /* Transmit Frame Sync Divider Register */ +#define OFFSET_TX 0x10 /* Transmit Data Register */ +#define OFFSET_RX 0x18 /* Receive Data Register */ +#define OFFSET_RCR1 0x20 /* Receive Configuration 1 Register */ +#define OFFSET_RCR2 0x24 /* Receive Configuration 2 Register */ +#define OFFSET_RCLKDIV 0x28 /* Receive Serial Clock Divider Register */ +#define OFFSET_RFSDIV 0x2c /* Receive Frame Sync Divider Register */ +#define OFFSET_STAT 0x30 /* Status Register */ + +#define SPORT_GET_TCR1(sport) bfin_read16(((sport)->port.membase + OFFSET_TCR1)) +#define SPORT_GET_TCR2(sport) bfin_read16(((sport)->port.membase + OFFSET_TCR2)) +#define SPORT_GET_TCLKDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_TCLKDIV)) +#define SPORT_GET_TFSDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_TFSDIV)) +#define SPORT_GET_TX(sport) bfin_read16(((sport)->port.membase + OFFSET_TX)) +#define SPORT_GET_RX(sport) bfin_read16(((sport)->port.membase + OFFSET_RX)) +#define SPORT_GET_RX32(sport) bfin_read32(((sport)->port.membase + OFFSET_RX)) +#define SPORT_GET_RCR1(sport) bfin_read16(((sport)->port.membase + OFFSET_RCR1)) +#define SPORT_GET_RCR2(sport) bfin_read16(((sport)->port.membase + OFFSET_RCR2)) +#define SPORT_GET_RCLKDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_RCLKDIV)) +#define SPORT_GET_RFSDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_RFSDIV)) +#define SPORT_GET_STAT(sport) bfin_read16(((sport)->port.membase + OFFSET_STAT)) + +#define SPORT_PUT_TCR1(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TCR1), v) +#define SPORT_PUT_TCR2(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TCR2), v) +#define SPORT_PUT_TCLKDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TCLKDIV), v) +#define SPORT_PUT_TFSDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TFSDIV), v) +#define SPORT_PUT_TX(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TX), v) +#define SPORT_PUT_RX(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RX), v) +#define SPORT_PUT_RCR1(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RCR1), v) +#define SPORT_PUT_RCR2(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RCR2), v) +#define SPORT_PUT_RCLKDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RCLKDIV), v) +#define SPORT_PUT_RFSDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RFSDIV), v) +#define SPORT_PUT_STAT(sport, v) bfin_write16(((sport)->port.membase + OFFSET_STAT), v) diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index a638ba0679ac..a19dc7ef8861 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -1117,7 +1117,7 @@ int cpm_uart_drv_get_platform_data(struct platform_device *pdev, int is_con) line = cpm_uart_id2nr(idx); if(line < 0) { - printk(KERN_ERR"%s(): port %d is not registered", __FUNCTION__, idx); + printk(KERN_ERR"%s(): port %d is not registered", __func__, idx); return -EINVAL; } diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c index 88e7c1d5b919..f9fa237aa949 100644 --- a/drivers/serial/crisv10.c +++ b/drivers/serial/crisv10.c @@ -1788,7 +1788,7 @@ static unsigned int handle_descr_data(struct e100_serial *info, if (info->recv_cnt + recvl > 65536) { printk(KERN_CRIT - "%s: Too much pending incoming serial data! Dropping %u bytes.\n", __FUNCTION__, recvl); + "%s: Too much pending incoming serial data! Dropping %u bytes.\n", __func__, recvl); return 0; } @@ -1801,7 +1801,7 @@ static unsigned int handle_descr_data(struct e100_serial *info, append_recv_buffer(info, buffer); if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE))) - panic("%s: Failed to allocate memory for receive buffer!\n", __FUNCTION__); + panic("%s: Failed to allocate memory for receive buffer!\n", __func__); descr->buf = virt_to_phys(buffer->buffer); @@ -1925,7 +1925,7 @@ static int start_recv_dma(struct e100_serial *info) /* Set up the receiving descriptors */ for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) { if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE))) - panic("%s: Failed to allocate memory for receive buffer!\n", __FUNCTION__); + panic("%s: Failed to allocate memory for receive buffer!\n", __func__); descr[i].ctrl = d_int; descr[i].buf = virt_to_phys(buffer->buffer); @@ -3581,8 +3581,9 @@ rs_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear) { struct e100_serial *info = (struct e100_serial *)tty->driver_data; + unsigned long flags; - lock_kernel(); + local_irq_save(flags); if (clear & TIOCM_RTS) e100_rts(info, 0); @@ -3604,7 +3605,7 @@ rs_tiocmset(struct tty_struct *tty, struct file *file, if (set & TIOCM_CD) e100_cd_out(info, 1); - unlock_kernel(); + local_irq_restore(flags); return 0; } @@ -3613,8 +3614,10 @@ rs_tiocmget(struct tty_struct *tty, struct file *file) { struct e100_serial *info = (struct e100_serial *)tty->driver_data; unsigned int result; + unsigned long flags; + + local_irq_save(flags); - lock_kernel(); result = (!E100_RTS_GET(info) ? TIOCM_RTS : 0) | (!E100_DTR_GET(info) ? TIOCM_DTR : 0) @@ -3623,7 +3626,7 @@ rs_tiocmget(struct tty_struct *tty, struct file *file) | (!E100_CD_GET(info) ? TIOCM_CAR : 0) | (!E100_CTS_GET(info) ? TIOCM_CTS : 0); - unlock_kernel(); + local_irq_restore(flags); #ifdef SERIAL_DEBUG_IO printk(KERN_DEBUG "ser%i: modem state: %i 0x%08X\n", @@ -3702,10 +3705,6 @@ rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct e100_serial *info = (struct e100_serial *)tty->driver_data; - if (tty->termios->c_cflag == old_termios->c_cflag && - tty->termios->c_iflag == old_termios->c_iflag) - return; - change_speed(info); /* Handle turning off CRTSCTS */ @@ -3808,10 +3807,8 @@ rs_close(struct tty_struct *tty, struct file * filp) #endif shutdown(info); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + rs_flush_buffer(tty); + tty_ldisc_flush_buffer(tty); tty->closing = 0; info->event = 0; info->tty = 0; @@ -3885,6 +3882,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) * Check R_DMA_CHx_STATUS bit 0-6=number of available bytes in FIFO * R_DMA_CHx_HWSW bit 31-16=nbr of bytes left in DMA buffer (0=64k) */ + lock_kernel(); orig_jiffies = jiffies; while (info->xmit.head != info->xmit.tail || /* More in send queue */ (*info->ostatusadr & 0x007f) || /* more in FIFO */ @@ -3901,6 +3899,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) curr_time_usec - info->last_tx_active_usec; } set_current_state(TASK_RUNNING); + unlock_kernel(); } /* @@ -4520,7 +4519,7 @@ rs_init(void) if (request_irq(SERIAL_IRQ_NBR, ser_interrupt, IRQF_SHARED | IRQF_DISABLED, "serial ", driver)) - panic("%s: Failed to request irq8", __FUNCTION__); + panic("%s: Failed to request irq8", __func__); #endif #endif /* CONFIG_SVINTO_SIM */ diff --git a/drivers/serial/ioc3_serial.c b/drivers/serial/ioc3_serial.c index 168073f12cec..4f1af71e9a1b 100644 --- a/drivers/serial/ioc3_serial.c +++ b/drivers/serial/ioc3_serial.c @@ -52,7 +52,7 @@ static unsigned int Submodule_slot; #define DPRINT_CONFIG(_x...) ; //#define DPRINT_CONFIG(_x...) printk _x #define NOT_PROGRESS() ; -//#define NOT_PROGRESS() printk("%s : fails %d\n", __FUNCTION__, __LINE__) +//#define NOT_PROGRESS() printk("%s : fails %d\n", __func__, __LINE__) /* number of characters we want to transmit to the lower level at a time */ #define MAX_CHARS 256 @@ -445,7 +445,7 @@ static int inline port_init(struct ioc3_port *port) sbbr_h = &idd->vma->sbbr_h; ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf; DPRINT_CONFIG(("%s: ring_pci_addr 0x%p\n", - __FUNCTION__, (void *)ring_pci_addr)); + __func__, (void *)ring_pci_addr)); writel((unsigned int)((uint64_t) ring_pci_addr >> 32), sbbr_h); writel((unsigned int)ring_pci_addr | BUF_SIZE_BIT, sbbr_l); @@ -593,7 +593,7 @@ config_port(struct ioc3_port *port, DPRINT_CONFIG(("%s: line %d baud %d byte_size %d stop %d parenb %d " "parodd %d\n", - __FUNCTION__, ((struct uart_port *)port->ip_port)->line, + __func__, ((struct uart_port *)port->ip_port)->line, baud, byte_size, stop_bits, parenb, parodd)); if (set_baud(port, baud)) @@ -871,14 +871,14 @@ static int ioc3_set_proto(struct ioc3_port *port, int proto) default: case PROTO_RS232: /* Clear the appropriate GIO pin */ - DPRINT_CONFIG(("%s: rs232\n", __FUNCTION__)); + DPRINT_CONFIG(("%s: rs232\n", __func__)); writel(0, (&port->ip_idd->vma->gppr[0] + hooks->rs422_select_pin)); break; case PROTO_RS422: /* Set the appropriate GIO pin */ - DPRINT_CONFIG(("%s: rs422\n", __FUNCTION__)); + DPRINT_CONFIG(("%s: rs422\n", __func__)); writel(1, (&port->ip_idd->vma->gppr[0] + hooks->rs422_select_pin)); break; @@ -988,7 +988,7 @@ ioc3_change_speed(struct uart_port *the_port, } baud = uart_get_baud_rate(the_port, new_termios, old_termios, MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED); - DPRINT_CONFIG(("%s: returned baud %d for line %d\n", __FUNCTION__, baud, + DPRINT_CONFIG(("%s: returned baud %d for line %d\n", __func__, baud, the_port->line)); if (!the_port->fifosize) @@ -1026,7 +1026,7 @@ ioc3_change_speed(struct uart_port *the_port, DPRINT_CONFIG(("%s : port 0x%p line %d cflag 0%o " "config_port(baud %d data %d stop %d penable %d " " parity %d), notification 0x%x\n", - __FUNCTION__, (void *)port, the_port->line, cflag, baud, + __func__, (void *)port, the_port->line, cflag, baud, new_data, new_stop, new_parity_enable, new_parity, the_port->ignore_status_mask)); @@ -1919,7 +1919,7 @@ static inline int ioc3_serial_core_attach( struct ioc3_submodule *is, struct pci_dev *pdev = idd->pdev; DPRINT_CONFIG(("%s: attach pdev 0x%p - card_ptr 0x%p\n", - __FUNCTION__, pdev, (void *)card_ptr)); + __func__, pdev, (void *)card_ptr)); if (!card_ptr) return -ENODEV; @@ -1933,7 +1933,7 @@ static inline int ioc3_serial_core_attach( struct ioc3_submodule *is, port->ip_port = the_port; DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p [%d/%d]\n", - __FUNCTION__, (void *)the_port, (void *)port, + __func__, (void *)the_port, (void *)port, phys_port, ii)); /* membase, iobase and mapbase just need to be non-0 */ @@ -1950,7 +1950,7 @@ static inline int ioc3_serial_core_attach( struct ioc3_submodule *is, if (uart_add_one_port(&ioc3_uart, the_port) < 0) { printk(KERN_WARNING "%s: unable to add port %d bus %d\n", - __FUNCTION__, the_port->line, pdev->bus->number); + __func__, the_port->line, pdev->bus->number); } else { DPRINT_CONFIG(("IOC3 serial port %d irq %d bus %d\n", the_port->line, the_port->irq, pdev->bus->number)); @@ -2017,7 +2017,7 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd) struct ioc3_port *ports[PORTS_PER_CARD]; int phys_port; - DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, is, idd)); + DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, is, idd)); card_ptr = kzalloc(sizeof(struct ioc3_card), GFP_KERNEL); if (!card_ptr) { @@ -2067,7 +2067,7 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd) DPRINT_CONFIG(("%s : Port A ip_serial_regs 0x%p " "ip_uart_regs 0x%p\n", - __FUNCTION__, + __func__, (void *)port->ip_serial_regs, (void *)port->ip_uart_regs)); @@ -2082,7 +2082,7 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd) DPRINT_CONFIG(("%s : Port A ip_cpu_ringbuf 0x%p " "ip_dma_ringbuf 0x%p, ip_inring 0x%p " "ip_outring 0x%p\n", - __FUNCTION__, + __func__, (void *)port->ip_cpu_ringbuf, (void *)port->ip_dma_ringbuf, (void *)port->ip_inring, @@ -2094,7 +2094,7 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd) DPRINT_CONFIG(("%s : Port B ip_serial_regs 0x%p " "ip_uart_regs 0x%p\n", - __FUNCTION__, + __func__, (void *)port->ip_serial_regs, (void *)port->ip_uart_regs)); @@ -2108,7 +2108,7 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd) DPRINT_CONFIG(("%s : Port B ip_cpu_ringbuf 0x%p " "ip_dma_ringbuf 0x%p, ip_inring 0x%p " "ip_outring 0x%p\n", - __FUNCTION__, + __func__, (void *)port->ip_cpu_ringbuf, (void *)port->ip_dma_ringbuf, (void *)port->ip_inring, @@ -2116,7 +2116,7 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd) } DPRINT_CONFIG(("%s : port %d [addr 0x%p] card_ptr 0x%p", - __FUNCTION__, + __func__, phys_port, (void *)port, (void *)card_ptr)); DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n", (void *)port->ip_serial_regs, @@ -2127,7 +2127,7 @@ ioc3uart_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd) DPRINT_CONFIG(("%s: phys_port %d port 0x%p inring 0x%p " "outring 0x%p\n", - __FUNCTION__, + __func__, phys_port, (void *)port, (void *)port->ip_inring, (void *)port->ip_outring)); @@ -2170,7 +2170,7 @@ static int __devinit ioc3uart_init(void) if ((ret = uart_register_driver(&ioc3_uart)) < 0) { printk(KERN_WARNING "%s: Couldn't register IOC3 uart serial driver\n", - __FUNCTION__); + __func__); return ret; } ret = ioc3_register_submodule(&ioc3uart_submodule); diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c index 0c179384fb0c..49b8a82b7b9f 100644 --- a/drivers/serial/ioc4_serial.c +++ b/drivers/serial/ioc4_serial.c @@ -889,7 +889,7 @@ static int inline port_init(struct ioc4_port *port) ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf; DPRINT_CONFIG(("%s: ring_pci_addr 0x%lx\n", - __FUNCTION__, ring_pci_addr)); + __func__, ring_pci_addr)); writel((unsigned int)((uint64_t)ring_pci_addr >> 32), sbbr_h); writel((unsigned int)ring_pci_addr | IOC4_BUF_SIZE_BIT, sbbr_l); @@ -1028,7 +1028,7 @@ static irqreturn_t ioc4_intr(int irq, void *arg) spin_lock_irqsave(&soft->is_ir_lock, flag); printk ("%s : %d : mem 0x%p sio_ir 0x%x sio_ies 0x%x " "other_ir 0x%x other_ies 0x%x mask 0x%x\n", - __FUNCTION__, __LINE__, + __func__, __LINE__, (void *)mem, readl(&mem->sio_ir.raw), readl(&mem->sio_ies.raw), readl(&mem->other_ir.raw), @@ -1155,14 +1155,14 @@ static int inline ioc4_attach_local(struct ioc4_driver_data *idd) (TOTAL_RING_BUF_SIZE - 1)) == 0)); DPRINT_CONFIG(("%s : ip_cpu_ringbuf 0x%p " "ip_dma_ringbuf 0x%p\n", - __FUNCTION__, + __func__, (void *)port->ip_cpu_ringbuf, (void *)port->ip_dma_ringbuf)); port->ip_inring = RING(port, RX_0_OR_2); port->ip_outring = RING(port, TX_0_OR_2); } DPRINT_CONFIG(("%s : port %d [addr 0x%p] control 0x%p", - __FUNCTION__, + __func__, port_number, (void *)port, (void *)control)); DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n", (void *)port->ip_serial_regs, @@ -1173,7 +1173,7 @@ static int inline ioc4_attach_local(struct ioc4_driver_data *idd) DPRINT_CONFIG(("%s: port_number %d port 0x%p inring 0x%p " "outring 0x%p\n", - __FUNCTION__, + __func__, port_number, (void *)port, (void *)port->ip_inring, (void *)port->ip_outring)); @@ -1317,7 +1317,7 @@ config_port(struct ioc4_port *port, int spiniter = 0; DPRINT_CONFIG(("%s: baud %d byte_size %d stop %d parenb %d parodd %d\n", - __FUNCTION__, baud, byte_size, stop_bits, parenb, parodd)); + __func__, baud, byte_size, stop_bits, parenb, parodd)); if (set_baud(port, baud)) return 1; @@ -1725,7 +1725,7 @@ ioc4_change_speed(struct uart_port *the_port, } baud = uart_get_baud_rate(the_port, new_termios, old_termios, MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED); - DPRINT_CONFIG(("%s: returned baud %d\n", __FUNCTION__, baud)); + DPRINT_CONFIG(("%s: returned baud %d\n", __func__, baud)); /* default is 9600 */ if (!baud) @@ -1765,7 +1765,7 @@ ioc4_change_speed(struct uart_port *the_port, DPRINT_CONFIG(("%s : port 0x%p cflag 0%o " "config_port(baud %d data %d stop %d p enable %d parity %d)," " notification 0x%x\n", - __FUNCTION__, (void *)port, cflag, baud, new_data, new_stop, + __func__, (void *)port, cflag, baud, new_data, new_stop, new_parity_enable, new_parity, the_port->ignore_status_mask)); if ((config_port(port, baud, /* baud */ @@ -2715,7 +2715,7 @@ ioc4_serial_core_attach(struct pci_dev *pdev, int port_type) DPRINT_CONFIG(("%s: attach pdev 0x%p - control 0x%p\n", - __FUNCTION__, pdev, (void *)control)); + __func__, pdev, (void *)control)); if (!control) return -ENODEV; @@ -2734,7 +2734,7 @@ ioc4_serial_core_attach(struct pci_dev *pdev, int port_type) port->ip_all_ports[port_type_idx] = the_port; DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p : type %s\n", - __FUNCTION__, (void *)the_port, + __func__, (void *)the_port, (void *)port, port_type == PROTO_RS232 ? "rs232" : "rs422")); @@ -2752,7 +2752,7 @@ ioc4_serial_core_attach(struct pci_dev *pdev, int port_type) if (uart_add_one_port(u_driver, the_port) < 0) { printk(KERN_WARNING "%s: unable to add port %d bus %d\n", - __FUNCTION__, the_port->line, pdev->bus->number); + __func__, the_port->line, pdev->bus->number); } else { DPRINT_CONFIG( ("IOC4 serial port %d irq = %d, bus %d\n", @@ -2777,7 +2777,7 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd) int ret = 0; - DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, idd->idd_pdev, + DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, idd->idd_pdev, idd->idd_pci_id)); /* PCI-RT does not bring out serial connections. @@ -2806,7 +2806,7 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd) goto out2; } DPRINT_CONFIG(("%s : mem 0x%p, serial 0x%p\n", - __FUNCTION__, (void *)idd->idd_misc_regs, + __func__, (void *)idd->idd_misc_regs, (void *)serial)); /* Get memory for the new card */ @@ -2858,7 +2858,7 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd) } else { printk(KERN_WARNING "%s : request_irq fails for IRQ 0x%x\n ", - __FUNCTION__, idd->idd_pdev->irq); + __func__, idd->idd_pdev->irq); } ret = ioc4_attach_local(idd); if (ret) @@ -2911,13 +2911,13 @@ int ioc4_serial_init(void) if ((ret = uart_register_driver(&ioc4_uart_rs232)) < 0) { printk(KERN_WARNING "%s: Couldn't register rs232 IOC4 serial driver\n", - __FUNCTION__); + __func__); return ret; } if ((ret = uart_register_driver(&ioc4_uart_rs422)) < 0) { printk(KERN_WARNING "%s: Couldn't register rs422 IOC4 serial driver\n", - __FUNCTION__); + __func__); return ret; } diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c index 9cf03327386a..eadc1ab6bbce 100644 --- a/drivers/serial/kgdboc.c +++ b/drivers/serial/kgdboc.c @@ -96,12 +96,14 @@ static void cleanup_kgdboc(void) static int kgdboc_get_char(void) { - return kgdb_tty_driver->poll_get_char(kgdb_tty_driver, kgdb_tty_line); + return kgdb_tty_driver->ops->poll_get_char(kgdb_tty_driver, + kgdb_tty_line); } static void kgdboc_put_char(u8 chr) { - kgdb_tty_driver->poll_put_char(kgdb_tty_driver, kgdb_tty_line, chr); + kgdb_tty_driver->ops->poll_put_char(kgdb_tty_driver, + kgdb_tty_line, chr); } static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp) diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c index ddd3aa50d4ad..43af40d59b8a 100644 --- a/drivers/serial/mcfserial.c +++ b/drivers/serial/mcfserial.c @@ -1072,18 +1072,6 @@ static int mcfrs_ioctl(struct tty_struct *tty, struct file * file, tty_wait_until_sent(tty, 0); send_break(info, arg ? arg*(HZ/10) : HZ/4); return 0; - case TIOCGSOFTCAR: - error = put_user(C_CLOCAL(tty) ? 1 : 0, - (unsigned long *) arg); - if (error) - return error; - return 0; - case TIOCSSOFTCAR: - get_user(arg, (unsigned long *) arg); - tty->termios->c_cflag = - ((tty->termios->c_cflag & ~CLOCAL) | - (arg ? CLOCAL : 0)); - return 0; case TIOCGSERIAL: if (access_ok(VERIFY_WRITE, (void *) arg, sizeof(struct serial_struct))) @@ -1222,8 +1210,7 @@ static void mcfrs_close(struct tty_struct *tty, struct file * filp) } else #endif shutdown(info); - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + mcfrs_flush_buffer(tty); tty_ldisc_flush(tty); tty->closing = 0; @@ -1276,6 +1263,8 @@ mcfrs_wait_until_sent(struct tty_struct *tty, int timeout) * Note: we have to use pretty tight timings here to satisfy * the NIST-PCTS. */ + lock_kernel(); + fifo_time = (MCF5272_FIFO_SIZE * HZ * 10) / info->baud; char_time = fifo_time / 5; if (char_time == 0) @@ -1312,6 +1301,7 @@ mcfrs_wait_until_sent(struct tty_struct *tty, int timeout) if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; } + unlock_kernel(); #else /* * For the other coldfire models, assume all data has been sent @@ -1907,7 +1897,7 @@ static struct tty_driver *mcfrs_console_device(struct console *c, int *index) * This is used for console output. */ -void mcfrs_put_char(char ch) +int mcfrs_put_char(char ch) { volatile unsigned char *uartp; unsigned long flags; @@ -1931,7 +1921,7 @@ void mcfrs_put_char(char ch) mcfrs_init_console(); /* try and get it back */ local_irq_restore(flags); - return; + return 1; } diff --git a/drivers/serial/netx-serial.c b/drivers/serial/netx-serial.c index 3123ffeac8ad..81ac9bb4f39b 100644 --- a/drivers/serial/netx-serial.c +++ b/drivers/serial/netx-serial.c @@ -287,6 +287,7 @@ static void netx_set_mctrl(struct uart_port *port, unsigned int mctrl) { unsigned int val; + /* FIXME: Locking needed ? */ if (mctrl & TIOCM_RTS) { val = readl(port->membase + UART_RTS_CR); writel(val | RTS_CR_RTS, port->membase + UART_RTS_CR); diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c index 4ffa2585429a..2b6a013639e6 100644 --- a/drivers/serial/s3c2410.c +++ b/drivers/serial/s3c2410.c @@ -1022,6 +1022,7 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, struct uart_port *port = &ourport->port; struct s3c2410_uartcfg *cfg; struct resource *res; + int ret; dbg("s3c24xx_serial_init_port: port=%p, platdev=%p\n", port, platdev); @@ -1064,9 +1065,11 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, port->mapbase = res->start; port->membase = S3C24XX_VA_UART + (res->start - S3C24XX_PA_UART); - port->irq = platform_get_irq(platdev, 0); - if (port->irq < 0) + ret = platform_get_irq(platdev, 0); + if (ret < 0) port->irq = 0; + else + port->irq = ret; ourport->clk = clk_get(&platdev->dev, "uart"); @@ -1093,13 +1096,13 @@ static int s3c24xx_serial_probe(struct platform_device *dev, ourport = &s3c24xx_serial_ports[probe_index]; probe_index++; - dbg("%s: initialising port %p...\n", __FUNCTION__, ourport); + dbg("%s: initialising port %p...\n", __func__, ourport); ret = s3c24xx_serial_init_port(ourport, info, dev); if (ret < 0) goto probe_err; - dbg("%s: adding port\n", __FUNCTION__); + dbg("%s: adding port\n", __func__); uart_add_one_port(&s3c24xx_uart_drv, &ourport->port); platform_set_drvdata(dev, &ourport->port); @@ -1584,7 +1587,7 @@ static int s3c2412_serial_resetport(struct uart_port *port, unsigned long ucon = rd_regl(port, S3C2410_UCON); dbg("%s: port=%p (%08lx), cfg=%p\n", - __FUNCTION__, port, port->mapbase, cfg); + __func__, port, port->mapbase, cfg); /* ensure we don't change the clock settings... */ diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c index 67b2338913c2..62b38582f5e9 100644 --- a/drivers/serial/sa1100.c +++ b/drivers/serial/sa1100.c @@ -655,7 +655,7 @@ void __init sa1100_register_uart_fns(struct sa1100_port_fns *fns) void __init sa1100_register_uart(int idx, int port) { if (idx >= NR_PORTS) { - printk(KERN_ERR "%s: bad index number %d\n", __FUNCTION__, idx); + printk(KERN_ERR "%s: bad index number %d\n", __func__, idx); return; } @@ -682,7 +682,7 @@ void __init sa1100_register_uart(int idx, int port) break; default: - printk(KERN_ERR "%s: bad port number %d\n", __FUNCTION__, port); + printk(KERN_ERR "%s: bad port number %d\n", __func__, port); } } diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 977ce820ce30..1e2b9d826f69 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -422,6 +422,7 @@ uart_get_divisor(struct uart_port *port, unsigned int baud) EXPORT_SYMBOL(uart_get_divisor); +/* FIXME: Consistent locking policy */ static void uart_change_speed(struct uart_state *state, struct ktermios *old_termios) { @@ -454,27 +455,30 @@ uart_change_speed(struct uart_state *state, struct ktermios *old_termios) port->ops->set_termios(port, termios, old_termios); } -static inline void +static inline int __uart_put_char(struct uart_port *port, struct circ_buf *circ, unsigned char c) { unsigned long flags; + int ret = 0; if (!circ->buf) - return; + return 0; spin_lock_irqsave(&port->lock, flags); if (uart_circ_chars_free(circ) != 0) { circ->buf[circ->head] = c; circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1); + ret = 1; } spin_unlock_irqrestore(&port->lock, flags); + return ret; } -static void uart_put_char(struct tty_struct *tty, unsigned char ch) +static int uart_put_char(struct tty_struct *tty, unsigned char ch) { struct uart_state *state = tty->driver_data; - __uart_put_char(state->port, &state->info->xmit, ch); + return __uart_put_char(state->port, &state->info->xmit, ch); } static void uart_flush_chars(struct tty_struct *tty) @@ -528,15 +532,25 @@ uart_write(struct tty_struct *tty, const unsigned char *buf, int count) static int uart_write_room(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; + unsigned long flags; + int ret; - return uart_circ_chars_free(&state->info->xmit); + spin_lock_irqsave(&state->port->lock, flags); + ret = uart_circ_chars_free(&state->info->xmit); + spin_unlock_irqrestore(&state->port->lock, flags); + return ret; } static int uart_chars_in_buffer(struct tty_struct *tty) { struct uart_state *state = tty->driver_data; + unsigned long flags; + int ret; - return uart_circ_chars_pending(&state->info->xmit); + spin_lock_irqsave(&state->port->lock, flags); + ret = uart_circ_chars_pending(&state->info->xmit); + spin_unlock_irqrestore(&state->port->lock, flags); + return ret; } static void uart_flush_buffer(struct tty_struct *tty) @@ -618,6 +632,11 @@ static int uart_get_info(struct uart_state *state, struct serial_struct tmp; memset(&tmp, 0, sizeof(tmp)); + + /* Ensure the state we copy is consistent and no hardware changes + occur as we go */ + mutex_lock(&state->mutex); + tmp.type = port->type; tmp.line = port->line; tmp.port = port->iobase; @@ -637,6 +656,8 @@ static int uart_get_info(struct uart_state *state, tmp.iomem_reg_shift = port->regshift; tmp.iomem_base = (void *)(unsigned long)port->mapbase; + mutex_unlock(&state->mutex); + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) return -EFAULT; return 0; @@ -914,8 +935,6 @@ static void uart_break_ctl(struct tty_struct *tty, int break_state) struct uart_state *state = tty->driver_data; struct uart_port *port = state->port; - BUG_ON(!kernel_locked()); - mutex_lock(&state->mutex); if (port->type != PORT_UNKNOWN) @@ -1059,7 +1078,7 @@ static int uart_get_count(struct uart_state *state, } /* - * Called via sys_ioctl under the BKL. We can use spin_lock_irq() here. + * Called via sys_ioctl. We can use spin_lock_irq() here. */ static int uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, @@ -1069,7 +1088,6 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, void __user *uarg = (void __user *)arg; int ret = -ENOIOCTLCMD; - BUG_ON(!kernel_locked()); /* * These ioctls don't rely on the hardware to be present. @@ -1140,9 +1158,9 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, break; } } - out_up: +out_up: mutex_unlock(&state->mutex); - out: +out: return ret; } @@ -1153,7 +1171,6 @@ static void uart_set_termios(struct tty_struct *tty, unsigned long flags; unsigned int cflag = tty->termios->c_cflag; - BUG_ON(!kernel_locked()); /* * These are the bits that are used to setup various @@ -1165,8 +1182,9 @@ static void uart_set_termios(struct tty_struct *tty, if ((cflag ^ old_termios->c_cflag) == 0 && tty->termios->c_ospeed == old_termios->c_ospeed && tty->termios->c_ispeed == old_termios->c_ispeed && - RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) + RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) { return; + } uart_change_speed(state, old_termios); @@ -1200,7 +1218,6 @@ static void uart_set_termios(struct tty_struct *tty, } spin_unlock_irqrestore(&state->port->lock, flags); } - #if 0 /* * No need to wake up processes in open wait, since they @@ -1316,11 +1333,11 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout) struct uart_port *port = state->port; unsigned long char_time, expire; - BUG_ON(!kernel_locked()); - if (port->type == PORT_UNKNOWN || port->fifosize == 0) return; + lock_kernel(); + /* * Set the check interval to be 1/5 of the estimated time to * send a single character, and make it at least 1. The check @@ -1366,6 +1383,7 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout) break; } set_current_state(TASK_RUNNING); /* might not be needed */ + unlock_kernel(); } /* @@ -2079,7 +2097,9 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port) int ret; uart_change_pm(state, 0); + spin_lock_irq(&port->lock); ops->set_mctrl(port, 0); + spin_unlock_irq(&port->lock); ret = ops->startup(port); if (ret == 0) { uart_change_speed(state, NULL); diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index c2ea5d4df44a..969106187718 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -855,7 +855,7 @@ static int sci_notifier(struct notifier_block *self, printk(KERN_INFO "%s: got a postchange notification " "for cpu %d (old %d, new %d)\n", - __FUNCTION__, freqs->cpu, freqs->old, freqs->new); + __func__, freqs->cpu, freqs->old, freqs->new); } return NOTIFY_OK; diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c index 41fc61264443..019da2e05f0b 100644 --- a/drivers/serial/sn_console.c +++ b/drivers/serial/sn_console.c @@ -839,7 +839,7 @@ static int __init sn_sal_module_init(void) if (uart_add_one_port(&sal_console_uart, &sal_console_port.sc_port) < 0) { /* error - not sure what I'd do - so I'll do nothing */ - printk(KERN_ERR "%s: unable to add port\n", __FUNCTION__); + printk(KERN_ERR "%s: unable to add port\n", __func__); } /* when this driver is compiled in, the console initialization diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index b565d5a37499..b51c24245be4 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -584,7 +584,7 @@ ulite_of_probe(struct of_device *op, const struct of_device_id *match) const unsigned int *id; int irq, rc; - dev_dbg(&op->dev, "%s(%p, %p)\n", __FUNCTION__, op, match); + dev_dbg(&op->dev, "%s(%p, %p)\n", __func__, op, match); rc = of_address_to_resource(op->node, 0, &res); if (rc) { diff --git a/drivers/serial/ucc_uart.c b/drivers/serial/ucc_uart.c index 5e4310ccd591..01917c433f17 100644 --- a/drivers/serial/ucc_uart.c +++ b/drivers/serial/ucc_uart.c @@ -215,7 +215,7 @@ static inline dma_addr_t cpu2qe_addr(void *addr, struct uart_qe_port *qe_port) return qe_port->bd_dma_addr + (addr - qe_port->bd_virt); /* something nasty happened */ - printk(KERN_ERR "%s: addr=%p\n", __FUNCTION__, addr); + printk(KERN_ERR "%s: addr=%p\n", __func__, addr); BUG(); return 0; } @@ -234,7 +234,7 @@ static inline void *qe2cpu_addr(dma_addr_t addr, struct uart_qe_port *qe_port) return qe_port->bd_virt + (addr - qe_port->bd_dma_addr); /* something nasty happened */ - printk(KERN_ERR "%s: addr=%x\n", __FUNCTION__, addr); + printk(KERN_ERR "%s: addr=%x\n", __func__, addr); BUG(); return NULL; } diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index 02c8e305b14f..e81d59d78910 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c @@ -497,7 +497,7 @@ static int atmel_spi_setup(struct spi_device *spi) struct atmel_spi *as; u32 scbr, csr; unsigned int bits = spi->bits_per_word; - unsigned long bus_hz, sck_hz; + unsigned long bus_hz; unsigned int npcs_pin; int ret; @@ -536,14 +536,25 @@ static int atmel_spi_setup(struct spi_device *spi) return -EINVAL; } - /* speed zero convention is used by some upper layers */ + /* + * Pre-new_1 chips start out at half the peripheral + * bus speed. + */ bus_hz = clk_get_rate(as->clk); + if (!as->new_1) + bus_hz /= 2; + if (spi->max_speed_hz) { - /* assume div32/fdiv/mbz == 0 */ - if (!as->new_1) - bus_hz /= 2; - scbr = ((bus_hz + spi->max_speed_hz - 1) - / spi->max_speed_hz); + /* + * Calculate the lowest divider that satisfies the + * constraint, assuming div32/fdiv/mbz == 0. + */ + scbr = DIV_ROUND_UP(bus_hz, spi->max_speed_hz); + + /* + * If the resulting divider doesn't fit into the + * register bitfield, we can't satisfy the constraint. + */ if (scbr >= (1 << SPI_SCBR_SIZE)) { dev_dbg(&spi->dev, "setup: %d Hz too slow, scbr %u; min %ld Hz\n", @@ -551,8 +562,8 @@ static int atmel_spi_setup(struct spi_device *spi) return -EINVAL; } } else + /* speed zero means "as slow as possible" */ scbr = 0xff; - sck_hz = bus_hz / scbr; csr = SPI_BF(SCBR, scbr) | SPI_BF(BITS, bits - 8); if (spi->mode & SPI_CPOL) @@ -589,7 +600,7 @@ static int atmel_spi_setup(struct spi_device *spi) dev_dbg(&spi->dev, "setup: %lu Hz bpw %u mode 0x%x -> csr%d %08x\n", - sck_hz, bits, spi->mode, spi->chip_select, csr); + bus_hz / scbr, bits, spi->mode, spi->chip_select, csr); spi_writel(as, CSR0 + 4 * spi->chip_select, csr); diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 4220f22b6660..5f71ff3aee35 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -305,8 +305,6 @@ enum { */ #define FW_GET_BYTE(p) *((__u8 *) (p)) -#define FW_GET_WORD(p) le16_to_cpu(get_unaligned((__le16 *) (p))) -#define FW_GET_LONG(p) le32_to_cpu(get_unaligned((__le32 *) (p))) #define FW_DIR "ueagle-atm/" #define NB_MODEM 4 @@ -621,7 +619,7 @@ static void uea_upload_pre_firmware(const struct firmware *fw_entry, void *conte if (size < 4) goto err_fw_corrupted; - crc = FW_GET_LONG(pfw); + crc = get_unaligned_le32(pfw); pfw += 4; size -= 4; if (crc32_be(0, pfw, size) != crc) @@ -640,7 +638,7 @@ static void uea_upload_pre_firmware(const struct firmware *fw_entry, void *conte while (size > 3) { u8 len = FW_GET_BYTE(pfw); - u16 add = FW_GET_WORD(pfw + 1); + u16 add = get_unaligned_le16(pfw + 1); size -= len + 3; if (size < 0) @@ -738,7 +736,7 @@ static int check_dsp_e1(u8 *dsp, unsigned int len) for (i = 0; i < pagecount; i++) { - pageoffset = FW_GET_LONG(dsp + p); + pageoffset = get_unaligned_le32(dsp + p); p += 4; if (pageoffset == 0) @@ -759,7 +757,7 @@ static int check_dsp_e1(u8 *dsp, unsigned int len) return 1; pp += 2; /* skip blockaddr */ - blocksize = FW_GET_WORD(dsp + pp); + blocksize = get_unaligned_le16(dsp + pp); pp += 2; /* enough space for block data? */ @@ -928,7 +926,7 @@ static void uea_load_page_e1(struct work_struct *work) goto bad1; p += 4 * pageno; - pageoffset = FW_GET_LONG(p); + pageoffset = get_unaligned_le32(p); if (pageoffset == 0) goto bad1; @@ -945,10 +943,10 @@ static void uea_load_page_e1(struct work_struct *work) bi.wOvlOffset = cpu_to_le16(ovl | 0x8000); for (i = 0; i < blockcount; i++) { - blockaddr = FW_GET_WORD(p); + blockaddr = get_unaligned_le16(p); p += 2; - blocksize = FW_GET_WORD(p); + blocksize = get_unaligned_le16(p); p += 2; bi.wSize = cpu_to_le16(blocksize); @@ -1152,9 +1150,9 @@ static int uea_cmv_e1(struct uea_softc *sc, cmv.bDirection = E1_HOSTTOMODEM; cmv.bFunction = function; cmv.wIndex = cpu_to_le16(sc->cmv_dsc.e1.idx); - put_unaligned(cpu_to_le32(address), &cmv.dwSymbolicAddress); + put_unaligned_le32(address, &cmv.dwSymbolicAddress); cmv.wOffsetAddress = cpu_to_le16(offset); - put_unaligned(cpu_to_le32(data >> 16 | data << 16), &cmv.dwData); + put_unaligned_le32(data >> 16 | data << 16, &cmv.dwData); ret = uea_request(sc, UEA_E1_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv); if (ret < 0) @@ -1646,7 +1644,7 @@ static int request_cmvs(struct uea_softc *sc, if (size < 5) goto err_fw_corrupted; - crc = FW_GET_LONG(data); + crc = get_unaligned_le32(data); data += 4; size -= 4; if (crc32_be(0, data, size) != crc) @@ -1696,9 +1694,9 @@ static int uea_send_cmvs_e1(struct uea_softc *sc) "please update your firmware\n"); for (i = 0; i < len; i++) { - ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v1[i].address), - FW_GET_WORD(&cmvs_v1[i].offset), - FW_GET_LONG(&cmvs_v1[i].data)); + ret = uea_write_cmv_e1(sc, get_unaligned_le32(&cmvs_v1[i].address), + get_unaligned_le16(&cmvs_v1[i].offset), + get_unaligned_le32(&cmvs_v1[i].data)); if (ret < 0) goto out; } @@ -1706,9 +1704,9 @@ static int uea_send_cmvs_e1(struct uea_softc *sc) struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr; for (i = 0; i < len; i++) { - ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v2[i].address), - (u16) FW_GET_LONG(&cmvs_v2[i].offset), - FW_GET_LONG(&cmvs_v2[i].data)); + ret = uea_write_cmv_e1(sc, get_unaligned_le32(&cmvs_v2[i].address), + (u16) get_unaligned_le32(&cmvs_v2[i].offset), + get_unaligned_le32(&cmvs_v2[i].data)); if (ret < 0) goto out; } @@ -1759,10 +1757,10 @@ static int uea_send_cmvs_e4(struct uea_softc *sc) for (i = 0; i < len; i++) { ret = uea_write_cmv_e4(sc, 1, - FW_GET_LONG(&cmvs_v2[i].group), - FW_GET_LONG(&cmvs_v2[i].address), - FW_GET_LONG(&cmvs_v2[i].offset), - FW_GET_LONG(&cmvs_v2[i].data)); + get_unaligned_le32(&cmvs_v2[i].group), + get_unaligned_le32(&cmvs_v2[i].address), + get_unaligned_le32(&cmvs_v2[i].offset), + get_unaligned_le32(&cmvs_v2[i].data)); if (ret < 0) goto out; } @@ -1964,7 +1962,7 @@ static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr) if (UEA_CHIP_VERSION(sc) == ADI930 && cmv->bFunction == E1_MAKEFUNCTION(2, 2)) { cmv->wIndex = cpu_to_le16(dsc->idx); - put_unaligned(cpu_to_le32(dsc->address), &cmv->dwSymbolicAddress); + put_unaligned_le32(dsc->address, &cmv->dwSymbolicAddress); cmv->wOffsetAddress = cpu_to_le16(dsc->offset); } else goto bad2; @@ -1978,11 +1976,11 @@ static void uea_dispatch_cmv_e1(struct uea_softc *sc, struct intr_pkt *intr) /* in case of MEMACCESS */ if (le16_to_cpu(cmv->wIndex) != dsc->idx || - le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) != dsc->address || + get_unaligned_le32(&cmv->dwSymbolicAddress) != dsc->address || le16_to_cpu(cmv->wOffsetAddress) != dsc->offset) goto bad2; - sc->data = le32_to_cpu(get_unaligned(&cmv->dwData)); + sc->data = get_unaligned_le32(&cmv->dwData); sc->data = sc->data << 16 | sc->data >> 16; wake_up_cmv_ack(sc); diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 7b572e75e73c..cefe7f2c6f75 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -280,7 +280,7 @@ static void acm_ctrl_irq(struct urb *urb) case USB_CDC_NOTIFY_SERIAL_STATE: - newctrl = le16_to_cpu(get_unaligned((__le16 *) data)); + newctrl = get_unaligned_le16(data); if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) { dbg("calling hangup"); diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index 8607846e3c3f..1d253dd4ea81 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -773,7 +773,7 @@ int __init usbfs_init(void) usb_register_notify(&usbfs_nb); /* create mount point for usbfs */ - usbdir = proc_mkdir("usb", proc_bus); + usbdir = proc_mkdir("bus/usb", NULL); return 0; } @@ -783,6 +783,6 @@ void usbfs_cleanup(void) usb_unregister_notify(&usbfs_nb); unregister_filesystem(&usb_fs_type); if (usbdir) - remove_proc_entry("usb", proc_bus); + remove_proc_entry("bus/usb", NULL); } diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 9b913afb2e6d..274c60a970cd 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -231,6 +231,7 @@ static int proc_udc_open(struct inode *inode, struct file *file) } static const struct file_operations proc_ops = { + .owner = THIS_MODULE, .open = proc_udc_open, .read = seq_read, .llseek = seq_lseek, @@ -239,15 +240,7 @@ static const struct file_operations proc_ops = { static void create_debug_file(struct at91_udc *udc) { - struct proc_dir_entry *pde; - - pde = create_proc_entry (debug_filename, 0, NULL); - udc->pde = pde; - if (pde == NULL) - return; - - pde->proc_fops = &proc_ops; - pde->data = udc; + udc->pde = proc_create_data(debug_filename, 0, NULL, &proc_ops, udc); } static void remove_debug_file(struct at91_udc *udc) diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 64a592cbbe7b..be6613afedbf 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -127,7 +127,7 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) /* enabling the no-toggle interrupt mode would need an api hook */ mode = 0; - max = le16_to_cpu(get_unaligned(&desc->wMaxPacketSize)); + max = get_unaligned_le16(&desc->wMaxPacketSize); switch (max) { case 64: mode++; case 32: mode++; diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 95f7662376f1..881d74c3d964 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -2504,6 +2504,7 @@ static int proc_udc_open(struct inode *inode, struct file *file) } static const struct file_operations proc_ops = { + .owner = THIS_MODULE, .open = proc_udc_open, .read = seq_read, .llseek = seq_lseek, @@ -2512,11 +2513,7 @@ static const struct file_operations proc_ops = { static void create_proc_file(void) { - struct proc_dir_entry *pde; - - pde = create_proc_entry (proc_filename, 0, NULL); - if (pde) - pde->proc_fops = &proc_ops; + proc_create(proc_filename, 0, NULL, &proc_ops); } static void remove_proc_file(void) diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index bd58dd504f6f..d0677f5d3cd5 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -183,14 +183,10 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, DBG("query OID %08x value, len %d:\n", OID, buf_len); for (i = 0; i < buf_len; i += 16) { DBG("%03d: %08x %08x %08x %08x\n", i, - le32_to_cpu(get_unaligned((__le32 *) - &buf[i])), - le32_to_cpu(get_unaligned((__le32 *) - &buf[i + 4])), - le32_to_cpu(get_unaligned((__le32 *) - &buf[i + 8])), - le32_to_cpu(get_unaligned((__le32 *) - &buf[i + 12]))); + get_unaligned_le32(&buf[i]), + get_unaligned_le32(&buf[i + 4]), + get_unaligned_le32(&buf[i + 8]), + get_unaligned_le32(&buf[i + 12])); } } @@ -666,7 +662,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len, break; case OID_PNP_QUERY_POWER: DBG("%s: OID_PNP_QUERY_POWER D%d\n", __func__, - le32_to_cpu(get_unaligned((__le32 *)buf)) - 1); + get_unaligned_le32(buf) - 1); /* only suspend is a real power state, and * it can't be entered by OID_PNP_SET_POWER... */ @@ -705,14 +701,10 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len, DBG("set OID %08x value, len %d:\n", OID, buf_len); for (i = 0; i < buf_len; i += 16) { DBG("%03d: %08x %08x %08x %08x\n", i, - le32_to_cpu(get_unaligned((__le32 *) - &buf[i])), - le32_to_cpu(get_unaligned((__le32 *) - &buf[i + 4])), - le32_to_cpu(get_unaligned((__le32 *) - &buf[i + 8])), - le32_to_cpu(get_unaligned((__le32 *) - &buf[i + 12]))); + get_unaligned_le32(&buf[i]), + get_unaligned_le32(&buf[i + 4]), + get_unaligned_le32(&buf[i + 8]), + get_unaligned_le32(&buf[i + 12])); } } @@ -726,8 +718,7 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len, * PROMISCUOUS, DIRECTED, * MULTICAST, ALL_MULTICAST, BROADCAST */ - *params->filter = (u16) le32_to_cpu(get_unaligned( - (__le32 *)buf)); + *params->filter = (u16)get_unaligned_le32(buf); DBG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n", __func__, *params->filter); @@ -777,7 +768,7 @@ update_linkstate: * resuming, Windows forces a reset, and then SET_POWER D0. * FIXME ... then things go batty; Windows wedges itself. */ - i = le32_to_cpu(get_unaligned((__le32 *)buf)); + i = get_unaligned_le32(buf); DBG("%s: OID_PNP_SET_POWER D%d\n", __func__, i - 1); switch (i) { case NdisDeviceStateD0: @@ -1064,8 +1055,8 @@ int rndis_msg_parser (u8 configNr, u8 *buf) return -ENOMEM; tmp = (__le32 *) buf; - MsgType = le32_to_cpu(get_unaligned(tmp++)); - MsgLength = le32_to_cpu(get_unaligned(tmp++)); + MsgType = get_unaligned_le32(tmp++); + MsgLength = get_unaligned_le32(tmp++); if (configNr >= RNDIS_MAX_CONFIGS) return -ENOTSUPP; @@ -1296,10 +1287,9 @@ int rndis_rm_hdr(struct sk_buff *skb) tmp++; /* DataOffset, DataLength */ - if (!skb_pull(skb, le32_to_cpu(get_unaligned(tmp++)) - + 8 /* offset of DataOffset */)) + if (!skb_pull(skb, get_unaligned_le32(tmp++) + 8)) return -EOVERFLOW; - skb_trim(skb, le32_to_cpu(get_unaligned(tmp++))); + skb_trim(skb, get_unaligned_le32(tmp++)); return 0; } diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 433b3f44f42e..8d158e5640e3 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -170,7 +170,7 @@ static int gs_open(struct tty_struct *tty, struct file *file); static void gs_close(struct tty_struct *tty, struct file *file); static int gs_write(struct tty_struct *tty, const unsigned char *buf, int count); -static void gs_put_char(struct tty_struct *tty, unsigned char ch); +static int gs_put_char(struct tty_struct *tty, unsigned char ch); static void gs_flush_chars(struct tty_struct *tty); static int gs_write_room(struct tty_struct *tty); static int gs_chars_in_buffer(struct tty_struct *tty); @@ -883,14 +883,15 @@ exit: /* * gs_put_char */ -static void gs_put_char(struct tty_struct *tty, unsigned char ch) +static int gs_put_char(struct tty_struct *tty, unsigned char ch) { unsigned long flags; struct gs_port *port = tty->driver_data; + int ret = 0; if (port == NULL) { pr_err("gs_put_char: NULL port pointer\n"); - return; + return 0; } gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p\n", @@ -910,10 +911,11 @@ static void gs_put_char(struct tty_struct *tty, unsigned char ch) goto exit; } - gs_buf_put(port->port_write_buf, &ch, 1); + ret = gs_buf_put(port->port_write_buf, &ch, 1); exit: spin_unlock_irqrestore(&port->port_lock, flags); + return ret; } /* diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c index 878e428a0ec1..4154be375c7a 100644 --- a/drivers/usb/gadget/usbstring.c +++ b/drivers/usb/gadget/usbstring.c @@ -74,7 +74,7 @@ static int utf8_to_utf16le(const char *s, __le16 *cp, unsigned len) goto fail; } else uchar = c; - put_unaligned (cpu_to_le16 (uchar), cp++); + put_unaligned_le16(uchar, cp++); count++; len--; } diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index f13d1029aeb2..382587c4457c 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -770,7 +770,7 @@ static int ehci_hub_control ( if (status & ~0xffff) /* only if wPortChange is interesting */ #endif dbg_port (ehci, "GetStatus", wIndex + 1, temp); - put_unaligned(cpu_to_le32 (status), (__le32 *) buf); + put_unaligned_le32(status, buf); break; case SetHubFeature: switch (wValue) { diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 5be3bb3e6a9d..17dc2eccda83 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -736,14 +736,14 @@ static int ohci_hub_control ( break; case GetHubStatus: temp = roothub_status (ohci) & ~(RH_HS_CRWE | RH_HS_DRWE); - put_unaligned(cpu_to_le32 (temp), (__le32 *) buf); + put_unaligned_le32(temp, buf); break; case GetPortStatus: if (!wIndex || wIndex > ports) goto error; wIndex--; temp = roothub_portstatus (ohci, wIndex); - put_unaligned(cpu_to_le32 (temp), (__le32 *) buf); + put_unaligned_le32(temp, buf); #ifndef OHCI_VERBOSE_DEBUG if (*(u16*)(buf+2)) /* only if wPortChange is interesting */ diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 3fd7a0c12078..426575247b23 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -1506,15 +1506,7 @@ static const char proc_filename[] = "driver/sl811h"; static void create_debug_file(struct sl811 *sl811) { - struct proc_dir_entry *pde; - - pde = create_proc_entry(proc_filename, 0, NULL); - if (pde == NULL) - return; - - pde->proc_fops = &proc_ops; - pde->data = sl811; - sl811->pde = pde; + sl811->pde = proc_create_data(proc_filename, 0, NULL, &proc_ops, sl811); } static void remove_debug_file(struct sl811 *sl811) diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index d17d1645714f..04a56f300ea6 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -1421,8 +1421,7 @@ static void digi_close(struct usb_serial_port *port, struct file *filp) tty_wait_until_sent(tty, DIGI_CLOSE_TIMEOUT); /* flush driver and line discipline buffers */ - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + tty_driver_flush_buffer(tty); tty_ldisc_flush(tty); if (port->serial->dev) { diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index a9934a3f9845..0cb0d77dc429 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -296,16 +296,14 @@ static int serial_write (struct tty_struct * tty, const unsigned char *buf, int struct usb_serial_port *port = tty->driver_data; int retval = -ENODEV; - if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED) + if (port->serial->dev->state == USB_STATE_NOTATTACHED) goto exit; dbg("%s - port %d, %d byte(s)", __func__, port->number, count); - if (!port->open_count) { - retval = -EINVAL; - dbg("%s - port not opened", __func__); - goto exit; - } + /* open_count is managed under the mutex lock for the tty so cannot + drop to zero until after the last close completes */ + WARN_ON(!port->open_count); /* pass on to the driver specific version of this function */ retval = port->serial->type->write(port, buf, count); @@ -317,61 +315,28 @@ exit: static int serial_write_room (struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - int retval = -ENODEV; - - if (!port) - goto exit; - dbg("%s - port %d", __func__, port->number); - - if (!port->open_count) { - dbg("%s - port not open", __func__); - goto exit; - } - + WARN_ON(!port->open_count); /* pass on to the driver specific version of this function */ - retval = port->serial->type->write_room(port); - -exit: - return retval; + return port->serial->type->write_room(port); } static int serial_chars_in_buffer (struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - int retval = -ENODEV; - - if (!port) - goto exit; - dbg("%s = port %d", __func__, port->number); - if (!port->open_count) { - dbg("%s - port not open", __func__); - goto exit; - } - + WARN_ON(!port->open_count); /* pass on to the driver specific version of this function */ - retval = port->serial->type->chars_in_buffer(port); - -exit: - return retval; + return port->serial->type->chars_in_buffer(port); } static void serial_throttle (struct tty_struct * tty) { struct usb_serial_port *port = tty->driver_data; - - if (!port) - return; - dbg("%s - port %d", __func__, port->number); - if (!port->open_count) { - dbg ("%s - port not open", __func__); - return; - } - + WARN_ON(!port->open_count); /* pass on to the driver specific version of this function */ if (port->serial->type->throttle) port->serial->type->throttle(port); @@ -380,17 +345,9 @@ static void serial_throttle (struct tty_struct * tty) static void serial_unthrottle (struct tty_struct * tty) { struct usb_serial_port *port = tty->driver_data; - - if (!port) - return; - dbg("%s - port %d", __func__, port->number); - if (!port->open_count) { - dbg("%s - port not open", __func__); - return; - } - + WARN_ON(!port->open_count); /* pass on to the driver specific version of this function */ if (port->serial->type->unthrottle) port->serial->type->unthrottle(port); @@ -401,42 +358,27 @@ static int serial_ioctl (struct tty_struct *tty, struct file * file, unsigned in struct usb_serial_port *port = tty->driver_data; int retval = -ENODEV; - lock_kernel(); - if (!port) - goto exit; - dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd); - /* Caution - port->open_count is BKL protected */ - if (!port->open_count) { - dbg ("%s - port not open", __func__); - goto exit; - } + WARN_ON(!port->open_count); /* pass on to the driver specific version of this function if it is available */ - if (port->serial->type->ioctl) + if (port->serial->type->ioctl) { + lock_kernel(); retval = port->serial->type->ioctl(port, file, cmd, arg); + unlock_kernel(); + } else retval = -ENOIOCTLCMD; -exit: - unlock_kernel(); return retval; } static void serial_set_termios (struct tty_struct *tty, struct ktermios * old) { struct usb_serial_port *port = tty->driver_data; - - if (!port) - return; - dbg("%s - port %d", __func__, port->number); - if (!port->open_count) { - dbg("%s - port not open", __func__); - return; - } - + WARN_ON(!port->open_count); /* pass on to the driver specific version of this function if it is available */ if (port->serial->type->set_termios) port->serial->type->set_termios(port, old); @@ -448,24 +390,15 @@ static void serial_break (struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; - lock_kernel(); - if (!port) { - unlock_kernel(); - return; - } - dbg("%s - port %d", __func__, port->number); - if (!port->open_count) { - dbg("%s - port not open", __func__); - unlock_kernel(); - return; - } - + WARN_ON(!port->open_count); /* pass on to the driver specific version of this function if it is available */ - if (port->serial->type->break_ctl) + if (port->serial->type->break_ctl) { + lock_kernel(); port->serial->type->break_ctl(port, break_state); - unlock_kernel(); + unlock_kernel(); + } } static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data) @@ -519,19 +452,11 @@ static int serial_tiocmget (struct tty_struct *tty, struct file *file) { struct usb_serial_port *port = tty->driver_data; - if (!port) - return -ENODEV; - dbg("%s - port %d", __func__, port->number); - if (!port->open_count) { - dbg("%s - port not open", __func__); - return -ENODEV; - } - + WARN_ON(!port->open_count); if (port->serial->type->tiocmget) return port->serial->type->tiocmget(port, file); - return -EINVAL; } @@ -540,19 +465,11 @@ static int serial_tiocmset (struct tty_struct *tty, struct file *file, { struct usb_serial_port *port = tty->driver_data; - if (!port) - return -ENODEV; - dbg("%s - port %d", __func__, port->number); - if (!port->open_count) { - dbg("%s - port not open", __func__); - return -ENODEV; - } - + WARN_ON(!port->open_count); if (port->serial->type->tiocmset) return port->serial->type->tiocmset(port, file, set, clear); - return -EINVAL; } diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index e96bf8663ffc..f07e8a4c1f3d 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -673,15 +673,13 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp) } */ - if (port->tty->driver->flush_buffer) - port->tty->driver->flush_buffer(port->tty); + tty_driver_flush_buffer(port->tty); tty_ldisc_flush(port->tty); firm_report_tx_done(port); firm_close(port); -printk(KERN_ERR"Before processing rx_urbs_submitted.\n"); /* shutdown our bulk reads and writes */ mutex_lock(&info->deathwarrant); spin_lock_irq(&info->lock); diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index a576dc261732..bb1dadaa4a23 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1774,6 +1774,11 @@ config FB_PXA If unsure, say N. +config FB_PXA_SMARTPANEL + bool "PXA Smartpanel LCD support" + default n + depends on FB_PXA + config FB_PXA_PARAMETERS bool "PXA LCD command line parameters" default n diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c index 17b5267f44d7..9f8a389dc7ae 100644 --- a/drivers/video/clps711xfb.c +++ b/drivers/video/clps711xfb.c @@ -381,7 +381,7 @@ int __init clps711xfb_init(void) /* Register the /proc entries. */ clps7111fb_backlight_proc_entry = create_proc_entry("backlight", 0444, - &proc_root); + NULL); if (clps7111fb_backlight_proc_entry == NULL) { printk("Couldn't create the /proc entry for the backlight.\n"); return -EINVAL; diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 8eda7b60df8f..ad31983b43eb 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -1881,7 +1881,7 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * (b - count)), - vc->vc_video_erase_char, + vc->vc_scrl_erase_char, vc->vc_size_row * count); return 1; break; @@ -1953,7 +1953,7 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * (b - count)), - vc->vc_video_erase_char, + vc->vc_scrl_erase_char, vc->vc_size_row * count); return 1; } @@ -1972,7 +1972,7 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * t), - vc->vc_video_erase_char, + vc->vc_scrl_erase_char, vc->vc_size_row * count); return 1; break; @@ -2042,7 +2042,7 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, scr_memsetw((unsigned short *) (vc->vc_origin + vc->vc_size_row * t), - vc->vc_video_erase_char, + vc->vc_scrl_erase_char, vc->vc_size_row * count); return 1; } diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c index bd8d995fe25d..38a296bbdfc9 100644 --- a/drivers/video/console/mdacon.c +++ b/drivers/video/console/mdacon.c @@ -531,7 +531,7 @@ static void mdacon_cursor(struct vc_data *c, int mode) static int mdacon_scroll(struct vc_data *c, int t, int b, int dir, int lines) { - u16 eattr = mda_convert_attr(c->vc_video_erase_char); + u16 eattr = mda_convert_attr(c->vc_scrl_erase_char); if (!lines) return 0; diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c index 67a682d6cc7b..a11cc2fdd4cd 100644 --- a/drivers/video/console/sticon.c +++ b/drivers/video/console/sticon.c @@ -170,12 +170,12 @@ static int sticon_scroll(struct vc_data *conp, int t, int b, int dir, int count) switch (dir) { case SM_UP: sti_bmove(sti, t + count, 0, t, 0, b - t - count, conp->vc_cols); - sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_video_erase_char); + sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_scrl_erase_char); break; case SM_DOWN: sti_bmove(sti, t, 0, t + count, 0, b - t - count, conp->vc_cols); - sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_video_erase_char); + sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_scrl_erase_char); break; } diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 6df29a62d720..bd1f57b259d9 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -1350,7 +1350,7 @@ static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, } else c->vc_origin += delta; scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size - - delta), c->vc_video_erase_char, + delta), c->vc_scrl_erase_char, delta); } else { if (oldo - delta < vga_vram_base) { @@ -1363,7 +1363,7 @@ static int vgacon_scroll(struct vc_data *c, int t, int b, int dir, } else c->vc_origin -= delta; c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; - scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char, + scr_memsetw((u16 *) (c->vc_origin), c->vc_scrl_erase_char, delta); } c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size; diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c index aaa3e538e5da..5b5f072fc1a8 100644 --- a/drivers/video/matrox/matroxfb_misc.c +++ b/drivers/video/matrox/matroxfb_misc.c @@ -522,8 +522,6 @@ static void parse_bios(unsigned char __iomem* vbios, struct matrox_bios* bd) { #endif } -#define get_u16(x) (le16_to_cpu(get_unaligned((__u16*)(x)))) -#define get_u32(x) (le32_to_cpu(get_unaligned((__u32*)(x)))) static int parse_pins1(WPMINFO const struct matrox_bios* bd) { unsigned int maxdac; @@ -532,11 +530,12 @@ static int parse_pins1(WPMINFO const struct matrox_bios* bd) { case 1: maxdac = 220000; break; default: maxdac = 240000; break; } - if (get_u16(bd->pins + 24)) { - maxdac = get_u16(bd->pins + 24) * 10; + if (get_unaligned_le16(bd->pins + 24)) { + maxdac = get_unaligned_le16(bd->pins + 24) * 10; } MINFO->limits.pixel.vcomax = maxdac; - MINFO->values.pll.system = get_u16(bd->pins + 28) ? get_u16(bd->pins + 28) * 10 : 50000; + MINFO->values.pll.system = get_unaligned_le16(bd->pins + 28) ? + get_unaligned_le16(bd->pins + 28) * 10 : 50000; /* ignore 4MB, 8MB, module clocks */ MINFO->features.pll.ref_freq = 14318; MINFO->values.reg.mctlwtst = 0x00030101; @@ -575,7 +574,8 @@ static void default_pins2(WPMINFO2) { static int parse_pins3(WPMINFO const struct matrox_bios* bd) { MINFO->limits.pixel.vcomax = MINFO->limits.system.vcomax = (bd->pins[36] == 0xFF) ? 230000 : ((bd->pins[36] + 100) * 1000); - MINFO->values.reg.mctlwtst = get_u32(bd->pins + 48) == 0xFFFFFFFF ? 0x01250A21 : get_u32(bd->pins + 48); + MINFO->values.reg.mctlwtst = get_unaligned_le32(bd->pins + 48) == 0xFFFFFFFF ? + 0x01250A21 : get_unaligned_le32(bd->pins + 48); /* memory config */ MINFO->values.reg.memrdbk = ((bd->pins[57] << 21) & 0x1E000000) | ((bd->pins[57] << 22) & 0x00C00000) | @@ -601,7 +601,7 @@ static void default_pins3(WPMINFO2) { static int parse_pins4(WPMINFO const struct matrox_bios* bd) { MINFO->limits.pixel.vcomax = (bd->pins[ 39] == 0xFF) ? 230000 : bd->pins[ 39] * 4000; MINFO->limits.system.vcomax = (bd->pins[ 38] == 0xFF) ? MINFO->limits.pixel.vcomax : bd->pins[ 38] * 4000; - MINFO->values.reg.mctlwtst = get_u32(bd->pins + 71); + MINFO->values.reg.mctlwtst = get_unaligned_le32(bd->pins + 71); MINFO->values.reg.memrdbk = ((bd->pins[87] << 21) & 0x1E000000) | ((bd->pins[87] << 22) & 0x00C00000) | ((bd->pins[86] << 1) & 0x000001E0) | @@ -609,7 +609,7 @@ static int parse_pins4(WPMINFO const struct matrox_bios* bd) { MINFO->values.reg.opt = ((bd->pins[53] << 15) & 0x00400000) | ((bd->pins[53] << 22) & 0x10000000) | ((bd->pins[53] << 7) & 0x00001C00); - MINFO->values.reg.opt3 = get_u32(bd->pins + 67); + MINFO->values.reg.opt3 = get_unaligned_le32(bd->pins + 67); MINFO->values.pll.system = (bd->pins[ 65] == 0xFF) ? 200000 : bd->pins[ 65] * 4000; MINFO->features.pll.ref_freq = (bd->pins[ 92] & 0x01) ? 14318 : 27000; return 0; @@ -640,12 +640,12 @@ static int parse_pins5(WPMINFO const struct matrox_bios* bd) { MINFO->limits.video.vcomin = (bd->pins[122] == 0xFF) ? MINFO->limits.system.vcomin : bd->pins[122] * mult; MINFO->values.pll.system = MINFO->values.pll.video = (bd->pins[ 92] == 0xFF) ? 284000 : bd->pins[ 92] * 4000; - MINFO->values.reg.opt = get_u32(bd->pins+ 48); - MINFO->values.reg.opt2 = get_u32(bd->pins+ 52); - MINFO->values.reg.opt3 = get_u32(bd->pins+ 94); - MINFO->values.reg.mctlwtst = get_u32(bd->pins+ 98); - MINFO->values.reg.memmisc = get_u32(bd->pins+102); - MINFO->values.reg.memrdbk = get_u32(bd->pins+106); + MINFO->values.reg.opt = get_unaligned_le32(bd->pins + 48); + MINFO->values.reg.opt2 = get_unaligned_le32(bd->pins + 52); + MINFO->values.reg.opt3 = get_unaligned_le32(bd->pins + 94); + MINFO->values.reg.mctlwtst = get_unaligned_le32(bd->pins + 98); + MINFO->values.reg.memmisc = get_unaligned_le32(bd->pins + 102); + MINFO->values.reg.memrdbk = get_unaligned_le32(bd->pins + 106); MINFO->features.pll.ref_freq = (bd->pins[110] & 0x01) ? 14318 : 27000; MINFO->values.memory.ddr = (bd->pins[114] & 0x60) == 0x20; MINFO->values.memory.dll = (bd->pins[115] & 0x02) != 0; diff --git a/drivers/video/metronomefb.c b/drivers/video/metronomefb.c index 249791286367..cc4c038a1b3f 100644 --- a/drivers/video/metronomefb.c +++ b/drivers/video/metronomefb.c @@ -206,8 +206,7 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t, } /* check waveform mode table address checksum */ - wmta = le32_to_cpu(get_unaligned((__le32 *) wfm_hdr->wmta)); - wmta &= 0x00FFFFFF; + wmta = get_unaligned_le32(wfm_hdr->wmta) & 0x00FFFFFF; cksum_idx = wmta + m*4 + 3; if (cksum_idx > size) return -EINVAL; @@ -219,8 +218,7 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t, } /* check waveform temperature table address checksum */ - tta = le32_to_cpu(get_unaligned((int *) (mem + wmta + m*4))); - tta &= 0x00FFFFFF; + tta = get_unaligned_le32(mem + wmta + m * 4) & 0x00FFFFFF; cksum_idx = tta + trn*4 + 3; if (cksum_idx > size) return -EINVAL; @@ -233,8 +231,7 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t, /* here we do the real work of putting the waveform into the metromem buffer. this does runlength decoding of the waveform */ - wfm_idx = le32_to_cpu(get_unaligned((__le32 *) (mem + tta + trn*4))); - wfm_idx &= 0x00FFFFFF; + wfm_idx = get_unaligned_le32(mem + tta + trn * 4) & 0x00FFFFFF; owfm_idx = wfm_idx; if (wfm_idx > size) return -EINVAL; diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index 757651954e6c..3ab6e3d973a1 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -39,6 +39,9 @@ #include <linux/dma-mapping.h> #include <linux/clk.h> #include <linux/err.h> +#include <linux/completion.h> +#include <linux/kthread.h> +#include <linux/freezer.h> #include <asm/hardware.h> #include <asm/io.h> @@ -57,19 +60,31 @@ #include "pxafb.h" /* Bits which should not be set in machine configuration structures */ -#define LCCR0_INVALID_CONFIG_MASK (LCCR0_OUM|LCCR0_BM|LCCR0_QDM|LCCR0_DIS|LCCR0_EFM|LCCR0_IUM|LCCR0_SFM|LCCR0_LDM|LCCR0_ENB) -#define LCCR3_INVALID_CONFIG_MASK (LCCR3_HSP|LCCR3_VSP|LCCR3_PCD|LCCR3_BPP) +#define LCCR0_INVALID_CONFIG_MASK (LCCR0_OUM | LCCR0_BM | LCCR0_QDM |\ + LCCR0_DIS | LCCR0_EFM | LCCR0_IUM |\ + LCCR0_SFM | LCCR0_LDM | LCCR0_ENB) + +#define LCCR3_INVALID_CONFIG_MASK (LCCR3_HSP | LCCR3_VSP |\ + LCCR3_PCD | LCCR3_BPP) static void (*pxafb_backlight_power)(int); static void (*pxafb_lcd_power)(int, struct fb_var_screeninfo *); -static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *); +static int pxafb_activate_var(struct fb_var_screeninfo *var, + struct pxafb_info *); static void set_ctrlr_state(struct pxafb_info *fbi, u_int state); -#ifdef CONFIG_FB_PXA_PARAMETERS -#define PXAFB_OPTIONS_SIZE 256 -static char g_options[PXAFB_OPTIONS_SIZE] __devinitdata = ""; -#endif +static inline unsigned long +lcd_readl(struct pxafb_info *fbi, unsigned int off) +{ + return __raw_readl(fbi->mmio_base + off); +} + +static inline void +lcd_writel(struct pxafb_info *fbi, unsigned int off, unsigned long val) +{ + __raw_writel(val, fbi->mmio_base + off); +} static inline void pxafb_schedule_work(struct pxafb_info *fbi, u_int state) { @@ -79,10 +94,12 @@ static inline void pxafb_schedule_work(struct pxafb_info *fbi, u_int state) /* * We need to handle two requests being made at the same time. * There are two important cases: - * 1. When we are changing VT (C_REENABLE) while unblanking (C_ENABLE) - * We must perform the unblanking, which will do our REENABLE for us. - * 2. When we are blanking, but immediately unblank before we have - * blanked. We do the "REENABLE" thing here as well, just to be sure. + * 1. When we are changing VT (C_REENABLE) while unblanking + * (C_ENABLE) We must perform the unblanking, which will + * do our REENABLE for us. + * 2. When we are blanking, but immediately unblank before + * we have blanked. We do the "REENABLE" thing here as + * well, just to be sure. */ if (fbi->task_state == C_ENABLE && state == C_REENABLE) state = (u_int) -1; @@ -129,13 +146,13 @@ pxafb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue, val = ((red << 8) & 0x00f80000); val |= ((green >> 0) & 0x0000fc00); val |= ((blue >> 8) & 0x000000f8); - ((u32*)(fbi->palette_cpu))[regno] = val; + ((u32 *)(fbi->palette_cpu))[regno] = val; break; case LCCR4_PAL_FOR_2: val = ((red << 8) & 0x00fc0000); val |= ((green >> 0) & 0x0000fc00); val |= ((blue >> 8) & 0x000000fc); - ((u32*)(fbi->palette_cpu))[regno] = val; + ((u32 *)(fbi->palette_cpu))[regno] = val; break; } @@ -203,15 +220,15 @@ pxafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, */ static int pxafb_bpp_to_lccr3(struct fb_var_screeninfo *var) { - int ret = 0; - switch (var->bits_per_pixel) { - case 1: ret = LCCR3_1BPP; break; - case 2: ret = LCCR3_2BPP; break; - case 4: ret = LCCR3_4BPP; break; - case 8: ret = LCCR3_8BPP; break; - case 16: ret = LCCR3_16BPP; break; - } - return ret; + int ret = 0; + switch (var->bits_per_pixel) { + case 1: ret = LCCR3_1BPP; break; + case 2: ret = LCCR3_2BPP; break; + case 4: ret = LCCR3_4BPP; break; + case 8: ret = LCCR3_8BPP; break; + case 16: ret = LCCR3_16BPP; break; + } + return ret; } #ifdef CONFIG_CPU_FREQ @@ -223,31 +240,32 @@ static int pxafb_bpp_to_lccr3(struct fb_var_screeninfo *var) */ static unsigned int pxafb_display_dma_period(struct fb_var_screeninfo *var) { - /* - * Period = pixclock * bits_per_byte * bytes_per_transfer - * / memory_bits_per_pixel; - */ - return var->pixclock * 8 * 16 / var->bits_per_pixel; + /* + * Period = pixclock * bits_per_byte * bytes_per_transfer + * / memory_bits_per_pixel; + */ + return var->pixclock * 8 * 16 / var->bits_per_pixel; } - -extern unsigned int get_clk_frequency_khz(int info); #endif /* * Select the smallest mode that allows the desired resolution to be * displayed. If desired parameters can be rounded up. */ -static struct pxafb_mode_info *pxafb_getmode(struct pxafb_mach_info *mach, struct fb_var_screeninfo *var) +static struct pxafb_mode_info *pxafb_getmode(struct pxafb_mach_info *mach, + struct fb_var_screeninfo *var) { struct pxafb_mode_info *mode = NULL; struct pxafb_mode_info *modelist = mach->modes; unsigned int best_x = 0xffffffff, best_y = 0xffffffff; unsigned int i; - for (i = 0 ; i < mach->num_modes ; i++) { - if (modelist[i].xres >= var->xres && modelist[i].yres >= var->yres && - modelist[i].xres < best_x && modelist[i].yres < best_y && - modelist[i].bpp >= var->bits_per_pixel ) { + for (i = 0; i < mach->num_modes; i++) { + if (modelist[i].xres >= var->xres && + modelist[i].yres >= var->yres && + modelist[i].xres < best_x && + modelist[i].yres < best_y && + modelist[i].bpp >= var->bits_per_pixel) { best_x = modelist[i].xres; best_y = modelist[i].yres; mode = &modelist[i]; @@ -257,7 +275,8 @@ static struct pxafb_mode_info *pxafb_getmode(struct pxafb_mach_info *mach, struc return mode; } -static void pxafb_setmode(struct fb_var_screeninfo *var, struct pxafb_mode_info *mode) +static void pxafb_setmode(struct fb_var_screeninfo *var, + struct pxafb_mode_info *mode) { var->xres = mode->xres; var->yres = mode->yres; @@ -315,19 +334,20 @@ static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) var->yres_virtual = max(var->yres_virtual, var->yres); - /* + /* * Setup the RGB parameters for this display. * * The pixel packing format is described on page 7-11 of the * PXA2XX Developer's Manual. - */ + */ if (var->bits_per_pixel == 16) { var->red.offset = 11; var->red.length = 5; var->green.offset = 5; var->green.length = 6; var->blue.offset = 0; var->blue.length = 5; var->transp.offset = var->transp.length = 0; } else { - var->red.offset = var->green.offset = var->blue.offset = var->transp.offset = 0; + var->red.offset = var->green.offset = 0; + var->blue.offset = var->transp.offset = 0; var->red.length = 8; var->green.length = 8; var->blue.length = 8; @@ -345,8 +365,7 @@ static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) static inline void pxafb_set_truecolor(u_int is_true_color) { - pr_debug("pxafb: true_color = %d\n", is_true_color); - // do your machine-specific setup if needed + /* do your machine-specific setup if needed */ } /* @@ -357,9 +376,6 @@ static int pxafb_set_par(struct fb_info *info) { struct pxafb_info *fbi = (struct pxafb_info *)info; struct fb_var_screeninfo *var = &info->var; - unsigned long palette_mem_size; - - pr_debug("pxafb: set_par\n"); if (var->bits_per_pixel == 16) fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR; @@ -379,17 +395,10 @@ static int pxafb_set_par(struct fb_info *info) if (var->bits_per_pixel == 16) fbi->palette_size = 0; else - fbi->palette_size = var->bits_per_pixel == 1 ? 4 : 1 << var->bits_per_pixel; - - if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0) - palette_mem_size = fbi->palette_size * sizeof(u16); - else - palette_mem_size = fbi->palette_size * sizeof(u32); - - pr_debug("pxafb: palette_mem_size = 0x%08lx\n", palette_mem_size); + fbi->palette_size = var->bits_per_pixel == 1 ? + 4 : 1 << var->bits_per_pixel; - fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size); - fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size; + fbi->palette_cpu = (u16 *)&fbi->dma_buff->palette[0]; /* * Set (any) board control register to handle new color depth @@ -407,36 +416,6 @@ static int pxafb_set_par(struct fb_info *info) } /* - * Formal definition of the VESA spec: - * On - * This refers to the state of the display when it is in full operation - * Stand-By - * This defines an optional operating state of minimal power reduction with - * the shortest recovery time - * Suspend - * This refers to a level of power management in which substantial power - * reduction is achieved by the display. The display can have a longer - * recovery time from this state than from the Stand-by state - * Off - * This indicates that the display is consuming the lowest level of power - * and is non-operational. Recovery from this state may optionally require - * the user to manually power on the monitor - * - * Now, the fbdev driver adds an additional state, (blank), where they - * turn off the video (maybe by colormap tricks), but don't mess with the - * video itself: think of it semantically between on and Stand-By. - * - * So here's what we should do in our fbdev blank routine: - * - * VESA_NO_BLANKING (mode 0) Video on, front/back light on - * VESA_VSYNC_SUSPEND (mode 1) Video on, front/back light off - * VESA_HSYNC_SUSPEND (mode 2) Video on, front/back light off - * VESA_POWERDOWN (mode 3) Video off, front/back light off - * - * This will match the matrox implementation. - */ - -/* * pxafb_blank(): * Blank the display by setting all palette values to zero. Note, the * 16 bpp mode does not really use the palette, so this will not @@ -447,8 +426,6 @@ static int pxafb_blank(int blank, struct fb_info *info) struct pxafb_info *fbi = (struct pxafb_info *)info; int i; - pr_debug("pxafb: blank=%d\n", blank); - switch (blank) { case FB_BLANK_POWERDOWN: case FB_BLANK_VSYNC_SUSPEND: @@ -460,11 +437,11 @@ static int pxafb_blank(int blank, struct fb_info *info) pxafb_setpalettereg(i, 0, 0, 0, 0, info); pxafb_schedule_work(fbi, C_DISABLE); - //TODO if (pxafb_blank_helper) pxafb_blank_helper(blank); + /* TODO if (pxafb_blank_helper) pxafb_blank_helper(blank); */ break; case FB_BLANK_UNBLANK: - //TODO if (pxafb_blank_helper) pxafb_blank_helper(blank); + /* TODO if (pxafb_blank_helper) pxafb_blank_helper(blank); */ if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR || fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR) fb_set_cmap(&fbi->fb.cmap, info); @@ -480,7 +457,7 @@ static int pxafb_mmap(struct fb_info *info, unsigned long off = vma->vm_pgoff << PAGE_SHIFT; if (off < info->fix.smem_len) { - vma->vm_pgoff += 1; + vma->vm_pgoff += fbi->video_offset / PAGE_SIZE; return dma_mmap_writecombine(fbi->dev, vma, fbi->map_cpu, fbi->map_dma, fbi->map_size); } @@ -529,7 +506,8 @@ static struct fb_ops pxafb_ops = { * * Factoring the 10^4 and 10^-12 out gives 10^-8 == 1 / 100000000 as used below. */ -static inline unsigned int get_pcd(struct pxafb_info *fbi, unsigned int pixclock) +static inline unsigned int get_pcd(struct pxafb_info *fbi, + unsigned int pixclock) { unsigned long long pcd; @@ -555,7 +533,7 @@ static inline void set_hsync_time(struct pxafb_info *fbi, unsigned int pcd) unsigned long htime; if ((pcd == 0) || (fbi->fb.var.hsync_len == 0)) { - fbi->hsync_time=0; + fbi->hsync_time = 0; return; } @@ -576,71 +554,231 @@ unsigned long pxafb_get_hsync_time(struct device *dev) } EXPORT_SYMBOL(pxafb_get_hsync_time); -/* - * pxafb_activate_var(): - * Configures LCD Controller based on entries in var parameter. Settings are - * only written to the controller if changes were made. - */ -static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *fbi) +static int setup_frame_dma(struct pxafb_info *fbi, int dma, int pal, + unsigned int offset, size_t size) { - struct pxafb_lcd_reg new_regs; - u_long flags; - u_int lines_per_panel, pcd = get_pcd(fbi, var->pixclock); + struct pxafb_dma_descriptor *dma_desc, *pal_desc; + unsigned int dma_desc_off, pal_desc_off; - pr_debug("pxafb: Configuring PXA LCD\n"); + if (dma < 0 || dma >= DMA_MAX) + return -EINVAL; - pr_debug("var: xres=%d hslen=%d lm=%d rm=%d\n", - var->xres, var->hsync_len, - var->left_margin, var->right_margin); - pr_debug("var: yres=%d vslen=%d um=%d bm=%d\n", - var->yres, var->vsync_len, - var->upper_margin, var->lower_margin); - pr_debug("var: pixclock=%d pcd=%d\n", var->pixclock, pcd); + dma_desc = &fbi->dma_buff->dma_desc[dma]; + dma_desc_off = offsetof(struct pxafb_dma_buff, dma_desc[dma]); -#if DEBUG_VAR - if (var->xres < 16 || var->xres > 1024) - printk(KERN_ERR "%s: invalid xres %d\n", - fbi->fb.fix.id, var->xres); - switch(var->bits_per_pixel) { - case 1: - case 2: - case 4: - case 8: - case 16: - break; - default: - printk(KERN_ERR "%s: invalid bit depth %d\n", - fbi->fb.fix.id, var->bits_per_pixel); - break; + dma_desc->fsadr = fbi->screen_dma + offset; + dma_desc->fidr = 0; + dma_desc->ldcmd = size; + + if (pal < 0 || pal >= PAL_MAX) { + dma_desc->fdadr = fbi->dma_buff_phys + dma_desc_off; + fbi->fdadr[dma] = fbi->dma_buff_phys + dma_desc_off; + } else { + pal_desc = &fbi->dma_buff->pal_desc[dma]; + pal_desc_off = offsetof(struct pxafb_dma_buff, dma_desc[pal]); + + pal_desc->fsadr = fbi->dma_buff_phys + pal * PALETTE_SIZE; + pal_desc->fidr = 0; + + if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0) + pal_desc->ldcmd = fbi->palette_size * sizeof(u16); + else + pal_desc->ldcmd = fbi->palette_size * sizeof(u32); + + pal_desc->ldcmd |= LDCMD_PAL; + + /* flip back and forth between palette and frame buffer */ + pal_desc->fdadr = fbi->dma_buff_phys + dma_desc_off; + dma_desc->fdadr = fbi->dma_buff_phys + pal_desc_off; + fbi->fdadr[dma] = fbi->dma_buff_phys + dma_desc_off; } - if (var->hsync_len < 1 || var->hsync_len > 64) - printk(KERN_ERR "%s: invalid hsync_len %d\n", - fbi->fb.fix.id, var->hsync_len); - if (var->left_margin < 1 || var->left_margin > 255) - printk(KERN_ERR "%s: invalid left_margin %d\n", - fbi->fb.fix.id, var->left_margin); - if (var->right_margin < 1 || var->right_margin > 255) - printk(KERN_ERR "%s: invalid right_margin %d\n", - fbi->fb.fix.id, var->right_margin); - if (var->yres < 1 || var->yres > 1024) - printk(KERN_ERR "%s: invalid yres %d\n", - fbi->fb.fix.id, var->yres); - if (var->vsync_len < 1 || var->vsync_len > 64) - printk(KERN_ERR "%s: invalid vsync_len %d\n", - fbi->fb.fix.id, var->vsync_len); - if (var->upper_margin < 0 || var->upper_margin > 255) - printk(KERN_ERR "%s: invalid upper_margin %d\n", - fbi->fb.fix.id, var->upper_margin); - if (var->lower_margin < 0 || var->lower_margin > 255) - printk(KERN_ERR "%s: invalid lower_margin %d\n", - fbi->fb.fix.id, var->lower_margin); -#endif - new_regs.lccr0 = fbi->lccr0 | - (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | - LCCR0_QDM | LCCR0_BM | LCCR0_OUM); + return 0; +} + +#ifdef CONFIG_FB_PXA_SMARTPANEL +static int setup_smart_dma(struct pxafb_info *fbi) +{ + struct pxafb_dma_descriptor *dma_desc; + unsigned long dma_desc_off, cmd_buff_off; + + dma_desc = &fbi->dma_buff->dma_desc[DMA_CMD]; + dma_desc_off = offsetof(struct pxafb_dma_buff, dma_desc[DMA_CMD]); + cmd_buff_off = offsetof(struct pxafb_dma_buff, cmd_buff); + + dma_desc->fdadr = fbi->dma_buff_phys + dma_desc_off; + dma_desc->fsadr = fbi->dma_buff_phys + cmd_buff_off; + dma_desc->fidr = 0; + dma_desc->ldcmd = fbi->n_smart_cmds * sizeof(uint16_t); + + fbi->fdadr[DMA_CMD] = dma_desc->fdadr; + return 0; +} + +int pxafb_smart_flush(struct fb_info *info) +{ + struct pxafb_info *fbi = container_of(info, struct pxafb_info, fb); + uint32_t prsr; + int ret = 0; + + /* disable controller until all registers are set up */ + lcd_writel(fbi, LCCR0, fbi->reg_lccr0 & ~LCCR0_ENB); + + /* 1. make it an even number of commands to align on 32-bit boundary + * 2. add the interrupt command to the end of the chain so we can + * keep track of the end of the transfer + */ + + while (fbi->n_smart_cmds & 1) + fbi->smart_cmds[fbi->n_smart_cmds++] = SMART_CMD_NOOP; + + fbi->smart_cmds[fbi->n_smart_cmds++] = SMART_CMD_INTERRUPT; + fbi->smart_cmds[fbi->n_smart_cmds++] = SMART_CMD_WAIT_FOR_VSYNC; + setup_smart_dma(fbi); + + /* continue to execute next command */ + prsr = lcd_readl(fbi, PRSR) | PRSR_ST_OK | PRSR_CON_NT; + lcd_writel(fbi, PRSR, prsr); + + /* stop the processor in case it executed "wait for sync" cmd */ + lcd_writel(fbi, CMDCR, 0x0001); + + /* don't send interrupts for fifo underruns on channel 6 */ + lcd_writel(fbi, LCCR5, LCCR5_IUM(6)); + + lcd_writel(fbi, LCCR1, fbi->reg_lccr1); + lcd_writel(fbi, LCCR2, fbi->reg_lccr2); + lcd_writel(fbi, LCCR3, fbi->reg_lccr3); + lcd_writel(fbi, FDADR0, fbi->fdadr[0]); + lcd_writel(fbi, FDADR6, fbi->fdadr[6]); + + /* begin sending */ + lcd_writel(fbi, LCCR0, fbi->reg_lccr0 | LCCR0_ENB); + + if (wait_for_completion_timeout(&fbi->command_done, HZ/2) == 0) { + pr_warning("%s: timeout waiting for command done\n", + __func__); + ret = -ETIMEDOUT; + } + + /* quick disable */ + prsr = lcd_readl(fbi, PRSR) & ~(PRSR_ST_OK | PRSR_CON_NT); + lcd_writel(fbi, PRSR, prsr); + lcd_writel(fbi, LCCR0, fbi->reg_lccr0 & ~LCCR0_ENB); + lcd_writel(fbi, FDADR6, 0); + fbi->n_smart_cmds = 0; + return ret; +} + +int pxafb_smart_queue(struct fb_info *info, uint16_t *cmds, int n_cmds) +{ + int i; + struct pxafb_info *fbi = container_of(info, struct pxafb_info, fb); + + /* leave 2 commands for INTERRUPT and WAIT_FOR_SYNC */ + for (i = 0; i < n_cmds; i++) { + if (fbi->n_smart_cmds == CMD_BUFF_SIZE - 8) + pxafb_smart_flush(info); + + fbi->smart_cmds[fbi->n_smart_cmds++] = *cmds++; + } + + return 0; +} + +static unsigned int __smart_timing(unsigned time_ns, unsigned long lcd_clk) +{ + unsigned int t = (time_ns * (lcd_clk / 1000000) / 1000); + return (t == 0) ? 1 : t; +} + +static void setup_smart_timing(struct pxafb_info *fbi, + struct fb_var_screeninfo *var) +{ + struct pxafb_mach_info *inf = fbi->dev->platform_data; + struct pxafb_mode_info *mode = &inf->modes[0]; + unsigned long lclk = clk_get_rate(fbi->clk); + unsigned t1, t2, t3, t4; + + t1 = max(mode->a0csrd_set_hld, mode->a0cswr_set_hld); + t2 = max(mode->rd_pulse_width, mode->wr_pulse_width); + t3 = mode->op_hold_time; + t4 = mode->cmd_inh_time; + + fbi->reg_lccr1 = + LCCR1_DisWdth(var->xres) | + LCCR1_BegLnDel(__smart_timing(t1, lclk)) | + LCCR1_EndLnDel(__smart_timing(t2, lclk)) | + LCCR1_HorSnchWdth(__smart_timing(t3, lclk)); + + fbi->reg_lccr2 = LCCR2_DisHght(var->yres); + fbi->reg_lccr3 = LCCR3_PixClkDiv(__smart_timing(t4, lclk)); + + /* FIXME: make this configurable */ + fbi->reg_cmdcr = 1; +} + +static int pxafb_smart_thread(void *arg) +{ + struct pxafb_info *fbi = arg; + struct pxafb_mach_info *inf = fbi->dev->platform_data; + + if (!fbi || !inf->smart_update) { + pr_err("%s: not properly initialized, thread terminated\n", + __func__); + return -EINVAL; + } - new_regs.lccr1 = + pr_debug("%s(): task starting\n", __func__); + + set_freezable(); + while (!kthread_should_stop()) { + + if (try_to_freeze()) + continue; + + if (fbi->state == C_ENABLE) { + inf->smart_update(&fbi->fb); + complete(&fbi->refresh_done); + } + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(30 * HZ / 1000); + } + + pr_debug("%s(): task ending\n", __func__); + return 0; +} + +static int pxafb_smart_init(struct pxafb_info *fbi) +{ + fbi->smart_thread = kthread_run(pxafb_smart_thread, fbi, + "lcd_refresh"); + if (IS_ERR(fbi->smart_thread)) { + printk(KERN_ERR "%s: unable to create kernel thread\n", + __func__); + return PTR_ERR(fbi->smart_thread); + } + return 0; +} +#else +int pxafb_smart_queue(struct fb_info *info, uint16_t *cmds, int n_cmds) +{ + return 0; +} + +int pxafb_smart_flush(struct fb_info *info) +{ + return 0; +} +#endif /* CONFIG_FB_SMART_PANEL */ + +static void setup_parallel_timing(struct pxafb_info *fbi, + struct fb_var_screeninfo *var) +{ + unsigned int lines_per_panel, pcd = get_pcd(fbi, var->pixclock); + + fbi->reg_lccr1 = LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(var->hsync_len) + LCCR1_BegLnDel(var->left_margin) + @@ -654,110 +792,118 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info * if ((fbi->lccr0 & LCCR0_SDS) == LCCR0_Dual) lines_per_panel /= 2; - new_regs.lccr2 = + fbi->reg_lccr2 = LCCR2_DisHght(lines_per_panel) + LCCR2_VrtSnchWdth(var->vsync_len) + LCCR2_BegFrmDel(var->upper_margin) + LCCR2_EndFrmDel(var->lower_margin); - new_regs.lccr3 = fbi->lccr3 | - pxafb_bpp_to_lccr3(var) | - (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) | - (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL); + fbi->reg_lccr3 = fbi->lccr3 | + (var->sync & FB_SYNC_HOR_HIGH_ACT ? + LCCR3_HorSnchH : LCCR3_HorSnchL) | + (var->sync & FB_SYNC_VERT_HIGH_ACT ? + LCCR3_VrtSnchH : LCCR3_VrtSnchL); + + if (pcd) { + fbi->reg_lccr3 |= LCCR3_PixClkDiv(pcd); + set_hsync_time(fbi, pcd); + } +} - if (pcd) - new_regs.lccr3 |= LCCR3_PixClkDiv(pcd); +/* + * pxafb_activate_var(): + * Configures LCD Controller based on entries in var parameter. + * Settings are only written to the controller if changes were made. + */ +static int pxafb_activate_var(struct fb_var_screeninfo *var, + struct pxafb_info *fbi) +{ + u_long flags; + size_t nbytes; - pr_debug("nlccr0 = 0x%08x\n", new_regs.lccr0); - pr_debug("nlccr1 = 0x%08x\n", new_regs.lccr1); - pr_debug("nlccr2 = 0x%08x\n", new_regs.lccr2); - pr_debug("nlccr3 = 0x%08x\n", new_regs.lccr3); +#if DEBUG_VAR + if (!(fbi->lccr0 & LCCR0_LCDT)) { + if (var->xres < 16 || var->xres > 1024) + printk(KERN_ERR "%s: invalid xres %d\n", + fbi->fb.fix.id, var->xres); + switch (var->bits_per_pixel) { + case 1: + case 2: + case 4: + case 8: + case 16: + break; + default: + printk(KERN_ERR "%s: invalid bit depth %d\n", + fbi->fb.fix.id, var->bits_per_pixel); + break; + } + if (var->hsync_len < 1 || var->hsync_len > 64) + printk(KERN_ERR "%s: invalid hsync_len %d\n", + fbi->fb.fix.id, var->hsync_len); + if (var->left_margin < 1 || var->left_margin > 255) + printk(KERN_ERR "%s: invalid left_margin %d\n", + fbi->fb.fix.id, var->left_margin); + if (var->right_margin < 1 || var->right_margin > 255) + printk(KERN_ERR "%s: invalid right_margin %d\n", + fbi->fb.fix.id, var->right_margin); + if (var->yres < 1 || var->yres > 1024) + printk(KERN_ERR "%s: invalid yres %d\n", + fbi->fb.fix.id, var->yres); + if (var->vsync_len < 1 || var->vsync_len > 64) + printk(KERN_ERR "%s: invalid vsync_len %d\n", + fbi->fb.fix.id, var->vsync_len); + if (var->upper_margin < 0 || var->upper_margin > 255) + printk(KERN_ERR "%s: invalid upper_margin %d\n", + fbi->fb.fix.id, var->upper_margin); + if (var->lower_margin < 0 || var->lower_margin > 255) + printk(KERN_ERR "%s: invalid lower_margin %d\n", + fbi->fb.fix.id, var->lower_margin); + } +#endif /* Update shadow copy atomically */ local_irq_save(flags); - /* setup dma descriptors */ - fbi->dmadesc_fblow_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 3*16); - fbi->dmadesc_fbhigh_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 2*16); - fbi->dmadesc_palette_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 1*16); - - fbi->dmadesc_fblow_dma = fbi->palette_dma - 3*16; - fbi->dmadesc_fbhigh_dma = fbi->palette_dma - 2*16; - fbi->dmadesc_palette_dma = fbi->palette_dma - 1*16; - -#define BYTES_PER_PANEL (lines_per_panel * fbi->fb.fix.line_length) - - /* populate descriptors */ - fbi->dmadesc_fblow_cpu->fdadr = fbi->dmadesc_fblow_dma; - fbi->dmadesc_fblow_cpu->fsadr = fbi->screen_dma + BYTES_PER_PANEL; - fbi->dmadesc_fblow_cpu->fidr = 0; - fbi->dmadesc_fblow_cpu->ldcmd = BYTES_PER_PANEL; +#ifdef CONFIG_FB_PXA_SMARTPANEL + if (fbi->lccr0 & LCCR0_LCDT) + setup_smart_timing(fbi, var); + else +#endif + setup_parallel_timing(fbi, var); - fbi->fdadr1 = fbi->dmadesc_fblow_dma; /* only used in dual-panel mode */ + fbi->reg_lccr0 = fbi->lccr0 | + (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | + LCCR0_QDM | LCCR0_BM | LCCR0_OUM); - fbi->dmadesc_fbhigh_cpu->fsadr = fbi->screen_dma; - fbi->dmadesc_fbhigh_cpu->fidr = 0; - fbi->dmadesc_fbhigh_cpu->ldcmd = BYTES_PER_PANEL; + fbi->reg_lccr3 |= pxafb_bpp_to_lccr3(var); - fbi->dmadesc_palette_cpu->fsadr = fbi->palette_dma; - fbi->dmadesc_palette_cpu->fidr = 0; - if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0) - fbi->dmadesc_palette_cpu->ldcmd = fbi->palette_size * - sizeof(u16); - else - fbi->dmadesc_palette_cpu->ldcmd = fbi->palette_size * - sizeof(u32); - fbi->dmadesc_palette_cpu->ldcmd |= LDCMD_PAL; + nbytes = var->yres * fbi->fb.fix.line_length; - if (var->bits_per_pixel == 16) { - /* palette shouldn't be loaded in true-color mode */ - fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_fbhigh_dma; - fbi->fdadr0 = fbi->dmadesc_fbhigh_dma; /* no pal just fbhigh */ - /* init it to something, even though we won't be using it */ - fbi->dmadesc_palette_cpu->fdadr = fbi->dmadesc_palette_dma; - } else { - fbi->dmadesc_palette_cpu->fdadr = fbi->dmadesc_fbhigh_dma; - fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_palette_dma; - fbi->fdadr0 = fbi->dmadesc_palette_dma; /* flips back and forth between pal and fbhigh */ + if ((fbi->lccr0 & LCCR0_SDS) == LCCR0_Dual) { + nbytes = nbytes / 2; + setup_frame_dma(fbi, DMA_LOWER, PAL_NONE, nbytes, nbytes); } -#if 0 - pr_debug("fbi->dmadesc_fblow_cpu = 0x%p\n", fbi->dmadesc_fblow_cpu); - pr_debug("fbi->dmadesc_fbhigh_cpu = 0x%p\n", fbi->dmadesc_fbhigh_cpu); - pr_debug("fbi->dmadesc_palette_cpu = 0x%p\n", fbi->dmadesc_palette_cpu); - pr_debug("fbi->dmadesc_fblow_dma = 0x%x\n", fbi->dmadesc_fblow_dma); - pr_debug("fbi->dmadesc_fbhigh_dma = 0x%x\n", fbi->dmadesc_fbhigh_dma); - pr_debug("fbi->dmadesc_palette_dma = 0x%x\n", fbi->dmadesc_palette_dma); - - pr_debug("fbi->dmadesc_fblow_cpu->fdadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fdadr); - pr_debug("fbi->dmadesc_fbhigh_cpu->fdadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fdadr); - pr_debug("fbi->dmadesc_palette_cpu->fdadr = 0x%x\n", fbi->dmadesc_palette_cpu->fdadr); - - pr_debug("fbi->dmadesc_fblow_cpu->fsadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fsadr); - pr_debug("fbi->dmadesc_fbhigh_cpu->fsadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fsadr); - pr_debug("fbi->dmadesc_palette_cpu->fsadr = 0x%x\n", fbi->dmadesc_palette_cpu->fsadr); - - pr_debug("fbi->dmadesc_fblow_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fblow_cpu->ldcmd); - pr_debug("fbi->dmadesc_fbhigh_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fbhigh_cpu->ldcmd); - pr_debug("fbi->dmadesc_palette_cpu->ldcmd = 0x%x\n", fbi->dmadesc_palette_cpu->ldcmd); -#endif + if ((var->bits_per_pixel >= 16) || (fbi->lccr0 & LCCR0_LCDT)) + setup_frame_dma(fbi, DMA_BASE, PAL_NONE, 0, nbytes); + else + setup_frame_dma(fbi, DMA_BASE, PAL_BASE, 0, nbytes); - fbi->reg_lccr0 = new_regs.lccr0; - fbi->reg_lccr1 = new_regs.lccr1; - fbi->reg_lccr2 = new_regs.lccr2; - fbi->reg_lccr3 = new_regs.lccr3; - fbi->reg_lccr4 = LCCR4 & (~LCCR4_PAL_FOR_MASK); + fbi->reg_lccr4 = lcd_readl(fbi, LCCR4) & ~LCCR4_PAL_FOR_MASK; fbi->reg_lccr4 |= (fbi->lccr4 & LCCR4_PAL_FOR_MASK); - set_hsync_time(fbi, pcd); local_irq_restore(flags); /* * Only update the registers if the controller is enabled * and something has changed. */ - if ((LCCR0 != fbi->reg_lccr0) || (LCCR1 != fbi->reg_lccr1) || - (LCCR2 != fbi->reg_lccr2) || (LCCR3 != fbi->reg_lccr3) || - (FDADR0 != fbi->fdadr0) || (FDADR1 != fbi->fdadr1)) + if ((lcd_readl(fbi, LCCR0) != fbi->reg_lccr0) || + (lcd_readl(fbi, LCCR1) != fbi->reg_lccr1) || + (lcd_readl(fbi, LCCR2) != fbi->reg_lccr2) || + (lcd_readl(fbi, LCCR3) != fbi->reg_lccr3) || + (lcd_readl(fbi, FDADR0) != fbi->fdadr[0]) || + (lcd_readl(fbi, FDADR1) != fbi->fdadr[1])) pxafb_schedule_work(fbi, C_REENABLE); return 0; @@ -773,8 +919,8 @@ static inline void __pxafb_backlight_power(struct pxafb_info *fbi, int on) { pr_debug("pxafb: backlight o%s\n", on ? "n" : "ff"); - if (pxafb_backlight_power) - pxafb_backlight_power(on); + if (pxafb_backlight_power) + pxafb_backlight_power(on); } static inline void __pxafb_lcd_power(struct pxafb_info *fbi, int on) @@ -788,11 +934,11 @@ static inline void __pxafb_lcd_power(struct pxafb_info *fbi, int on) static void pxafb_setup_gpio(struct pxafb_info *fbi) { int gpio, ldd_bits; - unsigned int lccr0 = fbi->lccr0; + unsigned int lccr0 = fbi->lccr0; /* * setup is based on type of panel supported - */ + */ /* 4 bit interface */ if ((lccr0 & LCCR0_CMS) == LCCR0_Mono && @@ -801,21 +947,25 @@ static void pxafb_setup_gpio(struct pxafb_info *fbi) ldd_bits = 4; /* 8 bit interface */ - else if (((lccr0 & LCCR0_CMS) == LCCR0_Mono && - ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_DPD) == LCCR0_8PixMono)) || - ((lccr0 & LCCR0_CMS) == LCCR0_Color && - (lccr0 & LCCR0_PAS) == LCCR0_Pas && (lccr0 & LCCR0_SDS) == LCCR0_Sngl)) + else if (((lccr0 & LCCR0_CMS) == LCCR0_Mono && + ((lccr0 & LCCR0_SDS) == LCCR0_Dual || + (lccr0 & LCCR0_DPD) == LCCR0_8PixMono)) || + ((lccr0 & LCCR0_CMS) == LCCR0_Color && + (lccr0 & LCCR0_PAS) == LCCR0_Pas && + (lccr0 & LCCR0_SDS) == LCCR0_Sngl)) ldd_bits = 8; /* 16 bit interface */ else if ((lccr0 & LCCR0_CMS) == LCCR0_Color && - ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_PAS) == LCCR0_Act)) + ((lccr0 & LCCR0_SDS) == LCCR0_Dual || + (lccr0 & LCCR0_PAS) == LCCR0_Act)) ldd_bits = 16; else { - printk(KERN_ERR "pxafb_setup_gpio: unable to determine bits per pixel\n"); + printk(KERN_ERR "pxafb_setup_gpio: unable to determine " + "bits per pixel\n"); return; - } + } for (gpio = 58; ldd_bits; gpio++, ldd_bits--) pxa_gpio_mode(gpio | GPIO_ALT_FN_2_OUT); @@ -828,8 +978,8 @@ static void pxafb_setup_gpio(struct pxafb_info *fbi) static void pxafb_enable_controller(struct pxafb_info *fbi) { pr_debug("pxafb: Enabling LCD controller\n"); - pr_debug("fdadr0 0x%08x\n", (unsigned int) fbi->fdadr0); - pr_debug("fdadr1 0x%08x\n", (unsigned int) fbi->fdadr1); + pr_debug("fdadr0 0x%08x\n", (unsigned int) fbi->fdadr[0]); + pr_debug("fdadr1 0x%08x\n", (unsigned int) fbi->fdadr[1]); pr_debug("reg_lccr0 0x%08x\n", (unsigned int) fbi->reg_lccr0); pr_debug("reg_lccr1 0x%08x\n", (unsigned int) fbi->reg_lccr1); pr_debug("reg_lccr2 0x%08x\n", (unsigned int) fbi->reg_lccr2); @@ -838,40 +988,40 @@ static void pxafb_enable_controller(struct pxafb_info *fbi) /* enable LCD controller clock */ clk_enable(fbi->clk); + if (fbi->lccr0 & LCCR0_LCDT) + return; + /* Sequence from 11.7.10 */ - LCCR3 = fbi->reg_lccr3; - LCCR2 = fbi->reg_lccr2; - LCCR1 = fbi->reg_lccr1; - LCCR0 = fbi->reg_lccr0 & ~LCCR0_ENB; - - FDADR0 = fbi->fdadr0; - FDADR1 = fbi->fdadr1; - LCCR0 |= LCCR0_ENB; - - pr_debug("FDADR0 0x%08x\n", (unsigned int) FDADR0); - pr_debug("FDADR1 0x%08x\n", (unsigned int) FDADR1); - pr_debug("LCCR0 0x%08x\n", (unsigned int) LCCR0); - pr_debug("LCCR1 0x%08x\n", (unsigned int) LCCR1); - pr_debug("LCCR2 0x%08x\n", (unsigned int) LCCR2); - pr_debug("LCCR3 0x%08x\n", (unsigned int) LCCR3); - pr_debug("LCCR4 0x%08x\n", (unsigned int) LCCR4); + lcd_writel(fbi, LCCR3, fbi->reg_lccr3); + lcd_writel(fbi, LCCR2, fbi->reg_lccr2); + lcd_writel(fbi, LCCR1, fbi->reg_lccr1); + lcd_writel(fbi, LCCR0, fbi->reg_lccr0 & ~LCCR0_ENB); + + lcd_writel(fbi, FDADR0, fbi->fdadr[0]); + lcd_writel(fbi, FDADR1, fbi->fdadr[1]); + lcd_writel(fbi, LCCR0, fbi->reg_lccr0 | LCCR0_ENB); } static void pxafb_disable_controller(struct pxafb_info *fbi) { - DECLARE_WAITQUEUE(wait, current); + uint32_t lccr0; - pr_debug("pxafb: disabling LCD controller\n"); +#ifdef CONFIG_FB_PXA_SMARTPANEL + if (fbi->lccr0 & LCCR0_LCDT) { + wait_for_completion_timeout(&fbi->refresh_done, + 200 * HZ / 1000); + return; + } +#endif - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&fbi->ctrlr_wait, &wait); + /* Clear LCD Status Register */ + lcd_writel(fbi, LCSR, 0xffffffff); - LCSR = 0xffffffff; /* Clear LCD Status Register */ - LCCR0 &= ~LCCR0_LDM; /* Enable LCD Disable Done Interrupt */ - LCCR0 |= LCCR0_DIS; /* Disable LCD Controller */ + lccr0 = lcd_readl(fbi, LCCR0) & ~LCCR0_LDM; + lcd_writel(fbi, LCCR0, lccr0); + lcd_writel(fbi, LCCR0, lccr0 | LCCR0_DIS); - schedule_timeout(200 * HZ / 1000); - remove_wait_queue(&fbi->ctrlr_wait, &wait); + wait_for_completion_timeout(&fbi->disable_done, 200 * HZ / 1000); /* disable LCD controller clock */ clk_disable(fbi->clk); @@ -883,14 +1033,20 @@ static void pxafb_disable_controller(struct pxafb_info *fbi) static irqreturn_t pxafb_handle_irq(int irq, void *dev_id) { struct pxafb_info *fbi = dev_id; - unsigned int lcsr = LCSR; + unsigned int lccr0, lcsr = lcd_readl(fbi, LCSR); if (lcsr & LCSR_LDD) { - LCCR0 |= LCCR0_LDM; - wake_up(&fbi->ctrlr_wait); + lccr0 = lcd_readl(fbi, LCCR0); + lcd_writel(fbi, LCCR0, lccr0 | LCCR0_LDM); + complete(&fbi->disable_done); } - LCSR = lcsr; +#ifdef CONFIG_FB_PXA_SMARTPANEL + if (lcsr & LCSR_CMD_INT) + complete(&fbi->command_done); +#endif + + lcd_writel(fbi, LCSR, lcsr); return IRQ_HANDLED; } @@ -921,7 +1077,7 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state) */ if (old_state != C_DISABLE && old_state != C_DISABLE_PM) { fbi->state = state; - //TODO __pxafb_lcd_power(fbi, 0); + /* TODO __pxafb_lcd_power(fbi, 0); */ pxafb_disable_controller(fbi); } break; @@ -948,7 +1104,7 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state) if (old_state == C_DISABLE_CLKCHANGE) { fbi->state = C_ENABLE; pxafb_enable_controller(fbi); - //TODO __pxafb_lcd_power(fbi, 1); + /* TODO __pxafb_lcd_power(fbi, 1); */ } break; @@ -1019,7 +1175,7 @@ static int pxafb_freq_transition(struct notifier_block *nb, unsigned long val, void *data) { struct pxafb_info *fbi = TO_INF(nb, freq_transition); - //TODO struct cpufreq_freqs *f = data; + /* TODO struct cpufreq_freqs *f = data; */ u_int pcd; switch (val) { @@ -1030,7 +1186,8 @@ pxafb_freq_transition(struct notifier_block *nb, unsigned long val, void *data) case CPUFREQ_POSTCHANGE: pcd = get_pcd(fbi, fbi->fb.var.pixclock); set_hsync_time(fbi, pcd); - fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd); + fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | + LCCR3_PixClkDiv(pcd); set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE); break; } @@ -1050,18 +1207,8 @@ pxafb_freq_policy(struct notifier_block *nb, unsigned long val, void *data) pr_debug("min dma period: %d ps, " "new clock %d kHz\n", pxafb_display_dma_period(var), policy->max); - // TODO: fill in min/max values - break; -#if 0 - case CPUFREQ_NOTIFY: - printk(KERN_ERR "%s: got CPUFREQ_NOTIFY\n", __FUNCTION__); - do {} while(0); - /* todo: panic if min/max values aren't fulfilled - * [can't really happen unless there's a bug in the - * CPU policy verification process * - */ + /* TODO: fill in min/max values */ break; -#endif } return 0; } @@ -1102,21 +1249,21 @@ static int pxafb_resume(struct platform_device *dev) */ static int __init pxafb_map_video_memory(struct pxafb_info *fbi) { - u_long palette_mem_size; - /* * We reserve one page for the palette, plus the size * of the framebuffer. */ - fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE); + fbi->video_offset = PAGE_ALIGN(sizeof(struct pxafb_dma_buff)); + fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + fbi->video_offset); fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size, &fbi->map_dma, GFP_KERNEL); if (fbi->map_cpu) { /* prevent initial garbage on screen */ memset(fbi->map_cpu, 0, fbi->map_size); - fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE; - fbi->screen_dma = fbi->map_dma + PAGE_SIZE; + fbi->fb.screen_base = fbi->map_cpu + fbi->video_offset; + fbi->screen_dma = fbi->map_dma + fbi->video_offset; + /* * FIXME: this is actually the wrong thing to place in * smem_start. But fbdev suffers from the problem that @@ -1126,27 +1273,86 @@ static int __init pxafb_map_video_memory(struct pxafb_info *fbi) fbi->fb.fix.smem_start = fbi->screen_dma; fbi->palette_size = fbi->fb.var.bits_per_pixel == 8 ? 256 : 16; - if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0) - palette_mem_size = fbi->palette_size * sizeof(u16); - else - palette_mem_size = fbi->palette_size * sizeof(u32); + fbi->dma_buff = (void *) fbi->map_cpu; + fbi->dma_buff_phys = fbi->map_dma; + fbi->palette_cpu = (u16 *) fbi->dma_buff->palette; - pr_debug("pxafb: palette_mem_size = 0x%08lx\n", palette_mem_size); - - fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size); - fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size; +#ifdef CONFIG_FB_PXA_SMARTPANEL + fbi->smart_cmds = (uint16_t *) fbi->dma_buff->cmd_buff; + fbi->n_smart_cmds = 0; +#endif } return fbi->map_cpu ? 0 : -ENOMEM; } +static void pxafb_decode_mode_info(struct pxafb_info *fbi, + struct pxafb_mode_info *modes, + unsigned int num_modes) +{ + unsigned int i, smemlen; + + pxafb_setmode(&fbi->fb.var, &modes[0]); + + for (i = 0; i < num_modes; i++) { + smemlen = modes[i].xres * modes[i].yres * modes[i].bpp / 8; + if (smemlen > fbi->fb.fix.smem_len) + fbi->fb.fix.smem_len = smemlen; + } +} + +static int pxafb_decode_mach_info(struct pxafb_info *fbi, + struct pxafb_mach_info *inf) +{ + unsigned int lcd_conn = inf->lcd_conn; + + fbi->cmap_inverse = inf->cmap_inverse; + fbi->cmap_static = inf->cmap_static; + + switch (lcd_conn & 0xf) { + case LCD_TYPE_MONO_STN: + fbi->lccr0 = LCCR0_CMS; + break; + case LCD_TYPE_MONO_DSTN: + fbi->lccr0 = LCCR0_CMS | LCCR0_SDS; + break; + case LCD_TYPE_COLOR_STN: + fbi->lccr0 = 0; + break; + case LCD_TYPE_COLOR_DSTN: + fbi->lccr0 = LCCR0_SDS; + break; + case LCD_TYPE_COLOR_TFT: + fbi->lccr0 = LCCR0_PAS; + break; + case LCD_TYPE_SMART_PANEL: + fbi->lccr0 = LCCR0_LCDT | LCCR0_PAS; + break; + default: + /* fall back to backward compatibility way */ + fbi->lccr0 = inf->lccr0; + fbi->lccr3 = inf->lccr3; + fbi->lccr4 = inf->lccr4; + return -EINVAL; + } + + if (lcd_conn == LCD_MONO_STN_8BPP) + fbi->lccr0 |= LCCR0_DPD; + + fbi->lccr3 = LCCR3_Acb((inf->lcd_conn >> 10) & 0xff); + fbi->lccr3 |= (lcd_conn & LCD_BIAS_ACTIVE_LOW) ? LCCR3_OEP : 0; + fbi->lccr3 |= (lcd_conn & LCD_PCLK_EDGE_FALL) ? LCCR3_PCP : 0; + + pxafb_decode_mode_info(fbi, inf->modes, inf->num_modes); + return 0; +} + static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev) { struct pxafb_info *fbi; void *addr; struct pxafb_mach_info *inf = dev->platform_data; struct pxafb_mode_info *mode = inf->modes; - int i, smemlen; /* Alloc the pxafb_info and pseudo_palette in one step */ fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(u32) * 16, GFP_KERNEL); @@ -1186,187 +1392,233 @@ static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev) addr = addr + sizeof(struct pxafb_info); fbi->fb.pseudo_palette = addr; - pxafb_setmode(&fbi->fb.var, mode); + fbi->state = C_STARTUP; + fbi->task_state = (u_char)-1; - fbi->cmap_inverse = inf->cmap_inverse; - fbi->cmap_static = inf->cmap_static; - - fbi->lccr0 = inf->lccr0; - fbi->lccr3 = inf->lccr3; - fbi->lccr4 = inf->lccr4; - fbi->state = C_STARTUP; - fbi->task_state = (u_char)-1; - - for (i = 0; i < inf->num_modes; i++) { - smemlen = mode[i].xres * mode[i].yres * mode[i].bpp / 8; - if (smemlen > fbi->fb.fix.smem_len) - fbi->fb.fix.smem_len = smemlen; - } + pxafb_decode_mach_info(fbi, inf); init_waitqueue_head(&fbi->ctrlr_wait); INIT_WORK(&fbi->task, pxafb_task); init_MUTEX(&fbi->ctrlr_sem); + init_completion(&fbi->disable_done); +#ifdef CONFIG_FB_PXA_SMARTPANEL + init_completion(&fbi->command_done); + init_completion(&fbi->refresh_done); +#endif return fbi; } #ifdef CONFIG_FB_PXA_PARAMETERS -static int __init pxafb_parse_options(struct device *dev, char *options) +static int __init parse_opt_mode(struct device *dev, const char *this_opt) +{ + struct pxafb_mach_info *inf = dev->platform_data; + + const char *name = this_opt+5; + unsigned int namelen = strlen(name); + int res_specified = 0, bpp_specified = 0; + unsigned int xres = 0, yres = 0, bpp = 0; + int yres_specified = 0; + int i; + for (i = namelen-1; i >= 0; i--) { + switch (name[i]) { + case '-': + namelen = i; + if (!bpp_specified && !yres_specified) { + bpp = simple_strtoul(&name[i+1], NULL, 0); + bpp_specified = 1; + } else + goto done; + break; + case 'x': + if (!yres_specified) { + yres = simple_strtoul(&name[i+1], NULL, 0); + yres_specified = 1; + } else + goto done; + break; + case '0' ... '9': + break; + default: + goto done; + } + } + if (i < 0 && yres_specified) { + xres = simple_strtoul(name, NULL, 0); + res_specified = 1; + } +done: + if (res_specified) { + dev_info(dev, "overriding resolution: %dx%d\n", xres, yres); + inf->modes[0].xres = xres; inf->modes[0].yres = yres; + } + if (bpp_specified) + switch (bpp) { + case 1: + case 2: + case 4: + case 8: + case 16: + inf->modes[0].bpp = bpp; + dev_info(dev, "overriding bit depth: %d\n", bpp); + break; + default: + dev_err(dev, "Depth %d is not valid\n", bpp); + return -EINVAL; + } + return 0; +} + +static int __init parse_opt(struct device *dev, char *this_opt) { struct pxafb_mach_info *inf = dev->platform_data; + struct pxafb_mode_info *mode = &inf->modes[0]; + char s[64]; + + s[0] = '\0'; + + if (!strncmp(this_opt, "mode:", 5)) { + return parse_opt_mode(dev, this_opt); + } else if (!strncmp(this_opt, "pixclock:", 9)) { + mode->pixclock = simple_strtoul(this_opt+9, NULL, 0); + sprintf(s, "pixclock: %ld\n", mode->pixclock); + } else if (!strncmp(this_opt, "left:", 5)) { + mode->left_margin = simple_strtoul(this_opt+5, NULL, 0); + sprintf(s, "left: %u\n", mode->left_margin); + } else if (!strncmp(this_opt, "right:", 6)) { + mode->right_margin = simple_strtoul(this_opt+6, NULL, 0); + sprintf(s, "right: %u\n", mode->right_margin); + } else if (!strncmp(this_opt, "upper:", 6)) { + mode->upper_margin = simple_strtoul(this_opt+6, NULL, 0); + sprintf(s, "upper: %u\n", mode->upper_margin); + } else if (!strncmp(this_opt, "lower:", 6)) { + mode->lower_margin = simple_strtoul(this_opt+6, NULL, 0); + sprintf(s, "lower: %u\n", mode->lower_margin); + } else if (!strncmp(this_opt, "hsynclen:", 9)) { + mode->hsync_len = simple_strtoul(this_opt+9, NULL, 0); + sprintf(s, "hsynclen: %u\n", mode->hsync_len); + } else if (!strncmp(this_opt, "vsynclen:", 9)) { + mode->vsync_len = simple_strtoul(this_opt+9, NULL, 0); + sprintf(s, "vsynclen: %u\n", mode->vsync_len); + } else if (!strncmp(this_opt, "hsync:", 6)) { + if (simple_strtoul(this_opt+6, NULL, 0) == 0) { + sprintf(s, "hsync: Active Low\n"); + mode->sync &= ~FB_SYNC_HOR_HIGH_ACT; + } else { + sprintf(s, "hsync: Active High\n"); + mode->sync |= FB_SYNC_HOR_HIGH_ACT; + } + } else if (!strncmp(this_opt, "vsync:", 6)) { + if (simple_strtoul(this_opt+6, NULL, 0) == 0) { + sprintf(s, "vsync: Active Low\n"); + mode->sync &= ~FB_SYNC_VERT_HIGH_ACT; + } else { + sprintf(s, "vsync: Active High\n"); + mode->sync |= FB_SYNC_VERT_HIGH_ACT; + } + } else if (!strncmp(this_opt, "dpc:", 4)) { + if (simple_strtoul(this_opt+4, NULL, 0) == 0) { + sprintf(s, "double pixel clock: false\n"); + inf->lccr3 &= ~LCCR3_DPC; + } else { + sprintf(s, "double pixel clock: true\n"); + inf->lccr3 |= LCCR3_DPC; + } + } else if (!strncmp(this_opt, "outputen:", 9)) { + if (simple_strtoul(this_opt+9, NULL, 0) == 0) { + sprintf(s, "output enable: active low\n"); + inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnL; + } else { + sprintf(s, "output enable: active high\n"); + inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnH; + } + } else if (!strncmp(this_opt, "pixclockpol:", 12)) { + if (simple_strtoul(this_opt+12, NULL, 0) == 0) { + sprintf(s, "pixel clock polarity: falling edge\n"); + inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixFlEdg; + } else { + sprintf(s, "pixel clock polarity: rising edge\n"); + inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixRsEdg; + } + } else if (!strncmp(this_opt, "color", 5)) { + inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Color; + } else if (!strncmp(this_opt, "mono", 4)) { + inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Mono; + } else if (!strncmp(this_opt, "active", 6)) { + inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Act; + } else if (!strncmp(this_opt, "passive", 7)) { + inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Pas; + } else if (!strncmp(this_opt, "single", 6)) { + inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Sngl; + } else if (!strncmp(this_opt, "dual", 4)) { + inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Dual; + } else if (!strncmp(this_opt, "4pix", 4)) { + inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_4PixMono; + } else if (!strncmp(this_opt, "8pix", 4)) { + inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_8PixMono; + } else { + dev_err(dev, "unknown option: %s\n", this_opt); + return -EINVAL; + } + + if (s[0] != '\0') + dev_info(dev, "override %s", s); + + return 0; +} + +static int __init pxafb_parse_options(struct device *dev, char *options) +{ char *this_opt; + int ret; - if (!options || !*options) - return 0; + if (!options || !*options) + return 0; dev_dbg(dev, "options are \"%s\"\n", options ? options : "null"); /* could be made table driven or similar?... */ - while ((this_opt = strsep(&options, ",")) != NULL) { - if (!strncmp(this_opt, "mode:", 5)) { - const char *name = this_opt+5; - unsigned int namelen = strlen(name); - int res_specified = 0, bpp_specified = 0; - unsigned int xres = 0, yres = 0, bpp = 0; - int yres_specified = 0; - int i; - for (i = namelen-1; i >= 0; i--) { - switch (name[i]) { - case '-': - namelen = i; - if (!bpp_specified && !yres_specified) { - bpp = simple_strtoul(&name[i+1], NULL, 0); - bpp_specified = 1; - } else - goto done; - break; - case 'x': - if (!yres_specified) { - yres = simple_strtoul(&name[i+1], NULL, 0); - yres_specified = 1; - } else - goto done; - break; - case '0' ... '9': - break; - default: - goto done; - } - } - if (i < 0 && yres_specified) { - xres = simple_strtoul(name, NULL, 0); - res_specified = 1; - } - done: - if (res_specified) { - dev_info(dev, "overriding resolution: %dx%d\n", xres, yres); - inf->modes[0].xres = xres; inf->modes[0].yres = yres; - } - if (bpp_specified) - switch (bpp) { - case 1: - case 2: - case 4: - case 8: - case 16: - inf->modes[0].bpp = bpp; - dev_info(dev, "overriding bit depth: %d\n", bpp); - break; - default: - dev_err(dev, "Depth %d is not valid\n", bpp); - } - } else if (!strncmp(this_opt, "pixclock:", 9)) { - inf->modes[0].pixclock = simple_strtoul(this_opt+9, NULL, 0); - dev_info(dev, "override pixclock: %ld\n", inf->modes[0].pixclock); - } else if (!strncmp(this_opt, "left:", 5)) { - inf->modes[0].left_margin = simple_strtoul(this_opt+5, NULL, 0); - dev_info(dev, "override left: %u\n", inf->modes[0].left_margin); - } else if (!strncmp(this_opt, "right:", 6)) { - inf->modes[0].right_margin = simple_strtoul(this_opt+6, NULL, 0); - dev_info(dev, "override right: %u\n", inf->modes[0].right_margin); - } else if (!strncmp(this_opt, "upper:", 6)) { - inf->modes[0].upper_margin = simple_strtoul(this_opt+6, NULL, 0); - dev_info(dev, "override upper: %u\n", inf->modes[0].upper_margin); - } else if (!strncmp(this_opt, "lower:", 6)) { - inf->modes[0].lower_margin = simple_strtoul(this_opt+6, NULL, 0); - dev_info(dev, "override lower: %u\n", inf->modes[0].lower_margin); - } else if (!strncmp(this_opt, "hsynclen:", 9)) { - inf->modes[0].hsync_len = simple_strtoul(this_opt+9, NULL, 0); - dev_info(dev, "override hsynclen: %u\n", inf->modes[0].hsync_len); - } else if (!strncmp(this_opt, "vsynclen:", 9)) { - inf->modes[0].vsync_len = simple_strtoul(this_opt+9, NULL, 0); - dev_info(dev, "override vsynclen: %u\n", inf->modes[0].vsync_len); - } else if (!strncmp(this_opt, "hsync:", 6)) { - if (simple_strtoul(this_opt+6, NULL, 0) == 0) { - dev_info(dev, "override hsync: Active Low\n"); - inf->modes[0].sync &= ~FB_SYNC_HOR_HIGH_ACT; - } else { - dev_info(dev, "override hsync: Active High\n"); - inf->modes[0].sync |= FB_SYNC_HOR_HIGH_ACT; - } - } else if (!strncmp(this_opt, "vsync:", 6)) { - if (simple_strtoul(this_opt+6, NULL, 0) == 0) { - dev_info(dev, "override vsync: Active Low\n"); - inf->modes[0].sync &= ~FB_SYNC_VERT_HIGH_ACT; - } else { - dev_info(dev, "override vsync: Active High\n"); - inf->modes[0].sync |= FB_SYNC_VERT_HIGH_ACT; - } - } else if (!strncmp(this_opt, "dpc:", 4)) { - if (simple_strtoul(this_opt+4, NULL, 0) == 0) { - dev_info(dev, "override double pixel clock: false\n"); - inf->lccr3 &= ~LCCR3_DPC; - } else { - dev_info(dev, "override double pixel clock: true\n"); - inf->lccr3 |= LCCR3_DPC; - } - } else if (!strncmp(this_opt, "outputen:", 9)) { - if (simple_strtoul(this_opt+9, NULL, 0) == 0) { - dev_info(dev, "override output enable: active low\n"); - inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnL; - } else { - dev_info(dev, "override output enable: active high\n"); - inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnH; - } - } else if (!strncmp(this_opt, "pixclockpol:", 12)) { - if (simple_strtoul(this_opt+12, NULL, 0) == 0) { - dev_info(dev, "override pixel clock polarity: falling edge\n"); - inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixFlEdg; - } else { - dev_info(dev, "override pixel clock polarity: rising edge\n"); - inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixRsEdg; - } - } else if (!strncmp(this_opt, "color", 5)) { - inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Color; - } else if (!strncmp(this_opt, "mono", 4)) { - inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Mono; - } else if (!strncmp(this_opt, "active", 6)) { - inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Act; - } else if (!strncmp(this_opt, "passive", 7)) { - inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Pas; - } else if (!strncmp(this_opt, "single", 6)) { - inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Sngl; - } else if (!strncmp(this_opt, "dual", 4)) { - inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Dual; - } else if (!strncmp(this_opt, "4pix", 4)) { - inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_4PixMono; - } else if (!strncmp(this_opt, "8pix", 4)) { - inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_8PixMono; - } else { - dev_err(dev, "unknown option: %s\n", this_opt); - return -EINVAL; - } - } - return 0; + while ((this_opt = strsep(&options, ",")) != NULL) { + ret = parse_opt(dev, this_opt); + if (ret) + return ret; + } + return 0; +} + +static char g_options[256] __devinitdata = ""; +#ifndef CONFIG_MODULES +static int __devinit pxafb_setup_options(void) +{ + char *options = NULL; + + if (fb_get_options("pxafb", &options)) + return -ENODEV; + + if (options) + strlcpy(g_options, options, sizeof(g_options)); + + return 0; } +#else +#define pxafb_setup_options() (0) + +module_param_string(options, g_options, sizeof(g_options), 0); +MODULE_PARM_DESC(options, "LCD parameters (see Documentation/fb/pxafb.txt)"); +#endif + +#else +#define pxafb_parse_options(...) (0) +#define pxafb_setup_options() (0) #endif static int __init pxafb_probe(struct platform_device *dev) { struct pxafb_info *fbi; struct pxafb_mach_info *inf; - int ret; + struct resource *r; + int irq, ret; dev_dbg(&dev->dev, "pxafb_probe\n"); @@ -1376,38 +1628,45 @@ static int __init pxafb_probe(struct platform_device *dev) if (!inf) goto failed; -#ifdef CONFIG_FB_PXA_PARAMETERS ret = pxafb_parse_options(&dev->dev, g_options); if (ret < 0) goto failed; -#endif #ifdef DEBUG_VAR - /* Check for various illegal bit-combinations. Currently only + /* Check for various illegal bit-combinations. Currently only * a warning is given. */ - if (inf->lccr0 & LCCR0_INVALID_CONFIG_MASK) - dev_warn(&dev->dev, "machine LCCR0 setting contains illegal bits: %08x\n", - inf->lccr0 & LCCR0_INVALID_CONFIG_MASK); - if (inf->lccr3 & LCCR3_INVALID_CONFIG_MASK) - dev_warn(&dev->dev, "machine LCCR3 setting contains illegal bits: %08x\n", - inf->lccr3 & LCCR3_INVALID_CONFIG_MASK); - if (inf->lccr0 & LCCR0_DPD && + if (inf->lccr0 & LCCR0_INVALID_CONFIG_MASK) + dev_warn(&dev->dev, "machine LCCR0 setting contains " + "illegal bits: %08x\n", + inf->lccr0 & LCCR0_INVALID_CONFIG_MASK); + if (inf->lccr3 & LCCR3_INVALID_CONFIG_MASK) + dev_warn(&dev->dev, "machine LCCR3 setting contains " + "illegal bits: %08x\n", + inf->lccr3 & LCCR3_INVALID_CONFIG_MASK); + if (inf->lccr0 & LCCR0_DPD && ((inf->lccr0 & LCCR0_PAS) != LCCR0_Pas || (inf->lccr0 & LCCR0_SDS) != LCCR0_Sngl || (inf->lccr0 & LCCR0_CMS) != LCCR0_Mono)) - dev_warn(&dev->dev, "Double Pixel Data (DPD) mode is only valid in passive mono" - " single panel mode\n"); - if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Act && + dev_warn(&dev->dev, "Double Pixel Data (DPD) mode is " + "only valid in passive mono" + " single panel mode\n"); + if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Act && (inf->lccr0 & LCCR0_SDS) == LCCR0_Dual) - dev_warn(&dev->dev, "Dual panel only valid in passive mode\n"); - if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Pas && - (inf->modes->upper_margin || inf->modes->lower_margin)) - dev_warn(&dev->dev, "Upper and lower margins must be 0 in passive mode\n"); + dev_warn(&dev->dev, "Dual panel only valid in passive mode\n"); + if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Pas && + (inf->modes->upper_margin || inf->modes->lower_margin)) + dev_warn(&dev->dev, "Upper and lower margins must be 0 in " + "passive mode\n"); #endif - dev_dbg(&dev->dev, "got a %dx%dx%d LCD\n",inf->modes->xres, inf->modes->yres, inf->modes->bpp); - if (inf->modes->xres == 0 || inf->modes->yres == 0 || inf->modes->bpp == 0) { + dev_dbg(&dev->dev, "got a %dx%dx%d LCD\n", + inf->modes->xres, + inf->modes->yres, + inf->modes->bpp); + if (inf->modes->xres == 0 || + inf->modes->yres == 0 || + inf->modes->bpp == 0) { dev_err(&dev->dev, "Invalid resolution or bit depth\n"); ret = -EINVAL; goto failed; @@ -1416,26 +1675,62 @@ static int __init pxafb_probe(struct platform_device *dev) pxafb_lcd_power = inf->pxafb_lcd_power; fbi = pxafb_init_fbinfo(&dev->dev); if (!fbi) { + /* only reason for pxafb_init_fbinfo to fail is kmalloc */ dev_err(&dev->dev, "Failed to initialize framebuffer device\n"); - ret = -ENOMEM; // only reason for pxafb_init_fbinfo to fail is kmalloc + ret = -ENOMEM; goto failed; } + r = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (r == NULL) { + dev_err(&dev->dev, "no I/O memory resource defined\n"); + ret = -ENODEV; + goto failed; + } + + r = request_mem_region(r->start, r->end - r->start + 1, dev->name); + if (r == NULL) { + dev_err(&dev->dev, "failed to request I/O memory\n"); + ret = -EBUSY; + goto failed; + } + + fbi->mmio_base = ioremap(r->start, r->end - r->start + 1); + if (fbi->mmio_base == NULL) { + dev_err(&dev->dev, "failed to map I/O memory\n"); + ret = -EBUSY; + goto failed_free_res; + } + /* Initialize video memory */ ret = pxafb_map_video_memory(fbi); if (ret) { dev_err(&dev->dev, "Failed to allocate video RAM: %d\n", ret); ret = -ENOMEM; - goto failed; + goto failed_free_io; + } + + irq = platform_get_irq(dev, 0); + if (irq < 0) { + dev_err(&dev->dev, "no IRQ defined\n"); + ret = -ENODEV; + goto failed_free_mem; } - ret = request_irq(IRQ_LCD, pxafb_handle_irq, IRQF_DISABLED, "LCD", fbi); + ret = request_irq(irq, pxafb_handle_irq, IRQF_DISABLED, "LCD", fbi); if (ret) { dev_err(&dev->dev, "request_irq failed: %d\n", ret); ret = -EBUSY; - goto failed; + goto failed_free_mem; } +#ifdef CONFIG_FB_PXA_SMARTPANEL + ret = pxafb_smart_init(fbi); + if (ret) { + dev_err(&dev->dev, "failed to initialize smartpanel\n"); + goto failed_free_irq; + } +#endif /* * This makes sure that our colour bitfield * descriptors are correctly initialised. @@ -1447,19 +1742,18 @@ static int __init pxafb_probe(struct platform_device *dev) ret = register_framebuffer(&fbi->fb); if (ret < 0) { - dev_err(&dev->dev, "Failed to register framebuffer device: %d\n", ret); - goto failed; + dev_err(&dev->dev, + "Failed to register framebuffer device: %d\n", ret); + goto failed_free_irq; } -#ifdef CONFIG_PM - // TODO -#endif - #ifdef CONFIG_CPU_FREQ fbi->freq_transition.notifier_call = pxafb_freq_transition; fbi->freq_policy.notifier_call = pxafb_freq_policy; - cpufreq_register_notifier(&fbi->freq_transition, CPUFREQ_TRANSITION_NOTIFIER); - cpufreq_register_notifier(&fbi->freq_policy, CPUFREQ_POLICY_NOTIFIER); + cpufreq_register_notifier(&fbi->freq_transition, + CPUFREQ_TRANSITION_NOTIFIER); + cpufreq_register_notifier(&fbi->freq_policy, + CPUFREQ_POLICY_NOTIFIER); #endif /* @@ -1469,6 +1763,15 @@ static int __init pxafb_probe(struct platform_device *dev) return 0; +failed_free_irq: + free_irq(irq, fbi); +failed_free_res: + release_mem_region(r->start, r->end - r->start + 1); +failed_free_io: + iounmap(fbi->mmio_base); +failed_free_mem: + dma_free_writecombine(&dev->dev, fbi->map_size, + fbi->map_cpu, fbi->map_dma); failed: platform_set_drvdata(dev, NULL); kfree(fbi); @@ -1477,40 +1780,18 @@ failed: static struct platform_driver pxafb_driver = { .probe = pxafb_probe, -#ifdef CONFIG_PM .suspend = pxafb_suspend, .resume = pxafb_resume, -#endif .driver = { .name = "pxa2xx-fb", }, }; -#ifndef MODULE -static int __devinit pxafb_setup(char *options) -{ -# ifdef CONFIG_FB_PXA_PARAMETERS - if (options) - strlcpy(g_options, options, sizeof(g_options)); -# endif - return 0; -} -#else -# ifdef CONFIG_FB_PXA_PARAMETERS -module_param_string(options, g_options, sizeof(g_options), 0); -MODULE_PARM_DESC(options, "LCD parameters (see Documentation/fb/pxafb.txt)"); -# endif -#endif - static int __devinit pxafb_init(void) { -#ifndef MODULE - char *option = NULL; + if (pxafb_setup_options()) + return -EINVAL; - if (fb_get_options("pxafb", &option)) - return -ENODEV; - pxafb_setup(option); -#endif return platform_driver_register(&pxafb_driver); } diff --git a/drivers/video/pxafb.h b/drivers/video/pxafb.h index d920b8a14c35..8238dc826429 100644 --- a/drivers/video/pxafb.h +++ b/drivers/video/pxafb.h @@ -21,14 +21,6 @@ * for more details. */ -/* Shadows for LCD controller registers */ -struct pxafb_lcd_reg { - unsigned int lccr0; - unsigned int lccr1; - unsigned int lccr2; - unsigned int lccr3; -}; - /* PXA LCD DMA descriptor */ struct pxafb_dma_descriptor { unsigned int fdadr; @@ -37,11 +29,49 @@ struct pxafb_dma_descriptor { unsigned int ldcmd; }; +enum { + PAL_NONE = -1, + PAL_BASE = 0, + PAL_OV1 = 1, + PAL_OV2 = 2, + PAL_MAX, +}; + +enum { + DMA_BASE = 0, + DMA_UPPER = 0, + DMA_LOWER = 1, + DMA_OV1 = 1, + DMA_OV2_Y = 2, + DMA_OV2_Cb = 3, + DMA_OV2_Cr = 4, + DMA_CURSOR = 5, + DMA_CMD = 6, + DMA_MAX, +}; + +/* maximum palette size - 256 entries, each 4 bytes long */ +#define PALETTE_SIZE (256 * 4) +#define CMD_BUFF_SIZE (1024 * 50) + +struct pxafb_dma_buff { + unsigned char palette[PAL_MAX * PALETTE_SIZE]; + uint16_t cmd_buff[CMD_BUFF_SIZE]; + struct pxafb_dma_descriptor pal_desc[PAL_MAX]; + struct pxafb_dma_descriptor dma_desc[DMA_MAX]; +}; + struct pxafb_info { struct fb_info fb; struct device *dev; struct clk *clk; + void __iomem *mmio_base; + + struct pxafb_dma_buff *dma_buff; + dma_addr_t dma_buff_phys; + dma_addr_t fdadr[DMA_MAX]; + /* * These are the addresses we mapped * the framebuffer memory region to. @@ -55,19 +85,8 @@ struct pxafb_info { u_char * screen_cpu; /* virtual address of frame buffer */ dma_addr_t screen_dma; /* physical address of frame buffer */ u16 * palette_cpu; /* virtual address of palette memory */ - dma_addr_t palette_dma; /* physical address of palette memory */ u_int palette_size; - - /* DMA descriptors */ - struct pxafb_dma_descriptor * dmadesc_fblow_cpu; - dma_addr_t dmadesc_fblow_dma; - struct pxafb_dma_descriptor * dmadesc_fbhigh_cpu; - dma_addr_t dmadesc_fbhigh_dma; - struct pxafb_dma_descriptor * dmadesc_palette_cpu; - dma_addr_t dmadesc_palette_dma; - - dma_addr_t fdadr0; - dma_addr_t fdadr1; + ssize_t video_offset; u_int lccr0; u_int lccr3; @@ -81,6 +100,7 @@ struct pxafb_info { u_int reg_lccr2; u_int reg_lccr3; u_int reg_lccr4; + u_int reg_cmdcr; unsigned long hsync_time; @@ -90,6 +110,16 @@ struct pxafb_info { wait_queue_head_t ctrlr_wait; struct work_struct task; + struct completion disable_done; + +#ifdef CONFIG_FB_PXA_SMARTPANEL + uint16_t *smart_cmds; + size_t n_smart_cmds; + struct completion command_done; + struct completion refresh_done; + struct task_struct *smart_thread; +#endif + #ifdef CONFIG_CPU_FREQ struct notifier_block freq_transition; struct notifier_block freq_policy; diff --git a/drivers/w1/w1_log.h b/drivers/w1/w1_log.h index fe6bdf43380f..e6ab7cf08f88 100644 --- a/drivers/w1/w1_log.h +++ b/drivers/w1/w1_log.h @@ -30,7 +30,7 @@ # define assert(expr) \ if(unlikely(!(expr))) { \ printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \ - #expr,__FILE__,__FUNCTION__,__LINE__); \ + #expr, __FILE__, __func__, __LINE__); \ } #endif diff --git a/drivers/zorro/proc.c b/drivers/zorro/proc.c index 2ce4cebc31d9..099b6fb5b5cb 100644 --- a/drivers/zorro/proc.c +++ b/drivers/zorro/proc.c @@ -13,6 +13,7 @@ #include <linux/types.h> #include <linux/zorro.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <linux/init.h> #include <linux/smp_lock.h> #include <asm/uaccess.h> @@ -76,36 +77,58 @@ proc_bus_zorro_read(struct file *file, char __user *buf, size_t nbytes, loff_t * } static const struct file_operations proc_bus_zorro_operations = { + .owner = THIS_MODULE, .llseek = proc_bus_zorro_lseek, .read = proc_bus_zorro_read, }; -static int -get_zorro_dev_info(char *buf, char **start, off_t pos, int count) +static void * zorro_seq_start(struct seq_file *m, loff_t *pos) { - u_int slot; - off_t at = 0; - int len, cnt; - - for (slot = cnt = 0; slot < zorro_num_autocon && count > cnt; slot++) { - struct zorro_dev *z = &zorro_autocon[slot]; - len = sprintf(buf, "%02x\t%08x\t%08lx\t%08lx\t%02x\n", slot, - z->id, (unsigned long)zorro_resource_start(z), - (unsigned long)zorro_resource_len(z), - z->rom.er_Type); - at += len; - if (at >= pos) { - if (!*start) { - *start = buf + (pos - (at - len)); - cnt = at - pos; - } else - cnt += len; - buf += len; - } - } - return (count > cnt) ? cnt : count; + return (*pos < zorro_num_autocon) ? pos : NULL; +} + +static void * zorro_seq_next(struct seq_file *m, void *v, loff_t *pos) +{ + (*pos)++; + return (*pos < zorro_num_autocon) ? pos : NULL; +} + +static void zorro_seq_stop(struct seq_file *m, void *v) +{ +} + +static int zorro_seq_show(struct seq_file *m, void *v) +{ + u_int slot = *(loff_t *)v; + struct zorro_dev *z = &zorro_autocon[slot]; + + seq_printf(m, "%02x\t%08x\t%08lx\t%08lx\t%02x\n", slot, z->id, + (unsigned long)zorro_resource_start(z), + (unsigned long)zorro_resource_len(z), + z->rom.er_Type); + return 0; +} + +static const struct seq_operations zorro_devices_seq_ops = { + .start = zorro_seq_start, + .next = zorro_seq_next, + .stop = zorro_seq_stop, + .show = zorro_seq_show, +}; + +static int zorro_devices_proc_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &zorro_devices_seq_ops); } +static const struct file_operations zorro_devices_proc_fops = { + .owner = THIS_MODULE, + .open = zorro_devices_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + static struct proc_dir_entry *proc_bus_zorro_dir; static int __init zorro_proc_attach_device(u_int slot) @@ -114,11 +137,11 @@ static int __init zorro_proc_attach_device(u_int slot) char name[4]; sprintf(name, "%02x", slot); - entry = create_proc_entry(name, 0, proc_bus_zorro_dir); + entry = proc_create_data(name, 0, proc_bus_zorro_dir, + &proc_bus_zorro_operations, + &zorro_autocon[slot]); if (!entry) return -ENOMEM; - entry->proc_fops = &proc_bus_zorro_operations; - entry->data = &zorro_autocon[slot]; entry->size = sizeof(struct zorro_dev); return 0; } @@ -128,9 +151,9 @@ static int __init zorro_proc_init(void) u_int slot; if (MACH_IS_AMIGA && AMIGAHW_PRESENT(ZORRO)) { - proc_bus_zorro_dir = proc_mkdir("zorro", proc_bus); - create_proc_info_entry("devices", 0, proc_bus_zorro_dir, - get_zorro_dev_info); + proc_bus_zorro_dir = proc_mkdir("bus/zorro", NULL); + proc_create("devices", 0, proc_bus_zorro_dir, + &zorro_devices_proc_fops); for (slot = 0; slot < zorro_num_autocon; slot++) zorro_proc_attach_device(slot); } |