diff options
Diffstat (limited to 'drivers')
57 files changed, 1805 insertions, 280 deletions
diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c index 1022e38994c..0f280589921 100644 --- a/drivers/acpi/dispatcher/dsobject.c +++ b/drivers/acpi/dispatcher/dsobject.c @@ -496,7 +496,7 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, arg = arg->common.next; } - ACPI_ERROR((AE_INFO, + ACPI_WARNING((AE_INFO, "Package List length (%X) larger than NumElements count (%X), truncated\n", i, element_count)); } else if (i < element_count) { diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index bb7c51f712b..7d2edf143f1 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -563,9 +563,6 @@ EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); */ static int handle_eject_request(struct dock_station *ds, u32 event) { - if (!dock_present(ds)) - return -ENODEV; - if (dock_in_progress(ds)) return -EBUSY; @@ -573,8 +570,16 @@ static int handle_eject_request(struct dock_station *ds, u32 event) * here we need to generate the undock * event prior to actually doing the undock * so that the device struct still exists. + * Also, even send the dock event if the + * device is not present anymore */ dock_event(ds, event, UNDOCK_EVENT); + + if (!dock_present(ds)) { + complete_undock(ds); + return -ENODEV; + } + hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST); undock(ds); eject_dock(ds); diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 5622aee996b..13593f9f219 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -110,6 +110,31 @@ static struct acpi_ec { u8 handlers_installed; } *boot_ec, *first_ec; +/* + * Some Asus system have exchanged ECDT data/command IO addresses. + */ +static int print_ecdt_error(const struct dmi_system_id *id) +{ + printk(KERN_NOTICE PREFIX "%s detected - " + "ECDT has exchanged control/data I/O address\n", + id->ident); + return 0; +} + +static struct dmi_system_id __cpuinitdata ec_dmi_table[] = { + { + print_ecdt_error, "Asus L4R", { + DMI_MATCH(DMI_BIOS_VERSION, "1008.006"), + DMI_MATCH(DMI_PRODUCT_NAME, "L4R"), + DMI_MATCH(DMI_BOARD_NAME, "L4R") }, NULL}, + { + print_ecdt_error, "Asus M6R", { + DMI_MATCH(DMI_BIOS_VERSION, "0207"), + DMI_MATCH(DMI_PRODUCT_NAME, "M6R"), + DMI_MATCH(DMI_BOARD_NAME, "M6R") }, NULL}, + {}, +}; + /* -------------------------------------------------------------------------- Transaction Management -------------------------------------------------------------------------- */ @@ -196,6 +221,8 @@ static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll) return 0; msleep(1); } + if (acpi_ec_check_status(ec,event)) + return 0; } pr_err(PREFIX "acpi_ec_wait timeout, status = 0x%2.2x, event = %s\n", acpi_ec_read_status(ec), @@ -911,6 +938,15 @@ int __init acpi_ec_ecdt_probe(void) pr_info(PREFIX "EC description table is found, configuring boot EC\n"); boot_ec->command_addr = ecdt_ptr->control.address; boot_ec->data_addr = ecdt_ptr->data.address; + if (dmi_check_system(ec_dmi_table)) { + /* + * If the board falls into ec_dmi_table, it means + * that ECDT table gives the incorrect command/status + * & data I/O address. Just fix it. + */ + boot_ec->data_addr = ecdt_ptr->control.address; + boot_ec->command_addr = ecdt_ptr->data.address; + } boot_ec->gpe = ecdt_ptr->gpe; boot_ec->handle = ACPI_ROOT_OBJECT; acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, &boot_ec->handle); diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c index 2a32c843cb4..8892b9824fa 100644 --- a/drivers/acpi/executer/exconfig.c +++ b/drivers/acpi/executer/exconfig.c @@ -479,5 +479,8 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) acpi_tb_set_table_loaded_flag(table_index, FALSE); + /* Table unloaded, remove a reference to the ddb_handle object */ + + acpi_ut_remove_reference(ddb_handle); return_ACPI_STATUS(AE_OK); } diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/namespace/nsnames.c index 549db42f16c..bd577387800 100644 --- a/drivers/acpi/namespace/nsnames.c +++ b/drivers/acpi/namespace/nsnames.c @@ -56,13 +56,14 @@ ACPI_MODULE_NAME("nsnames") * Size - Size of the pathname * *name_buffer - Where to return the pathname * - * RETURN: Places the pathname into the name_buffer, in external format + * RETURN: Status + * Places the pathname into the name_buffer, in external format * (name segments separated by path separators) * * DESCRIPTION: Generate a full pathaname * ******************************************************************************/ -void +acpi_status acpi_ns_build_external_path(struct acpi_namespace_node *node, acpi_size size, char *name_buffer) { @@ -77,7 +78,7 @@ acpi_ns_build_external_path(struct acpi_namespace_node *node, if (index < ACPI_NAME_SIZE) { name_buffer[0] = AML_ROOT_PREFIX; name_buffer[1] = 0; - return; + return (AE_OK); } /* Store terminator byte, then build name backwards */ @@ -105,11 +106,13 @@ acpi_ns_build_external_path(struct acpi_namespace_node *node, if (index != 0) { ACPI_ERROR((AE_INFO, - "Could not construct pathname; index=%X, size=%X, Path=%s", + "Could not construct external pathname; index=%X, size=%X, Path=%s", (u32) index, (u32) size, &name_buffer[size])); + + return (AE_BAD_PARAMETER); } - return; + return (AE_OK); } #ifdef ACPI_DEBUG_OUTPUT @@ -129,6 +132,7 @@ acpi_ns_build_external_path(struct acpi_namespace_node *node, char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node) { + acpi_status status; char *name_buffer; acpi_size size; @@ -138,8 +142,7 @@ char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node) size = acpi_ns_get_pathname_length(node); if (!size) { - ACPI_ERROR((AE_INFO, "Invalid node failure")); - return_PTR(NULL); + return (NULL); } /* Allocate a buffer to be returned to caller */ @@ -152,7 +155,11 @@ char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node) /* Build the path in the allocated buffer */ - acpi_ns_build_external_path(node, size, name_buffer); + status = acpi_ns_build_external_path(node, size, name_buffer); + if (ACPI_FAILURE(status)) { + return (NULL); + } + return_PTR(name_buffer); } #endif @@ -186,7 +193,7 @@ acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node) while (next_node && (next_node != acpi_gbl_root_node)) { if (ACPI_GET_DESCRIPTOR_TYPE(next_node) != ACPI_DESC_TYPE_NAMED) { ACPI_ERROR((AE_INFO, - "Invalid NS Node (%p) while traversing path", + "Invalid Namespace Node (%p) while traversing namespace", next_node)); return 0; } @@ -234,8 +241,7 @@ acpi_ns_handle_to_pathname(acpi_handle target_handle, required_size = acpi_ns_get_pathname_length(node); if (!required_size) { - ACPI_ERROR((AE_INFO, "Invalid node failure")); - return_ACPI_STATUS(AE_ERROR); + return_ACPI_STATUS(AE_BAD_PARAMETER); } /* Validate/Allocate/Clear caller buffer */ @@ -247,7 +253,11 @@ acpi_ns_handle_to_pathname(acpi_handle target_handle, /* Build the path in the caller buffer */ - acpi_ns_build_external_path(node, required_size, buffer->pointer); + status = + acpi_ns_build_external_path(node, required_size, buffer->pointer); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%s [%X]\n", (char *)buffer->pointer, (u32) required_size)); diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 89f3b2abfdc..cf47805a744 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -849,7 +849,7 @@ static int __init acpi_irq_penalty_update(char *str, int used) if (irq < 0) continue; - if (irq >= ACPI_MAX_IRQS) + if (irq >= ARRAY_SIZE(acpi_irq_penalty)) continue; if (used) @@ -872,10 +872,12 @@ static int __init acpi_irq_penalty_update(char *str, int used) */ void acpi_penalize_isa_irq(int irq, int active) { - if (active) - acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED; - else - acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING; + if (irq >= 0 && irq < ARRAY_SIZE(acpi_irq_penalty)) { + if (active) + acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED; + else + acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING; + } } /* diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index e36422a7122..ee68ac54c0d 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -123,7 +123,7 @@ struct acpi_processor_errata errata __read_mostly; static int set_no_mwait(const struct dmi_system_id *id) { printk(KERN_NOTICE PREFIX "%s detected - " - "disable mwait for CPU C-stetes\n", id->ident); + "disabling mwait for CPU C-states\n", id->ident); idle_nomwait = 1; return 0; } @@ -138,7 +138,7 @@ static struct dmi_system_id __cpuinitdata processor_idle_dmi_table[] = { { set_no_mwait, "Extensa 5220", { DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), - DMI_MATCH(DMI_SYS_VENDOR, "ACER"), + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_PRODUCT_VERSION, "0100"), DMI_MATCH(DMI_BOARD_NAME, "Columbia") }, NULL}, {}, diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 283c08f5f4d..cf5b1b7b684 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -41,7 +41,6 @@ #include <linux/pm_qos_params.h> #include <linux/clockchips.h> #include <linux/cpuidle.h> -#include <linux/cpuidle.h> /* * Include the apic definitions for x86 to have the APIC timer related defines diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 0133af49cf0..80c251ec6d2 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -70,8 +70,8 @@ static DEFINE_MUTEX(performance_mutex); * 0 -> cpufreq low level drivers initialized -> consider _PPC values * 1 -> ignore _PPC totally -> forced by user through boot param */ -static unsigned int ignore_ppc = -1; -module_param(ignore_ppc, uint, 0644); +static int ignore_ppc = -1; +module_param(ignore_ppc, int, 0644); MODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \ "limited by BIOS, this should help"); diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c index f61ebc679e6..d9063ea414e 100644 --- a/drivers/acpi/resources/rscalc.c +++ b/drivers/acpi/resources/rscalc.c @@ -587,6 +587,9 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, } else { temp_size_needed += acpi_ns_get_pathname_length((*sub_object_list)->reference.node); + if (!temp_size_needed) { + return_ACPI_STATUS(AE_BAD_PARAMETER); + } } } else { /* diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index c3419182c9a..775c97a282b 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -300,6 +300,8 @@ int __init acpi_table_init(void) static int __init acpi_parse_apic_instance(char *str) { + if (!str) + return -EINVAL; acpi_apic_instance = simple_strtoul(str, NULL, 0); diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c index e7bf34a7b1d..7dcb67e0b21 100644 --- a/drivers/acpi/utilities/utalloc.c +++ b/drivers/acpi/utilities/utalloc.c @@ -242,10 +242,12 @@ acpi_ut_initialize_buffer(struct acpi_buffer * buffer, { acpi_status status = AE_OK; - if (!required_length) { - WARN_ON(1); - return AE_ERROR; + /* Parameter validation */ + + if (!buffer || !required_length) { + return (AE_BAD_PARAMETER); } + switch (buffer->length) { case ACPI_NO_BUFFER: diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c index c5c791a575c..42609d3a8aa 100644 --- a/drivers/acpi/utilities/utdelete.c +++ b/drivers/acpi/utilities/utdelete.c @@ -135,6 +135,10 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) obj_pointer = object->package.elements; break; + /* + * These objects have a possible list of notify handlers. + * Device object also may have a GPE block. + */ case ACPI_TYPE_DEVICE: if (object->device.gpe_block) { @@ -142,9 +146,14 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) gpe_block); } - /* Walk the handler list for this device */ + /*lint -fallthrough */ + + case ACPI_TYPE_PROCESSOR: + case ACPI_TYPE_THERMAL: + + /* Walk the notify handler list for this object */ - handler_desc = object->device.handler; + handler_desc = object->common_notify.handler; while (handler_desc) { next_desc = handler_desc->address_space.next; acpi_ut_remove_reference(handler_desc); diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/utilities/utobject.c index e25484495e6..916eff399eb 100644 --- a/drivers/acpi/utilities/utobject.c +++ b/drivers/acpi/utilities/utobject.c @@ -425,6 +425,7 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object, acpi_size * obj_length) { acpi_size length; + acpi_size size; acpi_status status = AE_OK; ACPI_FUNCTION_TRACE_PTR(ut_get_simple_object_size, internal_object); @@ -484,10 +485,14 @@ acpi_ut_get_simple_object_size(union acpi_operand_object *internal_object, * Get the actual length of the full pathname to this object. * The reference will be converted to the pathname to the object */ - length += - ACPI_ROUND_UP_TO_NATIVE_WORD - (acpi_ns_get_pathname_length - (internal_object->reference.node)); + size = + acpi_ns_get_pathname_length(internal_object-> + reference.node); + if (!size) { + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + + length += ACPI_ROUND_UP_TO_NATIVE_WORD(size); break; default: diff --git a/drivers/acpi/wmi.c b/drivers/acpi/wmi.c index c33b1c6e93b..cfe2c833474 100644 --- a/drivers/acpi/wmi.c +++ b/drivers/acpi/wmi.c @@ -347,7 +347,7 @@ struct acpi_buffer *out) strcpy(method, "WQ"); strncat(method, block->object_id, 2); - status = acpi_evaluate_object(handle, method, NULL, out); + status = acpi_evaluate_object(handle, method, &input, out); /* * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if diff --git a/drivers/char/pcmcia/ipwireless/tty.c b/drivers/char/pcmcia/ipwireless/tty.c index b1414507997..3a23e7694d5 100644 --- a/drivers/char/pcmcia/ipwireless/tty.c +++ b/drivers/char/pcmcia/ipwireless/tty.c @@ -29,7 +29,6 @@ #include <linux/tty_driver.h> #include <linux/tty_flip.h> #include <linux/uaccess.h> -#include <linux/version.h> #include "tty.h" #include "network.h" diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 509c89ac5bd..08911ed6649 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -47,7 +47,6 @@ #include <linux/module.h> -#include <linux/version.h> #include <linux/errno.h> #include <linux/signal.h> #include <linux/sched.h> diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 0e6866fe0f9..a27160ba21d 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -2496,45 +2496,25 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg) } /** - * tiocswinsz - implement window size set ioctl - * @tty; tty - * @arg: user buffer for result + * tty_do_resize - resize event + * @tty: tty being resized + * @real_tty: real tty (if using a pty/tty pair) + * @rows: rows (character) + * @cols: cols (character) * - * Copies the user idea of the window size to the kernel. Traditionally - * this is just advisory information but for the Linux console it - * actually has driver level meaning and triggers a VC resize. - * - * Locking: - * Called function use the console_sem is used to ensure we do - * not try and resize the console twice at once. - * The tty->termios_mutex is used to ensure we don't double - * resize and get confused. Lock order - tty->termios_mutex before - * console sem + * Update the termios variables and send the neccessary signals to + * peform a terminal resize correctly */ -static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, - struct winsize __user *arg) +int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty, + struct winsize *ws) { - struct winsize tmp_ws; struct pid *pgrp, *rpgrp; unsigned long flags; - if (copy_from_user(&tmp_ws, arg, sizeof(*arg))) - return -EFAULT; - mutex_lock(&tty->termios_mutex); - if (!memcmp(&tmp_ws, &tty->winsize, sizeof(*arg))) + if (!memcmp(ws, &tty->winsize, sizeof(*ws))) goto done; - -#ifdef CONFIG_VT - if (tty->driver->type == TTY_DRIVER_TYPE_CONSOLE) { - if (vc_lock_resize(tty->driver_data, tmp_ws.ws_col, - tmp_ws.ws_row)) { - mutex_unlock(&tty->termios_mutex); - return -ENXIO; - } - } -#endif /* 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); @@ -2550,14 +2530,42 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, put_pid(pgrp); put_pid(rpgrp); - tty->winsize = tmp_ws; - real_tty->winsize = tmp_ws; + tty->winsize = *ws; + real_tty->winsize = *ws; done: mutex_unlock(&tty->termios_mutex); return 0; } /** + * tiocswinsz - implement window size set ioctl + * @tty; tty + * @arg: user buffer for result + * + * Copies the user idea of the window size to the kernel. Traditionally + * this is just advisory information but for the Linux console it + * actually has driver level meaning and triggers a VC resize. + * + * Locking: + * Driver dependant. The default do_resize method takes the + * tty termios mutex and ctrl_lock. The console takes its own lock + * then calls into the default method. + */ + +static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, + struct winsize __user *arg) +{ + struct winsize tmp_ws; + if (copy_from_user(&tmp_ws, arg, sizeof(*arg))) + return -EFAULT; + + if (tty->ops->resize) + return tty->ops->resize(tty, real_tty, &tmp_ws); + else + return tty_do_resize(tty, real_tty, &tmp_ws); +} + +/** * tioccons - allow admin to move logical console * @file: the file to become console * diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 1bc00c9d860..60359c36091 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -803,7 +803,25 @@ static inline int resize_screen(struct vc_data *vc, int width, int height, */ #define VC_RESIZE_MAXCOL (32767) #define VC_RESIZE_MAXROW (32767) -int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) + +/** + * vc_do_resize - resizing method for the tty + * @tty: tty being resized + * @real_tty: real tty (different to tty if a pty/tty pair) + * @vc: virtual console private data + * @cols: columns + * @lines: lines + * + * Resize a virtual console, clipping according to the actual constraints. + * If the caller passes a tty structure then update the termios winsize + * information and perform any neccessary signal handling. + * + * Caller must hold the console semaphore. Takes the termios mutex and + * ctrl_lock of the tty IFF a tty is passed. + */ + +static int vc_do_resize(struct tty_struct *tty, struct tty_struct *real_tty, + struct vc_data *vc, unsigned int cols, unsigned int lines) { unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0; unsigned int old_cols, old_rows, old_row_size, old_screen_size; @@ -907,24 +925,15 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) gotoxy(vc, vc->vc_x, vc->vc_y); save_cur(vc); - if (vc->vc_tty) { - struct winsize ws, *cws = &vc->vc_tty->winsize; - struct pid *pgrp = NULL; - + if (tty) { + /* Rewrite the requested winsize data with the actual + resulting sizes */ + struct winsize ws; memset(&ws, 0, sizeof(ws)); ws.ws_row = vc->vc_rows; ws.ws_col = vc->vc_cols; ws.ws_ypixel = vc->vc_scan_lines; - - spin_lock_irq(&vc->vc_tty->ctrl_lock); - if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col)) - pgrp = get_pid(vc->vc_tty->pgrp); - spin_unlock_irq(&vc->vc_tty->ctrl_lock); - if (pgrp) { - kill_pgrp(vc->vc_tty->pgrp, SIGWINCH, 1); - put_pid(pgrp); - } - *cws = ws; + tty_do_resize(tty, real_tty, &ws); } if (CON_IS_VISIBLE(vc)) @@ -932,14 +941,47 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) return err; } -int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) +/** + * vc_resize - resize a VT + * @vc: virtual console + * @cols: columns + * @rows: rows + * + * Resize a virtual console as seen from the console end of things. We + * use the common vc_do_resize methods to update the structures. The + * caller must hold the console sem to protect console internals and + * vc->vc_tty + */ + +int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows) +{ + return vc_do_resize(vc->vc_tty, vc->vc_tty, vc, cols, rows); +} + +/** + * vt_resize - resize a VT + * @tty: tty to resize + * @real_tty: tty if a pty/tty pair + * @ws: winsize attributes + * + * Resize a virtual terminal. This is called by the tty layer as we + * register our own handler for resizing. The mutual helper does all + * the actual work. + * + * Takes the console sem and the called methods then take the tty + * termios_mutex and the tty ctrl_lock in that order. + */ + +int vt_resize(struct tty_struct *tty, struct tty_struct *real_tty, + struct winsize *ws) { - int rc; + struct vc_data *vc = tty->driver_data; + int ret; acquire_console_sem(); - rc = vc_resize(vc, cols, lines); + ret = vc_do_resize(tty, real_tty, vc, ws->ws_col, ws->ws_row); release_console_sem(); - return rc; + return ret; } void vc_deallocate(unsigned int currcons) @@ -2907,6 +2949,7 @@ static const struct tty_operations con_ops = { .start = con_start, .throttle = con_throttle, .unthrottle = con_unthrottle, + .resize = vt_resize, }; int __init vty_init(void) @@ -4061,7 +4104,6 @@ EXPORT_SYMBOL(default_blu); EXPORT_SYMBOL(update_region); EXPORT_SYMBOL(redraw_screen); EXPORT_SYMBOL(vc_resize); -EXPORT_SYMBOL(vc_lock_resize); EXPORT_SYMBOL(fg_console); EXPORT_SYMBOL(console_blank_hook); EXPORT_SYMBOL(console_blanked); diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index 3211afd9d57..c904e9ad4a7 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -947,14 +947,16 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, get_user(cc, &vtsizes->v_cols)) ret = -EFAULT; else { + acquire_console_sem(); 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); + vc_resize(vc_cons[i].d, cc, ll); } } + release_console_sem(); } break; } diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index 8bfee5fb722..278c9857bcf 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c @@ -74,7 +74,6 @@ * currently programmed in the FPGA. */ -#include <linux/version.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c index ba7b9a6b17a..a4bec3f919a 100644 --- a/drivers/cpuidle/governors/ladder.c +++ b/drivers/cpuidle/governors/ladder.c @@ -67,10 +67,17 @@ static int ladder_select_state(struct cpuidle_device *dev) struct ladder_device *ldev = &__get_cpu_var(ladder_devices); struct ladder_device_state *last_state; int last_residency, last_idx = ldev->last_state_idx; + int latency_req = pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY); if (unlikely(!ldev)) return 0; + /* Special case when user has set very strict latency requirement */ + if (unlikely(latency_req == 0)) { + ladder_do_selection(ldev, last_idx, 0); + return 0; + } + last_state = &ldev->states[last_idx]; if (dev->states[last_idx].flags & CPUIDLE_FLAG_TIME_VALID) @@ -81,8 +88,7 @@ static int ladder_select_state(struct cpuidle_device *dev) /* consider promotion */ if (last_idx < dev->state_count - 1 && last_residency > last_state->threshold.promotion_time && - dev->states[last_idx + 1].exit_latency <= - pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY)) { + dev->states[last_idx + 1].exit_latency <= latency_req) { last_state->stats.promotion_count++; last_state->stats.demotion_count = 0; if (last_state->stats.promotion_count >= last_state->threshold.promotion_count) { @@ -92,7 +98,19 @@ static int ladder_select_state(struct cpuidle_device *dev) } /* consider demotion */ - if (last_idx > 0 && + if (last_idx > CPUIDLE_DRIVER_STATE_START && + dev->states[last_idx].exit_latency > latency_req) { + int i; + + for (i = last_idx - 1; i > CPUIDLE_DRIVER_STATE_START; i--) { + if (dev->states[i].exit_latency <= latency_req) + break; + } + ladder_do_selection(ldev, last_idx, i); + return i; + } + + if (last_idx > CPUIDLE_DRIVER_STATE_START && last_residency < last_state->threshold.demotion_time) { last_state->stats.demotion_count++; last_state->stats.promotion_count = 0; @@ -117,7 +135,7 @@ static int ladder_enable_device(struct cpuidle_device *dev) struct ladder_device_state *lstate; struct cpuidle_state *state; - ldev->last_state_idx = 0; + ldev->last_state_idx = CPUIDLE_DRIVER_STATE_START; for (i = 0; i < dev->state_count; i++) { state = &dev->states[i]; diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 78d77c5dc35..8d7cf3f3145 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -34,21 +34,28 @@ static DEFINE_PER_CPU(struct menu_device, menu_devices); static int menu_select(struct cpuidle_device *dev) { struct menu_device *data = &__get_cpu_var(menu_devices); + int latency_req = pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY); int i; + /* Special case when user has set very strict latency requirement */ + if (unlikely(latency_req == 0)) { + data->last_state_idx = 0; + return 0; + } + /* determine the expected residency time */ data->expected_us = (u32) ktime_to_ns(tick_nohz_get_sleep_length()) / 1000; /* find the deepest idle state that satisfies our constraints */ - for (i = 1; i < dev->state_count; i++) { + for (i = CPUIDLE_DRIVER_STATE_START + 1; i < dev->state_count; i++) { struct cpuidle_state *s = &dev->states[i]; if (s->target_residency > data->expected_us) break; if (s->target_residency > data->predicted_us) break; - if (s->exit_latency > pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY)) + if (s->exit_latency > latency_req) break; } @@ -67,9 +74,9 @@ static void menu_reflect(struct cpuidle_device *dev) { struct menu_device *data = &__get_cpu_var(menu_devices); int last_idx = data->last_state_idx; - unsigned int measured_us = - cpuidle_get_last_residency(dev) + data->elapsed_us; + unsigned int last_idle_us = cpuidle_get_last_residency(dev); struct cpuidle_state *target = &dev->states[last_idx]; + unsigned int measured_us; /* * Ugh, this idle state doesn't support residency measurements, so we @@ -77,20 +84,27 @@ static void menu_reflect(struct cpuidle_device *dev) * for one full standard timer tick. However, be aware that this * could potentially result in a suboptimal state transition. */ - if (!(target->flags & CPUIDLE_FLAG_TIME_VALID)) - measured_us = USEC_PER_SEC / HZ; + if (unlikely(!(target->flags & CPUIDLE_FLAG_TIME_VALID))) + last_idle_us = USEC_PER_SEC / HZ; + + /* + * measured_us and elapsed_us are the cumulative idle time, since the + * last time we were woken out of idle by an interrupt. + */ + if (data->elapsed_us <= data->elapsed_us + last_idle_us) + measured_us = data->elapsed_us + last_idle_us; + else + measured_us = -1; + + /* Predict time until next break event */ + data->predicted_us = max(measured_us, data->last_measured_us); - /* Predict time remaining until next break event */ - if (measured_us + BREAK_FUZZ < data->expected_us - target->exit_latency) { - data->predicted_us = max(measured_us, data->last_measured_us); + if (last_idle_us + BREAK_FUZZ < + data->expected_us - target->exit_latency) { data->last_measured_us = measured_us; data->elapsed_us = 0; } else { - if (data->elapsed_us < data->elapsed_us + measured_us) - data->elapsed_us = measured_us; - else - data->elapsed_us = -1; - data->predicted_us = max(measured_us, data->last_measured_us); + data->elapsed_us = measured_us; } } diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index a4e4494663b..0328da020a1 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -25,7 +25,7 @@ #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/memory.h> -#include <asm/plat-orion/mv_xor.h> +#include <plat/mv_xor.h> #include "mv_xor.h" static void mv_xor_issue_pending(struct dma_chan *chan); diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 61e78a4369b..b15f8824963 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -654,12 +654,12 @@ static const struct hid_blacklist { { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI, HID_QUIRK_APPLE_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS, HID_QUIRK_APPLE_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI, HID_QUIRK_APPLE_HAS_FN }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD }, - { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS, HID_QUIRK_APPLE_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD | HID_QUIRK_IGNORE_MOUSE}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index bf4ebfb86fa..d402e8d813c 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -77,6 +77,22 @@ config SENSORS_AD7418 This driver can also be built as a module. If so, the module will be called ad7418. +config SENSORS_ADCXX + tristate "National Semiconductor ADCxxxSxxx" + depends on SPI_MASTER && EXPERIMENTAL + help + If you say yes here you get support for the National Semiconductor + ADC<bb><c>S<sss> chip family, where + * bb is the resolution in number of bits (8, 10, 12) + * c is the number of channels (1, 2, 4, 8) + * sss is the maximum conversion speed (021 for 200 kSPS, 051 for 500 + kSPS and 101 for 1 MSPS) + + Examples : ADC081S101, ADC124S501, ... + + This driver can also be built as a module. If so, the module + will be called adcxx. + config SENSORS_ADM1021 tristate "Analog Devices ADM1021 and compatibles" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 7943e5cefb0..950134ab842 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o obj-$(CONFIG_SENSORS_AD7414) += ad7414.o obj-$(CONFIG_SENSORS_AD7418) += ad7418.o +obj-$(CONFIG_SENSORS_ADCXX) += adcxx.o obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o diff --git a/drivers/hwmon/abituguru3.c b/drivers/hwmon/abituguru3.c index f00f497b9ca..d568c65c137 100644 --- a/drivers/hwmon/abituguru3.c +++ b/drivers/hwmon/abituguru3.c @@ -1,5 +1,8 @@ /* - abituguru3.c Copyright (c) 2006 Hans de Goede <j.w.r.degoede@hhs.nl> + abituguru3.c + + Copyright (c) 2006-2008 Hans de Goede <j.w.r.degoede@hhs.nl> + Copyright (c) 2008 Alistair John Strachan <alistair@devzero.co.uk> 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 @@ -116,7 +119,7 @@ struct abituguru3_sensor_info { struct abituguru3_motherboard_info { u16 id; - const char *name; + const char *dmi_name; /* + 1 -> end of sensors indicated by a sensor with name == NULL */ struct abituguru3_sensor_info sensors[ABIT_UGURU3_MAX_NO_SENSORS + 1]; }; @@ -161,7 +164,7 @@ struct abituguru3_data { /* Constants */ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { - { 0x000C, "unknown", { + { 0x000C, NULL /* Unknown, need DMI string */, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR", 1, 0, 10, 1, 0 }, { "DDR VTT", 2, 0, 10, 1, 0 }, @@ -183,7 +186,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX1 Fan", 35, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x000D, "Abit AW8", { + { 0x000D, NULL /* Abit AW8, need DMI string */, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR", 1, 0, 10, 1, 0 }, { "DDR VTT", 2, 0, 10, 1, 0 }, @@ -212,7 +215,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX5 Fan", 39, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x000E, "AL-8", { + { 0x000E, NULL /* AL-8, need DMI string */, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR", 1, 0, 10, 1, 0 }, { "DDR VTT", 2, 0, 10, 1, 0 }, @@ -233,7 +236,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "SYS Fan", 34, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x000F, "unknown", { + { 0x000F, NULL /* Unknown, need DMI string */, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR", 1, 0, 10, 1, 0 }, { "DDR VTT", 2, 0, 10, 1, 0 }, @@ -254,7 +257,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "SYS Fan", 34, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x0010, "Abit NI8 SLI GR", { + { 0x0010, NULL /* Abit NI8 SLI GR, need DMI string */, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR", 1, 0, 10, 1, 0 }, { "DDR VTT", 2, 0, 10, 1, 0 }, @@ -276,7 +279,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "OTES1 Fan", 36, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x0011, "Abit AT8 32X", { + { 0x0011, NULL /* Abit AT8 32X, need DMI string */, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR", 1, 0, 20, 1, 0 }, { "DDR VTT", 2, 0, 10, 1, 0 }, @@ -302,7 +305,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX2 Fan", 36, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x0012, "Abit AN8 32X", { + { 0x0012, NULL /* Abit AN8 32X, need DMI string */, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR", 1, 0, 20, 1, 0 }, { "DDR VTT", 2, 0, 10, 1, 0 }, @@ -324,7 +327,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX1 Fan", 36, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x0013, "Abit AW8D", { + { 0x0013, NULL /* Abit AW8D, need DMI string */, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR", 1, 0, 10, 1, 0 }, { "DDR VTT", 2, 0, 10, 1, 0 }, @@ -353,7 +356,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX5 Fan", 39, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x0014, "Abit AB9 Pro", { + { 0x0014, NULL /* Abit AB9 Pro, need DMI string */, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR", 1, 0, 10, 1, 0 }, { "DDR VTT", 2, 0, 10, 1, 0 }, @@ -374,7 +377,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "SYS Fan", 34, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x0015, "unknown", { + { 0x0015, NULL /* Unknown, need DMI string */, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR", 1, 0, 20, 1, 0 }, { "DDR VTT", 2, 0, 10, 1, 0 }, @@ -398,7 +401,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX3 Fan", 36, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x0016, "AW9D-MAX", { + { 0x0016, NULL /* AW9D-MAX, need DMI string */, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR2", 1, 0, 20, 1, 0 }, { "DDR2 VTT", 2, 0, 10, 1, 0 }, @@ -426,7 +429,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "OTES1 Fan", 38, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x0017, "unknown", { + { 0x0017, NULL /* Unknown, need DMI string */, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR2", 1, 0, 20, 1, 0 }, { "DDR2 VTT", 2, 0, 10, 1, 0 }, @@ -451,7 +454,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX3 FAN", 37, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x0018, "unknown", { + { 0x0018, NULL /* Unknown, need DMI string */, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR2", 1, 0, 20, 1, 0 }, { "DDR2 VTT", 2, 0, 10, 1, 0 }, @@ -478,7 +481,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX3 Fan", 36, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x0019, "unknown", { + { 0x0019, NULL /* Unknown, need DMI string */, { { "CPU Core", 7, 0, 10, 1, 0 }, { "DDR2", 13, 0, 20, 1, 0 }, { "DDR2 VTT", 14, 0, 10, 1, 0 }, @@ -505,7 +508,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX3 FAN", 36, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x001A, "Abit IP35 Pro", { + { 0x001A, "IP35 Pro(Intel P35-ICH9R)", { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR2", 1, 0, 20, 1, 0 }, { "DDR2 VTT", 2, 0, 10, 1, 0 }, @@ -533,7 +536,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX4 Fan", 37, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x001B, "unknown", { + { 0x001B, NULL /* Unknown, need DMI string */, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR3", 1, 0, 20, 1, 0 }, { "DDR3 VTT", 2, 0, 10, 1, 0 }, @@ -560,7 +563,7 @@ static const struct abituguru3_motherboard_info abituguru3_motherboards[] = { { "AUX3 Fan", 36, 2, 60, 1, 0 }, { NULL, 0, 0, 0, 0, 0 } } }, - { 0x001C, "unknown", { + { 0x001C, NULL /* Unknown, need DMI string */, { { "CPU Core", 0, 0, 10, 1, 0 }, { "DDR2", 1, 0, 20, 1, 0 }, { "DDR2 VTT", 2, 0, 10, 1, 0 }, @@ -935,9 +938,18 @@ static int __devinit abituguru3_probe(struct platform_device *pdev) goto abituguru3_probe_error; } data->sensors = abituguru3_motherboards[i].sensors; + printk(KERN_INFO ABIT_UGURU3_NAME ": found Abit uGuru3, motherboard " - "ID: %04X (%s)\n", (unsigned int)id, - abituguru3_motherboards[i].name); + "ID: %04X\n", (unsigned int)id); + +#ifdef CONFIG_DMI + if (!abituguru3_motherboards[i].dmi_name) { + printk(KERN_WARNING ABIT_UGURU3_NAME ": this motherboard was " + "not detected using DMI. Please send the output of " + "\"dmidecode\" to the abituguru3 maintainer" + "(see MAINTAINERS)\n"); + } +#endif /* Fill the sysfs attr array */ sysfs_attr_i = 0; @@ -1109,6 +1121,46 @@ static struct platform_driver abituguru3_driver = { .resume = abituguru3_resume }; +#ifdef CONFIG_DMI + +static int __init abituguru3_dmi_detect(void) +{ + const char *board_vendor, *board_name; + int i, err = (force) ? 1 : -ENODEV; + + board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); + if (!board_vendor || strcmp(board_vendor, "http://www.abit.com.tw/")) + return err; + + board_name = dmi_get_system_info(DMI_BOARD_NAME); + if (!board_name) + return err; + + for (i = 0; abituguru3_motherboards[i].id; i++) { + const char *dmi_name = abituguru3_motherboards[i].dmi_name; + if (dmi_name && !strcmp(dmi_name, board_name)) + break; + } + + if (!abituguru3_motherboards[i].id) + return 1; + + return 0; +} + +#else /* !CONFIG_DMI */ + +static inline int abituguru3_dmi_detect(void) +{ + return -ENODEV; +} + +#endif /* CONFIG_DMI */ + +/* FIXME: Manual detection should die eventually; we need to collect stable + * DMI model names first before we can rely entirely on CONFIG_DMI. + */ + static int __init abituguru3_detect(void) { /* See if there is an uguru3 there. An idle uGuru3 will hold 0x00 or @@ -1119,7 +1171,7 @@ static int __init abituguru3_detect(void) if (((data_val == 0x00) || (data_val == 0x08)) && ((cmd_val == 0xAC) || (cmd_val == 0x05) || (cmd_val == 0x55))) - return ABIT_UGURU3_BASE; + return 0; ABIT_UGURU3_DEBUG("no Abit uGuru3 found, data = 0x%02X, cmd = " "0x%02X\n", (unsigned int)data_val, (unsigned int)cmd_val); @@ -1127,7 +1179,7 @@ static int __init abituguru3_detect(void) if (force) { printk(KERN_INFO ABIT_UGURU3_NAME ": Assuming Abit uGuru3 is " "present because of \"force\" parameter\n"); - return ABIT_UGURU3_BASE; + return 0; } /* No uGuru3 found */ @@ -1138,27 +1190,29 @@ static struct platform_device *abituguru3_pdev; static int __init abituguru3_init(void) { - int address, err; struct resource res = { .flags = IORESOURCE_IO }; - -#ifdef CONFIG_DMI - const char *board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); - - /* safety check, refuse to load on non Abit motherboards */ - if (!force && (!board_vendor || - strcmp(board_vendor, "http://www.abit.com.tw/"))) - return -ENODEV; -#endif - - address = abituguru3_detect(); - if (address < 0) - return address; + int err; + + /* Attempt DMI detection first */ + err = abituguru3_dmi_detect(); + if (err < 0) + return err; + + /* Fall back to manual detection if there was no exact + * board name match, or force was specified. + */ + if (err > 0) { + err = abituguru3_detect(); + if (err) + return err; + } err = platform_driver_register(&abituguru3_driver); if (err) goto exit; - abituguru3_pdev = platform_device_alloc(ABIT_UGURU3_NAME, address); + abituguru3_pdev = platform_device_alloc(ABIT_UGURU3_NAME, + ABIT_UGURU3_BASE); if (!abituguru3_pdev) { printk(KERN_ERR ABIT_UGURU3_NAME ": Device allocation failed\n"); @@ -1166,8 +1220,8 @@ static int __init abituguru3_init(void) goto exit_driver_unregister; } - res.start = address; - res.end = address + ABIT_UGURU3_REGION_LENGTH - 1; + res.start = ABIT_UGURU3_BASE; + res.end = ABIT_UGURU3_BASE + ABIT_UGURU3_REGION_LENGTH - 1; res.name = ABIT_UGURU3_NAME; err = platform_device_add_resources(abituguru3_pdev, &res, 1); diff --git a/drivers/hwmon/adcxx.c b/drivers/hwmon/adcxx.c new file mode 100644 index 00000000000..242294db3db --- /dev/null +++ b/drivers/hwmon/adcxx.c @@ -0,0 +1,329 @@ +/* + * adcxx.c + * + * The adcxx4s is an AD converter family from National Semiconductor (NS). + * + * Copyright (c) 2008 Marc Pignat <marc.pignat@hevs.ch> + * + * The adcxx4s communicates with a host processor via an SPI/Microwire Bus + * interface. This driver supports the whole family of devices with name + * ADC<bb><c>S<sss>, where + * * bb is the resolution in number of bits (8, 10, 12) + * * c is the number of channels (1, 2, 4, 8) + * * sss is the maximum conversion speed (021 for 200 kSPS, 051 for 500 kSPS + * and 101 for 1 MSPS) + * + * Complete datasheets are available at National's website here: + * http://www.national.com/ds/DC/ADC<bb><c>S<sss>.pdf + * + * Handling of 8, 10 and 12 bits converters are the same, the + * unavailable bits are 0 :) + * + * 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 <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/sysfs.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/mutex.h> +#include <linux/spi/spi.h> + +#define DRVNAME "adcxx" + +struct adcxx { + struct device *hwmon_dev; + struct mutex lock; + u32 channels; + u32 reference; /* in millivolts */ +}; + +/* sysfs hook function */ +static ssize_t adcxx_read(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct spi_device *spi = to_spi_device(dev); + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct adcxx *adc = dev_get_drvdata(&spi->dev); + u8 tx_buf[2] = { attr->index << 3 }; /* other bits are don't care */ + u8 rx_buf[2]; + int status; + int value; + + if (mutex_lock_interruptible(&adc->lock)) + return -ERESTARTSYS; + + status = spi_write_then_read(spi, tx_buf, sizeof(tx_buf), + rx_buf, sizeof(rx_buf)); + if (status < 0) { + dev_warn(dev, "spi_write_then_read failed with status %d\n", + status); + goto out; + } + + value = (rx_buf[0] << 8) + rx_buf[1]; + dev_dbg(dev, "raw value = 0x%x\n", value); + + value = value * adc->reference >> 12; + status = sprintf(buf, "%d\n", value); +out: + mutex_unlock(&adc->lock); + return status; +} + +static ssize_t adcxx_show_min(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + /* The minimum reference is 0 for this chip family */ + return sprintf(buf, "0\n"); +} + +static ssize_t adcxx_show_max(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct spi_device *spi = to_spi_device(dev); + struct adcxx *adc = dev_get_drvdata(&spi->dev); + u32 reference; + + if (mutex_lock_interruptible(&adc->lock)) + return -ERESTARTSYS; + + reference = adc->reference; + + mutex_unlock(&adc->lock); + + return sprintf(buf, "%d\n", reference); +} + +static ssize_t adcxx_set_max(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + struct spi_device *spi = to_spi_device(dev); + struct adcxx *adc = dev_get_drvdata(&spi->dev); + unsigned long value; + + if (strict_strtoul(buf, 10, &value)) + return -EINVAL; + + if (mutex_lock_interruptible(&adc->lock)) + return -ERESTARTSYS; + + adc->reference = value; + + mutex_unlock(&adc->lock); + + return count; +} + +static ssize_t adcxx_show_name(struct device *dev, struct device_attribute + *devattr, char *buf) +{ + struct spi_device *spi = to_spi_device(dev); + struct adcxx *adc = dev_get_drvdata(&spi->dev); + + return sprintf(buf, "adcxx%ds\n", adc->channels); +} + +static struct sensor_device_attribute ad_input[] = { + SENSOR_ATTR(name, S_IRUGO, adcxx_show_name, NULL, 0), + SENSOR_ATTR(in_min, S_IRUGO, adcxx_show_min, NULL, 0), + SENSOR_ATTR(in_max, S_IWUSR | S_IRUGO, adcxx_show_max, + adcxx_set_max, 0), + SENSOR_ATTR(in0_input, S_IRUGO, adcxx_read, NULL, 0), + SENSOR_ATTR(in1_input, S_IRUGO, adcxx_read, NULL, 1), + SENSOR_ATTR(in2_input, S_IRUGO, adcxx_read, NULL, 2), + SENSOR_ATTR(in3_input, S_IRUGO, adcxx_read, NULL, 3), + SENSOR_ATTR(in4_input, S_IRUGO, adcxx_read, NULL, 4), + SENSOR_ATTR(in5_input, S_IRUGO, adcxx_read, NULL, 5), + SENSOR_ATTR(in6_input, S_IRUGO, adcxx_read, NULL, 6), + SENSOR_ATTR(in7_input, S_IRUGO, adcxx_read, NULL, 7), +}; + +/*----------------------------------------------------------------------*/ + +static int __devinit adcxx_probe(struct spi_device *spi, int channels) +{ + struct adcxx *adc; + int status; + int i; + + adc = kzalloc(sizeof *adc, GFP_KERNEL); + if (!adc) + return -ENOMEM; + + /* set a default value for the reference */ + adc->reference = 3300; + adc->channels = channels; + mutex_init(&adc->lock); + + mutex_lock(&adc->lock); + + dev_set_drvdata(&spi->dev, adc); + + for (i = 0; i < 3 + adc->channels; i++) { + status = device_create_file(&spi->dev, &ad_input[i].dev_attr); + if (status) { + dev_err(&spi->dev, "device_create_file failed.\n"); + goto out_err; + } + } + + adc->hwmon_dev = hwmon_device_register(&spi->dev); + if (IS_ERR(adc->hwmon_dev)) { + dev_err(&spi->dev, "hwmon_device_register failed.\n"); + status = PTR_ERR(adc->hwmon_dev); + goto out_err; + } + + mutex_unlock(&adc->lock); + return 0; + +out_err: + for (i--; i >= 0; i--) + device_remove_file(&spi->dev, &ad_input[i].dev_attr); + + dev_set_drvdata(&spi->dev, NULL); + mutex_unlock(&adc->lock); + kfree(adc); + return status; +} + +static int __devinit adcxx1s_probe(struct spi_device *spi) +{ + return adcxx_probe(spi, 1); +} + +static int __devinit adcxx2s_probe(struct spi_device *spi) +{ + return adcxx_probe(spi, 2); +} + +static int __devinit adcxx4s_probe(struct spi_device *spi) +{ + return adcxx_probe(spi, 4); +} + +static int __devinit adcxx8s_probe(struct spi_device *spi) +{ + return adcxx_probe(spi, 8); +} + +static int __devexit adcxx_remove(struct spi_device *spi) +{ + struct adcxx *adc = dev_get_drvdata(&spi->dev); + int i; + + mutex_lock(&adc->lock); + hwmon_device_unregister(adc->hwmon_dev); + for (i = 0; i < 3 + adc->channels; i++) + device_remove_file(&spi->dev, &ad_input[i].dev_attr); + + dev_set_drvdata(&spi->dev, NULL); + mutex_unlock(&adc->lock); + kfree(adc); + + return 0; +} + +static struct spi_driver adcxx1s_driver = { + .driver = { + .name = "adcxx1s", + .owner = THIS_MODULE, + }, + .probe = adcxx1s_probe, + .remove = __devexit_p(adcxx_remove), +}; + +static struct spi_driver adcxx2s_driver = { + .driver = { + .name = "adcxx2s", + .owner = THIS_MODULE, + }, + .probe = adcxx2s_probe, + .remove = __devexit_p(adcxx_remove), +}; + +static struct spi_driver adcxx4s_driver = { + .driver = { + .name = "adcxx4s", + .owner = THIS_MODULE, + }, + .probe = adcxx4s_probe, + .remove = __devexit_p(adcxx_remove), +}; + +static struct spi_driver adcxx8s_driver = { + .driver = { + .name = "adcxx8s", + .owner = THIS_MODULE, + }, + .probe = adcxx8s_probe, + .remove = __devexit_p(adcxx_remove), +}; + +static int __init init_adcxx(void) +{ + int status; + status = spi_register_driver(&adcxx1s_driver); + if (status) + goto reg_1_failed; + + status = spi_register_driver(&adcxx2s_driver); + if (status) + goto reg_2_failed; + + status = spi_register_driver(&adcxx4s_driver); + if (status) + goto reg_4_failed; + + status = spi_register_driver(&adcxx8s_driver); + if (status) + goto reg_8_failed; + + return status; + +reg_8_failed: + spi_unregister_driver(&adcxx4s_driver); +reg_4_failed: + spi_unregister_driver(&adcxx2s_driver); +reg_2_failed: + spi_unregister_driver(&adcxx1s_driver); +reg_1_failed: + return status; +} + +static void __exit exit_adcxx(void) +{ + spi_unregister_driver(&adcxx1s_driver); + spi_unregister_driver(&adcxx2s_driver); + spi_unregister_driver(&adcxx4s_driver); + spi_unregister_driver(&adcxx8s_driver); +} + +module_init(init_adcxx); +module_exit(exit_adcxx); + +MODULE_AUTHOR("Marc Pignat"); +MODULE_DESCRIPTION("National Semiconductor adcxx8sxxx Linux driver"); +MODULE_LICENSE("GPL"); + +MODULE_ALIAS("adcxx1s"); +MODULE_ALIAS("adcxx2s"); +MODULE_ALIAS("adcxx4s"); +MODULE_ALIAS("adcxx8s"); diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index aacc0c4b809..b06b8e090a2 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -98,6 +98,12 @@ static const char* temperature_sensors_sets[][36] = { "TH1P", "TH2P", "TH3P", "TMAP", "TMAS", "TMBS", "TM0P", "TM0S", "TM1P", "TM1S", "TM2P", "TM2S", "TM3S", "TM8P", "TM8S", "TM9P", "TM9S", "TN0H", "TS0C", NULL }, +/* Set 5: iMac */ + { "TC0D", "TA0P", "TG0P", "TG0D", "TG0H", "TH0P", "Tm0P", "TO0P", + "Tp0C", NULL }, +/* Set 6: Macbook3 set */ + { "TB0T", "TC0D", "TC0P", "TM0P", "TN0P", "TTF0", "TW0P", "Th0H", + "Th0S", "Th1H", NULL }, }; /* List of keys used to read/write fan speeds */ @@ -1223,6 +1229,10 @@ static __initdata struct dmi_match_data applesmc_dmi_data[] = { { .accelerometer = 0, .light = 0, .temperature_set = 3 }, /* MacPro: temperature set 4 */ { .accelerometer = 0, .light = 0, .temperature_set = 4 }, +/* iMac: temperature set 5 */ + { .accelerometer = 0, .light = 0, .temperature_set = 5 }, +/* MacBook3: accelerometer and temperature set 6 */ + { .accelerometer = 1, .light = 0, .temperature_set = 6 }, }; /* Note that DMI_MATCH(...,"MacBook") will match "MacBookPro1,1". @@ -1232,10 +1242,14 @@ static __initdata struct dmi_system_id applesmc_whitelist[] = { DMI_MATCH(DMI_BOARD_VENDOR,"Apple"), DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro") }, (void*)&applesmc_dmi_data[0]}, - { applesmc_dmi_match, "Apple MacBook", { + { applesmc_dmi_match, "Apple MacBook (v2)", { DMI_MATCH(DMI_BOARD_VENDOR,"Apple"), DMI_MATCH(DMI_PRODUCT_NAME,"MacBook2") }, (void*)&applesmc_dmi_data[1]}, + { applesmc_dmi_match, "Apple MacBook (v3)", { + DMI_MATCH(DMI_BOARD_VENDOR,"Apple"), + DMI_MATCH(DMI_PRODUCT_NAME,"MacBook3") }, + (void*)&applesmc_dmi_data[6]}, { applesmc_dmi_match, "Apple MacBook", { DMI_MATCH(DMI_BOARD_VENDOR,"Apple"), DMI_MATCH(DMI_PRODUCT_NAME,"MacBook") }, @@ -1248,6 +1262,10 @@ static __initdata struct dmi_system_id applesmc_whitelist[] = { DMI_MATCH(DMI_BOARD_VENDOR,"Apple"), DMI_MATCH(DMI_PRODUCT_NAME,"MacPro2") }, (void*)&applesmc_dmi_data[4]}, + { applesmc_dmi_match, "Apple iMac", { + DMI_MATCH(DMI_BOARD_VENDOR,"Apple"), + DMI_MATCH(DMI_PRODUCT_NAME,"iMac") }, + (void*)&applesmc_dmi_data[5]}, { .ident = NULL } }; diff --git a/drivers/hwmon/coretemp.c b/drivers/hwmon/coretemp.c index 70239acecc8..93c17223b52 100644 --- a/drivers/hwmon/coretemp.c +++ b/drivers/hwmon/coretemp.c @@ -413,10 +413,11 @@ static int __init coretemp_init(void) for_each_online_cpu(i) { struct cpuinfo_x86 *c = &cpu_data(i); - /* check if family 6, models 0xe, 0xf, 0x16, 0x17 */ + /* check if family 6, models 0xe, 0xf, 0x16, 0x17, 0x1A */ if ((c->cpuid_level < 0) || (c->x86 != 0x6) || !((c->x86_model == 0xe) || (c->x86_model == 0xf) || - (c->x86_model == 0x16) || (c->x86_model == 0x17))) { + (c->x86_model == 0x16) || (c->x86_model == 0x17) || + (c->x86_model == 0x1A))) { /* supported CPU not found, but report the unknown family 6 CPU */ diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c index 7b0a32c4dcf..c54eff92be4 100644 --- a/drivers/hwmon/hwmon-vid.c +++ b/drivers/hwmon/hwmon-vid.c @@ -37,13 +37,21 @@ * For VRD 10.0 and up, "VRD x.y Design Guide", * available at http://developer.intel.com/. * - * AMD NPT 0Fh (Athlon64 & Opteron), AMD Publication 32559, + * AMD Athlon 64 and AMD Opteron Processors, AMD Publication 26094, + * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/26094.PDF + * Table 74. VID Code Voltages + * This corresponds to an arbitrary VRM code of 24 in the functions below. + * These CPU models (K8 revision <= E) have 5 VID pins. See also: + * Revision Guide for AMD Athlon 64 and AMD Opteron Processors, AMD Publication 25759, + * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25759.pdf + * + * AMD NPT Family 0Fh Processors, AMD Publication 32559, * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/32559.pdf * Table 71. VID Code Voltages - * AMD Opteron processors don't follow the Intel specifications. - * I'm going to "make up" 2.4 as the spec number for the Opterons. - * No good reason just a mnemonic for the 24x Opteron processor - * series. + * This corresponds to an arbitrary VRM code of 25 in the functions below. + * These CPU models (K8 revision >= F) have 6 VID pins. See also: + * Revision Guide for AMD NPT Family 0Fh Processors, AMD Publication 33610, + * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/33610.pdf * * The 17 specification is in fact Intel Mobile Voltage Positioning - * (IMVP-II). You can find more information in the datasheet of Max1718 @@ -95,7 +103,12 @@ int vid_from_reg(int val, u8 vrm) return 0; return((1600000 - (val - 2) * 6250 + 500) / 1000); - case 24: /* AMD NPT 0Fh (Athlon64 & Opteron) */ + case 24: /* Athlon64 & Opteron */ + val &= 0x1f; + if (val == 0x1f) + return 0; + /* fall through */ + case 25: /* AMD NPT 0Fh */ val &= 0x3f; return (val < 32) ? 1550 - 25 * val : 775 - (25 * (val - 31)) / 2; @@ -157,11 +170,16 @@ struct vrm_model { #ifdef CONFIG_X86 -/* the stepping parameter is highest acceptable stepping for current line */ +/* + * The stepping parameter is highest acceptable stepping for current line. + * The model match must be exact for 4-bit values. For model values 0x10 + * and above (extended model), all models below the parameter will match. + */ static struct vrm_model vrm_models[] = { {X86_VENDOR_AMD, 0x6, ANY, ANY, 90}, /* Athlon Duron etc */ - {X86_VENDOR_AMD, 0xF, ANY, ANY, 24}, /* Athlon 64, Opteron and above VRM 24 */ + {X86_VENDOR_AMD, 0xF, 0x3F, ANY, 24}, /* Athlon 64, Opteron */ + {X86_VENDOR_AMD, 0xF, ANY, ANY, 25}, /* NPT family 0Fh */ {X86_VENDOR_INTEL, 0x6, 0x9, ANY, 13}, /* Pentium M (130 nm) */ {X86_VENDOR_INTEL, 0x6, 0xB, ANY, 85}, /* Tualatin */ {X86_VENDOR_INTEL, 0x6, 0xD, ANY, 13}, /* Pentium M (90 nm) */ @@ -189,6 +207,8 @@ static u8 find_vrm(u8 eff_family, u8 eff_model, u8 eff_stepping, u8 vendor) if (vrm_models[i].vendor==vendor) if ((vrm_models[i].eff_family==eff_family) && ((vrm_models[i].eff_model==eff_model) || + (vrm_models[i].eff_model >= 0x10 && + eff_model <= vrm_models[i].eff_model) || (vrm_models[i].eff_model==ANY)) && (eff_stepping <= vrm_models[i].eff_stepping)) return vrm_models[i].vrm_type; diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c index f9e2ed621f7..2ede9388096 100644 --- a/drivers/hwmon/i5k_amb.c +++ b/drivers/hwmon/i5k_amb.c @@ -81,6 +81,8 @@ static unsigned long amb_reg_temp(unsigned int amb) #define MAX_AMBS_PER_CHANNEL 16 #define MAX_AMBS (MAX_MEM_CHANNELS * \ MAX_AMBS_PER_CHANNEL) +#define CHANNEL_SHIFT 4 +#define DIMM_MASK 0xF /* * Ugly hack: For some reason the highest bit is set if there * are _any_ DIMMs in the channel. Attempting to read from @@ -89,7 +91,7 @@ static unsigned long amb_reg_temp(unsigned int amb) * might prevent us from seeing the 16th DIMM in the channel. */ #define REAL_MAX_AMBS_PER_CHANNEL 15 -#define KNOBS_PER_AMB 5 +#define KNOBS_PER_AMB 6 static unsigned long amb_num_from_reg(unsigned int byte_num, unsigned int bit) { @@ -238,6 +240,16 @@ static ssize_t show_amb_temp(struct device *dev, 500 * amb_read_byte(data, amb_reg_temp(attr->index))); } +static ssize_t show_label(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + + return sprintf(buf, "Ch. %d DIMM %d\n", attr->index >> CHANNEL_SHIFT, + attr->index & DIMM_MASK); +} + static int __devinit i5k_amb_hwmon_init(struct platform_device *pdev) { int i, j, k, d = 0; @@ -268,6 +280,20 @@ static int __devinit i5k_amb_hwmon_init(struct platform_device *pdev) continue; d++; + /* sysfs label */ + iattr = data->attrs + data->num_attrs; + snprintf(iattr->name, AMB_SYSFS_NAME_LEN, + "temp%d_label", d); + iattr->s_attr.dev_attr.attr.name = iattr->name; + iattr->s_attr.dev_attr.attr.mode = S_IRUGO; + iattr->s_attr.dev_attr.show = show_label; + iattr->s_attr.index = k; + res = device_create_file(&pdev->dev, + &iattr->s_attr.dev_attr); + if (res) + goto exit_remove; + data->num_attrs++; + /* Temperature sysfs knob */ iattr = data->attrs + data->num_attrs; snprintf(iattr->name, AMB_SYSFS_NAME_LEN, diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c index c9416e65748..0f70dc20410 100644 --- a/drivers/hwmon/ibmaem.c +++ b/drivers/hwmon/ibmaem.c @@ -1,6 +1,6 @@ /* - * A hwmon driver for the IBM Active Energy Manager temperature/power sensors - * and capping functionality. + * A hwmon driver for the IBM System Director Active Energy Manager (AEM) + * temperature/power/energy sensors and capping functionality. * Copyright (C) 2008 IBM * * Author: Darrick J. Wong <djwong@us.ibm.com> @@ -463,12 +463,18 @@ static int aem_read_sensor(struct aem_data *data, u8 elt, u8 reg, } /* Update AEM energy registers */ +static void update_aem_energy_one(struct aem_data *data, int which) +{ + aem_read_sensor(data, AEM_ENERGY_ELEMENT, which, + &data->energy[which], 8); +} + static void update_aem_energy(struct aem_data *data) { - aem_read_sensor(data, AEM_ENERGY_ELEMENT, 0, &data->energy[0], 8); + update_aem_energy_one(data, 0); if (data->ver_major < 2) return; - aem_read_sensor(data, AEM_ENERGY_ELEMENT, 1, &data->energy[1], 8); + update_aem_energy_one(data, 1); } /* Update all AEM1 sensors */ @@ -676,7 +682,8 @@ static int aem_find_aem2(struct aem_ipmi_data *data, return -ETIMEDOUT; if (data->rx_result || data->rx_msg_len != sizeof(*fi_resp) || - memcmp(&fi_resp->id, &system_x_id, sizeof(system_x_id))) + memcmp(&fi_resp->id, &system_x_id, sizeof(system_x_id)) || + fi_resp->num_instances <= instance_num) return -ENOENT; return 0; @@ -849,7 +856,7 @@ static ssize_t aem_show_power(struct device *dev, struct timespec b, a; mutex_lock(&data->lock); - update_aem_energy(data); + update_aem_energy_one(data, attr->index); getnstimeofday(&b); before = data->energy[attr->index]; @@ -861,7 +868,7 @@ static ssize_t aem_show_power(struct device *dev, return 0; } - update_aem_energy(data); + update_aem_energy_one(data, attr->index); getnstimeofday(&a); after = data->energy[attr->index]; mutex_unlock(&data->lock); @@ -880,7 +887,9 @@ static ssize_t aem_show_energy(struct device *dev, { struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct aem_data *a = dev_get_drvdata(dev); - a->update(a); + mutex_lock(&a->lock); + update_aem_energy_one(a, attr->index); + mutex_unlock(&a->lock); return sprintf(buf, "%llu\n", (unsigned long long)a->energy[attr->index] * 1000); @@ -1104,7 +1113,7 @@ static void __exit aem_exit(void) } MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>"); -MODULE_DESCRIPTION("IBM Active Energy Manager power/temp sensor driver"); +MODULE_DESCRIPTION("IBM AEM power/temp/energy sensor driver"); MODULE_LICENSE("GPL"); module_init(aem_init); diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index daa7d121483..de21142d106 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -1055,9 +1055,10 @@ static int w83791d_probe(struct i2c_client *client, { struct w83791d_data *data; struct device *dev = &client->dev; - int i, val1, err; + int i, err; #ifdef DEBUG + int val1; val1 = w83791d_read(client, W83791D_REG_DID_VID4); dev_dbg(dev, "Device ID version: %d.%d (0x%02x)\n", (val1 >> 5) & 0x07, (val1 >> 1) & 0x0f, val1); diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 2d65411f676..a92d8156755 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -647,6 +647,47 @@ static int str_to_user(const char *str, unsigned int maxlen, void __user *p) return copy_to_user(p, str, len) ? -EFAULT : len; } +#define OLD_KEY_MAX 0x1ff +static int handle_eviocgbit(struct input_dev *dev, unsigned int cmd, void __user *p, int compat_mode) +{ + static unsigned long keymax_warn_time; + unsigned long *bits; + int len; + + switch (_IOC_NR(cmd) & EV_MAX) { + + case 0: bits = dev->evbit; len = EV_MAX; break; + case EV_KEY: bits = dev->keybit; len = KEY_MAX; break; + case EV_REL: bits = dev->relbit; len = REL_MAX; break; + case EV_ABS: bits = dev->absbit; len = ABS_MAX; break; + case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break; + case EV_LED: bits = dev->ledbit; len = LED_MAX; break; + case EV_SND: bits = dev->sndbit; len = SND_MAX; break; + case EV_FF: bits = dev->ffbit; len = FF_MAX; break; + case EV_SW: bits = dev->swbit; len = SW_MAX; break; + default: return -EINVAL; + } + + /* + * Work around bugs in userspace programs that like to do + * EVIOCGBIT(EV_KEY, KEY_MAX) and not realize that 'len' + * should be in bytes, not in bits. + */ + if ((_IOC_NR(cmd) & EV_MAX) == EV_KEY && _IOC_SIZE(cmd) == OLD_KEY_MAX) { + len = OLD_KEY_MAX; + if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000)) + printk(KERN_WARNING + "evdev.c(EVIOCGBIT): Suspicious buffer size %d, " + "limiting output to %d bytes. See " + "http://userweb.kernel.org/~dtor/eviocgbit-bug.html\n", + OLD_KEY_MAX, + BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long)); + } + + return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode); +} +#undef OLD_KEY_MAX + static long evdev_do_ioctl(struct file *file, unsigned int cmd, void __user *p, int compat_mode) { @@ -733,26 +774,8 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, if (_IOC_DIR(cmd) == _IOC_READ) { - if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0))) { - - unsigned long *bits; - int len; - - switch (_IOC_NR(cmd) & EV_MAX) { - - case 0: bits = dev->evbit; len = EV_MAX; break; - case EV_KEY: bits = dev->keybit; len = KEY_MAX; break; - case EV_REL: bits = dev->relbit; len = REL_MAX; break; - case EV_ABS: bits = dev->absbit; len = ABS_MAX; break; - case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break; - case EV_LED: bits = dev->ledbit; len = LED_MAX; break; - case EV_SND: bits = dev->sndbit; len = SND_MAX; break; - case EV_FF: bits = dev->ffbit; len = FF_MAX; break; - case EV_SW: bits = dev->swbit; len = SW_MAX; break; - default: return -EINVAL; - } - return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode); - } + if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0))) + return handle_eviocgbit(dev, cmd, p, compat_mode); if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd), diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 87d3e7eabff..6791be81eb2 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -127,6 +127,7 @@ static const struct xpad_device { { 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x0c12, 0x8802, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, + { 0x0c12, 0x880a, "Pelican Eclipse PL-2023", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x0c12, 0x8810, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x0e4c, 0x1097, "Radica Gamester Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index be58730e636..3f48279f219 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -118,6 +118,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) unsigned int type = button->type ?: EV_KEY; bdata->input = input; + bdata->button = button; setup_timer(&bdata->timer, gpio_check_button, (unsigned long)bdata); @@ -256,7 +257,7 @@ static int gpio_keys_resume(struct platform_device *pdev) #define gpio_keys_resume NULL #endif -struct platform_driver gpio_keys_device_driver = { +static struct platform_driver gpio_keys_device_driver = { .probe = gpio_keys_probe, .remove = __devexit_p(gpio_keys_remove), .suspend = gpio_keys_suspend, diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 7bbea097cda..f996546fc44 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -130,6 +130,29 @@ config MOUSE_APPLETOUCH To compile this driver as a module, choose M here: the module will be called appletouch. +config MOUSE_BCM5974 + tristate "Apple USB BCM5974 Multitouch trackpad support" + depends on USB_ARCH_HAS_HCD + select USB + help + Say Y here if you have an Apple USB BCM5974 Multitouch + trackpad. + + The BCM5974 is the multitouch trackpad found in the Macbook + Air (JAN2008) and Macbook Pro Penryn (FEB2008) laptops. + + It is also found in the IPhone (2007) and Ipod Touch (2008). + + This driver provides multitouch functionality together with + the synaptics X11 driver. + + The interface is currently identical to the appletouch interface, + for further information, see + <file:Documentation/input/appletouch.txt>. + + To compile this driver as a module, choose M here: the + module will be called bcm5974. + config MOUSE_INPORT tristate "InPort/MS/ATIXL busmouse" depends on ISA diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index 9e6e3633082..d4d20251609 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o obj-$(CONFIG_MOUSE_APPLETOUCH) += appletouch.o +obj-$(CONFIG_MOUSE_BCM5974) += bcm5974.o obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o obj-$(CONFIG_MOUSE_INPORT) += inport.o diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c new file mode 100644 index 00000000000..2ec921bf3c6 --- /dev/null +++ b/drivers/input/mouse/bcm5974.c @@ -0,0 +1,681 @@ +/* + * Apple USB BCM5974 (Macbook Air and Penryn Macbook Pro) multitouch driver + * + * Copyright (C) 2008 Henrik Rydberg (rydberg@euromail.se) + * + * The USB initialization and package decoding was made by + * Scott Shawcroft as part of the touchd user-space driver project: + * Copyright (C) 2008 Scott Shawcroft (scott.shawcroft@gmail.com) + * + * The BCM5974 driver is based on the appletouch driver: + * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2005 Johannes Berg (johannes@sipsolutions.net) + * Copyright (C) 2005 Stelian Pop (stelian@popies.net) + * Copyright (C) 2005 Frank Arnold (frank@scirocco-5v-turbo.de) + * Copyright (C) 2005 Peter Osterlund (petero2@telia.com) + * Copyright (C) 2005 Michael Hanselmann (linux-kernel@hansmi.ch) + * Copyright (C) 2006 Nicolas Boichat (nicolas@boichat.ch) + * + * 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 <linux/kernel.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/usb/input.h> +#include <linux/hid.h> +#include <linux/mutex.h> + +#define USB_VENDOR_ID_APPLE 0x05ac + +/* MacbookAir, aka wellspring */ +#define USB_DEVICE_ID_APPLE_WELLSPRING_ANSI 0x0223 +#define USB_DEVICE_ID_APPLE_WELLSPRING_ISO 0x0224 +#define USB_DEVICE_ID_APPLE_WELLSPRING_JIS 0x0225 +/* MacbookProPenryn, aka wellspring2 */ +#define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI 0x0230 +#define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO 0x0231 +#define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS 0x0232 + +#define BCM5974_DEVICE(prod) { \ + .match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \ + USB_DEVICE_ID_MATCH_INT_CLASS | \ + USB_DEVICE_ID_MATCH_INT_PROTOCOL), \ + .idVendor = USB_VENDOR_ID_APPLE, \ + .idProduct = (prod), \ + .bInterfaceClass = USB_INTERFACE_CLASS_HID, \ + .bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE \ +} + +/* table of devices that work with this driver */ +static const struct usb_device_id bcm5974_table [] = { + /* MacbookAir1.1 */ + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_ANSI), + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_ISO), + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_JIS), + /* MacbookProPenryn */ + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI), + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_ISO), + BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_JIS), + /* Terminating entry */ + {} +}; +MODULE_DEVICE_TABLE(usb, bcm5974_table); + +MODULE_AUTHOR("Henrik Rydberg"); +MODULE_DESCRIPTION("Apple USB BCM5974 multitouch driver"); +MODULE_LICENSE("GPL"); + +#define dprintk(level, format, a...)\ + { if (debug >= level) printk(KERN_DEBUG format, ##a); } + +static int debug = 1; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Activate debugging output"); + +/* button data structure */ +struct bt_data { + u8 unknown1; /* constant */ + u8 button; /* left button */ + u8 rel_x; /* relative x coordinate */ + u8 rel_y; /* relative y coordinate */ +}; + +/* trackpad header structure */ +struct tp_header { + u8 unknown1[16]; /* constants, timers, etc */ + u8 fingers; /* number of fingers on trackpad */ + u8 unknown2[9]; /* constants, timers, etc */ +}; + +/* trackpad finger structure */ +struct tp_finger { + __le16 origin; /* left/right origin? */ + __le16 abs_x; /* absolute x coodinate */ + __le16 abs_y; /* absolute y coodinate */ + __le16 rel_x; /* relative x coodinate */ + __le16 rel_y; /* relative y coodinate */ + __le16 size_major; /* finger size, major axis? */ + __le16 size_minor; /* finger size, minor axis? */ + __le16 orientation; /* 16384 when point, else 15 bit angle */ + __le16 force_major; /* trackpad force, major axis? */ + __le16 force_minor; /* trackpad force, minor axis? */ + __le16 unused[3]; /* zeros */ + __le16 multi; /* one finger: varies, more fingers: constant */ +}; + +/* trackpad data structure, empirically at least ten fingers */ +struct tp_data { + struct tp_header header; + struct tp_finger finger[16]; +}; + +/* device-specific parameters */ +struct bcm5974_param { + int dim; /* logical dimension */ + int fuzz; /* logical noise value */ + int devmin; /* device minimum reading */ + int devmax; /* device maximum reading */ +}; + +/* device-specific configuration */ +struct bcm5974_config { + int ansi, iso, jis; /* the product id of this device */ + int bt_ep; /* the endpoint of the button interface */ + int bt_datalen; /* data length of the button interface */ + int tp_ep; /* the endpoint of the trackpad interface */ + int tp_datalen; /* data length of the trackpad interface */ + struct bcm5974_param p; /* finger pressure limits */ + struct bcm5974_param w; /* finger width limits */ + struct bcm5974_param x; /* horizontal limits */ + struct bcm5974_param y; /* vertical limits */ +}; + +/* logical device structure */ +struct bcm5974 { + char phys[64]; + struct usb_device *udev; /* usb device */ + struct usb_interface *intf; /* our interface */ + struct input_dev *input; /* input dev */ + struct bcm5974_config cfg; /* device configuration */ + struct mutex pm_mutex; /* serialize access to open/suspend */ + int opened; /* 1: opened, 0: closed */ + struct urb *bt_urb; /* button usb request block */ + struct bt_data *bt_data; /* button transferred data */ + struct urb *tp_urb; /* trackpad usb request block */ + struct tp_data *tp_data; /* trackpad transferred data */ +}; + +/* logical dimensions */ +#define DIM_PRESSURE 256 /* maximum finger pressure */ +#define DIM_WIDTH 16 /* maximum finger width */ +#define DIM_X 1280 /* maximum trackpad x value */ +#define DIM_Y 800 /* maximum trackpad y value */ + +/* logical signal quality */ +#define SN_PRESSURE 45 /* pressure signal-to-noise ratio */ +#define SN_WIDTH 100 /* width signal-to-noise ratio */ +#define SN_COORD 250 /* coordinate signal-to-noise ratio */ + +/* device constants */ +static const struct bcm5974_config bcm5974_config_table[] = { + { + USB_DEVICE_ID_APPLE_WELLSPRING_ANSI, + USB_DEVICE_ID_APPLE_WELLSPRING_ISO, + USB_DEVICE_ID_APPLE_WELLSPRING_JIS, + 0x84, sizeof(struct bt_data), + 0x81, sizeof(struct tp_data), + { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 }, + { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, + { DIM_X, DIM_X / SN_COORD, -4824, 5342 }, + { DIM_Y, DIM_Y / SN_COORD, -172, 5820 } + }, + { + USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI, + USB_DEVICE_ID_APPLE_WELLSPRING2_ISO, + USB_DEVICE_ID_APPLE_WELLSPRING2_JIS, + 0x84, sizeof(struct bt_data), + 0x81, sizeof(struct tp_data), + { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 }, + { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, + { DIM_X, DIM_X / SN_COORD, -4824, 4824 }, + { DIM_Y, DIM_Y / SN_COORD, -172, 4290 } + }, + {} +}; + +/* return the device-specific configuration by device */ +static const struct bcm5974_config *bcm5974_get_config(struct usb_device *udev) +{ + u16 id = le16_to_cpu(udev->descriptor.idProduct); + const struct bcm5974_config *cfg; + + for (cfg = bcm5974_config_table; cfg->ansi; ++cfg) + if (cfg->ansi == id || cfg->iso == id || cfg->jis == id) + return cfg; + + return bcm5974_config_table; +} + +/* convert 16-bit little endian to signed integer */ +static inline int raw2int(__le16 x) +{ + return (signed short)le16_to_cpu(x); +} + +/* scale device data to logical dimensions (asserts devmin < devmax) */ +static inline int int2scale(const struct bcm5974_param *p, int x) +{ + return x * p->dim / (p->devmax - p->devmin); +} + +/* all logical value ranges are [0,dim). */ +static inline int int2bound(const struct bcm5974_param *p, int x) +{ + int s = int2scale(p, x); + + return clamp_val(s, 0, p->dim - 1); +} + +/* setup which logical events to report */ +static void setup_events_to_report(struct input_dev *input_dev, + const struct bcm5974_config *cfg) +{ + __set_bit(EV_ABS, input_dev->evbit); + + input_set_abs_params(input_dev, ABS_PRESSURE, + 0, cfg->p.dim, cfg->p.fuzz, 0); + input_set_abs_params(input_dev, ABS_TOOL_WIDTH, + 0, cfg->w.dim, cfg->w.fuzz, 0); + input_set_abs_params(input_dev, ABS_X, + 0, cfg->x.dim, cfg->x.fuzz, 0); + input_set_abs_params(input_dev, ABS_Y, + 0, cfg->y.dim, cfg->y.fuzz, 0); + + __set_bit(EV_KEY, input_dev->evbit); + __set_bit(BTN_TOOL_FINGER, input_dev->keybit); + __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit); + __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit); + __set_bit(BTN_LEFT, input_dev->keybit); +} + +/* report button data as logical button state */ +static int report_bt_state(struct bcm5974 *dev, int size) +{ + if (size != sizeof(struct bt_data)) + return -EIO; + + input_report_key(dev->input, BTN_LEFT, dev->bt_data->button); + input_sync(dev->input); + + return 0; +} + +/* report trackpad data as logical trackpad state */ +static int report_tp_state(struct bcm5974 *dev, int size) +{ + const struct bcm5974_config *c = &dev->cfg; + const struct tp_finger *f = dev->tp_data->finger; + struct input_dev *input = dev->input; + const int fingers = (size - 26) / 28; + int p = 0, w, x, y, n = 0; + + if (size < 26 || (size - 26) % 28 != 0) + return -EIO; + + if (fingers) { + p = raw2int(f->force_major); + w = raw2int(f->size_major); + x = raw2int(f->abs_x); + y = raw2int(f->abs_y); + n = p > 0 ? fingers : 0; + + dprintk(9, + "bcm5974: p: %+05d w: %+05d x: %+05d y: %+05d n: %d\n", + p, w, x, y, n); + + input_report_abs(input, ABS_TOOL_WIDTH, int2bound(&c->w, w)); + input_report_abs(input, ABS_X, int2bound(&c->x, x - c->x.devmin)); + input_report_abs(input, ABS_Y, int2bound(&c->y, c->y.devmax - y)); + } + + input_report_abs(input, ABS_PRESSURE, int2bound(&c->p, p)); + + input_report_key(input, BTN_TOOL_FINGER, n == 1); + input_report_key(input, BTN_TOOL_DOUBLETAP, n == 2); + input_report_key(input, BTN_TOOL_TRIPLETAP, n > 2); + + input_sync(input); + + return 0; +} + +/* Wellspring initialization constants */ +#define BCM5974_WELLSPRING_MODE_READ_REQUEST_ID 1 +#define BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID 9 +#define BCM5974_WELLSPRING_MODE_REQUEST_VALUE 0x300 +#define BCM5974_WELLSPRING_MODE_REQUEST_INDEX 0 +#define BCM5974_WELLSPRING_MODE_VENDOR_VALUE 0x01 + +static int bcm5974_wellspring_mode(struct bcm5974 *dev) +{ + char *data = kmalloc(8, GFP_KERNEL); + int retval = 0, size; + + if (!data) { + err("bcm5974: out of memory"); + retval = -ENOMEM; + goto out; + } + + /* read configuration */ + size = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), + BCM5974_WELLSPRING_MODE_READ_REQUEST_ID, + USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, + BCM5974_WELLSPRING_MODE_REQUEST_VALUE, + BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000); + + if (size != 8) { + err("bcm5974: could not read from device"); + retval = -EIO; + goto out; + } + + /* apply the mode switch */ + data[0] = BCM5974_WELLSPRING_MODE_VENDOR_VALUE; + + /* write configuration */ + size = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), + BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID, + USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, + BCM5974_WELLSPRING_MODE_REQUEST_VALUE, + BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000); + + if (size != 8) { + err("bcm5974: could not write to device"); + retval = -EIO; + goto out; + } + + dprintk(2, "bcm5974: switched to wellspring mode.\n"); + + out: + kfree(data); + return retval; +} + +static void bcm5974_irq_button(struct urb *urb) +{ + struct bcm5974 *dev = urb->context; + int error; + + switch (urb->status) { + case 0: + break; + case -EOVERFLOW: + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + dbg("bcm5974: button urb shutting down: %d", urb->status); + return; + default: + dbg("bcm5974: button urb status: %d", urb->status); + goto exit; + } + + if (report_bt_state(dev, dev->bt_urb->actual_length)) + dprintk(1, "bcm5974: bad button package, length: %d\n", + dev->bt_urb->actual_length); + +exit: + error = usb_submit_urb(dev->bt_urb, GFP_ATOMIC); + if (error) + err("bcm5974: button urb failed: %d", error); +} + +static void bcm5974_irq_trackpad(struct urb *urb) +{ + struct bcm5974 *dev = urb->context; + int error; + + switch (urb->status) { + case 0: + break; + case -EOVERFLOW: + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + dbg("bcm5974: trackpad urb shutting down: %d", urb->status); + return; + default: + dbg("bcm5974: trackpad urb status: %d", urb->status); + goto exit; + } + + /* control response ignored */ + if (dev->tp_urb->actual_length == 2) + goto exit; + + if (report_tp_state(dev, dev->tp_urb->actual_length)) + dprintk(1, "bcm5974: bad trackpad package, length: %d\n", + dev->tp_urb->actual_length); + +exit: + error = usb_submit_urb(dev->tp_urb, GFP_ATOMIC); + if (error) + err("bcm5974: trackpad urb failed: %d", error); +} + +/* + * The Wellspring trackpad, like many recent Apple trackpads, share + * the usb device with the keyboard. Since keyboards are usually + * handled by the HID system, the device ends up being handled by two + * modules. Setting up the device therefore becomes slightly + * complicated. To enable multitouch features, a mode switch is + * required, which is usually applied via the control interface of the + * device. It can be argued where this switch should take place. In + * some drivers, like appletouch, the switch is made during + * probe. However, the hid module may also alter the state of the + * device, resulting in trackpad malfunction under certain + * circumstances. To get around this problem, there is at least one + * example that utilizes the USB_QUIRK_RESET_RESUME quirk in order to + * recieve a reset_resume request rather than the normal resume. + * Since the implementation of reset_resume is equal to mode switch + * plus start_traffic, it seems easier to always do the switch when + * starting traffic on the device. + */ +static int bcm5974_start_traffic(struct bcm5974 *dev) +{ + if (bcm5974_wellspring_mode(dev)) { + dprintk(1, "bcm5974: mode switch failed\n"); + goto error; + } + + if (usb_submit_urb(dev->bt_urb, GFP_KERNEL)) + goto error; + + if (usb_submit_urb(dev->tp_urb, GFP_KERNEL)) + goto err_kill_bt; + + return 0; + +err_kill_bt: + usb_kill_urb(dev->bt_urb); +error: + return -EIO; +} + +static void bcm5974_pause_traffic(struct bcm5974 *dev) +{ + usb_kill_urb(dev->tp_urb); + usb_kill_urb(dev->bt_urb); +} + +/* + * The code below implements open/close and manual suspend/resume. + * All functions may be called in random order. + * + * Opening a suspended device fails with EACCES - permission denied. + * + * Failing a resume leaves the device resumed but closed. + */ +static int bcm5974_open(struct input_dev *input) +{ + struct bcm5974 *dev = input_get_drvdata(input); + int error; + + error = usb_autopm_get_interface(dev->intf); + if (error) + return error; + + mutex_lock(&dev->pm_mutex); + + error = bcm5974_start_traffic(dev); + if (!error) + dev->opened = 1; + + mutex_unlock(&dev->pm_mutex); + + if (error) + usb_autopm_put_interface(dev->intf); + + return error; +} + +static void bcm5974_close(struct input_dev *input) +{ + struct bcm5974 *dev = input_get_drvdata(input); + + mutex_lock(&dev->pm_mutex); + + bcm5974_pause_traffic(dev); + dev->opened = 0; + + mutex_unlock(&dev->pm_mutex); + + usb_autopm_put_interface(dev->intf); +} + +static int bcm5974_suspend(struct usb_interface *iface, pm_message_t message) +{ + struct bcm5974 *dev = usb_get_intfdata(iface); + + mutex_lock(&dev->pm_mutex); + + if (dev->opened) + bcm5974_pause_traffic(dev); + + mutex_unlock(&dev->pm_mutex); + + return 0; +} + +static int bcm5974_resume(struct usb_interface *iface) +{ + struct bcm5974 *dev = usb_get_intfdata(iface); + int error = 0; + + mutex_lock(&dev->pm_mutex); + + if (dev->opened) + error = bcm5974_start_traffic(dev); + + mutex_unlock(&dev->pm_mutex); + + return error; +} + +static int bcm5974_probe(struct usb_interface *iface, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(iface); + const struct bcm5974_config *cfg; + struct bcm5974 *dev; + struct input_dev *input_dev; + int error = -ENOMEM; + + /* find the product index */ + cfg = bcm5974_get_config(udev); + + /* allocate memory for our device state and initialize it */ + dev = kzalloc(sizeof(struct bcm5974), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!dev || !input_dev) { + err("bcm5974: out of memory"); + goto err_free_devs; + } + + dev->udev = udev; + dev->intf = iface; + dev->input = input_dev; + dev->cfg = *cfg; + mutex_init(&dev->pm_mutex); + + /* setup urbs */ + dev->bt_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!dev->bt_urb) + goto err_free_devs; + + dev->tp_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!dev->tp_urb) + goto err_free_bt_urb; + + dev->bt_data = usb_buffer_alloc(dev->udev, + dev->cfg.bt_datalen, GFP_KERNEL, + &dev->bt_urb->transfer_dma); + if (!dev->bt_data) + goto err_free_urb; + + dev->tp_data = usb_buffer_alloc(dev->udev, + dev->cfg.tp_datalen, GFP_KERNEL, + &dev->tp_urb->transfer_dma); + if (!dev->tp_data) + goto err_free_bt_buffer; + + usb_fill_int_urb(dev->bt_urb, udev, + usb_rcvintpipe(udev, cfg->bt_ep), + dev->bt_data, dev->cfg.bt_datalen, + bcm5974_irq_button, dev, 1); + + usb_fill_int_urb(dev->tp_urb, udev, + usb_rcvintpipe(udev, cfg->tp_ep), + dev->tp_data, dev->cfg.tp_datalen, + bcm5974_irq_trackpad, dev, 1); + + /* create bcm5974 device */ + usb_make_path(udev, dev->phys, sizeof(dev->phys)); + strlcat(dev->phys, "/input0", sizeof(dev->phys)); + + input_dev->name = "bcm5974"; + input_dev->phys = dev->phys; + usb_to_input_id(dev->udev, &input_dev->id); + input_dev->dev.parent = &iface->dev; + + input_set_drvdata(input_dev, dev); + + input_dev->open = bcm5974_open; + input_dev->close = bcm5974_close; + + setup_events_to_report(input_dev, cfg); + + error = input_register_device(dev->input); + if (error) + goto err_free_buffer; + + /* save our data pointer in this interface device */ + usb_set_intfdata(iface, dev); + + return 0; + +err_free_buffer: + usb_buffer_free(dev->udev, dev->cfg.tp_datalen, + dev->tp_data, dev->tp_urb->transfer_dma); +err_free_bt_buffer: + usb_buffer_free(dev->udev, dev->cfg.bt_datalen, + dev->bt_data, dev->bt_urb->transfer_dma); +err_free_urb: + usb_free_urb(dev->tp_urb); +err_free_bt_urb: + usb_free_urb(dev->bt_urb); +err_free_devs: + usb_set_intfdata(iface, NULL); + input_free_device(input_dev); + kfree(dev); + return error; +} + +static void bcm5974_disconnect(struct usb_interface *iface) +{ + struct bcm5974 *dev = usb_get_intfdata(iface); + + usb_set_intfdata(iface, NULL); + + input_unregister_device(dev->input); + usb_buffer_free(dev->udev, dev->cfg.tp_datalen, + dev->tp_data, dev->tp_urb->transfer_dma); + usb_buffer_free(dev->udev, dev->cfg.bt_datalen, + dev->bt_data, dev->bt_urb->transfer_dma); + usb_free_urb(dev->tp_urb); + usb_free_urb(dev->bt_urb); + kfree(dev); +} + +static struct usb_driver bcm5974_driver = { + .name = "bcm5974", + .probe = bcm5974_probe, + .disconnect = bcm5974_disconnect, + .suspend = bcm5974_suspend, + .resume = bcm5974_resume, + .reset_resume = bcm5974_resume, + .id_table = bcm5974_table, + .supports_autosuspend = 1, +}; + +static int __init bcm5974_init(void) +{ + return usb_register(&bcm5974_driver); +} + +static void __exit bcm5974_exit(void) +{ + usb_deregister(&bcm5974_driver); +} + +module_init(bcm5974_init); +module_exit(bcm5974_exit); + diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index fe732a574ec..3282b741e24 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -394,6 +394,13 @@ static struct dmi_system_id __initdata i8042_dmi_dritek_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"), }, }, + { + .ident = "Acer TravelMate 4280", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4280"), + }, + }, { } }; diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c index 0ed044d5e68..765007899d9 100644 --- a/drivers/input/serio/xilinx_ps2.c +++ b/drivers/input/serio/xilinx_ps2.c @@ -269,8 +269,8 @@ static int xps2_setup(struct device *dev, struct resource *regs_res, * we have the PS2 in a good state */ out_be32(drvdata->base_address + XPS2_SRST_OFFSET, XPS2_SRST_RESET); - dev_info(dev, "Xilinx PS2 at 0x%08X mapped to 0x%08X, irq=%d\n", - drvdata->phys_addr, (u32)drvdata->base_address, drvdata->irq); + dev_info(dev, "Xilinx PS2 at 0x%08X mapped to 0x%p, irq=%d\n", + drvdata->phys_addr, drvdata->base_address, drvdata->irq); serio = &drvdata->serio; serio->id.type = SERIO_8042; diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 6e60a97a234..25287e80e23 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -249,29 +249,26 @@ config TOUCHSCREEN_WM97XX config TOUCHSCREEN_WM9705 bool "WM9705 Touchscreen interface support" depends on TOUCHSCREEN_WM97XX + default y help - Say Y here if you have a Wolfson Microelectronics WM9705 - touchscreen controller connected to your system. - - If unsure, say N. + Say Y here to enable support for the Wolfson Microelectronics + WM9705 touchscreen controller. config TOUCHSCREEN_WM9712 bool "WM9712 Touchscreen interface support" depends on TOUCHSCREEN_WM97XX + default y help - Say Y here if you have a Wolfson Microelectronics WM9712 - touchscreen controller connected to your system. - - If unsure, say N. + Say Y here to enable support for the Wolfson Microelectronics + WM9712 touchscreen controller. config TOUCHSCREEN_WM9713 bool "WM9713 Touchscreen interface support" depends on TOUCHSCREEN_WM97XX + default y help - Say Y here if you have a Wolfson Microelectronics WM9713 touchscreen - controller connected to your system. - - If unsure, say N. + Say Y here to enable support for the Wolfson Microelectronics + WM9713 touchscreen controller. config TOUCHSCREEN_WM97XX_MAINSTONE tristate "WM97xx Mainstone accelerated touch" diff --git a/drivers/md/md.c b/drivers/md/md.c index c7aae66c6f9..8cfadc5bd2b 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2393,6 +2393,8 @@ static void analyze_sbs(mddev_t * mddev) } +static void md_safemode_timeout(unsigned long data); + static ssize_t safe_delay_show(mddev_t *mddev, char *page) { @@ -2432,9 +2434,12 @@ safe_delay_store(mddev_t *mddev, const char *cbuf, size_t len) if (msec == 0) mddev->safemode_delay = 0; else { + unsigned long old_delay = mddev->safemode_delay; mddev->safemode_delay = (msec*HZ)/1000; if (mddev->safemode_delay == 0) mddev->safemode_delay = 1; + if (mddev->safemode_delay < old_delay) + md_safemode_timeout((unsigned long)mddev); } return len; } @@ -4634,6 +4639,11 @@ static int update_size(mddev_t *mddev, sector_t num_sectors) */ if (mddev->sync_thread) return -EBUSY; + if (mddev->bitmap) + /* Sorry, cannot grow a bitmap yet, just remove it, + * grow, and re-add. + */ + return -EBUSY; rdev_for_each(rdev, tmp, mddev) { sector_t avail; avail = rdev->size * 2; @@ -5993,7 +6003,7 @@ static int remove_and_add_spares(mddev_t *mddev) } } - if (mddev->degraded) { + if (mddev->degraded && ! mddev->ro) { rdev_for_each(rdev, rtmp, mddev) { if (rdev->raid_disk >= 0 && !test_bit(In_sync, &rdev->flags) && @@ -6067,6 +6077,8 @@ void md_check_recovery(mddev_t *mddev) flush_signals(current); } + if (mddev->ro && !test_bit(MD_RECOVERY_NEEDED, &mddev->recovery)) + return; if ( ! ( (mddev->flags && !mddev->external) || test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) || @@ -6080,6 +6092,15 @@ void md_check_recovery(mddev_t *mddev) if (mddev_trylock(mddev)) { int spares = 0; + if (mddev->ro) { + /* Only thing we do on a ro array is remove + * failed devices. + */ + remove_and_add_spares(mddev); + clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery); + goto unlock; + } + if (!mddev->external) { int did_change = 0; spin_lock_irq(&mddev->write_lock); @@ -6117,7 +6138,8 @@ void md_check_recovery(mddev_t *mddev) /* resync has finished, collect result */ md_unregister_thread(mddev->sync_thread); mddev->sync_thread = NULL; - if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { + if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery) && + !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) { /* success...*/ /* activate any spares */ if (mddev->pers->spare_active(mddev)) @@ -6169,6 +6191,7 @@ void md_check_recovery(mddev_t *mddev) } else if ((spares = remove_and_add_spares(mddev))) { clear_bit(MD_RECOVERY_SYNC, &mddev->recovery); clear_bit(MD_RECOVERY_CHECK, &mddev->recovery); + clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery); set_bit(MD_RECOVERY_RECOVER, &mddev->recovery); } else if (mddev->recovery_cp < MaxSector) { set_bit(MD_RECOVERY_SYNC, &mddev->recovery); @@ -6232,7 +6255,11 @@ static int md_notify_reboot(struct notifier_block *this, for_each_mddev(mddev, tmp) if (mddev_trylock(mddev)) { - do_md_stop (mddev, 1, 0); + /* Force a switch to readonly even array + * appears to still be in use. Hence + * the '100'. + */ + do_md_stop (mddev, 1, 100); mddev_unlock(mddev); } /* diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index d41bebb6da0..e34cd0e6247 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -76,11 +76,13 @@ static void r10bio_pool_free(void *r10_bio, void *data) kfree(r10_bio); } +/* Maximum size of each resync request */ #define RESYNC_BLOCK_SIZE (64*1024) -//#define RESYNC_BLOCK_SIZE PAGE_SIZE -#define RESYNC_SECTORS (RESYNC_BLOCK_SIZE >> 9) #define RESYNC_PAGES ((RESYNC_BLOCK_SIZE + PAGE_SIZE-1) / PAGE_SIZE) -#define RESYNC_WINDOW (2048*1024) +/* amount of memory to reserve for resync requests */ +#define RESYNC_WINDOW (1024*1024) +/* maximum number of concurrent requests, memory permitting */ +#define RESYNC_DEPTH (32*1024*1024/RESYNC_BLOCK_SIZE) /* * When performing a resync, we need to read and compare, so @@ -690,7 +692,6 @@ static int flush_pending_writes(conf_t *conf) * there is no normal IO happeing. It must arrange to call * lower_barrier when the particular background IO completes. */ -#define RESYNC_DEPTH 32 static void raise_barrier(conf_t *conf, int force) { diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 40e93967565..224de022e7c 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -2568,10 +2568,10 @@ static bool 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))) { + if (blocked_rdev == NULL && + 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 */ @@ -2588,8 +2588,14 @@ static bool handle_stripe5(struct stripe_head *sh) rcu_read_unlock(); if (unlikely(blocked_rdev)) { - set_bit(STRIPE_HANDLE, &sh->state); - goto unlock; + if (s.syncing || s.expanding || s.expanded || + s.to_write || s.written) { + set_bit(STRIPE_HANDLE, &sh->state); + goto unlock; + } + /* There is nothing for the blocked_rdev to block */ + rdev_dec_pending(blocked_rdev, conf->mddev); + blocked_rdev = NULL; } if (s.to_fill && !test_bit(STRIPE_BIOFILL_RUN, &sh->state)) { @@ -2832,10 +2838,10 @@ static bool 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))) { + if (blocked_rdev == NULL && + 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 */ @@ -2853,9 +2859,16 @@ static bool handle_stripe6(struct stripe_head *sh, struct page *tmp_page) rcu_read_unlock(); if (unlikely(blocked_rdev)) { - set_bit(STRIPE_HANDLE, &sh->state); - goto unlock; + if (s.syncing || s.expanding || s.expanded || + s.to_write || s.written) { + set_bit(STRIPE_HANDLE, &sh->state); + goto unlock; + } + /* There is nothing for the blocked_rdev to block */ + rdev_dec_pending(blocked_rdev, conf->mddev); + blocked_rdev = NULL; } + 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, @@ -4446,6 +4459,9 @@ static int raid5_check_reshape(mddev_t *mddev) return -EINVAL; /* Cannot shrink array or change level yet */ if (mddev->delta_disks == 0) return 0; /* nothing to do */ + if (mddev->bitmap) + /* Cannot grow a bitmap yet */ + return -EBUSY; /* Can only proceed if there are plenty of stripe_heads. * We need a minimum of one full stripe,, and for sensible progress diff --git a/drivers/misc/acer-wmi.c b/drivers/misc/acer-wmi.c index e7a3fe508df..b2d9878dc3f 100644 --- a/drivers/misc/acer-wmi.c +++ b/drivers/misc/acer-wmi.c @@ -803,11 +803,30 @@ static acpi_status get_u32(u32 *value, u32 cap) static acpi_status set_u32(u32 value, u32 cap) { + acpi_status status; + if (interface->capability & cap) { switch (interface->type) { case ACER_AMW0: return AMW0_set_u32(value, cap, interface); case ACER_AMW0_V2: + if (cap == ACER_CAP_MAILLED) + return AMW0_set_u32(value, cap, interface); + + /* + * On some models, some WMID methods don't toggle + * properly. For those cases, we want to run the AMW0 + * method afterwards to be certain we've really toggled + * the device state. + */ + if (cap == ACER_CAP_WIRELESS || + cap == ACER_CAP_BLUETOOTH) { + status = WMID_set_u32(value, cap, interface); + if (ACPI_FAILURE(status)) + return status; + + return AMW0_set_u32(value, cap, interface); + } case ACER_WMID: return WMID_set_u32(value, cap, interface); default: diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index 64002488c6e..917cf8d3ae9 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -19,7 +19,7 @@ #include <asm/io.h> #include <asm/sizes.h> #include <mach/hardware.h> -#include <asm/plat-orion/orion_nand.h> +#include <plat/orion_nand.h> #ifdef CONFIG_MTD_CMDLINE_PARTS static const char *part_probes[] = { "cmdlinepart", NULL }; diff --git a/drivers/pcmcia/pxa2xx_palmtx.c b/drivers/pcmcia/pxa2xx_palmtx.c index a8771ffc61e..e07b5c51ec5 100644 --- a/drivers/pcmcia/pxa2xx_palmtx.c +++ b/drivers/pcmcia/pxa2xx_palmtx.c @@ -23,12 +23,57 @@ static int palmtx_pcmcia_hw_init(struct soc_pcmcia_socket *skt) { - skt->irq = IRQ_GPIO(GPIO_NR_PALMTX_PCMCIA_READY); + int ret; + + ret = gpio_request(GPIO_NR_PALMTX_PCMCIA_POWER1, "PCMCIA PWR1"); + if (ret) + goto err1; + ret = gpio_direction_output(GPIO_NR_PALMTX_PCMCIA_POWER1, 0); + if (ret) + goto err2; + + ret = gpio_request(GPIO_NR_PALMTX_PCMCIA_POWER2, "PCMCIA PWR2"); + if (ret) + goto err2; + ret = gpio_direction_output(GPIO_NR_PALMTX_PCMCIA_POWER2, 0); + if (ret) + goto err3; + + ret = gpio_request(GPIO_NR_PALMTX_PCMCIA_RESET, "PCMCIA RST"); + if (ret) + goto err3; + ret = gpio_direction_output(GPIO_NR_PALMTX_PCMCIA_RESET, 1); + if (ret) + goto err4; + + ret = gpio_request(GPIO_NR_PALMTX_PCMCIA_READY, "PCMCIA RDY"); + if (ret) + goto err4; + ret = gpio_direction_input(GPIO_NR_PALMTX_PCMCIA_READY); + if (ret) + goto err5; + + skt->irq = gpio_to_irq(GPIO_NR_PALMTX_PCMCIA_READY); return 0; + +err5: + gpio_free(GPIO_NR_PALMTX_PCMCIA_READY); +err4: + gpio_free(GPIO_NR_PALMTX_PCMCIA_RESET); +err3: + gpio_free(GPIO_NR_PALMTX_PCMCIA_POWER2); +err2: + gpio_free(GPIO_NR_PALMTX_PCMCIA_POWER1); +err1: + return ret; } static void palmtx_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) { + gpio_free(GPIO_NR_PALMTX_PCMCIA_READY); + gpio_free(GPIO_NR_PALMTX_PCMCIA_RESET); + gpio_free(GPIO_NR_PALMTX_PCMCIA_POWER2); + gpio_free(GPIO_NR_PALMTX_PCMCIA_POWER1); } static void palmtx_pcmcia_socket_state(struct soc_pcmcia_socket *skt, @@ -109,7 +154,7 @@ static void __exit palmtx_pcmcia_exit(void) platform_device_unregister(palmtx_pcmcia_device); } -fs_initcall(palmtx_pcmcia_init); +module_init(palmtx_pcmcia_init); module_exit(palmtx_pcmcia_exit); MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index d7e9f2152df..95015cbfd33 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -405,8 +405,6 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: extended_irq = &res->data.extended_irq; - if (extended_irq->producer_consumer == ACPI_PRODUCER) - return AE_OK; if (extended_irq->interrupt_count == 0) pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED); diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 3b4a14e355c..77cb34270fc 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -449,6 +449,7 @@ config SERIAL_CLPS711X_CONSOLE config SERIAL_SAMSUNG tristate "Samsung SoC serial support" depends on ARM && PLAT_S3C24XX + select SERIAL_CORE help Support for the on-chip UARTs on the Samsung S3C24XX series CPUs, providing /dev/ttySAC0, 1 and 2 (note, some machines may not diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 964124b60db..75e86865234 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -226,10 +226,11 @@ EXPORT_SYMBOL_GPL(spi_alloc_device); * Companion function to spi_alloc_device. Devices allocated with * spi_alloc_device can be added onto the spi bus with this function. * - * Returns 0 on success; non-zero on failure + * Returns 0 on success; negative errno on failure */ int spi_add_device(struct spi_device *spi) { + static DEFINE_MUTEX(spi_add_lock); struct device *dev = spi->master->dev.parent; int status; @@ -246,26 +247,43 @@ int spi_add_device(struct spi_device *spi) "%s.%u", spi->master->dev.bus_id, spi->chip_select); - /* drivers may modify this initial i/o setup */ + + /* We need to make sure there's no other device with this + * chipselect **BEFORE** we call setup(), else we'll trash + * its configuration. Lock against concurrent add() calls. + */ + mutex_lock(&spi_add_lock); + + if (bus_find_device_by_name(&spi_bus_type, NULL, spi->dev.bus_id) + != NULL) { + dev_err(dev, "chipselect %d already in use\n", + spi->chip_select); + status = -EBUSY; + goto done; + } + + /* Drivers may modify this initial i/o setup, but will + * normally rely on the device being setup. Devices + * using SPI_CS_HIGH can't coexist well otherwise... + */ status = spi->master->setup(spi); if (status < 0) { dev_err(dev, "can't %s %s, status %d\n", "setup", spi->dev.bus_id, status); - return status; + goto done; } - /* driver core catches callers that misbehave by defining - * devices that already exist. - */ + /* Device may be bound to an active driver when this returns */ status = device_add(&spi->dev); - if (status < 0) { + if (status < 0) dev_err(dev, "can't %s %s, status %d\n", "add", spi->dev.bus_id, status); - return status; - } + else + dev_dbg(dev, "registered child %s\n", spi->dev.bus_id); - dev_dbg(dev, "registered child %s\n", spi->dev.bus_id); - return 0; +done: + mutex_unlock(&spi_add_lock); + return status; } EXPORT_SYMBOL_GPL(spi_add_device); diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index 5fbdc14e63b..5416cf96900 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -12,7 +12,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/mbus.h> -#include <asm/plat-orion/ehci-orion.h> +#include <plat/ehci-orion.h> #define rdl(off) __raw_readl(hcd->regs + (off)) #define wrl(off, val) __raw_writel((val), hcd->regs + (off)) diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index bd320a2bfb7..fb51197d1c9 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c @@ -479,6 +479,10 @@ static void adjust_aoi_size_position(struct fb_var_screeninfo *var, base_plane_width = machine_data->fsl_diu_info[0]->var.xres; base_plane_height = machine_data->fsl_diu_info[0]->var.yres; + if (mfbi->x_aoi_d < 0) + mfbi->x_aoi_d = 0; + if (mfbi->y_aoi_d < 0) + mfbi->y_aoi_d = 0; switch (index) { case 0: if (mfbi->x_aoi_d != 0) @@ -778,6 +782,22 @@ static void unmap_video_memory(struct fb_info *info) } /* + * Using the fb_var_screeninfo in fb_info we set the aoi of this + * particular framebuffer. It is a light version of fsl_diu_set_par. + */ +static int fsl_diu_set_aoi(struct fb_info *info) +{ + struct fb_var_screeninfo *var = &info->var; + struct mfb_info *mfbi = info->par; + struct diu_ad *ad = mfbi->ad; + + /* AOI should not be greater than display size */ + ad->offset_xyi = cpu_to_le32((var->yoffset << 16) | var->xoffset); + ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d); + return 0; +} + +/* * Using the fb_var_screeninfo in fb_info we set the resolution of this * particular framebuffer. This function alters the fb_fix_screeninfo stored * in fb_info. It does not alter var in fb_info since we are using that @@ -817,11 +837,11 @@ static int fsl_diu_set_par(struct fb_info *info) diu_ops.get_pixel_format(var->bits_per_pixel, machine_data->monitor_port); ad->addr = cpu_to_le32(info->fix.smem_start); - ad->src_size_g_alpha = cpu_to_le32((var->yres << 12) | - var->xres) | mfbi->g_alpha; - /* fix me. AOI should not be greater than display size */ + ad->src_size_g_alpha = cpu_to_le32((var->yres_virtual << 12) | + var->xres_virtual) | mfbi->g_alpha; + /* AOI should not be greater than display size */ ad->aoi_size = cpu_to_le32((var->yres << 16) | var->xres); - ad->offset_xyi = 0; + ad->offset_xyi = cpu_to_le32((var->yoffset << 16) | var->xoffset); ad->offset_xyd = cpu_to_le32((mfbi->y_aoi_d << 16) | mfbi->x_aoi_d); /* Disable chroma keying function */ @@ -921,6 +941,8 @@ static int fsl_diu_pan_display(struct fb_var_screeninfo *var, else info->var.vmode &= ~FB_VMODE_YWRAP; + fsl_diu_set_aoi(info); + return 0; } @@ -989,7 +1011,7 @@ static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd, pr_debug("set AOI display offset of index %d to (%d,%d)\n", mfbi->index, aoi_d.x_aoi_d, aoi_d.y_aoi_d); fsl_diu_check_var(&info->var, info); - fsl_diu_set_par(info); + fsl_diu_set_aoi(info); break; case MFB_GET_AOID: aoi_d.x_aoi_d = mfbi->x_aoi_d; diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index e7aa7ae8fca..97204497d9f 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c @@ -1031,7 +1031,9 @@ static void pxafb_setup_gpio(struct pxafb_info *fbi) pxa_gpio_mode(GPIO74_LCD_FCLK_MD); pxa_gpio_mode(GPIO75_LCD_LCLK_MD); pxa_gpio_mode(GPIO76_LCD_PCLK_MD); - pxa_gpio_mode(GPIO77_LCD_ACBIAS_MD); + + if ((lccr0 & LCCR0_PAS) == 0) + pxa_gpio_mode(GPIO77_LCD_ACBIAS_MD); } static void pxafb_enable_controller(struct pxafb_info *fbi) @@ -1400,6 +1402,8 @@ static void pxafb_decode_mach_info(struct pxafb_info *fbi, if (lcd_conn == LCD_MONO_STN_8BPP) fbi->lccr0 |= LCCR0_DPD; + fbi->lccr0 |= (lcd_conn & LCD_ALTERNATE_MAPPING) ? LCCR0_LDDALT : 0; + 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; @@ -1673,53 +1677,63 @@ MODULE_PARM_DESC(options, "LCD parameters (see Documentation/fb/pxafb.txt)"); #define pxafb_setup_options() (0) #endif -static int __devinit pxafb_probe(struct platform_device *dev) -{ - struct pxafb_info *fbi; - struct pxafb_mach_info *inf; - struct resource *r; - int irq, ret; - - dev_dbg(&dev->dev, "pxafb_probe\n"); - - inf = dev->dev.platform_data; - ret = -ENOMEM; - fbi = NULL; - if (!inf) - goto failed; - - ret = pxafb_parse_options(&dev->dev, g_options); - if (ret < 0) - goto failed; - #ifdef DEBUG_VAR - /* Check for various illegal bit-combinations. Currently only - * a warning is given. */ +/* Check for various illegal bit-combinations. Currently only + * a warning is given. */ +static void __devinit pxafb_check_options(struct device *dev, + struct pxafb_mach_info *inf) +{ + if (inf->lcd_conn) + return; if (inf->lccr0 & LCCR0_INVALID_CONFIG_MASK) - dev_warn(&dev->dev, "machine LCCR0 setting contains " + dev_warn(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 " + dev_warn(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 " + dev_warn(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"); + dev_warn(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 " + dev_warn(dev, "Upper and lower margins must be 0 in " "passive mode\n"); +} +#else +#define pxafb_check_options(...) do {} while (0) #endif +static int __devinit pxafb_probe(struct platform_device *dev) +{ + struct pxafb_info *fbi; + struct pxafb_mach_info *inf; + struct resource *r; + int irq, ret; + + dev_dbg(&dev->dev, "pxafb_probe\n"); + + inf = dev->dev.platform_data; + ret = -ENOMEM; + fbi = NULL; + if (!inf) + goto failed; + + ret = pxafb_parse_options(&dev->dev, g_options); + if (ret < 0) + goto failed; + + pxafb_check_options(&dev->dev, inf); + dev_dbg(&dev->dev, "got a %dx%dx%d LCD\n", inf->modes->xres, inf->modes->yres, diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 3da2b90d2fe..22715e3be5e 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c @@ -157,8 +157,6 @@ static void s3c2410wdt_start(void) writel(wdt_count, wdt_base + S3C2410_WTCNT); writel(wtcon, wdt_base + S3C2410_WTCON); spin_unlock(&wdt_lock); - - return 0; } static int s3c2410wdt_set_heartbeat(int timeout) |