diff options
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/Kconfig | 22 | ||||
-rw-r--r-- | drivers/misc/msi-laptop.c | 2 | ||||
-rw-r--r-- | drivers/misc/sony-laptop.c | 204 | ||||
-rw-r--r-- | drivers/misc/thinkpad_acpi.c | 321 | ||||
-rw-r--r-- | drivers/misc/thinkpad_acpi.h | 38 |
5 files changed, 415 insertions, 172 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index df89367032c3..e0a1ff927a5b 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
@@ -149,6 +149,7 @@ config SONY_LAPTOP | |||
149 | tristate "Sony Laptop Extras" | 149 | tristate "Sony Laptop Extras" |
150 | depends on X86 && ACPI | 150 | depends on X86 && ACPI |
151 | select BACKLIGHT_CLASS_DEVICE | 151 | select BACKLIGHT_CLASS_DEVICE |
152 | depends on INPUT | ||
152 | ---help--- | 153 | ---help--- |
153 | This mini-driver drives the SNC and SPIC devices present in the ACPI | 154 | This mini-driver drives the SNC and SPIC devices present in the ACPI |
154 | BIOS of the Sony Vaio laptops. | 155 | BIOS of the Sony Vaio laptops. |
@@ -171,6 +172,7 @@ config THINKPAD_ACPI | |||
171 | select BACKLIGHT_CLASS_DEVICE | 172 | select BACKLIGHT_CLASS_DEVICE |
172 | select HWMON | 173 | select HWMON |
173 | select NVRAM | 174 | select NVRAM |
175 | depends on INPUT | ||
174 | ---help--- | 176 | ---help--- |
175 | This is a driver for the IBM and Lenovo ThinkPad laptops. It adds | 177 | This is a driver for the IBM and Lenovo ThinkPad laptops. It adds |
176 | support for Fn-Fx key combinations, Bluetooth control, video | 178 | support for Fn-Fx key combinations, Bluetooth control, video |
@@ -217,25 +219,5 @@ config THINKPAD_ACPI_BAY | |||
217 | 219 | ||
218 | If you are not sure, say Y here. | 220 | If you are not sure, say Y here. |
219 | 221 | ||
220 | config THINKPAD_ACPI_INPUT_ENABLED | ||
221 | bool "Enable input layer support by default" | ||
222 | depends on THINKPAD_ACPI | ||
223 | default n | ||
224 | ---help--- | ||
225 | This option enables thinkpad-acpi hot key handling over the input | ||
226 | layer at driver load time. When it is unset, the driver does not | ||
227 | enable hot key handling by default, and also starts up with a mostly | ||
228 | empty keymap. | ||
229 | |||
230 | This option should be enabled if you have a new enough HAL or other | ||
231 | userspace support that properly handles the thinkpad-acpi event | ||
232 | device. It auto-tunes the hot key support to those reported by the | ||
233 | firmware and enables it automatically. | ||
234 | |||
235 | If unsure, say N here to retain the old behaviour of ibm-acpi, and | ||
236 | thinkpad-acpi up to kernel 2.6.21: userspace will have to enable and | ||
237 | set up the thinkpad-acpi hot key handling using the sysfs interace | ||
238 | after loading the driver. | ||
239 | |||
240 | 222 | ||
241 | endif # MISC_DEVICES | 223 | endif # MISC_DEVICES |
diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c index 932a415197b3..349be934db7c 100644 --- a/drivers/misc/msi-laptop.c +++ b/drivers/misc/msi-laptop.c | |||
@@ -353,7 +353,7 @@ static int __init msi_init(void) | |||
353 | if (IS_ERR(msibl_device)) | 353 | if (IS_ERR(msibl_device)) |
354 | return PTR_ERR(msibl_device); | 354 | return PTR_ERR(msibl_device); |
355 | 355 | ||
356 | msibl_device->props.max_brightness = MSI_LCD_LEVEL_MAX-1, | 356 | msibl_device->props.max_brightness = MSI_LCD_LEVEL_MAX-1; |
357 | 357 | ||
358 | ret = platform_driver_register(&msipf_driver); | 358 | ret = platform_driver_register(&msipf_driver); |
359 | if (ret) | 359 | if (ret) |
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c index d38ddce592c0..f248080828f2 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c | |||
@@ -1173,7 +1173,8 @@ static struct acpi_driver sony_nc_driver = { | |||
1173 | #define SONYPI_TYPE3_OFFSET 0x12 | 1173 | #define SONYPI_TYPE3_OFFSET 0x12 |
1174 | 1174 | ||
1175 | struct sony_pic_ioport { | 1175 | struct sony_pic_ioport { |
1176 | struct acpi_resource_io io; | 1176 | struct acpi_resource_io io1; |
1177 | struct acpi_resource_io io2; | ||
1177 | struct list_head list; | 1178 | struct list_head list; |
1178 | }; | 1179 | }; |
1179 | 1180 | ||
@@ -1443,11 +1444,11 @@ static u8 sony_pic_call1(u8 dev) | |||
1443 | { | 1444 | { |
1444 | u8 v1, v2; | 1445 | u8 v1, v2; |
1445 | 1446 | ||
1446 | wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, | 1447 | wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, |
1447 | ITERATIONS_LONG); | 1448 | ITERATIONS_LONG); |
1448 | outb(dev, spic_dev.cur_ioport->io.minimum + 4); | 1449 | outb(dev, spic_dev.cur_ioport->io1.minimum + 4); |
1449 | v1 = inb_p(spic_dev.cur_ioport->io.minimum + 4); | 1450 | v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4); |
1450 | v2 = inb_p(spic_dev.cur_ioport->io.minimum); | 1451 | v2 = inb_p(spic_dev.cur_ioport->io1.minimum); |
1451 | dprintk("sony_pic_call1: 0x%.4x\n", (v2 << 8) | v1); | 1452 | dprintk("sony_pic_call1: 0x%.4x\n", (v2 << 8) | v1); |
1452 | return v2; | 1453 | return v2; |
1453 | } | 1454 | } |
@@ -1456,13 +1457,13 @@ static u8 sony_pic_call2(u8 dev, u8 fn) | |||
1456 | { | 1457 | { |
1457 | u8 v1; | 1458 | u8 v1; |
1458 | 1459 | ||
1459 | wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, | 1460 | wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, |
1460 | ITERATIONS_LONG); | 1461 | ITERATIONS_LONG); |
1461 | outb(dev, spic_dev.cur_ioport->io.minimum + 4); | 1462 | outb(dev, spic_dev.cur_ioport->io1.minimum + 4); |
1462 | wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, | 1463 | wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, |
1463 | ITERATIONS_LONG); | 1464 | ITERATIONS_LONG); |
1464 | outb(fn, spic_dev.cur_ioport->io.minimum); | 1465 | outb(fn, spic_dev.cur_ioport->io1.minimum); |
1465 | v1 = inb_p(spic_dev.cur_ioport->io.minimum); | 1466 | v1 = inb_p(spic_dev.cur_ioport->io1.minimum); |
1466 | dprintk("sony_pic_call2: 0x%.4x\n", v1); | 1467 | dprintk("sony_pic_call2: 0x%.4x\n", v1); |
1467 | return v1; | 1468 | return v1; |
1468 | } | 1469 | } |
@@ -1471,13 +1472,13 @@ static u8 sony_pic_call3(u8 dev, u8 fn, u8 v) | |||
1471 | { | 1472 | { |
1472 | u8 v1; | 1473 | u8 v1; |
1473 | 1474 | ||
1474 | wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG); | 1475 | wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); |
1475 | outb(dev, spic_dev.cur_ioport->io.minimum + 4); | 1476 | outb(dev, spic_dev.cur_ioport->io1.minimum + 4); |
1476 | wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG); | 1477 | wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); |
1477 | outb(fn, spic_dev.cur_ioport->io.minimum); | 1478 | outb(fn, spic_dev.cur_ioport->io1.minimum); |
1478 | wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG); | 1479 | wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); |
1479 | outb(v, spic_dev.cur_ioport->io.minimum); | 1480 | outb(v, spic_dev.cur_ioport->io1.minimum); |
1480 | v1 = inb_p(spic_dev.cur_ioport->io.minimum); | 1481 | v1 = inb_p(spic_dev.cur_ioport->io1.minimum); |
1481 | dprintk("sony_pic_call3: 0x%.4x\n", v1); | 1482 | dprintk("sony_pic_call3: 0x%.4x\n", v1); |
1482 | return v1; | 1483 | return v1; |
1483 | } | 1484 | } |
@@ -2074,7 +2075,18 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context) | |||
2074 | 2075 | ||
2075 | switch (resource->type) { | 2076 | switch (resource->type) { |
2076 | case ACPI_RESOURCE_TYPE_START_DEPENDENT: | 2077 | case ACPI_RESOURCE_TYPE_START_DEPENDENT: |
2078 | { | ||
2079 | /* start IO enumeration */ | ||
2080 | struct sony_pic_ioport *ioport = kzalloc(sizeof(*ioport), GFP_KERNEL); | ||
2081 | if (!ioport) | ||
2082 | return AE_ERROR; | ||
2083 | |||
2084 | list_add(&ioport->list, &dev->ioports); | ||
2085 | return AE_OK; | ||
2086 | } | ||
2087 | |||
2077 | case ACPI_RESOURCE_TYPE_END_DEPENDENT: | 2088 | case ACPI_RESOURCE_TYPE_END_DEPENDENT: |
2089 | /* end IO enumeration */ | ||
2078 | return AE_OK; | 2090 | return AE_OK; |
2079 | 2091 | ||
2080 | case ACPI_RESOURCE_TYPE_IRQ: | 2092 | case ACPI_RESOURCE_TYPE_IRQ: |
@@ -2101,7 +2113,7 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context) | |||
2101 | if (!interrupt) | 2113 | if (!interrupt) |
2102 | return AE_ERROR; | 2114 | return AE_ERROR; |
2103 | 2115 | ||
2104 | list_add_tail(&interrupt->list, &dev->interrupts); | 2116 | list_add(&interrupt->list, &dev->interrupts); |
2105 | interrupt->irq.triggering = p->triggering; | 2117 | interrupt->irq.triggering = p->triggering; |
2106 | interrupt->irq.polarity = p->polarity; | 2118 | interrupt->irq.polarity = p->polarity; |
2107 | interrupt->irq.sharable = p->sharable; | 2119 | interrupt->irq.sharable = p->sharable; |
@@ -2113,18 +2125,27 @@ sony_pic_read_possible_resource(struct acpi_resource *resource, void *context) | |||
2113 | case ACPI_RESOURCE_TYPE_IO: | 2125 | case ACPI_RESOURCE_TYPE_IO: |
2114 | { | 2126 | { |
2115 | struct acpi_resource_io *io = &resource->data.io; | 2127 | struct acpi_resource_io *io = &resource->data.io; |
2116 | struct sony_pic_ioport *ioport = NULL; | 2128 | struct sony_pic_ioport *ioport = |
2129 | list_first_entry(&dev->ioports, struct sony_pic_ioport, list); | ||
2117 | if (!io) { | 2130 | if (!io) { |
2118 | dprintk("Blank IO resource\n"); | 2131 | dprintk("Blank IO resource\n"); |
2119 | return AE_OK; | 2132 | return AE_OK; |
2120 | } | 2133 | } |
2121 | 2134 | ||
2122 | ioport = kzalloc(sizeof(*ioport), GFP_KERNEL); | 2135 | if (!ioport->io1.minimum) { |
2123 | if (!ioport) | 2136 | memcpy(&ioport->io1, io, sizeof(*io)); |
2137 | dprintk("IO1 at 0x%.4x (0x%.2x)\n", ioport->io1.minimum, | ||
2138 | ioport->io1.address_length); | ||
2139 | } | ||
2140 | else if (!ioport->io2.minimum) { | ||
2141 | memcpy(&ioport->io2, io, sizeof(*io)); | ||
2142 | dprintk("IO2 at 0x%.4x (0x%.2x)\n", ioport->io2.minimum, | ||
2143 | ioport->io2.address_length); | ||
2144 | } | ||
2145 | else { | ||
2146 | printk(KERN_ERR DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n"); | ||
2124 | return AE_ERROR; | 2147 | return AE_ERROR; |
2125 | 2148 | } | |
2126 | list_add_tail(&ioport->list, &dev->ioports); | ||
2127 | memcpy(&ioport->io, io, sizeof(*io)); | ||
2128 | return AE_OK; | 2149 | return AE_OK; |
2129 | } | 2150 | } |
2130 | default: | 2151 | default: |
@@ -2199,10 +2220,22 @@ static int sony_pic_enable(struct acpi_device *device, | |||
2199 | { | 2220 | { |
2200 | acpi_status status; | 2221 | acpi_status status; |
2201 | int result = 0; | 2222 | int result = 0; |
2223 | /* Type 1 resource layout is: | ||
2224 | * IO | ||
2225 | * IO | ||
2226 | * IRQNoFlags | ||
2227 | * End | ||
2228 | * | ||
2229 | * Type 2 and 3 resource layout is: | ||
2230 | * IO | ||
2231 | * IRQNoFlags | ||
2232 | * End | ||
2233 | */ | ||
2202 | struct { | 2234 | struct { |
2203 | struct acpi_resource io_res; | 2235 | struct acpi_resource res1; |
2204 | struct acpi_resource irq_res; | 2236 | struct acpi_resource res2; |
2205 | struct acpi_resource end; | 2237 | struct acpi_resource res3; |
2238 | struct acpi_resource res4; | ||
2206 | } *resource; | 2239 | } *resource; |
2207 | struct acpi_buffer buffer = { 0, NULL }; | 2240 | struct acpi_buffer buffer = { 0, NULL }; |
2208 | 2241 | ||
@@ -2217,21 +2250,49 @@ static int sony_pic_enable(struct acpi_device *device, | |||
2217 | buffer.length = sizeof(*resource) + 1; | 2250 | buffer.length = sizeof(*resource) + 1; |
2218 | buffer.pointer = resource; | 2251 | buffer.pointer = resource; |
2219 | 2252 | ||
2220 | /* setup io resource */ | 2253 | /* setup Type 1 resources */ |
2221 | resource->io_res.type = ACPI_RESOURCE_TYPE_IO; | 2254 | if (spic_dev.model == SONYPI_DEVICE_TYPE1) { |
2222 | resource->io_res.length = sizeof(struct acpi_resource); | ||
2223 | memcpy(&resource->io_res.data.io, &ioport->io, | ||
2224 | sizeof(struct acpi_resource_io)); | ||
2225 | 2255 | ||
2226 | /* setup irq resource */ | 2256 | /* setup io resources */ |
2227 | resource->irq_res.type = ACPI_RESOURCE_TYPE_IRQ; | 2257 | resource->res1.type = ACPI_RESOURCE_TYPE_IO; |
2228 | resource->irq_res.length = sizeof(struct acpi_resource); | 2258 | resource->res1.length = sizeof(struct acpi_resource); |
2229 | memcpy(&resource->irq_res.data.irq, &irq->irq, | 2259 | memcpy(&resource->res1.data.io, &ioport->io1, |
2230 | sizeof(struct acpi_resource_irq)); | 2260 | sizeof(struct acpi_resource_io)); |
2231 | /* we requested a shared irq */ | ||
2232 | resource->irq_res.data.irq.sharable = ACPI_SHARED; | ||
2233 | 2261 | ||
2234 | resource->end.type = ACPI_RESOURCE_TYPE_END_TAG; | 2262 | resource->res2.type = ACPI_RESOURCE_TYPE_IO; |
2263 | resource->res2.length = sizeof(struct acpi_resource); | ||
2264 | memcpy(&resource->res2.data.io, &ioport->io2, | ||
2265 | sizeof(struct acpi_resource_io)); | ||
2266 | |||
2267 | /* setup irq resource */ | ||
2268 | resource->res3.type = ACPI_RESOURCE_TYPE_IRQ; | ||
2269 | resource->res3.length = sizeof(struct acpi_resource); | ||
2270 | memcpy(&resource->res3.data.irq, &irq->irq, | ||
2271 | sizeof(struct acpi_resource_irq)); | ||
2272 | /* we requested a shared irq */ | ||
2273 | resource->res3.data.irq.sharable = ACPI_SHARED; | ||
2274 | |||
2275 | resource->res4.type = ACPI_RESOURCE_TYPE_END_TAG; | ||
2276 | |||
2277 | } | ||
2278 | /* setup Type 2/3 resources */ | ||
2279 | else { | ||
2280 | /* setup io resource */ | ||
2281 | resource->res1.type = ACPI_RESOURCE_TYPE_IO; | ||
2282 | resource->res1.length = sizeof(struct acpi_resource); | ||
2283 | memcpy(&resource->res1.data.io, &ioport->io1, | ||
2284 | sizeof(struct acpi_resource_io)); | ||
2285 | |||
2286 | /* setup irq resource */ | ||
2287 | resource->res2.type = ACPI_RESOURCE_TYPE_IRQ; | ||
2288 | resource->res2.length = sizeof(struct acpi_resource); | ||
2289 | memcpy(&resource->res2.data.irq, &irq->irq, | ||
2290 | sizeof(struct acpi_resource_irq)); | ||
2291 | /* we requested a shared irq */ | ||
2292 | resource->res2.data.irq.sharable = ACPI_SHARED; | ||
2293 | |||
2294 | resource->res3.type = ACPI_RESOURCE_TYPE_END_TAG; | ||
2295 | } | ||
2235 | 2296 | ||
2236 | /* Attempt to set the resource */ | 2297 | /* Attempt to set the resource */ |
2237 | dprintk("Evaluating _SRS\n"); | 2298 | dprintk("Evaluating _SRS\n"); |
@@ -2239,7 +2300,7 @@ static int sony_pic_enable(struct acpi_device *device, | |||
2239 | 2300 | ||
2240 | /* check for total failure */ | 2301 | /* check for total failure */ |
2241 | if (ACPI_FAILURE(status)) { | 2302 | if (ACPI_FAILURE(status)) { |
2242 | printk(KERN_ERR DRV_PFX "Error evaluating _SRS"); | 2303 | printk(KERN_ERR DRV_PFX "Error evaluating _SRS\n"); |
2243 | result = -ENODEV; | 2304 | result = -ENODEV; |
2244 | goto end; | 2305 | goto end; |
2245 | } | 2306 | } |
@@ -2268,11 +2329,14 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id) | |||
2268 | 2329 | ||
2269 | struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id; | 2330 | struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id; |
2270 | 2331 | ||
2271 | ev = inb_p(dev->cur_ioport->io.minimum); | 2332 | ev = inb_p(dev->cur_ioport->io1.minimum); |
2272 | data_mask = inb_p(dev->cur_ioport->io.minimum + dev->evport_offset); | 2333 | if (dev->cur_ioport->io2.minimum) |
2334 | data_mask = inb_p(dev->cur_ioport->io2.minimum); | ||
2335 | else | ||
2336 | data_mask = inb_p(dev->cur_ioport->io1.minimum + dev->evport_offset); | ||
2273 | 2337 | ||
2274 | dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n", | 2338 | dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n", |
2275 | ev, data_mask, dev->cur_ioport->io.minimum, dev->evport_offset); | 2339 | ev, data_mask, dev->cur_ioport->io1.minimum, dev->evport_offset); |
2276 | 2340 | ||
2277 | if (ev == 0x00 || ev == 0xff) | 2341 | if (ev == 0x00 || ev == 0xff) |
2278 | return IRQ_HANDLED; | 2342 | return IRQ_HANDLED; |
@@ -2323,8 +2387,11 @@ static int sony_pic_remove(struct acpi_device *device, int type) | |||
2323 | } | 2387 | } |
2324 | 2388 | ||
2325 | free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev); | 2389 | free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev); |
2326 | release_region(spic_dev.cur_ioport->io.minimum, | 2390 | release_region(spic_dev.cur_ioport->io1.minimum, |
2327 | spic_dev.cur_ioport->io.address_length); | 2391 | spic_dev.cur_ioport->io1.address_length); |
2392 | if (spic_dev.cur_ioport->io2.minimum) | ||
2393 | release_region(spic_dev.cur_ioport->io2.minimum, | ||
2394 | spic_dev.cur_ioport->io2.address_length); | ||
2328 | 2395 | ||
2329 | sonypi_compat_exit(); | 2396 | sonypi_compat_exit(); |
2330 | 2397 | ||
@@ -2397,14 +2464,36 @@ static int sony_pic_add(struct acpi_device *device) | |||
2397 | goto err_remove_input; | 2464 | goto err_remove_input; |
2398 | 2465 | ||
2399 | /* request io port */ | 2466 | /* request io port */ |
2400 | list_for_each_entry(io, &spic_dev.ioports, list) { | 2467 | list_for_each_entry_reverse(io, &spic_dev.ioports, list) { |
2401 | if (request_region(io->io.minimum, io->io.address_length, | 2468 | if (request_region(io->io1.minimum, io->io1.address_length, |
2402 | "Sony Programable I/O Device")) { | 2469 | "Sony Programable I/O Device")) { |
2403 | dprintk("I/O port: 0x%.4x (0x%.4x) + 0x%.2x\n", | 2470 | dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n", |
2404 | io->io.minimum, io->io.maximum, | 2471 | io->io1.minimum, io->io1.maximum, |
2405 | io->io.address_length); | 2472 | io->io1.address_length); |
2406 | spic_dev.cur_ioport = io; | 2473 | /* Type 1 have 2 ioports */ |
2407 | break; | 2474 | if (io->io2.minimum) { |
2475 | if (request_region(io->io2.minimum, | ||
2476 | io->io2.address_length, | ||
2477 | "Sony Programable I/O Device")) { | ||
2478 | dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n", | ||
2479 | io->io2.minimum, io->io2.maximum, | ||
2480 | io->io2.address_length); | ||
2481 | spic_dev.cur_ioport = io; | ||
2482 | break; | ||
2483 | } | ||
2484 | else { | ||
2485 | dprintk("Unable to get I/O port2: " | ||
2486 | "0x%.4x (0x%.4x) + 0x%.2x\n", | ||
2487 | io->io2.minimum, io->io2.maximum, | ||
2488 | io->io2.address_length); | ||
2489 | release_region(io->io1.minimum, | ||
2490 | io->io1.address_length); | ||
2491 | } | ||
2492 | } | ||
2493 | else { | ||
2494 | spic_dev.cur_ioport = io; | ||
2495 | break; | ||
2496 | } | ||
2408 | } | 2497 | } |
2409 | } | 2498 | } |
2410 | if (!spic_dev.cur_ioport) { | 2499 | if (!spic_dev.cur_ioport) { |
@@ -2414,7 +2503,7 @@ static int sony_pic_add(struct acpi_device *device) | |||
2414 | } | 2503 | } |
2415 | 2504 | ||
2416 | /* request IRQ */ | 2505 | /* request IRQ */ |
2417 | list_for_each_entry(irq, &spic_dev.interrupts, list) { | 2506 | list_for_each_entry_reverse(irq, &spic_dev.interrupts, list) { |
2418 | if (!request_irq(irq->irq.interrupts[0], sony_pic_irq, | 2507 | if (!request_irq(irq->irq.interrupts[0], sony_pic_irq, |
2419 | IRQF_SHARED, "sony-laptop", &spic_dev)) { | 2508 | IRQF_SHARED, "sony-laptop", &spic_dev)) { |
2420 | dprintk("IRQ: %d - triggering: %d - " | 2509 | dprintk("IRQ: %d - triggering: %d - " |
@@ -2462,8 +2551,11 @@ err_free_irq: | |||
2462 | free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev); | 2551 | free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev); |
2463 | 2552 | ||
2464 | err_release_region: | 2553 | err_release_region: |
2465 | release_region(spic_dev.cur_ioport->io.minimum, | 2554 | release_region(spic_dev.cur_ioport->io1.minimum, |
2466 | spic_dev.cur_ioport->io.address_length); | 2555 | spic_dev.cur_ioport->io1.address_length); |
2556 | if (spic_dev.cur_ioport->io2.minimum) | ||
2557 | release_region(spic_dev.cur_ioport->io2.minimum, | ||
2558 | spic_dev.cur_ioport->io2.address_length); | ||
2467 | 2559 | ||
2468 | err_remove_compat: | 2560 | err_remove_compat: |
2469 | sonypi_compat_exit(); | 2561 | sonypi_compat_exit(); |
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index bb8956d0c104..37891a8c030a 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c | |||
@@ -21,8 +21,8 @@ | |||
21 | * 02110-1301, USA. | 21 | * 02110-1301, USA. |
22 | */ | 22 | */ |
23 | 23 | ||
24 | #define IBM_VERSION "0.15" | 24 | #define IBM_VERSION "0.16" |
25 | #define TPACPI_SYSFS_VERSION 0x010000 | 25 | #define TPACPI_SYSFS_VERSION 0x020000 |
26 | 26 | ||
27 | /* | 27 | /* |
28 | * Changelog: | 28 | * Changelog: |
@@ -117,6 +117,12 @@ IBM_BIOS_MODULE_ALIAS("K[U,X-Z]"); | |||
117 | 117 | ||
118 | #define __unused __attribute__ ((unused)) | 118 | #define __unused __attribute__ ((unused)) |
119 | 119 | ||
120 | static enum { | ||
121 | TPACPI_LIFE_INIT = 0, | ||
122 | TPACPI_LIFE_RUNNING, | ||
123 | TPACPI_LIFE_EXITING, | ||
124 | } tpacpi_lifecycle; | ||
125 | |||
120 | /**************************************************************************** | 126 | /**************************************************************************** |
121 | **************************************************************************** | 127 | **************************************************************************** |
122 | * | 128 | * |
@@ -342,6 +348,9 @@ static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data) | |||
342 | { | 348 | { |
343 | struct ibm_struct *ibm = data; | 349 | struct ibm_struct *ibm = data; |
344 | 350 | ||
351 | if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING) | ||
352 | return; | ||
353 | |||
345 | if (!ibm || !ibm->acpi || !ibm->acpi->notify) | 354 | if (!ibm || !ibm->acpi || !ibm->acpi->notify) |
346 | return; | 355 | return; |
347 | 356 | ||
@@ -517,8 +526,10 @@ static char *next_cmd(char **cmds) | |||
517 | ****************************************************************************/ | 526 | ****************************************************************************/ |
518 | 527 | ||
519 | static struct platform_device *tpacpi_pdev; | 528 | static struct platform_device *tpacpi_pdev; |
529 | static struct platform_device *tpacpi_sensors_pdev; | ||
520 | static struct class_device *tpacpi_hwmon; | 530 | static struct class_device *tpacpi_hwmon; |
521 | static struct input_dev *tpacpi_inputdev; | 531 | static struct input_dev *tpacpi_inputdev; |
532 | static struct mutex tpacpi_inputdev_send_mutex; | ||
522 | 533 | ||
523 | 534 | ||
524 | static int tpacpi_resume_handler(struct platform_device *pdev) | 535 | static int tpacpi_resume_handler(struct platform_device *pdev) |
@@ -543,6 +554,12 @@ static struct platform_driver tpacpi_pdriver = { | |||
543 | .resume = tpacpi_resume_handler, | 554 | .resume = tpacpi_resume_handler, |
544 | }; | 555 | }; |
545 | 556 | ||
557 | static struct platform_driver tpacpi_hwmon_pdriver = { | ||
558 | .driver = { | ||
559 | .name = IBM_HWMON_DRVR_NAME, | ||
560 | .owner = THIS_MODULE, | ||
561 | }, | ||
562 | }; | ||
546 | 563 | ||
547 | /************************************************************************* | 564 | /************************************************************************* |
548 | * thinkpad-acpi driver attributes | 565 | * thinkpad-acpi driver attributes |
@@ -692,6 +709,8 @@ static int parse_strtoul(const char *buf, | |||
692 | { | 709 | { |
693 | char *endp; | 710 | char *endp; |
694 | 711 | ||
712 | while (*buf && isspace(*buf)) | ||
713 | buf++; | ||
695 | *value = simple_strtoul(buf, &endp, 0); | 714 | *value = simple_strtoul(buf, &endp, 0); |
696 | while (*endp && isspace(*endp)) | 715 | while (*endp && isspace(*endp)) |
697 | endp++; | 716 | endp++; |
@@ -906,9 +925,26 @@ static ssize_t hotkey_radio_sw_show(struct device *dev, | |||
906 | static struct device_attribute dev_attr_hotkey_radio_sw = | 925 | static struct device_attribute dev_attr_hotkey_radio_sw = |
907 | __ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL); | 926 | __ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL); |
908 | 927 | ||
928 | /* sysfs hotkey report_mode -------------------------------------------- */ | ||
929 | static ssize_t hotkey_report_mode_show(struct device *dev, | ||
930 | struct device_attribute *attr, | ||
931 | char *buf) | ||
932 | { | ||
933 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
934 | (hotkey_report_mode != 0) ? hotkey_report_mode : 1); | ||
935 | } | ||
936 | |||
937 | static struct device_attribute dev_attr_hotkey_report_mode = | ||
938 | __ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL); | ||
939 | |||
909 | /* --------------------------------------------------------------------- */ | 940 | /* --------------------------------------------------------------------- */ |
910 | 941 | ||
911 | static struct attribute *hotkey_mask_attributes[] = { | 942 | static struct attribute *hotkey_attributes[] __initdata = { |
943 | &dev_attr_hotkey_enable.attr, | ||
944 | &dev_attr_hotkey_report_mode.attr, | ||
945 | }; | ||
946 | |||
947 | static struct attribute *hotkey_mask_attributes[] __initdata = { | ||
912 | &dev_attr_hotkey_mask.attr, | 948 | &dev_attr_hotkey_mask.attr, |
913 | &dev_attr_hotkey_bios_enabled.attr, | 949 | &dev_attr_hotkey_bios_enabled.attr, |
914 | &dev_attr_hotkey_bios_mask.attr, | 950 | &dev_attr_hotkey_bios_mask.attr, |
@@ -972,6 +1008,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
972 | 1008 | ||
973 | int res, i; | 1009 | int res, i; |
974 | int status; | 1010 | int status; |
1011 | int hkeyv; | ||
975 | 1012 | ||
976 | vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); | 1013 | vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); |
977 | 1014 | ||
@@ -987,27 +1024,45 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
987 | str_supported(tp_features.hotkey)); | 1024 | str_supported(tp_features.hotkey)); |
988 | 1025 | ||
989 | if (tp_features.hotkey) { | 1026 | if (tp_features.hotkey) { |
990 | hotkey_dev_attributes = create_attr_set(7, NULL); | 1027 | hotkey_dev_attributes = create_attr_set(8, NULL); |
991 | if (!hotkey_dev_attributes) | 1028 | if (!hotkey_dev_attributes) |
992 | return -ENOMEM; | 1029 | return -ENOMEM; |
993 | res = add_to_attr_set(hotkey_dev_attributes, | 1030 | res = add_many_to_attr_set(hotkey_dev_attributes, |
994 | &dev_attr_hotkey_enable.attr); | 1031 | hotkey_attributes, |
1032 | ARRAY_SIZE(hotkey_attributes)); | ||
995 | if (res) | 1033 | if (res) |
996 | return res; | 1034 | return res; |
997 | 1035 | ||
998 | /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, | 1036 | /* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, |
999 | A30, R30, R31, T20-22, X20-21, X22-24 */ | 1037 | A30, R30, R31, T20-22, X20-21, X22-24. Detected by checking |
1000 | tp_features.hotkey_mask = | 1038 | for HKEY interface version 0x100 */ |
1001 | acpi_evalf(hkey_handle, NULL, "DHKN", "qv"); | 1039 | if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) { |
1040 | if ((hkeyv >> 8) != 1) { | ||
1041 | printk(IBM_ERR "unknown version of the " | ||
1042 | "HKEY interface: 0x%x\n", hkeyv); | ||
1043 | printk(IBM_ERR "please report this to %s\n", | ||
1044 | IBM_MAIL); | ||
1045 | } else { | ||
1046 | /* | ||
1047 | * MHKV 0x100 in A31, R40, R40e, | ||
1048 | * T4x, X31, and later | ||
1049 | * */ | ||
1050 | tp_features.hotkey_mask = 1; | ||
1051 | } | ||
1052 | } | ||
1002 | 1053 | ||
1003 | vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", | 1054 | vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", |
1004 | str_supported(tp_features.hotkey_mask)); | 1055 | str_supported(tp_features.hotkey_mask)); |
1005 | 1056 | ||
1006 | if (tp_features.hotkey_mask) { | 1057 | if (tp_features.hotkey_mask) { |
1007 | /* MHKA available in A31, R40, R40e, T4x, X31, and later */ | ||
1008 | if (!acpi_evalf(hkey_handle, &hotkey_all_mask, | 1058 | if (!acpi_evalf(hkey_handle, &hotkey_all_mask, |
1009 | "MHKA", "qd")) | 1059 | "MHKA", "qd")) { |
1060 | printk(IBM_ERR | ||
1061 | "missing MHKA handler, " | ||
1062 | "please report this to %s\n", | ||
1063 | IBM_MAIL); | ||
1010 | hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */ | 1064 | hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */ |
1065 | } | ||
1011 | } | 1066 | } |
1012 | 1067 | ||
1013 | res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask); | 1068 | res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask); |
@@ -1055,11 +1110,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
1055 | TPACPI_HOTKEY_MAP_SIZE); | 1110 | TPACPI_HOTKEY_MAP_SIZE); |
1056 | } | 1111 | } |
1057 | 1112 | ||
1058 | #ifndef CONFIG_THINKPAD_ACPI_INPUT_ENABLED | ||
1059 | for (i = 0; i < 12; i++) | ||
1060 | hotkey_keycode_map[i] = KEY_UNKNOWN; | ||
1061 | #endif /* ! CONFIG_THINKPAD_ACPI_INPUT_ENABLED */ | ||
1062 | |||
1063 | set_bit(EV_KEY, tpacpi_inputdev->evbit); | 1113 | set_bit(EV_KEY, tpacpi_inputdev->evbit); |
1064 | set_bit(EV_MSC, tpacpi_inputdev->evbit); | 1114 | set_bit(EV_MSC, tpacpi_inputdev->evbit); |
1065 | set_bit(MSC_SCAN, tpacpi_inputdev->mscbit); | 1115 | set_bit(MSC_SCAN, tpacpi_inputdev->mscbit); |
@@ -1081,14 +1131,17 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
1081 | set_bit(SW_RADIO, tpacpi_inputdev->swbit); | 1131 | set_bit(SW_RADIO, tpacpi_inputdev->swbit); |
1082 | } | 1132 | } |
1083 | 1133 | ||
1084 | #ifdef CONFIG_THINKPAD_ACPI_INPUT_ENABLED | ||
1085 | dbg_printk(TPACPI_DBG_INIT, | 1134 | dbg_printk(TPACPI_DBG_INIT, |
1086 | "enabling hot key handling\n"); | 1135 | "enabling hot key handling\n"); |
1087 | res = hotkey_set(1, (hotkey_all_mask & ~hotkey_reserved_mask) | 1136 | res = hotkey_set(1, (hotkey_all_mask & ~hotkey_reserved_mask) |
1088 | | hotkey_orig_mask); | 1137 | | hotkey_orig_mask); |
1089 | if (res) | 1138 | if (res) |
1090 | return res; | 1139 | return res; |
1091 | #endif /* CONFIG_THINKPAD_ACPI_INPUT_ENABLED */ | 1140 | |
1141 | dbg_printk(TPACPI_DBG_INIT, | ||
1142 | "legacy hot key reporting over procfs %s\n", | ||
1143 | (hotkey_report_mode < 2) ? | ||
1144 | "enabled" : "disabled"); | ||
1092 | } | 1145 | } |
1093 | 1146 | ||
1094 | return (tp_features.hotkey)? 0 : 1; | 1147 | return (tp_features.hotkey)? 0 : 1; |
@@ -1115,6 +1168,8 @@ static void tpacpi_input_send_key(unsigned int scancode, | |||
1115 | unsigned int keycode) | 1168 | unsigned int keycode) |
1116 | { | 1169 | { |
1117 | if (keycode != KEY_RESERVED) { | 1170 | if (keycode != KEY_RESERVED) { |
1171 | mutex_lock(&tpacpi_inputdev_send_mutex); | ||
1172 | |||
1118 | input_report_key(tpacpi_inputdev, keycode, 1); | 1173 | input_report_key(tpacpi_inputdev, keycode, 1); |
1119 | if (keycode == KEY_UNKNOWN) | 1174 | if (keycode == KEY_UNKNOWN) |
1120 | input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, | 1175 | input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, |
@@ -1126,6 +1181,8 @@ static void tpacpi_input_send_key(unsigned int scancode, | |||
1126 | input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, | 1181 | input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, |
1127 | scancode); | 1182 | scancode); |
1128 | input_sync(tpacpi_inputdev); | 1183 | input_sync(tpacpi_inputdev); |
1184 | |||
1185 | mutex_unlock(&tpacpi_inputdev_send_mutex); | ||
1129 | } | 1186 | } |
1130 | } | 1187 | } |
1131 | 1188 | ||
@@ -1133,67 +1190,102 @@ static void tpacpi_input_send_radiosw(void) | |||
1133 | { | 1190 | { |
1134 | int wlsw; | 1191 | int wlsw; |
1135 | 1192 | ||
1136 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) | 1193 | mutex_lock(&tpacpi_inputdev_send_mutex); |
1194 | |||
1195 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { | ||
1137 | input_report_switch(tpacpi_inputdev, | 1196 | input_report_switch(tpacpi_inputdev, |
1138 | SW_RADIO, !!wlsw); | 1197 | SW_RADIO, !!wlsw); |
1198 | input_sync(tpacpi_inputdev); | ||
1199 | } | ||
1200 | |||
1201 | mutex_unlock(&tpacpi_inputdev_send_mutex); | ||
1139 | } | 1202 | } |
1140 | 1203 | ||
1141 | static void hotkey_notify(struct ibm_struct *ibm, u32 event) | 1204 | static void hotkey_notify(struct ibm_struct *ibm, u32 event) |
1142 | { | 1205 | { |
1143 | u32 hkey; | 1206 | u32 hkey; |
1144 | unsigned int keycode, scancode; | 1207 | unsigned int keycode, scancode; |
1145 | int sendacpi = 1; | 1208 | int send_acpi_ev; |
1146 | 1209 | int ignore_acpi_ev; | |
1147 | if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { | 1210 | |
1148 | if (tpacpi_inputdev->users > 0) { | 1211 | if (event != 0x80) { |
1149 | switch (hkey >> 12) { | 1212 | printk(IBM_ERR "unknown HKEY notification event %d\n", event); |
1150 | case 1: | 1213 | /* forward it to userspace, maybe it knows how to handle it */ |
1151 | /* 0x1000-0x1FFF: key presses */ | 1214 | acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, |
1152 | scancode = hkey & 0xfff; | 1215 | ibm->acpi->device->dev.bus_id, |
1153 | if (scancode > 0 && scancode < 0x21) { | 1216 | event, 0); |
1154 | scancode--; | 1217 | return; |
1155 | keycode = hotkey_keycode_map[scancode]; | 1218 | } |
1156 | tpacpi_input_send_key(scancode, keycode); | 1219 | |
1157 | sendacpi = (keycode == KEY_RESERVED | 1220 | while (1) { |
1158 | || keycode == KEY_UNKNOWN); | 1221 | if (!acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { |
1159 | } else { | 1222 | printk(IBM_ERR "failed to retrieve HKEY event\n"); |
1160 | printk(IBM_ERR | 1223 | return; |
1161 | "hotkey 0x%04x out of range for keyboard map\n", | 1224 | } |
1162 | hkey); | 1225 | |
1163 | } | 1226 | if (hkey == 0) { |
1164 | break; | 1227 | /* queue empty */ |
1165 | case 5: | 1228 | return; |
1166 | /* 0x5000-0x5FFF: LID */ | 1229 | } |
1167 | /* we don't handle it through this path, just | 1230 | |
1168 | * eat up known LID events */ | 1231 | send_acpi_ev = 0; |
1169 | if (hkey != 0x5001 && hkey != 0x5002) { | 1232 | ignore_acpi_ev = 0; |
1170 | printk(IBM_ERR | 1233 | |
1171 | "unknown LID-related hotkey event: 0x%04x\n", | 1234 | switch (hkey >> 12) { |
1172 | hkey); | 1235 | case 1: |
1173 | } | 1236 | /* 0x1000-0x1FFF: key presses */ |
1237 | scancode = hkey & 0xfff; | ||
1238 | if (scancode > 0 && scancode < 0x21) { | ||
1239 | scancode--; | ||
1240 | keycode = hotkey_keycode_map[scancode]; | ||
1241 | tpacpi_input_send_key(scancode, keycode); | ||
1242 | } else { | ||
1243 | printk(IBM_ERR | ||
1244 | "hotkey 0x%04x out of range for keyboard map\n", | ||
1245 | hkey); | ||
1246 | send_acpi_ev = 1; | ||
1247 | } | ||
1248 | break; | ||
1249 | case 5: | ||
1250 | /* 0x5000-0x5FFF: LID */ | ||
1251 | /* we don't handle it through this path, just | ||
1252 | * eat up known LID events */ | ||
1253 | if (hkey != 0x5001 && hkey != 0x5002) { | ||
1254 | printk(IBM_ERR | ||
1255 | "unknown LID-related HKEY event: 0x%04x\n", | ||
1256 | hkey); | ||
1257 | send_acpi_ev = 1; | ||
1258 | } else { | ||
1259 | ignore_acpi_ev = 1; | ||
1260 | } | ||
1261 | break; | ||
1262 | case 7: | ||
1263 | /* 0x7000-0x7FFF: misc */ | ||
1264 | if (tp_features.hotkey_wlsw && hkey == 0x7000) { | ||
1265 | tpacpi_input_send_radiosw(); | ||
1174 | break; | 1266 | break; |
1175 | case 7: | ||
1176 | /* 0x7000-0x7FFF: misc */ | ||
1177 | if (tp_features.hotkey_wlsw && hkey == 0x7000) { | ||
1178 | tpacpi_input_send_radiosw(); | ||
1179 | sendacpi = 0; | ||
1180 | break; | ||
1181 | } | ||
1182 | /* fallthrough to default */ | ||
1183 | default: | ||
1184 | /* case 2: dock-related */ | ||
1185 | /* 0x2305 - T43 waking up due to bay lever eject while aslept */ | ||
1186 | /* case 3: ultra-bay related. maybe bay in dock? */ | ||
1187 | /* 0x3003 - T43 after wake up by bay lever eject (0x2305) */ | ||
1188 | printk(IBM_NOTICE "unhandled hotkey event 0x%04x\n", hkey); | ||
1189 | } | 1267 | } |
1268 | /* fallthrough to default */ | ||
1269 | default: | ||
1270 | /* case 2: dock-related */ | ||
1271 | /* 0x2305 - T43 waking up due to bay lever eject while aslept */ | ||
1272 | /* case 3: ultra-bay related. maybe bay in dock? */ | ||
1273 | /* 0x3003 - T43 after wake up by bay lever eject (0x2305) */ | ||
1274 | printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey); | ||
1275 | send_acpi_ev = 1; | ||
1190 | } | 1276 | } |
1191 | 1277 | ||
1192 | if (sendacpi) | 1278 | /* Legacy events */ |
1279 | if (!ignore_acpi_ev && (send_acpi_ev || hotkey_report_mode < 2)) { | ||
1193 | acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey); | 1280 | acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey); |
1194 | } else { | 1281 | } |
1195 | printk(IBM_ERR "unknown hotkey notification event %d\n", event); | 1282 | |
1196 | acpi_bus_generate_proc_event(ibm->acpi->device, event, 0); | 1283 | /* netlink events */ |
1284 | if (!ignore_acpi_ev && send_acpi_ev) { | ||
1285 | acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, | ||
1286 | ibm->acpi->device->dev.bus_id, | ||
1287 | event, hkey); | ||
1288 | } | ||
1197 | } | 1289 | } |
1198 | } | 1290 | } |
1199 | 1291 | ||
@@ -2789,7 +2881,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm) | |||
2789 | 2881 | ||
2790 | switch(thermal_read_mode) { | 2882 | switch(thermal_read_mode) { |
2791 | case TPACPI_THERMAL_TPEC_16: | 2883 | case TPACPI_THERMAL_TPEC_16: |
2792 | res = sysfs_create_group(&tpacpi_pdev->dev.kobj, | 2884 | res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, |
2793 | &thermal_temp_input16_group); | 2885 | &thermal_temp_input16_group); |
2794 | if (res) | 2886 | if (res) |
2795 | return res; | 2887 | return res; |
@@ -2797,7 +2889,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm) | |||
2797 | case TPACPI_THERMAL_TPEC_8: | 2889 | case TPACPI_THERMAL_TPEC_8: |
2798 | case TPACPI_THERMAL_ACPI_TMP07: | 2890 | case TPACPI_THERMAL_ACPI_TMP07: |
2799 | case TPACPI_THERMAL_ACPI_UPDT: | 2891 | case TPACPI_THERMAL_ACPI_UPDT: |
2800 | res = sysfs_create_group(&tpacpi_pdev->dev.kobj, | 2892 | res = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, |
2801 | &thermal_temp_input8_group); | 2893 | &thermal_temp_input8_group); |
2802 | if (res) | 2894 | if (res) |
2803 | return res; | 2895 | return res; |
@@ -2814,13 +2906,13 @@ static void thermal_exit(void) | |||
2814 | { | 2906 | { |
2815 | switch(thermal_read_mode) { | 2907 | switch(thermal_read_mode) { |
2816 | case TPACPI_THERMAL_TPEC_16: | 2908 | case TPACPI_THERMAL_TPEC_16: |
2817 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, | 2909 | sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, |
2818 | &thermal_temp_input16_group); | 2910 | &thermal_temp_input16_group); |
2819 | break; | 2911 | break; |
2820 | case TPACPI_THERMAL_TPEC_8: | 2912 | case TPACPI_THERMAL_TPEC_8: |
2821 | case TPACPI_THERMAL_ACPI_TMP07: | 2913 | case TPACPI_THERMAL_ACPI_TMP07: |
2822 | case TPACPI_THERMAL_ACPI_UPDT: | 2914 | case TPACPI_THERMAL_ACPI_UPDT: |
2823 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, | 2915 | sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, |
2824 | &thermal_temp_input16_group); | 2916 | &thermal_temp_input16_group); |
2825 | break; | 2917 | break; |
2826 | case TPACPI_THERMAL_NONE: | 2918 | case TPACPI_THERMAL_NONE: |
@@ -3603,7 +3695,7 @@ static struct device_attribute dev_attr_fan_fan1_input = | |||
3603 | __ATTR(fan1_input, S_IRUGO, | 3695 | __ATTR(fan1_input, S_IRUGO, |
3604 | fan_fan1_input_show, NULL); | 3696 | fan_fan1_input_show, NULL); |
3605 | 3697 | ||
3606 | /* sysfs fan fan_watchdog (driver) ------------------------------------- */ | 3698 | /* sysfs fan fan_watchdog (hwmon driver) ------------------------------- */ |
3607 | static ssize_t fan_fan_watchdog_show(struct device_driver *drv, | 3699 | static ssize_t fan_fan_watchdog_show(struct device_driver *drv, |
3608 | char *buf) | 3700 | char *buf) |
3609 | { | 3701 | { |
@@ -3745,10 +3837,10 @@ static int __init fan_init(struct ibm_init_struct *iibm) | |||
3745 | 3837 | ||
3746 | if (fan_status_access_mode != TPACPI_FAN_NONE || | 3838 | if (fan_status_access_mode != TPACPI_FAN_NONE || |
3747 | fan_control_access_mode != TPACPI_FAN_WR_NONE) { | 3839 | fan_control_access_mode != TPACPI_FAN_WR_NONE) { |
3748 | rc = sysfs_create_group(&tpacpi_pdev->dev.kobj, | 3840 | rc = sysfs_create_group(&tpacpi_sensors_pdev->dev.kobj, |
3749 | &fan_attr_group); | 3841 | &fan_attr_group); |
3750 | if (!(rc < 0)) | 3842 | if (!(rc < 0)) |
3751 | rc = driver_create_file(&tpacpi_pdriver.driver, | 3843 | rc = driver_create_file(&tpacpi_hwmon_pdriver.driver, |
3752 | &driver_attr_fan_watchdog); | 3844 | &driver_attr_fan_watchdog); |
3753 | if (rc < 0) | 3845 | if (rc < 0) |
3754 | return rc; | 3846 | return rc; |
@@ -3831,8 +3923,8 @@ static void fan_exit(void) | |||
3831 | vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n"); | 3923 | vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n"); |
3832 | 3924 | ||
3833 | /* FIXME: can we really do this unconditionally? */ | 3925 | /* FIXME: can we really do this unconditionally? */ |
3834 | sysfs_remove_group(&tpacpi_pdev->dev.kobj, &fan_attr_group); | 3926 | sysfs_remove_group(&tpacpi_sensors_pdev->dev.kobj, &fan_attr_group); |
3835 | driver_remove_file(&tpacpi_pdriver.driver, &driver_attr_fan_watchdog); | 3927 | driver_remove_file(&tpacpi_hwmon_pdriver.driver, &driver_attr_fan_watchdog); |
3836 | 3928 | ||
3837 | cancel_delayed_work(&fan_watchdog_task); | 3929 | cancel_delayed_work(&fan_watchdog_task); |
3838 | flush_scheduled_work(); | 3930 | flush_scheduled_work(); |
@@ -3865,6 +3957,9 @@ static void fan_watchdog_fire(struct work_struct *ignored) | |||
3865 | { | 3957 | { |
3866 | int rc; | 3958 | int rc; |
3867 | 3959 | ||
3960 | if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING) | ||
3961 | return; | ||
3962 | |||
3868 | printk(IBM_NOTICE "fan watchdog: enabling fan\n"); | 3963 | printk(IBM_NOTICE "fan watchdog: enabling fan\n"); |
3869 | rc = fan_set_enable(); | 3964 | rc = fan_set_enable(); |
3870 | if (rc < 0) { | 3965 | if (rc < 0) { |
@@ -3885,7 +3980,8 @@ static void fan_watchdog_reset(void) | |||
3885 | if (fan_watchdog_active) | 3980 | if (fan_watchdog_active) |
3886 | cancel_delayed_work(&fan_watchdog_task); | 3981 | cancel_delayed_work(&fan_watchdog_task); |
3887 | 3982 | ||
3888 | if (fan_watchdog_maxinterval > 0) { | 3983 | if (fan_watchdog_maxinterval > 0 && |
3984 | tpacpi_lifecycle != TPACPI_LIFE_EXITING) { | ||
3889 | fan_watchdog_active = 1; | 3985 | fan_watchdog_active = 1; |
3890 | if (!schedule_delayed_work(&fan_watchdog_task, | 3986 | if (!schedule_delayed_work(&fan_watchdog_task, |
3891 | msecs_to_jiffies(fan_watchdog_maxinterval | 3987 | msecs_to_jiffies(fan_watchdog_maxinterval |
@@ -4279,6 +4375,19 @@ static struct ibm_struct fan_driver_data = { | |||
4279 | **************************************************************************** | 4375 | **************************************************************************** |
4280 | ****************************************************************************/ | 4376 | ****************************************************************************/ |
4281 | 4377 | ||
4378 | /* sysfs name ---------------------------------------------------------- */ | ||
4379 | static ssize_t thinkpad_acpi_pdev_name_show(struct device *dev, | ||
4380 | struct device_attribute *attr, | ||
4381 | char *buf) | ||
4382 | { | ||
4383 | return snprintf(buf, PAGE_SIZE, "%s\n", IBM_NAME); | ||
4384 | } | ||
4385 | |||
4386 | static struct device_attribute dev_attr_thinkpad_acpi_pdev_name = | ||
4387 | __ATTR(name, S_IRUGO, thinkpad_acpi_pdev_name_show, NULL); | ||
4388 | |||
4389 | /* --------------------------------------------------------------------- */ | ||
4390 | |||
4282 | /* /proc support */ | 4391 | /* /proc support */ |
4283 | static struct proc_dir_entry *proc_dir; | 4392 | static struct proc_dir_entry *proc_dir; |
4284 | 4393 | ||
@@ -4623,6 +4732,9 @@ module_param_named(fan_control, fan_control_allowed, bool, 0); | |||
4623 | static int brightness_mode; | 4732 | static int brightness_mode; |
4624 | module_param_named(brightness_mode, brightness_mode, int, 0); | 4733 | module_param_named(brightness_mode, brightness_mode, int, 0); |
4625 | 4734 | ||
4735 | static unsigned int hotkey_report_mode; | ||
4736 | module_param(hotkey_report_mode, uint, 0); | ||
4737 | |||
4626 | #define IBM_PARAM(feature) \ | 4738 | #define IBM_PARAM(feature) \ |
4627 | module_param_call(feature, set_ibm_param, NULL, NULL, 0) | 4739 | module_param_call(feature, set_ibm_param, NULL, NULL, 0) |
4628 | 4740 | ||
@@ -4648,6 +4760,12 @@ static int __init thinkpad_acpi_module_init(void) | |||
4648 | { | 4760 | { |
4649 | int ret, i; | 4761 | int ret, i; |
4650 | 4762 | ||
4763 | tpacpi_lifecycle = TPACPI_LIFE_INIT; | ||
4764 | |||
4765 | /* Parameter checking */ | ||
4766 | if (hotkey_report_mode > 2) | ||
4767 | return -EINVAL; | ||
4768 | |||
4651 | /* Driver-level probe */ | 4769 | /* Driver-level probe */ |
4652 | 4770 | ||
4653 | get_thinkpad_model_data(&thinkpad_id); | 4771 | get_thinkpad_model_data(&thinkpad_id); |
@@ -4672,19 +4790,31 @@ static int __init thinkpad_acpi_module_init(void) | |||
4672 | 4790 | ||
4673 | ret = platform_driver_register(&tpacpi_pdriver); | 4791 | ret = platform_driver_register(&tpacpi_pdriver); |
4674 | if (ret) { | 4792 | if (ret) { |
4675 | printk(IBM_ERR "unable to register platform driver\n"); | 4793 | printk(IBM_ERR "unable to register main platform driver\n"); |
4676 | thinkpad_acpi_module_exit(); | 4794 | thinkpad_acpi_module_exit(); |
4677 | return ret; | 4795 | return ret; |
4678 | } | 4796 | } |
4679 | tp_features.platform_drv_registered = 1; | 4797 | tp_features.platform_drv_registered = 1; |
4680 | 4798 | ||
4799 | ret = platform_driver_register(&tpacpi_hwmon_pdriver); | ||
4800 | if (ret) { | ||
4801 | printk(IBM_ERR "unable to register hwmon platform driver\n"); | ||
4802 | thinkpad_acpi_module_exit(); | ||
4803 | return ret; | ||
4804 | } | ||
4805 | tp_features.sensors_pdrv_registered = 1; | ||
4806 | |||
4681 | ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver); | 4807 | ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver); |
4808 | if (!ret) { | ||
4809 | tp_features.platform_drv_attrs_registered = 1; | ||
4810 | ret = tpacpi_create_driver_attributes(&tpacpi_hwmon_pdriver.driver); | ||
4811 | } | ||
4682 | if (ret) { | 4812 | if (ret) { |
4683 | printk(IBM_ERR "unable to create sysfs driver attributes\n"); | 4813 | printk(IBM_ERR "unable to create sysfs driver attributes\n"); |
4684 | thinkpad_acpi_module_exit(); | 4814 | thinkpad_acpi_module_exit(); |
4685 | return ret; | 4815 | return ret; |
4686 | } | 4816 | } |
4687 | tp_features.platform_drv_attrs_registered = 1; | 4817 | tp_features.sensors_pdrv_attrs_registered = 1; |
4688 | 4818 | ||
4689 | 4819 | ||
4690 | /* Device initialization */ | 4820 | /* Device initialization */ |
@@ -4697,7 +4827,26 @@ static int __init thinkpad_acpi_module_init(void) | |||
4697 | thinkpad_acpi_module_exit(); | 4827 | thinkpad_acpi_module_exit(); |
4698 | return ret; | 4828 | return ret; |
4699 | } | 4829 | } |
4700 | tpacpi_hwmon = hwmon_device_register(&tpacpi_pdev->dev); | 4830 | tpacpi_sensors_pdev = platform_device_register_simple( |
4831 | IBM_HWMON_DRVR_NAME, | ||
4832 | -1, NULL, 0); | ||
4833 | if (IS_ERR(tpacpi_sensors_pdev)) { | ||
4834 | ret = PTR_ERR(tpacpi_sensors_pdev); | ||
4835 | tpacpi_sensors_pdev = NULL; | ||
4836 | printk(IBM_ERR "unable to register hwmon platform device\n"); | ||
4837 | thinkpad_acpi_module_exit(); | ||
4838 | return ret; | ||
4839 | } | ||
4840 | ret = device_create_file(&tpacpi_sensors_pdev->dev, | ||
4841 | &dev_attr_thinkpad_acpi_pdev_name); | ||
4842 | if (ret) { | ||
4843 | printk(IBM_ERR | ||
4844 | "unable to create sysfs hwmon device attributes\n"); | ||
4845 | thinkpad_acpi_module_exit(); | ||
4846 | return ret; | ||
4847 | } | ||
4848 | tp_features.sensors_pdev_attrs_registered = 1; | ||
4849 | tpacpi_hwmon = hwmon_device_register(&tpacpi_sensors_pdev->dev); | ||
4701 | if (IS_ERR(tpacpi_hwmon)) { | 4850 | if (IS_ERR(tpacpi_hwmon)) { |
4702 | ret = PTR_ERR(tpacpi_hwmon); | 4851 | ret = PTR_ERR(tpacpi_hwmon); |
4703 | tpacpi_hwmon = NULL; | 4852 | tpacpi_hwmon = NULL; |
@@ -4705,6 +4854,7 @@ static int __init thinkpad_acpi_module_init(void) | |||
4705 | thinkpad_acpi_module_exit(); | 4854 | thinkpad_acpi_module_exit(); |
4706 | return ret; | 4855 | return ret; |
4707 | } | 4856 | } |
4857 | mutex_init(&tpacpi_inputdev_send_mutex); | ||
4708 | tpacpi_inputdev = input_allocate_device(); | 4858 | tpacpi_inputdev = input_allocate_device(); |
4709 | if (!tpacpi_inputdev) { | 4859 | if (!tpacpi_inputdev) { |
4710 | printk(IBM_ERR "unable to allocate input device\n"); | 4860 | printk(IBM_ERR "unable to allocate input device\n"); |
@@ -4739,6 +4889,7 @@ static int __init thinkpad_acpi_module_init(void) | |||
4739 | tp_features.input_device_registered = 1; | 4889 | tp_features.input_device_registered = 1; |
4740 | } | 4890 | } |
4741 | 4891 | ||
4892 | tpacpi_lifecycle = TPACPI_LIFE_RUNNING; | ||
4742 | return 0; | 4893 | return 0; |
4743 | } | 4894 | } |
4744 | 4895 | ||
@@ -4746,6 +4897,8 @@ static void thinkpad_acpi_module_exit(void) | |||
4746 | { | 4897 | { |
4747 | struct ibm_struct *ibm, *itmp; | 4898 | struct ibm_struct *ibm, *itmp; |
4748 | 4899 | ||
4900 | tpacpi_lifecycle = TPACPI_LIFE_EXITING; | ||
4901 | |||
4749 | list_for_each_entry_safe_reverse(ibm, itmp, | 4902 | list_for_each_entry_safe_reverse(ibm, itmp, |
4750 | &tpacpi_all_drivers, | 4903 | &tpacpi_all_drivers, |
4751 | all_drivers) { | 4904 | all_drivers) { |
@@ -4764,12 +4917,22 @@ static void thinkpad_acpi_module_exit(void) | |||
4764 | if (tpacpi_hwmon) | 4917 | if (tpacpi_hwmon) |
4765 | hwmon_device_unregister(tpacpi_hwmon); | 4918 | hwmon_device_unregister(tpacpi_hwmon); |
4766 | 4919 | ||
4920 | if (tp_features.sensors_pdev_attrs_registered) | ||
4921 | device_remove_file(&tpacpi_sensors_pdev->dev, | ||
4922 | &dev_attr_thinkpad_acpi_pdev_name); | ||
4923 | if (tpacpi_sensors_pdev) | ||
4924 | platform_device_unregister(tpacpi_sensors_pdev); | ||
4767 | if (tpacpi_pdev) | 4925 | if (tpacpi_pdev) |
4768 | platform_device_unregister(tpacpi_pdev); | 4926 | platform_device_unregister(tpacpi_pdev); |
4769 | 4927 | ||
4928 | if (tp_features.sensors_pdrv_attrs_registered) | ||
4929 | tpacpi_remove_driver_attributes(&tpacpi_hwmon_pdriver.driver); | ||
4770 | if (tp_features.platform_drv_attrs_registered) | 4930 | if (tp_features.platform_drv_attrs_registered) |
4771 | tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver); | 4931 | tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver); |
4772 | 4932 | ||
4933 | if (tp_features.sensors_pdrv_registered) | ||
4934 | platform_driver_unregister(&tpacpi_hwmon_pdriver); | ||
4935 | |||
4773 | if (tp_features.platform_drv_registered) | 4936 | if (tp_features.platform_drv_registered) |
4774 | platform_driver_unregister(&tpacpi_pdriver); | 4937 | platform_driver_unregister(&tpacpi_pdriver); |
4775 | 4938 | ||
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index eee8809a50d9..c5fdd688cc99 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h | |||
@@ -58,13 +58,14 @@ | |||
58 | 58 | ||
59 | #define IBM_NAME "thinkpad" | 59 | #define IBM_NAME "thinkpad" |
60 | #define IBM_DESC "ThinkPad ACPI Extras" | 60 | #define IBM_DESC "ThinkPad ACPI Extras" |
61 | #define IBM_FILE "thinkpad_acpi" | 61 | #define IBM_FILE IBM_NAME "_acpi" |
62 | #define IBM_URL "http://ibm-acpi.sf.net/" | 62 | #define IBM_URL "http://ibm-acpi.sf.net/" |
63 | #define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net" | 63 | #define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net" |
64 | 64 | ||
65 | #define IBM_PROC_DIR "ibm" | 65 | #define IBM_PROC_DIR "ibm" |
66 | #define IBM_ACPI_EVENT_PREFIX "ibm" | 66 | #define IBM_ACPI_EVENT_PREFIX "ibm" |
67 | #define IBM_DRVR_NAME IBM_FILE | 67 | #define IBM_DRVR_NAME IBM_FILE |
68 | #define IBM_HWMON_DRVR_NAME IBM_NAME "_hwmon" | ||
68 | 69 | ||
69 | #define IBM_LOG IBM_FILE ": " | 70 | #define IBM_LOG IBM_FILE ": " |
70 | #define IBM_ERR KERN_ERR IBM_LOG | 71 | #define IBM_ERR KERN_ERR IBM_LOG |
@@ -171,6 +172,7 @@ static int parse_strtoul(const char *buf, unsigned long max, | |||
171 | 172 | ||
172 | /* Device model */ | 173 | /* Device model */ |
173 | static struct platform_device *tpacpi_pdev; | 174 | static struct platform_device *tpacpi_pdev; |
175 | static struct platform_device *tpacpi_sensors_pdev; | ||
174 | static struct class_device *tpacpi_hwmon; | 176 | static struct class_device *tpacpi_hwmon; |
175 | static struct platform_driver tpacpi_pdriver; | 177 | static struct platform_driver tpacpi_pdriver; |
176 | static struct input_dev *tpacpi_inputdev; | 178 | static struct input_dev *tpacpi_inputdev; |
@@ -181,6 +183,7 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv); | |||
181 | static int experimental; | 183 | static int experimental; |
182 | static u32 dbg_level; | 184 | static u32 dbg_level; |
183 | static int force_load; | 185 | static int force_load; |
186 | static unsigned int hotkey_report_mode; | ||
184 | 187 | ||
185 | static int thinkpad_acpi_module_init(void); | 188 | static int thinkpad_acpi_module_init(void); |
186 | static void thinkpad_acpi_module_exit(void); | 189 | static void thinkpad_acpi_module_exit(void); |
@@ -232,22 +235,25 @@ struct ibm_init_struct { | |||
232 | 235 | ||
233 | static struct { | 236 | static struct { |
234 | #ifdef CONFIG_THINKPAD_ACPI_BAY | 237 | #ifdef CONFIG_THINKPAD_ACPI_BAY |
235 | u16 bay_status:1; | 238 | u32 bay_status:1; |
236 | u16 bay_eject:1; | 239 | u32 bay_eject:1; |
237 | u16 bay_status2:1; | 240 | u32 bay_status2:1; |
238 | u16 bay_eject2:1; | 241 | u32 bay_eject2:1; |
239 | #endif | 242 | #endif |
240 | u16 bluetooth:1; | 243 | u32 bluetooth:1; |
241 | u16 hotkey:1; | 244 | u32 hotkey:1; |
242 | u16 hotkey_mask:1; | 245 | u32 hotkey_mask:1; |
243 | u16 hotkey_wlsw:1; | 246 | u32 hotkey_wlsw:1; |
244 | u16 light:1; | 247 | u32 light:1; |
245 | u16 light_status:1; | 248 | u32 light_status:1; |
246 | u16 wan:1; | 249 | u32 wan:1; |
247 | u16 fan_ctrl_status_undef:1; | 250 | u32 fan_ctrl_status_undef:1; |
248 | u16 input_device_registered:1; | 251 | u32 input_device_registered:1; |
249 | u16 platform_drv_registered:1; | 252 | u32 platform_drv_registered:1; |
250 | u16 platform_drv_attrs_registered:1; | 253 | u32 platform_drv_attrs_registered:1; |
254 | u32 sensors_pdrv_registered:1; | ||
255 | u32 sensors_pdrv_attrs_registered:1; | ||
256 | u32 sensors_pdev_attrs_registered:1; | ||
251 | } tp_features; | 257 | } tp_features; |
252 | 258 | ||
253 | struct thinkpad_id_data { | 259 | struct thinkpad_id_data { |