diff options
Diffstat (limited to 'drivers')
92 files changed, 1883 insertions, 1671 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 20eacc2c9e0..e942ffe8b57 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -13,6 +13,7 @@ config ACPI depends on IA64 || X86 depends on PCI depends on PM + select PNP default y ---help--- Advanced Configuration and Power Interface (ACPI) support for @@ -132,15 +133,6 @@ config ACPI_VIDEO Note that this is an ref. implementation only. It may or may not work for your integrated video device. -config ACPI_HOTKEY - tristate "Generic Hotkey (EXPERIMENTAL)" - depends on EXPERIMENTAL - depends on X86 - default n - help - Experimental consolidated hotkey driver. - If you are unsure, say N. - config ACPI_FAN tristate "Fan" default y diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 856c32bccac..5956e9f64a8 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -46,7 +46,6 @@ obj-$(CONFIG_ACPI_FAN) += fan.o obj-$(CONFIG_ACPI_DOCK) += dock.o obj-$(CONFIG_ACPI_BAY) += bay.o obj-$(CONFIG_ACPI_VIDEO) += video.o -obj-$(CONFIG_ACPI_HOTKEY) += hotkey.o obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o obj-$(CONFIG_ACPI_POWER) += power.o obj-$(CONFIG_ACPI_PROCESSOR) += processor.o diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 6daeace796a..37c7dc4f9fe 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -35,7 +35,6 @@ #define ACPI_AC_COMPONENT 0x00020000 #define ACPI_AC_CLASS "ac_adapter" #define ACPI_AC_HID "ACPI0003" -#define ACPI_AC_DRIVER_NAME "ACPI AC Adapter Driver" #define ACPI_AC_DEVICE_NAME "AC Adapter" #define ACPI_AC_FILE_STATE "state" #define ACPI_AC_NOTIFY_STATUS 0x80 @@ -44,10 +43,10 @@ #define ACPI_AC_STATUS_UNKNOWN 0xFF #define _COMPONENT ACPI_AC_COMPONENT -ACPI_MODULE_NAME("acpi_ac") +ACPI_MODULE_NAME("ac"); - MODULE_AUTHOR("Paul Diefenbaugh"); -MODULE_DESCRIPTION(ACPI_AC_DRIVER_NAME); +MODULE_AUTHOR("Paul Diefenbaugh"); +MODULE_DESCRIPTION("ACPI AC Adapter Driver"); MODULE_LICENSE("GPL"); extern struct proc_dir_entry *acpi_lock_ac_dir(void); @@ -58,7 +57,7 @@ static int acpi_ac_remove(struct acpi_device *device, int type); static int acpi_ac_open_fs(struct inode *inode, struct file *file); static struct acpi_driver acpi_ac_driver = { - .name = ACPI_AC_DRIVER_NAME, + .name = "ac", .class = ACPI_AC_CLASS, .ids = ACPI_AC_HID, .ops = { diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index cd946ed192d..c26172671fd 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -35,14 +35,13 @@ #define ACPI_MEMORY_DEVICE_COMPONENT 0x08000000UL #define ACPI_MEMORY_DEVICE_CLASS "memory" #define ACPI_MEMORY_DEVICE_HID "PNP0C80" -#define ACPI_MEMORY_DEVICE_DRIVER_NAME "Hotplug Mem Driver" #define ACPI_MEMORY_DEVICE_NAME "Hotplug Mem Device" #define _COMPONENT ACPI_MEMORY_DEVICE_COMPONENT -ACPI_MODULE_NAME("acpi_memory") - MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>"); -MODULE_DESCRIPTION(ACPI_MEMORY_DEVICE_DRIVER_NAME); +ACPI_MODULE_NAME("acpi_memhotplug"); +MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>"); +MODULE_DESCRIPTION("Hotplug Mem Driver"); MODULE_LICENSE("GPL"); /* ACPI _STA method values */ @@ -60,7 +59,7 @@ static int acpi_memory_device_remove(struct acpi_device *device, int type); static int acpi_memory_device_start(struct acpi_device *device); static struct acpi_driver acpi_memory_device_driver = { - .name = ACPI_MEMORY_DEVICE_DRIVER_NAME, + .name = "acpi_memhotplug", .class = ACPI_MEMORY_DEVICE_CLASS, .ids = ACPI_MEMORY_DEVICE_HID, .ops = { diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c index 31ad70a6e22..772299fb5f9 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/acpi/asus_acpi.c @@ -141,6 +141,7 @@ struct asus_hotk { W5A, //W5A W3V, //W3030V xxN, //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N + A4S, //Z81sp //(Centrino) END_MODEL } model; //Models currently supported @@ -397,7 +398,16 @@ static struct model_data model_conf[END_MODEL] = { .brightness_set = "SPLV", .brightness_get = "GPLV", .display_set = "SDSP", - .display_get = "\\ADVG"} + .display_get = "\\ADVG"}, + + { + .name = "A4S", + .brightness_set = "SPLV", + .brightness_get = "GPLV", + .mt_bt_switch = "BLED", + .mt_wled = "WLED" + } + }; /* procdir we use */ @@ -421,7 +431,7 @@ static struct asus_hotk *hotk; static int asus_hotk_add(struct acpi_device *device); static int asus_hotk_remove(struct acpi_device *device, int type); static struct acpi_driver asus_hotk_driver = { - .name = ACPI_HOTK_NAME, + .name = "asus_acpi", .class = ACPI_HOTK_CLASS, .ids = ACPI_HOTK_HID, .ops = { @@ -1117,6 +1127,8 @@ static int asus_model_match(char *model) return W3V; else if (strncmp(model, "W5A", 3) == 0) return W5A; + else if (strncmp(model, "A4S", 3) == 0) + return A4S; else return END_MODEL; } @@ -1365,10 +1377,6 @@ static int __init asus_acpi_init(void) if (acpi_disabled) return -ENODEV; - if (!acpi_specific_hotkey_enabled) { - printk(KERN_ERR "Using generic hotkey driver\n"); - return -ENODEV; - } asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir); if (!asus_proc_dir) { printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n"); diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 2f4521a48fe..02de49ef1bc 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -42,7 +42,6 @@ #define ACPI_BATTERY_COMPONENT 0x00040000 #define ACPI_BATTERY_CLASS "battery" #define ACPI_BATTERY_HID "PNP0C0A" -#define ACPI_BATTERY_DRIVER_NAME "ACPI Battery Driver" #define ACPI_BATTERY_DEVICE_NAME "Battery" #define ACPI_BATTERY_FILE_INFO "info" #define ACPI_BATTERY_FILE_STATUS "state" @@ -53,10 +52,10 @@ #define ACPI_BATTERY_UNITS_AMPS "mA" #define _COMPONENT ACPI_BATTERY_COMPONENT -ACPI_MODULE_NAME("acpi_battery") +ACPI_MODULE_NAME("battery"); - MODULE_AUTHOR("Paul Diefenbaugh"); -MODULE_DESCRIPTION(ACPI_BATTERY_DRIVER_NAME); +MODULE_AUTHOR("Paul Diefenbaugh"); +MODULE_DESCRIPTION("ACPI Battery Driver"); MODULE_LICENSE("GPL"); extern struct proc_dir_entry *acpi_lock_battery_dir(void); @@ -67,7 +66,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type); static int acpi_battery_resume(struct acpi_device *device); static struct acpi_driver acpi_battery_driver = { - .name = ACPI_BATTERY_DRIVER_NAME, + .name = "battery", .class = ACPI_BATTERY_CLASS, .ids = ACPI_BATTERY_HID, .ops = { diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c index 91082ce6f5d..fb3f31b5e69 100644 --- a/drivers/acpi/bay.c +++ b/drivers/acpi/bay.c @@ -32,11 +32,9 @@ #include <asm/uaccess.h> #include <linux/platform_device.h> -#define ACPI_BAY_DRIVER_NAME "ACPI Removable Drive Bay Driver" - -ACPI_MODULE_NAME("bay") +ACPI_MODULE_NAME("bay"); MODULE_AUTHOR("Kristen Carlson Accardi"); -MODULE_DESCRIPTION(ACPI_BAY_DRIVER_NAME); +MODULE_DESCRIPTION("ACPI Removable Drive Bay Driver"); MODULE_LICENSE("GPL"); #define ACPI_BAY_CLASS "bay" #define ACPI_BAY_COMPONENT 0x10000000 @@ -47,18 +45,6 @@ MODULE_LICENSE("GPL"); acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\ printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); } static void bay_notify(acpi_handle handle, u32 event, void *data); -static int acpi_bay_add(struct acpi_device *device); -static int acpi_bay_remove(struct acpi_device *device, int type); - -static struct acpi_driver acpi_bay_driver = { - .name = ACPI_BAY_DRIVER_NAME, - .class = ACPI_BAY_CLASS, - .ids = ACPI_BAY_HID, - .ops = { - .add = acpi_bay_add, - .remove = acpi_bay_remove, - }, -}; struct bay { acpi_handle handle; @@ -234,14 +220,6 @@ int eject_removable_drive(struct device *dev) } EXPORT_SYMBOL_GPL(eject_removable_drive); -static int acpi_bay_add(struct acpi_device *device) -{ - bay_dprintk(device->handle, "adding bay device"); - strcpy(acpi_device_name(device), "Dockable Bay"); - strcpy(acpi_device_class(device), "bay"); - return 0; -} - static int acpi_bay_add_fs(struct bay *bay) { int ret; @@ -303,7 +281,7 @@ static int bay_add(acpi_handle handle, int id) /* initialize platform device stuff */ pdev = platform_device_register_simple(ACPI_BAY_CLASS, id, NULL, 0); - if (pdev == NULL) { + if (IS_ERR(pdev)) { printk(KERN_ERR PREFIX "Error registering bay device\n"); goto bay_add_err; } @@ -339,52 +317,6 @@ bay_add_err: return -ENODEV; } -static int acpi_bay_remove(struct acpi_device *device, int type) -{ - /*** FIXME: do something here */ - return 0; -} - -/** - * bay_create_acpi_device - add new devices to acpi - * @handle - handle of the device to add - * - * This function will create a new acpi_device for the given - * handle if one does not exist already. This should cause - * acpi to scan for drivers for the given devices, and call - * matching driver's add routine. - * - * Returns a pointer to the acpi_device corresponding to the handle. - */ -static struct acpi_device * bay_create_acpi_device(acpi_handle handle) -{ - struct acpi_device *device = NULL; - struct acpi_device *parent_device; - acpi_handle parent; - int ret; - - bay_dprintk(handle, "Trying to get device"); - if (acpi_bus_get_device(handle, &device)) { - /* - * no device created for this object, - * so we should create one. - */ - bay_dprintk(handle, "No device for handle"); - acpi_get_parent(handle, &parent); - if (acpi_bus_get_device(parent, &parent_device)) - parent_device = NULL; - - ret = acpi_bus_add(&device, parent_device, handle, - ACPI_BUS_TYPE_DEVICE); - if (ret) { - pr_debug("error adding bus, %x\n", - -ret); - return NULL; - } - } - return device; -} - /** * bay_notify - act upon an acpi bay notification * @handle: the bay handle @@ -394,38 +326,19 @@ static struct acpi_device * bay_create_acpi_device(acpi_handle handle) */ static void bay_notify(acpi_handle handle, u32 event, void *data) { - struct acpi_device *dev; + struct bay *bay_dev = (struct bay *)data; + struct device *dev = &bay_dev->pdev->dev; bay_dprintk(handle, "Bay event"); switch(event) { case ACPI_NOTIFY_BUS_CHECK: - printk("Bus Check\n"); case ACPI_NOTIFY_DEVICE_CHECK: - printk("Device Check\n"); - dev = bay_create_acpi_device(handle); - if (dev) - acpi_bus_generate_event(dev, event, 0); - else - printk("No device for generating event\n"); - /* wouldn't it be a good idea to just rescan SATA - * right here? - */ - break; case ACPI_NOTIFY_EJECT_REQUEST: - printk("Eject request\n"); - dev = bay_create_acpi_device(handle); - if (dev) - acpi_bus_generate_event(dev, event, 0); - else - printk("No device for generating eventn"); - - /* wouldn't it be a good idea to just call the - * eject_device here if we were a SATA device? - */ + kobject_uevent(&dev->kobj, KOBJ_CHANGE); break; default: - printk("unknown event %d\n", event); + printk(KERN_ERR PREFIX "Bay: unknown event %d\n", event); } } @@ -457,10 +370,6 @@ static int __init bay_init(void) acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX, find_bay, &bays, NULL); - if (bays) - if ((acpi_bus_register_driver(&acpi_bay_driver) < 0)) - printk(KERN_ERR "Unable to register bay driver\n"); - if (!bays) return -ENODEV; @@ -481,8 +390,6 @@ static void __exit bay_exit(void) kfree(bay->name); kfree(bay); } - - acpi_bus_unregister_driver(&acpi_bay_driver); } postcore_initcall(bay_init); diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index c26468da429..fd37e19360d 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -39,7 +39,7 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_BUS_COMPONENT -ACPI_MODULE_NAME("acpi_bus") +ACPI_MODULE_NAME("bus"); #ifdef CONFIG_X86 extern void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger); #endif diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index c726612fafb..cb4110b50cd 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -34,7 +34,6 @@ #include <acpi/acpi_drivers.h> #define ACPI_BUTTON_COMPONENT 0x00080000 -#define ACPI_BUTTON_DRIVER_NAME "ACPI Button Driver" #define ACPI_BUTTON_CLASS "button" #define ACPI_BUTTON_FILE_INFO "info" #define ACPI_BUTTON_FILE_STATE "state" @@ -61,10 +60,10 @@ #define ACPI_BUTTON_TYPE_LID 0x05 #define _COMPONENT ACPI_BUTTON_COMPONENT -ACPI_MODULE_NAME("acpi_button") +ACPI_MODULE_NAME("button"); MODULE_AUTHOR("Paul Diefenbaugh"); -MODULE_DESCRIPTION(ACPI_BUTTON_DRIVER_NAME); +MODULE_DESCRIPTION("ACPI Button Driver"); MODULE_LICENSE("GPL"); static int acpi_button_add(struct acpi_device *device); @@ -73,7 +72,7 @@ static int acpi_button_info_open_fs(struct inode *inode, struct file *file); static int acpi_button_state_open_fs(struct inode *inode, struct file *file); static struct acpi_driver acpi_button_driver = { - .name = ACPI_BUTTON_DRIVER_NAME, + .name = "button", .class = ACPI_BUTTON_CLASS, .ids = "button_power,button_sleep,PNP0C0D,PNP0C0C,PNP0C0E", .ops = { diff --git a/drivers/acpi/cm_sbs.c b/drivers/acpi/cm_sbs.c index 4a9b7bf6f44..f9db4f444bd 100644 --- a/drivers/acpi/cm_sbs.c +++ b/drivers/acpi/cm_sbs.c @@ -31,7 +31,7 @@ #include <acpi/actypes.h> #include <acpi/acutils.h> -ACPI_MODULE_NAME("cm_sbs") +ACPI_MODULE_NAME("cm_sbs"); #define ACPI_AC_CLASS "ac_adapter" #define ACPI_BATTERY_CLASS "battery" #define ACPI_SBS_COMPONENT 0x00080000 diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 69a68fd394c..0930d9413df 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -35,7 +35,6 @@ #include <acpi/acpi_drivers.h> #include <acpi/container.h> -#define ACPI_CONTAINER_DRIVER_NAME "ACPI container driver" #define ACPI_CONTAINER_DEVICE_NAME "ACPI container device" #define ACPI_CONTAINER_CLASS "container" @@ -44,10 +43,10 @@ #define ACPI_CONTAINER_COMPONENT 0x01000000 #define _COMPONENT ACPI_CONTAINER_COMPONENT -ACPI_MODULE_NAME("acpi_container") +ACPI_MODULE_NAME("container"); - MODULE_AUTHOR("Anil S Keshavamurthy"); -MODULE_DESCRIPTION(ACPI_CONTAINER_DRIVER_NAME); +MODULE_AUTHOR("Anil S Keshavamurthy"); +MODULE_DESCRIPTION("ACPI container driver"); MODULE_LICENSE("GPL"); #define ACPI_STA_PRESENT (0x00000001) @@ -56,7 +55,7 @@ static int acpi_container_add(struct acpi_device *device); static int acpi_container_remove(struct acpi_device *device, int type); static struct acpi_driver acpi_container_driver = { - .name = ACPI_CONTAINER_DRIVER_NAME, + .name = "container", .class = ACPI_CONTAINER_CLASS, .ids = "ACPI0004,PNP0A05,PNP0A06", .ops = { diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c index d48f65a8f65..bf513e07b77 100644 --- a/drivers/acpi/debug.c +++ b/drivers/acpi/debug.c @@ -12,7 +12,7 @@ #include <acpi/acglobal.h> #define _COMPONENT ACPI_SYSTEM_COMPONENT -ACPI_MODULE_NAME("debug") +ACPI_MODULE_NAME("debug"); #ifdef MODULE_PARAM_PREFIX #undef MODULE_PARAM_PREFIX diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 688e83a1690..54a697f9aa1 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -32,11 +32,11 @@ #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> -#define ACPI_DOCK_DRIVER_NAME "ACPI Dock Station Driver" +#define ACPI_DOCK_DRIVER_DESCRIPTION "ACPI Dock Station Driver" -ACPI_MODULE_NAME("dock") +ACPI_MODULE_NAME("dock"); MODULE_AUTHOR("Kristen Carlson Accardi"); -MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_NAME); +MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION); MODULE_LICENSE("GPL"); static struct atomic_notifier_head dock_notifier_list; @@ -741,7 +741,7 @@ static int dock_add(acpi_handle handle) goto dock_add_err; } - printk(KERN_INFO PREFIX "%s \n", ACPI_DOCK_DRIVER_NAME); + printk(KERN_INFO PREFIX "%s \n", ACPI_DOCK_DRIVER_DESCRIPTION); return 0; diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 743ce27fa0b..ab688837379 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -38,11 +38,10 @@ #include <acpi/actypes.h> #define _COMPONENT ACPI_EC_COMPONENT -ACPI_MODULE_NAME("acpi_ec") +ACPI_MODULE_NAME("ec"); #define ACPI_EC_COMPONENT 0x00100000 #define ACPI_EC_CLASS "embedded_controller" #define ACPI_EC_HID "PNP0C09" -#define ACPI_EC_DRIVER_NAME "ACPI Embedded Controller Driver" #define ACPI_EC_DEVICE_NAME "Embedded Controller" #define ACPI_EC_FILE_INFO "info" #undef PREFIX @@ -80,7 +79,7 @@ static int acpi_ec_stop(struct acpi_device *device, int type); static int acpi_ec_add(struct acpi_device *device); static struct acpi_driver acpi_ec_driver = { - .name = ACPI_EC_DRIVER_NAME, + .name = "ec", .class = ACPI_EC_CLASS, .ids = ACPI_EC_HID, .ops = { @@ -280,8 +279,10 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, mutex_lock(&ec->lock); if (ec->global_lock) { status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { + mutex_unlock(&ec->lock); return -ENODEV; + } } /* Make sure GPE is enabled before doing transaction */ diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index 959a893c8d1..3b23562e6f9 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -13,7 +13,7 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_SYSTEM_COMPONENT -ACPI_MODULE_NAME("event") +ACPI_MODULE_NAME("event"); /* Global vars for handling event proc entry */ static DEFINE_SPINLOCK(acpi_system_event_lock); diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c index dfac3ecc596..635ba449ebc 100644 --- a/drivers/acpi/events/evgpe.c +++ b/drivers/acpi/events/evgpe.c @@ -636,17 +636,6 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) } } - if (!acpi_gbl_system_awake_and_running) { - /* - * We just woke up because of a wake GPE. Disable any further GPEs - * until we are fully up and running (Only wake GPEs should be enabled - * at this time, but we just brute-force disable them all.) - * 1) We must disable this particular wake GPE so it won't fire again - * 2) We want to disable all wake GPEs, since we are now awake - */ - (void)acpi_hw_disable_all_gpes(); - } - /* * Dispatch the GPE to either an installed handler, or the control method * associated with this GPE (_Lxx or _Exx). If a handler exists, we invoke diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index af22fdf7341..ec655c53949 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -36,14 +36,13 @@ #define ACPI_FAN_COMPONENT 0x00200000 #define ACPI_FAN_CLASS "fan" -#define ACPI_FAN_DRIVER_NAME "ACPI Fan Driver" #define ACPI_FAN_FILE_STATE "state" #define _COMPONENT ACPI_FAN_COMPONENT -ACPI_MODULE_NAME("acpi_fan") +ACPI_MODULE_NAME("fan"); - MODULE_AUTHOR("Paul Diefenbaugh"); -MODULE_DESCRIPTION(ACPI_FAN_DRIVER_NAME); +MODULE_AUTHOR("Paul Diefenbaugh"); +MODULE_DESCRIPTION("ACPI Fan Driver"); MODULE_LICENSE("GPL"); static int acpi_fan_add(struct acpi_device *device); @@ -52,7 +51,7 @@ static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state); static int acpi_fan_resume(struct acpi_device *device); static struct acpi_driver acpi_fan_driver = { - .name = ACPI_FAN_DRIVER_NAME, + .name = "fan", .class = ACPI_FAN_CLASS, .ids = "PNP0C0B", .ops = { diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 7b6c9ff9beb..4334c208841 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -241,3 +241,65 @@ static int __init init_acpi_device_notify(void) } arch_initcall(init_acpi_device_notify); + + +#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE) + +/* Every ACPI platform has a mc146818 compatible "cmos rtc". Here we find + * its device node and pass extra config data. This helps its driver use + * capabilities that the now-obsolete mc146818 didn't have, and informs it + * that this board's RTC is wakeup-capable (per ACPI spec). + */ +#include <linux/mc146818rtc.h> + +static struct cmos_rtc_board_info rtc_info; + + +/* PNP devices are registered in a subsys_initcall(); + * ACPI specifies the PNP IDs to use. + */ +#include <linux/pnp.h> + +static int __init pnp_match(struct device *dev, void *data) +{ + static const char *ids[] = { "PNP0b00", "PNP0b01", "PNP0b02", }; + struct pnp_dev *pnp = to_pnp_dev(dev); + int i; + + for (i = 0; i < ARRAY_SIZE(ids); i++) { + if (compare_pnp_id(pnp->id, ids[i]) != 0) + return 1; + } + return 0; +} + +static struct device *__init get_rtc_dev(void) +{ + return bus_find_device(&pnp_bus_type, NULL, NULL, pnp_match); +} + +static int __init acpi_rtc_init(void) +{ + struct device *dev = get_rtc_dev(); + + if (dev) { + rtc_info.rtc_day_alarm = acpi_gbl_FADT.day_alarm; + rtc_info.rtc_mon_alarm = acpi_gbl_FADT.month_alarm; + rtc_info.rtc_century = acpi_gbl_FADT.century; + + /* NOTE: acpi_gbl_FADT->rtcs4 is NOT currently useful */ + + dev->platform_data = &rtc_info; + + /* RTC always wakes from S1/S2/S3, and often S4/STD */ + device_init_wakeup(dev, 1); + + put_device(dev); + } else + pr_debug("ACPI: RTC unavailable?\n"); + return 0; +} +/* do this between RTC subsys_initcall() and rtc_cmos driver_initcall() */ +fs_initcall(acpi_rtc_init); + +#endif diff --git a/drivers/acpi/hotkey.c b/drivers/acpi/hotkey.c deleted file mode 100644 index 8edfb92f7ed..00000000000 --- a/drivers/acpi/hotkey.c +++ /dev/null @@ -1,1042 +0,0 @@ -/* - * hotkey.c - ACPI Hotkey Driver ($Revision: 0.2 $) - * - * Copyright (C) 2004 Luming Yu <luming.yu@intel.com> - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/types.h> -#include <linux/proc_fs.h> -#include <linux/sched.h> -#include <linux/kmod.h> -#include <linux/seq_file.h> -#include <acpi/acpi_drivers.h> -#include <acpi/acpi_bus.h> -#include <asm/uaccess.h> - -#define HOTKEY_ACPI_VERSION "0.1" - -#define HOTKEY_PROC "hotkey" -#define HOTKEY_EV_CONFIG "event_config" -#define HOTKEY_PL_CONFIG "poll_config" -#define HOTKEY_ACTION "action" -#define HOTKEY_INFO "info" - -#define ACPI_HOTK_NAME "Generic Hotkey Driver" -#define ACPI_HOTK_CLASS "Hotkey" -#define ACPI_HOTK_DEVICE_NAME "Hotkey" -#define ACPI_HOTK_HID "Unknown?" -#define ACPI_HOTKEY_COMPONENT 0x20000000 - -#define ACPI_HOTKEY_EVENT 0x1 -#define ACPI_HOTKEY_POLLING 0x2 -#define ACPI_UNDEFINED_EVENT 0xf - -#define RESULT_STR_LEN 80 - -#define ACTION_METHOD 0 -#define POLL_METHOD 1 - -#define IS_EVENT(e) ((e) <= 10000 && (e) >0) -#define IS_POLL(e) ((e) > 10000) -#define IS_OTHERS(e) ((e)<=0 || (e)>=20000) -#define _COMPONENT ACPI_HOTKEY_COMPONENT -ACPI_MODULE_NAME("acpi_hotkey") - - MODULE_AUTHOR("luming.yu@intel.com"); -MODULE_DESCRIPTION(ACPI_HOTK_NAME); -MODULE_LICENSE("GPL"); - -/* standardized internal hotkey number/event */ -enum { - /* Video Extension event */ - HK_EVENT_CYCLE_OUTPUT_DEVICE = 0x80, - HK_EVENT_OUTPUT_DEVICE_STATUS_CHANGE, - HK_EVENT_CYCLE_DISPLAY_OUTPUT, - HK_EVENT_NEXT_DISPLAY_OUTPUT, - HK_EVENT_PREVIOUS_DISPLAY_OUTPUT, - HK_EVENT_CYCLE_BRIGHTNESS, - HK_EVENT_INCREASE_BRIGHTNESS, - HK_EVENT_DECREASE_BRIGHTNESS, - HK_EVENT_ZERO_BRIGHTNESS, - HK_EVENT_DISPLAY_DEVICE_OFF, - - /* Snd Card event */ - HK_EVENT_VOLUME_MUTE, - HK_EVENT_VOLUME_INCLREASE, - HK_EVENT_VOLUME_DECREASE, - - /* running state control */ - HK_EVENT_ENTERRING_S3, - HK_EVENT_ENTERRING_S4, - HK_EVENT_ENTERRING_S5, -}; - -enum conf_entry_enum { - bus_handle = 0, - bus_method = 1, - action_handle = 2, - method = 3, - LAST_CONF_ENTRY -}; - -/* procdir we use */ -static struct proc_dir_entry *hotkey_proc_dir; -static struct proc_dir_entry *hotkey_config; -static struct proc_dir_entry *hotkey_poll_config; -static struct proc_dir_entry *hotkey_action; -static struct proc_dir_entry *hotkey_info; - -/* linkage for all type of hotkey */ -struct acpi_hotkey_link { - struct list_head entries; - int hotkey_type; /* event or polling based hotkey */ - int hotkey_standard_num; /* standardized hotkey(event) number */ -}; - -/* event based hotkey */ -struct acpi_event_hotkey { - struct acpi_hotkey_link hotkey_link; - int flag; - acpi_handle bus_handle; /* bus to install notify handler */ - int external_hotkey_num; /* external hotkey/event number */ - acpi_handle action_handle; /* acpi handle attached aml action method */ - char *action_method; /* action method */ -}; - -/* - * There are two ways to poll status - * 1. directy call read_xxx method, without any arguments passed in - * 2. call write_xxx method, with arguments passed in, you need - * the result is saved in acpi_polling_hotkey.poll_result. - * anthoer read command through polling interface. - * - */ - -/* polling based hotkey */ -struct acpi_polling_hotkey { - struct acpi_hotkey_link hotkey_link; - int flag; - acpi_handle poll_handle; /* acpi handle attached polling method */ - char *poll_method; /* poll method */ - acpi_handle action_handle; /* acpi handle attached action method */ - char *action_method; /* action method */ - union acpi_object *poll_result; /* polling_result */ - struct proc_dir_entry *proc; -}; - -/* hotkey object union */ -union acpi_hotkey { - struct list_head entries; - struct acpi_hotkey_link link; - struct acpi_event_hotkey event_hotkey; - struct acpi_polling_hotkey poll_hotkey; -}; - -/* hotkey object list */ -struct acpi_hotkey_list { - struct list_head *entries; - int count; -}; - -static int auto_hotkey_add(struct acpi_device *device); -static int auto_hotkey_remove(struct acpi_device *device, int type); - -static struct acpi_driver hotkey_driver = { - .name = ACPI_HOTK_NAME, - .class = ACPI_HOTK_CLASS, - .ids = ACPI_HOTK_HID, - .ops = { - .add = auto_hotkey_add, - .remove = auto_hotkey_remove, - }, -}; - -static void free_hotkey_device(union acpi_hotkey *key); -static void free_hotkey_buffer(union acpi_hotkey *key); -static void free_poll_hotkey_buffer(union acpi_hotkey *key); -static int hotkey_open_config(struct inode *inode, struct file *file); -static int hotkey_poll_open_config(struct inode *inode, struct file *file); -static ssize_t hotkey_write_config(struct file *file, - const char __user * buffer, - size_t count, loff_t * data); -static int hotkey_info_open_fs(struct inode *inode, struct file *file); -static int hotkey_action_open_fs(struct inode *inode, struct file *file); -static ssize_t hotkey_execute_aml_method(struct file *file, - const char __user * buffer, - size_t count, loff_t * data); -static int hotkey_config_seq_show(struct seq_file *seq, void *offset); -static int hotkey_poll_config_seq_show(struct seq_file *seq, void *offset); -static int hotkey_polling_open_fs(struct inode *inode, struct file *file); -static union acpi_hotkey *get_hotkey_by_event(struct - acpi_hotkey_list - *hotkey_list, int event); - -/* event based config */ -static const struct file_operations hotkey_config_fops = { - .open = hotkey_open_config, - .read = seq_read, - .write = hotkey_write_config, - .llseek = seq_lseek, - .release = single_release, -}; - -/* polling based config */ -static const struct file_operations hotkey_poll_config_fops = { - .open = hotkey_poll_open_config, - .read = seq_read, - .write = hotkey_write_config, - .llseek = seq_lseek, - .release = single_release, -}; - -/* hotkey driver info */ -static const struct file_operations hotkey_info_fops = { - .open = hotkey_info_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -/* action */ -static const struct file_operations hotkey_action_fops = { - .open = hotkey_action_open_fs, - .read = seq_read, - .write = hotkey_execute_aml_method, - .llseek = seq_lseek, - .release = single_release, -}; - -/* polling results */ -static const struct file_operations hotkey_polling_fops = { - .open = hotkey_polling_open_fs, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -struct acpi_hotkey_list global_hotkey_list; /* link all ev or pl hotkey */ -struct list_head hotkey_entries; /* head of the list of hotkey_list */ - -static int hotkey_info_seq_show(struct seq_file *seq, void *offset) -{ - - seq_printf(seq, "Hotkey generic driver ver: %s\n", HOTKEY_ACPI_VERSION); - - return 0; -} - -static int hotkey_info_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, hotkey_info_seq_show, PDE(inode)->data); -} - -static char *format_result(union acpi_object *object) -{ - char *buf; - - buf = kzalloc(RESULT_STR_LEN, GFP_KERNEL); - if (!buf) - return NULL; - /* Now, just support integer type */ - if (object->type == ACPI_TYPE_INTEGER) - sprintf(buf, "%d\n", (u32) object->integer.value); - return buf; -} - -static int hotkey_polling_seq_show(struct seq_file *seq, void *offset) -{ - struct acpi_polling_hotkey *poll_hotkey = seq->private; - char *buf; - - - if (poll_hotkey->poll_result) { - buf = format_result(poll_hotkey->poll_result); - if (buf) - seq_printf(seq, "%s", buf); - kfree(buf); - } - return 0; -} - -static int hotkey_polling_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, hotkey_polling_seq_show, PDE(inode)->data); -} - -static int hotkey_action_open_fs(struct inode *inode, struct file *file) -{ - return single_open(file, hotkey_info_seq_show, PDE(inode)->data); -} - -/* Mapping external hotkey number to standardized hotkey event num */ -static int hotkey_get_internal_event(int event, struct acpi_hotkey_list *list) -{ - struct list_head *entries; - int val = -1; - - - list_for_each(entries, list->entries) { - union acpi_hotkey *key = - container_of(entries, union acpi_hotkey, entries); - if (key->link.hotkey_type == ACPI_HOTKEY_EVENT - && key->event_hotkey.external_hotkey_num == event) { - val = key->link.hotkey_standard_num; - break; - } - } - - return val; -} - -static void -acpi_hotkey_notify_handler(acpi_handle handle, u32 event, void *data) -{ - struct acpi_device *device = NULL; - u32 internal_event; - - - if (acpi_bus_get_device(handle, &device)) - return; - - internal_event = hotkey_get_internal_event(event, &global_hotkey_list); - acpi_bus_generate_event(device, internal_event, 0); - - return; -} - -/* Need to invent automatically hotkey add method */ -static int auto_hotkey_add(struct acpi_device *device) -{ - /* Implement me */ - return 0; -} - -/* Need to invent automatically hotkey remove method */ -static int auto_hotkey_remove(struct acpi_device *device, int type) -{ - /* Implement me */ - return 0; -} - -/* Create a proc file for each polling method */ -static int create_polling_proc(union acpi_hotkey *device) -{ - struct proc_dir_entry *proc; - char proc_name[80]; - mode_t mode; - - mode = S_IFREG | S_IRUGO | S_IWUGO; - - sprintf(proc_name, "%d", device->link.hotkey_standard_num); - /* - strcat(proc_name, device->poll_hotkey.poll_method); - */ - proc = create_proc_entry(proc_name, mode, hotkey_proc_dir); - - if (!proc) { - return -ENODEV; - } else { - proc->proc_fops = &hotkey_polling_fops; - proc->owner = THIS_MODULE; - proc->data = device; - proc->uid = 0; - proc->gid = 0; - device->poll_hotkey.proc = proc; - } - return 0; -} - -static int hotkey_add(union acpi_hotkey *device) -{ - int status = 0; - struct acpi_device *dev = NULL; - - - if (device->link.hotkey_type == ACPI_HOTKEY_EVENT) { - acpi_bus_get_device(device->event_hotkey.bus_handle, &dev); - status = acpi_install_notify_handler(dev->handle, - ACPI_DEVICE_NOTIFY, - acpi_hotkey_notify_handler, - dev); - } else /* Add polling hotkey */ - create_polling_proc(device); - - global_hotkey_list.count++; - - list_add_tail(&device->link.entries, global_hotkey_list.entries); - - return status; -} - -static int hotkey_remove(union acpi_hotkey *device) -{ - struct list_head *entries, *next; - - - list_for_each_safe(entries, next, global_hotkey_list.entries) { - union acpi_hotkey *key = - container_of(entries, union acpi_hotkey, entries); - if (key->link.hotkey_standard_num == - device->link.hotkey_standard_num) { - list_del(&key->link.entries); - free_hotkey_device(key); - global_hotkey_list.count--; - break; - } - } - kfree(device); - return 0; -} - -static int hotkey_update(union acpi_hotkey *key) -{ - struct list_head *entries; - - - list_for_each(entries, global_hotkey_list.entries) { - union acpi_hotkey *tmp = - container_of(entries, union acpi_hotkey, entries); - if (tmp->link.hotkey_standard_num == - key->link.hotkey_standard_num) { - if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) { - free_hotkey_buffer(tmp); - tmp->event_hotkey.bus_handle = - key->event_hotkey.bus_handle; - tmp->event_hotkey.external_hotkey_num = - key->event_hotkey.external_hotkey_num; - tmp->event_hotkey.action_handle = - key->event_hotkey.action_handle; - tmp->event_hotkey.action_method = - key->event_hotkey.action_method; - kfree(key); - } else { - /* - char proc_name[80]; - - sprintf(proc_name, "%d", tmp->link.hotkey_standard_num); - strcat(proc_name, tmp->poll_hotkey.poll_method); - remove_proc_entry(proc_name,hotkey_proc_dir); - */ - free_poll_hotkey_buffer(tmp); - tmp->poll_hotkey.poll_handle = - key->poll_hotkey.poll_handle; - tmp->poll_hotkey.poll_method = - key->poll_hotkey.poll_method; - tmp->poll_hotkey.action_handle = - key->poll_hotkey.action_handle; - tmp->poll_hotkey.action_method = - key->poll_hotkey.action_method; - tmp->poll_hotkey.poll_result = - key->poll_hotkey.poll_result; - /* - create_polling_proc(tmp); - */ - kfree(key); - } - return 0; - break; - } - } - - return -ENODEV; -} - -static void free_hotkey_device(union acpi_hotkey *key) -{ - struct acpi_device *dev; - - - if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) { - acpi_bus_get_device(key->event_hotkey.bus_handle, &dev); - if (dev->handle) - acpi_remove_notify_handler(dev->handle, - ACPI_DEVICE_NOTIFY, - acpi_hotkey_notify_handler); - free_hotkey_buffer(key); - } else { - char proc_name[80]; - - sprintf(proc_name, "%d", key->link.hotkey_standard_num); - /* - strcat(proc_name, key->poll_hotkey.poll_method); - */ - remove_proc_entry(proc_name, hotkey_proc_dir); - free_poll_hotkey_buffer(key); - } - kfree(key); - return; -} - -static void free_hotkey_buffer(union acpi_hotkey *key) -{ - /* key would never be null, action method could be */ - kfree(key->event_hotkey.action_method); -} - -static void free_poll_hotkey_buffer(union acpi_hotkey *key) -{ - /* key would never be null, others could be*/ - kfree(key->poll_hotkey.action_method); - kfree(key->poll_hotkey.poll_method); - kfree(key->poll_hotkey.poll_result); -} -static int -init_hotkey_device(union acpi_hotkey *key, char **config_entry, - int std_num, int external_num) -{ - acpi_handle tmp_handle; - acpi_status status = AE_OK; - - if (std_num < 0 || IS_POLL(std_num) || !key) - goto do_fail; - - if (!config_entry[bus_handle] || !config_entry[action_handle] - || !config_entry[method]) - goto do_fail; - - key->link.hotkey_type = ACPI_HOTKEY_EVENT; - key->link.hotkey_standard_num = std_num; - key->event_hotkey.flag = 0; - key->event_hotkey.action_method = config_entry[method]; - - status = acpi_get_handle(NULL, config_entry[bus_handle], - &(key->event_hotkey.bus_handle)); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - key->event_hotkey.external_hotkey_num = external_num; - status = acpi_get_handle(NULL, config_entry[action_handle], - &(key->event_hotkey.action_handle)); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - status = acpi_get_handle(key->event_hotkey.action_handle, - config_entry[method], &tmp_handle); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - return AE_OK; -do_fail_zero: - key->event_hotkey.action_method = NULL; -do_fail: - return -ENODEV; -} - -static int -init_poll_hotkey_device(union acpi_hotkey *key, char **config_entry, - int std_num) -{ - acpi_status status = AE_OK; - acpi_handle tmp_handle; - - if (std_num < 0 || IS_EVENT(std_num) || !key) - goto do_fail; - if (!config_entry[bus_handle] ||!config_entry[bus_method] || - !config_entry[action_handle] || !config_entry[method]) - goto do_fail; - - key->link.hotkey_type = ACPI_HOTKEY_POLLING; - key->link.hotkey_standard_num = std_num; - key->poll_hotkey.flag = 0; - key->poll_hotkey.poll_method = config_entry[bus_method]; - key->poll_hotkey.action_method = config_entry[method]; - - status = acpi_get_handle(NULL, config_entry[bus_handle], - &(key->poll_hotkey.poll_handle)); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - status = acpi_get_handle(key->poll_hotkey.poll_handle, - config_entry[bus_method], &tmp_handle); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - status = - acpi_get_handle(NULL, config_entry[action_handle], - &(key->poll_hotkey.action_handle)); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - status = acpi_get_handle(key->poll_hotkey.action_handle, - config_entry[method], &tmp_handle); - if (ACPI_FAILURE(status)) - goto do_fail_zero; - key->poll_hotkey.poll_result = - kmalloc(sizeof(union acpi_object), GFP_KERNEL); - if (!key->poll_hotkey.poll_result) - goto do_fail_zero; - return AE_OK; - -do_fail_zero: - key->poll_hotkey.poll_method = NULL; - key->poll_hotkey.action_method = NULL; -do_fail: - return -ENODEV; -} - -static int hotkey_open_config(struct inode *inode, struct file *file) -{ - return (single_open - (file, hotkey_config_seq_show, PDE(inode)->data)); -} - -static int hotkey_poll_open_config(struct inode *inode, struct file *file) -{ - return (single_open - (file, hotkey_poll_config_seq_show, PDE(inode)->data)); -} - -static int hotkey_config_seq_show(struct seq_file *seq, void *offset) -{ - struct acpi_hotkey_list *hotkey_list = &global_hotkey_list; - struct list_head *entries; - char bus_name[ACPI_PATHNAME_MAX] = { 0 }; - char action_name[ACPI_PATHNAME_MAX] = { 0 }; - struct acpi_buffer bus = { ACPI_PATHNAME_MAX, bus_name }; - struct acpi_buffer act = { ACPI_PATHNAME_MAX, action_name }; - - - list_for_each(entries, hotkey_list->entries) { - union acpi_hotkey *key = - container_of(entries, union acpi_hotkey, entries); - if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) { - acpi_get_name(key->event_hotkey.bus_handle, - ACPI_NAME_TYPE_MAX, &bus); - acpi_get_name(key->event_hotkey.action_handle, - ACPI_NAME_TYPE_MAX, &act); - seq_printf(seq, "%s:%s:%s:%d:%d\n", bus_name, - action_name, - key->event_hotkey.action_method, - key->link.hotkey_standard_num, - key->event_hotkey.external_hotkey_num); - } - } - seq_puts(seq, "\n"); - return 0; -} - -static int hotkey_poll_config_seq_show(struct seq_file *seq, void *offset) -{ - struct acpi_hotkey_list *hotkey_list = &global_hotkey_list; - struct list_head *entries; - char bus_name[ACPI_PATHNAME_MAX] = { 0 }; - char action_name[ACPI_PATHNAME_MAX] = { 0 }; - struct acpi_buffer bus = { ACPI_PATHNAME_MAX, bus_name }; - struct acpi_buffer act = { ACPI_PATHNAME_MAX, action_name }; - - - list_for_each(entries, hotkey_list->entries) { - union acpi_hotkey *key = - container_of(entries, union acpi_hotkey, entries); - if (key->link.hotkey_type == ACPI_HOTKEY_POLLING) { - acpi_get_name(key->poll_hotkey.poll_handle, - ACPI_NAME_TYPE_MAX, &bus); - acpi_get_name(key->poll_hotkey.action_handle, - ACPI_NAME_TYPE_MAX, &act); - seq_printf(seq, "%s:%s:%s:%s:%d\n", bus_name, - key->poll_hotkey.poll_method, - action_name, - key->poll_hotkey.action_method, - key->link.hotkey_standard_num); - } - } - seq_puts(seq, "\n"); - return 0; -} - -static int -get_parms(char *config_record, int *cmd, char **config_entry, - int *internal_event_num, int *external_event_num) -{ -/* the format of *config_record = - * "1:\d+:*" : "cmd:internal_event_num" - * "\d+:\w+:\w+:\w+:\w+:\d+:\d+" : - * "cmd:bus_handle:bus_method:action_handle:method:internal_event_num:external_event_num" - */ - char *tmp, *tmp1, count; - int i; - - sscanf(config_record, "%d", cmd); - if (*cmd == 1) { - if (sscanf(config_record, "%d:%d", cmd, internal_event_num) != - 2) - goto do_fail; - else - return (6); - } - tmp = strchr(config_record, ':'); - if (!tmp) - goto do_fail; - tmp++; - for (i = 0; i < LAST_CONF_ENTRY; i++) { - tmp1 = strchr(tmp, ':'); - if (!tmp1) { - goto do_fail; - } - count = tmp1 - tmp; - config_entry[i] = kzalloc(count + 1, GFP_KERNEL); - if (!config_entry[i]) - goto handle_failure; - strncpy(config_entry[i], tmp, count); - tmp = tmp1 + 1; - } - if (sscanf(tmp, "%d:%d", internal_event_num, external_event_num) <= 0) - goto handle_failure; - if (!IS_OTHERS(*internal_event_num)) { - return 6; - } -handle_failure: - while (i-- > 0) - kfree(config_entry[i]); -do_fail: - return -1; -} - -/* count is length for one input record */ -static ssize_t hotkey_write_config(struct file *file, - const char __user * buffer, - size_t count, loff_t * data) -{ - char *config_record = NULL; - char *config_entry[LAST_CONF_ENTRY]; - int cmd, internal_event_num, external_event_num; - int ret = 0; - union acpi_hotkey *key = kzalloc(sizeof(union acpi_hotkey), GFP_KERNEL); - - if (!key) - return -ENOMEM; - - config_record = kzalloc(count + 1, GFP_KERNEL); - if (!config_record) { - kfree(key); - return -ENOMEM; - } - - if (copy_from_user(config_record, buffer, count)) { - kfree(config_record); - kfree(key); - printk(KERN_ERR PREFIX "Invalid data\n"); - return -EINVAL; - } - ret = get_parms(config_record, &cmd, config_entry, - &internal_event_num, &external_event_num); - kfree(config_record); - if (ret != 6) { - printk(KERN_ERR PREFIX "Invalid data format ret=%d\n", ret); - return -EINVAL; - } - - if (cmd == 1) { - union acpi_hotkey *tmp = NULL; - tmp = get_hotkey_by_event(&global_hotkey_list, - internal_event_num); - if (!tmp) - printk(KERN_ERR PREFIX "Invalid key\n"); - else - memcpy(key, tmp, sizeof(union acpi_hotkey)); - goto cont_cmd; - } - if (IS_EVENT(internal_event_num)) { - if (init_hotkey_device(key, config_entry, - internal_event_num, external_event_num)) - goto init_hotkey_fail; - } else { - if (init_poll_hotkey_device(key, config_entry, - internal_event_num)) - goto init_poll_hotkey_fail; - } -cont_cmd: - switch (cmd) { - case 0: - if (get_hotkey_by_event(&global_hotkey_list, - key->link.hotkey_standard_num)) - goto fail_out; - else - hotkey_add(key); - break; - case 1: - hotkey_remove(key); - break; - case 2: - /* key is kfree()ed if matched*/ - if (hotkey_update(key)) - goto fail_out; - break; - default: - goto fail_out; - break; - } - return count; - -init_poll_hotkey_fail: /* failed init_poll_hotkey_device */ - kfree(config_entry[bus_method]); - config_entry[bus_method] = NULL; -init_hotkey_fail: /* failed init_hotkey_device */ - kfree(config_entry[method]); -fail_out: - kfree(config_entry[bus_handle]); - kfree(config_entry[action_handle]); - /* No double free since elements =NULL for error cases */ - if (IS_EVENT(internal_event_num)) { - if (config_entry[bus_method]) - kfree(config_entry[bus_method]); - free_hotkey_buffer(key); /* frees [method] */ - } else - free_poll_hotkey_buffer(key); /* frees [bus_method]+[method] */ - kfree(key); - printk(KERN_ERR PREFIX "invalid key\n"); - return -EINVAL; -} - -/* - * This function evaluates an ACPI method, given an int as parameter, the - * method is searched within the scope of the handle, can be NULL. The output - * of the method is written is output, which can also be NULL - * - * returns 1 if write is successful, 0 else. - */ -static int write_acpi_int(acpi_handle handle, const char *method, int val, - struct acpi_buffer *output) -{ - struct acpi_object_list params; /* list of input parameters (an int here) */ - union acpi_object in_obj; /* the only param we use */ - acpi_status status; - - params.count = 1; - params.pointer = &in_obj; - in_obj.type = ACPI_TYPE_INTEGER; - in_obj.integer.value = val; - - status = acpi_evaluate_object(handle, (char *)method, ¶ms, output); - - return (status == AE_OK); -} - -static int read_acpi_int(acpi_handle handle, const char *method, - union acpi_object *val) -{ - struct acpi_buffer output; - union acpi_object out_obj; - acpi_status status; - - output.length = sizeof(out_obj); - output.pointer = &out_obj; - - status = acpi_evaluate_object(handle, (char *)method, NULL, &output); - if (val) { - val->integer.value = out_obj.integer.value; - val->type = out_obj.type; - } else - printk(KERN_ERR PREFIX "null val pointer\n"); - return ((status == AE_OK) - && (out_obj.type == ACPI_TYPE_INTEGER)); -} - -static union acpi_hotkey *get_hotkey_by_event(struct - acpi_hotkey_list - *hotkey_list, int event) -{ - struct list_head *entries; - - list_for_each(entries, hotkey_list->entries) { - union acpi_hotkey *key = - container_of(entries, union acpi_hotkey, entries); - if (key->link.hotkey_standard_num == event) { - return (key); - } - } - return (NULL); -} - -/* - * user call AML method interface: - * Call convention: - * echo "event_num: arg type : value" - * example: echo "1:1:30" > /proc/acpi/action - * Just support 1 integer arg passing to AML method - */ - -static ssize_t hotkey_execute_aml_method(struct file *file, - const char __user * buffer, - size_t count, loff_t * data) -{ - struct acpi_hotkey_list *hotkey_list = &global_hotkey_list; - char *arg; - int event, method_type, type, value; - union acpi_hotkey *key; - - - arg = kzalloc(count + 1, GFP_KERNEL); - if (!arg) - return -ENOMEM; - - if (copy_from_user(arg, buffer, count)) { - kfree(arg); - printk(KERN_ERR PREFIX "Invalid argument 2\n"); - return -EINVAL; - } - - if (sscanf(arg, "%d:%d:%d:%d", &event, &method_type, &type, &value) != - 4) { - kfree(arg); - printk(KERN_ERR PREFIX "Invalid argument 3\n"); - return -EINVAL; - } - kfree(arg); - if (type == ACPI_TYPE_INTEGER) { - key = get_hotkey_by_event(hotkey_list, event); - if (!key) - goto do_fail; - if (IS_EVENT(event)) - write_acpi_int(key->event_hotkey.action_handle, - key->event_hotkey.action_method, value, - NULL); - else if (IS_POLL(event)) { - if (method_type == POLL_METHOD) - read_acpi_int(key->poll_hotkey.poll_handle, - key->poll_hotkey.poll_method, - key->poll_hotkey.poll_result); - else if (method_type == ACTION_METHOD) - write_acpi_int(key->poll_hotkey.action_handle, - key->poll_hotkey.action_method, - value, NULL); - else - goto do_fail; - - } - } else { - printk(KERN_WARNING "Not supported\n"); - return -EINVAL; - } - return count; - do_fail: - return -EINVAL; - -} - -static int __init hotkey_init(void) -{ - int result; - mode_t mode = S_IFREG | S_IRUGO | S_IWUGO; - - - if (acpi_disabled) - return -ENODEV; - - if (acpi_specific_hotkey_enabled) { - printk("Using specific hotkey driver\n"); - return -ENODEV; - } - - hotkey_proc_dir = proc_mkdir(HOTKEY_PROC, acpi_root_dir); - if (!hotkey_proc_dir) { - return (-ENODEV); - } - hotkey_proc_dir->owner = THIS_MODULE; - - hotkey_config = - create_proc_entry(HOTKEY_EV_CONFIG, mode, hotkey_proc_dir); - if (!hotkey_config) { - goto do_fail1; - } else { - hotkey_config->proc_fops = &hotkey_config_fops; - hotkey_config->data = &global_hotkey_list; - hotkey_config->owner = THIS_MODULE; - hotkey_config->uid = 0; - hotkey_config->gid = 0; - } - - hotkey_poll_config = - create_proc_entry(HOTKEY_PL_CONFIG, mode, hotkey_proc_dir); - if (!hotkey_poll_config) { - goto do_fail2; - } else { - hotkey_poll_config->proc_fops = &hotkey_poll_config_fops; - hotkey_poll_config->data = &global_hotkey_list; - hotkey_poll_config->owner = THIS_MODULE; - hotkey_poll_config->uid = 0; - hotkey_poll_config->gid = 0; - } - - hotkey_action = create_proc_entry(HOTKEY_ACTION, mode, hotkey_proc_dir); - if (!hotkey_action) { - goto do_fail3; - } else { - hotkey_action->proc_fops = &hotkey_action_fops; - hotkey_action->owner = THIS_MODULE; - hotkey_action->uid = 0; - hotkey_action->gid = 0; - } - - hotkey_info = create_proc_entry(HOTKEY_INFO, mode, hotkey_proc_dir); - if (!hotkey_info) { - goto do_fail4; - } else { - hotkey_info->proc_fops = &hotkey_info_fops; - hotkey_info->owner = THIS_MODULE; - hotkey_info->uid = 0; - hotkey_info->gid = 0; - } - - result = acpi_bus_register_driver(&hotkey_driver); - if (result < 0) - goto do_fail5; - global_hotkey_list.count = 0; - global_hotkey_list.entries = &hotkey_entries; - - INIT_LIST_HEAD(&hotkey_entries); - - return (0); - - do_fail5: - remove_proc_entry(HOTKEY_INFO, hotkey_proc_dir); - do_fail4: - remove_proc_entry(HOTKEY_ACTION, hotkey_proc_dir); - do_fail3: - remove_proc_entry(HOTKEY_PL_CONFIG, hotkey_proc_dir); - do_fail2: - remove_proc_entry(HOTKEY_EV_CONFIG, hotkey_proc_dir); - do_fail1: - remove_proc_entry(HOTKEY_PROC, acpi_root_dir); - return (-ENODEV); -} - -static void __exit hotkey_exit(void) -{ - struct list_head *entries, *next; - - - list_for_each_safe(entries, next, global_hotkey_list.entries) { - union acpi_hotkey *key = - container_of(entries, union acpi_hotkey, entries); - - acpi_os_wait_events_complete(NULL); - list_del(&key->link.entries); - global_hotkey_list.count--; - free_hotkey_device(key); - } - acpi_bus_unregister_driver(&hotkey_driver); - remove_proc_entry(HOTKEY_EV_CONFIG, hotkey_proc_dir); - remove_proc_entry(HOTKEY_PL_CONFIG, hotkey_proc_dir); - remove_proc_entry(HOTKEY_ACTION, hotkey_proc_dir); - remove_proc_entry(HOTKEY_INFO, hotkey_proc_dir); - remove_proc_entry(HOTKEY_PROC, acpi_root_dir); - return; -} - -module_init(hotkey_init); -module_exit(hotkey_exit); diff --git a/drivers/acpi/i2c_ec.c b/drivers/acpi/i2c_ec.c index 76ec8b63e69..acab4a48189 100644 --- a/drivers/acpi/i2c_ec.c +++ b/drivers/acpi/i2c_ec.c @@ -27,18 +27,17 @@ #define ACPI_EC_HC_COMPONENT 0x00080000 #define ACPI_EC_HC_CLASS "ec_hc_smbus" #define ACPI_EC_HC_HID "ACPI0001" -#define ACPI_EC_HC_DRIVER_NAME "ACPI EC HC smbus driver" #define ACPI_EC_HC_DEVICE_NAME "EC HC smbus" #define _COMPONENT ACPI_EC_HC_COMPONENT -ACPI_MODULE_NAME("acpi_smbus") +ACPI_MODULE_NAME("i2c_ec"); static int acpi_ec_hc_add(struct acpi_device *device); static int acpi_ec_hc_remove(struct acpi_device *device, int type); static struct acpi_driver acpi_ec_hc_driver = { - .name = ACPI_EC_HC_DRIVER_NAME, + .name = "i2c_ec", .class = ACPI_EC_HC_CLASS, .ids = ACPI_EC_HC_HID, .ops = { diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c index c6144ca6663..1a0ed3dc409 100644 --- a/drivers/acpi/ibm_acpi.c +++ b/drivers/acpi/ibm_acpi.c @@ -496,6 +496,10 @@ static int ibm_acpi_driver_init(void) printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION); printk(IBM_INFO "%s\n", IBM_URL); + if (ibm_thinkpad_ec_found) + printk(IBM_INFO "ThinkPad EC firmware %s\n", + ibm_thinkpad_ec_found); + return 0; } @@ -2617,7 +2621,7 @@ static void __init ibm_handle_init(char *name, ibm_handle_init(#object, &object##_handle, *object##_parent, \ object##_paths, ARRAY_SIZE(object##_paths), &object##_path) -static int set_ibm_param(const char *val, struct kernel_param *kp) +static int __init set_ibm_param(const char *val, struct kernel_param *kp) { unsigned int i; @@ -2659,7 +2663,8 @@ static void acpi_ibm_exit(void) for (i = ARRAY_SIZE(ibms) - 1; i >= 0; i--) ibm_exit(&ibms[i]); - remove_proc_entry(IBM_DIR, acpi_root_dir); + if (proc_dir) + remove_proc_entry(IBM_DIR, acpi_root_dir); if (ibm_thinkpad_ec_found) kfree(ibm_thinkpad_ec_found); @@ -2696,11 +2701,6 @@ static int __init acpi_ibm_init(void) if (acpi_disabled) return -ENODEV; - if (!acpi_specific_hotkey_enabled) { - printk(IBM_ERR "using generic hotkey driver\n"); - return -ENODEV; - } - /* ec is required because many other handles are relative to it */ IBM_HANDLE_INIT(ec); if (!ec_handle) { @@ -2710,9 +2710,6 @@ static int __init acpi_ibm_init(void) /* Models with newer firmware report the EC in DMI */ ibm_thinkpad_ec_found = check_dmi_for_ec(); - if (ibm_thinkpad_ec_found) - printk(IBM_INFO "ThinkPad EC firmware %s\n", - ibm_thinkpad_ec_found); /* these handles are not required */ IBM_HANDLE_INIT(vid); @@ -2742,6 +2739,7 @@ static int __init acpi_ibm_init(void) proc_dir = proc_mkdir(IBM_DIR, acpi_root_dir); if (!proc_dir) { printk(IBM_ERR "unable to create proc dir %s", IBM_DIR); + acpi_ibm_exit(); return -ENODEV; } proc_dir->owner = THIS_MODULE; diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index 4a9faff4c01..8fcd6a15517 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -33,7 +33,7 @@ #define ACPI_NUMA 0x80000000 #define _COMPONENT ACPI_NUMA -ACPI_MODULE_NAME("numa") +ACPI_MODULE_NAME("numa"); static nodemask_t nodes_found_map = NODE_MASK_NONE; #define PXM_INVAL -1 @@ -45,12 +45,6 @@ int __cpuinitdata pxm_to_node_map[MAX_PXM_DOMAINS] int __cpuinitdata node_to_pxm_map[MAX_NUMNODES] = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL }; -extern int __init acpi_table_parse_madt_family(char *id, - unsigned long madt_size, - int entry_id, - acpi_madt_entry_handler handler, - unsigned int max_entries); - int __cpuinit pxm_to_node(int pxm) { if (pxm < 0) @@ -208,9 +202,9 @@ static int __init acpi_parse_srat(struct acpi_table_header *table) int __init acpi_table_parse_srat(enum acpi_srat_type id, - acpi_madt_entry_handler handler, unsigned int max_entries) + acpi_table_entry_handler handler, unsigned int max_entries) { - return acpi_table_parse_madt_family(ACPI_SIG_SRAT, + return acpi_table_parse_entries(ACPI_SIG_SRAT, sizeof(struct acpi_table_srat), id, handler, max_entries); } @@ -220,9 +214,7 @@ int __init acpi_numa_init(void) int result; /* SRAT: Static Resource Affinity Table */ - result = acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat); - - if (result > 0) { + if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) { result = acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY, acpi_parse_processor_affinity, NR_CPUS); @@ -230,7 +222,7 @@ int __init acpi_numa_init(void) } /* SLIT: System Locality Information Table */ - result = acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit); + acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit); acpi_numa_arch_fixup(); return 0; diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 0f6f3bcbc8e..971eca4864f 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -46,7 +46,7 @@ #include <linux/efi.h> #define _COMPONENT ACPI_OS_SERVICES -ACPI_MODULE_NAME("osl") +ACPI_MODULE_NAME("osl"); #define PREFIX "ACPI: " struct acpi_os_dpc { acpi_osd_exec_callback function; @@ -68,9 +68,6 @@ EXPORT_SYMBOL(acpi_in_debugger); extern char line_buf[80]; #endif /*ENABLE_DEBUGGER */ -int acpi_specific_hotkey_enabled = TRUE; -EXPORT_SYMBOL(acpi_specific_hotkey_enabled); - static unsigned int acpi_irq_irq; static acpi_osd_handler acpi_irq_handler; static void *acpi_irq_context; @@ -205,7 +202,7 @@ void __iomem *acpi_os_map_memory(acpi_physical_address phys, acpi_size size) { if (phys > ULONG_MAX) { printk(KERN_ERR PREFIX "Cannot map memory that high\n"); - return 0; + return NULL; } if (acpi_gbl_permanent_mmap) /* @@ -890,26 +887,6 @@ u32 acpi_os_get_line(char *buffer) } #endif /* ACPI_FUTURE_USAGE */ -/* Assumes no unreadable holes inbetween */ -u8 acpi_os_readable(void *ptr, acpi_size len) -{ -#if defined(__i386__) || defined(__x86_64__) - char tmp; - return !__get_user(tmp, (char __user *)ptr) - && !__get_user(tmp, (char __user *)ptr + len - 1); -#endif - return 1; -} - -#ifdef ACPI_FUTURE_USAGE -u8 acpi_os_writable(void *ptr, acpi_size len) -{ - /* could do dummy write (racy) or a kernel page table lookup. - The later may be difficult at early boot when kmap doesn't work yet. */ - return 1; -} -#endif - acpi_status acpi_os_signal(u32 function, void *info) { switch (function) { @@ -1012,14 +989,6 @@ static int __init acpi_wake_gpes_always_on_setup(char *str) __setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup); -static int __init acpi_hotkey_setup(char *str) -{ - acpi_specific_hotkey_enabled = FALSE; - return 1; -} - -__setup("acpi_generic_hotkey", acpi_hotkey_setup); - /* * max_cstate is defined in the base kernel so modules can * change it w/o depending on the state of the processor module. diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c index 55f57a61c55..028969370bb 100644 --- a/drivers/acpi/pci_bind.c +++ b/drivers/acpi/pci_bind.c @@ -36,7 +36,7 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_PCI_COMPONENT -ACPI_MODULE_NAME("pci_bind") +ACPI_MODULE_NAME("pci_bind"); struct acpi_pci_data { struct acpi_pci_id id; diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index fe7d007833a..dd3186abe07 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -38,7 +38,7 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_PCI_COMPONENT -ACPI_MODULE_NAME("pci_irq") +ACPI_MODULE_NAME("pci_irq"); static struct acpi_prt_list acpi_prt; static DEFINE_SPINLOCK(acpi_prt_lock); diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 0f683c8c6fb..acc59477137 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -44,10 +44,9 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_PCI_COMPONENT -ACPI_MODULE_NAME("pci_link") +ACPI_MODULE_NAME("pci_link"); #define ACPI_PCI_LINK_CLASS "pci_irq_routing" #define ACPI_PCI_LINK_HID "PNP0C0F" -#define ACPI_PCI_LINK_DRIVER_NAME "ACPI PCI Interrupt Link Driver" #define ACPI_PCI_LINK_DEVICE_NAME "PCI Interrupt Link" #define ACPI_PCI_LINK_FILE_INFO "info" #define ACPI_PCI_LINK_FILE_STATUS "state" @@ -56,7 +55,7 @@ static int acpi_pci_link_add(struct acpi_device *device); static int acpi_pci_link_remove(struct acpi_device *device, int type); static struct acpi_driver acpi_pci_link_driver = { - .name = ACPI_PCI_LINK_DRIVER_NAME, + .name = "pci_link", .class = ACPI_PCI_LINK_CLASS, .ids = ACPI_PCI_LINK_HID, .ops = { diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 4ecf701687e..ad4145a3778 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -36,17 +36,16 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_PCI_COMPONENT -ACPI_MODULE_NAME("pci_root") +ACPI_MODULE_NAME("pci_root"); #define ACPI_PCI_ROOT_CLASS "pci_bridge" #define ACPI_PCI_ROOT_HID "PNP0A03" -#define ACPI_PCI_ROOT_DRIVER_NAME "ACPI PCI Root Bridge Driver" #define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge" static int acpi_pci_root_add(struct acpi_device *device); static int acpi_pci_root_remove(struct acpi_device *device, int type); static int acpi_pci_root_start(struct acpi_device *device); static struct acpi_driver acpi_pci_root_driver = { - .name = ACPI_PCI_ROOT_DRIVER_NAME, + .name = "pci_root", .class = ACPI_PCI_ROOT_CLASS, .ids = ACPI_PCI_ROOT_HID, .ops = { diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 0ba7dfbbb2e..92f80ba491c 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -45,10 +45,9 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_POWER_COMPONENT -ACPI_MODULE_NAME("acpi_power") +ACPI_MODULE_NAME("power"); #define ACPI_POWER_COMPONENT 0x00800000 #define ACPI_POWER_CLASS "power_resource" -#define ACPI_POWER_DRIVER_NAME "ACPI Power Resource Driver" #define ACPI_POWER_DEVICE_NAME "Power Resource" #define ACPI_POWER_FILE_INFO "info" #define ACPI_POWER_FILE_STATUS "state" @@ -60,7 +59,7 @@ static int acpi_power_remove(struct acpi_device *device, int type); static int acpi_power_open_fs(struct inode *inode, struct file *file); static struct acpi_driver acpi_power_driver = { - .name = ACPI_POWER_DRIVER_NAME, + .name = "power", .class = ACPI_POWER_CLASS, .ids = ACPI_POWER_HID, .ops = { diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 0079bc51082..99d1516d1e7 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -60,7 +60,6 @@ #define ACPI_PROCESSOR_COMPONENT 0x01000000 #define ACPI_PROCESSOR_CLASS "processor" -#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver" #define ACPI_PROCESSOR_DEVICE_NAME "Processor" #define ACPI_PROCESSOR_FILE_INFO "info" #define ACPI_PROCESSOR_FILE_THROTTLING "throttling" @@ -74,10 +73,10 @@ #define ACPI_STA_PRESENT 0x00000001 #define _COMPONENT ACPI_PROCESSOR_COMPONENT -ACPI_MODULE_NAME("acpi_processor") +ACPI_MODULE_NAME("processor_core"); - MODULE_AUTHOR("Paul Diefenbaugh"); -MODULE_DESCRIPTION(ACPI_PROCESSOR_DRIVER_NAME); +MODULE_AUTHOR("Paul Diefenbaugh"); +MODULE_DESCRIPTION("ACPI Processor Driver"); MODULE_LICENSE("GPL"); static int acpi_processor_add(struct acpi_device *device); @@ -89,7 +88,7 @@ static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu); static int acpi_processor_handle_eject(struct acpi_processor *pr); static struct acpi_driver acpi_processor_driver = { - .name = ACPI_PROCESSOR_DRIVER_NAME, + .name = "processor", .class = ACPI_PROCESSOR_CLASS, .ids = ACPI_PROCESSOR_HID, .ops = { @@ -404,7 +403,7 @@ static int map_lsapic_id(struct acpi_subtable_header *entry, if (lsapic->lapic_flags & ACPI_MADT_ENABLED) { /* First check against id */ if (lsapic->processor_id == acpi_id) { - *apic_id = lsapic->id; + *apic_id = (lsapic->id << 8) | lsapic->eid; return 1; /* Check against optional uid */ } else if (entry->length >= 16 && @@ -1005,7 +1004,7 @@ static int __init acpi_processor_init(void) #ifdef CONFIG_SMP if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0, (struct acpi_table_header **)&madt))) - madt = 0; + madt = NULL; #endif acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 6c6751b1405..60773005b8a 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -39,6 +39,25 @@ #include <linux/moduleparam.h> #include <linux/sched.h> /* need_resched() */ #include <linux/latency.h> +#include <linux/clockchips.h> + +/* + * Include the apic definitions for x86 to have the APIC timer related defines + * available also for UP (on SMP it gets magically included via linux/smp.h). + * asm/acpi.h is not an option, as it would require more include magic. Also + * creating an empty asm-ia64/apic.h would just trade pest vs. cholera. + */ +#ifdef CONFIG_X86 +#include <asm/apic.h> +#endif + +/* + * Include the apic definitions for x86 to have the APIC timer related defines + * available also for UP (on SMP it gets magically included via linux/smp.h). + */ +#ifdef CONFIG_X86 +#include <asm/apic.h> +#endif #include <asm/io.h> #include <asm/uaccess.h> @@ -48,9 +67,8 @@ #define ACPI_PROCESSOR_COMPONENT 0x01000000 #define ACPI_PROCESSOR_CLASS "processor" -#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver" #define _COMPONENT ACPI_PROCESSOR_COMPONENT -ACPI_MODULE_NAME("acpi_processor") +ACPI_MODULE_NAME("processor_idle"); #define ACPI_PROCESSOR_FILE_POWER "power" #define US_TO_PM_TIMER_TICKS(t) ((t * (PM_TIMER_FREQUENCY/1000)) / 1000) #define C2_OVERHEAD 4 /* 1us (3.579 ticks per us) */ @@ -238,6 +256,81 @@ static void acpi_cstate_enter(struct acpi_processor_cx *cstate) } } +#ifdef ARCH_APICTIMER_STOPS_ON_C3 + +/* + * Some BIOS implementations switch to C3 in the published C2 state. + * This seems to be a common problem on AMD boxen, but other vendors + * are affected too. We pick the most conservative approach: we assume + * that the local APIC stops in both C2 and C3. + */ +static void acpi_timer_check_state(int state, struct acpi_processor *pr, + struct acpi_processor_cx *cx) +{ + struct acpi_processor_power *pwr = &pr->power; + + /* + * Check, if one of the previous states already marked the lapic + * unstable + */ + if (pwr->timer_broadcast_on_state < state) + return; + + if (cx->type >= ACPI_STATE_C2) + pr->power.timer_broadcast_on_state = state; +} + +static void acpi_propagate_timer_broadcast(struct acpi_processor *pr) +{ +#ifdef CONFIG_GENERIC_CLOCKEVENTS + unsigned long reason; + + reason = pr->power.timer_broadcast_on_state < INT_MAX ? + CLOCK_EVT_NOTIFY_BROADCAST_ON : CLOCK_EVT_NOTIFY_BROADCAST_OFF; + + clockevents_notify(reason, &pr->id); +#else + cpumask_t mask = cpumask_of_cpu(pr->id); + + if (pr->power.timer_broadcast_on_state < INT_MAX) + on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1); + else + on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1); +#endif +} + +/* Power(C) State timer broadcast control */ +static void acpi_state_timer_broadcast(struct acpi_processor *pr, + struct acpi_processor_cx *cx, + int broadcast) +{ +#ifdef CONFIG_GENERIC_CLOCKEVENTS + + int state = cx - pr->power.states; + + if (state >= pr->power.timer_broadcast_on_state) { + unsigned long reason; + + reason = broadcast ? CLOCK_EVT_NOTIFY_BROADCAST_ENTER : + CLOCK_EVT_NOTIFY_BROADCAST_EXIT; + clockevents_notify(reason, &pr->id); + } +#endif +} + +#else + +static void acpi_timer_check_state(int state, struct acpi_processor *pr, + struct acpi_processor_cx *cstate) { } +static void acpi_propagate_timer_broadcast(struct acpi_processor *pr) { } +static void acpi_state_timer_broadcast(struct acpi_processor *pr, + struct acpi_processor_cx *cx, + int broadcast) +{ +} + +#endif + static void acpi_processor_idle(void) { struct acpi_processor *pr = NULL; @@ -382,6 +475,7 @@ static void acpi_processor_idle(void) /* Get start time (ticks) */ t1 = inl(acpi_gbl_FADT.xpm_timer_block.address); /* Invoke C2 */ + acpi_state_timer_broadcast(pr, cx, 1); acpi_cstate_enter(cx); /* Get end time (ticks) */ t2 = inl(acpi_gbl_FADT.xpm_timer_block.address); @@ -396,6 +490,7 @@ static void acpi_processor_idle(void) /* Compute time (ticks) that we were actually asleep */ sleep_ticks = ticks_elapsed(t1, t2) - cx->latency_ticks - C2_OVERHEAD; + acpi_state_timer_broadcast(pr, cx, 0); break; case ACPI_STATE_C3: @@ -417,6 +512,7 @@ static void acpi_processor_idle(void) /* Get start time (ticks) */ t1 = inl(acpi_gbl_FADT.xpm_timer_block.address); /* Invoke C3 */ + acpi_state_timer_broadcast(pr, cx, 1); acpi_cstate_enter(cx); /* Get end time (ticks) */ t2 = inl(acpi_gbl_FADT.xpm_timer_block.address); @@ -436,6 +532,7 @@ static void acpi_processor_idle(void) /* Compute time (ticks) that we were actually asleep */ sleep_ticks = ticks_elapsed(t1, t2) - cx->latency_ticks - C3_OVERHEAD; + acpi_state_timer_broadcast(pr, cx, 0); break; default: @@ -904,11 +1001,7 @@ static int acpi_processor_power_verify(struct acpi_processor *pr) unsigned int i; unsigned int working = 0; -#ifdef ARCH_APICTIMER_STOPS_ON_C3 - int timer_broadcast = 0; - cpumask_t mask = cpumask_of_cpu(pr->id); - on_each_cpu(switch_ipi_to_APIC_timer, &mask, 1, 1); -#endif + pr->power.timer_broadcast_on_state = INT_MAX; for (i = 1; i < ACPI_PROCESSOR_MAX_POWER; i++) { struct acpi_processor_cx *cx = &pr->power.states[i]; @@ -920,21 +1013,14 @@ static int acpi_processor_power_verify(struct acpi_processor *pr) case ACPI_STATE_C2: acpi_processor_power_verify_c2(cx); -#ifdef ARCH_APICTIMER_STOPS_ON_C3 - /* Some AMD systems fake C3 as C2, but still - have timer troubles */ - if (cx->valid && - boot_cpu_data.x86_vendor == X86_VENDOR_AMD) - timer_broadcast++; -#endif + if (cx->valid) + acpi_timer_check_state(i, pr, cx); break; case ACPI_STATE_C3: acpi_processor_power_verify_c3(pr, cx); -#ifdef ARCH_APICTIMER_STOPS_ON_C3 if (cx->valid) - timer_broadcast++; -#endif + acpi_timer_check_state(i, pr, cx); break; } @@ -942,10 +1028,7 @@ static int acpi_processor_power_verify(struct acpi_processor *pr) working++; } -#ifdef ARCH_APICTIMER_STOPS_ON_C3 - if (timer_broadcast) - on_each_cpu(switch_APIC_timer_to_ipi, &mask, 1, 1); -#endif + acpi_propagate_timer_broadcast(pr); return (working); } diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 058f13cf3b7..2f2e7964226 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -44,10 +44,9 @@ #define ACPI_PROCESSOR_COMPONENT 0x01000000 #define ACPI_PROCESSOR_CLASS "processor" -#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver" #define ACPI_PROCESSOR_FILE_PERFORMANCE "performance" #define _COMPONENT ACPI_PROCESSOR_COMPONENT -ACPI_MODULE_NAME("acpi_processor") +ACPI_MODULE_NAME("processor_perflib"); static DEFINE_MUTEX(performance_mutex); diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index 40fecd67ad8..06e6f3fb882 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -41,9 +41,8 @@ #define ACPI_PROCESSOR_COMPONENT 0x01000000 #define ACPI_PROCESSOR_CLASS "processor" -#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver" #define _COMPONENT ACPI_PROCESSOR_COMPONENT -ACPI_MODULE_NAME("acpi_processor") +ACPI_MODULE_NAME("processor_thermal"); /* -------------------------------------------------------------------------- Limit Interface diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 89dff3639ab..b33486009f4 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -41,9 +41,8 @@ #define ACPI_PROCESSOR_COMPONENT 0x01000000 #define ACPI_PROCESSOR_CLASS "processor" -#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver" #define _COMPONENT ACPI_PROCESSOR_COMPONENT -ACPI_MODULE_NAME("acpi_processor") +ACPI_MODULE_NAME("processor_throttling"); /* -------------------------------------------------------------------------- Throttling Control diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index f58fc7447ab..1eab2034c9a 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -59,7 +59,6 @@ extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); #define ACPI_AC_CLASS "ac_adapter" #define ACPI_BATTERY_CLASS "battery" #define ACPI_SBS_HID "ACPI0002" -#define ACPI_SBS_DRIVER_NAME "ACPI Smart Battery System Driver" #define ACPI_SBS_DEVICE_NAME "Smart Battery System" #define ACPI_SBS_FILE_INFO "info" #define ACPI_SBS_FILE_STATE "state" @@ -78,7 +77,7 @@ extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); #define MAX_SBS_BAT 4 #define MAX_SMBUS_ERR 1 -ACPI_MODULE_NAME("acpi_sbs"); +ACPI_MODULE_NAME("sbs"); MODULE_AUTHOR("Rich Townsend"); MODULE_DESCRIPTION("Smart Battery System ACPI interface driver"); @@ -110,7 +109,7 @@ static void acpi_battery_smbus_err_handler(struct acpi_ec_smbus *smbus); static void acpi_sbs_update_queue(void *data); static struct acpi_driver acpi_sbs_driver = { - .name = ACPI_SBS_DRIVER_NAME, + .name = "sbs", .class = ACPI_SBS_CLASS, .ids = ACPI_SBS_HID, .ops = { diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 64f26db10c8..bb0e0da39fb 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -11,13 +11,12 @@ #include <acpi/acinterp.h> /* for acpi_ex_eisa_id_to_string() */ #define _COMPONENT ACPI_BUS_COMPONENT -ACPI_MODULE_NAME("scan") +ACPI_MODULE_NAME("scan"); #define STRUCT_TO_INT(s) (*((int*)&s)) extern struct acpi_device *acpi_root; #define ACPI_BUS_CLASS "system_bus" #define ACPI_BUS_HID "ACPI_BUS" -#define ACPI_BUS_DRIVER_NAME "ACPI Bus Driver" #define ACPI_BUS_DEVICE_NAME "System Bus" static LIST_HEAD(acpi_device_list); diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c index 7147b0bdab0..83a8d309790 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c @@ -31,14 +31,13 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_SYSTEM_COMPONENT -ACPI_MODULE_NAME("acpi_system") +ACPI_MODULE_NAME("system"); #ifdef MODULE_PARAM_PREFIX #undef MODULE_PARAM_PREFIX #endif #define MODULE_PARAM_PREFIX "acpi." #define ACPI_SYSTEM_CLASS "system" -#define ACPI_SYSTEM_DRIVER_NAME "ACPI System Driver" #define ACPI_SYSTEM_DEVICE_NAME "System" #define ACPI_SYSTEM_FILE_INFO "info" #define ACPI_SYSTEM_FILE_EVENT "event" diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 45bd17313c4..849e2c36180 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -169,40 +169,40 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header * header) int __init -acpi_table_parse_madt_family(char *id, - unsigned long madt_size, +acpi_table_parse_entries(char *id, + unsigned long table_size, int entry_id, - acpi_madt_entry_handler handler, + acpi_table_entry_handler handler, unsigned int max_entries) { - struct acpi_table_header *madt = NULL; + struct acpi_table_header *table_header = NULL; struct acpi_subtable_header *entry; unsigned int count = 0; - unsigned long madt_end; + unsigned long table_end; if (!handler) return -EINVAL; - /* Locate the MADT (if exists). There should only be one. */ - acpi_get_table(id, 0, &madt); + /* Locate the table (if exists). There should only be one. */ + acpi_get_table(id, 0, &table_header); - if (!madt) { + if (!table_header) { printk(KERN_WARNING PREFIX "%4.4s not present\n", id); return -ENODEV; } - madt_end = (unsigned long)madt + madt->length; + table_end = (unsigned long)table_header + table_header->length; /* Parse all entries looking for a match. */ entry = (struct acpi_subtable_header *) - ((unsigned long)madt + madt_size); + ((unsigned long)table_header + table_size); while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) < - madt_end) { + table_end) { if (entry->type == entry_id && (!max_entries || count++ < max_entries)) - if (handler(entry, madt_end)) + if (handler(entry, table_end)) return -EINVAL; entry = (struct acpi_subtable_header *) @@ -218,13 +218,22 @@ acpi_table_parse_madt_family(char *id, int __init acpi_table_parse_madt(enum acpi_madt_type id, - acpi_madt_entry_handler handler, unsigned int max_entries) + acpi_table_entry_handler handler, unsigned int max_entries) { - return acpi_table_parse_madt_family(ACPI_SIG_MADT, + return acpi_table_parse_entries(ACPI_SIG_MADT, sizeof(struct acpi_table_madt), id, handler, max_entries); } +/** + * acpi_table_parse - find table with @id, run @handler on it + * + * @id: table id to find + * @handler: handler to run + * + * Scan the ACPI System Descriptor Table (STD) for a table matching @id, + * run @handler on it. Return 0 if table found, return on if not. + */ int __init acpi_table_parse(char *id, acpi_table_handler handler) { struct acpi_table_header *table = NULL; @@ -234,9 +243,9 @@ int __init acpi_table_parse(char *id, acpi_table_handler handler) acpi_get_table(id, 0, &table); if (table) { handler(table); - return 1; - } else return 0; + } else + return 1; } /* diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c index 807978d5381..417ef5fa766 100644 --- a/drivers/acpi/tables/tbxface.c +++ b/drivers/acpi/tables/tbxface.c @@ -338,9 +338,9 @@ acpi_status acpi_unload_table_id(acpi_owner_id id) int i; acpi_status status = AE_NOT_EXIST; - ACPI_FUNCTION_TRACE(acpi_unload_table); + ACPI_FUNCTION_TRACE(acpi_unload_table_id); - /* Find table from the requested type list */ + /* Find table in the global table list */ for (i = 0; i < acpi_gbl_root_table_list.count; ++i) { if (id != acpi_gbl_root_table_list.tables[i].owner_id) { continue; @@ -352,8 +352,9 @@ acpi_status acpi_unload_table_id(acpi_owner_id id) * simply a position within the hierarchy */ acpi_tb_delete_namespace_by_owner(i); - acpi_tb_release_owner_id(i); + status = acpi_tb_release_owner_id(i); acpi_tb_set_table_loaded_flag(i, FALSE); + break; } return_ACPI_STATUS(status); } @@ -408,7 +409,7 @@ acpi_get_table(char *signature, } if (!acpi_gbl_permanent_mmap) { - acpi_gbl_root_table_list.tables[i].pointer = 0; + acpi_gbl_root_table_list.tables[i].pointer = NULL; } return (status); diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 986afd470a1..15022bc8633 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -47,7 +47,6 @@ #define ACPI_THERMAL_COMPONENT 0x04000000 #define ACPI_THERMAL_CLASS "thermal_zone" -#define ACPI_THERMAL_DRIVER_NAME "ACPI Thermal Zone Driver" #define ACPI_THERMAL_DEVICE_NAME "Thermal Zone" #define ACPI_THERMAL_FILE_STATE "state" #define ACPI_THERMAL_FILE_TEMPERATURE "temperature" @@ -71,10 +70,10 @@ #define CELSIUS_TO_KELVIN(t) ((t+273)*10) #define _COMPONENT ACPI_THERMAL_COMPONENT -ACPI_MODULE_NAME("acpi_thermal") +ACPI_MODULE_NAME("thermal"); MODULE_AUTHOR("Paul Diefenbaugh"); -MODULE_DESCRIPTION(ACPI_THERMAL_DRIVER_NAME); +MODULE_DESCRIPTION("ACPI Thermal Zone Driver"); MODULE_LICENSE("GPL"); static int tzp; @@ -99,7 +98,7 @@ static ssize_t acpi_thermal_write_polling(struct file *, const char __user *, size_t, loff_t *); static struct acpi_driver acpi_thermal_driver = { - .name = ACPI_THERMAL_DRIVER_NAME, + .name = "thermal", .class = ACPI_THERMAL_CLASS, .ids = ACPI_THERMAL_HID, .ops = { @@ -270,7 +269,7 @@ static int acpi_thermal_set_polling(struct acpi_thermal *tz, int seconds) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency set to %lu seconds\n", - tz->polling_frequency)); + tz->polling_frequency/10)); return 0; } diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c index d9b651ffcdc..faf8a5232d8 100644 --- a/drivers/acpi/toshiba_acpi.c +++ b/drivers/acpi/toshiba_acpi.c @@ -125,7 +125,7 @@ static int write_acpi_int(const char *methodName, int val) union acpi_object in_objs[1]; acpi_status status; - params.count = sizeof(in_objs) / sizeof(in_objs[0]); + params.count = ARRAY_SIZE(in_objs); params.pointer = in_objs; in_objs[0].type = ACPI_TYPE_INTEGER; in_objs[0].integer.value = val; @@ -561,10 +561,6 @@ static int __init toshiba_acpi_init(void) if (acpi_disabled) return -ENODEV; - if (!acpi_specific_hotkey_enabled) { - printk(MY_INFO "Using generic hotkey driver\n"); - return -ENODEV; - } /* simple device detection: look for HCI method */ if (is_valid_acpi_path(METHOD_HCI_1)) method_hci = METHOD_HCI_1; diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 68a809fa7b1..34f15757108 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -31,7 +31,7 @@ #include <acpi/acpi_drivers.h> #define _COMPONENT ACPI_BUS_COMPONENT -ACPI_MODULE_NAME("acpi_utils") +ACPI_MODULE_NAME("utils"); /* -------------------------------------------------------------------------- Object Evaluation Helpers diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index e0b97add8c6..bf525cca3b6 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -40,7 +40,6 @@ #define ACPI_VIDEO_COMPONENT 0x08000000 #define ACPI_VIDEO_CLASS "video" -#define ACPI_VIDEO_DRIVER_NAME "ACPI Video Driver" #define ACPI_VIDEO_BUS_NAME "Video Bus" #define ACPI_VIDEO_DEVICE_NAME "Video Device" #define ACPI_VIDEO_NOTIFY_SWITCH 0x80 @@ -65,17 +64,17 @@ #define ACPI_VIDEO_DISPLAY_LCD 4 #define _COMPONENT ACPI_VIDEO_COMPONENT -ACPI_MODULE_NAME("acpi_video") +ACPI_MODULE_NAME("video"); - MODULE_AUTHOR("Bruno Ducrot"); -MODULE_DESCRIPTION(ACPI_VIDEO_DRIVER_NAME); +MODULE_AUTHOR("Bruno Ducrot"); +MODULE_DESCRIPTION("ACPI Video Driver"); MODULE_LICENSE("GPL"); static int acpi_video_bus_add(struct acpi_device *device); static int acpi_video_bus_remove(struct acpi_device *device, int type); static struct acpi_driver acpi_video_bus = { - .name = ACPI_VIDEO_DRIVER_NAME, + .name = "video", .class = ACPI_VIDEO_CLASS, .ids = ACPI_VIDEO_HID, .ops = { diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 25d8d3f778a..2cf8251728d 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1410,7 +1410,16 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class, } tf.protocol = ATA_PROT_PIO; - tf.flags |= ATA_TFLAG_POLLING; /* for polling presence detection */ + + /* Some devices choke if TF registers contain garbage. Make + * sure those are properly initialized. + */ + tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + + /* Device presence detection is unreliable on some + * controllers. Always poll IDENTIFY if available. + */ + tf.flags |= ATA_TFLAG_POLLING; err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE, id, sizeof(id[0]) * ATA_ID_WORDS); diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 4223e10de6a..98c1fee4b30 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -89,9 +89,10 @@ static int probe_all; /* Set to check all ISA port ranges */ static int ht6560a; /* HT 6560A on primary 1, secondary 2, both 3 */ static int ht6560b; /* HT 6560A on primary 1, secondary 2, both 3 */ static int opti82c611a; /* Opti82c611A on primary 1, secondary 2, both 3 */ -static int opti82c46x; /* Opti 82c465MV present (pri/sec autodetect) */ +static int opti82c46x; /* Opti 82c465MV present (pri/sec autodetect) */ static int autospeed; /* Chip present which snoops speed changes */ static int pio_mask = 0x1F; /* PIO range for autospeed devices */ +static int iordy_mask = 0xFFFFFFFF; /* Use iordy if available */ /** * legacy_set_mode - mode setting @@ -113,6 +114,7 @@ static int legacy_set_mode(struct ata_port *ap, struct ata_device **unused) for (i = 0; i < ATA_MAX_DEVICES; i++) { struct ata_device *dev = &ap->device[i]; if (ata_dev_enabled(dev)) { + ata_dev_printk(dev, KERN_INFO, "configured for PIO\n"); dev->pio_mode = XFER_PIO_0; dev->xfer_mode = XFER_PIO_0; dev->xfer_shift = ATA_SHIFT_PIO; @@ -695,6 +697,7 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl void __iomem *io_addr, *ctrl_addr; int pio_modes = pio_mask; u32 mask = (1 << port); + u32 iordy = (iordy_mask & mask) ? 0: ATA_FLAG_NO_IORDY; int ret; pdev = platform_device_register_simple(DRV_NAME, nr_legacy_host, NULL, 0); @@ -715,6 +718,7 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl if (ht6560a & mask) { ops = &ht6560a_port_ops; pio_modes = 0x07; + iordy = ATA_FLAG_NO_IORDY; } if (ht6560b & mask) { ops = &ht6560b_port_ops; @@ -750,6 +754,7 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl printk(KERN_INFO "PDC20230-C/20630 VLB ATA controller detected.\n"); pio_modes = 0x07; ops = &pdc20230_port_ops; + iordy = ATA_FLAG_NO_IORDY; udelay(100); inb(0x1F5); } else { @@ -767,6 +772,7 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl /* Chip does mode setting by command snooping */ if (ops == &legacy_port_ops && (autospeed & mask)) ops = &simple_port_ops; + memset(&ae, 0, sizeof(struct ata_probe_ent)); INIT_LIST_HEAD(&ae.node); ae.dev = &pdev->dev; @@ -776,7 +782,7 @@ static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl ae.pio_mask = pio_modes; ae.irq = irq; ae.irq_flags = 0; - ae.port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST; + ae.port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST|iordy; ae.port[0].cmd_addr = io_addr; ae.port[0].altstatus_addr = ctrl_addr; ae.port[0].ctl_addr = ctrl_addr; @@ -945,6 +951,7 @@ module_param(ht6560b, int, 0); module_param(opti82c611a, int, 0); module_param(opti82c46x, int, 0); module_param(pio_mask, int, 0); +module_param(iordy_mask, int, 0); module_init(legacy_init); module_exit(legacy_exit); diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c index 1b3b4ed8eb1..4362141976a 100644 --- a/drivers/ata/pata_qdi.c +++ b/drivers/ata/pata_qdi.c @@ -264,16 +264,18 @@ static __init int qdi_init_one(unsigned long port, int type, unsigned long io, i if (type == 6580) { ae.port_ops = &qdi6580_port_ops; ae.pio_mask = 0x1F; + ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; } else { ae.port_ops = &qdi6500_port_ops; ae.pio_mask = 0x07; /* Actually PIO3 !IORDY is possible */ + ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | + ATA_FLAG_NO_IORDY; } ae.sht = &qdi_sht; ae.n_ports = 1; ae.irq = irq; ae.irq_flags = 0; - ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST; ae.port[0].cmd_addr = io_addr; ae.port[0].altstatus_addr = ctl_addr; ae.port[0].ctl_addr = ctl_addr; diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c index f2fa158d07c..96e890fd645 100644 --- a/drivers/ata/pata_sl82c105.c +++ b/drivers/ata/pata_sl82c105.c @@ -187,7 +187,9 @@ static void sl82c105_bmdma_start(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; + udelay(100); sl82c105_reset_engine(ap); + udelay(100); /* Set the clocks for DMA */ sl82c105_configure_dmamode(ap, qc->dev); @@ -216,6 +218,7 @@ static void sl82c105_bmdma_stop(struct ata_queued_cmd *qc) ata_bmdma_stop(qc); sl82c105_reset_engine(ap); + udelay(100); /* This will redo the initial setup of the DMA device to matching PIO timings */ diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 095ef1b2cd0..ab92f208dae 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c @@ -827,7 +827,8 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) /* freeze if hotplugged or controller error */ if (unlikely(status & (NV_ADMA_STAT_HOTPLUG | NV_ADMA_STAT_HOTUNPLUG | - NV_ADMA_STAT_TIMEOUT))) { + NV_ADMA_STAT_TIMEOUT | + NV_ADMA_STAT_SERROR))) { struct ata_eh_info *ehi = &ap->eh_info; ata_ehi_clear_desc(ehi); @@ -841,6 +842,9 @@ static irqreturn_t nv_adma_interrupt(int irq, void *dev_instance) } else if (status & NV_ADMA_STAT_HOTUNPLUG) { ata_ehi_hotplugged(ehi); ata_ehi_push_desc(ehi, ": hot unplug"); + } else if (status & NV_ADMA_STAT_SERROR) { + /* let libata analyze SError and figure out the cause */ + ata_ehi_push_desc(ehi, ": SError"); } ata_port_freeze(ap); continue; diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index b2e2e695c92..cf9ed8c3930 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -119,9 +119,7 @@ static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg); static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); static irqreturn_t pdc_interrupt (int irq, void *dev_instance); -static void pdc_eng_timeout(struct ata_port *ap); static int pdc_port_start(struct ata_port *ap); -static void pdc_pata_phy_reset(struct ata_port *ap); static void pdc_qc_prep(struct ata_queued_cmd *qc); static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf); static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf); @@ -215,12 +213,12 @@ static const struct ata_port_operations pdc_pata_ops = { .dev_select = ata_std_dev_select, .check_atapi_dma = pdc_check_atapi_dma, - .phy_reset = pdc_pata_phy_reset, - .qc_prep = pdc_qc_prep, .qc_issue = pdc_qc_issue_prot, + .freeze = pdc_freeze, + .thaw = pdc_thaw, + .error_handler = pdc_error_handler, .data_xfer = ata_data_xfer, - .eng_timeout = pdc_eng_timeout, .irq_handler = pdc_interrupt, .irq_clear = pdc_irq_clear, .irq_on = ata_irq_on, @@ -253,7 +251,7 @@ static const struct ata_port_info pdc_port_info[] = { /* board_20619 */ { .sht = &pdc_ata_sht, - .flags = PDC_COMMON_FLAGS | ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS, + .flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ @@ -389,14 +387,6 @@ static void pdc_pata_cbl_detect(struct ata_port *ap) ap->cbl = ATA_CBL_PATA80; } -static void pdc_pata_phy_reset(struct ata_port *ap) -{ - pdc_pata_cbl_detect(ap); - pdc_reset_port(ap); - ata_port_probe(ap); - ata_bus_reset(ap); -} - static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) { if (sc_reg > SCR_CONTROL || ap->cbl != ATA_CBL_SATA) @@ -564,6 +554,13 @@ static void pdc_thaw(struct ata_port *ap) readl(mmio + PDC_CTLSTAT); /* flush */ } +static int pdc_pre_reset(struct ata_port *ap) +{ + if (!sata_scr_valid(ap)) + pdc_pata_cbl_detect(ap); + return ata_std_prereset(ap); +} + static void pdc_error_handler(struct ata_port *ap) { ata_reset_fn_t hardreset; @@ -576,7 +573,7 @@ static void pdc_error_handler(struct ata_port *ap) hardreset = sata_std_hardreset; /* perform recovery */ - ata_do_eh(ap, ata_std_prereset, ata_std_softreset, hardreset, + ata_do_eh(ap, pdc_pre_reset, ata_std_softreset, hardreset, ata_std_postreset); } @@ -592,43 +589,6 @@ static void pdc_post_internal_cmd(struct ata_queued_cmd *qc) pdc_reset_port(ap); } -static void pdc_eng_timeout(struct ata_port *ap) -{ - struct ata_host *host = ap->host; - u8 drv_stat; - struct ata_queued_cmd *qc; - unsigned long flags; - - DPRINTK("ENTER\n"); - - spin_lock_irqsave(&host->lock, flags); - - qc = ata_qc_from_tag(ap, ap->active_tag); - - switch (qc->tf.protocol) { - case ATA_PROT_DMA: - case ATA_PROT_NODATA: - ata_port_printk(ap, KERN_ERR, "command timeout\n"); - drv_stat = ata_wait_idle(ap); - qc->err_mask |= __ac_err_mask(drv_stat); - break; - - default: - drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); - - ata_port_printk(ap, KERN_ERR, - "unknown timeout, cmd 0x%x stat 0x%x\n", - qc->tf.command, drv_stat); - - qc->err_mask |= ac_err_mask(drv_stat); - break; - } - - spin_unlock_irqrestore(&host->lock, flags); - ata_eh_qc_complete(qc); - DPRINTK("EXIT\n"); -} - static inline unsigned int pdc_host_intr( struct ata_port *ap, struct ata_queued_cmd *qc) { diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c index 3d9daf23111..2fd037bde09 100644 --- a/drivers/ata/sata_vsc.c +++ b/drivers/ata/sata_vsc.c @@ -346,6 +346,7 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d struct ata_probe_ent *probe_ent; void __iomem *mmio_base; int rc; + u8 cls; if (!printed_version++) dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); @@ -383,9 +384,12 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d INIT_LIST_HEAD(&probe_ent->node); /* - * Due to a bug in the chip, the default cache line size can't be used + * Due to a bug in the chip, the default cache line size can't be + * used (unless the default is non-zero). */ - pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x80); + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cls); + if (cls == 0x00) + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x80); if (pci_enable_msi(pdev) == 0) pci_intx(pdev, 0); diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile index 3e581603d0a..a0d04a23dac 100644 --- a/drivers/char/agp/Makefile +++ b/drivers/char/agp/Makefile @@ -1,6 +1,7 @@ agpgart-y := backend.o frontend.o generic.o isoch.o obj-$(CONFIG_AGP) += agpgart.o +obj-$(CONFIG_COMPAT) += compat_ioctl.o obj-$(CONFIG_AGP_ALI) += ali-agp.o obj-$(CONFIG_AGP_ATI) += ati-agp.o obj-$(CONFIG_AGP_AMD) += amd-k7-agp.o diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 1d59e2a5b9a..9bd68d9f0f5 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -114,6 +114,7 @@ struct agp_bridge_driver { void (*free_by_type)(struct agp_memory *); void *(*agp_alloc_page)(struct agp_bridge_data *); void (*agp_destroy_page)(void *); + int (*agp_type_to_mask_type) (struct agp_bridge_data *, int); }; struct agp_bridge_data { @@ -218,6 +219,7 @@ struct agp_bridge_data { #define I810_PTE_MAIN_UNCACHED 0x00000000 #define I810_PTE_LOCAL 0x00000002 #define I810_PTE_VALID 0x00000001 +#define I830_PTE_SYSTEM_CACHED 0x00000006 #define I810_SMRAM_MISCC 0x70 #define I810_GFX_MEM_WIN_SIZE 0x00010000 #define I810_GFX_MEM_WIN_32M 0x00010000 @@ -270,8 +272,16 @@ void global_cache_flush(void); void get_agp_version(struct agp_bridge_data *bridge); unsigned long agp_generic_mask_memory(struct agp_bridge_data *bridge, unsigned long addr, int type); +int agp_generic_type_to_mask_type(struct agp_bridge_data *bridge, + int type); struct agp_bridge_data *agp_generic_find_bridge(struct pci_dev *pdev); +/* generic functions for user-populated AGP memory types */ +struct agp_memory *agp_generic_alloc_user(size_t page_count, int type); +void agp_alloc_page_array(size_t size, struct agp_memory *mem); +void agp_free_page_array(struct agp_memory *mem); + + /* generic routines for agp>=3 */ int agp3_generic_fetch_size(void); void agp3_generic_tlbflush(struct agp_memory *mem); @@ -288,6 +298,8 @@ extern struct aper_size_info_16 agp3_generic_sizes[]; extern int agp_off; extern int agp_try_unsupported_boot; +long compat_agp_ioctl(struct file *file, unsigned int cmd, unsigned long arg); + /* Chipset independant registers (from AGP Spec) */ #define AGP_APBASE 0x10 diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c index 5a31ec7c62f..98177a93076 100644 --- a/drivers/char/agp/ali-agp.c +++ b/drivers/char/agp/ali-agp.c @@ -214,6 +214,7 @@ static struct agp_bridge_driver ali_generic_bridge = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = ali_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_bridge_driver ali_m1541_bridge = { @@ -237,6 +238,7 @@ static struct agp_bridge_driver ali_m1541_bridge = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = m1541_alloc_page, .agp_destroy_page = m1541_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; diff --git a/drivers/char/agp/alpha-agp.c b/drivers/char/agp/alpha-agp.c index b4e00a343da..b0acf41c0db 100644 --- a/drivers/char/agp/alpha-agp.c +++ b/drivers/char/agp/alpha-agp.c @@ -91,6 +91,9 @@ static int alpha_core_agp_insert_memory(struct agp_memory *mem, off_t pg_start, int num_entries, status; void *temp; + if (type >= AGP_USER_TYPES || mem->type >= AGP_USER_TYPES) + return -EINVAL; + temp = agp_bridge->current_size; num_entries = A_SIZE_FIX(temp)->num_entries; if ((pg_start + mem->page_count) > num_entries) @@ -142,6 +145,7 @@ struct agp_bridge_driver alpha_core_agp_driver = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; struct agp_bridge_data *alpha_bridge; diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index c85c8cadb6d..3d8d448bf39 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c @@ -381,6 +381,7 @@ static struct agp_bridge_driver amd_irongate_driver = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_device_ids amd_agp_device_ids[] __devinitdata = diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 93d2209fee4..636d984ed4a 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -62,12 +62,18 @@ static int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type) { int i, j, num_entries; long long tmp; + int mask_type; + struct agp_bridge_data *bridge = mem->bridge; u32 pte; num_entries = agp_num_entries(); - if (type != 0 || mem->type != 0) + if (type != mem->type) return -EINVAL; + mask_type = bridge->driver->agp_type_to_mask_type(bridge, type); + if (mask_type != 0) + return -EINVAL; + /* Make sure we can fit the range in the gatt table. */ /* FIXME: could wrap */ @@ -90,7 +96,7 @@ static int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type) for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { tmp = agp_bridge->driver->mask_memory(agp_bridge, - mem->memory[i], mem->type); + mem->memory[i], mask_type); BUG_ON(tmp & 0xffffff0000000ffcULL); pte = (tmp & 0x000000ff00000000ULL) >> 28; @@ -247,6 +253,7 @@ static struct agp_bridge_driver amd_8151_driver = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; /* Some basic sanity checks for the aperture. */ diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index 9987dc2e0c3..77c9ad68fba 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -431,6 +431,7 @@ static struct agp_bridge_driver ati_generic_bridge = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c index d59e037ddd1..ebdd6dd66ed 100644 --- a/drivers/char/agp/backend.c +++ b/drivers/char/agp/backend.c @@ -43,7 +43,7 @@ * fix some real stupidity. It's only by chance we can bump * past 0.99 at all due to some boolean logic error. */ #define AGPGART_VERSION_MAJOR 0 -#define AGPGART_VERSION_MINOR 101 +#define AGPGART_VERSION_MINOR 102 static const struct agp_version agp_current_version = { .major = AGPGART_VERSION_MAJOR, diff --git a/drivers/char/agp/compat_ioctl.c b/drivers/char/agp/compat_ioctl.c new file mode 100644 index 00000000000..fcb4b1bf0d4 --- /dev/null +++ b/drivers/char/agp/compat_ioctl.c @@ -0,0 +1,282 @@ +/* + * AGPGART driver frontend compatibility ioctls + * Copyright (C) 2004 Silicon Graphics, Inc. + * Copyright (C) 2002-2003 Dave Jones + * Copyright (C) 1999 Jeff Hartmann + * Copyright (C) 1999 Precision Insight, Inc. + * Copyright (C) 1999 Xi Graphics, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/agpgart.h> +#include <asm/uaccess.h> +#include "agp.h" +#include "compat_ioctl.h" + +static int compat_agpioc_info_wrap(struct agp_file_private *priv, void __user *arg) +{ + struct agp_info32 userinfo; + struct agp_kern_info kerninfo; + + agp_copy_info(agp_bridge, &kerninfo); + + userinfo.version.major = kerninfo.version.major; + userinfo.version.minor = kerninfo.version.minor; + userinfo.bridge_id = kerninfo.device->vendor | + (kerninfo.device->device << 16); + userinfo.agp_mode = kerninfo.mode; + userinfo.aper_base = (compat_long_t)kerninfo.aper_base; + userinfo.aper_size = kerninfo.aper_size; + userinfo.pg_total = userinfo.pg_system = kerninfo.max_memory; + userinfo.pg_used = kerninfo.current_memory; + + if (copy_to_user(arg, &userinfo, sizeof(userinfo))) + return -EFAULT; + + return 0; +} + +static int compat_agpioc_reserve_wrap(struct agp_file_private *priv, void __user *arg) +{ + struct agp_region32 ureserve; + struct agp_region kreserve; + struct agp_client *client; + struct agp_file_private *client_priv; + + DBG(""); + if (copy_from_user(&ureserve, arg, sizeof(ureserve))) + return -EFAULT; + + if ((unsigned) ureserve.seg_count >= ~0U/sizeof(struct agp_segment32)) + return -EFAULT; + + kreserve.pid = ureserve.pid; + kreserve.seg_count = ureserve.seg_count; + + client = agp_find_client_by_pid(kreserve.pid); + + if (kreserve.seg_count == 0) { + /* remove a client */ + client_priv = agp_find_private(kreserve.pid); + + if (client_priv != NULL) { + set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags); + set_bit(AGP_FF_IS_VALID, &client_priv->access_flags); + } + if (client == NULL) { + /* client is already removed */ + return 0; + } + return agp_remove_client(kreserve.pid); + } else { + struct agp_segment32 *usegment; + struct agp_segment *ksegment; + int seg; + + if (ureserve.seg_count >= 16384) + return -EINVAL; + + usegment = kmalloc(sizeof(*usegment) * ureserve.seg_count, GFP_KERNEL); + if (!usegment) + return -ENOMEM; + + ksegment = kmalloc(sizeof(*ksegment) * kreserve.seg_count, GFP_KERNEL); + if (!ksegment) { + kfree(usegment); + return -ENOMEM; + } + + if (copy_from_user(usegment, (void __user *) ureserve.seg_list, + sizeof(*usegment) * ureserve.seg_count)) { + kfree(usegment); + kfree(ksegment); + return -EFAULT; + } + + for (seg = 0; seg < ureserve.seg_count; seg++) { + ksegment[seg].pg_start = usegment[seg].pg_start; + ksegment[seg].pg_count = usegment[seg].pg_count; + ksegment[seg].prot = usegment[seg].prot; + } + + kfree(usegment); + kreserve.seg_list = ksegment; + + if (client == NULL) { + /* Create the client and add the segment */ + client = agp_create_client(kreserve.pid); + + if (client == NULL) { + kfree(ksegment); + return -ENOMEM; + } + client_priv = agp_find_private(kreserve.pid); + + if (client_priv != NULL) { + set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags); + set_bit(AGP_FF_IS_VALID, &client_priv->access_flags); + } + } + return agp_create_segment(client, &kreserve); + } + /* Will never really happen */ + return -EINVAL; +} + +static int compat_agpioc_allocate_wrap(struct agp_file_private *priv, void __user *arg) +{ + struct agp_memory *memory; + struct agp_allocate32 alloc; + + DBG(""); + if (copy_from_user(&alloc, arg, sizeof(alloc))) + return -EFAULT; + + memory = agp_allocate_memory_wrap(alloc.pg_count, alloc.type); + + if (memory == NULL) + return -ENOMEM; + + alloc.key = memory->key; + alloc.physical = memory->physical; + + if (copy_to_user(arg, &alloc, sizeof(alloc))) { + agp_free_memory_wrap(memory); + return -EFAULT; + } + return 0; +} + +static int compat_agpioc_bind_wrap(struct agp_file_private *priv, void __user *arg) +{ + struct agp_bind32 bind_info; + struct agp_memory *memory; + + DBG(""); + if (copy_from_user(&bind_info, arg, sizeof(bind_info))) + return -EFAULT; + + memory = agp_find_mem_by_key(bind_info.key); + + if (memory == NULL) + return -EINVAL; + + return agp_bind_memory(memory, bind_info.pg_start); +} + +static int compat_agpioc_unbind_wrap(struct agp_file_private *priv, void __user *arg) +{ + struct agp_memory *memory; + struct agp_unbind32 unbind; + + DBG(""); + if (copy_from_user(&unbind, arg, sizeof(unbind))) + return -EFAULT; + + memory = agp_find_mem_by_key(unbind.key); + + if (memory == NULL) + return -EINVAL; + + return agp_unbind_memory(memory); +} + +long compat_agp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct agp_file_private *curr_priv = file->private_data; + int ret_val = -ENOTTY; + + mutex_lock(&(agp_fe.agp_mutex)); + + if ((agp_fe.current_controller == NULL) && + (cmd != AGPIOC_ACQUIRE32)) { + ret_val = -EINVAL; + goto ioctl_out; + } + if ((agp_fe.backend_acquired != TRUE) && + (cmd != AGPIOC_ACQUIRE32)) { + ret_val = -EBUSY; + goto ioctl_out; + } + if (cmd != AGPIOC_ACQUIRE32) { + if (!(test_bit(AGP_FF_IS_CONTROLLER, &curr_priv->access_flags))) { + ret_val = -EPERM; + goto ioctl_out; + } + /* Use the original pid of the controller, + * in case it's threaded */ + + if (agp_fe.current_controller->pid != curr_priv->my_pid) { + ret_val = -EBUSY; + goto ioctl_out; + } + } + + switch (cmd) { + case AGPIOC_INFO32: + ret_val = compat_agpioc_info_wrap(curr_priv, (void __user *) arg); + break; + + case AGPIOC_ACQUIRE32: + ret_val = agpioc_acquire_wrap(curr_priv); + break; + + case AGPIOC_RELEASE32: + ret_val = agpioc_release_wrap(curr_priv); + break; + + case AGPIOC_SETUP32: + ret_val = agpioc_setup_wrap(curr_priv, (void __user *) arg); + break; + + case AGPIOC_RESERVE32: + ret_val = compat_agpioc_reserve_wrap(curr_priv, (void __user *) arg); + break; + + case AGPIOC_PROTECT32: + ret_val = agpioc_protect_wrap(curr_priv); + break; + + case AGPIOC_ALLOCATE32: + ret_val = compat_agpioc_allocate_wrap(curr_priv, (void __user *) arg); + break; + + case AGPIOC_DEALLOCATE32: + ret_val = agpioc_deallocate_wrap(curr_priv, (int) arg); + break; + + case AGPIOC_BIND32: + ret_val = compat_agpioc_bind_wrap(curr_priv, (void __user *) arg); + break; + + case AGPIOC_UNBIND32: + ret_val = compat_agpioc_unbind_wrap(curr_priv, (void __user *) arg); + break; + } + +ioctl_out: + DBG("ioctl returns %d\n", ret_val); + mutex_unlock(&(agp_fe.agp_mutex)); + return ret_val; +} + diff --git a/drivers/char/agp/compat_ioctl.h b/drivers/char/agp/compat_ioctl.h new file mode 100644 index 00000000000..71939d63723 --- /dev/null +++ b/drivers/char/agp/compat_ioctl.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 1999 Jeff Hartmann + * Copyright (C) 1999 Precision Insight, Inc. + * Copyright (C) 1999 Xi Graphics, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef _AGP_COMPAT_IOCTL_H +#define _AGP_COMPAT_IOCTL_H + +#include <linux/compat.h> +#include <linux/agpgart.h> + +#define AGPIOC_INFO32 _IOR (AGPIOC_BASE, 0, compat_uptr_t) +#define AGPIOC_ACQUIRE32 _IO (AGPIOC_BASE, 1) +#define AGPIOC_RELEASE32 _IO (AGPIOC_BASE, 2) +#define AGPIOC_SETUP32 _IOW (AGPIOC_BASE, 3, compat_uptr_t) +#define AGPIOC_RESERVE32 _IOW (AGPIOC_BASE, 4, compat_uptr_t) +#define AGPIOC_PROTECT32 _IOW (AGPIOC_BASE, 5, compat_uptr_t) +#define AGPIOC_ALLOCATE32 _IOWR(AGPIOC_BASE, 6, compat_uptr_t) +#define AGPIOC_DEALLOCATE32 _IOW (AGPIOC_BASE, 7, compat_int_t) +#define AGPIOC_BIND32 _IOW (AGPIOC_BASE, 8, compat_uptr_t) +#define AGPIOC_UNBIND32 _IOW (AGPIOC_BASE, 9, compat_uptr_t) + +struct agp_info32 { + struct agp_version version; /* version of the driver */ + u32 bridge_id; /* bridge vendor/device */ + u32 agp_mode; /* mode info of bridge */ + compat_long_t aper_base; /* base of aperture */ + compat_size_t aper_size; /* size of aperture */ + compat_size_t pg_total; /* max pages (swap + system) */ + compat_size_t pg_system; /* max pages (system) */ + compat_size_t pg_used; /* current pages used */ +}; + +/* + * The "prot" down below needs still a "sleep" flag somehow ... + */ +struct agp_segment32 { + compat_off_t pg_start; /* starting page to populate */ + compat_size_t pg_count; /* number of pages */ + compat_int_t prot; /* prot flags for mmap */ +}; + +struct agp_region32 { + compat_pid_t pid; /* pid of process */ + compat_size_t seg_count; /* number of segments */ + struct agp_segment32 *seg_list; +}; + +struct agp_allocate32 { + compat_int_t key; /* tag of allocation */ + compat_size_t pg_count; /* number of pages */ + u32 type; /* 0 == normal, other devspec */ + u32 physical; /* device specific (some devices + * need a phys address of the + * actual page behind the gatt + * table) */ +}; + +struct agp_bind32 { + compat_int_t key; /* tag of allocation */ + compat_off_t pg_start; /* starting page to populate */ +}; + +struct agp_unbind32 { + compat_int_t key; /* tag of allocation */ + u32 priority; /* priority for paging out */ +}; + +extern struct agp_front_data agp_fe; + +int agpioc_acquire_wrap(struct agp_file_private *priv); +int agpioc_release_wrap(struct agp_file_private *priv); +int agpioc_protect_wrap(struct agp_file_private *priv); +int agpioc_setup_wrap(struct agp_file_private *priv, void __user *arg); +int agpioc_deallocate_wrap(struct agp_file_private *priv, int arg); +struct agp_file_private *agp_find_private(pid_t pid); +struct agp_client *agp_create_client(pid_t id); +int agp_remove_client(pid_t id); +int agp_create_segment(struct agp_client *client, struct agp_region *region); +void agp_free_memory_wrap(struct agp_memory *memory); +struct agp_memory *agp_allocate_memory_wrap(size_t pg_count, u32 type); +struct agp_memory *agp_find_mem_by_key(int key); +struct agp_client *agp_find_client_by_pid(pid_t id); + +#endif /* _AGP_COMPAT_H */ diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c index 30f730ff81c..658cb1a72d2 100644 --- a/drivers/char/agp/efficeon-agp.c +++ b/drivers/char/agp/efficeon-agp.c @@ -335,6 +335,7 @@ static struct agp_bridge_driver efficeon_driver = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static int __devinit agp_efficeon_probe(struct pci_dev *pdev, diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c index 0f2ed2aa2d8..679d7f97243 100644 --- a/drivers/char/agp/frontend.c +++ b/drivers/char/agp/frontend.c @@ -41,9 +41,9 @@ #include <asm/pgtable.h> #include "agp.h" -static struct agp_front_data agp_fe; +struct agp_front_data agp_fe; -static struct agp_memory *agp_find_mem_by_key(int key) +struct agp_memory *agp_find_mem_by_key(int key) { struct agp_memory *curr; @@ -159,7 +159,7 @@ static pgprot_t agp_convert_mmap_flags(int prot) return vm_get_page_prot(prot_bits); } -static int agp_create_segment(struct agp_client *client, struct agp_region *region) +int agp_create_segment(struct agp_client *client, struct agp_region *region) { struct agp_segment_priv **ret_seg; struct agp_segment_priv *seg; @@ -211,7 +211,7 @@ static void agp_insert_into_pool(struct agp_memory * temp) /* File private list routines */ -static struct agp_file_private *agp_find_private(pid_t pid) +struct agp_file_private *agp_find_private(pid_t pid) { struct agp_file_private *curr; @@ -266,13 +266,13 @@ static void agp_remove_file_private(struct agp_file_private * priv) * Wrappers for agp_free_memory & agp_allocate_memory * These make sure that internal lists are kept updated. */ -static void agp_free_memory_wrap(struct agp_memory *memory) +void agp_free_memory_wrap(struct agp_memory *memory) { agp_remove_from_pool(memory); agp_free_memory(memory); } -static struct agp_memory *agp_allocate_memory_wrap(size_t pg_count, u32 type) +struct agp_memory *agp_allocate_memory_wrap(size_t pg_count, u32 type) { struct agp_memory *memory; @@ -484,7 +484,7 @@ static struct agp_controller *agp_find_controller_for_client(pid_t id) return NULL; } -static struct agp_client *agp_find_client_by_pid(pid_t id) +struct agp_client *agp_find_client_by_pid(pid_t id) { struct agp_client *temp; @@ -509,7 +509,7 @@ static void agp_insert_client(struct agp_client *client) agp_fe.current_controller->num_clients++; } -static struct agp_client *agp_create_client(pid_t id) +struct agp_client *agp_create_client(pid_t id) { struct agp_client *new_client; @@ -522,7 +522,7 @@ static struct agp_client *agp_create_client(pid_t id) return new_client; } -static int agp_remove_client(pid_t id) +int agp_remove_client(pid_t id) { struct agp_client *client; struct agp_client *prev_client; @@ -746,7 +746,7 @@ static int agpioc_info_wrap(struct agp_file_private *priv, void __user *arg) return 0; } -static int agpioc_acquire_wrap(struct agp_file_private *priv) +int agpioc_acquire_wrap(struct agp_file_private *priv) { struct agp_controller *controller; @@ -789,14 +789,14 @@ static int agpioc_acquire_wrap(struct agp_file_private *priv) return 0; } -static int agpioc_release_wrap(struct agp_file_private *priv) +int agpioc_release_wrap(struct agp_file_private *priv) { DBG(""); agp_controller_release_current(agp_fe.current_controller, priv); return 0; } -static int agpioc_setup_wrap(struct agp_file_private *priv, void __user *arg) +int agpioc_setup_wrap(struct agp_file_private *priv, void __user *arg) { struct agp_setup mode; @@ -876,7 +876,7 @@ static int agpioc_reserve_wrap(struct agp_file_private *priv, void __user *arg) return -EINVAL; } -static int agpioc_protect_wrap(struct agp_file_private *priv) +int agpioc_protect_wrap(struct agp_file_private *priv) { DBG(""); /* This function is not currently implemented */ @@ -892,6 +892,9 @@ static int agpioc_allocate_wrap(struct agp_file_private *priv, void __user *arg) if (copy_from_user(&alloc, arg, sizeof(struct agp_allocate))) return -EFAULT; + if (alloc.type >= AGP_USER_TYPES) + return -EINVAL; + memory = agp_allocate_memory_wrap(alloc.pg_count, alloc.type); if (memory == NULL) @@ -907,7 +910,7 @@ static int agpioc_allocate_wrap(struct agp_file_private *priv, void __user *arg) return 0; } -static int agpioc_deallocate_wrap(struct agp_file_private *priv, int arg) +int agpioc_deallocate_wrap(struct agp_file_private *priv, int arg) { struct agp_memory *memory; @@ -1043,6 +1046,9 @@ static const struct file_operations agp_fops = .read = agp_read, .write = agp_write, .ioctl = agp_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = compat_agp_ioctl, +#endif .mmap = agp_mmap, .open = agp_open, .release = agp_release, diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index 3491d6f84bc..7923337c3d2 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -101,6 +101,63 @@ static int agp_get_key(void) return -1; } +/* + * Use kmalloc if possible for the page list. Otherwise fall back to + * vmalloc. This speeds things up and also saves memory for small AGP + * regions. + */ + +void agp_alloc_page_array(size_t size, struct agp_memory *mem) +{ + mem->memory = NULL; + mem->vmalloc_flag = 0; + + if (size <= 2*PAGE_SIZE) + mem->memory = kmalloc(size, GFP_KERNEL | __GFP_NORETRY); + if (mem->memory == NULL) { + mem->memory = vmalloc(size); + mem->vmalloc_flag = 1; + } +} +EXPORT_SYMBOL(agp_alloc_page_array); + +void agp_free_page_array(struct agp_memory *mem) +{ + if (mem->vmalloc_flag) { + vfree(mem->memory); + } else { + kfree(mem->memory); + } +} +EXPORT_SYMBOL(agp_free_page_array); + + +static struct agp_memory *agp_create_user_memory(unsigned long num_agp_pages) +{ + struct agp_memory *new; + unsigned long alloc_size = num_agp_pages*sizeof(struct page *); + + new = kzalloc(sizeof(struct agp_memory), GFP_KERNEL); + if (new == NULL) + return NULL; + + new->key = agp_get_key(); + + if (new->key < 0) { + kfree(new); + return NULL; + } + + agp_alloc_page_array(alloc_size, new); + + if (new->memory == NULL) { + agp_free_key(new->key); + kfree(new); + return NULL; + } + new->num_scratch_pages = 0; + return new; +} struct agp_memory *agp_create_memory(int scratch_pages) { @@ -116,7 +173,8 @@ struct agp_memory *agp_create_memory(int scratch_pages) kfree(new); return NULL; } - new->memory = vmalloc(PAGE_SIZE * scratch_pages); + + agp_alloc_page_array(PAGE_SIZE * scratch_pages, new); if (new->memory == NULL) { agp_free_key(new->key); @@ -124,6 +182,7 @@ struct agp_memory *agp_create_memory(int scratch_pages) return NULL; } new->num_scratch_pages = scratch_pages; + new->type = AGP_NORMAL_MEMORY; return new; } EXPORT_SYMBOL(agp_create_memory); @@ -146,6 +205,11 @@ void agp_free_memory(struct agp_memory *curr) if (curr->is_bound == TRUE) agp_unbind_memory(curr); + if (curr->type >= AGP_USER_TYPES) { + agp_generic_free_by_type(curr); + return; + } + if (curr->type != 0) { curr->bridge->driver->free_by_type(curr); return; @@ -157,7 +221,7 @@ void agp_free_memory(struct agp_memory *curr) flush_agp_mappings(); } agp_free_key(curr->key); - vfree(curr->memory); + agp_free_page_array(curr); kfree(curr); } EXPORT_SYMBOL(agp_free_memory); @@ -188,6 +252,13 @@ struct agp_memory *agp_allocate_memory(struct agp_bridge_data *bridge, if ((atomic_read(&bridge->current_memory_agp) + page_count) > bridge->max_memory_agp) return NULL; + if (type >= AGP_USER_TYPES) { + new = agp_generic_alloc_user(page_count, type); + if (new) + new->bridge = bridge; + return new; + } + if (type != 0) { new = bridge->driver->alloc_by_type(page_count, type); if (new) @@ -960,6 +1031,7 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type) off_t j; void *temp; struct agp_bridge_data *bridge; + int mask_type; bridge = mem->bridge; if (!bridge) @@ -995,7 +1067,11 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type) num_entries -= agp_memory_reserved/PAGE_SIZE; if (num_entries < 0) num_entries = 0; - if (type != 0 || mem->type != 0) { + if (type != mem->type) + return -EINVAL; + + mask_type = bridge->driver->agp_type_to_mask_type(bridge, type); + if (mask_type != 0) { /* The generic routines know nothing of memory types */ return -EINVAL; } @@ -1018,7 +1094,8 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type) } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { - writel(bridge->driver->mask_memory(bridge, mem->memory[i], mem->type), bridge->gatt_table+j); + writel(bridge->driver->mask_memory(bridge, mem->memory[i], mask_type), + bridge->gatt_table+j); } readl(bridge->gatt_table+j-1); /* PCI Posting. */ @@ -1032,6 +1109,7 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type) { size_t i; struct agp_bridge_data *bridge; + int mask_type; bridge = mem->bridge; if (!bridge) @@ -1040,7 +1118,11 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type) if (mem->page_count == 0) return 0; - if (type != 0 || mem->type != 0) { + if (type != mem->type) + return -EINVAL; + + mask_type = bridge->driver->agp_type_to_mask_type(bridge, type); + if (mask_type != 0) { /* The generic routines know nothing of memory types */ return -EINVAL; } @@ -1056,22 +1138,40 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type) } EXPORT_SYMBOL(agp_generic_remove_memory); - struct agp_memory *agp_generic_alloc_by_type(size_t page_count, int type) { return NULL; } EXPORT_SYMBOL(agp_generic_alloc_by_type); - void agp_generic_free_by_type(struct agp_memory *curr) { - vfree(curr->memory); + agp_free_page_array(curr); agp_free_key(curr->key); kfree(curr); } EXPORT_SYMBOL(agp_generic_free_by_type); +struct agp_memory *agp_generic_alloc_user(size_t page_count, int type) +{ + struct agp_memory *new; + int i; + int pages; + + pages = (page_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE; + new = agp_create_user_memory(page_count); + if (new == NULL) + return NULL; + + for (i = 0; i < page_count; i++) + new->memory[i] = 0; + new->page_count = 0; + new->type = type; + new->num_scratch_pages = pages; + + return new; +} +EXPORT_SYMBOL(agp_generic_alloc_user); /* * Basic Page Allocation Routines - @@ -1165,6 +1265,15 @@ unsigned long agp_generic_mask_memory(struct agp_bridge_data *bridge, } EXPORT_SYMBOL(agp_generic_mask_memory); +int agp_generic_type_to_mask_type(struct agp_bridge_data *bridge, + int type) +{ + if (type >= AGP_USER_TYPES) + return 0; + return type; +} +EXPORT_SYMBOL(agp_generic_type_to_mask_type); + /* * These functions are implemented according to the AGPv3 spec, * which covers implementation details that had previously been diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c index 907fb66ec4a..847deabf7f9 100644 --- a/drivers/char/agp/hp-agp.c +++ b/drivers/char/agp/hp-agp.c @@ -438,6 +438,7 @@ struct agp_bridge_driver hp_zx1_driver = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, .cant_use_aperture = 1, }; diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c index 91769443d8f..3e7618653ab 100644 --- a/drivers/char/agp/i460-agp.c +++ b/drivers/char/agp/i460-agp.c @@ -293,6 +293,9 @@ static int i460_insert_memory_small_io_page (struct agp_memory *mem, pr_debug("i460_insert_memory_small_io_page(mem=%p, pg_start=%ld, type=%d, paddr0=0x%lx)\n", mem, pg_start, type, mem->memory[0]); + if (type >= AGP_USER_TYPES || mem->type >= AGP_USER_TYPES) + return -EINVAL; + io_pg_start = I460_IOPAGES_PER_KPAGE * pg_start; temp = agp_bridge->current_size; @@ -396,6 +399,9 @@ static int i460_insert_memory_large_io_page (struct agp_memory *mem, struct lp_desc *start, *end, *lp; void *temp; + if (type >= AGP_USER_TYPES || mem->type >= AGP_USER_TYPES) + return -EINVAL; + temp = agp_bridge->current_size; num_entries = A_SIZE_8(temp)->num_entries; @@ -572,6 +578,7 @@ struct agp_bridge_driver intel_i460_driver = { #endif .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_free_by_type, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, .cant_use_aperture = 1, }; diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index a3011de51f7..06b0bb6d982 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -5,6 +5,7 @@ #include <linux/module.h> #include <linux/pci.h> #include <linux/init.h> +#include <linux/kernel.h> #include <linux/pagemap.h> #include <linux/agp_backend.h> #include "agp.h" @@ -24,6 +25,9 @@ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB) +extern int agp_memory_reserved; + + /* Intel 815 register */ #define INTEL_815_APCONT 0x51 #define INTEL_815_ATTBASE_MASK ~0x1FFFFFFF @@ -68,12 +72,15 @@ static struct aper_size_info_fixed intel_i810_sizes[] = #define AGP_DCACHE_MEMORY 1 #define AGP_PHYS_MEMORY 2 +#define INTEL_AGP_CACHED_MEMORY 3 static struct gatt_mask intel_i810_masks[] = { {.mask = I810_PTE_VALID, .type = 0}, {.mask = (I810_PTE_VALID | I810_PTE_LOCAL), .type = AGP_DCACHE_MEMORY}, - {.mask = I810_PTE_VALID, .type = 0} + {.mask = I810_PTE_VALID, .type = 0}, + {.mask = I810_PTE_VALID | I830_PTE_SYSTEM_CACHED, + .type = INTEL_AGP_CACHED_MEMORY} }; static struct _intel_i810_private { @@ -117,13 +124,15 @@ static int intel_i810_configure(void) current_size = A_SIZE_FIX(agp_bridge->current_size); - pci_read_config_dword(intel_i810_private.i810_dev, I810_MMADDR, &temp); - temp &= 0xfff80000; - - intel_i810_private.registers = ioremap(temp, 128 * 4096); if (!intel_i810_private.registers) { - printk(KERN_ERR PFX "Unable to remap memory.\n"); - return -ENOMEM; + pci_read_config_dword(intel_i810_private.i810_dev, I810_MMADDR, &temp); + temp &= 0xfff80000; + + intel_i810_private.registers = ioremap(temp, 128 * 4096); + if (!intel_i810_private.registers) { + printk(KERN_ERR PFX "Unable to remap memory.\n"); + return -ENOMEM; + } } if ((readl(intel_i810_private.registers+I810_DRAM_CTL) @@ -201,62 +210,79 @@ static void i8xx_destroy_pages(void *addr) atomic_dec(&agp_bridge->current_memory_agp); } +static int intel_i830_type_to_mask_type(struct agp_bridge_data *bridge, + int type) +{ + if (type < AGP_USER_TYPES) + return type; + else if (type == AGP_USER_CACHED_MEMORY) + return INTEL_AGP_CACHED_MEMORY; + else + return 0; +} + static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start, int type) { int i, j, num_entries; void *temp; + int ret = -EINVAL; + int mask_type; if (mem->page_count == 0) - return 0; + goto out; temp = agp_bridge->current_size; num_entries = A_SIZE_FIX(temp)->num_entries; if ((pg_start + mem->page_count) > num_entries) - return -EINVAL; + goto out_err; - for (j = pg_start; j < (pg_start + mem->page_count); j++) { - if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) - return -EBUSY; - } - if (type != 0 || mem->type != 0) { - if ((type == AGP_DCACHE_MEMORY) && (mem->type == AGP_DCACHE_MEMORY)) { - /* special insert */ - if (!mem->is_flushed) { - global_cache_flush(); - mem->is_flushed = TRUE; - } - - for (i = pg_start; i < (pg_start + mem->page_count); i++) { - writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID, intel_i810_private.registers+I810_PTE_BASE+(i*4)); - } - readl(intel_i810_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI Posting. */ - - agp_bridge->driver->tlb_flush(mem); - return 0; + for (j = pg_start; j < (pg_start + mem->page_count); j++) { + if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) { + ret = -EBUSY; + goto out_err; } - if ((type == AGP_PHYS_MEMORY) && (mem->type == AGP_PHYS_MEMORY)) - goto insert; - return -EINVAL; } -insert: - if (!mem->is_flushed) { - global_cache_flush(); - mem->is_flushed = TRUE; - } + if (type != mem->type) + goto out_err; - for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { - writel(agp_bridge->driver->mask_memory(agp_bridge, - mem->memory[i], mem->type), - intel_i810_private.registers+I810_PTE_BASE+(j*4)); + mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type); + + switch (mask_type) { + case AGP_DCACHE_MEMORY: + if (!mem->is_flushed) + global_cache_flush(); + for (i = pg_start; i < (pg_start + mem->page_count); i++) { + writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID, + intel_i810_private.registers+I810_PTE_BASE+(i*4)); + } + readl(intel_i810_private.registers+I810_PTE_BASE+((i-1)*4)); + break; + case AGP_PHYS_MEMORY: + case AGP_NORMAL_MEMORY: + if (!mem->is_flushed) + global_cache_flush(); + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { + writel(agp_bridge->driver->mask_memory(agp_bridge, + mem->memory[i], + mask_type), + intel_i810_private.registers+I810_PTE_BASE+(j*4)); + } + readl(intel_i810_private.registers+I810_PTE_BASE+((j-1)*4)); + break; + default: + goto out_err; } - readl(intel_i810_private.registers+I810_PTE_BASE+((j-1)*4)); /* PCI Posting. */ agp_bridge->driver->tlb_flush(mem); - return 0; +out: + ret = 0; +out_err: + mem->is_flushed = 1; + return ret; } static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start, @@ -337,12 +363,11 @@ static struct agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type) new->type = AGP_DCACHE_MEMORY; new->page_count = pg_count; new->num_scratch_pages = 0; - vfree(new->memory); + agp_free_page_array(new); return new; } if (type == AGP_PHYS_MEMORY) return alloc_agpphysmem_i8xx(pg_count, type); - return NULL; } @@ -357,7 +382,7 @@ static void intel_i810_free_by_type(struct agp_memory *curr) gart_to_virt(curr->memory[0])); global_flush_tlb(); } - vfree(curr->memory); + agp_free_page_array(curr); } kfree(curr); } @@ -619,9 +644,11 @@ static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, int { int i,j,num_entries; void *temp; + int ret = -EINVAL; + int mask_type; if (mem->page_count == 0) - return 0; + goto out; temp = agp_bridge->current_size; num_entries = A_SIZE_FIX(temp)->num_entries; @@ -631,34 +658,41 @@ static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, int pg_start,intel_i830_private.gtt_entries); printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n"); - return -EINVAL; + goto out_err; } if ((pg_start + mem->page_count) > num_entries) - return -EINVAL; + goto out_err; /* The i830 can't check the GTT for entries since its read only, * depend on the caller to make the correct offset decisions. */ - if ((type != 0 && type != AGP_PHYS_MEMORY) || - (mem->type != 0 && mem->type != AGP_PHYS_MEMORY)) - return -EINVAL; + if (type != mem->type) + goto out_err; + + mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type); - if (!mem->is_flushed) { + if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY && + mask_type != INTEL_AGP_CACHED_MEMORY) + goto out_err; + + if (!mem->is_flushed) global_cache_flush(); - mem->is_flushed = TRUE; - } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { writel(agp_bridge->driver->mask_memory(agp_bridge, - mem->memory[i], mem->type), - intel_i830_private.registers+I810_PTE_BASE+(j*4)); + mem->memory[i], mask_type), + intel_i830_private.registers+I810_PTE_BASE+(j*4)); } readl(intel_i830_private.registers+I810_PTE_BASE+((j-1)*4)); - agp_bridge->driver->tlb_flush(mem); - return 0; + +out: + ret = 0; +out_err: + mem->is_flushed = 1; + return ret; } static int intel_i830_remove_entries(struct agp_memory *mem,off_t pg_start, @@ -687,7 +721,6 @@ static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count,int type) { if (type == AGP_PHYS_MEMORY) return alloc_agpphysmem_i8xx(pg_count, type); - /* always return NULL for other allocation types for now */ return NULL; } @@ -734,9 +767,11 @@ static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start, { int i,j,num_entries; void *temp; + int ret = -EINVAL; + int mask_type; if (mem->page_count == 0) - return 0; + goto out; temp = agp_bridge->current_size; num_entries = A_SIZE_FIX(temp)->num_entries; @@ -746,33 +781,41 @@ static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start, pg_start,intel_i830_private.gtt_entries); printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n"); - return -EINVAL; + goto out_err; } if ((pg_start + mem->page_count) > num_entries) - return -EINVAL; + goto out_err; - /* The i830 can't check the GTT for entries since its read only, + /* The i915 can't check the GTT for entries since its read only, * depend on the caller to make the correct offset decisions. */ - if ((type != 0 && type != AGP_PHYS_MEMORY) || - (mem->type != 0 && mem->type != AGP_PHYS_MEMORY)) - return -EINVAL; + if (type != mem->type) + goto out_err; + + mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type); - if (!mem->is_flushed) { + if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY && + mask_type != INTEL_AGP_CACHED_MEMORY) + goto out_err; + + if (!mem->is_flushed) global_cache_flush(); - mem->is_flushed = TRUE; - } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { writel(agp_bridge->driver->mask_memory(agp_bridge, - mem->memory[i], mem->type), intel_i830_private.gtt+j); + mem->memory[i], mask_type), intel_i830_private.gtt+j); } - readl(intel_i830_private.gtt+j-1); + readl(intel_i830_private.gtt+j-1); agp_bridge->driver->tlb_flush(mem); - return 0; + + out: + ret = 0; + out_err: + mem->is_flushed = 1; + return ret; } static int intel_i915_remove_entries(struct agp_memory *mem,off_t pg_start, @@ -803,7 +846,7 @@ static int intel_i915_remove_entries(struct agp_memory *mem,off_t pg_start, */ static int intel_i9xx_fetch_size(void) { - int num_sizes = sizeof(intel_i830_sizes) / sizeof(*intel_i830_sizes); + int num_sizes = ARRAY_SIZE(intel_i830_sizes); int aper_size; /* size in megabytes */ int i; @@ -1384,6 +1427,7 @@ static struct agp_bridge_driver intel_generic_driver = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_bridge_driver intel_810_driver = { @@ -1408,6 +1452,7 @@ static struct agp_bridge_driver intel_810_driver = { .free_by_type = intel_i810_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_bridge_driver intel_815_driver = { @@ -1431,6 +1476,7 @@ static struct agp_bridge_driver intel_815_driver = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_bridge_driver intel_830_driver = { @@ -1455,6 +1501,7 @@ static struct agp_bridge_driver intel_830_driver = { .free_by_type = intel_i810_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = intel_i830_type_to_mask_type, }; static struct agp_bridge_driver intel_820_driver = { @@ -1478,6 +1525,7 @@ static struct agp_bridge_driver intel_820_driver = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_bridge_driver intel_830mp_driver = { @@ -1501,6 +1549,7 @@ static struct agp_bridge_driver intel_830mp_driver = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_bridge_driver intel_840_driver = { @@ -1524,6 +1573,7 @@ static struct agp_bridge_driver intel_840_driver = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_bridge_driver intel_845_driver = { @@ -1547,6 +1597,7 @@ static struct agp_bridge_driver intel_845_driver = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_bridge_driver intel_850_driver = { @@ -1570,6 +1621,7 @@ static struct agp_bridge_driver intel_850_driver = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_bridge_driver intel_860_driver = { @@ -1593,6 +1645,7 @@ static struct agp_bridge_driver intel_860_driver = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_bridge_driver intel_915_driver = { @@ -1617,6 +1670,7 @@ static struct agp_bridge_driver intel_915_driver = { .free_by_type = intel_i810_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = intel_i830_type_to_mask_type, }; static struct agp_bridge_driver intel_i965_driver = { @@ -1641,6 +1695,7 @@ static struct agp_bridge_driver intel_i965_driver = { .free_by_type = intel_i810_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = intel_i830_type_to_mask_type, }; static struct agp_bridge_driver intel_7505_driver = { @@ -1664,6 +1719,7 @@ static struct agp_bridge_driver intel_7505_driver = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static int find_i810(u16 device) diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c index df7f37b2739..2563286b2fc 100644 --- a/drivers/char/agp/nvidia-agp.c +++ b/drivers/char/agp/nvidia-agp.c @@ -310,6 +310,7 @@ static struct agp_bridge_driver nvidia_driver = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static int __devinit agp_nvidia_probe(struct pci_dev *pdev, diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c index 17c50b0f83f..b7b4590673a 100644 --- a/drivers/char/agp/parisc-agp.c +++ b/drivers/char/agp/parisc-agp.c @@ -228,6 +228,7 @@ struct agp_bridge_driver parisc_agp_driver = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, .cant_use_aperture = 1, }; diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c index 902648db7ef..92d1dc45b9b 100644 --- a/drivers/char/agp/sgi-agp.c +++ b/drivers/char/agp/sgi-agp.c @@ -265,6 +265,7 @@ struct agp_bridge_driver sgi_tioca_driver = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = sgi_tioca_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, .cant_use_aperture = 1, .needs_scratch_page = 0, .num_aperture_sizes = 1, diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c index a00fd48a6f0..60342b70815 100644 --- a/drivers/char/agp/sis-agp.c +++ b/drivers/char/agp/sis-agp.c @@ -140,6 +140,7 @@ static struct agp_bridge_driver sis_driver = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_device_ids sis_agp_device_ids[] __devinitdata = diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c index 4f2d7d99902..9f5ae7714f8 100644 --- a/drivers/char/agp/sworks-agp.c +++ b/drivers/char/agp/sworks-agp.c @@ -444,6 +444,7 @@ static struct agp_bridge_driver sworks_driver = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static int __devinit agp_serverworks_probe(struct pci_dev *pdev, diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index dffc19382f7..6c45702e542 100644 --- a/drivers/char/agp/uninorth-agp.c +++ b/drivers/char/agp/uninorth-agp.c @@ -510,6 +510,7 @@ struct agp_bridge_driver uninorth_agp_driver = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, .cant_use_aperture = 1, }; @@ -534,6 +535,7 @@ struct agp_bridge_driver u3_agp_driver = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, .cant_use_aperture = 1, .needs_scratch_page = 1, }; diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c index 2ded7a280d7..2e7c04370cd 100644 --- a/drivers/char/agp/via-agp.c +++ b/drivers/char/agp/via-agp.c @@ -191,6 +191,7 @@ static struct agp_bridge_driver via_agp3_driver = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_bridge_driver via_driver = { @@ -214,6 +215,7 @@ static struct agp_bridge_driver via_driver = { .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; static struct agp_device_ids via_agp_device_ids[] __devinitdata = diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c index 1aa93a752a9..ae76a9ffe89 100644 --- a/drivers/char/hangcheck-timer.c +++ b/drivers/char/hangcheck-timer.c @@ -117,7 +117,7 @@ __setup("hcheck_reboot", hangcheck_parse_reboot); __setup("hcheck_dump_tasks", hangcheck_parse_dump_tasks); #endif /* not MODULE */ -#if defined(CONFIG_X86_64) || defined(CONFIG_S390) +#if defined(CONFIG_S390) # define HAVE_MONOTONIC # define TIMER_FREQ 1000000000ULL #elif defined(CONFIG_IA64) diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index be73c80d699..1d8c4ae6155 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -36,6 +36,7 @@ #include <linux/workqueue.h> #include <linux/kexec.h> #include <linux/irq.h> +#include <linux/hrtimer.h> #include <asm/ptrace.h> #include <asm/irq_regs.h> @@ -158,6 +159,17 @@ static struct sysrq_key_op sysrq_sync_op = { .enable_mask = SYSRQ_ENABLE_SYNC, }; +static void sysrq_handle_show_timers(int key, struct tty_struct *tty) +{ + sysrq_timer_list_show(); +} + +static struct sysrq_key_op sysrq_show_timers_op = { + .handler = sysrq_handle_show_timers, + .help_msg = "show-all-timers(Q)", + .action_msg = "Show Pending Timers", +}; + static void sysrq_handle_mountro(int key, struct tty_struct *tty) { emergency_remount(); @@ -335,7 +347,7 @@ static struct sysrq_key_op *sysrq_key_table[36] = { /* o: This will often be registered as 'Off' at init time */ NULL, /* o */ &sysrq_showregs_op, /* p */ - NULL, /* q */ + &sysrq_show_timers_op, /* q */ &sysrq_unraw_op, /* r */ &sysrq_sync_op, /* s */ &sysrq_showstate_op, /* t */ diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c index b6bcdbbf57b..ccaa6a39cb4 100644 --- a/drivers/clocksource/acpi_pm.c +++ b/drivers/clocksource/acpi_pm.c @@ -16,15 +16,13 @@ * This file is licensed under the GPL v2. */ +#include <linux/acpi_pmtmr.h> #include <linux/clocksource.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/pci.h> #include <asm/io.h> -/* Number of PMTMR ticks expected during calibration run */ -#define PMTMR_TICKS_PER_SEC 3579545 - /* * The I/O port the PMTMR resides at. * The location is detected during setup_arch(), @@ -32,15 +30,13 @@ */ u32 pmtmr_ioport __read_mostly; -#define ACPI_PM_MASK CLOCKSOURCE_MASK(24) /* limit it to 24 bits */ - static inline u32 read_pmtmr(void) { /* mask the output to 24 bits */ return inl(pmtmr_ioport) & ACPI_PM_MASK; } -static cycle_t acpi_pm_read_verified(void) +u32 acpi_pm_read_verified(void) { u32 v1 = 0, v2 = 0, v3 = 0; @@ -57,7 +53,12 @@ static cycle_t acpi_pm_read_verified(void) } while (unlikely((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2))); - return (cycle_t)v2; + return v2; +} + +static cycle_t acpi_pm_read_slow(void) +{ + return (cycle_t)acpi_pm_read_verified(); } static cycle_t acpi_pm_read(void) @@ -72,7 +73,8 @@ static struct clocksource clocksource_acpi_pm = { .mask = (cycle_t)ACPI_PM_MASK, .mult = 0, /*to be caluclated*/ .shift = 22, - .is_continuous = 1, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, + }; @@ -87,7 +89,7 @@ __setup("acpi_pm_good", acpi_pm_good_setup); static inline void acpi_pm_need_workaround(void) { - clocksource_acpi_pm.read = acpi_pm_read_verified; + clocksource_acpi_pm.read = acpi_pm_read_slow; clocksource_acpi_pm.rating = 110; } diff --git a/drivers/clocksource/cyclone.c b/drivers/clocksource/cyclone.c index bf4d3d50d1c..4f3925ceb36 100644 --- a/drivers/clocksource/cyclone.c +++ b/drivers/clocksource/cyclone.c @@ -31,7 +31,7 @@ static struct clocksource clocksource_cyclone = { .mask = CYCLONE_TIMER_MASK, .mult = 10, .shift = 0, - .is_continuous = 1, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; static int __init init_cyclone_clocksource(void) diff --git a/drivers/clocksource/scx200_hrt.c b/drivers/clocksource/scx200_hrt.c index 22915cc46ba..b92da677aa5 100644 --- a/drivers/clocksource/scx200_hrt.c +++ b/drivers/clocksource/scx200_hrt.c @@ -57,7 +57,7 @@ static struct clocksource cs_hrt = { .rating = 250, .read = read_hrt, .mask = CLOCKSOURCE_MASK(32), - .is_continuous = 1, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, /* mult, shift are set based on mhz27 flag */ }; diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 491779af8d5..d155e81b5c9 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -16,7 +16,7 @@ config CPU_FREQ if CPU_FREQ config CPU_FREQ_TABLE - def_tristate m + tristate config CPU_FREQ_DEBUG bool "Enable CPUfreq debugging" diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index a45cc89e387..f52facc570f 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -41,8 +41,67 @@ static struct cpufreq_driver *cpufreq_driver; static struct cpufreq_policy *cpufreq_cpu_data[NR_CPUS]; static DEFINE_SPINLOCK(cpufreq_driver_lock); +/* + * cpu_policy_rwsem is a per CPU reader-writer semaphore designed to cure + * all cpufreq/hotplug/workqueue/etc related lock issues. + * + * The rules for this semaphore: + * - Any routine that wants to read from the policy structure will + * do a down_read on this semaphore. + * - Any routine that will write to the policy structure and/or may take away + * the policy altogether (eg. CPU hotplug), will hold this lock in write + * mode before doing so. + * + * Additional rules: + * - All holders of the lock should check to make sure that the CPU they + * are concerned with are online after they get the lock. + * - Governor routines that can be called in cpufreq hotplug path should not + * take this sem as top level hotplug notifier handler takes this. + */ +static DEFINE_PER_CPU(int, policy_cpu); +static DEFINE_PER_CPU(struct rw_semaphore, cpu_policy_rwsem); + +#define lock_policy_rwsem(mode, cpu) \ +int lock_policy_rwsem_##mode \ +(int cpu) \ +{ \ + int policy_cpu = per_cpu(policy_cpu, cpu); \ + BUG_ON(policy_cpu == -1); \ + down_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu)); \ + if (unlikely(!cpu_online(cpu))) { \ + up_##mode(&per_cpu(cpu_policy_rwsem, policy_cpu)); \ + return -1; \ + } \ + \ + return 0; \ +} + +lock_policy_rwsem(read, cpu); +EXPORT_SYMBOL_GPL(lock_policy_rwsem_read); + +lock_policy_rwsem(write, cpu); +EXPORT_SYMBOL_GPL(lock_policy_rwsem_write); + +void unlock_policy_rwsem_read(int cpu) +{ + int policy_cpu = per_cpu(policy_cpu, cpu); + BUG_ON(policy_cpu == -1); + up_read(&per_cpu(cpu_policy_rwsem, policy_cpu)); +} +EXPORT_SYMBOL_GPL(unlock_policy_rwsem_read); + +void unlock_policy_rwsem_write(int cpu) +{ + int policy_cpu = per_cpu(policy_cpu, cpu); + BUG_ON(policy_cpu == -1); + up_write(&per_cpu(cpu_policy_rwsem, policy_cpu)); +} +EXPORT_SYMBOL_GPL(unlock_policy_rwsem_write); + + /* internal prototypes */ static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event); +static unsigned int __cpufreq_get(unsigned int cpu); static void handle_update(struct work_struct *work); /** @@ -415,12 +474,8 @@ static ssize_t store_##file_name \ if (ret != 1) \ return -EINVAL; \ \ - lock_cpu_hotplug(); \ - mutex_lock(&policy->lock); \ ret = __cpufreq_set_policy(policy, &new_policy); \ policy->user_policy.object = policy->object; \ - mutex_unlock(&policy->lock); \ - unlock_cpu_hotplug(); \ \ return ret ? ret : count; \ } @@ -434,7 +489,7 @@ store_one(scaling_max_freq,max); static ssize_t show_cpuinfo_cur_freq (struct cpufreq_policy * policy, char *buf) { - unsigned int cur_freq = cpufreq_get(policy->cpu); + unsigned int cur_freq = __cpufreq_get(policy->cpu); if (!cur_freq) return sprintf(buf, "<unknown>"); return sprintf(buf, "%u\n", cur_freq); @@ -479,18 +534,12 @@ static ssize_t store_scaling_governor (struct cpufreq_policy * policy, &new_policy.governor)) return -EINVAL; - lock_cpu_hotplug(); - /* Do not use cpufreq_set_policy here or the user_policy.max will be wrongly overridden */ - mutex_lock(&policy->lock); ret = __cpufreq_set_policy(policy, &new_policy); policy->user_policy.policy = policy->policy; policy->user_policy.governor = policy->governor; - mutex_unlock(&policy->lock); - - unlock_cpu_hotplug(); if (ret) return ret; @@ -595,11 +644,17 @@ static ssize_t show(struct kobject * kobj, struct attribute * attr ,char * buf) policy = cpufreq_cpu_get(policy->cpu); if (!policy) return -EINVAL; + + if (lock_policy_rwsem_read(policy->cpu) < 0) + return -EINVAL; + if (fattr->show) ret = fattr->show(policy, buf); else ret = -EIO; + unlock_policy_rwsem_read(policy->cpu); + cpufreq_cpu_put(policy); return ret; } @@ -613,11 +668,17 @@ static ssize_t store(struct kobject * kobj, struct attribute * attr, policy = cpufreq_cpu_get(policy->cpu); if (!policy) return -EINVAL; + + if (lock_policy_rwsem_write(policy->cpu) < 0) + return -EINVAL; + if (fattr->store) ret = fattr->store(policy, buf, count); else ret = -EIO; + unlock_policy_rwsem_write(policy->cpu); + cpufreq_cpu_put(policy); return ret; } @@ -691,8 +752,10 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) policy->cpu = cpu; policy->cpus = cpumask_of_cpu(cpu); - mutex_init(&policy->lock); - mutex_lock(&policy->lock); + /* Initially set CPU itself as the policy_cpu */ + per_cpu(policy_cpu, cpu) = cpu; + lock_policy_rwsem_write(cpu); + init_completion(&policy->kobj_unregister); INIT_WORK(&policy->update, handle_update); @@ -702,7 +765,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) ret = cpufreq_driver->init(policy); if (ret) { dprintk("initialization failed\n"); - mutex_unlock(&policy->lock); + unlock_policy_rwsem_write(cpu); goto err_out; } @@ -716,6 +779,14 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) */ managed_policy = cpufreq_cpu_get(j); if (unlikely(managed_policy)) { + + /* Set proper policy_cpu */ + unlock_policy_rwsem_write(cpu); + per_cpu(policy_cpu, cpu) = managed_policy->cpu; + + if (lock_policy_rwsem_write(cpu) < 0) + goto err_out_driver_exit; + spin_lock_irqsave(&cpufreq_driver_lock, flags); managed_policy->cpus = policy->cpus; cpufreq_cpu_data[cpu] = managed_policy; @@ -726,13 +797,13 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) &managed_policy->kobj, "cpufreq"); if (ret) { - mutex_unlock(&policy->lock); + unlock_policy_rwsem_write(cpu); goto err_out_driver_exit; } cpufreq_debug_enable_ratelimit(); - mutex_unlock(&policy->lock); ret = 0; + unlock_policy_rwsem_write(cpu); goto err_out_driver_exit; /* call driver->exit() */ } } @@ -746,7 +817,7 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) ret = kobject_register(&policy->kobj); if (ret) { - mutex_unlock(&policy->lock); + unlock_policy_rwsem_write(cpu); goto err_out_driver_exit; } /* set up files for this cpu device */ @@ -761,8 +832,10 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr); spin_lock_irqsave(&cpufreq_driver_lock, flags); - for_each_cpu_mask(j, policy->cpus) + for_each_cpu_mask(j, policy->cpus) { cpufreq_cpu_data[j] = policy; + per_cpu(policy_cpu, j) = policy->cpu; + } spin_unlock_irqrestore(&cpufreq_driver_lock, flags); /* symlink affected CPUs */ @@ -778,14 +851,14 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) ret = sysfs_create_link(&cpu_sys_dev->kobj, &policy->kobj, "cpufreq"); if (ret) { - mutex_unlock(&policy->lock); + unlock_policy_rwsem_write(cpu); goto err_out_unregister; } } policy->governor = NULL; /* to assure that the starting sequence is * run in cpufreq_set_policy */ - mutex_unlock(&policy->lock); + unlock_policy_rwsem_write(cpu); /* set default policy */ ret = cpufreq_set_policy(&new_policy); @@ -826,11 +899,13 @@ module_out: /** - * cpufreq_remove_dev - remove a CPU device + * __cpufreq_remove_dev - remove a CPU device * * Removes the cpufreq interface for a CPU device. + * Caller should already have policy_rwsem in write mode for this CPU. + * This routine frees the rwsem before returning. */ -static int cpufreq_remove_dev (struct sys_device * sys_dev) +static int __cpufreq_remove_dev (struct sys_device * sys_dev) { unsigned int cpu = sys_dev->id; unsigned long flags; @@ -849,6 +924,7 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev) if (!data) { spin_unlock_irqrestore(&cpufreq_driver_lock, flags); cpufreq_debug_enable_ratelimit(); + unlock_policy_rwsem_write(cpu); return -EINVAL; } cpufreq_cpu_data[cpu] = NULL; @@ -865,6 +941,7 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev) sysfs_remove_link(&sys_dev->kobj, "cpufreq"); cpufreq_cpu_put(data); cpufreq_debug_enable_ratelimit(); + unlock_policy_rwsem_write(cpu); return 0; } #endif @@ -873,6 +950,7 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev) if (!kobject_get(&data->kobj)) { spin_unlock_irqrestore(&cpufreq_driver_lock, flags); cpufreq_debug_enable_ratelimit(); + unlock_policy_rwsem_write(cpu); return -EFAULT; } @@ -906,10 +984,10 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev) spin_unlock_irqrestore(&cpufreq_driver_lock, flags); #endif - mutex_lock(&data->lock); if (cpufreq_driver->target) __cpufreq_governor(data, CPUFREQ_GOV_STOP); - mutex_unlock(&data->lock); + + unlock_policy_rwsem_write(cpu); kobject_unregister(&data->kobj); @@ -933,6 +1011,18 @@ static int cpufreq_remove_dev (struct sys_device * sys_dev) } +static int cpufreq_remove_dev (struct sys_device * sys_dev) +{ + unsigned int cpu = sys_dev->id; + int retval; + if (unlikely(lock_policy_rwsem_write(cpu))) + BUG(); + + retval = __cpufreq_remove_dev(sys_dev); + return retval; +} + + static void handle_update(struct work_struct *work) { struct cpufreq_policy *policy = @@ -980,9 +1070,12 @@ unsigned int cpufreq_quick_get(unsigned int cpu) unsigned int ret_freq = 0; if (policy) { - mutex_lock(&policy->lock); + if (unlikely(lock_policy_rwsem_read(cpu))) + return ret_freq; + ret_freq = policy->cur; - mutex_unlock(&policy->lock); + + unlock_policy_rwsem_read(cpu); cpufreq_cpu_put(policy); } @@ -991,24 +1084,13 @@ unsigned int cpufreq_quick_get(unsigned int cpu) EXPORT_SYMBOL(cpufreq_quick_get); -/** - * cpufreq_get - get the current CPU frequency (in kHz) - * @cpu: CPU number - * - * Get the CPU current (static) CPU frequency - */ -unsigned int cpufreq_get(unsigned int cpu) +static unsigned int __cpufreq_get(unsigned int cpu) { - struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); + struct cpufreq_policy *policy = cpufreq_cpu_data[cpu]; unsigned int ret_freq = 0; - if (!policy) - return 0; - if (!cpufreq_driver->get) - goto out; - - mutex_lock(&policy->lock); + return (ret_freq); ret_freq = cpufreq_driver->get(cpu); @@ -1022,11 +1104,33 @@ unsigned int cpufreq_get(unsigned int cpu) } } - mutex_unlock(&policy->lock); + return (ret_freq); +} -out: - cpufreq_cpu_put(policy); +/** + * cpufreq_get - get the current CPU frequency (in kHz) + * @cpu: CPU number + * + * Get the CPU current (static) CPU frequency + */ +unsigned int cpufreq_get(unsigned int cpu) +{ + unsigned int ret_freq = 0; + struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); + + if (!policy) + goto out; + + if (unlikely(lock_policy_rwsem_read(cpu))) + goto out_policy; + + ret_freq = __cpufreq_get(cpu); + unlock_policy_rwsem_read(cpu); + +out_policy: + cpufreq_cpu_put(policy); +out: return (ret_freq); } EXPORT_SYMBOL(cpufreq_get); @@ -1278,7 +1382,6 @@ EXPORT_SYMBOL(cpufreq_unregister_notifier); *********************************************************************/ -/* Must be called with lock_cpu_hotplug held */ int __cpufreq_driver_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) @@ -1304,20 +1407,19 @@ int cpufreq_driver_target(struct cpufreq_policy *policy, if (!policy) return -EINVAL; - lock_cpu_hotplug(); - mutex_lock(&policy->lock); + if (unlikely(lock_policy_rwsem_write(policy->cpu))) + return -EINVAL; ret = __cpufreq_driver_target(policy, target_freq, relation); - mutex_unlock(&policy->lock); - unlock_cpu_hotplug(); + unlock_policy_rwsem_write(policy->cpu); cpufreq_cpu_put(policy); return ret; } EXPORT_SYMBOL_GPL(cpufreq_driver_target); -int cpufreq_driver_getavg(struct cpufreq_policy *policy) +int __cpufreq_driver_getavg(struct cpufreq_policy *policy) { int ret = 0; @@ -1325,20 +1427,15 @@ int cpufreq_driver_getavg(struct cpufreq_policy *policy) if (!policy) return -EINVAL; - mutex_lock(&policy->lock); - if (cpu_online(policy->cpu) && cpufreq_driver->getavg) ret = cpufreq_driver->getavg(policy->cpu); - mutex_unlock(&policy->lock); - cpufreq_cpu_put(policy); return ret; } -EXPORT_SYMBOL_GPL(cpufreq_driver_getavg); +EXPORT_SYMBOL_GPL(__cpufreq_driver_getavg); /* - * Locking: Must be called with the lock_cpu_hotplug() lock held * when "event" is CPUFREQ_GOV_LIMITS */ @@ -1420,9 +1517,7 @@ int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu) if (!cpu_policy) return -EINVAL; - mutex_lock(&cpu_policy->lock); memcpy(policy, cpu_policy, sizeof(struct cpufreq_policy)); - mutex_unlock(&cpu_policy->lock); cpufreq_cpu_put(cpu_policy); return 0; @@ -1433,7 +1528,6 @@ EXPORT_SYMBOL(cpufreq_get_policy); /* * data : current policy. * policy : policy to be set. - * Locking: Must be called with the lock_cpu_hotplug() lock held */ static int __cpufreq_set_policy(struct cpufreq_policy *data, struct cpufreq_policy *policy) @@ -1539,10 +1633,9 @@ int cpufreq_set_policy(struct cpufreq_policy *policy) if (!data) return -EINVAL; - lock_cpu_hotplug(); + if (unlikely(lock_policy_rwsem_write(policy->cpu))) + return -EINVAL; - /* lock this CPU */ - mutex_lock(&data->lock); ret = __cpufreq_set_policy(data, policy); data->user_policy.min = data->min; @@ -1550,9 +1643,8 @@ int cpufreq_set_policy(struct cpufreq_policy *policy) data->user_policy.policy = data->policy; data->user_policy.governor = data->governor; - mutex_unlock(&data->lock); + unlock_policy_rwsem_write(policy->cpu); - unlock_cpu_hotplug(); cpufreq_cpu_put(data); return ret; @@ -1576,8 +1668,8 @@ int cpufreq_update_policy(unsigned int cpu) if (!data) return -ENODEV; - lock_cpu_hotplug(); - mutex_lock(&data->lock); + if (unlikely(lock_policy_rwsem_write(cpu))) + return -EINVAL; dprintk("updating policy for CPU %u\n", cpu); memcpy(&policy, data, sizeof(struct cpufreq_policy)); @@ -1602,8 +1694,8 @@ int cpufreq_update_policy(unsigned int cpu) ret = __cpufreq_set_policy(data, &policy); - mutex_unlock(&data->lock); - unlock_cpu_hotplug(); + unlock_policy_rwsem_write(cpu); + cpufreq_cpu_put(data); return ret; } @@ -1613,31 +1705,28 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { unsigned int cpu = (unsigned long)hcpu; - struct cpufreq_policy *policy; struct sys_device *sys_dev; + struct cpufreq_policy *policy; sys_dev = get_cpu_sysdev(cpu); - if (sys_dev) { switch (action) { case CPU_ONLINE: cpufreq_add_dev(sys_dev); break; case CPU_DOWN_PREPARE: - /* - * We attempt to put this cpu in lowest frequency - * possible before going down. This will permit - * hardware-managed P-State to switch other related - * threads to min or higher speeds if possible. - */ + if (unlikely(lock_policy_rwsem_write(cpu))) + BUG(); + policy = cpufreq_cpu_data[cpu]; if (policy) { - cpufreq_driver_target(policy, policy->min, + __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_H); } + __cpufreq_remove_dev(sys_dev); break; - case CPU_DEAD: - cpufreq_remove_dev(sys_dev); + case CPU_DOWN_FAILED: + cpufreq_add_dev(sys_dev); break; } } @@ -1751,3 +1840,16 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver) return 0; } EXPORT_SYMBOL_GPL(cpufreq_unregister_driver); + +static int __init cpufreq_core_init(void) +{ + int cpu; + + for_each_possible_cpu(cpu) { + per_cpu(policy_cpu, cpu) = -1; + init_rwsem(&per_cpu(cpu_policy_rwsem, cpu)); + } + return 0; +} + +core_initcall(cpufreq_core_init); diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 05d6c22ba07..26f440ccc3f 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -429,14 +429,12 @@ static void dbs_check_cpu(int cpu) static void do_dbs_timer(struct work_struct *work) { int i; - lock_cpu_hotplug(); mutex_lock(&dbs_mutex); for_each_online_cpu(i) dbs_check_cpu(i); schedule_delayed_work(&dbs_work, usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); mutex_unlock(&dbs_mutex); - unlock_cpu_hotplug(); } static inline void dbs_timer_init(void) diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index f697449327c..d60bcb9d14c 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -52,19 +52,20 @@ static unsigned int def_sampling_rate; static void do_dbs_timer(struct work_struct *work); /* Sampling types */ -enum dbs_sample {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE}; +enum {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE}; struct cpu_dbs_info_s { cputime64_t prev_cpu_idle; cputime64_t prev_cpu_wall; struct cpufreq_policy *cur_policy; struct delayed_work work; - enum dbs_sample sample_type; - unsigned int enable; struct cpufreq_frequency_table *freq_table; unsigned int freq_lo; unsigned int freq_lo_jiffies; unsigned int freq_hi_jiffies; + int cpu; + unsigned int enable:1, + sample_type:1; }; static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info); @@ -402,7 +403,7 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info) if (load < (dbs_tuners_ins.up_threshold - 10)) { unsigned int freq_next, freq_cur; - freq_cur = cpufreq_driver_getavg(policy); + freq_cur = __cpufreq_driver_getavg(policy); if (!freq_cur) freq_cur = policy->cur; @@ -423,9 +424,11 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info) static void do_dbs_timer(struct work_struct *work) { - unsigned int cpu = smp_processor_id(); - struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu); - enum dbs_sample sample_type = dbs_info->sample_type; + struct cpu_dbs_info_s *dbs_info = + container_of(work, struct cpu_dbs_info_s, work.work); + unsigned int cpu = dbs_info->cpu; + int sample_type = dbs_info->sample_type; + /* We want all CPUs to do sampling nearly on same jiffy */ int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); @@ -434,15 +437,19 @@ static void do_dbs_timer(struct work_struct *work) delay -= jiffies % delay; - if (!dbs_info->enable) + if (lock_policy_rwsem_write(cpu) < 0) + return; + + if (!dbs_info->enable) { + unlock_policy_rwsem_write(cpu); return; + } + /* Common NORMAL_SAMPLE setup */ dbs_info->sample_type = DBS_NORMAL_SAMPLE; if (!dbs_tuners_ins.powersave_bias || sample_type == DBS_NORMAL_SAMPLE) { - lock_cpu_hotplug(); dbs_check_cpu(dbs_info); - unlock_cpu_hotplug(); if (dbs_info->freq_lo) { /* Setup timer for SUB_SAMPLE */ dbs_info->sample_type = DBS_SUB_SAMPLE; @@ -454,26 +461,27 @@ static void do_dbs_timer(struct work_struct *work) CPUFREQ_RELATION_H); } queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay); + unlock_policy_rwsem_write(cpu); } -static inline void dbs_timer_init(unsigned int cpu) +static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info) { - struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu); /* We want all CPUs to do sampling nearly on same jiffy */ int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); delay -= jiffies % delay; + dbs_info->enable = 1; ondemand_powersave_bias_init(); - INIT_DELAYED_WORK_NAR(&dbs_info->work, do_dbs_timer); dbs_info->sample_type = DBS_NORMAL_SAMPLE; - queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay); + INIT_DELAYED_WORK_NAR(&dbs_info->work, do_dbs_timer); + queue_delayed_work_on(dbs_info->cpu, kondemand_wq, &dbs_info->work, + delay); } static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info) { dbs_info->enable = 0; cancel_delayed_work(&dbs_info->work); - flush_workqueue(kondemand_wq); } static int cpufreq_governor_dbs(struct cpufreq_policy *policy, @@ -502,21 +510,9 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, mutex_lock(&dbs_mutex); dbs_enable++; - if (dbs_enable == 1) { - kondemand_wq = create_workqueue("kondemand"); - if (!kondemand_wq) { - printk(KERN_ERR - "Creation of kondemand failed\n"); - dbs_enable--; - mutex_unlock(&dbs_mutex); - return -ENOSPC; - } - } rc = sysfs_create_group(&policy->kobj, &dbs_attr_group); if (rc) { - if (dbs_enable == 1) - destroy_workqueue(kondemand_wq); dbs_enable--; mutex_unlock(&dbs_mutex); return rc; @@ -530,7 +526,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j); j_dbs_info->prev_cpu_wall = get_jiffies_64(); } - this_dbs_info->enable = 1; + this_dbs_info->cpu = cpu; /* * Start the timerschedule work, when this governor * is used for first time @@ -550,7 +546,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, dbs_tuners_ins.sampling_rate = def_sampling_rate; } - dbs_timer_init(policy->cpu); + dbs_timer_init(this_dbs_info); mutex_unlock(&dbs_mutex); break; @@ -560,9 +556,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, dbs_timer_exit(this_dbs_info); sysfs_remove_group(&policy->kobj, &dbs_attr_group); dbs_enable--; - if (dbs_enable == 0) - destroy_workqueue(kondemand_wq); - mutex_unlock(&dbs_mutex); break; @@ -591,12 +584,18 @@ static struct cpufreq_governor cpufreq_gov_dbs = { static int __init cpufreq_gov_dbs_init(void) { + kondemand_wq = create_workqueue("kondemand"); + if (!kondemand_wq) { + printk(KERN_ERR "Creation of kondemand failed\n"); + return -EFAULT; + } return cpufreq_register_governor(&cpufreq_gov_dbs); } static void __exit cpufreq_gov_dbs_exit(void) { cpufreq_unregister_governor(&cpufreq_gov_dbs); + destroy_workqueue(kondemand_wq); } @@ -608,3 +607,4 @@ MODULE_LICENSE("GPL"); module_init(cpufreq_gov_dbs_init); module_exit(cpufreq_gov_dbs_exit); + diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index 91ad342a605..d1c7cac9316 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -370,12 +370,10 @@ __exit cpufreq_stats_exit(void) cpufreq_unregister_notifier(¬ifier_trans_block, CPUFREQ_TRANSITION_NOTIFIER); unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier); - lock_cpu_hotplug(); for_each_online_cpu(cpu) { cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, CPU_DEAD, (void *)(long)cpu); } - unlock_cpu_hotplug(); } MODULE_AUTHOR ("Zou Nan hai <nanhai.zou@intel.com>"); diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c index 2a4eb0bfaf3..860345c7799 100644 --- a/drivers/cpufreq/cpufreq_userspace.c +++ b/drivers/cpufreq/cpufreq_userspace.c @@ -71,7 +71,6 @@ static int cpufreq_set(unsigned int freq, struct cpufreq_policy *policy) dprintk("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq); - lock_cpu_hotplug(); mutex_lock(&userspace_mutex); if (!cpu_is_managed[policy->cpu]) goto err; @@ -94,7 +93,6 @@ static int cpufreq_set(unsigned int freq, struct cpufreq_policy *policy) err: mutex_unlock(&userspace_mutex); - unlock_cpu_hotplug(); return ret; } diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index cd251efda41..0a26e066354 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -546,7 +546,7 @@ static void ads7846_rx(void *ads) ts->spi->dev.bus_id, ts->tc.ignore, Rt); #endif hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), - HRTIMER_REL); + HRTIMER_MODE_REL); return; } @@ -578,7 +578,8 @@ static void ads7846_rx(void *ads) #endif } - hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), HRTIMER_REL); + hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), + HRTIMER_MODE_REL); } static int ads7846_debounce(void *ads, int data_idx, int *val) @@ -667,7 +668,7 @@ static void ads7846_rx_val(void *ads) status); } -static int ads7846_timer(struct hrtimer *handle) +static enum hrtimer_restart ads7846_timer(struct hrtimer *handle) { struct ads7846 *ts = container_of(handle, struct ads7846, timer); int status = 0; @@ -724,7 +725,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle) disable_irq(ts->spi->irq); ts->pending = 1; hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY), - HRTIMER_REL); + HRTIMER_MODE_REL); } } spin_unlock_irqrestore(&ts->lock, flags); @@ -862,7 +863,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) ts->spi = spi; ts->input = input_dev; - hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_REL); + hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ts->timer.function = ads7846_timer; spin_lock_init(&ts->lock); diff --git a/drivers/isdn/gigaset/Makefile b/drivers/isdn/gigaset/Makefile index 835b806a9de..077e297d8c7 100644 --- a/drivers/isdn/gigaset/Makefile +++ b/drivers/isdn/gigaset/Makefile @@ -5,4 +5,4 @@ ser_gigaset-y := ser-gigaset.o asyncdata.o obj-$(CONFIG_GIGASET_M105) += usb_gigaset.o gigaset.o obj-$(CONFIG_GIGASET_BASE) += bas_gigaset.o gigaset.o -obj-$(CONFIG_GIGASET_M105) += ser_gigaset.o gigaset.o +obj-$(CONFIG_GIGASET_M101) += ser_gigaset.o gigaset.o diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index bedae4ad3f7..80b199fa0aa 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -107,4 +107,19 @@ config MSI_LAPTOP If you have an MSI S270 laptop, say Y or M here. +config SONY_LAPTOP + tristate "Sony Laptop Extras" + depends on X86 && ACPI + select BACKLIGHT_CLASS_DEVICE + ---help--- + This mini-driver drives the SNC device present in the ACPI BIOS of + the Sony Vaio laptops. + + It gives access to some extra laptop functionalities. In its current + form, this driver let the user set or query the screen brightness + through the backlight subsystem and remove/apply power to some + devices. + + Read <file:Documentation/sony-laptop.txt> for more information. + endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 35da53c409c..7793ccd7904 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_LKDTM) += lkdtm.o obj-$(CONFIG_TIFM_CORE) += tifm_core.o obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o obj-$(CONFIG_SGI_IOC4) += ioc4.o +obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c index 861c39935f9..e4e2b707a35 100644 --- a/drivers/misc/asus-laptop.c +++ b/drivers/misc/asus-laptop.c @@ -1088,11 +1088,6 @@ static int __init asus_laptop_init(void) if (acpi_disabled) return -ENODEV; - if (!acpi_specific_hotkey_enabled) { - printk(ASUS_ERR "Using generic hotkey driver\n"); - return -ENODEV; - } - result = acpi_bus_register_driver(&asus_hotk_driver); if (result < 0) return result; diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c new file mode 100644 index 00000000000..cabbed0015e --- /dev/null +++ b/drivers/misc/sony-laptop.c @@ -0,0 +1,562 @@ +/* + * ACPI Sony Notebook Control Driver (SNC) + * + * Copyright (C) 2004-2005 Stelian Pop <stelian@popies.net> + * Copyright (C) 2007 Mattia Dongili <malattia@linux.it> + * + * Parts of this driver inspired from asus_acpi.c and ibm_acpi.c + * which are copyrighted by their respective authors. + * + * 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/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/backlight.h> +#include <linux/platform_device.h> +#include <linux/err.h> +#include <acpi/acpi_drivers.h> +#include <acpi/acpi_bus.h> +#include <asm/uaccess.h> + +#define ACPI_SNC_CLASS "sony" +#define ACPI_SNC_HID "SNY5001" +#define ACPI_SNC_DRIVER_NAME "ACPI Sony Notebook Control Driver v0.4" + +/* the device uses 1-based values, while the backlight subsystem uses + 0-based values */ +#define SONY_MAX_BRIGHTNESS 8 + +#define LOG_PFX KERN_WARNING "sony-laptop: " + +MODULE_AUTHOR("Stelian Pop, Mattia Dongili"); +MODULE_DESCRIPTION(ACPI_SNC_DRIVER_NAME); +MODULE_LICENSE("GPL"); + +static int debug; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "set this to 1 (and RTFM) if you want to help " + "the development of this driver"); + +static ssize_t sony_acpi_show(struct device *, struct device_attribute *, + char *); +static ssize_t sony_acpi_store(struct device *, struct device_attribute *, + const char *, size_t); +static int boolean_validate(const int, const int); +static int brightness_default_validate(const int, const int); + +#define SNC_VALIDATE_IN 0 +#define SNC_VALIDATE_OUT 1 + +struct sony_acpi_value { + char *name; /* name of the entry */ + char **acpiget; /* names of the ACPI get function */ + char **acpiset; /* names of the ACPI set function */ + int (*validate)(const int, const int); /* input/output validation */ + int value; /* current setting */ + int valid; /* Has ever been set */ + int debug; /* active only in debug mode ? */ + struct device_attribute devattr; /* sysfs atribute */ +}; + +#define HANDLE_NAMES(_name, _values...) \ + static char *snc_##_name[] = { _values, NULL } + +#define SONY_ACPI_VALUE(_name, _getters, _setters, _validate, _debug) \ + { \ + .name = __stringify(_name), \ + .acpiget = _getters, \ + .acpiset = _setters, \ + .validate = _validate, \ + .debug = _debug, \ + .devattr = __ATTR(_name, 0, sony_acpi_show, sony_acpi_store), \ + } + +#define SONY_ACPI_VALUE_NULL { .name = NULL } + +HANDLE_NAMES(fnkey_get, "GHKE"); + +HANDLE_NAMES(brightness_def_get, "GPBR"); +HANDLE_NAMES(brightness_def_set, "SPBR"); + +HANDLE_NAMES(cdpower_get, "GCDP"); +HANDLE_NAMES(cdpower_set, "SCDP", "CDPW"); + +HANDLE_NAMES(audiopower_get, "GAZP"); +HANDLE_NAMES(audiopower_set, "AZPW"); + +HANDLE_NAMES(lanpower_get, "GLNP"); +HANDLE_NAMES(lanpower_set, "LNPW"); + +HANDLE_NAMES(PID_get, "GPID"); + +HANDLE_NAMES(CTR_get, "GCTR"); +HANDLE_NAMES(CTR_set, "SCTR"); + +HANDLE_NAMES(PCR_get, "GPCR"); +HANDLE_NAMES(PCR_set, "SPCR"); + +HANDLE_NAMES(CMI_get, "GCMI"); +HANDLE_NAMES(CMI_set, "SCMI"); + +static struct sony_acpi_value sony_acpi_values[] = { + SONY_ACPI_VALUE(brightness_default, snc_brightness_def_get, + snc_brightness_def_set, brightness_default_validate, 0), + SONY_ACPI_VALUE(fnkey, snc_fnkey_get, NULL, NULL, 0), + SONY_ACPI_VALUE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0), + SONY_ACPI_VALUE(audiopower, snc_audiopower_get, snc_audiopower_set, + boolean_validate, 0), + SONY_ACPI_VALUE(lanpower, snc_lanpower_get, snc_lanpower_set, + boolean_validate, 1), + /* unknown methods */ + SONY_ACPI_VALUE(PID, snc_PID_get, NULL, NULL, 1), + SONY_ACPI_VALUE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1), + SONY_ACPI_VALUE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1), + SONY_ACPI_VALUE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1), + SONY_ACPI_VALUE_NULL +}; + +static acpi_handle sony_acpi_handle; +static struct acpi_device *sony_acpi_acpi_device = NULL; + +/* + * acpi_evaluate_object wrappers + */ +static int acpi_callgetfunc(acpi_handle handle, char *name, int *result) +{ + struct acpi_buffer output; + union acpi_object out_obj; + acpi_status status; + + output.length = sizeof(out_obj); + output.pointer = &out_obj; + + status = acpi_evaluate_object(handle, name, NULL, &output); + if ((status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER)) { + *result = out_obj.integer.value; + return 0; + } + + printk(LOG_PFX "acpi_callreadfunc failed\n"); + + return -1; +} + +static int acpi_callsetfunc(acpi_handle handle, char *name, int value, + int *result) +{ + struct acpi_object_list params; + union acpi_object in_obj; + struct acpi_buffer output; + union acpi_object out_obj; + acpi_status status; + + params.count = 1; + params.pointer = &in_obj; + in_obj.type = ACPI_TYPE_INTEGER; + in_obj.integer.value = value; + + output.length = sizeof(out_obj); + output.pointer = &out_obj; + + status = acpi_evaluate_object(handle, name, ¶ms, &output); + if (status == AE_OK) { + if (result != NULL) { + if (out_obj.type != ACPI_TYPE_INTEGER) { + printk(LOG_PFX "acpi_evaluate_object bad " + "return type\n"); + return -1; + } + *result = out_obj.integer.value; + } + return 0; + } + + printk(LOG_PFX "acpi_evaluate_object failed\n"); + + return -1; +} + +/* + * sony_acpi_values input/output validate functions + */ + +/* brightness_default_validate: + * + * manipulate input output values to keep consistency with the + * backlight framework for which brightness values are 0-based. + */ +static int brightness_default_validate(const int direction, const int value) +{ + switch (direction) { + case SNC_VALIDATE_OUT: + return value - 1; + case SNC_VALIDATE_IN: + if (value >= 0 && value < SONY_MAX_BRIGHTNESS) + return value + 1; + } + return -EINVAL; +} + +/* boolean_validate: + * + * on input validate boolean values 0/1, on output just pass the + * received value. + */ +static int boolean_validate(const int direction, const int value) +{ + if (direction == SNC_VALIDATE_IN) { + if (value != 0 && value != 1) + return -EINVAL; + } + return value; +} + +/* + * Sysfs show/store common to all sony_acpi_values + */ +static ssize_t sony_acpi_show(struct device *dev, struct device_attribute *attr, + char *buffer) +{ + int value; + struct sony_acpi_value *item = + container_of(attr, struct sony_acpi_value, devattr); + + if (!*item->acpiget) + return -EIO; + + if (acpi_callgetfunc(sony_acpi_handle, *item->acpiget, &value) < 0) + return -EIO; + + if (item->validate) + value = item->validate(SNC_VALIDATE_OUT, value); + + return snprintf(buffer, PAGE_SIZE, "%d\n", value); +} + +static ssize_t sony_acpi_store(struct device *dev, + struct device_attribute *attr, + const char *buffer, size_t count) +{ + int value; + struct sony_acpi_value *item = + container_of(attr, struct sony_acpi_value, devattr); + + if (!item->acpiset) + return -EIO; + + if (count > 31) + return -EINVAL; + + value = simple_strtoul(buffer, NULL, 10); + + if (item->validate) + value = item->validate(SNC_VALIDATE_IN, value); + + if (value < 0) + return value; + + if (acpi_callsetfunc(sony_acpi_handle, *item->acpiset, value, NULL) < 0) + return -EIO; + item->value = value; + item->valid = 1; + return count; +} + +/* + * Platform device + */ +static struct platform_driver sncpf_driver = { + .driver = { + .name = "sony-laptop", + .owner = THIS_MODULE, + } +}; +static struct platform_device *sncpf_device; + +static int sony_snc_pf_add(void) +{ + acpi_handle handle; + struct sony_acpi_value *item; + int ret = 0; + + ret = platform_driver_register(&sncpf_driver); + if (ret) + goto out; + + sncpf_device = platform_device_alloc("sony-laptop", -1); + if (!sncpf_device) { + ret = -ENOMEM; + goto out_platform_registered; + } + + ret = platform_device_add(sncpf_device); + if (ret) + goto out_platform_alloced; + + for (item = sony_acpi_values; item->name; ++item) { + + if (!debug && item->debug) + continue; + + /* find the available acpiget as described in the DSDT */ + for (; item->acpiget && *item->acpiget; ++item->acpiget) { + if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle, + *item->acpiget, + &handle))) { + if (debug) + printk(LOG_PFX "Found %s getter: %s\n", + item->name, *item->acpiget); + item->devattr.attr.mode |= S_IRUGO; + break; + } + } + + /* find the available acpiset as described in the DSDT */ + for (; item->acpiset && *item->acpiset; ++item->acpiset) { + if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle, + *item->acpiset, + &handle))) { + if (debug) + printk(LOG_PFX "Found %s setter: %s\n", + item->name, *item->acpiset); + item->devattr.attr.mode |= S_IWUSR; + break; + } + } + + if (item->devattr.attr.mode != 0) { + ret = + device_create_file(&sncpf_device->dev, + &item->devattr); + if (ret) + goto out_sysfs; + } + } + + return 0; + + out_sysfs: + for (item = sony_acpi_values; item->name; ++item) { + device_remove_file(&sncpf_device->dev, &item->devattr); + } + platform_device_del(sncpf_device); + out_platform_alloced: + platform_device_put(sncpf_device); + out_platform_registered: + platform_driver_unregister(&sncpf_driver); + out: + return ret; +} + +static void sony_snc_pf_remove(void) +{ + struct sony_acpi_value *item; + + for (item = sony_acpi_values; item->name; ++item) { + device_remove_file(&sncpf_device->dev, &item->devattr); + } + + platform_device_del(sncpf_device); + platform_device_put(sncpf_device); + platform_driver_unregister(&sncpf_driver); +} + +/* + * Backlight device + */ +static int sony_backlight_update_status(struct backlight_device *bd) +{ + return acpi_callsetfunc(sony_acpi_handle, "SBRT", + bd->props->brightness + 1, NULL); +} + +static int sony_backlight_get_brightness(struct backlight_device *bd) +{ + int value; + + if (acpi_callgetfunc(sony_acpi_handle, "GBRT", &value)) + return 0; + /* brightness levels are 1-based, while backlight ones are 0-based */ + return value - 1; +} + +static struct backlight_device *sony_backlight_device; +static struct backlight_properties sony_backlight_properties = { + .owner = THIS_MODULE, + .update_status = sony_backlight_update_status, + .get_brightness = sony_backlight_get_brightness, + .max_brightness = SONY_MAX_BRIGHTNESS - 1, +}; + +/* + * ACPI callbacks + */ +static void sony_acpi_notify(acpi_handle handle, u32 event, void *data) +{ + if (debug) + printk(LOG_PFX "sony_acpi_notify, event: %d\n", event); + acpi_bus_generate_event(sony_acpi_acpi_device, 1, event); +} + +static acpi_status sony_walk_callback(acpi_handle handle, u32 level, + void *context, void **return_value) +{ + struct acpi_namespace_node *node; + union acpi_operand_object *operand; + + node = (struct acpi_namespace_node *)handle; + operand = (union acpi_operand_object *)node->object; + + printk(LOG_PFX "method: name: %4.4s, args %X\n", node->name.ascii, + (u32) operand->method.param_count); + + return AE_OK; +} + +/* + * ACPI device + */ +static int sony_acpi_resume(struct acpi_device *device) +{ + struct sony_acpi_value *item; + + for (item = sony_acpi_values; item->name; item++) { + int ret; + + if (!item->valid) + continue; + ret = acpi_callsetfunc(sony_acpi_handle, *item->acpiset, + item->value, NULL); + if (ret < 0) { + printk("%s: %d\n", __FUNCTION__, ret); + break; + } + } + return 0; +} + +static int sony_acpi_add(struct acpi_device *device) +{ + acpi_status status; + int result; + acpi_handle handle; + + sony_acpi_acpi_device = device; + + sony_acpi_handle = device->handle; + + if (debug) { + status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_acpi_handle, + 1, sony_walk_callback, NULL, NULL); + if (ACPI_FAILURE(status)) { + printk(LOG_PFX "unable to walk acpi resources\n"); + result = -ENODEV; + goto outwalk; + } + } + + status = acpi_install_notify_handler(sony_acpi_handle, + ACPI_DEVICE_NOTIFY, + sony_acpi_notify, NULL); + if (ACPI_FAILURE(status)) { + printk(LOG_PFX "unable to install notify handler\n"); + result = -ENODEV; + goto outwalk; + } + + if (ACPI_SUCCESS(acpi_get_handle(sony_acpi_handle, "GBRT", &handle))) { + sony_backlight_device = backlight_device_register("sony", NULL, + NULL, + &sony_backlight_properties); + + if (IS_ERR(sony_backlight_device)) { + printk(LOG_PFX "unable to register backlight device\n"); + sony_backlight_device = NULL; + } else + sony_backlight_properties.brightness = + sony_backlight_get_brightness + (sony_backlight_device); + } + + if (sony_snc_pf_add()) + goto outbacklight; + + printk(KERN_INFO ACPI_SNC_DRIVER_NAME " successfully installed\n"); + + return 0; + + outbacklight: + if (sony_backlight_device) + backlight_device_unregister(sony_backlight_device); + + status = acpi_remove_notify_handler(sony_acpi_handle, + ACPI_DEVICE_NOTIFY, + sony_acpi_notify); + if (ACPI_FAILURE(status)) + printk(LOG_PFX "unable to remove notify handler\n"); + outwalk: + return result; +} + +static int sony_acpi_remove(struct acpi_device *device, int type) +{ + acpi_status status; + + if (sony_backlight_device) + backlight_device_unregister(sony_backlight_device); + + sony_acpi_acpi_device = NULL; + + status = acpi_remove_notify_handler(sony_acpi_handle, + ACPI_DEVICE_NOTIFY, + sony_acpi_notify); + if (ACPI_FAILURE(status)) + printk(LOG_PFX "unable to remove notify handler\n"); + + sony_snc_pf_remove(); + + printk(KERN_INFO ACPI_SNC_DRIVER_NAME " successfully removed\n"); + + return 0; +} + +static struct acpi_driver sony_acpi_driver = { + .name = ACPI_SNC_DRIVER_NAME, + .class = ACPI_SNC_CLASS, + .ids = ACPI_SNC_HID, + .ops = { + .add = sony_acpi_add, + .remove = sony_acpi_remove, + .resume = sony_acpi_resume, + }, +}; + +static int __init sony_acpi_init(void) +{ + return acpi_bus_register_driver(&sony_acpi_driver); +} + +static void __exit sony_acpi_exit(void) +{ + acpi_bus_unregister_driver(&sony_acpi_driver); +} + +module_init(sony_acpi_init); +module_exit(sony_acpi_exit); diff --git a/drivers/pnp/pnpacpi/Kconfig b/drivers/pnp/pnpacpi/Kconfig index ad27e5e0101..b04767ce273 100644 --- a/drivers/pnp/pnpacpi/Kconfig +++ b/drivers/pnp/pnpacpi/Kconfig @@ -2,17 +2,5 @@ # Plug and Play ACPI configuration # config PNPACPI - bool "Plug and Play ACPI support" - depends on PNP && ACPI - default y - ---help--- - Linux uses the PNPACPI to autodetect built-in - mainboard resources (e.g. parallel port resources). - - Some features (e.g. real hotplug) are not currently - implemented. - - If you would like the kernel to detect and allocate resources to - your mainboard devices (on some systems they are disabled by the - BIOS) say Y here. Also the PNPACPI can help prevent resource - conflicts between mainboard devices and other bus devices. + bool + default (PNP && ACPI) diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index 32f0e3a5b02..e573c8ba978 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -281,8 +281,8 @@ static int appledisplay_probe(struct usb_interface *iface, /* Register backlight device */ snprintf(bl_name, sizeof(bl_name), "appledisplay%d", atomic_inc_return(&count_displays) - 1); - pdata->bd = backlight_device_register(bl_name, NULL, - pdata, &appledisplay_bl_data); + pdata->bd = backlight_device_register(bl_name, NULL, pdata, + &appledisplay_bl_data); if (IS_ERR(pdata->bd)) { err("appledisplay: Backlight registration failed"); goto error; diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index ccef56d0c15..ed3426062a8 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -791,6 +791,8 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) info = fbinfo->par; info->fb = fbinfo; + info->dev = &pdev->dev; + platform_set_drvdata(pdev, fbinfo); dprintk("devinit\n"); |