diff options
Diffstat (limited to 'drivers')
65 files changed, 4776 insertions, 803 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 139f41f033..408b45168a 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig | |||
@@ -2,16 +2,12 @@ | |||
2 | # ACPI Configuration | 2 | # ACPI Configuration |
3 | # | 3 | # |
4 | 4 | ||
5 | menu "ACPI (Advanced Configuration and Power Interface) Support" | 5 | menuconfig ACPI |
6 | bool "ACPI Support (Advanced Configuration and Power Interface) Support" | ||
6 | depends on !X86_NUMAQ | 7 | depends on !X86_NUMAQ |
7 | depends on !X86_VISWS | 8 | depends on !X86_VISWS |
8 | depends on !IA64_HP_SIM | 9 | depends on !IA64_HP_SIM |
9 | depends on IA64 || X86 | 10 | depends on IA64 || X86 |
10 | depends on PM | ||
11 | |||
12 | config ACPI | ||
13 | bool "ACPI Support" | ||
14 | depends on IA64 || X86 | ||
15 | depends on PCI | 11 | depends on PCI |
16 | depends on PM | 12 | depends on PM |
17 | select PNP | 13 | select PNP |
@@ -49,7 +45,6 @@ if ACPI | |||
49 | config ACPI_SLEEP | 45 | config ACPI_SLEEP |
50 | bool "Sleep States" | 46 | bool "Sleep States" |
51 | depends on X86 && (!SMP || SUSPEND_SMP) | 47 | depends on X86 && (!SMP || SUSPEND_SMP) |
52 | depends on PM | ||
53 | default y | 48 | default y |
54 | ---help--- | 49 | ---help--- |
55 | This option adds support for ACPI suspend states. | 50 | This option adds support for ACPI suspend states. |
@@ -82,7 +77,6 @@ config ACPI_SLEEP_PROC_SLEEP | |||
82 | 77 | ||
83 | config ACPI_PROCFS | 78 | config ACPI_PROCFS |
84 | bool "Procfs interface (deprecated)" | 79 | bool "Procfs interface (deprecated)" |
85 | depends on ACPI | ||
86 | default y | 80 | default y |
87 | ---help--- | 81 | ---help--- |
88 | The Procfs interface for ACPI is made optional for backward compatibility. | 82 | The Procfs interface for ACPI is made optional for backward compatibility. |
@@ -124,7 +118,7 @@ config ACPI_BUTTON | |||
124 | 118 | ||
125 | config ACPI_VIDEO | 119 | config ACPI_VIDEO |
126 | tristate "Video" | 120 | tristate "Video" |
127 | depends on X86 && BACKLIGHT_CLASS_DEVICE | 121 | depends on X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL |
128 | help | 122 | help |
129 | This driver implement the ACPI Extensions For Display Adapters | 123 | This driver implement the ACPI Extensions For Display Adapters |
130 | for integrated graphics devices on motherboard, as specified in | 124 | for integrated graphics devices on motherboard, as specified in |
@@ -280,6 +274,14 @@ config ACPI_DEBUG | |||
280 | of verbosity. Saying Y enables these statements. This will increase | 274 | of verbosity. Saying Y enables these statements. This will increase |
281 | your kernel size by around 50K. | 275 | your kernel size by around 50K. |
282 | 276 | ||
277 | config ACPI_DEBUG_FUNC_TRACE | ||
278 | bool "Additionally enable ACPI function tracing" | ||
279 | default n | ||
280 | depends on ACPI_DEBUG | ||
281 | help | ||
282 | ACPI Debug Statements slow down ACPI processing. Function trace | ||
283 | is about half of the penalty and is rarely useful. | ||
284 | |||
283 | config ACPI_EC | 285 | config ACPI_EC |
284 | bool | 286 | bool |
285 | default y | 287 | default y |
@@ -330,7 +332,6 @@ config ACPI_CONTAINER | |||
330 | 332 | ||
331 | config ACPI_HOTPLUG_MEMORY | 333 | config ACPI_HOTPLUG_MEMORY |
332 | tristate "Memory Hotplug" | 334 | tristate "Memory Hotplug" |
333 | depends on ACPI | ||
334 | depends on MEMORY_HOTPLUG | 335 | depends on MEMORY_HOTPLUG |
335 | default n | 336 | default n |
336 | help | 337 | help |
@@ -359,5 +360,3 @@ config ACPI_SBS | |||
359 | to today's ACPI "Control Method" battery. | 360 | to today's ACPI "Control Method" battery. |
360 | 361 | ||
361 | endif # ACPI | 362 | endif # ACPI |
362 | |||
363 | endmenu | ||
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index e64c76c8b7..cad932de38 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c | |||
@@ -43,21 +43,30 @@ | |||
43 | #define ACPI_BATTERY_CLASS "battery" | 43 | #define ACPI_BATTERY_CLASS "battery" |
44 | #define ACPI_BATTERY_HID "PNP0C0A" | 44 | #define ACPI_BATTERY_HID "PNP0C0A" |
45 | #define ACPI_BATTERY_DEVICE_NAME "Battery" | 45 | #define ACPI_BATTERY_DEVICE_NAME "Battery" |
46 | #define ACPI_BATTERY_FILE_INFO "info" | ||
47 | #define ACPI_BATTERY_FILE_STATUS "state" | ||
48 | #define ACPI_BATTERY_FILE_ALARM "alarm" | ||
49 | #define ACPI_BATTERY_NOTIFY_STATUS 0x80 | 46 | #define ACPI_BATTERY_NOTIFY_STATUS 0x80 |
50 | #define ACPI_BATTERY_NOTIFY_INFO 0x81 | 47 | #define ACPI_BATTERY_NOTIFY_INFO 0x81 |
51 | #define ACPI_BATTERY_UNITS_WATTS "mW" | 48 | #define ACPI_BATTERY_UNITS_WATTS "mW" |
52 | #define ACPI_BATTERY_UNITS_AMPS "mA" | 49 | #define ACPI_BATTERY_UNITS_AMPS "mA" |
53 | 50 | ||
54 | #define _COMPONENT ACPI_BATTERY_COMPONENT | 51 | #define _COMPONENT ACPI_BATTERY_COMPONENT |
52 | |||
53 | #define ACPI_BATTERY_UPDATE_TIME 0 | ||
54 | |||
55 | #define ACPI_BATTERY_NONE_UPDATE 0 | ||
56 | #define ACPI_BATTERY_EASY_UPDATE 1 | ||
57 | #define ACPI_BATTERY_INIT_UPDATE 2 | ||
58 | |||
55 | ACPI_MODULE_NAME("battery"); | 59 | ACPI_MODULE_NAME("battery"); |
56 | 60 | ||
57 | MODULE_AUTHOR("Paul Diefenbaugh"); | 61 | MODULE_AUTHOR("Paul Diefenbaugh"); |
58 | MODULE_DESCRIPTION("ACPI Battery Driver"); | 62 | MODULE_DESCRIPTION("ACPI Battery Driver"); |
59 | MODULE_LICENSE("GPL"); | 63 | MODULE_LICENSE("GPL"); |
60 | 64 | ||
65 | static unsigned int update_time = ACPI_BATTERY_UPDATE_TIME; | ||
66 | |||
67 | /* 0 - every time, > 0 - by update_time */ | ||
68 | module_param(update_time, uint, 0644); | ||
69 | |||
61 | extern struct proc_dir_entry *acpi_lock_battery_dir(void); | 70 | extern struct proc_dir_entry *acpi_lock_battery_dir(void); |
62 | extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); | 71 | extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir); |
63 | 72 | ||
@@ -76,7 +85,7 @@ static struct acpi_driver acpi_battery_driver = { | |||
76 | }, | 85 | }, |
77 | }; | 86 | }; |
78 | 87 | ||
79 | struct acpi_battery_status { | 88 | struct acpi_battery_state { |
80 | acpi_integer state; | 89 | acpi_integer state; |
81 | acpi_integer present_rate; | 90 | acpi_integer present_rate; |
82 | acpi_integer remaining_capacity; | 91 | acpi_integer remaining_capacity; |
@@ -99,33 +108,111 @@ struct acpi_battery_info { | |||
99 | acpi_string oem_info; | 108 | acpi_string oem_info; |
100 | }; | 109 | }; |
101 | 110 | ||
102 | struct acpi_battery_flags { | 111 | enum acpi_battery_files{ |
103 | u8 present:1; /* Bay occupied? */ | 112 | ACPI_BATTERY_INFO = 0, |
104 | u8 power_unit:1; /* 0=watts, 1=apms */ | 113 | ACPI_BATTERY_STATE, |
105 | u8 alarm:1; /* _BTP present? */ | 114 | ACPI_BATTERY_ALARM, |
106 | u8 reserved:5; | 115 | ACPI_BATTERY_NUMFILES, |
107 | }; | 116 | }; |
108 | 117 | ||
109 | struct acpi_battery_trips { | 118 | struct acpi_battery_flags { |
110 | unsigned long warning; | 119 | u8 battery_present_prev; |
111 | unsigned long low; | 120 | u8 alarm_present; |
121 | u8 init_update; | ||
122 | u8 update[ACPI_BATTERY_NUMFILES]; | ||
123 | u8 power_unit; | ||
112 | }; | 124 | }; |
113 | 125 | ||
114 | struct acpi_battery { | 126 | struct acpi_battery { |
115 | struct acpi_device * device; | 127 | struct mutex mutex; |
128 | struct acpi_device *device; | ||
116 | struct acpi_battery_flags flags; | 129 | struct acpi_battery_flags flags; |
117 | struct acpi_battery_trips trips; | 130 | struct acpi_buffer bif_data; |
131 | struct acpi_buffer bst_data; | ||
118 | unsigned long alarm; | 132 | unsigned long alarm; |
119 | struct acpi_battery_info *info; | 133 | unsigned long update_time[ACPI_BATTERY_NUMFILES]; |
120 | }; | 134 | }; |
121 | 135 | ||
136 | inline int acpi_battery_present(struct acpi_battery *battery) | ||
137 | { | ||
138 | return battery->device->status.battery_present; | ||
139 | } | ||
140 | inline char *acpi_battery_power_units(struct acpi_battery *battery) | ||
141 | { | ||
142 | if (battery->flags.power_unit) | ||
143 | return ACPI_BATTERY_UNITS_AMPS; | ||
144 | else | ||
145 | return ACPI_BATTERY_UNITS_WATTS; | ||
146 | } | ||
147 | |||
148 | inline acpi_handle acpi_battery_handle(struct acpi_battery *battery) | ||
149 | { | ||
150 | return battery->device->handle; | ||
151 | } | ||
152 | |||
122 | /* -------------------------------------------------------------------------- | 153 | /* -------------------------------------------------------------------------- |
123 | Battery Management | 154 | Battery Management |
124 | -------------------------------------------------------------------------- */ | 155 | -------------------------------------------------------------------------- */ |
125 | 156 | ||
126 | static int | 157 | static void acpi_battery_check_result(struct acpi_battery *battery, int result) |
127 | acpi_battery_get_info(struct acpi_battery *battery, | 158 | { |
128 | struct acpi_battery_info **bif) | 159 | if (!battery) |
160 | return; | ||
161 | |||
162 | if (result) { | ||
163 | battery->flags.init_update = 1; | ||
164 | } | ||
165 | } | ||
166 | |||
167 | static int acpi_battery_extract_package(struct acpi_battery *battery, | ||
168 | union acpi_object *package, | ||
169 | struct acpi_buffer *format, | ||
170 | struct acpi_buffer *data, | ||
171 | char *package_name) | ||
172 | { | ||
173 | acpi_status status = AE_OK; | ||
174 | struct acpi_buffer data_null = { 0, NULL }; | ||
175 | |||
176 | status = acpi_extract_package(package, format, &data_null); | ||
177 | if (status != AE_BUFFER_OVERFLOW) { | ||
178 | ACPI_EXCEPTION((AE_INFO, status, "Extracting size %s", | ||
179 | package_name)); | ||
180 | return -ENODEV; | ||
181 | } | ||
182 | |||
183 | if (data_null.length != data->length) { | ||
184 | kfree(data->pointer); | ||
185 | data->pointer = kzalloc(data_null.length, GFP_KERNEL); | ||
186 | if (!data->pointer) { | ||
187 | ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "kzalloc()")); | ||
188 | return -ENOMEM; | ||
189 | } | ||
190 | data->length = data_null.length; | ||
191 | } | ||
192 | |||
193 | status = acpi_extract_package(package, format, data); | ||
194 | if (ACPI_FAILURE(status)) { | ||
195 | ACPI_EXCEPTION((AE_INFO, status, "Extracting %s", | ||
196 | package_name)); | ||
197 | return -ENODEV; | ||
198 | } | ||
199 | |||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | static int acpi_battery_get_status(struct acpi_battery *battery) | ||
204 | { | ||
205 | int result = 0; | ||
206 | |||
207 | result = acpi_bus_get_status(battery->device); | ||
208 | if (result) { | ||
209 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Evaluating _STA")); | ||
210 | return -ENODEV; | ||
211 | } | ||
212 | return result; | ||
213 | } | ||
214 | |||
215 | static int acpi_battery_get_info(struct acpi_battery *battery) | ||
129 | { | 216 | { |
130 | int result = 0; | 217 | int result = 0; |
131 | acpi_status status = 0; | 218 | acpi_status status = 0; |
@@ -133,16 +220,20 @@ acpi_battery_get_info(struct acpi_battery *battery, | |||
133 | struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BIF), | 220 | struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BIF), |
134 | ACPI_BATTERY_FORMAT_BIF | 221 | ACPI_BATTERY_FORMAT_BIF |
135 | }; | 222 | }; |
136 | struct acpi_buffer data = { 0, NULL }; | ||
137 | union acpi_object *package = NULL; | 223 | union acpi_object *package = NULL; |
224 | struct acpi_buffer *data = NULL; | ||
225 | struct acpi_battery_info *bif = NULL; | ||
138 | 226 | ||
227 | battery->update_time[ACPI_BATTERY_INFO] = get_seconds(); | ||
139 | 228 | ||
140 | if (!battery || !bif) | 229 | if (!acpi_battery_present(battery)) |
141 | return -EINVAL; | 230 | return 0; |
142 | 231 | ||
143 | /* Evalute _BIF */ | 232 | /* Evaluate _BIF */ |
144 | 233 | ||
145 | status = acpi_evaluate_object(battery->device->handle, "_BIF", NULL, &buffer); | 234 | status = |
235 | acpi_evaluate_object(acpi_battery_handle(battery), "_BIF", NULL, | ||
236 | &buffer); | ||
146 | if (ACPI_FAILURE(status)) { | 237 | if (ACPI_FAILURE(status)) { |
147 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF")); | 238 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF")); |
148 | return -ENODEV; | 239 | return -ENODEV; |
@@ -150,41 +241,29 @@ acpi_battery_get_info(struct acpi_battery *battery, | |||
150 | 241 | ||
151 | package = buffer.pointer; | 242 | package = buffer.pointer; |
152 | 243 | ||
153 | /* Extract Package Data */ | 244 | data = &battery->bif_data; |
154 | |||
155 | status = acpi_extract_package(package, &format, &data); | ||
156 | if (status != AE_BUFFER_OVERFLOW) { | ||
157 | ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF")); | ||
158 | result = -ENODEV; | ||
159 | goto end; | ||
160 | } | ||
161 | 245 | ||
162 | data.pointer = kzalloc(data.length, GFP_KERNEL); | 246 | /* Extract Package Data */ |
163 | if (!data.pointer) { | ||
164 | result = -ENOMEM; | ||
165 | goto end; | ||
166 | } | ||
167 | 247 | ||
168 | status = acpi_extract_package(package, &format, &data); | 248 | result = |
169 | if (ACPI_FAILURE(status)) { | 249 | acpi_battery_extract_package(battery, package, &format, data, |
170 | ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF")); | 250 | "_BIF"); |
171 | kfree(data.pointer); | 251 | if (result) |
172 | result = -ENODEV; | ||
173 | goto end; | 252 | goto end; |
174 | } | ||
175 | 253 | ||
176 | end: | 254 | end: |
255 | |||
177 | kfree(buffer.pointer); | 256 | kfree(buffer.pointer); |
178 | 257 | ||
179 | if (!result) | 258 | if (!result) { |
180 | (*bif) = data.pointer; | 259 | bif = data->pointer; |
260 | battery->flags.power_unit = bif->power_unit; | ||
261 | } | ||
181 | 262 | ||
182 | return result; | 263 | return result; |
183 | } | 264 | } |
184 | 265 | ||
185 | static int | 266 | static int acpi_battery_get_state(struct acpi_battery *battery) |
186 | acpi_battery_get_status(struct acpi_battery *battery, | ||
187 | struct acpi_battery_status **bst) | ||
188 | { | 267 | { |
189 | int result = 0; | 268 | int result = 0; |
190 | acpi_status status = 0; | 269 | acpi_status status = 0; |
@@ -192,16 +271,19 @@ acpi_battery_get_status(struct acpi_battery *battery, | |||
192 | struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BST), | 271 | struct acpi_buffer format = { sizeof(ACPI_BATTERY_FORMAT_BST), |
193 | ACPI_BATTERY_FORMAT_BST | 272 | ACPI_BATTERY_FORMAT_BST |
194 | }; | 273 | }; |
195 | struct acpi_buffer data = { 0, NULL }; | ||
196 | union acpi_object *package = NULL; | 274 | union acpi_object *package = NULL; |
275 | struct acpi_buffer *data = NULL; | ||
197 | 276 | ||
277 | battery->update_time[ACPI_BATTERY_STATE] = get_seconds(); | ||
198 | 278 | ||
199 | if (!battery || !bst) | 279 | if (!acpi_battery_present(battery)) |
200 | return -EINVAL; | 280 | return 0; |
201 | 281 | ||
202 | /* Evalute _BST */ | 282 | /* Evaluate _BST */ |
203 | 283 | ||
204 | status = acpi_evaluate_object(battery->device->handle, "_BST", NULL, &buffer); | 284 | status = |
285 | acpi_evaluate_object(acpi_battery_handle(battery), "_BST", NULL, | ||
286 | &buffer); | ||
205 | if (ACPI_FAILURE(status)) { | 287 | if (ACPI_FAILURE(status)) { |
206 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST")); | 288 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST")); |
207 | return -ENODEV; | 289 | return -ENODEV; |
@@ -209,55 +291,49 @@ acpi_battery_get_status(struct acpi_battery *battery, | |||
209 | 291 | ||
210 | package = buffer.pointer; | 292 | package = buffer.pointer; |
211 | 293 | ||
212 | /* Extract Package Data */ | 294 | data = &battery->bst_data; |
213 | |||
214 | status = acpi_extract_package(package, &format, &data); | ||
215 | if (status != AE_BUFFER_OVERFLOW) { | ||
216 | ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST")); | ||
217 | result = -ENODEV; | ||
218 | goto end; | ||
219 | } | ||
220 | 295 | ||
221 | data.pointer = kzalloc(data.length, GFP_KERNEL); | 296 | /* Extract Package Data */ |
222 | if (!data.pointer) { | ||
223 | result = -ENOMEM; | ||
224 | goto end; | ||
225 | } | ||
226 | 297 | ||
227 | status = acpi_extract_package(package, &format, &data); | 298 | result = |
228 | if (ACPI_FAILURE(status)) { | 299 | acpi_battery_extract_package(battery, package, &format, data, |
229 | ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST")); | 300 | "_BST"); |
230 | kfree(data.pointer); | 301 | if (result) |
231 | result = -ENODEV; | ||
232 | goto end; | 302 | goto end; |
233 | } | ||
234 | 303 | ||
235 | end: | 304 | end: |
236 | kfree(buffer.pointer); | 305 | kfree(buffer.pointer); |
237 | 306 | ||
238 | if (!result) | ||
239 | (*bst) = data.pointer; | ||
240 | |||
241 | return result; | 307 | return result; |
242 | } | 308 | } |
243 | 309 | ||
244 | static int | 310 | static int acpi_battery_get_alarm(struct acpi_battery *battery) |
245 | acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long alarm) | 311 | { |
312 | battery->update_time[ACPI_BATTERY_ALARM] = get_seconds(); | ||
313 | |||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | static int acpi_battery_set_alarm(struct acpi_battery *battery, | ||
318 | unsigned long alarm) | ||
246 | { | 319 | { |
247 | acpi_status status = 0; | 320 | acpi_status status = 0; |
248 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; | 321 | union acpi_object arg0 = { ACPI_TYPE_INTEGER }; |
249 | struct acpi_object_list arg_list = { 1, &arg0 }; | 322 | struct acpi_object_list arg_list = { 1, &arg0 }; |
250 | 323 | ||
324 | battery->update_time[ACPI_BATTERY_ALARM] = get_seconds(); | ||
251 | 325 | ||
252 | if (!battery) | 326 | if (!acpi_battery_present(battery)) |
253 | return -EINVAL; | 327 | return -ENODEV; |
254 | 328 | ||
255 | if (!battery->flags.alarm) | 329 | if (!battery->flags.alarm_present) |
256 | return -ENODEV; | 330 | return -ENODEV; |
257 | 331 | ||
258 | arg0.integer.value = alarm; | 332 | arg0.integer.value = alarm; |
259 | 333 | ||
260 | status = acpi_evaluate_object(battery->device->handle, "_BTP", &arg_list, NULL); | 334 | status = |
335 | acpi_evaluate_object(acpi_battery_handle(battery), "_BTP", | ||
336 | &arg_list, NULL); | ||
261 | if (ACPI_FAILURE(status)) | 337 | if (ACPI_FAILURE(status)) |
262 | return -ENODEV; | 338 | return -ENODEV; |
263 | 339 | ||
@@ -268,65 +344,114 @@ acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long alarm) | |||
268 | return 0; | 344 | return 0; |
269 | } | 345 | } |
270 | 346 | ||
271 | static int acpi_battery_check(struct acpi_battery *battery) | 347 | static int acpi_battery_init_alarm(struct acpi_battery *battery) |
272 | { | 348 | { |
273 | int result = 0; | 349 | int result = 0; |
274 | acpi_status status = AE_OK; | 350 | acpi_status status = AE_OK; |
275 | acpi_handle handle = NULL; | 351 | acpi_handle handle = NULL; |
276 | struct acpi_device *device = NULL; | 352 | struct acpi_battery_info *bif = battery->bif_data.pointer; |
277 | struct acpi_battery_info *bif = NULL; | 353 | unsigned long alarm = battery->alarm; |
278 | 354 | ||
355 | /* See if alarms are supported, and if so, set default */ | ||
279 | 356 | ||
280 | if (!battery) | 357 | status = acpi_get_handle(acpi_battery_handle(battery), "_BTP", &handle); |
281 | return -EINVAL; | 358 | if (ACPI_SUCCESS(status)) { |
282 | 359 | battery->flags.alarm_present = 1; | |
283 | device = battery->device; | 360 | if (!alarm && bif) { |
361 | alarm = bif->design_capacity_warning; | ||
362 | } | ||
363 | result = acpi_battery_set_alarm(battery, alarm); | ||
364 | if (result) | ||
365 | goto end; | ||
366 | } else { | ||
367 | battery->flags.alarm_present = 0; | ||
368 | } | ||
284 | 369 | ||
285 | result = acpi_bus_get_status(device); | 370 | end: |
286 | if (result) | ||
287 | return result; | ||
288 | 371 | ||
289 | /* Insertion? */ | 372 | return result; |
373 | } | ||
290 | 374 | ||
291 | if (!battery->flags.present && device->status.battery_present) { | 375 | static int acpi_battery_init_update(struct acpi_battery *battery) |
376 | { | ||
377 | int result = 0; | ||
292 | 378 | ||
293 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery inserted\n")); | 379 | result = acpi_battery_get_status(battery); |
380 | if (result) | ||
381 | return result; | ||
294 | 382 | ||
295 | /* Evalute _BIF to get certain static information */ | 383 | battery->flags.battery_present_prev = acpi_battery_present(battery); |
296 | 384 | ||
297 | result = acpi_battery_get_info(battery, &bif); | 385 | if (acpi_battery_present(battery)) { |
386 | result = acpi_battery_get_info(battery); | ||
387 | if (result) | ||
388 | return result; | ||
389 | result = acpi_battery_get_state(battery); | ||
298 | if (result) | 390 | if (result) |
299 | return result; | 391 | return result; |
300 | 392 | ||
301 | battery->flags.power_unit = bif->power_unit; | 393 | acpi_battery_init_alarm(battery); |
302 | battery->trips.warning = bif->design_capacity_warning; | 394 | } |
303 | battery->trips.low = bif->design_capacity_low; | 395 | |
304 | kfree(bif); | 396 | return result; |
397 | } | ||
305 | 398 | ||
306 | /* See if alarms are supported, and if so, set default */ | 399 | static int acpi_battery_update(struct acpi_battery *battery, |
400 | int update, int *update_result_ptr) | ||
401 | { | ||
402 | int result = 0; | ||
403 | int update_result = ACPI_BATTERY_NONE_UPDATE; | ||
404 | |||
405 | if (!acpi_battery_present(battery)) { | ||
406 | update = 1; | ||
407 | } | ||
307 | 408 | ||
308 | status = acpi_get_handle(battery->device->handle, "_BTP", &handle); | 409 | if (battery->flags.init_update) { |
309 | if (ACPI_SUCCESS(status)) { | 410 | result = acpi_battery_init_update(battery); |
310 | battery->flags.alarm = 1; | 411 | if (result) |
311 | acpi_battery_set_alarm(battery, battery->trips.warning); | 412 | goto end; |
413 | update_result = ACPI_BATTERY_INIT_UPDATE; | ||
414 | } else if (update) { | ||
415 | result = acpi_battery_get_status(battery); | ||
416 | if (result) | ||
417 | goto end; | ||
418 | if ((!battery->flags.battery_present_prev & acpi_battery_present(battery)) | ||
419 | || (battery->flags.battery_present_prev & !acpi_battery_present(battery))) { | ||
420 | result = acpi_battery_init_update(battery); | ||
421 | if (result) | ||
422 | goto end; | ||
423 | update_result = ACPI_BATTERY_INIT_UPDATE; | ||
424 | } else { | ||
425 | update_result = ACPI_BATTERY_EASY_UPDATE; | ||
312 | } | 426 | } |
313 | } | 427 | } |
314 | 428 | ||
315 | /* Removal? */ | 429 | end: |
316 | 430 | ||
317 | else if (battery->flags.present && !device->status.battery_present) { | 431 | battery->flags.init_update = (result != 0); |
318 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery removed\n")); | ||
319 | } | ||
320 | 432 | ||
321 | battery->flags.present = device->status.battery_present; | 433 | *update_result_ptr = update_result; |
322 | 434 | ||
323 | return result; | 435 | return result; |
324 | } | 436 | } |
325 | 437 | ||
326 | static void acpi_battery_check_present(struct acpi_battery *battery) | 438 | static void acpi_battery_notify_update(struct acpi_battery *battery) |
327 | { | 439 | { |
328 | if (!battery->flags.present) { | 440 | acpi_battery_get_status(battery); |
329 | acpi_battery_check(battery); | 441 | |
442 | if (battery->flags.init_update) { | ||
443 | return; | ||
444 | } | ||
445 | |||
446 | if ((!battery->flags.battery_present_prev & | ||
447 | acpi_battery_present(battery)) || | ||
448 | (battery->flags.battery_present_prev & | ||
449 | !acpi_battery_present(battery))) { | ||
450 | battery->flags.init_update = 1; | ||
451 | } else { | ||
452 | battery->flags.update[ACPI_BATTERY_INFO] = 1; | ||
453 | battery->flags.update[ACPI_BATTERY_STATE] = 1; | ||
454 | battery->flags.update[ACPI_BATTERY_ALARM] = 1; | ||
330 | } | 455 | } |
331 | } | 456 | } |
332 | 457 | ||
@@ -335,37 +460,33 @@ static void acpi_battery_check_present(struct acpi_battery *battery) | |||
335 | -------------------------------------------------------------------------- */ | 460 | -------------------------------------------------------------------------- */ |
336 | 461 | ||
337 | static struct proc_dir_entry *acpi_battery_dir; | 462 | static struct proc_dir_entry *acpi_battery_dir; |
338 | static int acpi_battery_read_info(struct seq_file *seq, void *offset) | 463 | |
464 | static int acpi_battery_print_info(struct seq_file *seq, int result) | ||
339 | { | 465 | { |
340 | int result = 0; | ||
341 | struct acpi_battery *battery = seq->private; | 466 | struct acpi_battery *battery = seq->private; |
342 | struct acpi_battery_info *bif = NULL; | 467 | struct acpi_battery_info *bif = NULL; |
343 | char *units = "?"; | 468 | char *units = "?"; |
344 | 469 | ||
345 | 470 | if (result) | |
346 | if (!battery) | ||
347 | goto end; | 471 | goto end; |
348 | 472 | ||
349 | acpi_battery_check_present(battery); | 473 | if (acpi_battery_present(battery)) |
350 | |||
351 | if (battery->flags.present) | ||
352 | seq_printf(seq, "present: yes\n"); | 474 | seq_printf(seq, "present: yes\n"); |
353 | else { | 475 | else { |
354 | seq_printf(seq, "present: no\n"); | 476 | seq_printf(seq, "present: no\n"); |
355 | goto end; | 477 | goto end; |
356 | } | 478 | } |
357 | 479 | ||
358 | /* Battery Info (_BIF) */ | 480 | bif = battery->bif_data.pointer; |
359 | 481 | if (!bif) { | |
360 | result = acpi_battery_get_info(battery, &bif); | 482 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BIF buffer is NULL")); |
361 | if (result || !bif) { | 483 | result = -ENODEV; |
362 | seq_printf(seq, "ERROR: Unable to read battery information\n"); | ||
363 | goto end; | 484 | goto end; |
364 | } | 485 | } |
365 | 486 | ||
366 | units = | 487 | /* Battery Units */ |
367 | bif-> | 488 | |
368 | power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS; | 489 | units = acpi_battery_power_units(battery); |
369 | 490 | ||
370 | if (bif->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN) | 491 | if (bif->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN) |
371 | seq_printf(seq, "design capacity: unknown\n"); | 492 | seq_printf(seq, "design capacity: unknown\n"); |
@@ -396,7 +517,6 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset) | |||
396 | else | 517 | else |
397 | seq_printf(seq, "design voltage: %d mV\n", | 518 | seq_printf(seq, "design voltage: %d mV\n", |
398 | (u32) bif->design_voltage); | 519 | (u32) bif->design_voltage); |
399 | |||
400 | seq_printf(seq, "design capacity warning: %d %sh\n", | 520 | seq_printf(seq, "design capacity warning: %d %sh\n", |
401 | (u32) bif->design_capacity_warning, units); | 521 | (u32) bif->design_capacity_warning, units); |
402 | seq_printf(seq, "design capacity low: %d %sh\n", | 522 | seq_printf(seq, "design capacity low: %d %sh\n", |
@@ -411,50 +531,40 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset) | |||
411 | seq_printf(seq, "OEM info: %s\n", bif->oem_info); | 531 | seq_printf(seq, "OEM info: %s\n", bif->oem_info); |
412 | 532 | ||
413 | end: | 533 | end: |
414 | kfree(bif); | ||
415 | 534 | ||
416 | return 0; | 535 | if (result) |
417 | } | 536 | seq_printf(seq, "ERROR: Unable to read battery info\n"); |
418 | 537 | ||
419 | static int acpi_battery_info_open_fs(struct inode *inode, struct file *file) | 538 | return result; |
420 | { | ||
421 | return single_open(file, acpi_battery_read_info, PDE(inode)->data); | ||
422 | } | 539 | } |
423 | 540 | ||
424 | static int acpi_battery_read_state(struct seq_file *seq, void *offset) | 541 | static int acpi_battery_print_state(struct seq_file *seq, int result) |
425 | { | 542 | { |
426 | int result = 0; | ||
427 | struct acpi_battery *battery = seq->private; | 543 | struct acpi_battery *battery = seq->private; |
428 | struct acpi_battery_status *bst = NULL; | 544 | struct acpi_battery_state *bst = NULL; |
429 | char *units = "?"; | 545 | char *units = "?"; |
430 | 546 | ||
431 | 547 | if (result) | |
432 | if (!battery) | ||
433 | goto end; | 548 | goto end; |
434 | 549 | ||
435 | acpi_battery_check_present(battery); | 550 | if (acpi_battery_present(battery)) |
436 | |||
437 | if (battery->flags.present) | ||
438 | seq_printf(seq, "present: yes\n"); | 551 | seq_printf(seq, "present: yes\n"); |
439 | else { | 552 | else { |
440 | seq_printf(seq, "present: no\n"); | 553 | seq_printf(seq, "present: no\n"); |
441 | goto end; | 554 | goto end; |
442 | } | 555 | } |
443 | 556 | ||
444 | /* Battery Units */ | 557 | bst = battery->bst_data.pointer; |
445 | 558 | if (!bst) { | |
446 | units = | 559 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, "BST buffer is NULL")); |
447 | battery->flags. | 560 | result = -ENODEV; |
448 | power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS; | ||
449 | |||
450 | /* Battery Status (_BST) */ | ||
451 | |||
452 | result = acpi_battery_get_status(battery, &bst); | ||
453 | if (result || !bst) { | ||
454 | seq_printf(seq, "ERROR: Unable to read battery status\n"); | ||
455 | goto end; | 561 | goto end; |
456 | } | 562 | } |
457 | 563 | ||
564 | /* Battery Units */ | ||
565 | |||
566 | units = acpi_battery_power_units(battery); | ||
567 | |||
458 | if (!(bst->state & 0x04)) | 568 | if (!(bst->state & 0x04)) |
459 | seq_printf(seq, "capacity state: ok\n"); | 569 | seq_printf(seq, "capacity state: ok\n"); |
460 | else | 570 | else |
@@ -490,48 +600,43 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset) | |||
490 | (u32) bst->present_voltage); | 600 | (u32) bst->present_voltage); |
491 | 601 | ||
492 | end: | 602 | end: |
493 | kfree(bst); | ||
494 | 603 | ||
495 | return 0; | 604 | if (result) { |
496 | } | 605 | seq_printf(seq, "ERROR: Unable to read battery state\n"); |
606 | } | ||
497 | 607 | ||
498 | static int acpi_battery_state_open_fs(struct inode *inode, struct file *file) | 608 | return result; |
499 | { | ||
500 | return single_open(file, acpi_battery_read_state, PDE(inode)->data); | ||
501 | } | 609 | } |
502 | 610 | ||
503 | static int acpi_battery_read_alarm(struct seq_file *seq, void *offset) | 611 | static int acpi_battery_print_alarm(struct seq_file *seq, int result) |
504 | { | 612 | { |
505 | struct acpi_battery *battery = seq->private; | 613 | struct acpi_battery *battery = seq->private; |
506 | char *units = "?"; | 614 | char *units = "?"; |
507 | 615 | ||
508 | 616 | if (result) | |
509 | if (!battery) | ||
510 | goto end; | 617 | goto end; |
511 | 618 | ||
512 | acpi_battery_check_present(battery); | 619 | if (!acpi_battery_present(battery)) { |
513 | |||
514 | if (!battery->flags.present) { | ||
515 | seq_printf(seq, "present: no\n"); | 620 | seq_printf(seq, "present: no\n"); |
516 | goto end; | 621 | goto end; |
517 | } | 622 | } |
518 | 623 | ||
519 | /* Battery Units */ | 624 | /* Battery Units */ |
520 | 625 | ||
521 | units = | 626 | units = acpi_battery_power_units(battery); |
522 | battery->flags. | ||
523 | power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS; | ||
524 | |||
525 | /* Battery Alarm */ | ||
526 | 627 | ||
527 | seq_printf(seq, "alarm: "); | 628 | seq_printf(seq, "alarm: "); |
528 | if (!battery->alarm) | 629 | if (!battery->alarm) |
529 | seq_printf(seq, "unsupported\n"); | 630 | seq_printf(seq, "unsupported\n"); |
530 | else | 631 | else |
531 | seq_printf(seq, "%d %sh\n", (u32) battery->alarm, units); | 632 | seq_printf(seq, "%lu %sh\n", battery->alarm, units); |
532 | 633 | ||
533 | end: | 634 | end: |
534 | return 0; | 635 | |
636 | if (result) | ||
637 | seq_printf(seq, "ERROR: Unable to read battery alarm\n"); | ||
638 | |||
639 | return result; | ||
535 | } | 640 | } |
536 | 641 | ||
537 | static ssize_t | 642 | static ssize_t |
@@ -543,27 +648,113 @@ acpi_battery_write_alarm(struct file *file, | |||
543 | char alarm_string[12] = { '\0' }; | 648 | char alarm_string[12] = { '\0' }; |
544 | struct seq_file *m = file->private_data; | 649 | struct seq_file *m = file->private_data; |
545 | struct acpi_battery *battery = m->private; | 650 | struct acpi_battery *battery = m->private; |
546 | 651 | int update_result = ACPI_BATTERY_NONE_UPDATE; | |
547 | 652 | ||
548 | if (!battery || (count > sizeof(alarm_string) - 1)) | 653 | if (!battery || (count > sizeof(alarm_string) - 1)) |
549 | return -EINVAL; | 654 | return -EINVAL; |
550 | 655 | ||
551 | acpi_battery_check_present(battery); | 656 | mutex_lock(&battery->mutex); |
552 | 657 | ||
553 | if (!battery->flags.present) | 658 | result = acpi_battery_update(battery, 1, &update_result); |
554 | return -ENODEV; | 659 | if (result) { |
660 | result = -ENODEV; | ||
661 | goto end; | ||
662 | } | ||
663 | |||
664 | if (!acpi_battery_present(battery)) { | ||
665 | result = -ENODEV; | ||
666 | goto end; | ||
667 | } | ||
555 | 668 | ||
556 | if (copy_from_user(alarm_string, buffer, count)) | 669 | if (copy_from_user(alarm_string, buffer, count)) { |
557 | return -EFAULT; | 670 | result = -EFAULT; |
671 | goto end; | ||
672 | } | ||
558 | 673 | ||
559 | alarm_string[count] = '\0'; | 674 | alarm_string[count] = '\0'; |
560 | 675 | ||
561 | result = acpi_battery_set_alarm(battery, | 676 | result = acpi_battery_set_alarm(battery, |
562 | simple_strtoul(alarm_string, NULL, 0)); | 677 | simple_strtoul(alarm_string, NULL, 0)); |
563 | if (result) | 678 | if (result) |
564 | return result; | 679 | goto end; |
680 | |||
681 | end: | ||
565 | 682 | ||
566 | return count; | 683 | acpi_battery_check_result(battery, result); |
684 | |||
685 | if (!result) | ||
686 | result = count; | ||
687 | |||
688 | mutex_unlock(&battery->mutex); | ||
689 | |||
690 | return result; | ||
691 | } | ||
692 | |||
693 | typedef int(*print_func)(struct seq_file *seq, int result); | ||
694 | typedef int(*get_func)(struct acpi_battery *battery); | ||
695 | |||
696 | static struct acpi_read_mux { | ||
697 | print_func print; | ||
698 | get_func get; | ||
699 | } acpi_read_funcs[ACPI_BATTERY_NUMFILES] = { | ||
700 | {.get = acpi_battery_get_info, .print = acpi_battery_print_info}, | ||
701 | {.get = acpi_battery_get_state, .print = acpi_battery_print_state}, | ||
702 | {.get = acpi_battery_get_alarm, .print = acpi_battery_print_alarm}, | ||
703 | }; | ||
704 | |||
705 | static int acpi_battery_read(int fid, struct seq_file *seq) | ||
706 | { | ||
707 | struct acpi_battery *battery = seq->private; | ||
708 | int result = 0; | ||
709 | int update_result = ACPI_BATTERY_NONE_UPDATE; | ||
710 | int update = 0; | ||
711 | |||
712 | mutex_lock(&battery->mutex); | ||
713 | |||
714 | update = (get_seconds() - battery->update_time[fid] >= update_time); | ||
715 | update = (update | battery->flags.update[fid]); | ||
716 | |||
717 | result = acpi_battery_update(battery, update, &update_result); | ||
718 | if (result) | ||
719 | goto end; | ||
720 | |||
721 | if (update_result == ACPI_BATTERY_EASY_UPDATE) { | ||
722 | result = acpi_read_funcs[fid].get(battery); | ||
723 | if (result) | ||
724 | goto end; | ||
725 | } | ||
726 | |||
727 | end: | ||
728 | result = acpi_read_funcs[fid].print(seq, result); | ||
729 | acpi_battery_check_result(battery, result); | ||
730 | battery->flags.update[fid] = result; | ||
731 | mutex_unlock(&battery->mutex); | ||
732 | return result; | ||
733 | } | ||
734 | |||
735 | static int acpi_battery_read_info(struct seq_file *seq, void *offset) | ||
736 | { | ||
737 | return acpi_battery_read(ACPI_BATTERY_INFO, seq); | ||
738 | } | ||
739 | |||
740 | static int acpi_battery_read_state(struct seq_file *seq, void *offset) | ||
741 | { | ||
742 | return acpi_battery_read(ACPI_BATTERY_STATE, seq); | ||
743 | } | ||
744 | |||
745 | static int acpi_battery_read_alarm(struct seq_file *seq, void *offset) | ||
746 | { | ||
747 | return acpi_battery_read(ACPI_BATTERY_ALARM, seq); | ||
748 | } | ||
749 | |||
750 | static int acpi_battery_info_open_fs(struct inode *inode, struct file *file) | ||
751 | { | ||
752 | return single_open(file, acpi_battery_read_info, PDE(inode)->data); | ||
753 | } | ||
754 | |||
755 | static int acpi_battery_state_open_fs(struct inode *inode, struct file *file) | ||
756 | { | ||
757 | return single_open(file, acpi_battery_read_state, PDE(inode)->data); | ||
567 | } | 758 | } |
568 | 759 | ||
569 | static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file) | 760 | static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file) |
@@ -571,35 +762,51 @@ static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file) | |||
571 | return single_open(file, acpi_battery_read_alarm, PDE(inode)->data); | 762 | return single_open(file, acpi_battery_read_alarm, PDE(inode)->data); |
572 | } | 763 | } |
573 | 764 | ||
574 | static const struct file_operations acpi_battery_info_ops = { | 765 | static struct battery_file { |
766 | struct file_operations ops; | ||
767 | mode_t mode; | ||
768 | char *name; | ||
769 | } acpi_battery_file[] = { | ||
770 | { | ||
771 | .name = "info", | ||
772 | .mode = S_IRUGO, | ||
773 | .ops = { | ||
575 | .open = acpi_battery_info_open_fs, | 774 | .open = acpi_battery_info_open_fs, |
576 | .read = seq_read, | 775 | .read = seq_read, |
577 | .llseek = seq_lseek, | 776 | .llseek = seq_lseek, |
578 | .release = single_release, | 777 | .release = single_release, |
579 | .owner = THIS_MODULE, | 778 | .owner = THIS_MODULE, |
580 | }; | 779 | }, |
581 | 780 | }, | |
582 | static const struct file_operations acpi_battery_state_ops = { | 781 | { |
782 | .name = "state", | ||
783 | .mode = S_IRUGO, | ||
784 | .ops = { | ||
583 | .open = acpi_battery_state_open_fs, | 785 | .open = acpi_battery_state_open_fs, |
584 | .read = seq_read, | 786 | .read = seq_read, |
585 | .llseek = seq_lseek, | 787 | .llseek = seq_lseek, |
586 | .release = single_release, | 788 | .release = single_release, |
587 | .owner = THIS_MODULE, | 789 | .owner = THIS_MODULE, |
588 | }; | 790 | }, |
589 | 791 | }, | |
590 | static const struct file_operations acpi_battery_alarm_ops = { | 792 | { |
793 | .name = "alarm", | ||
794 | .mode = S_IFREG | S_IRUGO | S_IWUSR, | ||
795 | .ops = { | ||
591 | .open = acpi_battery_alarm_open_fs, | 796 | .open = acpi_battery_alarm_open_fs, |
592 | .read = seq_read, | 797 | .read = seq_read, |
593 | .write = acpi_battery_write_alarm, | 798 | .write = acpi_battery_write_alarm, |
594 | .llseek = seq_lseek, | 799 | .llseek = seq_lseek, |
595 | .release = single_release, | 800 | .release = single_release, |
596 | .owner = THIS_MODULE, | 801 | .owner = THIS_MODULE, |
802 | }, | ||
803 | }, | ||
597 | }; | 804 | }; |
598 | 805 | ||
599 | static int acpi_battery_add_fs(struct acpi_device *device) | 806 | static int acpi_battery_add_fs(struct acpi_device *device) |
600 | { | 807 | { |
601 | struct proc_dir_entry *entry = NULL; | 808 | struct proc_dir_entry *entry = NULL; |
602 | 809 | int i; | |
603 | 810 | ||
604 | if (!acpi_device_dir(device)) { | 811 | if (!acpi_device_dir(device)) { |
605 | acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), | 812 | acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), |
@@ -609,38 +816,16 @@ static int acpi_battery_add_fs(struct acpi_device *device) | |||
609 | acpi_device_dir(device)->owner = THIS_MODULE; | 816 | acpi_device_dir(device)->owner = THIS_MODULE; |
610 | } | 817 | } |
611 | 818 | ||
612 | /* 'info' [R] */ | 819 | for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) { |
613 | entry = create_proc_entry(ACPI_BATTERY_FILE_INFO, | 820 | entry = create_proc_entry(acpi_battery_file[i].name, |
614 | S_IRUGO, acpi_device_dir(device)); | 821 | acpi_battery_file[i].mode, acpi_device_dir(device)); |
615 | if (!entry) | 822 | if (!entry) |
616 | return -ENODEV; | 823 | return -ENODEV; |
617 | else { | 824 | else { |
618 | entry->proc_fops = &acpi_battery_info_ops; | 825 | entry->proc_fops = &acpi_battery_file[i].ops; |
619 | entry->data = acpi_driver_data(device); | 826 | entry->data = acpi_driver_data(device); |
620 | entry->owner = THIS_MODULE; | 827 | entry->owner = THIS_MODULE; |
621 | } | 828 | } |
622 | |||
623 | /* 'status' [R] */ | ||
624 | entry = create_proc_entry(ACPI_BATTERY_FILE_STATUS, | ||
625 | S_IRUGO, acpi_device_dir(device)); | ||
626 | if (!entry) | ||
627 | return -ENODEV; | ||
628 | else { | ||
629 | entry->proc_fops = &acpi_battery_state_ops; | ||
630 | entry->data = acpi_driver_data(device); | ||
631 | entry->owner = THIS_MODULE; | ||
632 | } | ||
633 | |||
634 | /* 'alarm' [R/W] */ | ||
635 | entry = create_proc_entry(ACPI_BATTERY_FILE_ALARM, | ||
636 | S_IFREG | S_IRUGO | S_IWUSR, | ||
637 | acpi_device_dir(device)); | ||
638 | if (!entry) | ||
639 | return -ENODEV; | ||
640 | else { | ||
641 | entry->proc_fops = &acpi_battery_alarm_ops; | ||
642 | entry->data = acpi_driver_data(device); | ||
643 | entry->owner = THIS_MODULE; | ||
644 | } | 829 | } |
645 | 830 | ||
646 | return 0; | 831 | return 0; |
@@ -648,15 +833,12 @@ static int acpi_battery_add_fs(struct acpi_device *device) | |||
648 | 833 | ||
649 | static int acpi_battery_remove_fs(struct acpi_device *device) | 834 | static int acpi_battery_remove_fs(struct acpi_device *device) |
650 | { | 835 | { |
651 | 836 | int i; | |
652 | if (acpi_device_dir(device)) { | 837 | if (acpi_device_dir(device)) { |
653 | remove_proc_entry(ACPI_BATTERY_FILE_ALARM, | 838 | for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) { |
839 | remove_proc_entry(acpi_battery_file[i].name, | ||
654 | acpi_device_dir(device)); | 840 | acpi_device_dir(device)); |
655 | remove_proc_entry(ACPI_BATTERY_FILE_STATUS, | 841 | } |
656 | acpi_device_dir(device)); | ||
657 | remove_proc_entry(ACPI_BATTERY_FILE_INFO, | ||
658 | acpi_device_dir(device)); | ||
659 | |||
660 | remove_proc_entry(acpi_device_bid(device), acpi_battery_dir); | 842 | remove_proc_entry(acpi_device_bid(device), acpi_battery_dir); |
661 | acpi_device_dir(device) = NULL; | 843 | acpi_device_dir(device) = NULL; |
662 | } | 844 | } |
@@ -673,7 +855,6 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) | |||
673 | struct acpi_battery *battery = data; | 855 | struct acpi_battery *battery = data; |
674 | struct acpi_device *device = NULL; | 856 | struct acpi_device *device = NULL; |
675 | 857 | ||
676 | |||
677 | if (!battery) | 858 | if (!battery) |
678 | return; | 859 | return; |
679 | 860 | ||
@@ -684,8 +865,10 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) | |||
684 | case ACPI_BATTERY_NOTIFY_INFO: | 865 | case ACPI_BATTERY_NOTIFY_INFO: |
685 | case ACPI_NOTIFY_BUS_CHECK: | 866 | case ACPI_NOTIFY_BUS_CHECK: |
686 | case ACPI_NOTIFY_DEVICE_CHECK: | 867 | case ACPI_NOTIFY_DEVICE_CHECK: |
687 | acpi_battery_check(battery); | 868 | device = battery->device; |
688 | acpi_bus_generate_event(device, event, battery->flags.present); | 869 | acpi_battery_notify_update(battery); |
870 | acpi_bus_generate_event(device, event, | ||
871 | acpi_battery_present(battery)); | ||
689 | break; | 872 | break; |
690 | default: | 873 | default: |
691 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 874 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
@@ -702,7 +885,6 @@ static int acpi_battery_add(struct acpi_device *device) | |||
702 | acpi_status status = 0; | 885 | acpi_status status = 0; |
703 | struct acpi_battery *battery = NULL; | 886 | struct acpi_battery *battery = NULL; |
704 | 887 | ||
705 | |||
706 | if (!device) | 888 | if (!device) |
707 | return -EINVAL; | 889 | return -EINVAL; |
708 | 890 | ||
@@ -710,15 +892,21 @@ static int acpi_battery_add(struct acpi_device *device) | |||
710 | if (!battery) | 892 | if (!battery) |
711 | return -ENOMEM; | 893 | return -ENOMEM; |
712 | 894 | ||
895 | mutex_init(&battery->mutex); | ||
896 | |||
897 | mutex_lock(&battery->mutex); | ||
898 | |||
713 | battery->device = device; | 899 | battery->device = device; |
714 | strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME); | 900 | strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME); |
715 | strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); | 901 | strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); |
716 | acpi_driver_data(device) = battery; | 902 | acpi_driver_data(device) = battery; |
717 | 903 | ||
718 | result = acpi_battery_check(battery); | 904 | result = acpi_battery_get_status(battery); |
719 | if (result) | 905 | if (result) |
720 | goto end; | 906 | goto end; |
721 | 907 | ||
908 | battery->flags.init_update = 1; | ||
909 | |||
722 | result = acpi_battery_add_fs(device); | 910 | result = acpi_battery_add_fs(device); |
723 | if (result) | 911 | if (result) |
724 | goto end; | 912 | goto end; |
@@ -727,6 +915,7 @@ static int acpi_battery_add(struct acpi_device *device) | |||
727 | ACPI_ALL_NOTIFY, | 915 | ACPI_ALL_NOTIFY, |
728 | acpi_battery_notify, battery); | 916 | acpi_battery_notify, battery); |
729 | if (ACPI_FAILURE(status)) { | 917 | if (ACPI_FAILURE(status)) { |
918 | ACPI_EXCEPTION((AE_INFO, status, "Installing notify handler")); | ||
730 | result = -ENODEV; | 919 | result = -ENODEV; |
731 | goto end; | 920 | goto end; |
732 | } | 921 | } |
@@ -736,11 +925,14 @@ static int acpi_battery_add(struct acpi_device *device) | |||
736 | device->status.battery_present ? "present" : "absent"); | 925 | device->status.battery_present ? "present" : "absent"); |
737 | 926 | ||
738 | end: | 927 | end: |
928 | |||
739 | if (result) { | 929 | if (result) { |
740 | acpi_battery_remove_fs(device); | 930 | acpi_battery_remove_fs(device); |
741 | kfree(battery); | 931 | kfree(battery); |
742 | } | 932 | } |
743 | 933 | ||
934 | mutex_unlock(&battery->mutex); | ||
935 | |||
744 | return result; | 936 | return result; |
745 | } | 937 | } |
746 | 938 | ||
@@ -749,18 +941,27 @@ static int acpi_battery_remove(struct acpi_device *device, int type) | |||
749 | acpi_status status = 0; | 941 | acpi_status status = 0; |
750 | struct acpi_battery *battery = NULL; | 942 | struct acpi_battery *battery = NULL; |
751 | 943 | ||
752 | |||
753 | if (!device || !acpi_driver_data(device)) | 944 | if (!device || !acpi_driver_data(device)) |
754 | return -EINVAL; | 945 | return -EINVAL; |
755 | 946 | ||
756 | battery = acpi_driver_data(device); | 947 | battery = acpi_driver_data(device); |
757 | 948 | ||
949 | mutex_lock(&battery->mutex); | ||
950 | |||
758 | status = acpi_remove_notify_handler(device->handle, | 951 | status = acpi_remove_notify_handler(device->handle, |
759 | ACPI_ALL_NOTIFY, | 952 | ACPI_ALL_NOTIFY, |
760 | acpi_battery_notify); | 953 | acpi_battery_notify); |
761 | 954 | ||
762 | acpi_battery_remove_fs(device); | 955 | acpi_battery_remove_fs(device); |
763 | 956 | ||
957 | kfree(battery->bif_data.pointer); | ||
958 | |||
959 | kfree(battery->bst_data.pointer); | ||
960 | |||
961 | mutex_unlock(&battery->mutex); | ||
962 | |||
963 | mutex_destroy(&battery->mutex); | ||
964 | |||
764 | kfree(battery); | 965 | kfree(battery); |
765 | 966 | ||
766 | return 0; | 967 | return 0; |
@@ -775,7 +976,10 @@ static int acpi_battery_resume(struct acpi_device *device) | |||
775 | return -EINVAL; | 976 | return -EINVAL; |
776 | 977 | ||
777 | battery = device->driver_data; | 978 | battery = device->driver_data; |
778 | return acpi_battery_check(battery); | 979 | |
980 | battery->flags.init_update = 1; | ||
981 | |||
982 | return 0; | ||
779 | } | 983 | } |
780 | 984 | ||
781 | static int __init acpi_battery_init(void) | 985 | static int __init acpi_battery_init(void) |
@@ -800,7 +1004,6 @@ static int __init acpi_battery_init(void) | |||
800 | 1004 | ||
801 | static void __exit acpi_battery_exit(void) | 1005 | static void __exit acpi_battery_exit(void) |
802 | { | 1006 | { |
803 | |||
804 | acpi_bus_unregister_driver(&acpi_battery_driver); | 1007 | acpi_bus_unregister_driver(&acpi_battery_driver); |
805 | 1008 | ||
806 | acpi_unlock_battery_dir(acpi_battery_dir); | 1009 | acpi_unlock_battery_dir(acpi_battery_dir); |
diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c index fb3f31b5e6..56a5b3fffe 100644 --- a/drivers/acpi/bay.c +++ b/drivers/acpi/bay.c | |||
@@ -288,6 +288,11 @@ static int bay_add(acpi_handle handle, int id) | |||
288 | new_bay->pdev = pdev; | 288 | new_bay->pdev = pdev; |
289 | platform_set_drvdata(pdev, new_bay); | 289 | platform_set_drvdata(pdev, new_bay); |
290 | 290 | ||
291 | /* | ||
292 | * we want the bay driver to be able to send uevents | ||
293 | */ | ||
294 | pdev->dev.uevent_suppress = 0; | ||
295 | |||
291 | if (acpi_bay_add_fs(new_bay)) { | 296 | if (acpi_bay_add_fs(new_bay)) { |
292 | platform_device_unregister(new_bay->pdev); | 297 | platform_device_unregister(new_bay->pdev); |
293 | goto bay_add_err; | 298 | goto bay_add_err; |
@@ -328,18 +333,12 @@ static void bay_notify(acpi_handle handle, u32 event, void *data) | |||
328 | { | 333 | { |
329 | struct bay *bay_dev = (struct bay *)data; | 334 | struct bay *bay_dev = (struct bay *)data; |
330 | struct device *dev = &bay_dev->pdev->dev; | 335 | struct device *dev = &bay_dev->pdev->dev; |
336 | char event_string[12]; | ||
337 | char *envp[] = { event_string, NULL }; | ||
331 | 338 | ||
332 | bay_dprintk(handle, "Bay event"); | 339 | bay_dprintk(handle, "Bay event"); |
333 | 340 | sprintf(event_string, "BAY_EVENT=%d\n", event); | |
334 | switch(event) { | 341 | kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); |
335 | case ACPI_NOTIFY_BUS_CHECK: | ||
336 | case ACPI_NOTIFY_DEVICE_CHECK: | ||
337 | case ACPI_NOTIFY_EJECT_REQUEST: | ||
338 | kobject_uevent(&dev->kobj, KOBJ_CHANGE); | ||
339 | break; | ||
340 | default: | ||
341 | printk(KERN_ERR PREFIX "Bay: unknown event %d\n", event); | ||
342 | } | ||
343 | } | 342 | } |
344 | 343 | ||
345 | static acpi_status | 344 | static acpi_status |
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index e5084ececb..6b2658c962 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c | |||
@@ -292,6 +292,10 @@ int acpi_bus_generate_event(struct acpi_device *device, u8 type, int data) | |||
292 | if (!device) | 292 | if (!device) |
293 | return -EINVAL; | 293 | return -EINVAL; |
294 | 294 | ||
295 | if (acpi_bus_generate_genetlink_event(device, type, data)) | ||
296 | printk(KERN_WARNING PREFIX | ||
297 | "Failed to generate an ACPI event via genetlink!\n"); | ||
298 | |||
295 | /* drop event on the floor if no one's listening */ | 299 | /* drop event on the floor if no one's listening */ |
296 | if (!event_is_open) | 300 | if (!event_is_open) |
297 | return 0; | 301 | return 0; |
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 4546bf873a..6192c8be66 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c | |||
@@ -40,8 +40,15 @@ MODULE_AUTHOR("Kristen Carlson Accardi"); | |||
40 | MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION); | 40 | MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION); |
41 | MODULE_LICENSE("GPL"); | 41 | MODULE_LICENSE("GPL"); |
42 | 42 | ||
43 | static int immediate_undock = 1; | ||
44 | module_param(immediate_undock, bool, 0644); | ||
45 | MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to " | ||
46 | "undock immediately when the undock button is pressed, 0 will cause" | ||
47 | " the driver to wait for userspace to write the undock sysfs file " | ||
48 | " before undocking"); | ||
49 | |||
43 | static struct atomic_notifier_head dock_notifier_list; | 50 | static struct atomic_notifier_head dock_notifier_list; |
44 | static struct platform_device dock_device; | 51 | static struct platform_device *dock_device; |
45 | static char dock_device_name[] = "dock"; | 52 | static char dock_device_name[] = "dock"; |
46 | 53 | ||
47 | struct dock_station { | 54 | struct dock_station { |
@@ -63,6 +70,7 @@ struct dock_dependent_device { | |||
63 | }; | 70 | }; |
64 | 71 | ||
65 | #define DOCK_DOCKING 0x00000001 | 72 | #define DOCK_DOCKING 0x00000001 |
73 | #define DOCK_UNDOCKING 0x00000002 | ||
66 | #define DOCK_EVENT 3 | 74 | #define DOCK_EVENT 3 |
67 | #define UNDOCK_EVENT 2 | 75 | #define UNDOCK_EVENT 2 |
68 | 76 | ||
@@ -327,12 +335,20 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) | |||
327 | 335 | ||
328 | static void dock_event(struct dock_station *ds, u32 event, int num) | 336 | static void dock_event(struct dock_station *ds, u32 event, int num) |
329 | { | 337 | { |
330 | struct device *dev = &dock_device.dev; | 338 | struct device *dev = &dock_device->dev; |
339 | char event_string[7]; | ||
340 | char *envp[] = { event_string, NULL }; | ||
341 | |||
342 | if (num == UNDOCK_EVENT) | ||
343 | sprintf(event_string, "UNDOCK"); | ||
344 | else | ||
345 | sprintf(event_string, "DOCK"); | ||
346 | |||
331 | /* | 347 | /* |
332 | * Indicate that the status of the dock station has | 348 | * Indicate that the status of the dock station has |
333 | * changed. | 349 | * changed. |
334 | */ | 350 | */ |
335 | kobject_uevent(&dev->kobj, KOBJ_CHANGE); | 351 | kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); |
336 | } | 352 | } |
337 | 353 | ||
338 | /** | 354 | /** |
@@ -380,12 +396,11 @@ static void handle_dock(struct dock_station *ds, int dock) | |||
380 | union acpi_object arg; | 396 | union acpi_object arg; |
381 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 397 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
382 | struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 398 | struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
383 | union acpi_object *obj; | ||
384 | 399 | ||
385 | acpi_get_name(ds->handle, ACPI_FULL_PATHNAME, &name_buffer); | 400 | acpi_get_name(ds->handle, ACPI_FULL_PATHNAME, &name_buffer); |
386 | obj = name_buffer.pointer; | ||
387 | 401 | ||
388 | printk(KERN_INFO PREFIX "%s\n", dock ? "docking" : "undocking"); | 402 | printk(KERN_INFO PREFIX "%s - %s\n", |
403 | (char *)name_buffer.pointer, dock ? "docking" : "undocking"); | ||
389 | 404 | ||
390 | /* _DCK method has one argument */ | 405 | /* _DCK method has one argument */ |
391 | arg_list.count = 1; | 406 | arg_list.count = 1; |
@@ -394,7 +409,8 @@ static void handle_dock(struct dock_station *ds, int dock) | |||
394 | arg.integer.value = dock; | 409 | arg.integer.value = dock; |
395 | status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer); | 410 | status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer); |
396 | if (ACPI_FAILURE(status)) | 411 | if (ACPI_FAILURE(status)) |
397 | pr_debug("%s: failed to execute _DCK\n", obj->string.pointer); | 412 | printk(KERN_ERR PREFIX "%s - failed to execute _DCK\n", |
413 | (char *)name_buffer.pointer); | ||
398 | kfree(buffer.pointer); | 414 | kfree(buffer.pointer); |
399 | kfree(name_buffer.pointer); | 415 | kfree(name_buffer.pointer); |
400 | } | 416 | } |
@@ -420,6 +436,16 @@ static inline void complete_dock(struct dock_station *ds) | |||
420 | ds->last_dock_time = jiffies; | 436 | ds->last_dock_time = jiffies; |
421 | } | 437 | } |
422 | 438 | ||
439 | static inline void begin_undock(struct dock_station *ds) | ||
440 | { | ||
441 | ds->flags |= DOCK_UNDOCKING; | ||
442 | } | ||
443 | |||
444 | static inline void complete_undock(struct dock_station *ds) | ||
445 | { | ||
446 | ds->flags &= ~(DOCK_UNDOCKING); | ||
447 | } | ||
448 | |||
423 | /** | 449 | /** |
424 | * dock_in_progress - see if we are in the middle of handling a dock event | 450 | * dock_in_progress - see if we are in the middle of handling a dock event |
425 | * @ds: the dock station | 451 | * @ds: the dock station |
@@ -550,7 +576,7 @@ static int handle_eject_request(struct dock_station *ds, u32 event) | |||
550 | printk(KERN_ERR PREFIX "Unable to undock!\n"); | 576 | printk(KERN_ERR PREFIX "Unable to undock!\n"); |
551 | return -EBUSY; | 577 | return -EBUSY; |
552 | } | 578 | } |
553 | 579 | complete_undock(ds); | |
554 | return 0; | 580 | return 0; |
555 | } | 581 | } |
556 | 582 | ||
@@ -594,7 +620,11 @@ static void dock_notify(acpi_handle handle, u32 event, void *data) | |||
594 | * to the driver who wish to hotplug. | 620 | * to the driver who wish to hotplug. |
595 | */ | 621 | */ |
596 | case ACPI_NOTIFY_EJECT_REQUEST: | 622 | case ACPI_NOTIFY_EJECT_REQUEST: |
597 | handle_eject_request(ds, event); | 623 | begin_undock(ds); |
624 | if (immediate_undock) | ||
625 | handle_eject_request(ds, event); | ||
626 | else | ||
627 | dock_event(ds, event, UNDOCK_EVENT); | ||
598 | break; | 628 | break; |
599 | default: | 629 | default: |
600 | printk(KERN_ERR PREFIX "Unknown dock event %d\n", event); | 630 | printk(KERN_ERR PREFIX "Unknown dock event %d\n", event); |
@@ -653,6 +683,17 @@ static ssize_t show_docked(struct device *dev, | |||
653 | DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL); | 683 | DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL); |
654 | 684 | ||
655 | /* | 685 | /* |
686 | * show_flags - read method for flags file in sysfs | ||
687 | */ | ||
688 | static ssize_t show_flags(struct device *dev, | ||
689 | struct device_attribute *attr, char *buf) | ||
690 | { | ||
691 | return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags); | ||
692 | |||
693 | } | ||
694 | DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL); | ||
695 | |||
696 | /* | ||
656 | * write_undock - write method for "undock" file in sysfs | 697 | * write_undock - write method for "undock" file in sysfs |
657 | */ | 698 | */ |
658 | static ssize_t write_undock(struct device *dev, struct device_attribute *attr, | 699 | static ssize_t write_undock(struct device *dev, struct device_attribute *attr, |
@@ -675,16 +716,15 @@ static ssize_t show_dock_uid(struct device *dev, | |||
675 | struct device_attribute *attr, char *buf) | 716 | struct device_attribute *attr, char *buf) |
676 | { | 717 | { |
677 | unsigned long lbuf; | 718 | unsigned long lbuf; |
678 | acpi_status status = acpi_evaluate_integer(dock_station->handle, "_UID", NULL, &lbuf); | 719 | acpi_status status = acpi_evaluate_integer(dock_station->handle, |
679 | if(ACPI_FAILURE(status)) { | 720 | "_UID", NULL, &lbuf); |
721 | if (ACPI_FAILURE(status)) | ||
680 | return 0; | 722 | return 0; |
681 | } | 723 | |
682 | return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf); | 724 | return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf); |
683 | } | 725 | } |
684 | DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL); | 726 | DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL); |
685 | 727 | ||
686 | |||
687 | |||
688 | /** | 728 | /** |
689 | * dock_add - add a new dock station | 729 | * dock_add - add a new dock station |
690 | * @handle: the dock station handle | 730 | * @handle: the dock station handle |
@@ -711,33 +751,53 @@ static int dock_add(acpi_handle handle) | |||
711 | ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); | 751 | ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); |
712 | 752 | ||
713 | /* initialize platform device stuff */ | 753 | /* initialize platform device stuff */ |
714 | dock_device.name = dock_device_name; | 754 | dock_device = |
715 | ret = platform_device_register(&dock_device); | 755 | platform_device_register_simple(dock_device_name, 0, NULL, 0); |
756 | if (IS_ERR(dock_device)) { | ||
757 | kfree(dock_station); | ||
758 | dock_station = NULL; | ||
759 | return PTR_ERR(dock_device); | ||
760 | } | ||
761 | |||
762 | /* we want the dock device to send uevents */ | ||
763 | dock_device->dev.uevent_suppress = 0; | ||
764 | |||
765 | ret = device_create_file(&dock_device->dev, &dev_attr_docked); | ||
716 | if (ret) { | 766 | if (ret) { |
717 | printk(KERN_ERR PREFIX "Error %d registering dock device\n", ret); | 767 | printk("Error %d adding sysfs file\n", ret); |
768 | platform_device_unregister(dock_device); | ||
718 | kfree(dock_station); | 769 | kfree(dock_station); |
770 | dock_station = NULL; | ||
719 | return ret; | 771 | return ret; |
720 | } | 772 | } |
721 | ret = device_create_file(&dock_device.dev, &dev_attr_docked); | 773 | ret = device_create_file(&dock_device->dev, &dev_attr_undock); |
722 | if (ret) { | 774 | if (ret) { |
723 | printk("Error %d adding sysfs file\n", ret); | 775 | printk("Error %d adding sysfs file\n", ret); |
724 | platform_device_unregister(&dock_device); | 776 | device_remove_file(&dock_device->dev, &dev_attr_docked); |
777 | platform_device_unregister(dock_device); | ||
725 | kfree(dock_station); | 778 | kfree(dock_station); |
779 | dock_station = NULL; | ||
726 | return ret; | 780 | return ret; |
727 | } | 781 | } |
728 | ret = device_create_file(&dock_device.dev, &dev_attr_undock); | 782 | ret = device_create_file(&dock_device->dev, &dev_attr_uid); |
729 | if (ret) { | 783 | if (ret) { |
730 | printk("Error %d adding sysfs file\n", ret); | 784 | printk("Error %d adding sysfs file\n", ret); |
731 | device_remove_file(&dock_device.dev, &dev_attr_docked); | 785 | device_remove_file(&dock_device->dev, &dev_attr_docked); |
732 | platform_device_unregister(&dock_device); | 786 | device_remove_file(&dock_device->dev, &dev_attr_undock); |
787 | platform_device_unregister(dock_device); | ||
733 | kfree(dock_station); | 788 | kfree(dock_station); |
789 | dock_station = NULL; | ||
734 | return ret; | 790 | return ret; |
735 | } | 791 | } |
736 | ret = device_create_file(&dock_device.dev, &dev_attr_uid); | 792 | ret = device_create_file(&dock_device->dev, &dev_attr_flags); |
737 | if (ret) { | 793 | if (ret) { |
738 | printk("Error %d adding sysfs file\n", ret); | 794 | printk("Error %d adding sysfs file\n", ret); |
739 | platform_device_unregister(&dock_device); | 795 | device_remove_file(&dock_device->dev, &dev_attr_docked); |
796 | device_remove_file(&dock_device->dev, &dev_attr_undock); | ||
797 | device_remove_file(&dock_device->dev, &dev_attr_uid); | ||
798 | platform_device_unregister(dock_device); | ||
740 | kfree(dock_station); | 799 | kfree(dock_station); |
800 | dock_station = NULL; | ||
741 | return ret; | 801 | return ret; |
742 | } | 802 | } |
743 | 803 | ||
@@ -750,6 +810,7 @@ static int dock_add(acpi_handle handle) | |||
750 | dd = alloc_dock_dependent_device(handle); | 810 | dd = alloc_dock_dependent_device(handle); |
751 | if (!dd) { | 811 | if (!dd) { |
752 | kfree(dock_station); | 812 | kfree(dock_station); |
813 | dock_station = NULL; | ||
753 | ret = -ENOMEM; | 814 | ret = -ENOMEM; |
754 | goto dock_add_err_unregister; | 815 | goto dock_add_err_unregister; |
755 | } | 816 | } |
@@ -773,10 +834,13 @@ static int dock_add(acpi_handle handle) | |||
773 | dock_add_err: | 834 | dock_add_err: |
774 | kfree(dd); | 835 | kfree(dd); |
775 | dock_add_err_unregister: | 836 | dock_add_err_unregister: |
776 | device_remove_file(&dock_device.dev, &dev_attr_docked); | 837 | device_remove_file(&dock_device->dev, &dev_attr_docked); |
777 | device_remove_file(&dock_device.dev, &dev_attr_undock); | 838 | device_remove_file(&dock_device->dev, &dev_attr_undock); |
778 | platform_device_unregister(&dock_device); | 839 | device_remove_file(&dock_device->dev, &dev_attr_uid); |
840 | device_remove_file(&dock_device->dev, &dev_attr_flags); | ||
841 | platform_device_unregister(dock_device); | ||
779 | kfree(dock_station); | 842 | kfree(dock_station); |
843 | dock_station = NULL; | ||
780 | return ret; | 844 | return ret; |
781 | } | 845 | } |
782 | 846 | ||
@@ -804,12 +868,15 @@ static int dock_remove(void) | |||
804 | printk(KERN_ERR "Error removing notify handler\n"); | 868 | printk(KERN_ERR "Error removing notify handler\n"); |
805 | 869 | ||
806 | /* cleanup sysfs */ | 870 | /* cleanup sysfs */ |
807 | device_remove_file(&dock_device.dev, &dev_attr_docked); | 871 | device_remove_file(&dock_device->dev, &dev_attr_docked); |
808 | device_remove_file(&dock_device.dev, &dev_attr_undock); | 872 | device_remove_file(&dock_device->dev, &dev_attr_undock); |
809 | platform_device_unregister(&dock_device); | 873 | device_remove_file(&dock_device->dev, &dev_attr_uid); |
874 | device_remove_file(&dock_device->dev, &dev_attr_flags); | ||
875 | platform_device_unregister(dock_device); | ||
810 | 876 | ||
811 | /* free dock station memory */ | 877 | /* free dock station memory */ |
812 | kfree(dock_station); | 878 | kfree(dock_station); |
879 | dock_station = NULL; | ||
813 | return 0; | 880 | return 0; |
814 | } | 881 | } |
815 | 882 | ||
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 82f496c076..10e851021e 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c | |||
@@ -34,25 +34,26 @@ | |||
34 | #include <linux/proc_fs.h> | 34 | #include <linux/proc_fs.h> |
35 | #include <linux/seq_file.h> | 35 | #include <linux/seq_file.h> |
36 | #include <linux/interrupt.h> | 36 | #include <linux/interrupt.h> |
37 | #include <linux/list.h> | ||
37 | #include <asm/io.h> | 38 | #include <asm/io.h> |
38 | #include <acpi/acpi_bus.h> | 39 | #include <acpi/acpi_bus.h> |
39 | #include <acpi/acpi_drivers.h> | 40 | #include <acpi/acpi_drivers.h> |
40 | #include <acpi/actypes.h> | 41 | #include <acpi/actypes.h> |
41 | 42 | ||
42 | #define _COMPONENT ACPI_EC_COMPONENT | ||
43 | ACPI_MODULE_NAME("ec"); | ||
44 | #define ACPI_EC_COMPONENT 0x00100000 | ||
45 | #define ACPI_EC_CLASS "embedded_controller" | 43 | #define ACPI_EC_CLASS "embedded_controller" |
46 | #define ACPI_EC_HID "PNP0C09" | 44 | #define ACPI_EC_HID "PNP0C09" |
47 | #define ACPI_EC_DEVICE_NAME "Embedded Controller" | 45 | #define ACPI_EC_DEVICE_NAME "Embedded Controller" |
48 | #define ACPI_EC_FILE_INFO "info" | 46 | #define ACPI_EC_FILE_INFO "info" |
47 | |||
49 | #undef PREFIX | 48 | #undef PREFIX |
50 | #define PREFIX "ACPI: EC: " | 49 | #define PREFIX "ACPI: EC: " |
50 | |||
51 | /* EC status register */ | 51 | /* EC status register */ |
52 | #define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */ | 52 | #define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */ |
53 | #define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */ | 53 | #define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */ |
54 | #define ACPI_EC_FLAG_BURST 0x10 /* burst mode */ | 54 | #define ACPI_EC_FLAG_BURST 0x10 /* burst mode */ |
55 | #define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */ | 55 | #define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */ |
56 | |||
56 | /* EC commands */ | 57 | /* EC commands */ |
57 | enum ec_command { | 58 | enum ec_command { |
58 | ACPI_EC_COMMAND_READ = 0x80, | 59 | ACPI_EC_COMMAND_READ = 0x80, |
@@ -61,6 +62,7 @@ enum ec_command { | |||
61 | ACPI_EC_BURST_DISABLE = 0x83, | 62 | ACPI_EC_BURST_DISABLE = 0x83, |
62 | ACPI_EC_COMMAND_QUERY = 0x84, | 63 | ACPI_EC_COMMAND_QUERY = 0x84, |
63 | }; | 64 | }; |
65 | |||
64 | /* EC events */ | 66 | /* EC events */ |
65 | enum ec_event { | 67 | enum ec_event { |
66 | ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */ | 68 | ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */ |
@@ -94,6 +96,16 @@ static struct acpi_driver acpi_ec_driver = { | |||
94 | 96 | ||
95 | /* If we find an EC via the ECDT, we need to keep a ptr to its context */ | 97 | /* If we find an EC via the ECDT, we need to keep a ptr to its context */ |
96 | /* External interfaces use first EC only, so remember */ | 98 | /* External interfaces use first EC only, so remember */ |
99 | typedef int (*acpi_ec_query_func) (void *data); | ||
100 | |||
101 | struct acpi_ec_query_handler { | ||
102 | struct list_head node; | ||
103 | acpi_ec_query_func func; | ||
104 | acpi_handle handle; | ||
105 | void *data; | ||
106 | u8 query_bit; | ||
107 | }; | ||
108 | |||
97 | static struct acpi_ec { | 109 | static struct acpi_ec { |
98 | acpi_handle handle; | 110 | acpi_handle handle; |
99 | unsigned long gpe; | 111 | unsigned long gpe; |
@@ -104,6 +116,7 @@ static struct acpi_ec { | |||
104 | atomic_t query_pending; | 116 | atomic_t query_pending; |
105 | atomic_t event_count; | 117 | atomic_t event_count; |
106 | wait_queue_head_t wait; | 118 | wait_queue_head_t wait; |
119 | struct list_head list; | ||
107 | } *boot_ec, *first_ec; | 120 | } *boot_ec, *first_ec; |
108 | 121 | ||
109 | /* -------------------------------------------------------------------------- | 122 | /* -------------------------------------------------------------------------- |
@@ -245,7 +258,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command, | |||
245 | 258 | ||
246 | status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0, 0); | 259 | status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0, 0); |
247 | if (status) { | 260 | if (status) { |
248 | printk(KERN_DEBUG PREFIX | 261 | printk(KERN_ERR PREFIX |
249 | "input buffer is not empty, aborting transaction\n"); | 262 | "input buffer is not empty, aborting transaction\n"); |
250 | goto end; | 263 | goto end; |
251 | } | 264 | } |
@@ -394,21 +407,67 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data) | |||
394 | /* -------------------------------------------------------------------------- | 407 | /* -------------------------------------------------------------------------- |
395 | Event Management | 408 | Event Management |
396 | -------------------------------------------------------------------------- */ | 409 | -------------------------------------------------------------------------- */ |
410 | int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit, | ||
411 | acpi_handle handle, acpi_ec_query_func func, | ||
412 | void *data) | ||
413 | { | ||
414 | struct acpi_ec_query_handler *handler = | ||
415 | kzalloc(sizeof(struct acpi_ec_query_handler), GFP_KERNEL); | ||
416 | if (!handler) | ||
417 | return -ENOMEM; | ||
418 | |||
419 | handler->query_bit = query_bit; | ||
420 | handler->handle = handle; | ||
421 | handler->func = func; | ||
422 | handler->data = data; | ||
423 | mutex_lock(&ec->lock); | ||
424 | list_add_tail(&handler->node, &ec->list); | ||
425 | mutex_unlock(&ec->lock); | ||
426 | return 0; | ||
427 | } | ||
428 | |||
429 | EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler); | ||
430 | |||
431 | void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) | ||
432 | { | ||
433 | struct acpi_ec_query_handler *handler; | ||
434 | mutex_lock(&ec->lock); | ||
435 | list_for_each_entry(handler, &ec->list, node) { | ||
436 | if (query_bit == handler->query_bit) { | ||
437 | list_del(&handler->node); | ||
438 | kfree(handler); | ||
439 | break; | ||
440 | } | ||
441 | } | ||
442 | mutex_unlock(&ec->lock); | ||
443 | } | ||
444 | |||
445 | EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); | ||
397 | 446 | ||
398 | static void acpi_ec_gpe_query(void *ec_cxt) | 447 | static void acpi_ec_gpe_query(void *ec_cxt) |
399 | { | 448 | { |
400 | struct acpi_ec *ec = ec_cxt; | 449 | struct acpi_ec *ec = ec_cxt; |
401 | u8 value = 0; | 450 | u8 value = 0; |
402 | char object_name[8]; | 451 | struct acpi_ec_query_handler *handler, copy; |
403 | 452 | ||
404 | if (!ec || acpi_ec_query(ec, &value)) | 453 | if (!ec || acpi_ec_query(ec, &value)) |
405 | return; | 454 | return; |
406 | 455 | mutex_lock(&ec->lock); | |
407 | snprintf(object_name, 8, "_Q%2.2X", value); | 456 | list_for_each_entry(handler, &ec->list, node) { |
408 | 457 | if (value == handler->query_bit) { | |
409 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s", object_name)); | 458 | /* have custom handler for this bit */ |
410 | 459 | memcpy(©, handler, sizeof(copy)); | |
411 | acpi_evaluate_object(ec->handle, object_name, NULL, NULL); | 460 | mutex_unlock(&ec->lock); |
461 | if (copy.func) { | ||
462 | copy.func(copy.data); | ||
463 | } else if (copy.handle) { | ||
464 | acpi_evaluate_object(copy.handle, NULL, NULL, NULL); | ||
465 | } | ||
466 | return; | ||
467 | } | ||
468 | } | ||
469 | mutex_unlock(&ec->lock); | ||
470 | printk(KERN_ERR PREFIX "Handler for query 0x%x is not found!\n", value); | ||
412 | } | 471 | } |
413 | 472 | ||
414 | static u32 acpi_ec_gpe_handler(void *data) | 473 | static u32 acpi_ec_gpe_handler(void *data) |
@@ -427,8 +486,7 @@ static u32 acpi_ec_gpe_handler(void *data) | |||
427 | if ((value & ACPI_EC_FLAG_SCI) && !atomic_read(&ec->query_pending)) { | 486 | if ((value & ACPI_EC_FLAG_SCI) && !atomic_read(&ec->query_pending)) { |
428 | atomic_set(&ec->query_pending, 1); | 487 | atomic_set(&ec->query_pending, 1); |
429 | status = | 488 | status = |
430 | acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, | 489 | acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec); |
431 | ec); | ||
432 | } | 490 | } |
433 | 491 | ||
434 | return status == AE_OK ? | 492 | return status == AE_OK ? |
@@ -454,57 +512,35 @@ acpi_ec_space_setup(acpi_handle region_handle, | |||
454 | } | 512 | } |
455 | 513 | ||
456 | static acpi_status | 514 | static acpi_status |
457 | acpi_ec_space_handler(u32 function, | 515 | acpi_ec_space_handler(u32 function, acpi_physical_address address, |
458 | acpi_physical_address address, | 516 | u32 bits, acpi_integer *value, |
459 | u32 bit_width, | ||
460 | acpi_integer * value, | ||
461 | void *handler_context, void *region_context) | 517 | void *handler_context, void *region_context) |
462 | { | 518 | { |
463 | int result = 0; | ||
464 | struct acpi_ec *ec = handler_context; | 519 | struct acpi_ec *ec = handler_context; |
465 | u64 temp = *value; | 520 | int result = 0, i = 0; |
466 | acpi_integer f_v = 0; | 521 | u8 temp = 0; |
467 | int i = 0; | ||
468 | 522 | ||
469 | if ((address > 0xFF) || !value || !handler_context) | 523 | if ((address > 0xFF) || !value || !handler_context) |
470 | return AE_BAD_PARAMETER; | 524 | return AE_BAD_PARAMETER; |
471 | 525 | ||
472 | if (bit_width != 8 && acpi_strict) { | 526 | if (function != ACPI_READ && function != ACPI_WRITE) |
473 | return AE_BAD_PARAMETER; | 527 | return AE_BAD_PARAMETER; |
474 | } | ||
475 | |||
476 | next_byte: | ||
477 | switch (function) { | ||
478 | case ACPI_READ: | ||
479 | temp = 0; | ||
480 | result = acpi_ec_read(ec, (u8) address, (u8 *) & temp); | ||
481 | break; | ||
482 | case ACPI_WRITE: | ||
483 | result = acpi_ec_write(ec, (u8) address, (u8) temp); | ||
484 | break; | ||
485 | default: | ||
486 | result = -EINVAL; | ||
487 | goto out; | ||
488 | break; | ||
489 | } | ||
490 | 528 | ||
491 | bit_width -= 8; | 529 | if (bits != 8 && acpi_strict) |
492 | if (bit_width) { | 530 | return AE_BAD_PARAMETER; |
493 | if (function == ACPI_READ) | ||
494 | f_v |= temp << 8 * i; | ||
495 | if (function == ACPI_WRITE) | ||
496 | temp >>= 8; | ||
497 | i++; | ||
498 | address++; | ||
499 | goto next_byte; | ||
500 | } | ||
501 | 531 | ||
502 | if (function == ACPI_READ) { | 532 | while (bits - i > 0) { |
503 | f_v |= temp << 8 * i; | 533 | if (function == ACPI_READ) { |
504 | *value = f_v; | 534 | result = acpi_ec_read(ec, address, &temp); |
535 | (*value) |= ((acpi_integer)temp) << i; | ||
536 | } else { | ||
537 | temp = 0xff & ((*value) >> i); | ||
538 | result = acpi_ec_write(ec, address, temp); | ||
539 | } | ||
540 | i += 8; | ||
541 | ++address; | ||
505 | } | 542 | } |
506 | 543 | ||
507 | out: | ||
508 | switch (result) { | 544 | switch (result) { |
509 | case -EINVAL: | 545 | case -EINVAL: |
510 | return AE_BAD_PARAMETER; | 546 | return AE_BAD_PARAMETER; |
@@ -597,9 +633,6 @@ static int acpi_ec_remove_fs(struct acpi_device *device) | |||
597 | static acpi_status | 633 | static acpi_status |
598 | ec_parse_io_ports(struct acpi_resource *resource, void *context); | 634 | ec_parse_io_ports(struct acpi_resource *resource, void *context); |
599 | 635 | ||
600 | static acpi_status | ||
601 | ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval); | ||
602 | |||
603 | static struct acpi_ec *make_acpi_ec(void) | 636 | static struct acpi_ec *make_acpi_ec(void) |
604 | { | 637 | { |
605 | struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL); | 638 | struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL); |
@@ -610,13 +643,52 @@ static struct acpi_ec *make_acpi_ec(void) | |||
610 | atomic_set(&ec->event_count, 1); | 643 | atomic_set(&ec->event_count, 1); |
611 | mutex_init(&ec->lock); | 644 | mutex_init(&ec->lock); |
612 | init_waitqueue_head(&ec->wait); | 645 | init_waitqueue_head(&ec->wait); |
646 | INIT_LIST_HEAD(&ec->list); | ||
613 | 647 | ||
614 | return ec; | 648 | return ec; |
615 | } | 649 | } |
616 | 650 | ||
651 | static acpi_status | ||
652 | acpi_ec_register_query_methods(acpi_handle handle, u32 level, | ||
653 | void *context, void **return_value) | ||
654 | { | ||
655 | struct acpi_namespace_node *node = handle; | ||
656 | struct acpi_ec *ec = context; | ||
657 | int value = 0; | ||
658 | if (sscanf(node->name.ascii, "_Q%x", &value) == 1) { | ||
659 | acpi_ec_add_query_handler(ec, value, handle, NULL, NULL); | ||
660 | } | ||
661 | return AE_OK; | ||
662 | } | ||
663 | |||
664 | static int ec_parse_device(struct acpi_ec *ec, acpi_handle handle) | ||
665 | { | ||
666 | if (ACPI_FAILURE(acpi_walk_resources(handle, METHOD_NAME__CRS, | ||
667 | ec_parse_io_ports, ec))) | ||
668 | return -EINVAL; | ||
669 | |||
670 | /* Get GPE bit assignment (EC events). */ | ||
671 | /* TODO: Add support for _GPE returning a package */ | ||
672 | if (ACPI_FAILURE(acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe))) | ||
673 | return -EINVAL; | ||
674 | |||
675 | /* Use the global lock for all EC transactions? */ | ||
676 | acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock); | ||
677 | |||
678 | /* Find and register all query methods */ | ||
679 | acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1, | ||
680 | acpi_ec_register_query_methods, ec, NULL); | ||
681 | |||
682 | ec->handle = handle; | ||
683 | |||
684 | printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx", | ||
685 | ec->gpe, ec->command_addr, ec->data_addr); | ||
686 | |||
687 | return 0; | ||
688 | } | ||
689 | |||
617 | static int acpi_ec_add(struct acpi_device *device) | 690 | static int acpi_ec_add(struct acpi_device *device) |
618 | { | 691 | { |
619 | acpi_status status = AE_OK; | ||
620 | struct acpi_ec *ec = NULL; | 692 | struct acpi_ec *ec = NULL; |
621 | 693 | ||
622 | if (!device) | 694 | if (!device) |
@@ -629,8 +701,7 @@ static int acpi_ec_add(struct acpi_device *device) | |||
629 | if (!ec) | 701 | if (!ec) |
630 | return -ENOMEM; | 702 | return -ENOMEM; |
631 | 703 | ||
632 | status = ec_parse_device(device->handle, 0, ec, NULL); | 704 | if (ec_parse_device(ec, device->handle)) { |
633 | if (status != AE_CTRL_TERMINATE) { | ||
634 | kfree(ec); | 705 | kfree(ec); |
635 | return -EINVAL; | 706 | return -EINVAL; |
636 | } | 707 | } |
@@ -641,6 +712,8 @@ static int acpi_ec_add(struct acpi_device *device) | |||
641 | /* We might have incorrect info for GL at boot time */ | 712 | /* We might have incorrect info for GL at boot time */ |
642 | mutex_lock(&boot_ec->lock); | 713 | mutex_lock(&boot_ec->lock); |
643 | boot_ec->global_lock = ec->global_lock; | 714 | boot_ec->global_lock = ec->global_lock; |
715 | /* Copy handlers from new ec into boot ec */ | ||
716 | list_splice(&ec->list, &boot_ec->list); | ||
644 | mutex_unlock(&boot_ec->lock); | 717 | mutex_unlock(&boot_ec->lock); |
645 | kfree(ec); | 718 | kfree(ec); |
646 | ec = boot_ec; | 719 | ec = boot_ec; |
@@ -651,22 +724,24 @@ static int acpi_ec_add(struct acpi_device *device) | |||
651 | acpi_driver_data(device) = ec; | 724 | acpi_driver_data(device) = ec; |
652 | 725 | ||
653 | acpi_ec_add_fs(device); | 726 | acpi_ec_add_fs(device); |
654 | |||
655 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.", | ||
656 | acpi_device_name(device), acpi_device_bid(device), | ||
657 | (u32) ec->gpe)); | ||
658 | |||
659 | return 0; | 727 | return 0; |
660 | } | 728 | } |
661 | 729 | ||
662 | static int acpi_ec_remove(struct acpi_device *device, int type) | 730 | static int acpi_ec_remove(struct acpi_device *device, int type) |
663 | { | 731 | { |
664 | struct acpi_ec *ec; | 732 | struct acpi_ec *ec; |
733 | struct acpi_ec_query_handler *handler; | ||
665 | 734 | ||
666 | if (!device) | 735 | if (!device) |
667 | return -EINVAL; | 736 | return -EINVAL; |
668 | 737 | ||
669 | ec = acpi_driver_data(device); | 738 | ec = acpi_driver_data(device); |
739 | mutex_lock(&ec->lock); | ||
740 | list_for_each_entry(handler, &ec->list, node) { | ||
741 | list_del(&handler->node); | ||
742 | kfree(handler); | ||
743 | } | ||
744 | mutex_unlock(&ec->lock); | ||
670 | acpi_ec_remove_fs(device); | 745 | acpi_ec_remove_fs(device); |
671 | acpi_driver_data(device) = NULL; | 746 | acpi_driver_data(device) = NULL; |
672 | if (ec == first_ec) | 747 | if (ec == first_ec) |
@@ -722,15 +797,13 @@ static int ec_install_handlers(struct acpi_ec *ec) | |||
722 | return -ENODEV; | 797 | return -ENODEV; |
723 | } | 798 | } |
724 | 799 | ||
725 | /* EC is fully operational, allow queries */ | ||
726 | atomic_set(&ec->query_pending, 0); | ||
727 | |||
728 | return 0; | 800 | return 0; |
729 | } | 801 | } |
730 | 802 | ||
731 | static int acpi_ec_start(struct acpi_device *device) | 803 | static int acpi_ec_start(struct acpi_device *device) |
732 | { | 804 | { |
733 | struct acpi_ec *ec; | 805 | struct acpi_ec *ec; |
806 | int ret = 0; | ||
734 | 807 | ||
735 | if (!device) | 808 | if (!device) |
736 | return -EINVAL; | 809 | return -EINVAL; |
@@ -740,14 +813,14 @@ static int acpi_ec_start(struct acpi_device *device) | |||
740 | if (!ec) | 813 | if (!ec) |
741 | return -EINVAL; | 814 | return -EINVAL; |
742 | 815 | ||
743 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx", | ||
744 | ec->gpe, ec->command_addr, ec->data_addr)); | ||
745 | |||
746 | /* Boot EC is already working */ | 816 | /* Boot EC is already working */ |
747 | if (ec == boot_ec) | 817 | if (ec != boot_ec) |
748 | return 0; | 818 | ret = ec_install_handlers(ec); |
819 | |||
820 | /* EC is fully operational, allow queries */ | ||
821 | atomic_set(&ec->query_pending, 0); | ||
749 | 822 | ||
750 | return ec_install_handlers(ec); | 823 | return ret; |
751 | } | 824 | } |
752 | 825 | ||
753 | static int acpi_ec_stop(struct acpi_device *device, int type) | 826 | static int acpi_ec_stop(struct acpi_device *device, int type) |
@@ -779,34 +852,6 @@ static int acpi_ec_stop(struct acpi_device *device, int type) | |||
779 | return 0; | 852 | return 0; |
780 | } | 853 | } |
781 | 854 | ||
782 | static acpi_status | ||
783 | ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval) | ||
784 | { | ||
785 | acpi_status status; | ||
786 | |||
787 | struct acpi_ec *ec = context; | ||
788 | status = acpi_walk_resources(handle, METHOD_NAME__CRS, | ||
789 | ec_parse_io_ports, ec); | ||
790 | if (ACPI_FAILURE(status)) | ||
791 | return status; | ||
792 | |||
793 | /* Get GPE bit assignment (EC events). */ | ||
794 | /* TODO: Add support for _GPE returning a package */ | ||
795 | status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe); | ||
796 | if (ACPI_FAILURE(status)) | ||
797 | return status; | ||
798 | |||
799 | /* Use the global lock for all EC transactions? */ | ||
800 | acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock); | ||
801 | |||
802 | ec->handle = handle; | ||
803 | |||
804 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx", | ||
805 | ec->gpe, ec->command_addr, ec->data_addr)); | ||
806 | |||
807 | return AE_CTRL_TERMINATE; | ||
808 | } | ||
809 | |||
810 | int __init acpi_ec_ecdt_probe(void) | 855 | int __init acpi_ec_ecdt_probe(void) |
811 | { | 856 | { |
812 | int ret; | 857 | int ret; |
@@ -825,7 +870,7 @@ int __init acpi_ec_ecdt_probe(void) | |||
825 | if (ACPI_FAILURE(status)) | 870 | if (ACPI_FAILURE(status)) |
826 | goto error; | 871 | goto error; |
827 | 872 | ||
828 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT")); | 873 | printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n"); |
829 | 874 | ||
830 | boot_ec->command_addr = ecdt_ptr->control.address; | 875 | boot_ec->command_addr = ecdt_ptr->control.address; |
831 | boot_ec->data_addr = ecdt_ptr->data.address; | 876 | boot_ec->data_addr = ecdt_ptr->data.address; |
diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index 3b23562e6f..dfa5853b17 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c | |||
@@ -11,6 +11,8 @@ | |||
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <linux/poll.h> | 12 | #include <linux/poll.h> |
13 | #include <acpi/acpi_drivers.h> | 13 | #include <acpi/acpi_drivers.h> |
14 | #include <net/netlink.h> | ||
15 | #include <net/genetlink.h> | ||
14 | 16 | ||
15 | #define _COMPONENT ACPI_SYSTEM_COMPONENT | 17 | #define _COMPONENT ACPI_SYSTEM_COMPONENT |
16 | ACPI_MODULE_NAME("event"); | 18 | ACPI_MODULE_NAME("event"); |
@@ -48,7 +50,6 @@ acpi_system_read_event(struct file *file, char __user * buffer, size_t count, | |||
48 | static int chars_remaining = 0; | 50 | static int chars_remaining = 0; |
49 | static char *ptr; | 51 | static char *ptr; |
50 | 52 | ||
51 | |||
52 | if (!chars_remaining) { | 53 | if (!chars_remaining) { |
53 | memset(&event, 0, sizeof(struct acpi_bus_event)); | 54 | memset(&event, 0, sizeof(struct acpi_bus_event)); |
54 | 55 | ||
@@ -106,23 +107,161 @@ static const struct file_operations acpi_system_event_ops = { | |||
106 | .poll = acpi_system_poll_event, | 107 | .poll = acpi_system_poll_event, |
107 | }; | 108 | }; |
108 | 109 | ||
110 | #ifdef CONFIG_NET | ||
111 | unsigned int acpi_event_seqnum; | ||
112 | struct acpi_genl_event { | ||
113 | acpi_device_class device_class; | ||
114 | char bus_id[15]; | ||
115 | u32 type; | ||
116 | u32 data; | ||
117 | }; | ||
118 | |||
119 | /* attributes of acpi_genl_family */ | ||
120 | enum { | ||
121 | ACPI_GENL_ATTR_UNSPEC, | ||
122 | ACPI_GENL_ATTR_EVENT, /* ACPI event info needed by user space */ | ||
123 | __ACPI_GENL_ATTR_MAX, | ||
124 | }; | ||
125 | #define ACPI_GENL_ATTR_MAX (__ACPI_GENL_ATTR_MAX - 1) | ||
126 | |||
127 | /* commands supported by the acpi_genl_family */ | ||
128 | enum { | ||
129 | ACPI_GENL_CMD_UNSPEC, | ||
130 | ACPI_GENL_CMD_EVENT, /* kernel->user notifications for ACPI events */ | ||
131 | __ACPI_GENL_CMD_MAX, | ||
132 | }; | ||
133 | #define ACPI_GENL_CMD_MAX (__ACPI_GENL_CMD_MAX - 1) | ||
134 | |||
135 | #define ACPI_GENL_FAMILY_NAME "acpi_event" | ||
136 | #define ACPI_GENL_VERSION 0x01 | ||
137 | #define ACPI_GENL_MCAST_GROUP_NAME "acpi_mc_group" | ||
138 | |||
139 | static struct genl_family acpi_event_genl_family = { | ||
140 | .id = GENL_ID_GENERATE, | ||
141 | .name = ACPI_GENL_FAMILY_NAME, | ||
142 | .version = ACPI_GENL_VERSION, | ||
143 | .maxattr = ACPI_GENL_ATTR_MAX, | ||
144 | }; | ||
145 | |||
146 | static struct genl_multicast_group acpi_event_mcgrp = { | ||
147 | .name = ACPI_GENL_MCAST_GROUP_NAME, | ||
148 | }; | ||
149 | |||
150 | int acpi_bus_generate_genetlink_event(struct acpi_device *device, | ||
151 | u8 type, int data) | ||
152 | { | ||
153 | struct sk_buff *skb; | ||
154 | struct nlattr *attr; | ||
155 | struct acpi_genl_event *event; | ||
156 | void *msg_header; | ||
157 | int size; | ||
158 | int result; | ||
159 | |||
160 | /* allocate memory */ | ||
161 | size = nla_total_size(sizeof(struct acpi_genl_event)) + | ||
162 | nla_total_size(0); | ||
163 | |||
164 | skb = genlmsg_new(size, GFP_ATOMIC); | ||
165 | if (!skb) | ||
166 | return -ENOMEM; | ||
167 | |||
168 | /* add the genetlink message header */ | ||
169 | msg_header = genlmsg_put(skb, 0, acpi_event_seqnum++, | ||
170 | &acpi_event_genl_family, 0, | ||
171 | ACPI_GENL_CMD_EVENT); | ||
172 | if (!msg_header) { | ||
173 | nlmsg_free(skb); | ||
174 | return -ENOMEM; | ||
175 | } | ||
176 | |||
177 | /* fill the data */ | ||
178 | attr = | ||
179 | nla_reserve(skb, ACPI_GENL_ATTR_EVENT, | ||
180 | sizeof(struct acpi_genl_event)); | ||
181 | if (!attr) { | ||
182 | nlmsg_free(skb); | ||
183 | return -EINVAL; | ||
184 | } | ||
185 | |||
186 | event = nla_data(attr); | ||
187 | if (!event) { | ||
188 | nlmsg_free(skb); | ||
189 | return -EINVAL; | ||
190 | } | ||
191 | |||
192 | memset(event, 0, sizeof(struct acpi_genl_event)); | ||
193 | |||
194 | strcpy(event->device_class, device->pnp.device_class); | ||
195 | strcpy(event->bus_id, device->dev.bus_id); | ||
196 | event->type = type; | ||
197 | event->data = data; | ||
198 | |||
199 | /* send multicast genetlink message */ | ||
200 | result = genlmsg_end(skb, msg_header); | ||
201 | if (result < 0) { | ||
202 | nlmsg_free(skb); | ||
203 | return result; | ||
204 | } | ||
205 | |||
206 | result = | ||
207 | genlmsg_multicast(skb, 0, acpi_event_mcgrp.id, GFP_ATOMIC); | ||
208 | if (result) | ||
209 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | ||
210 | "Failed to send a Genetlink message!\n")); | ||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | static int acpi_event_genetlink_init(void) | ||
215 | { | ||
216 | int result; | ||
217 | |||
218 | result = genl_register_family(&acpi_event_genl_family); | ||
219 | if (result) | ||
220 | return result; | ||
221 | |||
222 | result = genl_register_mc_group(&acpi_event_genl_family, | ||
223 | &acpi_event_mcgrp); | ||
224 | if (result) | ||
225 | genl_unregister_family(&acpi_event_genl_family); | ||
226 | |||
227 | return result; | ||
228 | } | ||
229 | |||
230 | #else | ||
231 | int acpi_bus_generate_genetlink_event(struct acpi_device *device, u8 type, | ||
232 | int data) | ||
233 | { | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static int acpi_event_genetlink_init(void) | ||
238 | { | ||
239 | return -ENODEV; | ||
240 | } | ||
241 | #endif | ||
242 | |||
109 | static int __init acpi_event_init(void) | 243 | static int __init acpi_event_init(void) |
110 | { | 244 | { |
111 | struct proc_dir_entry *entry; | 245 | struct proc_dir_entry *entry; |
112 | int error = 0; | 246 | int error = 0; |
113 | 247 | ||
114 | |||
115 | if (acpi_disabled) | 248 | if (acpi_disabled) |
116 | return 0; | 249 | return 0; |
117 | 250 | ||
251 | /* create genetlink for acpi event */ | ||
252 | error = acpi_event_genetlink_init(); | ||
253 | if (error) | ||
254 | printk(KERN_WARNING PREFIX | ||
255 | "Failed to create genetlink family for ACPI event\n"); | ||
256 | |||
118 | /* 'event' [R] */ | 257 | /* 'event' [R] */ |
119 | entry = create_proc_entry("event", S_IRUSR, acpi_root_dir); | 258 | entry = create_proc_entry("event", S_IRUSR, acpi_root_dir); |
120 | if (entry) | 259 | if (entry) |
121 | entry->proc_fops = &acpi_system_event_ops; | 260 | entry->proc_fops = &acpi_system_event_ops; |
122 | else { | 261 | else |
123 | error = -ENODEV; | 262 | return -ENODEV; |
124 | } | 263 | |
125 | return error; | 264 | return 0; |
126 | } | 265 | } |
127 | 266 | ||
128 | subsys_initcall(acpi_event_init); | 267 | fs_initcall(acpi_event_init); |
diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c index 902c287b3a..361ebe6c4a 100644 --- a/drivers/acpi/events/evgpeblk.c +++ b/drivers/acpi/events/evgpeblk.c | |||
@@ -586,6 +586,10 @@ acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt) | |||
586 | flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); | 586 | flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); |
587 | if (gpe_xrupt->previous) { | 587 | if (gpe_xrupt->previous) { |
588 | gpe_xrupt->previous->next = gpe_xrupt->next; | 588 | gpe_xrupt->previous->next = gpe_xrupt->next; |
589 | } else { | ||
590 | /* No previous, update list head */ | ||
591 | |||
592 | acpi_gbl_gpe_xrupt_list_head = gpe_xrupt->next; | ||
589 | } | 593 | } |
590 | 594 | ||
591 | if (gpe_xrupt->next) { | 595 | if (gpe_xrupt->next) { |
diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c index 400d90fca9..23ee7bc4a7 100644 --- a/drivers/acpi/events/evrgnini.c +++ b/drivers/acpi/events/evrgnini.c | |||
@@ -284,6 +284,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, | |||
284 | } | 284 | } |
285 | 285 | ||
286 | if (!pci_device_node) { | 286 | if (!pci_device_node) { |
287 | ACPI_FREE(pci_id); | ||
287 | return_ACPI_STATUS(AE_AML_OPERAND_TYPE); | 288 | return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
288 | } | 289 | } |
289 | 290 | ||
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 41427a41f6..4893e256e3 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c | |||
@@ -16,7 +16,7 @@ | |||
16 | #if ACPI_GLUE_DEBUG | 16 | #if ACPI_GLUE_DEBUG |
17 | #define DBG(x...) printk(PREFIX x) | 17 | #define DBG(x...) printk(PREFIX x) |
18 | #else | 18 | #else |
19 | #define DBG(x...) | 19 | #define DBG(x...) do { } while(0) |
20 | #endif | 20 | #endif |
21 | static LIST_HEAD(bus_type_list); | 21 | static LIST_HEAD(bus_type_list); |
22 | static DECLARE_RWSEM(bus_type_sem); | 22 | static DECLARE_RWSEM(bus_type_sem); |
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index 0c9f15c54e..ab04d848b1 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c | |||
@@ -36,13 +36,11 @@ | |||
36 | ACPI_MODULE_NAME("numa"); | 36 | ACPI_MODULE_NAME("numa"); |
37 | 37 | ||
38 | static nodemask_t nodes_found_map = NODE_MASK_NONE; | 38 | static nodemask_t nodes_found_map = NODE_MASK_NONE; |
39 | #define PXM_INVAL -1 | ||
40 | #define NID_INVAL -1 | ||
41 | 39 | ||
42 | /* maps to convert between proximity domain and logical node ID */ | 40 | /* maps to convert between proximity domain and logical node ID */ |
43 | static int pxm_to_node_map[MAX_PXM_DOMAINS] | 41 | static int __cpuinitdata pxm_to_node_map[MAX_PXM_DOMAINS] |
44 | = { [0 ... MAX_PXM_DOMAINS - 1] = NID_INVAL }; | 42 | = { [0 ... MAX_PXM_DOMAINS - 1] = NID_INVAL }; |
45 | static int node_to_pxm_map[MAX_NUMNODES] | 43 | static int __cpuinitdata node_to_pxm_map[MAX_NUMNODES] |
46 | = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL }; | 44 | = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL }; |
47 | 45 | ||
48 | int pxm_to_node(int pxm) | 46 | int pxm_to_node(int pxm) |
@@ -59,6 +57,12 @@ int node_to_pxm(int node) | |||
59 | return node_to_pxm_map[node]; | 57 | return node_to_pxm_map[node]; |
60 | } | 58 | } |
61 | 59 | ||
60 | void __acpi_map_pxm_to_node(int pxm, int node) | ||
61 | { | ||
62 | pxm_to_node_map[pxm] = node; | ||
63 | node_to_pxm_map[node] = pxm; | ||
64 | } | ||
65 | |||
62 | int acpi_map_pxm_to_node(int pxm) | 66 | int acpi_map_pxm_to_node(int pxm) |
63 | { | 67 | { |
64 | int node = pxm_to_node_map[pxm]; | 68 | int node = pxm_to_node_map[pxm]; |
@@ -67,8 +71,7 @@ int acpi_map_pxm_to_node(int pxm) | |||
67 | if (nodes_weight(nodes_found_map) >= MAX_NUMNODES) | 71 | if (nodes_weight(nodes_found_map) >= MAX_NUMNODES) |
68 | return NID_INVAL; | 72 | return NID_INVAL; |
69 | node = first_unset_node(nodes_found_map); | 73 | node = first_unset_node(nodes_found_map); |
70 | pxm_to_node_map[pxm] = node; | 74 | __acpi_map_pxm_to_node(pxm, node); |
71 | node_to_pxm_map[node] = pxm; | ||
72 | node_set(node, nodes_found_map); | 75 | node_set(node, nodes_found_map); |
73 | } | 76 | } |
74 | 77 | ||
@@ -83,7 +86,8 @@ void __cpuinit acpi_unmap_pxm_to_node(int node) | |||
83 | node_clear(node, nodes_found_map); | 86 | node_clear(node, nodes_found_map); |
84 | } | 87 | } |
85 | 88 | ||
86 | void __init acpi_table_print_srat_entry(struct acpi_subtable_header * header) | 89 | static void __init |
90 | acpi_table_print_srat_entry(struct acpi_subtable_header *header) | ||
87 | { | 91 | { |
88 | 92 | ||
89 | ACPI_FUNCTION_NAME("acpi_table_print_srat_entry"); | 93 | ACPI_FUNCTION_NAME("acpi_table_print_srat_entry"); |
@@ -200,7 +204,7 @@ static int __init acpi_parse_srat(struct acpi_table_header *table) | |||
200 | return 0; | 204 | return 0; |
201 | } | 205 | } |
202 | 206 | ||
203 | int __init | 207 | static int __init |
204 | acpi_table_parse_srat(enum acpi_srat_type id, | 208 | acpi_table_parse_srat(enum acpi_srat_type id, |
205 | acpi_table_entry_handler handler, unsigned int max_entries) | 209 | acpi_table_entry_handler handler, unsigned int max_entries) |
206 | { | 210 | { |
@@ -211,14 +215,13 @@ acpi_table_parse_srat(enum acpi_srat_type id, | |||
211 | 215 | ||
212 | int __init acpi_numa_init(void) | 216 | int __init acpi_numa_init(void) |
213 | { | 217 | { |
214 | int result; | ||
215 | |||
216 | /* SRAT: Static Resource Affinity Table */ | 218 | /* SRAT: Static Resource Affinity Table */ |
217 | if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) { | 219 | if (!acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat)) { |
218 | result = acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY, | 220 | acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY, |
219 | acpi_parse_processor_affinity, | 221 | acpi_parse_processor_affinity, NR_CPUS); |
220 | NR_CPUS); | 222 | acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY, |
221 | result = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY, acpi_parse_memory_affinity, NR_NODE_MEMBLKS); // IA64 specific | 223 | acpi_parse_memory_affinity, |
224 | NR_NODE_MEMBLKS); | ||
222 | } | 225 | } |
223 | 226 | ||
224 | /* SLIT: System Locality Information Table */ | 227 | /* SLIT: System Locality Information Table */ |
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 00d53c2fd1..12c09fafce 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c | |||
@@ -77,13 +77,7 @@ static struct workqueue_struct *kacpi_notify_wq; | |||
77 | #define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ | 77 | #define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ |
78 | static char osi_additional_string[OSI_STRING_LENGTH_MAX]; | 78 | static char osi_additional_string[OSI_STRING_LENGTH_MAX]; |
79 | 79 | ||
80 | #define OSI_LINUX_ENABLED | 80 | static int osi_linux; /* disable _OSI(Linux) by default */ |
81 | #ifdef OSI_LINUX_ENABLED | ||
82 | int osi_linux = 1; /* enable _OSI(Linux) by default */ | ||
83 | #else | ||
84 | int osi_linux; /* disable _OSI(Linux) by default */ | ||
85 | #endif | ||
86 | |||
87 | 81 | ||
88 | #ifdef CONFIG_DMI | 82 | #ifdef CONFIG_DMI |
89 | static struct __initdata dmi_system_id acpi_osl_dmi_table[]; | 83 | static struct __initdata dmi_system_id acpi_osl_dmi_table[]; |
@@ -1183,17 +1177,10 @@ acpi_os_validate_interface (char *interface) | |||
1183 | if (!strcmp("Linux", interface)) { | 1177 | if (!strcmp("Linux", interface)) { |
1184 | printk(KERN_WARNING PREFIX | 1178 | printk(KERN_WARNING PREFIX |
1185 | "System BIOS is requesting _OSI(Linux)\n"); | 1179 | "System BIOS is requesting _OSI(Linux)\n"); |
1186 | #ifdef OSI_LINUX_ENABLED | ||
1187 | printk(KERN_WARNING PREFIX | ||
1188 | "Please test with \"acpi_osi=!Linux\"\n" | ||
1189 | "Please send dmidecode " | ||
1190 | "to linux-acpi@vger.kernel.org\n"); | ||
1191 | #else | ||
1192 | printk(KERN_WARNING PREFIX | 1180 | printk(KERN_WARNING PREFIX |
1193 | "If \"acpi_osi=Linux\" works better,\n" | 1181 | "If \"acpi_osi=Linux\" works better,\n" |
1194 | "Please send dmidecode " | 1182 | "Please send dmidecode " |
1195 | "to linux-acpi@vger.kernel.org\n"); | 1183 | "to linux-acpi@vger.kernel.org\n"); |
1196 | #endif | ||
1197 | if(osi_linux) | 1184 | if(osi_linux) |
1198 | return AE_OK; | 1185 | return AE_OK; |
1199 | } | 1186 | } |
@@ -1227,36 +1214,14 @@ acpi_os_validate_address ( | |||
1227 | } | 1214 | } |
1228 | 1215 | ||
1229 | #ifdef CONFIG_DMI | 1216 | #ifdef CONFIG_DMI |
1230 | #ifdef OSI_LINUX_ENABLED | ||
1231 | static int dmi_osi_not_linux(struct dmi_system_id *d) | ||
1232 | { | ||
1233 | printk(KERN_NOTICE "%s detected: requires not _OSI(Linux)\n", d->ident); | ||
1234 | enable_osi_linux(0); | ||
1235 | return 0; | ||
1236 | } | ||
1237 | #else | ||
1238 | static int dmi_osi_linux(struct dmi_system_id *d) | 1217 | static int dmi_osi_linux(struct dmi_system_id *d) |
1239 | { | 1218 | { |
1240 | printk(KERN_NOTICE "%s detected: requires _OSI(Linux)\n", d->ident); | 1219 | printk(KERN_NOTICE "%s detected: enabling _OSI(Linux)\n", d->ident); |
1241 | enable_osi_linux(1); | 1220 | enable_osi_linux(1); |
1242 | return 0; | 1221 | return 0; |
1243 | } | 1222 | } |
1244 | #endif | ||
1245 | 1223 | ||
1246 | static struct dmi_system_id acpi_osl_dmi_table[] __initdata = { | 1224 | static struct dmi_system_id acpi_osl_dmi_table[] __initdata = { |
1247 | #ifdef OSI_LINUX_ENABLED | ||
1248 | /* | ||
1249 | * Boxes that need NOT _OSI(Linux) | ||
1250 | */ | ||
1251 | { | ||
1252 | .callback = dmi_osi_not_linux, | ||
1253 | .ident = "Toshiba Satellite P100", | ||
1254 | .matches = { | ||
1255 | DMI_MATCH(DMI_BOARD_VENDOR, "TOSHIBA"), | ||
1256 | DMI_MATCH(DMI_BOARD_NAME, "Satellite P100"), | ||
1257 | }, | ||
1258 | }, | ||
1259 | #else | ||
1260 | /* | 1225 | /* |
1261 | * Boxes that need _OSI(Linux) | 1226 | * Boxes that need _OSI(Linux) |
1262 | */ | 1227 | */ |
@@ -1268,7 +1233,6 @@ static struct dmi_system_id acpi_osl_dmi_table[] __initdata = { | |||
1268 | DMI_MATCH(DMI_BOARD_NAME, "MPAD-MSAE Customer Reference Boards"), | 1233 | DMI_MATCH(DMI_BOARD_NAME, "MPAD-MSAE Customer Reference Boards"), |
1269 | }, | 1234 | }, |
1270 | }, | 1235 | }, |
1271 | #endif | ||
1272 | {} | 1236 | {} |
1273 | }; | 1237 | }; |
1274 | #endif /* CONFIG_DMI */ | 1238 | #endif /* CONFIG_DMI */ |
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index acc5947713..3448edd61d 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c | |||
@@ -733,7 +733,7 @@ static int acpi_pci_link_add(struct acpi_device *device) | |||
733 | /* query and set link->irq.active */ | 733 | /* query and set link->irq.active */ |
734 | acpi_pci_link_get_current(link); | 734 | acpi_pci_link_get_current(link); |
735 | 735 | ||
736 | printk(PREFIX "%s [%s] (IRQs", acpi_device_name(device), | 736 | printk(KERN_INFO PREFIX "%s [%s] (IRQs", acpi_device_name(device), |
737 | acpi_device_bid(device)); | 737 | acpi_device_bid(device)); |
738 | for (i = 0; i < link->irq.possible_count; i++) { | 738 | for (i = 0; i < link->irq.possible_count; i++) { |
739 | if (link->irq.active == link->irq.possible[i]) { | 739 | if (link->irq.active == link->irq.possible[i]) { |
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index e1ca86dfdd..81aceb5da7 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c | |||
@@ -66,6 +66,7 @@ | |||
66 | #define ACPI_PROCESSOR_FILE_LIMIT "limit" | 66 | #define ACPI_PROCESSOR_FILE_LIMIT "limit" |
67 | #define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80 | 67 | #define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80 |
68 | #define ACPI_PROCESSOR_NOTIFY_POWER 0x81 | 68 | #define ACPI_PROCESSOR_NOTIFY_POWER 0x81 |
69 | #define ACPI_PROCESSOR_NOTIFY_THROTTLING 0x82 | ||
69 | 70 | ||
70 | #define ACPI_PROCESSOR_LIMIT_USER 0 | 71 | #define ACPI_PROCESSOR_LIMIT_USER 0 |
71 | #define ACPI_PROCESSOR_LIMIT_THERMAL 1 | 72 | #define ACPI_PROCESSOR_LIMIT_THERMAL 1 |
@@ -84,6 +85,8 @@ static int acpi_processor_info_open_fs(struct inode *inode, struct file *file); | |||
84 | static void acpi_processor_notify(acpi_handle handle, u32 event, void *data); | 85 | static void acpi_processor_notify(acpi_handle handle, u32 event, void *data); |
85 | static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu); | 86 | static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu); |
86 | static int acpi_processor_handle_eject(struct acpi_processor *pr); | 87 | static int acpi_processor_handle_eject(struct acpi_processor *pr); |
88 | extern int acpi_processor_tstate_has_changed(struct acpi_processor *pr); | ||
89 | |||
87 | 90 | ||
88 | static struct acpi_driver acpi_processor_driver = { | 91 | static struct acpi_driver acpi_processor_driver = { |
89 | .name = "processor", | 92 | .name = "processor", |
@@ -696,6 +699,9 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data) | |||
696 | acpi_processor_cst_has_changed(pr); | 699 | acpi_processor_cst_has_changed(pr); |
697 | acpi_bus_generate_event(device, event, 0); | 700 | acpi_bus_generate_event(device, event, 0); |
698 | break; | 701 | break; |
702 | case ACPI_PROCESSOR_NOTIFY_THROTTLING: | ||
703 | acpi_processor_tstate_has_changed(pr); | ||
704 | acpi_bus_generate_event(device, event, 0); | ||
699 | default: | 705 | default: |
700 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 706 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
701 | "Unsupported event [0x%x]\n", event)); | 707 | "Unsupported event [0x%x]\n", event)); |
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index bb5d23be42..a898991f77 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c | |||
@@ -490,7 +490,17 @@ static void acpi_processor_idle(void) | |||
490 | 490 | ||
491 | case ACPI_STATE_C3: | 491 | case ACPI_STATE_C3: |
492 | 492 | ||
493 | if (pr->flags.bm_check) { | 493 | /* |
494 | * disable bus master | ||
495 | * bm_check implies we need ARB_DIS | ||
496 | * !bm_check implies we need cache flush | ||
497 | * bm_control implies whether we can do ARB_DIS | ||
498 | * | ||
499 | * That leaves a case where bm_check is set and bm_control is | ||
500 | * not set. In that case we cannot do much, we enter C3 | ||
501 | * without doing anything. | ||
502 | */ | ||
503 | if (pr->flags.bm_check && pr->flags.bm_control) { | ||
494 | if (atomic_inc_return(&c3_cpu_count) == | 504 | if (atomic_inc_return(&c3_cpu_count) == |
495 | num_online_cpus()) { | 505 | num_online_cpus()) { |
496 | /* | 506 | /* |
@@ -499,7 +509,7 @@ static void acpi_processor_idle(void) | |||
499 | */ | 509 | */ |
500 | acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1); | 510 | acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1); |
501 | } | 511 | } |
502 | } else { | 512 | } else if (!pr->flags.bm_check) { |
503 | /* SMP with no shared cache... Invalidate cache */ | 513 | /* SMP with no shared cache... Invalidate cache */ |
504 | ACPI_FLUSH_CPU_CACHE(); | 514 | ACPI_FLUSH_CPU_CACHE(); |
505 | } | 515 | } |
@@ -511,7 +521,7 @@ static void acpi_processor_idle(void) | |||
511 | acpi_cstate_enter(cx); | 521 | acpi_cstate_enter(cx); |
512 | /* Get end time (ticks) */ | 522 | /* Get end time (ticks) */ |
513 | t2 = inl(acpi_gbl_FADT.xpm_timer_block.address); | 523 | t2 = inl(acpi_gbl_FADT.xpm_timer_block.address); |
514 | if (pr->flags.bm_check) { | 524 | if (pr->flags.bm_check && pr->flags.bm_control) { |
515 | /* Enable bus master arbitration */ | 525 | /* Enable bus master arbitration */ |
516 | atomic_dec(&c3_cpu_count); | 526 | atomic_dec(&c3_cpu_count); |
517 | acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0); | 527 | acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0); |
@@ -961,9 +971,9 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr, | |||
961 | if (pr->flags.bm_check) { | 971 | if (pr->flags.bm_check) { |
962 | /* bus mastering control is necessary */ | 972 | /* bus mastering control is necessary */ |
963 | if (!pr->flags.bm_control) { | 973 | if (!pr->flags.bm_control) { |
974 | /* In this case we enter C3 without bus mastering */ | ||
964 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 975 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
965 | "C3 support requires bus mastering control\n")); | 976 | "C3 support without bus mastering control\n")); |
966 | return; | ||
967 | } | 977 | } |
968 | } else { | 978 | } else { |
969 | /* | 979 | /* |
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index b33486009f..3f55d1f90c 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c | |||
@@ -44,17 +44,231 @@ | |||
44 | #define _COMPONENT ACPI_PROCESSOR_COMPONENT | 44 | #define _COMPONENT ACPI_PROCESSOR_COMPONENT |
45 | ACPI_MODULE_NAME("processor_throttling"); | 45 | ACPI_MODULE_NAME("processor_throttling"); |
46 | 46 | ||
47 | static int acpi_processor_get_throttling(struct acpi_processor *pr); | ||
48 | int acpi_processor_set_throttling(struct acpi_processor *pr, int state); | ||
49 | |||
50 | static int acpi_processor_get_platform_limit(struct acpi_processor *pr) | ||
51 | { | ||
52 | acpi_status status = 0; | ||
53 | unsigned long tpc = 0; | ||
54 | |||
55 | if (!pr) | ||
56 | return -EINVAL; | ||
57 | status = acpi_evaluate_integer(pr->handle, "_TPC", NULL, &tpc); | ||
58 | if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { | ||
59 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TPC")); | ||
60 | return -ENODEV; | ||
61 | } | ||
62 | pr->throttling_platform_limit = (int)tpc; | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | int acpi_processor_tstate_has_changed(struct acpi_processor *pr) | ||
67 | { | ||
68 | return acpi_processor_get_platform_limit(pr); | ||
69 | } | ||
70 | |||
71 | /* -------------------------------------------------------------------------- | ||
72 | _PTC, _TSS, _TSD support | ||
73 | -------------------------------------------------------------------------- */ | ||
74 | static int acpi_processor_get_throttling_control(struct acpi_processor *pr) | ||
75 | { | ||
76 | int result = 0; | ||
77 | acpi_status status = 0; | ||
78 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
79 | union acpi_object *ptc = NULL; | ||
80 | union acpi_object obj = { 0 }; | ||
81 | |||
82 | status = acpi_evaluate_object(pr->handle, "_PTC", NULL, &buffer); | ||
83 | if (ACPI_FAILURE(status)) { | ||
84 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PTC")); | ||
85 | return -ENODEV; | ||
86 | } | ||
87 | |||
88 | ptc = (union acpi_object *)buffer.pointer; | ||
89 | if (!ptc || (ptc->type != ACPI_TYPE_PACKAGE) | ||
90 | || (ptc->package.count != 2)) { | ||
91 | printk(KERN_ERR PREFIX "Invalid _PTC data\n"); | ||
92 | result = -EFAULT; | ||
93 | goto end; | ||
94 | } | ||
95 | |||
96 | /* | ||
97 | * control_register | ||
98 | */ | ||
99 | |||
100 | obj = ptc->package.elements[0]; | ||
101 | |||
102 | if ((obj.type != ACPI_TYPE_BUFFER) | ||
103 | || (obj.buffer.length < sizeof(struct acpi_ptc_register)) | ||
104 | || (obj.buffer.pointer == NULL)) { | ||
105 | printk(KERN_ERR PREFIX | ||
106 | "Invalid _PTC data (control_register)\n"); | ||
107 | result = -EFAULT; | ||
108 | goto end; | ||
109 | } | ||
110 | memcpy(&pr->throttling.control_register, obj.buffer.pointer, | ||
111 | sizeof(struct acpi_ptc_register)); | ||
112 | |||
113 | /* | ||
114 | * status_register | ||
115 | */ | ||
116 | |||
117 | obj = ptc->package.elements[1]; | ||
118 | |||
119 | if ((obj.type != ACPI_TYPE_BUFFER) | ||
120 | || (obj.buffer.length < sizeof(struct acpi_ptc_register)) | ||
121 | || (obj.buffer.pointer == NULL)) { | ||
122 | printk(KERN_ERR PREFIX "Invalid _PTC data (status_register)\n"); | ||
123 | result = -EFAULT; | ||
124 | goto end; | ||
125 | } | ||
126 | |||
127 | memcpy(&pr->throttling.status_register, obj.buffer.pointer, | ||
128 | sizeof(struct acpi_ptc_register)); | ||
129 | |||
130 | end: | ||
131 | kfree(buffer.pointer); | ||
132 | |||
133 | return result; | ||
134 | } | ||
135 | static int acpi_processor_get_throttling_states(struct acpi_processor *pr) | ||
136 | { | ||
137 | int result = 0; | ||
138 | acpi_status status = AE_OK; | ||
139 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
140 | struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" }; | ||
141 | struct acpi_buffer state = { 0, NULL }; | ||
142 | union acpi_object *tss = NULL; | ||
143 | int i; | ||
144 | |||
145 | status = acpi_evaluate_object(pr->handle, "_TSS", NULL, &buffer); | ||
146 | if (ACPI_FAILURE(status)) { | ||
147 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TSS")); | ||
148 | return -ENODEV; | ||
149 | } | ||
150 | |||
151 | tss = buffer.pointer; | ||
152 | if (!tss || (tss->type != ACPI_TYPE_PACKAGE)) { | ||
153 | printk(KERN_ERR PREFIX "Invalid _TSS data\n"); | ||
154 | result = -EFAULT; | ||
155 | goto end; | ||
156 | } | ||
157 | |||
158 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d throttling states\n", | ||
159 | tss->package.count)); | ||
160 | |||
161 | pr->throttling.state_count = tss->package.count; | ||
162 | pr->throttling.states_tss = | ||
163 | kmalloc(sizeof(struct acpi_processor_tx_tss) * tss->package.count, | ||
164 | GFP_KERNEL); | ||
165 | if (!pr->throttling.states_tss) { | ||
166 | result = -ENOMEM; | ||
167 | goto end; | ||
168 | } | ||
169 | |||
170 | for (i = 0; i < pr->throttling.state_count; i++) { | ||
171 | |||
172 | struct acpi_processor_tx_tss *tx = | ||
173 | (struct acpi_processor_tx_tss *)&(pr->throttling. | ||
174 | states_tss[i]); | ||
175 | |||
176 | state.length = sizeof(struct acpi_processor_tx_tss); | ||
177 | state.pointer = tx; | ||
178 | |||
179 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Extracting state %d\n", i)); | ||
180 | |||
181 | status = acpi_extract_package(&(tss->package.elements[i]), | ||
182 | &format, &state); | ||
183 | if (ACPI_FAILURE(status)) { | ||
184 | ACPI_EXCEPTION((AE_INFO, status, "Invalid _TSS data")); | ||
185 | result = -EFAULT; | ||
186 | kfree(pr->throttling.states_tss); | ||
187 | goto end; | ||
188 | } | ||
189 | |||
190 | if (!tx->freqpercentage) { | ||
191 | printk(KERN_ERR PREFIX | ||
192 | "Invalid _TSS data: freq is zero\n"); | ||
193 | result = -EFAULT; | ||
194 | kfree(pr->throttling.states_tss); | ||
195 | goto end; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | end: | ||
200 | kfree(buffer.pointer); | ||
201 | |||
202 | return result; | ||
203 | } | ||
204 | static int acpi_processor_get_tsd(struct acpi_processor *pr) | ||
205 | { | ||
206 | int result = 0; | ||
207 | acpi_status status = AE_OK; | ||
208 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
209 | struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" }; | ||
210 | struct acpi_buffer state = { 0, NULL }; | ||
211 | union acpi_object *tsd = NULL; | ||
212 | struct acpi_tsd_package *pdomain; | ||
213 | |||
214 | status = acpi_evaluate_object(pr->handle, "_TSD", NULL, &buffer); | ||
215 | if (ACPI_FAILURE(status)) { | ||
216 | return -ENODEV; | ||
217 | } | ||
218 | |||
219 | tsd = buffer.pointer; | ||
220 | if (!tsd || (tsd->type != ACPI_TYPE_PACKAGE)) { | ||
221 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n")); | ||
222 | result = -EFAULT; | ||
223 | goto end; | ||
224 | } | ||
225 | |||
226 | if (tsd->package.count != 1) { | ||
227 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n")); | ||
228 | result = -EFAULT; | ||
229 | goto end; | ||
230 | } | ||
231 | |||
232 | pdomain = &(pr->throttling.domain_info); | ||
233 | |||
234 | state.length = sizeof(struct acpi_tsd_package); | ||
235 | state.pointer = pdomain; | ||
236 | |||
237 | status = acpi_extract_package(&(tsd->package.elements[0]), | ||
238 | &format, &state); | ||
239 | if (ACPI_FAILURE(status)) { | ||
240 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n")); | ||
241 | result = -EFAULT; | ||
242 | goto end; | ||
243 | } | ||
244 | |||
245 | if (pdomain->num_entries != ACPI_TSD_REV0_ENTRIES) { | ||
246 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _TSD:num_entries\n")); | ||
247 | result = -EFAULT; | ||
248 | goto end; | ||
249 | } | ||
250 | |||
251 | if (pdomain->revision != ACPI_TSD_REV0_REVISION) { | ||
252 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _TSD:revision\n")); | ||
253 | result = -EFAULT; | ||
254 | goto end; | ||
255 | } | ||
256 | |||
257 | end: | ||
258 | kfree(buffer.pointer); | ||
259 | return result; | ||
260 | } | ||
261 | |||
47 | /* -------------------------------------------------------------------------- | 262 | /* -------------------------------------------------------------------------- |
48 | Throttling Control | 263 | Throttling Control |
49 | -------------------------------------------------------------------------- */ | 264 | -------------------------------------------------------------------------- */ |
50 | static int acpi_processor_get_throttling(struct acpi_processor *pr) | 265 | static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr) |
51 | { | 266 | { |
52 | int state = 0; | 267 | int state = 0; |
53 | u32 value = 0; | 268 | u32 value = 0; |
54 | u32 duty_mask = 0; | 269 | u32 duty_mask = 0; |
55 | u32 duty_value = 0; | 270 | u32 duty_value = 0; |
56 | 271 | ||
57 | |||
58 | if (!pr) | 272 | if (!pr) |
59 | return -EINVAL; | 273 | return -EINVAL; |
60 | 274 | ||
@@ -94,13 +308,115 @@ static int acpi_processor_get_throttling(struct acpi_processor *pr) | |||
94 | return 0; | 308 | return 0; |
95 | } | 309 | } |
96 | 310 | ||
97 | int acpi_processor_set_throttling(struct acpi_processor *pr, int state) | 311 | static int acpi_read_throttling_status(struct acpi_processor_throttling |
312 | *throttling) | ||
313 | { | ||
314 | int value = -1; | ||
315 | switch (throttling->status_register.space_id) { | ||
316 | case ACPI_ADR_SPACE_SYSTEM_IO: | ||
317 | acpi_os_read_port((acpi_io_address) throttling->status_register. | ||
318 | address, &value, | ||
319 | (u32) throttling->status_register.bit_width * | ||
320 | 8); | ||
321 | break; | ||
322 | case ACPI_ADR_SPACE_FIXED_HARDWARE: | ||
323 | printk(KERN_ERR PREFIX | ||
324 | "HARDWARE addr space,NOT supported yet\n"); | ||
325 | break; | ||
326 | default: | ||
327 | printk(KERN_ERR PREFIX "Unknown addr space %d\n", | ||
328 | (u32) (throttling->status_register.space_id)); | ||
329 | } | ||
330 | return value; | ||
331 | } | ||
332 | |||
333 | static int acpi_write_throttling_state(struct acpi_processor_throttling | ||
334 | *throttling, int value) | ||
335 | { | ||
336 | int ret = -1; | ||
337 | |||
338 | switch (throttling->control_register.space_id) { | ||
339 | case ACPI_ADR_SPACE_SYSTEM_IO: | ||
340 | acpi_os_write_port((acpi_io_address) throttling-> | ||
341 | control_register.address, value, | ||
342 | (u32) throttling->control_register. | ||
343 | bit_width * 8); | ||
344 | ret = 0; | ||
345 | break; | ||
346 | case ACPI_ADR_SPACE_FIXED_HARDWARE: | ||
347 | printk(KERN_ERR PREFIX | ||
348 | "HARDWARE addr space,NOT supported yet\n"); | ||
349 | break; | ||
350 | default: | ||
351 | printk(KERN_ERR PREFIX "Unknown addr space %d\n", | ||
352 | (u32) (throttling->control_register.space_id)); | ||
353 | } | ||
354 | return ret; | ||
355 | } | ||
356 | |||
357 | static int acpi_get_throttling_state(struct acpi_processor *pr, int value) | ||
358 | { | ||
359 | int i; | ||
360 | |||
361 | for (i = 0; i < pr->throttling.state_count; i++) { | ||
362 | struct acpi_processor_tx_tss *tx = | ||
363 | (struct acpi_processor_tx_tss *)&(pr->throttling. | ||
364 | states_tss[i]); | ||
365 | if (tx->control == value) | ||
366 | break; | ||
367 | } | ||
368 | if (i > pr->throttling.state_count) | ||
369 | i = -1; | ||
370 | return i; | ||
371 | } | ||
372 | |||
373 | static int acpi_get_throttling_value(struct acpi_processor *pr, int state) | ||
374 | { | ||
375 | int value = -1; | ||
376 | if (state >= 0 && state <= pr->throttling.state_count) { | ||
377 | struct acpi_processor_tx_tss *tx = | ||
378 | (struct acpi_processor_tx_tss *)&(pr->throttling. | ||
379 | states_tss[state]); | ||
380 | value = tx->control; | ||
381 | } | ||
382 | return value; | ||
383 | } | ||
384 | |||
385 | static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr) | ||
386 | { | ||
387 | int state = 0; | ||
388 | u32 value = 0; | ||
389 | |||
390 | if (!pr) | ||
391 | return -EINVAL; | ||
392 | |||
393 | if (!pr->flags.throttling) | ||
394 | return -ENODEV; | ||
395 | |||
396 | pr->throttling.state = 0; | ||
397 | local_irq_disable(); | ||
398 | value = acpi_read_throttling_status(&pr->throttling); | ||
399 | if (value >= 0) { | ||
400 | state = acpi_get_throttling_state(pr, value); | ||
401 | pr->throttling.state = state; | ||
402 | } | ||
403 | local_irq_enable(); | ||
404 | |||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | static int acpi_processor_get_throttling(struct acpi_processor *pr) | ||
409 | { | ||
410 | return pr->throttling.acpi_processor_get_throttling(pr); | ||
411 | } | ||
412 | |||
413 | static int acpi_processor_set_throttling_fadt(struct acpi_processor *pr, | ||
414 | int state) | ||
98 | { | 415 | { |
99 | u32 value = 0; | 416 | u32 value = 0; |
100 | u32 duty_mask = 0; | 417 | u32 duty_mask = 0; |
101 | u32 duty_value = 0; | 418 | u32 duty_value = 0; |
102 | 419 | ||
103 | |||
104 | if (!pr) | 420 | if (!pr) |
105 | return -EINVAL; | 421 | return -EINVAL; |
106 | 422 | ||
@@ -113,6 +429,8 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state) | |||
113 | if (state == pr->throttling.state) | 429 | if (state == pr->throttling.state) |
114 | return 0; | 430 | return 0; |
115 | 431 | ||
432 | if (state < pr->throttling_platform_limit) | ||
433 | return -EPERM; | ||
116 | /* | 434 | /* |
117 | * Calculate the duty_value and duty_mask. | 435 | * Calculate the duty_value and duty_mask. |
118 | */ | 436 | */ |
@@ -165,12 +483,51 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state) | |||
165 | return 0; | 483 | return 0; |
166 | } | 484 | } |
167 | 485 | ||
486 | static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr, | ||
487 | int state) | ||
488 | { | ||
489 | u32 value = 0; | ||
490 | |||
491 | if (!pr) | ||
492 | return -EINVAL; | ||
493 | |||
494 | if ((state < 0) || (state > (pr->throttling.state_count - 1))) | ||
495 | return -EINVAL; | ||
496 | |||
497 | if (!pr->flags.throttling) | ||
498 | return -ENODEV; | ||
499 | |||
500 | if (state == pr->throttling.state) | ||
501 | return 0; | ||
502 | |||
503 | if (state < pr->throttling_platform_limit) | ||
504 | return -EPERM; | ||
505 | |||
506 | local_irq_disable(); | ||
507 | |||
508 | value = acpi_get_throttling_value(pr, state); | ||
509 | if (value >= 0) { | ||
510 | acpi_write_throttling_state(&pr->throttling, value); | ||
511 | pr->throttling.state = state; | ||
512 | } | ||
513 | local_irq_enable(); | ||
514 | |||
515 | return 0; | ||
516 | } | ||
517 | |||
518 | int acpi_processor_set_throttling(struct acpi_processor *pr, int state) | ||
519 | { | ||
520 | return pr->throttling.acpi_processor_set_throttling(pr, state); | ||
521 | } | ||
522 | |||
168 | int acpi_processor_get_throttling_info(struct acpi_processor *pr) | 523 | int acpi_processor_get_throttling_info(struct acpi_processor *pr) |
169 | { | 524 | { |
170 | int result = 0; | 525 | int result = 0; |
171 | int step = 0; | 526 | int step = 0; |
172 | int i = 0; | 527 | int i = 0; |
173 | 528 | int no_ptc = 0; | |
529 | int no_tss = 0; | ||
530 | int no_tsd = 0; | ||
174 | 531 | ||
175 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 532 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
176 | "pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n", | 533 | "pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n", |
@@ -182,6 +539,21 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr) | |||
182 | return -EINVAL; | 539 | return -EINVAL; |
183 | 540 | ||
184 | /* TBD: Support ACPI 2.0 objects */ | 541 | /* TBD: Support ACPI 2.0 objects */ |
542 | no_ptc = acpi_processor_get_throttling_control(pr); | ||
543 | no_tss = acpi_processor_get_throttling_states(pr); | ||
544 | no_tsd = acpi_processor_get_tsd(pr); | ||
545 | |||
546 | if (no_ptc || no_tss) { | ||
547 | pr->throttling.acpi_processor_get_throttling = | ||
548 | &acpi_processor_get_throttling_fadt; | ||
549 | pr->throttling.acpi_processor_set_throttling = | ||
550 | &acpi_processor_set_throttling_fadt; | ||
551 | } else { | ||
552 | pr->throttling.acpi_processor_get_throttling = | ||
553 | &acpi_processor_get_throttling_ptc; | ||
554 | pr->throttling.acpi_processor_set_throttling = | ||
555 | &acpi_processor_set_throttling_ptc; | ||
556 | } | ||
185 | 557 | ||
186 | if (!pr->throttling.address) { | 558 | if (!pr->throttling.address) { |
187 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling register\n")); | 559 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling register\n")); |
@@ -262,7 +634,6 @@ static int acpi_processor_throttling_seq_show(struct seq_file *seq, | |||
262 | int i = 0; | 634 | int i = 0; |
263 | int result = 0; | 635 | int result = 0; |
264 | 636 | ||
265 | |||
266 | if (!pr) | 637 | if (!pr) |
267 | goto end; | 638 | goto end; |
268 | 639 | ||
@@ -280,15 +651,25 @@ static int acpi_processor_throttling_seq_show(struct seq_file *seq, | |||
280 | } | 651 | } |
281 | 652 | ||
282 | seq_printf(seq, "state count: %d\n" | 653 | seq_printf(seq, "state count: %d\n" |
283 | "active state: T%d\n", | 654 | "active state: T%d\n" |
284 | pr->throttling.state_count, pr->throttling.state); | 655 | "state available: T%d to T%d\n", |
656 | pr->throttling.state_count, pr->throttling.state, | ||
657 | pr->throttling_platform_limit, | ||
658 | pr->throttling.state_count - 1); | ||
285 | 659 | ||
286 | seq_puts(seq, "states:\n"); | 660 | seq_puts(seq, "states:\n"); |
287 | for (i = 0; i < pr->throttling.state_count; i++) | 661 | if (acpi_processor_get_throttling == acpi_processor_get_throttling_fadt) |
288 | seq_printf(seq, " %cT%d: %02d%%\n", | 662 | for (i = 0; i < pr->throttling.state_count; i++) |
289 | (i == pr->throttling.state ? '*' : ' '), i, | 663 | seq_printf(seq, " %cT%d: %02d%%\n", |
290 | (pr->throttling.states[i].performance ? pr-> | 664 | (i == pr->throttling.state ? '*' : ' '), i, |
291 | throttling.states[i].performance / 10 : 0)); | 665 | (pr->throttling.states[i].performance ? pr-> |
666 | throttling.states[i].performance / 10 : 0)); | ||
667 | else | ||
668 | for (i = 0; i < pr->throttling.state_count; i++) | ||
669 | seq_printf(seq, " %cT%d: %02d%%\n", | ||
670 | (i == pr->throttling.state ? '*' : ' '), i, | ||
671 | (int)pr->throttling.states_tss[i]. | ||
672 | freqpercentage); | ||
292 | 673 | ||
293 | end: | 674 | end: |
294 | return 0; | 675 | return 0; |
@@ -301,7 +682,7 @@ static int acpi_processor_throttling_open_fs(struct inode *inode, | |||
301 | PDE(inode)->data); | 682 | PDE(inode)->data); |
302 | } | 683 | } |
303 | 684 | ||
304 | static ssize_t acpi_processor_write_throttling(struct file * file, | 685 | static ssize_t acpi_processor_write_throttling(struct file *file, |
305 | const char __user * buffer, | 686 | const char __user * buffer, |
306 | size_t count, loff_t * data) | 687 | size_t count, loff_t * data) |
307 | { | 688 | { |
@@ -310,7 +691,6 @@ static ssize_t acpi_processor_write_throttling(struct file * file, | |||
310 | struct acpi_processor *pr = m->private; | 691 | struct acpi_processor *pr = m->private; |
311 | char state_string[12] = { '\0' }; | 692 | char state_string[12] = { '\0' }; |
312 | 693 | ||
313 | |||
314 | if (!pr || (count > sizeof(state_string) - 1)) | 694 | if (!pr || (count > sizeof(state_string) - 1)) |
315 | return -EINVAL; | 695 | return -EINVAL; |
316 | 696 | ||
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index c1bae10683..974d00ccfe 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c | |||
@@ -127,7 +127,7 @@ static int acpi_sbs_resume(struct acpi_device *device); | |||
127 | static struct acpi_driver acpi_sbs_driver = { | 127 | static struct acpi_driver acpi_sbs_driver = { |
128 | .name = "sbs", | 128 | .name = "sbs", |
129 | .class = ACPI_SBS_CLASS, | 129 | .class = ACPI_SBS_CLASS, |
130 | .ids = ACPI_SBS_HID, | 130 | .ids = "ACPI0001,ACPI0005", |
131 | .ops = { | 131 | .ops = { |
132 | .add = acpi_sbs_add, | 132 | .add = acpi_sbs_add, |
133 | .remove = acpi_sbs_remove, | 133 | .remove = acpi_sbs_remove, |
@@ -176,10 +176,8 @@ struct acpi_battery { | |||
176 | }; | 176 | }; |
177 | 177 | ||
178 | struct acpi_sbs { | 178 | struct acpi_sbs { |
179 | acpi_handle handle; | ||
180 | int base; | 179 | int base; |
181 | struct acpi_device *device; | 180 | struct acpi_device *device; |
182 | struct acpi_ec_smbus *smbus; | ||
183 | struct mutex mutex; | 181 | struct mutex mutex; |
184 | int sbsm_present; | 182 | int sbsm_present; |
185 | int sbsm_batteries_supported; | 183 | int sbsm_batteries_supported; |
@@ -511,7 +509,7 @@ static int acpi_sbsm_get_info(struct acpi_sbs *sbs) | |||
511 | "acpi_sbs_read_word() failed")); | 509 | "acpi_sbs_read_word() failed")); |
512 | goto end; | 510 | goto end; |
513 | } | 511 | } |
514 | 512 | sbs->sbsm_present = 1; | |
515 | sbs->sbsm_batteries_supported = battery_system_info & 0x000f; | 513 | sbs->sbsm_batteries_supported = battery_system_info & 0x000f; |
516 | 514 | ||
517 | end: | 515 | end: |
@@ -1630,13 +1628,12 @@ static int acpi_sbs_add(struct acpi_device *device) | |||
1630 | { | 1628 | { |
1631 | struct acpi_sbs *sbs = NULL; | 1629 | struct acpi_sbs *sbs = NULL; |
1632 | int result = 0, remove_result = 0; | 1630 | int result = 0, remove_result = 0; |
1633 | unsigned long sbs_obj; | ||
1634 | int id; | 1631 | int id; |
1635 | acpi_status status = AE_OK; | 1632 | acpi_status status = AE_OK; |
1636 | unsigned long val; | 1633 | unsigned long val; |
1637 | 1634 | ||
1638 | status = | 1635 | status = |
1639 | acpi_evaluate_integer(device->parent->handle, "_EC", NULL, &val); | 1636 | acpi_evaluate_integer(device->handle, "_EC", NULL, &val); |
1640 | if (ACPI_FAILURE(status)) { | 1637 | if (ACPI_FAILURE(status)) { |
1641 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Error obtaining _EC")); | 1638 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Error obtaining _EC")); |
1642 | return -EIO; | 1639 | return -EIO; |
@@ -1653,7 +1650,7 @@ static int acpi_sbs_add(struct acpi_device *device) | |||
1653 | 1650 | ||
1654 | sbs_mutex_lock(sbs); | 1651 | sbs_mutex_lock(sbs); |
1655 | 1652 | ||
1656 | sbs->base = (val & 0xff00ull) >> 8; | 1653 | sbs->base = 0xff & (val >> 8); |
1657 | sbs->device = device; | 1654 | sbs->device = device; |
1658 | 1655 | ||
1659 | strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME); | 1656 | strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME); |
@@ -1665,24 +1662,10 @@ static int acpi_sbs_add(struct acpi_device *device) | |||
1665 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_ac_add() failed")); | 1662 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_ac_add() failed")); |
1666 | goto end; | 1663 | goto end; |
1667 | } | 1664 | } |
1668 | status = acpi_evaluate_integer(device->handle, "_SBS", NULL, &sbs_obj); | ||
1669 | if (status) { | ||
1670 | ACPI_EXCEPTION((AE_INFO, status, | ||
1671 | "acpi_evaluate_integer() failed")); | ||
1672 | result = -EIO; | ||
1673 | goto end; | ||
1674 | } | ||
1675 | if (sbs_obj > 0) { | ||
1676 | result = acpi_sbsm_get_info(sbs); | ||
1677 | if (result) { | ||
1678 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | ||
1679 | "acpi_sbsm_get_info() failed")); | ||
1680 | goto end; | ||
1681 | } | ||
1682 | sbs->sbsm_present = 1; | ||
1683 | } | ||
1684 | 1665 | ||
1685 | if (sbs->sbsm_present == 0) { | 1666 | acpi_sbsm_get_info(sbs); |
1667 | |||
1668 | if (!sbs->sbsm_present) { | ||
1686 | result = acpi_battery_add(sbs, 0); | 1669 | result = acpi_battery_add(sbs, 0); |
1687 | if (result) { | 1670 | if (result) { |
1688 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, | 1671 | ACPI_EXCEPTION((AE_INFO, AE_ERROR, |
@@ -1702,8 +1685,6 @@ static int acpi_sbs_add(struct acpi_device *device) | |||
1702 | } | 1685 | } |
1703 | } | 1686 | } |
1704 | 1687 | ||
1705 | sbs->handle = device->handle; | ||
1706 | |||
1707 | init_timer(&sbs->update_timer); | 1688 | init_timer(&sbs->update_timer); |
1708 | result = acpi_check_update_proc(sbs); | 1689 | result = acpi_check_update_proc(sbs); |
1709 | if (result) | 1690 | if (result) |
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c index 42127c0d61..3279e72a94 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/sleep/main.c | |||
@@ -210,11 +210,6 @@ static void acpi_hibernation_finish(void) | |||
210 | 210 | ||
211 | /* reset firmware waking vector */ | 211 | /* reset firmware waking vector */ |
212 | acpi_set_firmware_waking_vector((acpi_physical_address) 0); | 212 | acpi_set_firmware_waking_vector((acpi_physical_address) 0); |
213 | |||
214 | if (init_8259A_after_S1) { | ||
215 | printk("Broken toshiba laptop -> kicking interrupts\n"); | ||
216 | init_8259A(0); | ||
217 | } | ||
218 | } | 213 | } |
219 | 214 | ||
220 | static int acpi_hibernation_pre_restore(void) | 215 | static int acpi_hibernation_pre_restore(void) |
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c index 83a8d30979..edee2806e3 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c | |||
@@ -39,15 +39,12 @@ ACPI_MODULE_NAME("system"); | |||
39 | 39 | ||
40 | #define ACPI_SYSTEM_CLASS "system" | 40 | #define ACPI_SYSTEM_CLASS "system" |
41 | #define ACPI_SYSTEM_DEVICE_NAME "System" | 41 | #define ACPI_SYSTEM_DEVICE_NAME "System" |
42 | #define ACPI_SYSTEM_FILE_INFO "info" | ||
43 | #define ACPI_SYSTEM_FILE_EVENT "event" | ||
44 | #define ACPI_SYSTEM_FILE_DSDT "dsdt" | ||
45 | #define ACPI_SYSTEM_FILE_FADT "fadt" | ||
46 | 42 | ||
47 | /* | 43 | /* |
48 | * Make ACPICA version work as module param | 44 | * Make ACPICA version work as module param |
49 | */ | 45 | */ |
50 | static int param_get_acpica_version(char *buffer, struct kernel_param *kp) { | 46 | static int param_get_acpica_version(char *buffer, struct kernel_param *kp) |
47 | { | ||
51 | int result; | 48 | int result; |
52 | 49 | ||
53 | result = sprintf(buffer, "%x", ACPI_CA_VERSION); | 50 | result = sprintf(buffer, "%x", ACPI_CA_VERSION); |
@@ -58,9 +55,126 @@ static int param_get_acpica_version(char *buffer, struct kernel_param *kp) { | |||
58 | module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444); | 55 | module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444); |
59 | 56 | ||
60 | /* -------------------------------------------------------------------------- | 57 | /* -------------------------------------------------------------------------- |
58 | FS Interface (/sys) | ||
59 | -------------------------------------------------------------------------- */ | ||
60 | static LIST_HEAD(acpi_table_attr_list); | ||
61 | static struct kobject tables_kobj; | ||
62 | |||
63 | struct acpi_table_attr { | ||
64 | struct bin_attribute attr; | ||
65 | char name[8]; | ||
66 | int instance; | ||
67 | struct list_head node; | ||
68 | }; | ||
69 | |||
70 | static ssize_t acpi_table_show(struct kobject *kobj, | ||
71 | struct bin_attribute *bin_attr, char *buf, | ||
72 | loff_t offset, size_t count) | ||
73 | { | ||
74 | struct acpi_table_attr *table_attr = | ||
75 | container_of(bin_attr, struct acpi_table_attr, attr); | ||
76 | struct acpi_table_header *table_header = NULL; | ||
77 | acpi_status status; | ||
78 | ssize_t ret_count = count; | ||
79 | |||
80 | status = | ||
81 | acpi_get_table(table_attr->name, table_attr->instance, | ||
82 | &table_header); | ||
83 | if (ACPI_FAILURE(status)) | ||
84 | return -ENODEV; | ||
85 | |||
86 | if (offset >= table_header->length) { | ||
87 | ret_count = 0; | ||
88 | goto end; | ||
89 | } | ||
90 | |||
91 | if (offset + ret_count > table_header->length) | ||
92 | ret_count = table_header->length - offset; | ||
93 | |||
94 | memcpy(buf, ((char *)table_header) + offset, ret_count); | ||
95 | |||
96 | end: | ||
97 | return ret_count; | ||
98 | } | ||
99 | |||
100 | static void acpi_table_attr_init(struct acpi_table_attr *table_attr, | ||
101 | struct acpi_table_header *table_header) | ||
102 | { | ||
103 | struct acpi_table_header *header = NULL; | ||
104 | struct acpi_table_attr *attr = NULL; | ||
105 | |||
106 | memcpy(table_attr->name, table_header->signature, ACPI_NAME_SIZE); | ||
107 | |||
108 | list_for_each_entry(attr, &acpi_table_attr_list, node) { | ||
109 | if (!memcmp(table_header->signature, attr->name, | ||
110 | ACPI_NAME_SIZE)) | ||
111 | if (table_attr->instance < attr->instance) | ||
112 | table_attr->instance = attr->instance; | ||
113 | } | ||
114 | table_attr->instance++; | ||
115 | |||
116 | if (table_attr->instance > 1 || (table_attr->instance == 1 && | ||
117 | !acpi_get_table(table_header-> | ||
118 | signature, 2, | ||
119 | &header))) | ||
120 | sprintf(table_attr->name + 4, "%d", table_attr->instance); | ||
121 | |||
122 | table_attr->attr.size = 0; | ||
123 | table_attr->attr.read = acpi_table_show; | ||
124 | table_attr->attr.attr.name = table_attr->name; | ||
125 | table_attr->attr.attr.mode = 0444; | ||
126 | table_attr->attr.attr.owner = THIS_MODULE; | ||
127 | |||
128 | return; | ||
129 | } | ||
130 | |||
131 | static int acpi_system_sysfs_init(void) | ||
132 | { | ||
133 | struct acpi_table_attr *table_attr; | ||
134 | struct acpi_table_header *table_header = NULL; | ||
135 | int table_index = 0; | ||
136 | int result; | ||
137 | |||
138 | tables_kobj.parent = &acpi_subsys.kobj; | ||
139 | kobject_set_name(&tables_kobj, "tables"); | ||
140 | result = kobject_register(&tables_kobj); | ||
141 | if (result) | ||
142 | return result; | ||
143 | |||
144 | do { | ||
145 | result = acpi_get_table_by_index(table_index, &table_header); | ||
146 | if (!result) { | ||
147 | table_index++; | ||
148 | table_attr = NULL; | ||
149 | table_attr = | ||
150 | kzalloc(sizeof(struct acpi_table_attr), GFP_KERNEL); | ||
151 | if (!table_attr) | ||
152 | return -ENOMEM; | ||
153 | |||
154 | acpi_table_attr_init(table_attr, table_header); | ||
155 | result = | ||
156 | sysfs_create_bin_file(&tables_kobj, | ||
157 | &table_attr->attr); | ||
158 | if (result) { | ||
159 | kfree(table_attr); | ||
160 | return result; | ||
161 | } else | ||
162 | list_add_tail(&table_attr->node, | ||
163 | &acpi_table_attr_list); | ||
164 | } | ||
165 | } while (!result); | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | /* -------------------------------------------------------------------------- | ||
61 | FS Interface (/proc) | 171 | FS Interface (/proc) |
62 | -------------------------------------------------------------------------- */ | 172 | -------------------------------------------------------------------------- */ |
63 | #ifdef CONFIG_ACPI_PROCFS | 173 | #ifdef CONFIG_ACPI_PROCFS |
174 | #define ACPI_SYSTEM_FILE_INFO "info" | ||
175 | #define ACPI_SYSTEM_FILE_EVENT "event" | ||
176 | #define ACPI_SYSTEM_FILE_DSDT "dsdt" | ||
177 | #define ACPI_SYSTEM_FILE_FADT "fadt" | ||
64 | 178 | ||
65 | static int acpi_system_read_info(struct seq_file *seq, void *offset) | 179 | static int acpi_system_read_info(struct seq_file *seq, void *offset) |
66 | { | 180 | { |
@@ -80,7 +194,6 @@ static const struct file_operations acpi_system_info_ops = { | |||
80 | .llseek = seq_lseek, | 194 | .llseek = seq_lseek, |
81 | .release = single_release, | 195 | .release = single_release, |
82 | }; | 196 | }; |
83 | #endif | ||
84 | 197 | ||
85 | static ssize_t acpi_system_read_dsdt(struct file *, char __user *, size_t, | 198 | static ssize_t acpi_system_read_dsdt(struct file *, char __user *, size_t, |
86 | loff_t *); | 199 | loff_t *); |
@@ -97,13 +210,11 @@ acpi_system_read_dsdt(struct file *file, | |||
97 | struct acpi_table_header *dsdt = NULL; | 210 | struct acpi_table_header *dsdt = NULL; |
98 | ssize_t res; | 211 | ssize_t res; |
99 | 212 | ||
100 | |||
101 | status = acpi_get_table(ACPI_SIG_DSDT, 1, &dsdt); | 213 | status = acpi_get_table(ACPI_SIG_DSDT, 1, &dsdt); |
102 | if (ACPI_FAILURE(status)) | 214 | if (ACPI_FAILURE(status)) |
103 | return -ENODEV; | 215 | return -ENODEV; |
104 | 216 | ||
105 | res = simple_read_from_buffer(buffer, count, ppos, | 217 | res = simple_read_from_buffer(buffer, count, ppos, dsdt, dsdt->length); |
106 | dsdt, dsdt->length); | ||
107 | 218 | ||
108 | return res; | 219 | return res; |
109 | } | 220 | } |
@@ -123,28 +234,21 @@ acpi_system_read_fadt(struct file *file, | |||
123 | struct acpi_table_header *fadt = NULL; | 234 | struct acpi_table_header *fadt = NULL; |
124 | ssize_t res; | 235 | ssize_t res; |
125 | 236 | ||
126 | |||
127 | status = acpi_get_table(ACPI_SIG_FADT, 1, &fadt); | 237 | status = acpi_get_table(ACPI_SIG_FADT, 1, &fadt); |
128 | if (ACPI_FAILURE(status)) | 238 | if (ACPI_FAILURE(status)) |
129 | return -ENODEV; | 239 | return -ENODEV; |
130 | 240 | ||
131 | res = simple_read_from_buffer(buffer, count, ppos, | 241 | res = simple_read_from_buffer(buffer, count, ppos, fadt, fadt->length); |
132 | fadt, fadt->length); | ||
133 | 242 | ||
134 | return res; | 243 | return res; |
135 | } | 244 | } |
136 | 245 | ||
137 | static int __init acpi_system_init(void) | 246 | static int acpi_system_procfs_init(void) |
138 | { | 247 | { |
139 | struct proc_dir_entry *entry; | 248 | struct proc_dir_entry *entry; |
140 | int error = 0; | 249 | int error = 0; |
141 | char *name; | 250 | char *name; |
142 | 251 | ||
143 | |||
144 | if (acpi_disabled) | ||
145 | return 0; | ||
146 | |||
147 | #ifdef CONFIG_ACPI_PROCFS | ||
148 | /* 'info' [R] */ | 252 | /* 'info' [R] */ |
149 | name = ACPI_SYSTEM_FILE_INFO; | 253 | name = ACPI_SYSTEM_FILE_INFO; |
150 | entry = create_proc_entry(name, S_IRUGO, acpi_root_dir); | 254 | entry = create_proc_entry(name, S_IRUGO, acpi_root_dir); |
@@ -153,7 +257,6 @@ static int __init acpi_system_init(void) | |||
153 | else { | 257 | else { |
154 | entry->proc_fops = &acpi_system_info_ops; | 258 | entry->proc_fops = &acpi_system_info_ops; |
155 | } | 259 | } |
156 | #endif | ||
157 | 260 | ||
158 | /* 'dsdt' [R] */ | 261 | /* 'dsdt' [R] */ |
159 | name = ACPI_SYSTEM_FILE_DSDT; | 262 | name = ACPI_SYSTEM_FILE_DSDT; |
@@ -177,12 +280,32 @@ static int __init acpi_system_init(void) | |||
177 | Error: | 280 | Error: |
178 | remove_proc_entry(ACPI_SYSTEM_FILE_FADT, acpi_root_dir); | 281 | remove_proc_entry(ACPI_SYSTEM_FILE_FADT, acpi_root_dir); |
179 | remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_root_dir); | 282 | remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_root_dir); |
180 | #ifdef CONFIG_ACPI_PROCFS | ||
181 | remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_root_dir); | 283 | remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_root_dir); |
182 | #endif | ||
183 | 284 | ||
184 | error = -EFAULT; | 285 | error = -EFAULT; |
185 | goto Done; | 286 | goto Done; |
186 | } | 287 | } |
288 | #else | ||
289 | static int acpi_system_procfs_init(void) | ||
290 | { | ||
291 | return 0; | ||
292 | } | ||
293 | #endif | ||
294 | |||
295 | static int __init acpi_system_init(void) | ||
296 | { | ||
297 | int result = 0; | ||
298 | |||
299 | if (acpi_disabled) | ||
300 | return 0; | ||
301 | |||
302 | result = acpi_system_procfs_init(); | ||
303 | if (result) | ||
304 | return result; | ||
305 | |||
306 | result = acpi_system_sysfs_init(); | ||
307 | |||
308 | return result; | ||
309 | } | ||
187 | 310 | ||
188 | subsys_initcall(acpi_system_init); | 311 | subsys_initcall(acpi_system_init); |
diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c index 1285e91474..002bb33003 100644 --- a/drivers/acpi/tables/tbfadt.c +++ b/drivers/acpi/tables/tbfadt.c | |||
@@ -211,14 +211,17 @@ void acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags) | |||
211 | * DESCRIPTION: Get a local copy of the FADT and convert it to a common format. | 211 | * DESCRIPTION: Get a local copy of the FADT and convert it to a common format. |
212 | * Performs validation on some important FADT fields. | 212 | * Performs validation on some important FADT fields. |
213 | * | 213 | * |
214 | * NOTE: We create a local copy of the FADT regardless of the version. | ||
215 | * | ||
214 | ******************************************************************************/ | 216 | ******************************************************************************/ |
215 | 217 | ||
216 | void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) | 218 | void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) |
217 | { | 219 | { |
218 | 220 | ||
219 | /* | 221 | /* |
220 | * Check if the FADT is larger than what we know about (ACPI 2.0 version). | 222 | * Check if the FADT is larger than the largest table that we expect |
221 | * Truncate the table, but make some noise. | 223 | * (the ACPI 2.0/3.0 version). If so, truncate the table, and issue |
224 | * a warning. | ||
222 | */ | 225 | */ |
223 | if (length > sizeof(struct acpi_table_fadt)) { | 226 | if (length > sizeof(struct acpi_table_fadt)) { |
224 | ACPI_WARNING((AE_INFO, | 227 | ACPI_WARNING((AE_INFO, |
@@ -227,10 +230,12 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) | |||
227 | sizeof(struct acpi_table_fadt))); | 230 | sizeof(struct acpi_table_fadt))); |
228 | } | 231 | } |
229 | 232 | ||
230 | /* Copy the entire FADT locally. Zero first for tb_convert_fadt */ | 233 | /* Clear the entire local FADT */ |
231 | 234 | ||
232 | ACPI_MEMSET(&acpi_gbl_FADT, 0, sizeof(struct acpi_table_fadt)); | 235 | ACPI_MEMSET(&acpi_gbl_FADT, 0, sizeof(struct acpi_table_fadt)); |
233 | 236 | ||
237 | /* Copy the original FADT, up to sizeof (struct acpi_table_fadt) */ | ||
238 | |||
234 | ACPI_MEMCPY(&acpi_gbl_FADT, table, | 239 | ACPI_MEMCPY(&acpi_gbl_FADT, table, |
235 | ACPI_MIN(length, sizeof(struct acpi_table_fadt))); | 240 | ACPI_MIN(length, sizeof(struct acpi_table_fadt))); |
236 | 241 | ||
@@ -251,7 +256,7 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) | |||
251 | * RETURN: None | 256 | * RETURN: None |
252 | * | 257 | * |
253 | * DESCRIPTION: Converts all versions of the FADT to a common internal format. | 258 | * DESCRIPTION: Converts all versions of the FADT to a common internal format. |
254 | * -> Expand all 32-bit addresses to 64-bit. | 259 | * Expand all 32-bit addresses to 64-bit. |
255 | * | 260 | * |
256 | * NOTE: acpi_gbl_FADT must be of size (struct acpi_table_fadt), | 261 | * NOTE: acpi_gbl_FADT must be of size (struct acpi_table_fadt), |
257 | * and must contain a copy of the actual FADT. | 262 | * and must contain a copy of the actual FADT. |
@@ -292,8 +297,23 @@ static void acpi_tb_convert_fadt(void) | |||
292 | } | 297 | } |
293 | 298 | ||
294 | /* | 299 | /* |
295 | * Expand the 32-bit V1.0 addresses to the 64-bit "X" generic address | 300 | * For ACPI 1.0 FADTs (revision 1 or 2), ensure that reserved fields which |
296 | * structures as necessary. | 301 | * should be zero are indeed zero. This will workaround BIOSs that |
302 | * inadvertently place values in these fields. | ||
303 | * | ||
304 | * The ACPI 1.0 reserved fields that will be zeroed are the bytes located at | ||
305 | * offset 45, 55, 95, and the word located at offset 109, 110. | ||
306 | */ | ||
307 | if (acpi_gbl_FADT.header.revision < 3) { | ||
308 | acpi_gbl_FADT.preferred_profile = 0; | ||
309 | acpi_gbl_FADT.pstate_control = 0; | ||
310 | acpi_gbl_FADT.cst_control = 0; | ||
311 | acpi_gbl_FADT.boot_flags = 0; | ||
312 | } | ||
313 | |||
314 | /* | ||
315 | * Expand the ACPI 1.0 32-bit V1.0 addresses to the ACPI 2.0 64-bit "X" | ||
316 | * generic address structures as necessary. | ||
297 | */ | 317 | */ |
298 | for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { | 318 | for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { |
299 | target = | 319 | target = |
@@ -349,18 +369,6 @@ static void acpi_tb_convert_fadt(void) | |||
349 | acpi_gbl_FADT.xpm1a_event_block.space_id; | 369 | acpi_gbl_FADT.xpm1a_event_block.space_id; |
350 | 370 | ||
351 | } | 371 | } |
352 | |||
353 | /* | ||
354 | * For ACPI 1.0 FADTs, ensure that reserved fields (which should be zero) | ||
355 | * are indeed zero. This will workaround BIOSs that inadvertently placed | ||
356 | * values in these fields. | ||
357 | */ | ||
358 | if (acpi_gbl_FADT.header.revision < 3) { | ||
359 | acpi_gbl_FADT.preferred_profile = 0; | ||
360 | acpi_gbl_FADT.pstate_control = 0; | ||
361 | acpi_gbl_FADT.cst_control = 0; | ||
362 | acpi_gbl_FADT.boot_flags = 0; | ||
363 | } | ||
364 | } | 372 | } |
365 | 373 | ||
366 | /****************************************************************************** | 374 | /****************************************************************************** |
diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c index 8ec6f8e481..f112af433e 100644 --- a/drivers/acpi/utilities/uteval.c +++ b/drivers/acpi/utilities/uteval.c | |||
@@ -62,16 +62,13 @@ acpi_ut_translate_one_cid(union acpi_operand_object *obj_desc, | |||
62 | static char *acpi_interfaces_supported[] = { | 62 | static char *acpi_interfaces_supported[] = { |
63 | /* Operating System Vendor Strings */ | 63 | /* Operating System Vendor Strings */ |
64 | 64 | ||
65 | "Windows 2000", | 65 | "Windows 2000", /* Windows 2000 */ |
66 | "Windows 2001", | 66 | "Windows 2001", /* Windows XP */ |
67 | "Windows 2001 SP0", | 67 | "Windows 2001 SP1", /* Windows XP SP1 */ |
68 | "Windows 2001 SP1", | 68 | "Windows 2001 SP2", /* Windows XP SP2 */ |
69 | "Windows 2001 SP2", | 69 | "Windows 2001.1", /* Windows Server 2003 */ |
70 | "Windows 2001 SP3", | 70 | "Windows 2001.1 SP1", /* Windows Server 2003 SP1 - Added 03/2006 */ |
71 | "Windows 2001 SP4", | 71 | "Windows 2006", /* Windows Vista - Added 03/2006 */ |
72 | "Windows 2001.1", | ||
73 | "Windows 2001.1 SP1", /* Added 03/2006 */ | ||
74 | "Windows 2006", /* Added 03/2006 */ | ||
75 | 72 | ||
76 | /* Feature Group Strings */ | 73 | /* Feature Group Strings */ |
77 | 74 | ||
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 00d25b3472..5f014d3764 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/seq_file.h> | 33 | #include <linux/seq_file.h> |
34 | 34 | ||
35 | #include <linux/backlight.h> | 35 | #include <linux/backlight.h> |
36 | #include <linux/video_output.h> | ||
36 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
37 | 38 | ||
38 | #include <acpi/acpi_bus.h> | 39 | #include <acpi/acpi_bus.h> |
@@ -169,6 +170,7 @@ struct acpi_video_device { | |||
169 | struct acpi_device *dev; | 170 | struct acpi_device *dev; |
170 | struct acpi_video_device_brightness *brightness; | 171 | struct acpi_video_device_brightness *brightness; |
171 | struct backlight_device *backlight; | 172 | struct backlight_device *backlight; |
173 | struct output_device *output_dev; | ||
172 | }; | 174 | }; |
173 | 175 | ||
174 | /* bus */ | 176 | /* bus */ |
@@ -272,6 +274,10 @@ static int acpi_video_get_next_level(struct acpi_video_device *device, | |||
272 | u32 level_current, u32 event); | 274 | u32 level_current, u32 event); |
273 | static void acpi_video_switch_brightness(struct acpi_video_device *device, | 275 | static void acpi_video_switch_brightness(struct acpi_video_device *device, |
274 | int event); | 276 | int event); |
277 | static int acpi_video_device_get_state(struct acpi_video_device *device, | ||
278 | unsigned long *state); | ||
279 | static int acpi_video_output_get(struct output_device *od); | ||
280 | static int acpi_video_device_set_state(struct acpi_video_device *device, int state); | ||
275 | 281 | ||
276 | /*backlight device sysfs support*/ | 282 | /*backlight device sysfs support*/ |
277 | static int acpi_video_get_brightness(struct backlight_device *bd) | 283 | static int acpi_video_get_brightness(struct backlight_device *bd) |
@@ -297,6 +303,28 @@ static struct backlight_ops acpi_backlight_ops = { | |||
297 | .update_status = acpi_video_set_brightness, | 303 | .update_status = acpi_video_set_brightness, |
298 | }; | 304 | }; |
299 | 305 | ||
306 | /*video output device sysfs support*/ | ||
307 | static int acpi_video_output_get(struct output_device *od) | ||
308 | { | ||
309 | unsigned long state; | ||
310 | struct acpi_video_device *vd = | ||
311 | (struct acpi_video_device *)class_get_devdata(&od->class_dev); | ||
312 | acpi_video_device_get_state(vd, &state); | ||
313 | return (int)state; | ||
314 | } | ||
315 | |||
316 | static int acpi_video_output_set(struct output_device *od) | ||
317 | { | ||
318 | unsigned long state = od->request_state; | ||
319 | struct acpi_video_device *vd= | ||
320 | (struct acpi_video_device *)class_get_devdata(&od->class_dev); | ||
321 | return acpi_video_device_set_state(vd, state); | ||
322 | } | ||
323 | |||
324 | static struct output_properties acpi_output_properties = { | ||
325 | .set_state = acpi_video_output_set, | ||
326 | .get_status = acpi_video_output_get, | ||
327 | }; | ||
300 | /* -------------------------------------------------------------------------- | 328 | /* -------------------------------------------------------------------------- |
301 | Video Management | 329 | Video Management |
302 | -------------------------------------------------------------------------- */ | 330 | -------------------------------------------------------------------------- */ |
@@ -531,7 +559,6 @@ acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag) | |||
531 | 559 | ||
532 | static void acpi_video_device_find_cap(struct acpi_video_device *device) | 560 | static void acpi_video_device_find_cap(struct acpi_video_device *device) |
533 | { | 561 | { |
534 | acpi_integer status; | ||
535 | acpi_handle h_dummy1; | 562 | acpi_handle h_dummy1; |
536 | int i; | 563 | int i; |
537 | u32 max_level = 0; | 564 | u32 max_level = 0; |
@@ -565,50 +592,55 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) | |||
565 | device->cap._DSS = 1; | 592 | device->cap._DSS = 1; |
566 | } | 593 | } |
567 | 594 | ||
568 | status = acpi_video_device_lcd_query_levels(device, &obj); | 595 | if (ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) { |
569 | 596 | ||
570 | if (obj && obj->type == ACPI_TYPE_PACKAGE && obj->package.count >= 2) { | 597 | if (obj->package.count >= 2) { |
571 | int count = 0; | 598 | int count = 0; |
572 | union acpi_object *o; | 599 | union acpi_object *o; |
573 | 600 | ||
574 | br = kzalloc(sizeof(*br), GFP_KERNEL); | 601 | br = kzalloc(sizeof(*br), GFP_KERNEL); |
575 | if (!br) { | 602 | if (!br) { |
576 | printk(KERN_ERR "can't allocate memory\n"); | 603 | printk(KERN_ERR "can't allocate memory\n"); |
577 | } else { | ||
578 | br->levels = kmalloc(obj->package.count * | ||
579 | sizeof *(br->levels), GFP_KERNEL); | ||
580 | if (!br->levels) | ||
581 | goto out; | ||
582 | |||
583 | for (i = 0; i < obj->package.count; i++) { | ||
584 | o = (union acpi_object *)&obj->package. | ||
585 | elements[i]; | ||
586 | if (o->type != ACPI_TYPE_INTEGER) { | ||
587 | printk(KERN_ERR PREFIX "Invalid data\n"); | ||
588 | continue; | ||
589 | } | ||
590 | br->levels[count] = (u32) o->integer.value; | ||
591 | if (br->levels[count] > max_level) | ||
592 | max_level = br->levels[count]; | ||
593 | count++; | ||
594 | } | ||
595 | out: | ||
596 | if (count < 2) { | ||
597 | kfree(br->levels); | ||
598 | kfree(br); | ||
599 | } else { | 604 | } else { |
600 | br->count = count; | 605 | br->levels = kmalloc(obj->package.count * |
601 | device->brightness = br; | 606 | sizeof *(br->levels), GFP_KERNEL); |
602 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 607 | if (!br->levels) |
603 | "found %d brightness levels\n", | 608 | goto out; |
604 | count)); | 609 | |
610 | for (i = 0; i < obj->package.count; i++) { | ||
611 | o = (union acpi_object *)&obj->package. | ||
612 | elements[i]; | ||
613 | if (o->type != ACPI_TYPE_INTEGER) { | ||
614 | printk(KERN_ERR PREFIX "Invalid data\n"); | ||
615 | continue; | ||
616 | } | ||
617 | br->levels[count] = (u32) o->integer.value; | ||
618 | |||
619 | if (br->levels[count] > max_level) | ||
620 | max_level = br->levels[count]; | ||
621 | count++; | ||
622 | } | ||
623 | out: | ||
624 | if (count < 2) { | ||
625 | kfree(br->levels); | ||
626 | kfree(br); | ||
627 | } else { | ||
628 | br->count = count; | ||
629 | device->brightness = br; | ||
630 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | ||
631 | "found %d brightness levels\n", | ||
632 | count)); | ||
633 | } | ||
605 | } | 634 | } |
606 | } | 635 | } |
636 | |||
637 | } else { | ||
638 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available LCD brightness level\n")); | ||
607 | } | 639 | } |
608 | 640 | ||
609 | kfree(obj); | 641 | kfree(obj); |
610 | 642 | ||
611 | if (device->cap._BCL && device->cap._BCM && device->cap._BQC){ | 643 | if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){ |
612 | unsigned long tmp; | 644 | unsigned long tmp; |
613 | static int count = 0; | 645 | static int count = 0; |
614 | char *name; | 646 | char *name; |
@@ -626,6 +658,17 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) | |||
626 | 658 | ||
627 | kfree(name); | 659 | kfree(name); |
628 | } | 660 | } |
661 | if (device->cap._DCS && device->cap._DSS){ | ||
662 | static int count = 0; | ||
663 | char *name; | ||
664 | name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); | ||
665 | if (!name) | ||
666 | return; | ||
667 | sprintf(name, "acpi_video%d", count++); | ||
668 | device->output_dev = video_output_register(name, | ||
669 | NULL, device, &acpi_output_properties); | ||
670 | kfree(name); | ||
671 | } | ||
629 | return; | 672 | return; |
630 | } | 673 | } |
631 | 674 | ||
@@ -1669,6 +1712,7 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device) | |||
1669 | ACPI_DEVICE_NOTIFY, | 1712 | ACPI_DEVICE_NOTIFY, |
1670 | acpi_video_device_notify); | 1713 | acpi_video_device_notify); |
1671 | backlight_device_unregister(device->backlight); | 1714 | backlight_device_unregister(device->backlight); |
1715 | video_output_unregister(device->output_dev); | ||
1672 | return 0; | 1716 | return 0; |
1673 | } | 1717 | } |
1674 | 1718 | ||
diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c index a9ab30feff..2b0c601e42 100644 --- a/drivers/base/power/trace.c +++ b/drivers/base/power/trace.c | |||
@@ -142,6 +142,7 @@ void set_trace_device(struct device *dev) | |||
142 | { | 142 | { |
143 | dev_hash_value = hash_string(DEVSEED, dev->bus_id, DEVHASH); | 143 | dev_hash_value = hash_string(DEVSEED, dev->bus_id, DEVHASH); |
144 | } | 144 | } |
145 | EXPORT_SYMBOL(set_trace_device); | ||
145 | 146 | ||
146 | /* | 147 | /* |
147 | * We could just take the "tracedata" index into the .tracedata | 148 | * We could just take the "tracedata" index into the .tracedata |
@@ -162,6 +163,7 @@ void generate_resume_trace(void *tracedata, unsigned int user) | |||
162 | file_hash_value = hash_string(lineno, file, FILEHASH); | 163 | file_hash_value = hash_string(lineno, file, FILEHASH); |
163 | set_magic_time(user_hash_value, file_hash_value, dev_hash_value); | 164 | set_magic_time(user_hash_value, file_hash_value, dev_hash_value); |
164 | } | 165 | } |
166 | EXPORT_SYMBOL(generate_resume_trace); | ||
165 | 167 | ||
166 | extern char __tracedata_start, __tracedata_end; | 168 | extern char __tracedata_start, __tracedata_end; |
167 | static int show_file_hash(unsigned int value) | 169 | static int show_file_hash(unsigned int value) |
@@ -170,7 +172,8 @@ static int show_file_hash(unsigned int value) | |||
170 | char *tracedata; | 172 | char *tracedata; |
171 | 173 | ||
172 | match = 0; | 174 | match = 0; |
173 | for (tracedata = &__tracedata_start ; tracedata < &__tracedata_end ; tracedata += 6) { | 175 | for (tracedata = &__tracedata_start ; tracedata < &__tracedata_end ; |
176 | tracedata += 2 + sizeof(unsigned long)) { | ||
174 | unsigned short lineno = *(unsigned short *)tracedata; | 177 | unsigned short lineno = *(unsigned short *)tracedata; |
175 | const char *file = *(const char **)(tracedata + 2); | 178 | const char *file = *(const char **)(tracedata + 2); |
176 | unsigned int hash = hash_string(lineno, file, FILEHASH); | 179 | unsigned int hash = hash_string(lineno, file, FILEHASH); |
diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 819c829125..a7a099027f 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile | |||
@@ -8,6 +8,7 @@ | |||
8 | obj-$(CONFIG_MAC_FLOPPY) += swim3.o | 8 | obj-$(CONFIG_MAC_FLOPPY) += swim3.o |
9 | obj-$(CONFIG_BLK_DEV_FD) += floppy.o | 9 | obj-$(CONFIG_BLK_DEV_FD) += floppy.o |
10 | obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o | 10 | obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o |
11 | obj-$(CONFIG_PS3_DISK) += ps3disk.o | ||
11 | obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o | 12 | obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o |
12 | obj-$(CONFIG_AMIGA_Z2RAM) += z2ram.o | 13 | obj-$(CONFIG_AMIGA_Z2RAM) += z2ram.o |
13 | obj-$(CONFIG_BLK_DEV_RAM) += rd.o | 14 | obj-$(CONFIG_BLK_DEV_RAM) += rd.o |
diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c new file mode 100644 index 0000000000..170fb33dba --- /dev/null +++ b/drivers/block/ps3disk.c | |||
@@ -0,0 +1,630 @@ | |||
1 | /* | ||
2 | * PS3 Disk Storage Driver | ||
3 | * | ||
4 | * Copyright (C) 2007 Sony Computer Entertainment Inc. | ||
5 | * Copyright 2007 Sony Corp. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published | ||
9 | * by the Free Software Foundation; version 2 of the License. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/ata.h> | ||
22 | #include <linux/blkdev.h> | ||
23 | |||
24 | #include <asm/lv1call.h> | ||
25 | #include <asm/ps3stor.h> | ||
26 | #include <asm/firmware.h> | ||
27 | |||
28 | |||
29 | #define DEVICE_NAME "ps3disk" | ||
30 | |||
31 | #define BOUNCE_SIZE (64*1024) | ||
32 | |||
33 | #define PS3DISK_MAX_DISKS 16 | ||
34 | #define PS3DISK_MINORS 16 | ||
35 | |||
36 | |||
37 | #define PS3DISK_NAME "ps3d%c" | ||
38 | |||
39 | |||
40 | struct ps3disk_private { | ||
41 | spinlock_t lock; /* Request queue spinlock */ | ||
42 | struct request_queue *queue; | ||
43 | struct gendisk *gendisk; | ||
44 | unsigned int blocking_factor; | ||
45 | struct request *req; | ||
46 | u64 raw_capacity; | ||
47 | unsigned char model[ATA_ID_PROD_LEN+1]; | ||
48 | }; | ||
49 | |||
50 | |||
51 | #define LV1_STORAGE_SEND_ATA_COMMAND (2) | ||
52 | #define LV1_STORAGE_ATA_HDDOUT (0x23) | ||
53 | |||
54 | struct lv1_ata_cmnd_block { | ||
55 | u16 features; | ||
56 | u16 sector_count; | ||
57 | u16 LBA_low; | ||
58 | u16 LBA_mid; | ||
59 | u16 LBA_high; | ||
60 | u8 device; | ||
61 | u8 command; | ||
62 | u32 is_ext; | ||
63 | u32 proto; | ||
64 | u32 in_out; | ||
65 | u32 size; | ||
66 | u64 buffer; | ||
67 | u32 arglen; | ||
68 | }; | ||
69 | |||
70 | enum lv1_ata_proto { | ||
71 | NON_DATA_PROTO = 0, | ||
72 | PIO_DATA_IN_PROTO = 1, | ||
73 | PIO_DATA_OUT_PROTO = 2, | ||
74 | DMA_PROTO = 3 | ||
75 | }; | ||
76 | |||
77 | enum lv1_ata_in_out { | ||
78 | DIR_WRITE = 0, /* memory -> device */ | ||
79 | DIR_READ = 1 /* device -> memory */ | ||
80 | }; | ||
81 | |||
82 | static int ps3disk_major; | ||
83 | |||
84 | |||
85 | static struct block_device_operations ps3disk_fops = { | ||
86 | .owner = THIS_MODULE, | ||
87 | }; | ||
88 | |||
89 | |||
90 | static void ps3disk_scatter_gather(struct ps3_storage_device *dev, | ||
91 | struct request *req, int gather) | ||
92 | { | ||
93 | unsigned int offset = 0; | ||
94 | struct bio *bio; | ||
95 | sector_t sector; | ||
96 | struct bio_vec *bvec; | ||
97 | unsigned int i = 0, j; | ||
98 | size_t size; | ||
99 | void *buf; | ||
100 | |||
101 | rq_for_each_bio(bio, req) { | ||
102 | sector = bio->bi_sector; | ||
103 | dev_dbg(&dev->sbd.core, | ||
104 | "%s:%u: bio %u: %u segs %u sectors from %lu\n", | ||
105 | __func__, __LINE__, i, bio_segments(bio), | ||
106 | bio_sectors(bio), sector); | ||
107 | bio_for_each_segment(bvec, bio, j) { | ||
108 | size = bvec->bv_len; | ||
109 | buf = __bio_kmap_atomic(bio, j, KM_IRQ0); | ||
110 | if (gather) | ||
111 | memcpy(dev->bounce_buf+offset, buf, size); | ||
112 | else | ||
113 | memcpy(buf, dev->bounce_buf+offset, size); | ||
114 | offset += size; | ||
115 | flush_kernel_dcache_page(bio_iovec_idx(bio, j)->bv_page); | ||
116 | __bio_kunmap_atomic(bio, KM_IRQ0); | ||
117 | } | ||
118 | i++; | ||
119 | } | ||
120 | } | ||
121 | |||
122 | static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, | ||
123 | struct request *req) | ||
124 | { | ||
125 | struct ps3disk_private *priv = dev->sbd.core.driver_data; | ||
126 | int write = rq_data_dir(req), res; | ||
127 | const char *op = write ? "write" : "read"; | ||
128 | u64 start_sector, sectors; | ||
129 | unsigned int region_id = dev->regions[dev->region_idx].id; | ||
130 | |||
131 | #ifdef DEBUG | ||
132 | unsigned int n = 0; | ||
133 | struct bio *bio; | ||
134 | |||
135 | rq_for_each_bio(bio, req) | ||
136 | n++; | ||
137 | dev_dbg(&dev->sbd.core, | ||
138 | "%s:%u: %s req has %u bios for %lu sectors %lu hard sectors\n", | ||
139 | __func__, __LINE__, op, n, req->nr_sectors, | ||
140 | req->hard_nr_sectors); | ||
141 | #endif | ||
142 | |||
143 | start_sector = req->sector * priv->blocking_factor; | ||
144 | sectors = req->nr_sectors * priv->blocking_factor; | ||
145 | dev_dbg(&dev->sbd.core, "%s:%u: %s %lu sectors starting at %lu\n", | ||
146 | __func__, __LINE__, op, sectors, start_sector); | ||
147 | |||
148 | if (write) { | ||
149 | ps3disk_scatter_gather(dev, req, 1); | ||
150 | |||
151 | res = lv1_storage_write(dev->sbd.dev_id, region_id, | ||
152 | start_sector, sectors, 0, | ||
153 | dev->bounce_lpar, &dev->tag); | ||
154 | } else { | ||
155 | res = lv1_storage_read(dev->sbd.dev_id, region_id, | ||
156 | start_sector, sectors, 0, | ||
157 | dev->bounce_lpar, &dev->tag); | ||
158 | } | ||
159 | if (res) { | ||
160 | dev_err(&dev->sbd.core, "%s:%u: %s failed %d\n", __func__, | ||
161 | __LINE__, op, res); | ||
162 | end_request(req, 0); | ||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | priv->req = req; | ||
167 | return 1; | ||
168 | } | ||
169 | |||
170 | static int ps3disk_submit_flush_request(struct ps3_storage_device *dev, | ||
171 | struct request *req) | ||
172 | { | ||
173 | struct ps3disk_private *priv = dev->sbd.core.driver_data; | ||
174 | u64 res; | ||
175 | |||
176 | dev_dbg(&dev->sbd.core, "%s:%u: flush request\n", __func__, __LINE__); | ||
177 | |||
178 | res = lv1_storage_send_device_command(dev->sbd.dev_id, | ||
179 | LV1_STORAGE_ATA_HDDOUT, 0, 0, 0, | ||
180 | 0, &dev->tag); | ||
181 | if (res) { | ||
182 | dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%lx\n", | ||
183 | __func__, __LINE__, res); | ||
184 | end_request(req, 0); | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | priv->req = req; | ||
189 | return 1; | ||
190 | } | ||
191 | |||
192 | static void ps3disk_do_request(struct ps3_storage_device *dev, | ||
193 | request_queue_t *q) | ||
194 | { | ||
195 | struct request *req; | ||
196 | |||
197 | dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__); | ||
198 | |||
199 | while ((req = elv_next_request(q))) { | ||
200 | if (blk_fs_request(req)) { | ||
201 | if (ps3disk_submit_request_sg(dev, req)) | ||
202 | break; | ||
203 | } else if (req->cmd_type == REQ_TYPE_FLUSH) { | ||
204 | if (ps3disk_submit_flush_request(dev, req)) | ||
205 | break; | ||
206 | } else { | ||
207 | blk_dump_rq_flags(req, DEVICE_NAME " bad request"); | ||
208 | end_request(req, 0); | ||
209 | continue; | ||
210 | } | ||
211 | } | ||
212 | } | ||
213 | |||
214 | static void ps3disk_request(request_queue_t *q) | ||
215 | { | ||
216 | struct ps3_storage_device *dev = q->queuedata; | ||
217 | struct ps3disk_private *priv = dev->sbd.core.driver_data; | ||
218 | |||
219 | if (priv->req) { | ||
220 | dev_dbg(&dev->sbd.core, "%s:%u busy\n", __func__, __LINE__); | ||
221 | return; | ||
222 | } | ||
223 | |||
224 | ps3disk_do_request(dev, q); | ||
225 | } | ||
226 | |||
227 | static irqreturn_t ps3disk_interrupt(int irq, void *data) | ||
228 | { | ||
229 | struct ps3_storage_device *dev = data; | ||
230 | struct ps3disk_private *priv; | ||
231 | struct request *req; | ||
232 | int res, read, uptodate; | ||
233 | u64 tag, status; | ||
234 | unsigned long num_sectors; | ||
235 | const char *op; | ||
236 | |||
237 | res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status); | ||
238 | |||
239 | if (tag != dev->tag) | ||
240 | dev_err(&dev->sbd.core, | ||
241 | "%s:%u: tag mismatch, got %lx, expected %lx\n", | ||
242 | __func__, __LINE__, tag, dev->tag); | ||
243 | |||
244 | if (res) { | ||
245 | dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%lx\n", | ||
246 | __func__, __LINE__, res, status); | ||
247 | return IRQ_HANDLED; | ||
248 | } | ||
249 | |||
250 | priv = dev->sbd.core.driver_data; | ||
251 | req = priv->req; | ||
252 | if (!req) { | ||
253 | dev_dbg(&dev->sbd.core, | ||
254 | "%s:%u non-block layer request completed\n", __func__, | ||
255 | __LINE__); | ||
256 | dev->lv1_status = status; | ||
257 | complete(&dev->done); | ||
258 | return IRQ_HANDLED; | ||
259 | } | ||
260 | |||
261 | if (req->cmd_type == REQ_TYPE_FLUSH) { | ||
262 | read = 0; | ||
263 | num_sectors = req->hard_cur_sectors; | ||
264 | op = "flush"; | ||
265 | } else { | ||
266 | read = !rq_data_dir(req); | ||
267 | num_sectors = req->nr_sectors; | ||
268 | op = read ? "read" : "write"; | ||
269 | } | ||
270 | if (status) { | ||
271 | dev_dbg(&dev->sbd.core, "%s:%u: %s failed 0x%lx\n", __func__, | ||
272 | __LINE__, op, status); | ||
273 | uptodate = 0; | ||
274 | } else { | ||
275 | dev_dbg(&dev->sbd.core, "%s:%u: %s completed\n", __func__, | ||
276 | __LINE__, op); | ||
277 | uptodate = 1; | ||
278 | if (read) | ||
279 | ps3disk_scatter_gather(dev, req, 0); | ||
280 | } | ||
281 | |||
282 | spin_lock(&priv->lock); | ||
283 | if (!end_that_request_first(req, uptodate, num_sectors)) { | ||
284 | add_disk_randomness(req->rq_disk); | ||
285 | blkdev_dequeue_request(req); | ||
286 | end_that_request_last(req, uptodate); | ||
287 | } | ||
288 | priv->req = NULL; | ||
289 | ps3disk_do_request(dev, priv->queue); | ||
290 | spin_unlock(&priv->lock); | ||
291 | |||
292 | return IRQ_HANDLED; | ||
293 | } | ||
294 | |||
295 | static int ps3disk_sync_cache(struct ps3_storage_device *dev) | ||
296 | { | ||
297 | u64 res; | ||
298 | |||
299 | dev_dbg(&dev->sbd.core, "%s:%u: sync cache\n", __func__, __LINE__); | ||
300 | |||
301 | res = ps3stor_send_command(dev, LV1_STORAGE_ATA_HDDOUT, 0, 0, 0, 0); | ||
302 | if (res) { | ||
303 | dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%lx\n", | ||
304 | __func__, __LINE__, res); | ||
305 | return -EIO; | ||
306 | } | ||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | |||
311 | /* ATA helpers copied from drivers/ata/libata-core.c */ | ||
312 | |||
313 | static void swap_buf_le16(u16 *buf, unsigned int buf_words) | ||
314 | { | ||
315 | #ifdef __BIG_ENDIAN | ||
316 | unsigned int i; | ||
317 | |||
318 | for (i = 0; i < buf_words; i++) | ||
319 | buf[i] = le16_to_cpu(buf[i]); | ||
320 | #endif /* __BIG_ENDIAN */ | ||
321 | } | ||
322 | |||
323 | static u64 ata_id_n_sectors(const u16 *id) | ||
324 | { | ||
325 | if (ata_id_has_lba(id)) { | ||
326 | if (ata_id_has_lba48(id)) | ||
327 | return ata_id_u64(id, 100); | ||
328 | else | ||
329 | return ata_id_u32(id, 60); | ||
330 | } else { | ||
331 | if (ata_id_current_chs_valid(id)) | ||
332 | return ata_id_u32(id, 57); | ||
333 | else | ||
334 | return id[1] * id[3] * id[6]; | ||
335 | } | ||
336 | } | ||
337 | |||
338 | static void ata_id_string(const u16 *id, unsigned char *s, unsigned int ofs, | ||
339 | unsigned int len) | ||
340 | { | ||
341 | unsigned int c; | ||
342 | |||
343 | while (len > 0) { | ||
344 | c = id[ofs] >> 8; | ||
345 | *s = c; | ||
346 | s++; | ||
347 | |||
348 | c = id[ofs] & 0xff; | ||
349 | *s = c; | ||
350 | s++; | ||
351 | |||
352 | ofs++; | ||
353 | len -= 2; | ||
354 | } | ||
355 | } | ||
356 | |||
357 | static void ata_id_c_string(const u16 *id, unsigned char *s, unsigned int ofs, | ||
358 | unsigned int len) | ||
359 | { | ||
360 | unsigned char *p; | ||
361 | |||
362 | WARN_ON(!(len & 1)); | ||
363 | |||
364 | ata_id_string(id, s, ofs, len - 1); | ||
365 | |||
366 | p = s + strnlen(s, len - 1); | ||
367 | while (p > s && p[-1] == ' ') | ||
368 | p--; | ||
369 | *p = '\0'; | ||
370 | } | ||
371 | |||
372 | static int ps3disk_identify(struct ps3_storage_device *dev) | ||
373 | { | ||
374 | struct ps3disk_private *priv = dev->sbd.core.driver_data; | ||
375 | struct lv1_ata_cmnd_block ata_cmnd; | ||
376 | u16 *id = dev->bounce_buf; | ||
377 | u64 res; | ||
378 | |||
379 | dev_dbg(&dev->sbd.core, "%s:%u: identify disk\n", __func__, __LINE__); | ||
380 | |||
381 | memset(&ata_cmnd, 0, sizeof(struct lv1_ata_cmnd_block)); | ||
382 | ata_cmnd.command = ATA_CMD_ID_ATA; | ||
383 | ata_cmnd.sector_count = 1; | ||
384 | ata_cmnd.size = ata_cmnd.arglen = ATA_ID_WORDS * 2; | ||
385 | ata_cmnd.buffer = dev->bounce_lpar; | ||
386 | ata_cmnd.proto = PIO_DATA_IN_PROTO; | ||
387 | ata_cmnd.in_out = DIR_READ; | ||
388 | |||
389 | res = ps3stor_send_command(dev, LV1_STORAGE_SEND_ATA_COMMAND, | ||
390 | ps3_mm_phys_to_lpar(__pa(&ata_cmnd)), | ||
391 | sizeof(ata_cmnd), ata_cmnd.buffer, | ||
392 | ata_cmnd.arglen); | ||
393 | if (res) { | ||
394 | dev_err(&dev->sbd.core, "%s:%u: identify disk failed 0x%lx\n", | ||
395 | __func__, __LINE__, res); | ||
396 | return -EIO; | ||
397 | } | ||
398 | |||
399 | swap_buf_le16(id, ATA_ID_WORDS); | ||
400 | |||
401 | /* All we're interested in are raw capacity and model name */ | ||
402 | priv->raw_capacity = ata_id_n_sectors(id); | ||
403 | ata_id_c_string(id, priv->model, ATA_ID_PROD, sizeof(priv->model)); | ||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static void ps3disk_prepare_flush(request_queue_t *q, struct request *req) | ||
408 | { | ||
409 | struct ps3_storage_device *dev = q->queuedata; | ||
410 | |||
411 | dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__); | ||
412 | |||
413 | memset(req->cmd, 0, sizeof(req->cmd)); | ||
414 | req->cmd_type = REQ_TYPE_FLUSH; | ||
415 | } | ||
416 | |||
417 | static int ps3disk_issue_flush(request_queue_t *q, struct gendisk *gendisk, | ||
418 | sector_t *sector) | ||
419 | { | ||
420 | struct ps3_storage_device *dev = q->queuedata; | ||
421 | struct request *req; | ||
422 | int res; | ||
423 | |||
424 | dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__); | ||
425 | |||
426 | req = blk_get_request(q, WRITE, __GFP_WAIT); | ||
427 | ps3disk_prepare_flush(q, req); | ||
428 | res = blk_execute_rq(q, gendisk, req, 0); | ||
429 | if (res) | ||
430 | dev_err(&dev->sbd.core, "%s:%u: flush request failed %d\n", | ||
431 | __func__, __LINE__, res); | ||
432 | blk_put_request(req); | ||
433 | return res; | ||
434 | } | ||
435 | |||
436 | |||
437 | static unsigned long ps3disk_mask; | ||
438 | |||
439 | static DEFINE_MUTEX(ps3disk_mask_mutex); | ||
440 | |||
441 | static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev) | ||
442 | { | ||
443 | struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); | ||
444 | struct ps3disk_private *priv; | ||
445 | int error; | ||
446 | unsigned int devidx; | ||
447 | struct request_queue *queue; | ||
448 | struct gendisk *gendisk; | ||
449 | |||
450 | if (dev->blk_size < 512) { | ||
451 | dev_err(&dev->sbd.core, | ||
452 | "%s:%u: cannot handle block size %lu\n", __func__, | ||
453 | __LINE__, dev->blk_size); | ||
454 | return -EINVAL; | ||
455 | } | ||
456 | |||
457 | BUILD_BUG_ON(PS3DISK_MAX_DISKS > BITS_PER_LONG); | ||
458 | mutex_lock(&ps3disk_mask_mutex); | ||
459 | devidx = find_first_zero_bit(&ps3disk_mask, PS3DISK_MAX_DISKS); | ||
460 | if (devidx >= PS3DISK_MAX_DISKS) { | ||
461 | dev_err(&dev->sbd.core, "%s:%u: Too many disks\n", __func__, | ||
462 | __LINE__); | ||
463 | mutex_unlock(&ps3disk_mask_mutex); | ||
464 | return -ENOSPC; | ||
465 | } | ||
466 | __set_bit(devidx, &ps3disk_mask); | ||
467 | mutex_unlock(&ps3disk_mask_mutex); | ||
468 | |||
469 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
470 | if (!priv) { | ||
471 | error = -ENOMEM; | ||
472 | goto fail; | ||
473 | } | ||
474 | |||
475 | dev->sbd.core.driver_data = priv; | ||
476 | spin_lock_init(&priv->lock); | ||
477 | |||
478 | dev->bounce_size = BOUNCE_SIZE; | ||
479 | dev->bounce_buf = kmalloc(BOUNCE_SIZE, GFP_DMA); | ||
480 | if (!dev->bounce_buf) { | ||
481 | error = -ENOMEM; | ||
482 | goto fail_free_priv; | ||
483 | } | ||
484 | |||
485 | error = ps3stor_setup(dev, ps3disk_interrupt); | ||
486 | if (error) | ||
487 | goto fail_free_bounce; | ||
488 | |||
489 | ps3disk_identify(dev); | ||
490 | |||
491 | queue = blk_init_queue(ps3disk_request, &priv->lock); | ||
492 | if (!queue) { | ||
493 | dev_err(&dev->sbd.core, "%s:%u: blk_init_queue failed\n", | ||
494 | __func__, __LINE__); | ||
495 | error = -ENOMEM; | ||
496 | goto fail_teardown; | ||
497 | } | ||
498 | |||
499 | priv->queue = queue; | ||
500 | queue->queuedata = dev; | ||
501 | |||
502 | blk_queue_bounce_limit(queue, BLK_BOUNCE_HIGH); | ||
503 | |||
504 | blk_queue_max_sectors(queue, dev->bounce_size >> 9); | ||
505 | blk_queue_segment_boundary(queue, -1UL); | ||
506 | blk_queue_dma_alignment(queue, dev->blk_size-1); | ||
507 | blk_queue_hardsect_size(queue, dev->blk_size); | ||
508 | |||
509 | blk_queue_issue_flush_fn(queue, ps3disk_issue_flush); | ||
510 | blk_queue_ordered(queue, QUEUE_ORDERED_DRAIN_FLUSH, | ||
511 | ps3disk_prepare_flush); | ||
512 | |||
513 | blk_queue_max_phys_segments(queue, -1); | ||
514 | blk_queue_max_hw_segments(queue, -1); | ||
515 | blk_queue_max_segment_size(queue, dev->bounce_size); | ||
516 | |||
517 | gendisk = alloc_disk(PS3DISK_MINORS); | ||
518 | if (!gendisk) { | ||
519 | dev_err(&dev->sbd.core, "%s:%u: alloc_disk failed\n", __func__, | ||
520 | __LINE__); | ||
521 | error = -ENOMEM; | ||
522 | goto fail_cleanup_queue; | ||
523 | } | ||
524 | |||
525 | priv->gendisk = gendisk; | ||
526 | gendisk->major = ps3disk_major; | ||
527 | gendisk->first_minor = devidx * PS3DISK_MINORS; | ||
528 | gendisk->fops = &ps3disk_fops; | ||
529 | gendisk->queue = queue; | ||
530 | gendisk->private_data = dev; | ||
531 | gendisk->driverfs_dev = &dev->sbd.core; | ||
532 | snprintf(gendisk->disk_name, sizeof(gendisk->disk_name), PS3DISK_NAME, | ||
533 | devidx+'a'); | ||
534 | priv->blocking_factor = dev->blk_size >> 9; | ||
535 | set_capacity(gendisk, | ||
536 | dev->regions[dev->region_idx].size*priv->blocking_factor); | ||
537 | |||
538 | dev_info(&dev->sbd.core, | ||
539 | "%s is a %s (%lu MiB total, %lu MiB for OtherOS)\n", | ||
540 | gendisk->disk_name, priv->model, priv->raw_capacity >> 11, | ||
541 | get_capacity(gendisk) >> 11); | ||
542 | |||
543 | add_disk(gendisk); | ||
544 | return 0; | ||
545 | |||
546 | fail_cleanup_queue: | ||
547 | blk_cleanup_queue(queue); | ||
548 | fail_teardown: | ||
549 | ps3stor_teardown(dev); | ||
550 | fail_free_bounce: | ||
551 | kfree(dev->bounce_buf); | ||
552 | fail_free_priv: | ||
553 | kfree(priv); | ||
554 | dev->sbd.core.driver_data = NULL; | ||
555 | fail: | ||
556 | mutex_lock(&ps3disk_mask_mutex); | ||
557 | __clear_bit(devidx, &ps3disk_mask); | ||
558 | mutex_unlock(&ps3disk_mask_mutex); | ||
559 | return error; | ||
560 | } | ||
561 | |||
562 | static int ps3disk_remove(struct ps3_system_bus_device *_dev) | ||
563 | { | ||
564 | struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); | ||
565 | struct ps3disk_private *priv = dev->sbd.core.driver_data; | ||
566 | |||
567 | mutex_lock(&ps3disk_mask_mutex); | ||
568 | __clear_bit(priv->gendisk->first_minor / PS3DISK_MINORS, | ||
569 | &ps3disk_mask); | ||
570 | mutex_unlock(&ps3disk_mask_mutex); | ||
571 | del_gendisk(priv->gendisk); | ||
572 | blk_cleanup_queue(priv->queue); | ||
573 | put_disk(priv->gendisk); | ||
574 | dev_notice(&dev->sbd.core, "Synchronizing disk cache\n"); | ||
575 | ps3disk_sync_cache(dev); | ||
576 | ps3stor_teardown(dev); | ||
577 | kfree(dev->bounce_buf); | ||
578 | kfree(priv); | ||
579 | dev->sbd.core.driver_data = NULL; | ||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | static struct ps3_system_bus_driver ps3disk = { | ||
584 | .match_id = PS3_MATCH_ID_STOR_DISK, | ||
585 | .core.name = DEVICE_NAME, | ||
586 | .core.owner = THIS_MODULE, | ||
587 | .probe = ps3disk_probe, | ||
588 | .remove = ps3disk_remove, | ||
589 | .shutdown = ps3disk_remove, | ||
590 | }; | ||
591 | |||
592 | |||
593 | static int __init ps3disk_init(void) | ||
594 | { | ||
595 | int error; | ||
596 | |||
597 | if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) | ||
598 | return -ENODEV; | ||
599 | |||
600 | error = register_blkdev(0, DEVICE_NAME); | ||
601 | if (error <= 0) { | ||
602 | printk(KERN_ERR "%s:%u: register_blkdev failed %d\n", __func__, | ||
603 | __LINE__, error); | ||
604 | return error; | ||
605 | } | ||
606 | ps3disk_major = error; | ||
607 | |||
608 | pr_info("%s:%u: registered block device major %d\n", __func__, | ||
609 | __LINE__, ps3disk_major); | ||
610 | |||
611 | error = ps3_system_bus_driver_register(&ps3disk); | ||
612 | if (error) | ||
613 | unregister_blkdev(ps3disk_major, DEVICE_NAME); | ||
614 | |||
615 | return error; | ||
616 | } | ||
617 | |||
618 | static void __exit ps3disk_exit(void) | ||
619 | { | ||
620 | ps3_system_bus_driver_unregister(&ps3disk); | ||
621 | unregister_blkdev(ps3disk_major, DEVICE_NAME); | ||
622 | } | ||
623 | |||
624 | module_init(ps3disk_init); | ||
625 | module_exit(ps3disk_exit); | ||
626 | |||
627 | MODULE_LICENSE("GPL"); | ||
628 | MODULE_DESCRIPTION("PS3 Disk Storage Driver"); | ||
629 | MODULE_AUTHOR("Sony Corporation"); | ||
630 | MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_DISK); | ||
diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 4e6f387fd1..8fecaf4010 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile | |||
@@ -107,6 +107,8 @@ obj-$(CONFIG_IPMI_HANDLER) += ipmi/ | |||
107 | obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o | 107 | obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o |
108 | obj-$(CONFIG_TCG_TPM) += tpm/ | 108 | obj-$(CONFIG_TCG_TPM) += tpm/ |
109 | 109 | ||
110 | obj-$(CONFIG_PS3_FLASH) += ps3flash.o | ||
111 | |||
110 | # Files generated that shall be removed upon make clean | 112 | # Files generated that shall be removed upon make clean |
111 | clean-files := consolemap_deftbl.c defkeymap.c | 113 | clean-files := consolemap_deftbl.c defkeymap.c |
112 | 114 | ||
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 7cda04b335..2d7cd486e0 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig | |||
@@ -41,7 +41,7 @@ config HW_RANDOM_AMD | |||
41 | 41 | ||
42 | config HW_RANDOM_GEODE | 42 | config HW_RANDOM_GEODE |
43 | tristate "AMD Geode HW Random Number Generator support" | 43 | tristate "AMD Geode HW Random Number Generator support" |
44 | depends on HW_RANDOM && X86 && PCI | 44 | depends on HW_RANDOM && X86_32 && PCI |
45 | default HW_RANDOM | 45 | default HW_RANDOM |
46 | ---help--- | 46 | ---help--- |
47 | This driver provides kernel-side support for the Random Number | 47 | This driver provides kernel-side support for the Random Number |
diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c new file mode 100644 index 0000000000..79b6f461be --- /dev/null +++ b/drivers/char/ps3flash.c | |||
@@ -0,0 +1,440 @@ | |||
1 | /* | ||
2 | * PS3 FLASH ROM Storage Driver | ||
3 | * | ||
4 | * Copyright (C) 2007 Sony Computer Entertainment Inc. | ||
5 | * Copyright 2007 Sony Corp. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published | ||
9 | * by the Free Software Foundation; version 2 of the License. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/fs.h> | ||
22 | #include <linux/miscdevice.h> | ||
23 | #include <linux/uaccess.h> | ||
24 | |||
25 | #include <asm/lv1call.h> | ||
26 | #include <asm/ps3stor.h> | ||
27 | |||
28 | |||
29 | #define DEVICE_NAME "ps3flash" | ||
30 | |||
31 | #define FLASH_BLOCK_SIZE (256*1024) | ||
32 | |||
33 | |||
34 | struct ps3flash_private { | ||
35 | struct mutex mutex; /* Bounce buffer mutex */ | ||
36 | }; | ||
37 | |||
38 | static struct ps3_storage_device *ps3flash_dev; | ||
39 | |||
40 | static ssize_t ps3flash_read_write_sectors(struct ps3_storage_device *dev, | ||
41 | u64 lpar, u64 start_sector, | ||
42 | u64 sectors, int write) | ||
43 | { | ||
44 | u64 res = ps3stor_read_write_sectors(dev, lpar, start_sector, sectors, | ||
45 | write); | ||
46 | if (res) { | ||
47 | dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%lx\n", __func__, | ||
48 | __LINE__, write ? "write" : "read", res); | ||
49 | return -EIO; | ||
50 | } | ||
51 | return sectors; | ||
52 | } | ||
53 | |||
54 | static ssize_t ps3flash_read_sectors(struct ps3_storage_device *dev, | ||
55 | u64 start_sector, u64 sectors, | ||
56 | unsigned int sector_offset) | ||
57 | { | ||
58 | u64 max_sectors, lpar; | ||
59 | |||
60 | max_sectors = dev->bounce_size / dev->blk_size; | ||
61 | if (sectors > max_sectors) { | ||
62 | dev_dbg(&dev->sbd.core, "%s:%u Limiting sectors to %lu\n", | ||
63 | __func__, __LINE__, max_sectors); | ||
64 | sectors = max_sectors; | ||
65 | } | ||
66 | |||
67 | lpar = dev->bounce_lpar + sector_offset * dev->blk_size; | ||
68 | return ps3flash_read_write_sectors(dev, lpar, start_sector, sectors, | ||
69 | 0); | ||
70 | } | ||
71 | |||
72 | static ssize_t ps3flash_write_chunk(struct ps3_storage_device *dev, | ||
73 | u64 start_sector) | ||
74 | { | ||
75 | u64 sectors = dev->bounce_size / dev->blk_size; | ||
76 | return ps3flash_read_write_sectors(dev, dev->bounce_lpar, start_sector, | ||
77 | sectors, 1); | ||
78 | } | ||
79 | |||
80 | static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin) | ||
81 | { | ||
82 | struct ps3_storage_device *dev = ps3flash_dev; | ||
83 | loff_t res; | ||
84 | |||
85 | mutex_lock(&file->f_mapping->host->i_mutex); | ||
86 | switch (origin) { | ||
87 | case 1: | ||
88 | offset += file->f_pos; | ||
89 | break; | ||
90 | case 2: | ||
91 | offset += dev->regions[dev->region_idx].size*dev->blk_size; | ||
92 | break; | ||
93 | } | ||
94 | if (offset < 0) { | ||
95 | res = -EINVAL; | ||
96 | goto out; | ||
97 | } | ||
98 | |||
99 | file->f_pos = offset; | ||
100 | res = file->f_pos; | ||
101 | |||
102 | out: | ||
103 | mutex_unlock(&file->f_mapping->host->i_mutex); | ||
104 | return res; | ||
105 | } | ||
106 | |||
107 | static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count, | ||
108 | loff_t *pos) | ||
109 | { | ||
110 | struct ps3_storage_device *dev = ps3flash_dev; | ||
111 | struct ps3flash_private *priv = dev->sbd.core.driver_data; | ||
112 | u64 size, start_sector, end_sector, offset; | ||
113 | ssize_t sectors_read; | ||
114 | size_t remaining, n; | ||
115 | |||
116 | dev_dbg(&dev->sbd.core, | ||
117 | "%s:%u: Reading %zu bytes at position %lld to user 0x%p\n", | ||
118 | __func__, __LINE__, count, *pos, buf); | ||
119 | |||
120 | size = dev->regions[dev->region_idx].size*dev->blk_size; | ||
121 | if (*pos >= size || !count) | ||
122 | return 0; | ||
123 | |||
124 | if (*pos + count > size) { | ||
125 | dev_dbg(&dev->sbd.core, | ||
126 | "%s:%u Truncating count from %zu to %llu\n", __func__, | ||
127 | __LINE__, count, size - *pos); | ||
128 | count = size - *pos; | ||
129 | } | ||
130 | |||
131 | start_sector = *pos / dev->blk_size; | ||
132 | offset = *pos % dev->blk_size; | ||
133 | end_sector = DIV_ROUND_UP(*pos + count, dev->blk_size); | ||
134 | |||
135 | remaining = count; | ||
136 | do { | ||
137 | mutex_lock(&priv->mutex); | ||
138 | |||
139 | sectors_read = ps3flash_read_sectors(dev, start_sector, | ||
140 | end_sector-start_sector, | ||
141 | 0); | ||
142 | if (sectors_read < 0) { | ||
143 | mutex_unlock(&priv->mutex); | ||
144 | goto fail; | ||
145 | } | ||
146 | |||
147 | n = min(remaining, sectors_read*dev->blk_size-offset); | ||
148 | dev_dbg(&dev->sbd.core, | ||
149 | "%s:%u: copy %lu bytes from 0x%p to user 0x%p\n", | ||
150 | __func__, __LINE__, n, dev->bounce_buf+offset, buf); | ||
151 | if (copy_to_user(buf, dev->bounce_buf+offset, n)) { | ||
152 | mutex_unlock(&priv->mutex); | ||
153 | sectors_read = -EFAULT; | ||
154 | goto fail; | ||
155 | } | ||
156 | |||
157 | mutex_unlock(&priv->mutex); | ||
158 | |||
159 | *pos += n; | ||
160 | buf += n; | ||
161 | remaining -= n; | ||
162 | start_sector += sectors_read; | ||
163 | offset = 0; | ||
164 | } while (remaining > 0); | ||
165 | |||
166 | return count; | ||
167 | |||
168 | fail: | ||
169 | return sectors_read; | ||
170 | } | ||
171 | |||
172 | static ssize_t ps3flash_write(struct file *file, const char __user *buf, | ||
173 | size_t count, loff_t *pos) | ||
174 | { | ||
175 | struct ps3_storage_device *dev = ps3flash_dev; | ||
176 | struct ps3flash_private *priv = dev->sbd.core.driver_data; | ||
177 | u64 size, chunk_sectors, start_write_sector, end_write_sector, | ||
178 | end_read_sector, start_read_sector, head, tail, offset; | ||
179 | ssize_t res; | ||
180 | size_t remaining, n; | ||
181 | unsigned int sec_off; | ||
182 | |||
183 | dev_dbg(&dev->sbd.core, | ||
184 | "%s:%u: Writing %zu bytes at position %lld from user 0x%p\n", | ||
185 | __func__, __LINE__, count, *pos, buf); | ||
186 | |||
187 | size = dev->regions[dev->region_idx].size*dev->blk_size; | ||
188 | if (*pos >= size || !count) | ||
189 | return 0; | ||
190 | |||
191 | if (*pos + count > size) { | ||
192 | dev_dbg(&dev->sbd.core, | ||
193 | "%s:%u Truncating count from %zu to %llu\n", __func__, | ||
194 | __LINE__, count, size - *pos); | ||
195 | count = size - *pos; | ||
196 | } | ||
197 | |||
198 | chunk_sectors = dev->bounce_size / dev->blk_size; | ||
199 | |||
200 | start_write_sector = *pos / dev->bounce_size * chunk_sectors; | ||
201 | offset = *pos % dev->bounce_size; | ||
202 | end_write_sector = DIV_ROUND_UP(*pos + count, dev->bounce_size) * | ||
203 | chunk_sectors; | ||
204 | |||
205 | end_read_sector = DIV_ROUND_UP(*pos, dev->blk_size); | ||
206 | start_read_sector = (*pos + count) / dev->blk_size; | ||
207 | |||
208 | /* | ||
209 | * As we have to write in 256 KiB chunks, while we can read in blk_size | ||
210 | * (usually 512 bytes) chunks, we perform the following steps: | ||
211 | * 1. Read from start_write_sector to end_read_sector ("head") | ||
212 | * 2. Read from start_read_sector to end_write_sector ("tail") | ||
213 | * 3. Copy data to buffer | ||
214 | * 4. Write from start_write_sector to end_write_sector | ||
215 | * All of this is complicated by using only one 256 KiB bounce buffer. | ||
216 | */ | ||
217 | |||
218 | head = end_read_sector - start_write_sector; | ||
219 | tail = end_write_sector - start_read_sector; | ||
220 | |||
221 | remaining = count; | ||
222 | do { | ||
223 | mutex_lock(&priv->mutex); | ||
224 | |||
225 | if (end_read_sector >= start_read_sector) { | ||
226 | /* Merge head and tail */ | ||
227 | dev_dbg(&dev->sbd.core, | ||
228 | "Merged head and tail: %lu sectors at %lu\n", | ||
229 | chunk_sectors, start_write_sector); | ||
230 | res = ps3flash_read_sectors(dev, start_write_sector, | ||
231 | chunk_sectors, 0); | ||
232 | if (res < 0) | ||
233 | goto fail; | ||
234 | } else { | ||
235 | if (head) { | ||
236 | /* Read head */ | ||
237 | dev_dbg(&dev->sbd.core, | ||
238 | "head: %lu sectors at %lu\n", head, | ||
239 | start_write_sector); | ||
240 | res = ps3flash_read_sectors(dev, | ||
241 | start_write_sector, | ||
242 | head, 0); | ||
243 | if (res < 0) | ||
244 | goto fail; | ||
245 | } | ||
246 | if (start_read_sector < | ||
247 | start_write_sector+chunk_sectors) { | ||
248 | /* Read tail */ | ||
249 | dev_dbg(&dev->sbd.core, | ||
250 | "tail: %lu sectors at %lu\n", tail, | ||
251 | start_read_sector); | ||
252 | sec_off = start_read_sector-start_write_sector; | ||
253 | res = ps3flash_read_sectors(dev, | ||
254 | start_read_sector, | ||
255 | tail, sec_off); | ||
256 | if (res < 0) | ||
257 | goto fail; | ||
258 | } | ||
259 | } | ||
260 | |||
261 | n = min(remaining, dev->bounce_size-offset); | ||
262 | dev_dbg(&dev->sbd.core, | ||
263 | "%s:%u: copy %lu bytes from user 0x%p to 0x%p\n", | ||
264 | __func__, __LINE__, n, buf, dev->bounce_buf+offset); | ||
265 | if (copy_from_user(dev->bounce_buf+offset, buf, n)) { | ||
266 | res = -EFAULT; | ||
267 | goto fail; | ||
268 | } | ||
269 | |||
270 | res = ps3flash_write_chunk(dev, start_write_sector); | ||
271 | if (res < 0) | ||
272 | goto fail; | ||
273 | |||
274 | mutex_unlock(&priv->mutex); | ||
275 | |||
276 | *pos += n; | ||
277 | buf += n; | ||
278 | remaining -= n; | ||
279 | start_write_sector += chunk_sectors; | ||
280 | head = 0; | ||
281 | offset = 0; | ||
282 | } while (remaining > 0); | ||
283 | |||
284 | return count; | ||
285 | |||
286 | fail: | ||
287 | mutex_unlock(&priv->mutex); | ||
288 | return res; | ||
289 | } | ||
290 | |||
291 | |||
292 | static irqreturn_t ps3flash_interrupt(int irq, void *data) | ||
293 | { | ||
294 | struct ps3_storage_device *dev = data; | ||
295 | int res; | ||
296 | u64 tag, status; | ||
297 | |||
298 | res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status); | ||
299 | |||
300 | if (tag != dev->tag) | ||
301 | dev_err(&dev->sbd.core, | ||
302 | "%s:%u: tag mismatch, got %lx, expected %lx\n", | ||
303 | __func__, __LINE__, tag, dev->tag); | ||
304 | |||
305 | if (res) { | ||
306 | dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%lx\n", | ||
307 | __func__, __LINE__, res, status); | ||
308 | } else { | ||
309 | dev->lv1_status = status; | ||
310 | complete(&dev->done); | ||
311 | } | ||
312 | return IRQ_HANDLED; | ||
313 | } | ||
314 | |||
315 | |||
316 | static const struct file_operations ps3flash_fops = { | ||
317 | .owner = THIS_MODULE, | ||
318 | .llseek = ps3flash_llseek, | ||
319 | .read = ps3flash_read, | ||
320 | .write = ps3flash_write, | ||
321 | }; | ||
322 | |||
323 | static struct miscdevice ps3flash_misc = { | ||
324 | .minor = MISC_DYNAMIC_MINOR, | ||
325 | .name = DEVICE_NAME, | ||
326 | .fops = &ps3flash_fops, | ||
327 | }; | ||
328 | |||
329 | static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev) | ||
330 | { | ||
331 | struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); | ||
332 | struct ps3flash_private *priv; | ||
333 | int error; | ||
334 | unsigned long tmp; | ||
335 | |||
336 | tmp = dev->regions[dev->region_idx].start*dev->blk_size; | ||
337 | if (tmp % FLASH_BLOCK_SIZE) { | ||
338 | dev_err(&dev->sbd.core, | ||
339 | "%s:%u region start %lu is not aligned\n", __func__, | ||
340 | __LINE__, tmp); | ||
341 | return -EINVAL; | ||
342 | } | ||
343 | tmp = dev->regions[dev->region_idx].size*dev->blk_size; | ||
344 | if (tmp % FLASH_BLOCK_SIZE) { | ||
345 | dev_err(&dev->sbd.core, | ||
346 | "%s:%u region size %lu is not aligned\n", __func__, | ||
347 | __LINE__, tmp); | ||
348 | return -EINVAL; | ||
349 | } | ||
350 | |||
351 | /* use static buffer, kmalloc cannot allocate 256 KiB */ | ||
352 | if (!ps3flash_bounce_buffer.address) | ||
353 | return -ENODEV; | ||
354 | |||
355 | if (ps3flash_dev) { | ||
356 | dev_err(&dev->sbd.core, | ||
357 | "Only one FLASH device is supported\n"); | ||
358 | return -EBUSY; | ||
359 | } | ||
360 | |||
361 | ps3flash_dev = dev; | ||
362 | |||
363 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
364 | if (!priv) { | ||
365 | error = -ENOMEM; | ||
366 | goto fail; | ||
367 | } | ||
368 | |||
369 | dev->sbd.core.driver_data = priv; | ||
370 | mutex_init(&priv->mutex); | ||
371 | |||
372 | dev->bounce_size = ps3flash_bounce_buffer.size; | ||
373 | dev->bounce_buf = ps3flash_bounce_buffer.address; | ||
374 | |||
375 | error = ps3stor_setup(dev, ps3flash_interrupt); | ||
376 | if (error) | ||
377 | goto fail_free_priv; | ||
378 | |||
379 | ps3flash_misc.parent = &dev->sbd.core; | ||
380 | error = misc_register(&ps3flash_misc); | ||
381 | if (error) { | ||
382 | dev_err(&dev->sbd.core, "%s:%u: misc_register failed %d\n", | ||
383 | __func__, __LINE__, error); | ||
384 | goto fail_teardown; | ||
385 | } | ||
386 | |||
387 | dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n", | ||
388 | __func__, __LINE__, ps3flash_misc.minor); | ||
389 | return 0; | ||
390 | |||
391 | fail_teardown: | ||
392 | ps3stor_teardown(dev); | ||
393 | fail_free_priv: | ||
394 | kfree(priv); | ||
395 | dev->sbd.core.driver_data = NULL; | ||
396 | fail: | ||
397 | ps3flash_dev = NULL; | ||
398 | return error; | ||
399 | } | ||
400 | |||
401 | static int ps3flash_remove(struct ps3_system_bus_device *_dev) | ||
402 | { | ||
403 | struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); | ||
404 | |||
405 | misc_deregister(&ps3flash_misc); | ||
406 | ps3stor_teardown(dev); | ||
407 | kfree(dev->sbd.core.driver_data); | ||
408 | dev->sbd.core.driver_data = NULL; | ||
409 | ps3flash_dev = NULL; | ||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | |||
414 | static struct ps3_system_bus_driver ps3flash = { | ||
415 | .match_id = PS3_MATCH_ID_STOR_FLASH, | ||
416 | .core.name = DEVICE_NAME, | ||
417 | .core.owner = THIS_MODULE, | ||
418 | .probe = ps3flash_probe, | ||
419 | .remove = ps3flash_remove, | ||
420 | .shutdown = ps3flash_remove, | ||
421 | }; | ||
422 | |||
423 | |||
424 | static int __init ps3flash_init(void) | ||
425 | { | ||
426 | return ps3_system_bus_driver_register(&ps3flash); | ||
427 | } | ||
428 | |||
429 | static void __exit ps3flash_exit(void) | ||
430 | { | ||
431 | ps3_system_bus_driver_unregister(&ps3flash); | ||
432 | } | ||
433 | |||
434 | module_init(ps3flash_init); | ||
435 | module_exit(ps3flash_exit); | ||
436 | |||
437 | MODULE_LICENSE("GPL"); | ||
438 | MODULE_DESCRIPTION("PS3 FLASH ROM Storage Driver"); | ||
439 | MODULE_AUTHOR("Sony Corporation"); | ||
440 | MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_FLASH); | ||
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 30c3f54c76..ec6b65ec69 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c | |||
@@ -82,7 +82,7 @@ | |||
82 | #include <asm/uaccess.h> | 82 | #include <asm/uaccess.h> |
83 | #include <asm/system.h> | 83 | #include <asm/system.h> |
84 | 84 | ||
85 | #if defined(__i386__) | 85 | #ifdef CONFIG_X86 |
86 | #include <asm/hpet.h> | 86 | #include <asm/hpet.h> |
87 | #endif | 87 | #endif |
88 | 88 | ||
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c index e783dbf0f1..7b46faf223 100644 --- a/drivers/clocksource/acpi_pm.c +++ b/drivers/clocksource/acpi_pm.c | |||
@@ -71,7 +71,7 @@ static struct clocksource clocksource_acpi_pm = { | |||
71 | .rating = 200, | 71 | .rating = 200, |
72 | .read = acpi_pm_read, | 72 | .read = acpi_pm_read, |
73 | .mask = (cycle_t)ACPI_PM_MASK, | 73 | .mask = (cycle_t)ACPI_PM_MASK, |
74 | .mult = 0, /*to be caluclated*/ | 74 | .mult = 0, /*to be calculated*/ |
75 | .shift = 22, | 75 | .shift = 22, |
76 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | 76 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
77 | 77 | ||
diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c index 31989dcd92..906bf5e8de 100644 --- a/drivers/input/misc/pcspkr.c +++ b/drivers/input/misc/pcspkr.c | |||
@@ -24,7 +24,12 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | |||
24 | MODULE_DESCRIPTION("PC Speaker beeper driver"); | 24 | MODULE_DESCRIPTION("PC Speaker beeper driver"); |
25 | MODULE_LICENSE("GPL"); | 25 | MODULE_LICENSE("GPL"); |
26 | 26 | ||
27 | static DEFINE_SPINLOCK(i8253_beep_lock); | 27 | #ifdef CONFIG_X86 |
28 | /* Use the global PIT lock ! */ | ||
29 | #include <asm/i8253.h> | ||
30 | #else | ||
31 | static DEFINE_SPINLOCK(i8253_lock); | ||
32 | #endif | ||
28 | 33 | ||
29 | static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | 34 | static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) |
30 | { | 35 | { |
@@ -43,7 +48,7 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int c | |||
43 | if (value > 20 && value < 32767) | 48 | if (value > 20 && value < 32767) |
44 | count = PIT_TICK_RATE / value; | 49 | count = PIT_TICK_RATE / value; |
45 | 50 | ||
46 | spin_lock_irqsave(&i8253_beep_lock, flags); | 51 | spin_lock_irqsave(&i8253_lock, flags); |
47 | 52 | ||
48 | if (count) { | 53 | if (count) { |
49 | /* enable counter 2 */ | 54 | /* enable counter 2 */ |
@@ -58,7 +63,7 @@ static int pcspkr_event(struct input_dev *dev, unsigned int type, unsigned int c | |||
58 | outb(inb_p(0x61) & 0xFC, 0x61); | 63 | outb(inb_p(0x61) & 0xFC, 0x61); |
59 | } | 64 | } |
60 | 65 | ||
61 | spin_unlock_irqrestore(&i8253_beep_lock, flags); | 66 | spin_unlock_irqrestore(&i8253_lock, flags); |
62 | 67 | ||
63 | return 0; | 68 | return 0; |
64 | } | 69 | } |
diff --git a/drivers/isdn/Kconfig b/drivers/isdn/Kconfig index cf906c8cee..66f946aa30 100644 --- a/drivers/isdn/Kconfig +++ b/drivers/isdn/Kconfig | |||
@@ -21,9 +21,7 @@ menuconfig ISDN | |||
21 | 21 | ||
22 | if ISDN | 22 | if ISDN |
23 | 23 | ||
24 | menu "Old ISDN4Linux" | 24 | menuconfig ISDN_I4L |
25 | |||
26 | config ISDN_I4L | ||
27 | tristate "Old ISDN4Linux (deprecated)" | 25 | tristate "Old ISDN4Linux (deprecated)" |
28 | ---help--- | 26 | ---help--- |
29 | This driver allows you to use an ISDN adapter for networking | 27 | This driver allows you to use an ISDN adapter for networking |
@@ -45,12 +43,8 @@ if ISDN_I4L | |||
45 | source "drivers/isdn/i4l/Kconfig" | 43 | source "drivers/isdn/i4l/Kconfig" |
46 | endif | 44 | endif |
47 | 45 | ||
48 | endmenu | 46 | menuconfig ISDN_CAPI |
49 | 47 | tristate "CAPI 2.0 subsystem" | |
50 | comment "CAPI subsystem" | ||
51 | |||
52 | config ISDN_CAPI | ||
53 | tristate "CAPI2.0 support" | ||
54 | help | 48 | help |
55 | This provides the CAPI (Common ISDN Application Programming | 49 | This provides the CAPI (Common ISDN Application Programming |
56 | Interface, a standard making it easy for programs to access ISDN | 50 | Interface, a standard making it easy for programs to access ISDN |
diff --git a/drivers/isdn/act2000/Kconfig b/drivers/isdn/act2000/Kconfig index 78e6ad8d57..3fc1a5434e 100644 --- a/drivers/isdn/act2000/Kconfig +++ b/drivers/isdn/act2000/Kconfig | |||
@@ -3,7 +3,7 @@ | |||
3 | # | 3 | # |
4 | config ISDN_DRV_ACT2000 | 4 | config ISDN_DRV_ACT2000 |
5 | tristate "IBM Active 2000 support" | 5 | tristate "IBM Active 2000 support" |
6 | depends on ISDN_I4L && ISA | 6 | depends on ISA |
7 | help | 7 | help |
8 | Say Y here if you have an IBM Active 2000 ISDN card. In order to use | 8 | Say Y here if you have an IBM Active 2000 ISDN card. In order to use |
9 | this card, additional firmware is necessary, which has to be loaded | 9 | this card, additional firmware is necessary, which has to be loaded |
diff --git a/drivers/isdn/gigaset/Kconfig b/drivers/isdn/gigaset/Kconfig index bcbb6502a7..0017e50c69 100644 --- a/drivers/isdn/gigaset/Kconfig +++ b/drivers/isdn/gigaset/Kconfig | |||
@@ -1,9 +1,5 @@ | |||
1 | menu "Siemens Gigaset" | 1 | menuconfig ISDN_DRV_GIGASET |
2 | depends on ISDN_I4L | ||
3 | |||
4 | config ISDN_DRV_GIGASET | ||
5 | tristate "Siemens Gigaset support (isdn)" | 2 | tristate "Siemens Gigaset support (isdn)" |
6 | depends on ISDN_I4L | ||
7 | select CRC_CCITT | 3 | select CRC_CCITT |
8 | select BITREVERSE | 4 | select BITREVERSE |
9 | help | 5 | help |
@@ -55,6 +51,4 @@ config GIGASET_UNDOCREQ | |||
55 | features like configuration mode of M105, say yes. If you | 51 | features like configuration mode of M105, say yes. If you |
56 | care about your device, say no. | 52 | care about your device, say no. |
57 | 53 | ||
58 | endif | 54 | endif # ISDN_DRV_GIGASET != n |
59 | |||
60 | endmenu | ||
diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig index 12d91fb9f8..a3b945ac32 100644 --- a/drivers/isdn/hisax/Kconfig +++ b/drivers/isdn/hisax/Kconfig | |||
@@ -1,6 +1,5 @@ | |||
1 | 1 | ||
2 | menu "Passive cards" | 2 | menu "Passive cards" |
3 | depends on ISDN_I4L | ||
4 | 3 | ||
5 | config ISDN_DRV_HISAX | 4 | config ISDN_DRV_HISAX |
6 | tristate "HiSax SiemensChipSet driver support" | 5 | tristate "HiSax SiemensChipSet driver support" |
diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig index e91c187992..36778b270c 100644 --- a/drivers/isdn/i4l/Kconfig +++ b/drivers/isdn/i4l/Kconfig | |||
@@ -99,7 +99,6 @@ config ISDN_DRV_LOOP | |||
99 | 99 | ||
100 | config ISDN_DIVERSION | 100 | config ISDN_DIVERSION |
101 | tristate "Support isdn diversion services" | 101 | tristate "Support isdn diversion services" |
102 | depends on ISDN_I4L | ||
103 | help | 102 | help |
104 | This option allows you to use some supplementary diversion | 103 | This option allows you to use some supplementary diversion |
105 | services in conjunction with the HiSax driver on an EURO/DSS1 | 104 | services in conjunction with the HiSax driver on an EURO/DSS1 |
@@ -119,13 +118,11 @@ config ISDN_DIVERSION | |||
119 | endmenu | 118 | endmenu |
120 | 119 | ||
121 | comment "ISDN4Linux hardware drivers" | 120 | comment "ISDN4Linux hardware drivers" |
122 | depends on ISDN_I4L | ||
123 | 121 | ||
124 | source "drivers/isdn/hisax/Kconfig" | 122 | source "drivers/isdn/hisax/Kconfig" |
125 | 123 | ||
126 | 124 | ||
127 | menu "Active cards" | 125 | menu "Active cards" |
128 | depends on ISDN_I4L!=n | ||
129 | 126 | ||
130 | source "drivers/isdn/icn/Kconfig" | 127 | source "drivers/isdn/icn/Kconfig" |
131 | 128 | ||
diff --git a/drivers/isdn/icn/Kconfig b/drivers/isdn/icn/Kconfig index fcb99f5f0b..89d15eed76 100644 --- a/drivers/isdn/icn/Kconfig +++ b/drivers/isdn/icn/Kconfig | |||
@@ -3,7 +3,7 @@ | |||
3 | # | 3 | # |
4 | config ISDN_DRV_ICN | 4 | config ISDN_DRV_ICN |
5 | tristate "ICN 2B and 4B support" | 5 | tristate "ICN 2B and 4B support" |
6 | depends on ISDN_I4L && ISA | 6 | depends on ISA |
7 | help | 7 | help |
8 | This enables support for two kinds of ISDN-cards made by a German | 8 | This enables support for two kinds of ISDN-cards made by a German |
9 | company called ICN. 2B is the standard version for a single ISDN | 9 | company called ICN. 2B is the standard version for a single ISDN |
diff --git a/drivers/isdn/pcbit/Kconfig b/drivers/isdn/pcbit/Kconfig index 0933881ab0..ffba6eca12 100644 --- a/drivers/isdn/pcbit/Kconfig +++ b/drivers/isdn/pcbit/Kconfig | |||
@@ -3,7 +3,7 @@ | |||
3 | # | 3 | # |
4 | config ISDN_DRV_PCBIT | 4 | config ISDN_DRV_PCBIT |
5 | tristate "PCBIT-D support" | 5 | tristate "PCBIT-D support" |
6 | depends on ISDN_I4L && ISA && (BROKEN || X86) | 6 | depends on ISA && (BROKEN || X86) |
7 | help | 7 | help |
8 | This enables support for the PCBIT ISDN-card. This card is | 8 | This enables support for the PCBIT ISDN-card. This card is |
9 | manufactured in Portugal by Octal. For running this card, | 9 | manufactured in Portugal by Octal. For running this card, |
diff --git a/drivers/isdn/sc/Kconfig b/drivers/isdn/sc/Kconfig index 5346e33d81..e6510ca7bf 100644 --- a/drivers/isdn/sc/Kconfig +++ b/drivers/isdn/sc/Kconfig | |||
@@ -3,7 +3,7 @@ | |||
3 | # | 3 | # |
4 | config ISDN_DRV_SC | 4 | config ISDN_DRV_SC |
5 | tristate "Spellcaster support" | 5 | tristate "Spellcaster support" |
6 | depends on ISDN_I4L && ISA | 6 | depends on ISA |
7 | help | 7 | help |
8 | This enables support for the Spellcaster BRI ISDN boards. This | 8 | This enables support for the Spellcaster BRI ISDN boards. This |
9 | driver currently builds only in a modularized version. | 9 | driver currently builds only in a modularized version. |
diff --git a/drivers/kvm/Kconfig b/drivers/kvm/Kconfig index 2f661e5f0d..6cecc396e0 100644 --- a/drivers/kvm/Kconfig +++ b/drivers/kvm/Kconfig | |||
@@ -11,6 +11,7 @@ if VIRTUALIZATION | |||
11 | config KVM | 11 | config KVM |
12 | tristate "Kernel-based Virtual Machine (KVM) support" | 12 | tristate "Kernel-based Virtual Machine (KVM) support" |
13 | depends on X86 && EXPERIMENTAL | 13 | depends on X86 && EXPERIMENTAL |
14 | select ANON_INODES | ||
14 | ---help--- | 15 | ---help--- |
15 | Support hosting fully virtualized guest machines using hardware | 16 | Support hosting fully virtualized guest machines using hardware |
16 | virtualization extensions. You will need a fairly recent | 17 | virtualization extensions. You will need a fairly recent |
diff --git a/drivers/lguest/lguest.c b/drivers/lguest/lguest.c index 434fea1e82..18dade06d4 100644 --- a/drivers/lguest/lguest.c +++ b/drivers/lguest/lguest.c | |||
@@ -398,6 +398,8 @@ static void lguest_clockevent_set_mode(enum clock_event_mode mode, | |||
398 | break; | 398 | break; |
399 | case CLOCK_EVT_MODE_PERIODIC: | 399 | case CLOCK_EVT_MODE_PERIODIC: |
400 | BUG(); | 400 | BUG(); |
401 | case CLOCK_EVT_MODE_RESUME: | ||
402 | break; | ||
401 | } | 403 | } |
402 | } | 404 | } |
403 | 405 | ||
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index ba952a0325..bdc52d6922 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c | |||
@@ -920,6 +920,8 @@ static void crypt_dtr(struct dm_target *ti) | |||
920 | { | 920 | { |
921 | struct crypt_config *cc = (struct crypt_config *) ti->private; | 921 | struct crypt_config *cc = (struct crypt_config *) ti->private; |
922 | 922 | ||
923 | flush_workqueue(_kcryptd_workqueue); | ||
924 | |||
923 | bioset_free(cc->bs); | 925 | bioset_free(cc->bs); |
924 | mempool_destroy(cc->page_pool); | 926 | mempool_destroy(cc->page_pool); |
925 | mempool_destroy(cc->io_pool); | 927 | mempool_destroy(cc->io_pool); |
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 1d516f24ba..aaaa61ea42 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
@@ -150,6 +150,7 @@ config THINKPAD_ACPI | |||
150 | depends on X86 && ACPI | 150 | depends on X86 && ACPI |
151 | select BACKLIGHT_CLASS_DEVICE | 151 | select BACKLIGHT_CLASS_DEVICE |
152 | select HWMON | 152 | select HWMON |
153 | select NVRAM | ||
153 | ---help--- | 154 | ---help--- |
154 | This is a driver for the IBM and Lenovo ThinkPad laptops. It adds | 155 | This is a driver for the IBM and Lenovo ThinkPad laptops. It adds |
155 | support for Fn-Fx key combinations, Bluetooth control, video | 156 | support for Fn-Fx key combinations, Bluetooth control, video |
@@ -196,4 +197,17 @@ config THINKPAD_ACPI_BAY | |||
196 | 197 | ||
197 | If you are not sure, say Y here. | 198 | If you are not sure, say Y here. |
198 | 199 | ||
200 | config THINKPAD_ACPI_INPUT_ENABLED | ||
201 | bool "Enable input layer support by default" | ||
202 | depends on THINKPAD_ACPI | ||
203 | default y | ||
204 | ---help--- | ||
205 | Enables hot key handling over the input layer by default. If unset, | ||
206 | the driver does not enable any hot key handling by default, and also | ||
207 | starts up with a mostly empty keymap. | ||
208 | |||
209 | If you are not sure, say Y here. Say N to retain the deprecated | ||
210 | behavior of ibm-acpi, and thinkpad-acpi for kernels up to 2.6.21. | ||
211 | |||
212 | |||
199 | endif # MISC_DEVICES | 213 | endif # MISC_DEVICES |
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c index 9623eaf4f8..303e48ca0e 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c | |||
@@ -142,43 +142,124 @@ struct sony_laptop_keypress { | |||
142 | int key; | 142 | int key; |
143 | }; | 143 | }; |
144 | 144 | ||
145 | /* Correspondance table between sonypi events and input layer events */ | 145 | /* Correspondance table between sonypi events |
146 | static struct { | 146 | * and input layer indexes in the keymap |
147 | int sonypiev; | 147 | */ |
148 | int inputev; | 148 | static int sony_laptop_input_index[] = { |
149 | } sony_laptop_inputkeys[] = { | 149 | -1, /* no event */ |
150 | { SONYPI_EVENT_CAPTURE_PRESSED, KEY_CAMERA }, | 150 | -1, /* SONYPI_EVENT_JOGDIAL_DOWN */ |
151 | { SONYPI_EVENT_FNKEY_ONLY, KEY_FN }, | 151 | -1, /* SONYPI_EVENT_JOGDIAL_UP */ |
152 | { SONYPI_EVENT_FNKEY_ESC, KEY_FN_ESC }, | 152 | -1, /* SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */ |
153 | { SONYPI_EVENT_FNKEY_F1, KEY_FN_F1 }, | 153 | -1, /* SONYPI_EVENT_JOGDIAL_UP_PRESSED */ |
154 | { SONYPI_EVENT_FNKEY_F2, KEY_FN_F2 }, | 154 | -1, /* SONYPI_EVENT_JOGDIAL_PRESSED */ |
155 | { SONYPI_EVENT_FNKEY_F3, KEY_FN_F3 }, | 155 | -1, /* SONYPI_EVENT_JOGDIAL_RELEASED */ |
156 | { SONYPI_EVENT_FNKEY_F4, KEY_FN_F4 }, | 156 | 0, /* SONYPI_EVENT_CAPTURE_PRESSED */ |
157 | { SONYPI_EVENT_FNKEY_F5, KEY_FN_F5 }, | 157 | 1, /* SONYPI_EVENT_CAPTURE_RELEASED */ |
158 | { SONYPI_EVENT_FNKEY_F6, KEY_FN_F6 }, | 158 | 2, /* SONYPI_EVENT_CAPTURE_PARTIALPRESSED */ |
159 | { SONYPI_EVENT_FNKEY_F7, KEY_FN_F7 }, | 159 | 3, /* SONYPI_EVENT_CAPTURE_PARTIALRELEASED */ |
160 | { SONYPI_EVENT_FNKEY_F8, KEY_FN_F8 }, | 160 | 4, /* SONYPI_EVENT_FNKEY_ESC */ |
161 | { SONYPI_EVENT_FNKEY_F9, KEY_FN_F9 }, | 161 | 5, /* SONYPI_EVENT_FNKEY_F1 */ |
162 | { SONYPI_EVENT_FNKEY_F10, KEY_FN_F10 }, | 162 | 6, /* SONYPI_EVENT_FNKEY_F2 */ |
163 | { SONYPI_EVENT_FNKEY_F11, KEY_FN_F11 }, | 163 | 7, /* SONYPI_EVENT_FNKEY_F3 */ |
164 | { SONYPI_EVENT_FNKEY_F12, KEY_FN_F12 }, | 164 | 8, /* SONYPI_EVENT_FNKEY_F4 */ |
165 | { SONYPI_EVENT_FNKEY_1, KEY_FN_1 }, | 165 | 9, /* SONYPI_EVENT_FNKEY_F5 */ |
166 | { SONYPI_EVENT_FNKEY_2, KEY_FN_2 }, | 166 | 10, /* SONYPI_EVENT_FNKEY_F6 */ |
167 | { SONYPI_EVENT_FNKEY_D, KEY_FN_D }, | 167 | 11, /* SONYPI_EVENT_FNKEY_F7 */ |
168 | { SONYPI_EVENT_FNKEY_E, KEY_FN_E }, | 168 | 12, /* SONYPI_EVENT_FNKEY_F8 */ |
169 | { SONYPI_EVENT_FNKEY_F, KEY_FN_F }, | 169 | 13, /* SONYPI_EVENT_FNKEY_F9 */ |
170 | { SONYPI_EVENT_FNKEY_S, KEY_FN_S }, | 170 | 14, /* SONYPI_EVENT_FNKEY_F10 */ |
171 | { SONYPI_EVENT_FNKEY_B, KEY_FN_B }, | 171 | 15, /* SONYPI_EVENT_FNKEY_F11 */ |
172 | { SONYPI_EVENT_BLUETOOTH_PRESSED, KEY_BLUE }, | 172 | 16, /* SONYPI_EVENT_FNKEY_F12 */ |
173 | { SONYPI_EVENT_BLUETOOTH_ON, KEY_BLUE }, | 173 | 17, /* SONYPI_EVENT_FNKEY_1 */ |
174 | { SONYPI_EVENT_PKEY_P1, KEY_PROG1 }, | 174 | 18, /* SONYPI_EVENT_FNKEY_2 */ |
175 | { SONYPI_EVENT_PKEY_P2, KEY_PROG2 }, | 175 | 19, /* SONYPI_EVENT_FNKEY_D */ |
176 | { SONYPI_EVENT_PKEY_P3, KEY_PROG3 }, | 176 | 20, /* SONYPI_EVENT_FNKEY_E */ |
177 | { SONYPI_EVENT_BACK_PRESSED, KEY_BACK }, | 177 | 21, /* SONYPI_EVENT_FNKEY_F */ |
178 | { SONYPI_EVENT_HELP_PRESSED, KEY_HELP }, | 178 | 22, /* SONYPI_EVENT_FNKEY_S */ |
179 | { SONYPI_EVENT_ZOOM_PRESSED, KEY_ZOOM }, | 179 | 23, /* SONYPI_EVENT_FNKEY_B */ |
180 | { SONYPI_EVENT_THUMBPHRASE_PRESSED, BTN_THUMB }, | 180 | 24, /* SONYPI_EVENT_BLUETOOTH_PRESSED */ |
181 | { 0, 0 }, | 181 | 25, /* SONYPI_EVENT_PKEY_P1 */ |
182 | 26, /* SONYPI_EVENT_PKEY_P2 */ | ||
183 | 27, /* SONYPI_EVENT_PKEY_P3 */ | ||
184 | 28, /* SONYPI_EVENT_BACK_PRESSED */ | ||
185 | -1, /* SONYPI_EVENT_LID_CLOSED */ | ||
186 | -1, /* SONYPI_EVENT_LID_OPENED */ | ||
187 | 29, /* SONYPI_EVENT_BLUETOOTH_ON */ | ||
188 | 30, /* SONYPI_EVENT_BLUETOOTH_OFF */ | ||
189 | 31, /* SONYPI_EVENT_HELP_PRESSED */ | ||
190 | 32, /* SONYPI_EVENT_FNKEY_ONLY */ | ||
191 | 33, /* SONYPI_EVENT_JOGDIAL_FAST_DOWN */ | ||
192 | 34, /* SONYPI_EVENT_JOGDIAL_FAST_UP */ | ||
193 | 35, /* SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */ | ||
194 | 36, /* SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */ | ||
195 | 37, /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN */ | ||
196 | 38, /* SONYPI_EVENT_JOGDIAL_VFAST_UP */ | ||
197 | 39, /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */ | ||
198 | 40, /* SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */ | ||
199 | 41, /* SONYPI_EVENT_ZOOM_PRESSED */ | ||
200 | 42, /* SONYPI_EVENT_THUMBPHRASE_PRESSED */ | ||
201 | 43, /* SONYPI_EVENT_MEYE_FACE */ | ||
202 | 44, /* SONYPI_EVENT_MEYE_OPPOSITE */ | ||
203 | 45, /* SONYPI_EVENT_MEMORYSTICK_INSERT */ | ||
204 | 46, /* SONYPI_EVENT_MEMORYSTICK_EJECT */ | ||
205 | -1, /* SONYPI_EVENT_ANYBUTTON_RELEASED */ | ||
206 | -1, /* SONYPI_EVENT_BATTERY_INSERT */ | ||
207 | -1, /* SONYPI_EVENT_BATTERY_REMOVE */ | ||
208 | -1, /* SONYPI_EVENT_FNKEY_RELEASED */ | ||
209 | 47, /* SONYPI_EVENT_WIRELESS_ON */ | ||
210 | 48, /* SONYPI_EVENT_WIRELESS_OFF */ | ||
211 | }; | ||
212 | |||
213 | static int sony_laptop_input_keycode_map[] = { | ||
214 | KEY_CAMERA, /* 0 SONYPI_EVENT_CAPTURE_PRESSED */ | ||
215 | KEY_RESERVED, /* 1 SONYPI_EVENT_CAPTURE_RELEASED */ | ||
216 | KEY_RESERVED, /* 2 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */ | ||
217 | KEY_RESERVED, /* 3 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */ | ||
218 | KEY_FN_ESC, /* 4 SONYPI_EVENT_FNKEY_ESC */ | ||
219 | KEY_FN_F1, /* 5 SONYPI_EVENT_FNKEY_F1 */ | ||
220 | KEY_FN_F2, /* 6 SONYPI_EVENT_FNKEY_F2 */ | ||
221 | KEY_FN_F3, /* 7 SONYPI_EVENT_FNKEY_F3 */ | ||
222 | KEY_FN_F4, /* 8 SONYPI_EVENT_FNKEY_F4 */ | ||
223 | KEY_FN_F5, /* 9 SONYPI_EVENT_FNKEY_F5 */ | ||
224 | KEY_FN_F6, /* 10 SONYPI_EVENT_FNKEY_F6 */ | ||
225 | KEY_FN_F7, /* 11 SONYPI_EVENT_FNKEY_F7 */ | ||
226 | KEY_FN_F8, /* 12 SONYPI_EVENT_FNKEY_F8 */ | ||
227 | KEY_FN_F9, /* 13 SONYPI_EVENT_FNKEY_F9 */ | ||
228 | KEY_FN_F10, /* 14 SONYPI_EVENT_FNKEY_F10 */ | ||
229 | KEY_FN_F11, /* 15 SONYPI_EVENT_FNKEY_F11 */ | ||
230 | KEY_FN_F12, /* 16 SONYPI_EVENT_FNKEY_F12 */ | ||
231 | KEY_FN_F1, /* 17 SONYPI_EVENT_FNKEY_1 */ | ||
232 | KEY_FN_F2, /* 18 SONYPI_EVENT_FNKEY_2 */ | ||
233 | KEY_FN_D, /* 19 SONYPI_EVENT_FNKEY_D */ | ||
234 | KEY_FN_E, /* 20 SONYPI_EVENT_FNKEY_E */ | ||
235 | KEY_FN_F, /* 21 SONYPI_EVENT_FNKEY_F */ | ||
236 | KEY_FN_S, /* 22 SONYPI_EVENT_FNKEY_S */ | ||
237 | KEY_FN_B, /* 23 SONYPI_EVENT_FNKEY_B */ | ||
238 | KEY_BLUETOOTH, /* 24 SONYPI_EVENT_BLUETOOTH_PRESSED */ | ||
239 | KEY_PROG1, /* 25 SONYPI_EVENT_PKEY_P1 */ | ||
240 | KEY_PROG2, /* 26 SONYPI_EVENT_PKEY_P2 */ | ||
241 | KEY_PROG3, /* 27 SONYPI_EVENT_PKEY_P3 */ | ||
242 | KEY_BACK, /* 28 SONYPI_EVENT_BACK_PRESSED */ | ||
243 | KEY_BLUETOOTH, /* 29 SONYPI_EVENT_BLUETOOTH_ON */ | ||
244 | KEY_BLUETOOTH, /* 30 SONYPI_EVENT_BLUETOOTH_OFF */ | ||
245 | KEY_HELP, /* 31 SONYPI_EVENT_HELP_PRESSED */ | ||
246 | KEY_FN, /* 32 SONYPI_EVENT_FNKEY_ONLY */ | ||
247 | KEY_RESERVED, /* 33 SONYPI_EVENT_JOGDIAL_FAST_DOWN */ | ||
248 | KEY_RESERVED, /* 34 SONYPI_EVENT_JOGDIAL_FAST_UP */ | ||
249 | KEY_RESERVED, /* 35 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */ | ||
250 | KEY_RESERVED, /* 36 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */ | ||
251 | KEY_RESERVED, /* 37 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */ | ||
252 | KEY_RESERVED, /* 38 SONYPI_EVENT_JOGDIAL_VFAST_UP */ | ||
253 | KEY_RESERVED, /* 39 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */ | ||
254 | KEY_RESERVED, /* 40 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */ | ||
255 | KEY_ZOOM, /* 41 SONYPI_EVENT_ZOOM_PRESSED */ | ||
256 | BTN_THUMB, /* 42 SONYPI_EVENT_THUMBPHRASE_PRESSED */ | ||
257 | KEY_RESERVED, /* 43 SONYPI_EVENT_MEYE_FACE */ | ||
258 | KEY_RESERVED, /* 44 SONYPI_EVENT_MEYE_OPPOSITE */ | ||
259 | KEY_RESERVED, /* 45 SONYPI_EVENT_MEMORYSTICK_INSERT */ | ||
260 | KEY_RESERVED, /* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */ | ||
261 | KEY_WLAN, /* 47 SONYPI_EVENT_WIRELESS_ON */ | ||
262 | KEY_WLAN, /* 48 SONYPI_EVENT_WIRELESS_OFF */ | ||
182 | }; | 263 | }; |
183 | 264 | ||
184 | /* release buttons after a short delay if pressed */ | 265 | /* release buttons after a short delay if pressed */ |
@@ -202,7 +283,6 @@ static void sony_laptop_report_input_event(u8 event) | |||
202 | struct input_dev *jog_dev = sony_laptop_input.jog_dev; | 283 | struct input_dev *jog_dev = sony_laptop_input.jog_dev; |
203 | struct input_dev *key_dev = sony_laptop_input.key_dev; | 284 | struct input_dev *key_dev = sony_laptop_input.key_dev; |
204 | struct sony_laptop_keypress kp = { NULL }; | 285 | struct sony_laptop_keypress kp = { NULL }; |
205 | int i; | ||
206 | 286 | ||
207 | if (event == SONYPI_EVENT_FNKEY_RELEASED) { | 287 | if (event == SONYPI_EVENT_FNKEY_RELEASED) { |
208 | /* Nothing, not all VAIOs generate this event */ | 288 | /* Nothing, not all VAIOs generate this event */ |
@@ -231,17 +311,22 @@ static void sony_laptop_report_input_event(u8 event) | |||
231 | break; | 311 | break; |
232 | 312 | ||
233 | default: | 313 | default: |
234 | for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++) | 314 | if (event > ARRAY_SIZE (sony_laptop_input_keycode_map)) { |
235 | if (event == sony_laptop_inputkeys[i].sonypiev) { | 315 | dprintk("sony_laptop_report_input_event, event not known: %d\n", event); |
316 | break; | ||
317 | } | ||
318 | if (sony_laptop_input_index[event] != -1) { | ||
319 | kp.key = sony_laptop_input_keycode_map[sony_laptop_input_index[event]]; | ||
320 | if (kp.key != KEY_UNKNOWN) | ||
236 | kp.dev = key_dev; | 321 | kp.dev = key_dev; |
237 | kp.key = sony_laptop_inputkeys[i].inputev; | 322 | } |
238 | break; | ||
239 | } | ||
240 | break; | 323 | break; |
241 | } | 324 | } |
242 | 325 | ||
243 | if (kp.dev) { | 326 | if (kp.dev) { |
244 | input_report_key(kp.dev, kp.key, 1); | 327 | input_report_key(kp.dev, kp.key, 1); |
328 | /* we emit the scancode so we can always remap the key */ | ||
329 | input_event(kp.dev, EV_MSC, MSC_SCAN, event); | ||
245 | input_sync(kp.dev); | 330 | input_sync(kp.dev); |
246 | kfifo_put(sony_laptop_input.fifo, | 331 | kfifo_put(sony_laptop_input.fifo, |
247 | (unsigned char *)&kp, sizeof(kp)); | 332 | (unsigned char *)&kp, sizeof(kp)); |
@@ -296,11 +381,18 @@ static int sony_laptop_setup_input(void) | |||
296 | key_dev->id.vendor = PCI_VENDOR_ID_SONY; | 381 | key_dev->id.vendor = PCI_VENDOR_ID_SONY; |
297 | 382 | ||
298 | /* Initialize the Input Drivers: special keys */ | 383 | /* Initialize the Input Drivers: special keys */ |
299 | key_dev->evbit[0] = BIT(EV_KEY); | 384 | set_bit(EV_KEY, key_dev->evbit); |
300 | for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++) | 385 | set_bit(EV_MSC, key_dev->evbit); |
301 | if (sony_laptop_inputkeys[i].inputev) | 386 | set_bit(MSC_SCAN, key_dev->mscbit); |
302 | set_bit(sony_laptop_inputkeys[i].inputev, | 387 | key_dev->keycodesize = sizeof(sony_laptop_input_keycode_map[0]); |
303 | key_dev->keybit); | 388 | key_dev->keycodemax = ARRAY_SIZE(sony_laptop_input_keycode_map); |
389 | key_dev->keycode = &sony_laptop_input_keycode_map; | ||
390 | for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++) { | ||
391 | if (sony_laptop_input_keycode_map[i] != KEY_RESERVED) { | ||
392 | set_bit(sony_laptop_input_keycode_map[i], | ||
393 | key_dev->keybit); | ||
394 | } | ||
395 | } | ||
304 | 396 | ||
305 | error = input_register_device(key_dev); | 397 | error = input_register_device(key_dev); |
306 | if (error) | 398 | if (error) |
@@ -487,6 +579,14 @@ SNC_HANDLE_NAMES(audiopower_set, "AZPW"); | |||
487 | SNC_HANDLE_NAMES(lanpower_get, "GLNP"); | 579 | SNC_HANDLE_NAMES(lanpower_get, "GLNP"); |
488 | SNC_HANDLE_NAMES(lanpower_set, "LNPW"); | 580 | SNC_HANDLE_NAMES(lanpower_set, "LNPW"); |
489 | 581 | ||
582 | SNC_HANDLE_NAMES(lidstate_get, "GLID"); | ||
583 | |||
584 | SNC_HANDLE_NAMES(indicatorlamp_get, "GILS"); | ||
585 | SNC_HANDLE_NAMES(indicatorlamp_set, "SILS"); | ||
586 | |||
587 | SNC_HANDLE_NAMES(gainbass_get, "GMGB"); | ||
588 | SNC_HANDLE_NAMES(gainbass_set, "CMGB"); | ||
589 | |||
490 | SNC_HANDLE_NAMES(PID_get, "GPID"); | 590 | SNC_HANDLE_NAMES(PID_get, "GPID"); |
491 | 591 | ||
492 | SNC_HANDLE_NAMES(CTR_get, "GCTR"); | 592 | SNC_HANDLE_NAMES(CTR_get, "GCTR"); |
@@ -507,6 +607,12 @@ static struct sony_nc_value sony_nc_values[] = { | |||
507 | boolean_validate, 0), | 607 | boolean_validate, 0), |
508 | SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set, | 608 | SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set, |
509 | boolean_validate, 1), | 609 | boolean_validate, 1), |
610 | SNC_HANDLE(lidstate, snc_lidstate_get, NULL, | ||
611 | boolean_validate, 0), | ||
612 | SNC_HANDLE(indicatorlamp, snc_indicatorlamp_get, snc_indicatorlamp_set, | ||
613 | boolean_validate, 0), | ||
614 | SNC_HANDLE(gainbass, snc_gainbass_get, snc_gainbass_set, | ||
615 | boolean_validate, 0), | ||
510 | /* unknown methods */ | 616 | /* unknown methods */ |
511 | SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1), | 617 | SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1), |
512 | SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1), | 618 | SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1), |
@@ -689,13 +795,116 @@ static struct backlight_ops sony_backlight_ops = { | |||
689 | }; | 795 | }; |
690 | 796 | ||
691 | /* | 797 | /* |
798 | * New SNC-only Vaios event mapping to driver known keys | ||
799 | */ | ||
800 | struct sony_nc_event { | ||
801 | u8 data; | ||
802 | u8 event; | ||
803 | }; | ||
804 | |||
805 | static struct sony_nc_event *sony_nc_events; | ||
806 | |||
807 | /* Vaio C* --maybe also FE*, N* and AR* ?-- special init sequence | ||
808 | * for Fn keys | ||
809 | */ | ||
810 | static int sony_nc_C_enable(struct dmi_system_id *id) | ||
811 | { | ||
812 | int result = 0; | ||
813 | |||
814 | printk(KERN_NOTICE DRV_PFX "detected %s\n", id->ident); | ||
815 | |||
816 | sony_nc_events = id->driver_data; | ||
817 | |||
818 | if (acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x4, &result) < 0 | ||
819 | || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x2, &result) < 0 | ||
820 | || acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x10, &result) < 0 | ||
821 | || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x0, &result) < 0 | ||
822 | || acpi_callsetfunc(sony_nc_acpi_handle, "SN03", 0x2, &result) < 0 | ||
823 | || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x101, &result) < 0) { | ||
824 | printk(KERN_WARNING DRV_PFX "failed to initialize SNC, some " | ||
825 | "functionalities may be missing\n"); | ||
826 | return 1; | ||
827 | } | ||
828 | return 0; | ||
829 | } | ||
830 | |||
831 | static struct sony_nc_event sony_C_events[] = { | ||
832 | { 0x81, SONYPI_EVENT_FNKEY_F1 }, | ||
833 | { 0x01, SONYPI_EVENT_FNKEY_RELEASED }, | ||
834 | { 0x85, SONYPI_EVENT_FNKEY_F5 }, | ||
835 | { 0x05, SONYPI_EVENT_FNKEY_RELEASED }, | ||
836 | { 0x86, SONYPI_EVENT_FNKEY_F6 }, | ||
837 | { 0x06, SONYPI_EVENT_FNKEY_RELEASED }, | ||
838 | { 0x87, SONYPI_EVENT_FNKEY_F7 }, | ||
839 | { 0x07, SONYPI_EVENT_FNKEY_RELEASED }, | ||
840 | { 0x8A, SONYPI_EVENT_FNKEY_F10 }, | ||
841 | { 0x0A, SONYPI_EVENT_FNKEY_RELEASED }, | ||
842 | { 0x8C, SONYPI_EVENT_FNKEY_F12 }, | ||
843 | { 0x0C, SONYPI_EVENT_FNKEY_RELEASED }, | ||
844 | { 0, 0 }, | ||
845 | }; | ||
846 | |||
847 | /* SNC-only model map */ | ||
848 | struct dmi_system_id sony_nc_ids[] = { | ||
849 | { | ||
850 | .ident = "Sony Vaio FE Series", | ||
851 | .callback = sony_nc_C_enable, | ||
852 | .driver_data = sony_C_events, | ||
853 | .matches = { | ||
854 | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), | ||
855 | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FE"), | ||
856 | }, | ||
857 | }, | ||
858 | { | ||
859 | .ident = "Sony Vaio C Series", | ||
860 | .callback = sony_nc_C_enable, | ||
861 | .driver_data = sony_C_events, | ||
862 | .matches = { | ||
863 | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), | ||
864 | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-C"), | ||
865 | }, | ||
866 | }, | ||
867 | { } | ||
868 | }; | ||
869 | |||
870 | /* | ||
692 | * ACPI callbacks | 871 | * ACPI callbacks |
693 | */ | 872 | */ |
694 | static void sony_acpi_notify(acpi_handle handle, u32 event, void *data) | 873 | static void sony_acpi_notify(acpi_handle handle, u32 event, void *data) |
695 | { | 874 | { |
696 | dprintk("sony_acpi_notify, event: %d\n", event); | 875 | struct sony_nc_event *evmap; |
697 | sony_laptop_report_input_event(event); | 876 | u32 ev = event; |
698 | acpi_bus_generate_event(sony_nc_acpi_device, 1, event); | 877 | int result; |
878 | |||
879 | if (ev == 0x92) { | ||
880 | /* read the key pressed from EC.GECR | ||
881 | * A call to SN07 with 0x0202 will do it as well respecting | ||
882 | * the current protocol on different OSes | ||
883 | * | ||
884 | * Note: the path for GECR may be | ||
885 | * \_SB.PCI0.LPCB.EC (C, FE, AR, N and friends) | ||
886 | * \_SB.PCI0.PIB.EC0 (VGN-FR notifications are sent directly, no GECR) | ||
887 | * | ||
888 | * TODO: we may want to do the same for the older GHKE -need | ||
889 | * dmi list- so this snippet may become one more callback. | ||
890 | */ | ||
891 | if (acpi_callsetfunc(handle, "SN07", 0x0202, &result) < 0) | ||
892 | dprintk("sony_acpi_notify, unable to decode event 0x%.2x\n", ev); | ||
893 | else | ||
894 | ev = result & 0xFF; | ||
895 | } | ||
896 | |||
897 | if (sony_nc_events) | ||
898 | for (evmap = sony_nc_events; evmap->event; evmap++) { | ||
899 | if (evmap->data == ev) { | ||
900 | ev = evmap->event; | ||
901 | break; | ||
902 | } | ||
903 | } | ||
904 | |||
905 | dprintk("sony_acpi_notify, event: 0x%.2x\n", ev); | ||
906 | sony_laptop_report_input_event(ev); | ||
907 | acpi_bus_generate_event(sony_nc_acpi_device, 1, ev); | ||
699 | } | 908 | } |
700 | 909 | ||
701 | static acpi_status sony_walk_callback(acpi_handle handle, u32 level, | 910 | static acpi_status sony_walk_callback(acpi_handle handle, u32 level, |
@@ -732,6 +941,10 @@ static int sony_nc_resume(struct acpi_device *device) | |||
732 | break; | 941 | break; |
733 | } | 942 | } |
734 | } | 943 | } |
944 | |||
945 | /* re-initialize models with specific requirements */ | ||
946 | dmi_check_system(sony_nc_ids); | ||
947 | |||
735 | return 0; | 948 | return 0; |
736 | } | 949 | } |
737 | 950 | ||
@@ -750,6 +963,15 @@ static int sony_nc_add(struct acpi_device *device) | |||
750 | 963 | ||
751 | sony_nc_acpi_handle = device->handle; | 964 | sony_nc_acpi_handle = device->handle; |
752 | 965 | ||
966 | /* read device status */ | ||
967 | result = acpi_bus_get_status(device); | ||
968 | /* bail IFF the above call was successful and the device is not present */ | ||
969 | if (!result && !device->status.present) { | ||
970 | dprintk("Device not present\n"); | ||
971 | result = -ENODEV; | ||
972 | goto outwalk; | ||
973 | } | ||
974 | |||
753 | if (debug) { | 975 | if (debug) { |
754 | status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle, | 976 | status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle, |
755 | 1, sony_walk_callback, NULL, NULL); | 977 | 1, sony_walk_callback, NULL, NULL); |
@@ -760,6 +982,15 @@ static int sony_nc_add(struct acpi_device *device) | |||
760 | } | 982 | } |
761 | } | 983 | } |
762 | 984 | ||
985 | /* try to _INI the device if such method exists (ACPI spec 3.0-6.5.1 | ||
986 | * should be respected as we already checked for the device presence above */ | ||
987 | if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, METHOD_NAME__INI, &handle))) { | ||
988 | dprintk("Invoking _INI\n"); | ||
989 | if (ACPI_FAILURE(acpi_evaluate_object(sony_nc_acpi_handle, METHOD_NAME__INI, | ||
990 | NULL, NULL))) | ||
991 | dprintk("_INI Method failed\n"); | ||
992 | } | ||
993 | |||
763 | /* setup input devices and helper fifo */ | 994 | /* setup input devices and helper fifo */ |
764 | result = sony_laptop_setup_input(); | 995 | result = sony_laptop_setup_input(); |
765 | if (result) { | 996 | if (result) { |
@@ -772,7 +1003,7 @@ static int sony_nc_add(struct acpi_device *device) | |||
772 | ACPI_DEVICE_NOTIFY, | 1003 | ACPI_DEVICE_NOTIFY, |
773 | sony_acpi_notify, NULL); | 1004 | sony_acpi_notify, NULL); |
774 | if (ACPI_FAILURE(status)) { | 1005 | if (ACPI_FAILURE(status)) { |
775 | printk(KERN_WARNING DRV_PFX "unable to install notify handler\n"); | 1006 | printk(KERN_WARNING DRV_PFX "unable to install notify handler (%u)\n", status); |
776 | result = -ENODEV; | 1007 | result = -ENODEV; |
777 | goto outinput; | 1008 | goto outinput; |
778 | } | 1009 | } |
@@ -795,6 +1026,9 @@ static int sony_nc_add(struct acpi_device *device) | |||
795 | 1026 | ||
796 | } | 1027 | } |
797 | 1028 | ||
1029 | /* initialize models with specific requirements */ | ||
1030 | dmi_check_system(sony_nc_ids); | ||
1031 | |||
798 | result = sony_pf_add(); | 1032 | result = sony_pf_add(); |
799 | if (result) | 1033 | if (result) |
800 | goto outbacklight; | 1034 | goto outbacklight; |
@@ -908,7 +1142,9 @@ static struct acpi_driver sony_nc_driver = { | |||
908 | #define SONYPI_DEVICE_TYPE2 0x00000002 | 1142 | #define SONYPI_DEVICE_TYPE2 0x00000002 |
909 | #define SONYPI_DEVICE_TYPE3 0x00000004 | 1143 | #define SONYPI_DEVICE_TYPE3 0x00000004 |
910 | 1144 | ||
911 | #define SONY_PIC_EV_MASK 0xff | 1145 | #define SONYPI_TYPE1_OFFSET 0x04 |
1146 | #define SONYPI_TYPE2_OFFSET 0x12 | ||
1147 | #define SONYPI_TYPE3_OFFSET 0x12 | ||
912 | 1148 | ||
913 | struct sony_pic_ioport { | 1149 | struct sony_pic_ioport { |
914 | struct acpi_resource_io io; | 1150 | struct acpi_resource_io io; |
@@ -922,6 +1158,7 @@ struct sony_pic_irq { | |||
922 | 1158 | ||
923 | struct sony_pic_dev { | 1159 | struct sony_pic_dev { |
924 | int model; | 1160 | int model; |
1161 | u16 evport_offset; | ||
925 | u8 camera_power; | 1162 | u8 camera_power; |
926 | u8 bluetooth_power; | 1163 | u8 bluetooth_power; |
927 | u8 wwan_power; | 1164 | u8 wwan_power; |
@@ -1999,20 +2236,17 @@ end: | |||
1999 | static irqreturn_t sony_pic_irq(int irq, void *dev_id) | 2236 | static irqreturn_t sony_pic_irq(int irq, void *dev_id) |
2000 | { | 2237 | { |
2001 | int i, j; | 2238 | int i, j; |
2002 | u32 port_val = 0; | ||
2003 | u8 ev = 0; | 2239 | u8 ev = 0; |
2004 | u8 data_mask = 0; | 2240 | u8 data_mask = 0; |
2005 | u8 device_event = 0; | 2241 | u8 device_event = 0; |
2006 | 2242 | ||
2007 | struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id; | 2243 | struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id; |
2008 | 2244 | ||
2009 | acpi_os_read_port(dev->cur_ioport->io.minimum, &port_val, | 2245 | ev = inb_p(dev->cur_ioport->io.minimum); |
2010 | dev->cur_ioport->io.address_length); | 2246 | data_mask = inb_p(dev->cur_ioport->io.minimum + dev->evport_offset); |
2011 | ev = port_val & SONY_PIC_EV_MASK; | ||
2012 | data_mask = 0xff & (port_val >> (dev->cur_ioport->io.address_length - 8)); | ||
2013 | 2247 | ||
2014 | dprintk("event (0x%.8x [%.2x] [%.2x]) at port 0x%.4x\n", | 2248 | dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n", |
2015 | port_val, ev, data_mask, dev->cur_ioport->io.minimum); | 2249 | ev, data_mask, dev->cur_ioport->io.minimum, dev->evport_offset); |
2016 | 2250 | ||
2017 | if (ev == 0x00 || ev == 0xff) | 2251 | if (ev == 0x00 || ev == 0xff) |
2018 | return IRQ_HANDLED; | 2252 | return IRQ_HANDLED; |
@@ -2103,6 +2337,20 @@ static int sony_pic_add(struct acpi_device *device) | |||
2103 | spic_dev.model = sony_pic_detect_device_type(); | 2337 | spic_dev.model = sony_pic_detect_device_type(); |
2104 | mutex_init(&spic_dev.lock); | 2338 | mutex_init(&spic_dev.lock); |
2105 | 2339 | ||
2340 | /* model specific characteristics */ | ||
2341 | switch(spic_dev.model) { | ||
2342 | case SONYPI_DEVICE_TYPE1: | ||
2343 | spic_dev.evport_offset = SONYPI_TYPE1_OFFSET; | ||
2344 | break; | ||
2345 | case SONYPI_DEVICE_TYPE3: | ||
2346 | spic_dev.evport_offset = SONYPI_TYPE3_OFFSET; | ||
2347 | break; | ||
2348 | case SONYPI_DEVICE_TYPE2: | ||
2349 | default: | ||
2350 | spic_dev.evport_offset = SONYPI_TYPE2_OFFSET; | ||
2351 | break; | ||
2352 | } | ||
2353 | |||
2106 | /* read _PRS resources */ | 2354 | /* read _PRS resources */ |
2107 | result = sony_pic_possible_resources(device); | 2355 | result = sony_pic_possible_resources(device); |
2108 | if (result) { | 2356 | if (result) { |
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 95c0b96e83..f15a58f740 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.14" | 24 | #define IBM_VERSION "0.15" |
25 | #define TPACPI_SYSFS_VERSION 0x000100 | 25 | #define TPACPI_SYSFS_VERSION 0x010000 |
26 | 26 | ||
27 | /* | 27 | /* |
28 | * Changelog: | 28 | * Changelog: |
@@ -92,6 +92,29 @@ MODULE_LICENSE("GPL"); | |||
92 | /* Please remove this in year 2009 */ | 92 | /* Please remove this in year 2009 */ |
93 | MODULE_ALIAS("ibm_acpi"); | 93 | MODULE_ALIAS("ibm_acpi"); |
94 | 94 | ||
95 | /* | ||
96 | * DMI matching for module autoloading | ||
97 | * | ||
98 | * See http://thinkwiki.org/wiki/List_of_DMI_IDs | ||
99 | * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads | ||
100 | * | ||
101 | * Only models listed in thinkwiki will be supported, so add yours | ||
102 | * if it is not there yet. | ||
103 | */ | ||
104 | #define IBM_BIOS_MODULE_ALIAS(__type) \ | ||
105 | MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW") | ||
106 | |||
107 | /* Non-ancient thinkpads */ | ||
108 | MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*"); | ||
109 | MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*"); | ||
110 | |||
111 | /* Ancient thinkpad BIOSes have to be identified by | ||
112 | * BIOS type or model number, and there are far less | ||
113 | * BIOS types than model numbers... */ | ||
114 | IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]"); | ||
115 | IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]"); | ||
116 | IBM_BIOS_MODULE_ALIAS("K[U,X-Z]"); | ||
117 | |||
95 | #define __unused __attribute__ ((unused)) | 118 | #define __unused __attribute__ ((unused)) |
96 | 119 | ||
97 | /**************************************************************************** | 120 | /**************************************************************************** |
@@ -106,7 +129,7 @@ MODULE_ALIAS("ibm_acpi"); | |||
106 | * ACPI basic handles | 129 | * ACPI basic handles |
107 | */ | 130 | */ |
108 | 131 | ||
109 | static acpi_handle root_handle = NULL; | 132 | static acpi_handle root_handle; |
110 | 133 | ||
111 | #define IBM_HANDLE(object, parent, paths...) \ | 134 | #define IBM_HANDLE(object, parent, paths...) \ |
112 | static acpi_handle object##_handle; \ | 135 | static acpi_handle object##_handle; \ |
@@ -487,19 +510,36 @@ static char *next_cmd(char **cmds) | |||
487 | /**************************************************************************** | 510 | /**************************************************************************** |
488 | **************************************************************************** | 511 | **************************************************************************** |
489 | * | 512 | * |
490 | * Device model: hwmon and platform | 513 | * Device model: input, hwmon and platform |
491 | * | 514 | * |
492 | **************************************************************************** | 515 | **************************************************************************** |
493 | ****************************************************************************/ | 516 | ****************************************************************************/ |
494 | 517 | ||
495 | static struct platform_device *tpacpi_pdev = NULL; | 518 | static struct platform_device *tpacpi_pdev; |
496 | static struct class_device *tpacpi_hwmon = NULL; | 519 | static struct class_device *tpacpi_hwmon; |
520 | static struct input_dev *tpacpi_inputdev; | ||
521 | |||
522 | |||
523 | static int tpacpi_resume_handler(struct platform_device *pdev) | ||
524 | { | ||
525 | struct ibm_struct *ibm, *itmp; | ||
526 | |||
527 | list_for_each_entry_safe(ibm, itmp, | ||
528 | &tpacpi_all_drivers, | ||
529 | all_drivers) { | ||
530 | if (ibm->resume) | ||
531 | (ibm->resume)(); | ||
532 | } | ||
533 | |||
534 | return 0; | ||
535 | } | ||
497 | 536 | ||
498 | static struct platform_driver tpacpi_pdriver = { | 537 | static struct platform_driver tpacpi_pdriver = { |
499 | .driver = { | 538 | .driver = { |
500 | .name = IBM_DRVR_NAME, | 539 | .name = IBM_DRVR_NAME, |
501 | .owner = THIS_MODULE, | 540 | .owner = THIS_MODULE, |
502 | }, | 541 | }, |
542 | .resume = tpacpi_resume_handler, | ||
503 | }; | 543 | }; |
504 | 544 | ||
505 | 545 | ||
@@ -677,9 +717,19 @@ static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm) | |||
677 | printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION); | 717 | printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION); |
678 | printk(IBM_INFO "%s\n", IBM_URL); | 718 | printk(IBM_INFO "%s\n", IBM_URL); |
679 | 719 | ||
680 | if (ibm_thinkpad_ec_found) | 720 | printk(IBM_INFO "ThinkPad BIOS %s, EC %s\n", |
681 | printk(IBM_INFO "ThinkPad EC firmware %s\n", | 721 | (thinkpad_id.bios_version_str) ? |
682 | ibm_thinkpad_ec_found); | 722 | thinkpad_id.bios_version_str : "unknown", |
723 | (thinkpad_id.ec_version_str) ? | ||
724 | thinkpad_id.ec_version_str : "unknown"); | ||
725 | |||
726 | if (thinkpad_id.vendor && thinkpad_id.model_str) | ||
727 | printk(IBM_INFO "%s %s\n", | ||
728 | (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ? | ||
729 | "IBM" : ((thinkpad_id.vendor == | ||
730 | PCI_VENDOR_ID_LENOVO) ? | ||
731 | "Lenovo" : "Unknown vendor"), | ||
732 | thinkpad_id.model_str); | ||
683 | 733 | ||
684 | return 0; | 734 | return 0; |
685 | } | 735 | } |
@@ -704,16 +754,28 @@ static struct ibm_struct thinkpad_acpi_driver_data = { | |||
704 | */ | 754 | */ |
705 | 755 | ||
706 | static int hotkey_orig_status; | 756 | static int hotkey_orig_status; |
707 | static int hotkey_orig_mask; | 757 | static u32 hotkey_orig_mask; |
758 | static u32 hotkey_all_mask; | ||
759 | static u32 hotkey_reserved_mask; | ||
760 | |||
761 | static u16 *hotkey_keycode_map; | ||
708 | 762 | ||
709 | static struct attribute_set *hotkey_dev_attributes = NULL; | 763 | static struct attribute_set *hotkey_dev_attributes; |
764 | |||
765 | static int hotkey_get_wlsw(int *status) | ||
766 | { | ||
767 | if (!acpi_evalf(hkey_handle, status, "WLSW", "d")) | ||
768 | return -EIO; | ||
769 | return 0; | ||
770 | } | ||
710 | 771 | ||
711 | /* sysfs hotkey enable ------------------------------------------------- */ | 772 | /* sysfs hotkey enable ------------------------------------------------- */ |
712 | static ssize_t hotkey_enable_show(struct device *dev, | 773 | static ssize_t hotkey_enable_show(struct device *dev, |
713 | struct device_attribute *attr, | 774 | struct device_attribute *attr, |
714 | char *buf) | 775 | char *buf) |
715 | { | 776 | { |
716 | int res, status, mask; | 777 | int res, status; |
778 | u32 mask; | ||
717 | 779 | ||
718 | res = hotkey_get(&status, &mask); | 780 | res = hotkey_get(&status, &mask); |
719 | if (res) | 781 | if (res) |
@@ -727,7 +789,8 @@ static ssize_t hotkey_enable_store(struct device *dev, | |||
727 | const char *buf, size_t count) | 789 | const char *buf, size_t count) |
728 | { | 790 | { |
729 | unsigned long t; | 791 | unsigned long t; |
730 | int res, status, mask; | 792 | int res, status; |
793 | u32 mask; | ||
731 | 794 | ||
732 | if (parse_strtoul(buf, 1, &t)) | 795 | if (parse_strtoul(buf, 1, &t)) |
733 | return -EINVAL; | 796 | return -EINVAL; |
@@ -748,13 +811,14 @@ static ssize_t hotkey_mask_show(struct device *dev, | |||
748 | struct device_attribute *attr, | 811 | struct device_attribute *attr, |
749 | char *buf) | 812 | char *buf) |
750 | { | 813 | { |
751 | int res, status, mask; | 814 | int res, status; |
815 | u32 mask; | ||
752 | 816 | ||
753 | res = hotkey_get(&status, &mask); | 817 | res = hotkey_get(&status, &mask); |
754 | if (res) | 818 | if (res) |
755 | return res; | 819 | return res; |
756 | 820 | ||
757 | return snprintf(buf, PAGE_SIZE, "0x%04x\n", mask); | 821 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", mask); |
758 | } | 822 | } |
759 | 823 | ||
760 | static ssize_t hotkey_mask_store(struct device *dev, | 824 | static ssize_t hotkey_mask_store(struct device *dev, |
@@ -762,9 +826,10 @@ static ssize_t hotkey_mask_store(struct device *dev, | |||
762 | const char *buf, size_t count) | 826 | const char *buf, size_t count) |
763 | { | 827 | { |
764 | unsigned long t; | 828 | unsigned long t; |
765 | int res, status, mask; | 829 | int res, status; |
830 | u32 mask; | ||
766 | 831 | ||
767 | if (parse_strtoul(buf, 0xffff, &t)) | 832 | if (parse_strtoul(buf, 0xffffffffUL, &t)) |
768 | return -EINVAL; | 833 | return -EINVAL; |
769 | 834 | ||
770 | res = hotkey_get(&status, &mask); | 835 | res = hotkey_get(&status, &mask); |
@@ -794,26 +859,123 @@ static ssize_t hotkey_bios_mask_show(struct device *dev, | |||
794 | struct device_attribute *attr, | 859 | struct device_attribute *attr, |
795 | char *buf) | 860 | char *buf) |
796 | { | 861 | { |
797 | return snprintf(buf, PAGE_SIZE, "0x%04x\n", hotkey_orig_mask); | 862 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_orig_mask); |
798 | } | 863 | } |
799 | 864 | ||
800 | static struct device_attribute dev_attr_hotkey_bios_mask = | 865 | static struct device_attribute dev_attr_hotkey_bios_mask = |
801 | __ATTR(hotkey_bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL); | 866 | __ATTR(hotkey_bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL); |
802 | 867 | ||
868 | /* sysfs hotkey all_mask ----------------------------------------------- */ | ||
869 | static ssize_t hotkey_all_mask_show(struct device *dev, | ||
870 | struct device_attribute *attr, | ||
871 | char *buf) | ||
872 | { | ||
873 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_all_mask); | ||
874 | } | ||
875 | |||
876 | static struct device_attribute dev_attr_hotkey_all_mask = | ||
877 | __ATTR(hotkey_all_mask, S_IRUGO, hotkey_all_mask_show, NULL); | ||
878 | |||
879 | /* sysfs hotkey recommended_mask --------------------------------------- */ | ||
880 | static ssize_t hotkey_recommended_mask_show(struct device *dev, | ||
881 | struct device_attribute *attr, | ||
882 | char *buf) | ||
883 | { | ||
884 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", | ||
885 | hotkey_all_mask & ~hotkey_reserved_mask); | ||
886 | } | ||
887 | |||
888 | static struct device_attribute dev_attr_hotkey_recommended_mask = | ||
889 | __ATTR(hotkey_recommended_mask, S_IRUGO, | ||
890 | hotkey_recommended_mask_show, NULL); | ||
891 | |||
892 | /* sysfs hotkey radio_sw ----------------------------------------------- */ | ||
893 | static ssize_t hotkey_radio_sw_show(struct device *dev, | ||
894 | struct device_attribute *attr, | ||
895 | char *buf) | ||
896 | { | ||
897 | int res, s; | ||
898 | res = hotkey_get_wlsw(&s); | ||
899 | if (res < 0) | ||
900 | return res; | ||
901 | |||
902 | return snprintf(buf, PAGE_SIZE, "%d\n", !!s); | ||
903 | } | ||
904 | |||
905 | static struct device_attribute dev_attr_hotkey_radio_sw = | ||
906 | __ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL); | ||
907 | |||
803 | /* --------------------------------------------------------------------- */ | 908 | /* --------------------------------------------------------------------- */ |
804 | 909 | ||
805 | static struct attribute *hotkey_mask_attributes[] = { | 910 | static struct attribute *hotkey_mask_attributes[] = { |
806 | &dev_attr_hotkey_mask.attr, | 911 | &dev_attr_hotkey_mask.attr, |
807 | &dev_attr_hotkey_bios_enabled.attr, | 912 | &dev_attr_hotkey_bios_enabled.attr, |
808 | &dev_attr_hotkey_bios_mask.attr, | 913 | &dev_attr_hotkey_bios_mask.attr, |
914 | &dev_attr_hotkey_all_mask.attr, | ||
915 | &dev_attr_hotkey_recommended_mask.attr, | ||
809 | }; | 916 | }; |
810 | 917 | ||
811 | static int __init hotkey_init(struct ibm_init_struct *iibm) | 918 | static int __init hotkey_init(struct ibm_init_struct *iibm) |
812 | { | 919 | { |
813 | int res; | 920 | |
921 | static u16 ibm_keycode_map[] __initdata = { | ||
922 | /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ | ||
923 | KEY_FN_F1, KEY_FN_F2, KEY_COFFEE, KEY_SLEEP, | ||
924 | KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, | ||
925 | KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND, | ||
926 | /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */ | ||
927 | KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ | ||
928 | KEY_UNKNOWN, /* 0x0D: FN+INSERT */ | ||
929 | KEY_UNKNOWN, /* 0x0E: FN+DELETE */ | ||
930 | KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ | ||
931 | /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */ | ||
932 | KEY_RESERVED, /* 0x10: FN+END (brightness down) */ | ||
933 | KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ | ||
934 | KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ | ||
935 | KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ | ||
936 | KEY_RESERVED, /* 0x14: VOLUME UP */ | ||
937 | KEY_RESERVED, /* 0x15: VOLUME DOWN */ | ||
938 | KEY_RESERVED, /* 0x16: MUTE */ | ||
939 | KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ | ||
940 | /* (assignments unknown, please report if found) */ | ||
941 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | ||
942 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | ||
943 | }; | ||
944 | static u16 lenovo_keycode_map[] __initdata = { | ||
945 | /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */ | ||
946 | KEY_FN_F1, KEY_COFFEE, KEY_BATTERY, KEY_SLEEP, | ||
947 | KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8, | ||
948 | KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND, | ||
949 | /* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */ | ||
950 | KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ | ||
951 | KEY_UNKNOWN, /* 0x0D: FN+INSERT */ | ||
952 | KEY_UNKNOWN, /* 0x0E: FN+DELETE */ | ||
953 | KEY_BRIGHTNESSUP, /* 0x0F: FN+HOME (brightness up) */ | ||
954 | /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */ | ||
955 | KEY_BRIGHTNESSDOWN, /* 0x10: FN+END (brightness down) */ | ||
956 | KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ | ||
957 | KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ | ||
958 | KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ | ||
959 | KEY_RESERVED, /* 0x14: VOLUME UP */ | ||
960 | KEY_RESERVED, /* 0x15: VOLUME DOWN */ | ||
961 | KEY_RESERVED, /* 0x16: MUTE */ | ||
962 | KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ | ||
963 | /* (assignments unknown, please report if found) */ | ||
964 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | ||
965 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | ||
966 | }; | ||
967 | |||
968 | #define TPACPI_HOTKEY_MAP_LEN ARRAY_SIZE(ibm_keycode_map) | ||
969 | #define TPACPI_HOTKEY_MAP_SIZE sizeof(ibm_keycode_map) | ||
970 | #define TPACPI_HOTKEY_MAP_TYPESIZE sizeof(ibm_keycode_map[0]) | ||
971 | |||
972 | int res, i; | ||
973 | int status; | ||
814 | 974 | ||
815 | vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); | 975 | vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); |
816 | 976 | ||
977 | BUG_ON(!tpacpi_inputdev); | ||
978 | |||
817 | IBM_ACPIHANDLE_INIT(hkey); | 979 | IBM_ACPIHANDLE_INIT(hkey); |
818 | mutex_init(&hotkey_mutex); | 980 | mutex_init(&hotkey_mutex); |
819 | 981 | ||
@@ -824,7 +986,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
824 | str_supported(tp_features.hotkey)); | 986 | str_supported(tp_features.hotkey)); |
825 | 987 | ||
826 | if (tp_features.hotkey) { | 988 | if (tp_features.hotkey) { |
827 | hotkey_dev_attributes = create_attr_set(4, NULL); | 989 | hotkey_dev_attributes = create_attr_set(7, NULL); |
828 | if (!hotkey_dev_attributes) | 990 | if (!hotkey_dev_attributes) |
829 | return -ENOMEM; | 991 | return -ENOMEM; |
830 | res = add_to_attr_set(hotkey_dev_attributes, | 992 | res = add_to_attr_set(hotkey_dev_attributes, |
@@ -840,19 +1002,92 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
840 | vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", | 1002 | vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", |
841 | str_supported(tp_features.hotkey_mask)); | 1003 | str_supported(tp_features.hotkey_mask)); |
842 | 1004 | ||
1005 | if (tp_features.hotkey_mask) { | ||
1006 | /* MHKA available in A31, R40, R40e, T4x, X31, and later */ | ||
1007 | if (!acpi_evalf(hkey_handle, &hotkey_all_mask, | ||
1008 | "MHKA", "qd")) | ||
1009 | hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */ | ||
1010 | } | ||
1011 | |||
843 | res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask); | 1012 | res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask); |
844 | if (!res && tp_features.hotkey_mask) { | 1013 | if (!res && tp_features.hotkey_mask) { |
845 | res = add_many_to_attr_set(hotkey_dev_attributes, | 1014 | res = add_many_to_attr_set(hotkey_dev_attributes, |
846 | hotkey_mask_attributes, | 1015 | hotkey_mask_attributes, |
847 | ARRAY_SIZE(hotkey_mask_attributes)); | 1016 | ARRAY_SIZE(hotkey_mask_attributes)); |
848 | } | 1017 | } |
1018 | |||
1019 | /* Not all thinkpads have a hardware radio switch */ | ||
1020 | if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { | ||
1021 | tp_features.hotkey_wlsw = 1; | ||
1022 | printk(IBM_INFO | ||
1023 | "radio switch found; radios are %s\n", | ||
1024 | enabled(status, 0)); | ||
1025 | res = add_to_attr_set(hotkey_dev_attributes, | ||
1026 | &dev_attr_hotkey_radio_sw.attr); | ||
1027 | } | ||
1028 | |||
849 | if (!res) | 1029 | if (!res) |
850 | res = register_attr_set_with_sysfs( | 1030 | res = register_attr_set_with_sysfs( |
851 | hotkey_dev_attributes, | 1031 | hotkey_dev_attributes, |
852 | &tpacpi_pdev->dev.kobj); | 1032 | &tpacpi_pdev->dev.kobj); |
1033 | if (res) | ||
1034 | return res; | ||
1035 | |||
1036 | /* Set up key map */ | ||
1037 | |||
1038 | hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE, | ||
1039 | GFP_KERNEL); | ||
1040 | if (!hotkey_keycode_map) { | ||
1041 | printk(IBM_ERR "failed to allocate memory for key map\n"); | ||
1042 | return -ENOMEM; | ||
1043 | } | ||
1044 | |||
1045 | if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) { | ||
1046 | dbg_printk(TPACPI_DBG_INIT, | ||
1047 | "using Lenovo default hot key map\n"); | ||
1048 | memcpy(hotkey_keycode_map, &lenovo_keycode_map, | ||
1049 | TPACPI_HOTKEY_MAP_SIZE); | ||
1050 | } else { | ||
1051 | dbg_printk(TPACPI_DBG_INIT, | ||
1052 | "using IBM default hot key map\n"); | ||
1053 | memcpy(hotkey_keycode_map, &ibm_keycode_map, | ||
1054 | TPACPI_HOTKEY_MAP_SIZE); | ||
1055 | } | ||
853 | 1056 | ||
1057 | #ifndef CONFIG_THINKPAD_ACPI_INPUT_ENABLED | ||
1058 | for (i = 0; i < 12; i++) | ||
1059 | hotkey_keycode_map[i] = KEY_UNKNOWN; | ||
1060 | #endif /* ! CONFIG_THINKPAD_ACPI_INPUT_ENABLED */ | ||
1061 | |||
1062 | set_bit(EV_KEY, tpacpi_inputdev->evbit); | ||
1063 | set_bit(EV_MSC, tpacpi_inputdev->evbit); | ||
1064 | set_bit(MSC_SCAN, tpacpi_inputdev->mscbit); | ||
1065 | tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE; | ||
1066 | tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN; | ||
1067 | tpacpi_inputdev->keycode = hotkey_keycode_map; | ||
1068 | for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) { | ||
1069 | if (hotkey_keycode_map[i] != KEY_RESERVED) { | ||
1070 | set_bit(hotkey_keycode_map[i], | ||
1071 | tpacpi_inputdev->keybit); | ||
1072 | } else { | ||
1073 | if (i < sizeof(hotkey_reserved_mask)*8) | ||
1074 | hotkey_reserved_mask |= 1 << i; | ||
1075 | } | ||
1076 | } | ||
1077 | |||
1078 | if (tp_features.hotkey_wlsw) { | ||
1079 | set_bit(EV_SW, tpacpi_inputdev->evbit); | ||
1080 | set_bit(SW_RADIO, tpacpi_inputdev->swbit); | ||
1081 | } | ||
1082 | |||
1083 | #ifdef CONFIG_THINKPAD_ACPI_INPUT_ENABLED | ||
1084 | dbg_printk(TPACPI_DBG_INIT, | ||
1085 | "enabling hot key handling\n"); | ||
1086 | res = hotkey_set(1, (hotkey_all_mask & ~hotkey_reserved_mask) | ||
1087 | | hotkey_orig_mask); | ||
854 | if (res) | 1088 | if (res) |
855 | return res; | 1089 | return res; |
1090 | #endif /* CONFIG_THINKPAD_ACPI_INPUT_ENABLED */ | ||
856 | } | 1091 | } |
857 | 1092 | ||
858 | return (tp_features.hotkey)? 0 : 1; | 1093 | return (tp_features.hotkey)? 0 : 1; |
@@ -875,22 +1110,101 @@ static void hotkey_exit(void) | |||
875 | } | 1110 | } |
876 | } | 1111 | } |
877 | 1112 | ||
1113 | static void tpacpi_input_send_key(unsigned int scancode, | ||
1114 | unsigned int keycode) | ||
1115 | { | ||
1116 | if (keycode != KEY_RESERVED) { | ||
1117 | input_report_key(tpacpi_inputdev, keycode, 1); | ||
1118 | if (keycode == KEY_UNKNOWN) | ||
1119 | input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, | ||
1120 | scancode); | ||
1121 | input_sync(tpacpi_inputdev); | ||
1122 | |||
1123 | input_report_key(tpacpi_inputdev, keycode, 0); | ||
1124 | if (keycode == KEY_UNKNOWN) | ||
1125 | input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, | ||
1126 | scancode); | ||
1127 | input_sync(tpacpi_inputdev); | ||
1128 | } | ||
1129 | } | ||
1130 | |||
1131 | static void tpacpi_input_send_radiosw(void) | ||
1132 | { | ||
1133 | int wlsw; | ||
1134 | |||
1135 | if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) | ||
1136 | input_report_switch(tpacpi_inputdev, | ||
1137 | SW_RADIO, !!wlsw); | ||
1138 | } | ||
1139 | |||
878 | static void hotkey_notify(struct ibm_struct *ibm, u32 event) | 1140 | static void hotkey_notify(struct ibm_struct *ibm, u32 event) |
879 | { | 1141 | { |
880 | int hkey; | 1142 | u32 hkey; |
1143 | unsigned int keycode, scancode; | ||
1144 | int sendacpi = 1; | ||
1145 | |||
1146 | if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { | ||
1147 | if (tpacpi_inputdev->users > 0) { | ||
1148 | switch (hkey >> 12) { | ||
1149 | case 1: | ||
1150 | /* 0x1000-0x1FFF: key presses */ | ||
1151 | scancode = hkey & 0xfff; | ||
1152 | if (scancode > 0 && scancode < 0x21) { | ||
1153 | scancode--; | ||
1154 | keycode = hotkey_keycode_map[scancode]; | ||
1155 | tpacpi_input_send_key(scancode, keycode); | ||
1156 | sendacpi = (keycode == KEY_RESERVED | ||
1157 | || keycode == KEY_UNKNOWN); | ||
1158 | } else { | ||
1159 | printk(IBM_ERR | ||
1160 | "hotkey 0x%04x out of range for keyboard map\n", | ||
1161 | hkey); | ||
1162 | } | ||
1163 | break; | ||
1164 | case 5: | ||
1165 | /* 0x5000-0x5FFF: LID */ | ||
1166 | /* we don't handle it through this path, just | ||
1167 | * eat up known LID events */ | ||
1168 | if (hkey != 0x5001 && hkey != 0x5002) { | ||
1169 | printk(IBM_ERR | ||
1170 | "unknown LID-related hotkey event: 0x%04x\n", | ||
1171 | hkey); | ||
1172 | } | ||
1173 | break; | ||
1174 | case 7: | ||
1175 | /* 0x7000-0x7FFF: misc */ | ||
1176 | if (tp_features.hotkey_wlsw && hkey == 0x7000) { | ||
1177 | tpacpi_input_send_radiosw(); | ||
1178 | sendacpi = 0; | ||
1179 | break; | ||
1180 | } | ||
1181 | /* fallthrough to default */ | ||
1182 | default: | ||
1183 | /* case 2: dock-related */ | ||
1184 | /* 0x2305 - T43 waking up due to bay lever eject while aslept */ | ||
1185 | /* case 3: ultra-bay related. maybe bay in dock? */ | ||
1186 | /* 0x3003 - T43 after wake up by bay lever eject (0x2305) */ | ||
1187 | printk(IBM_NOTICE "unhandled hotkey event 0x%04x\n", hkey); | ||
1188 | } | ||
1189 | } | ||
881 | 1190 | ||
882 | if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) | 1191 | if (sendacpi) |
883 | acpi_bus_generate_event(ibm->acpi->device, event, hkey); | 1192 | acpi_bus_generate_event(ibm->acpi->device, event, hkey); |
884 | else { | 1193 | } else { |
885 | printk(IBM_ERR "unknown hotkey event %d\n", event); | 1194 | printk(IBM_ERR "unknown hotkey notification event %d\n", event); |
886 | acpi_bus_generate_event(ibm->acpi->device, event, 0); | 1195 | acpi_bus_generate_event(ibm->acpi->device, event, 0); |
887 | } | 1196 | } |
888 | } | 1197 | } |
889 | 1198 | ||
1199 | static void hotkey_resume(void) | ||
1200 | { | ||
1201 | tpacpi_input_send_radiosw(); | ||
1202 | } | ||
1203 | |||
890 | /* | 1204 | /* |
891 | * Call with hotkey_mutex held | 1205 | * Call with hotkey_mutex held |
892 | */ | 1206 | */ |
893 | static int hotkey_get(int *status, int *mask) | 1207 | static int hotkey_get(int *status, u32 *mask) |
894 | { | 1208 | { |
895 | if (!acpi_evalf(hkey_handle, status, "DHKC", "d")) | 1209 | if (!acpi_evalf(hkey_handle, status, "DHKC", "d")) |
896 | return -EIO; | 1210 | return -EIO; |
@@ -905,7 +1219,7 @@ static int hotkey_get(int *status, int *mask) | |||
905 | /* | 1219 | /* |
906 | * Call with hotkey_mutex held | 1220 | * Call with hotkey_mutex held |
907 | */ | 1221 | */ |
908 | static int hotkey_set(int status, int mask) | 1222 | static int hotkey_set(int status, u32 mask) |
909 | { | 1223 | { |
910 | int i; | 1224 | int i; |
911 | 1225 | ||
@@ -926,7 +1240,8 @@ static int hotkey_set(int status, int mask) | |||
926 | /* procfs -------------------------------------------------------------- */ | 1240 | /* procfs -------------------------------------------------------------- */ |
927 | static int hotkey_read(char *p) | 1241 | static int hotkey_read(char *p) |
928 | { | 1242 | { |
929 | int res, status, mask; | 1243 | int res, status; |
1244 | u32 mask; | ||
930 | int len = 0; | 1245 | int len = 0; |
931 | 1246 | ||
932 | if (!tp_features.hotkey) { | 1247 | if (!tp_features.hotkey) { |
@@ -944,7 +1259,7 @@ static int hotkey_read(char *p) | |||
944 | 1259 | ||
945 | len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); | 1260 | len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); |
946 | if (tp_features.hotkey_mask) { | 1261 | if (tp_features.hotkey_mask) { |
947 | len += sprintf(p + len, "mask:\t\t0x%04x\n", mask); | 1262 | len += sprintf(p + len, "mask:\t\t0x%08x\n", mask); |
948 | len += sprintf(p + len, | 1263 | len += sprintf(p + len, |
949 | "commands:\tenable, disable, reset, <mask>\n"); | 1264 | "commands:\tenable, disable, reset, <mask>\n"); |
950 | } else { | 1265 | } else { |
@@ -957,7 +1272,8 @@ static int hotkey_read(char *p) | |||
957 | 1272 | ||
958 | static int hotkey_write(char *buf) | 1273 | static int hotkey_write(char *buf) |
959 | { | 1274 | { |
960 | int res, status, mask; | 1275 | int res, status; |
1276 | u32 mask; | ||
961 | char *cmd; | 1277 | char *cmd; |
962 | int do_cmd = 0; | 1278 | int do_cmd = 0; |
963 | 1279 | ||
@@ -1012,6 +1328,7 @@ static struct ibm_struct hotkey_driver_data = { | |||
1012 | .read = hotkey_read, | 1328 | .read = hotkey_read, |
1013 | .write = hotkey_write, | 1329 | .write = hotkey_write, |
1014 | .exit = hotkey_exit, | 1330 | .exit = hotkey_exit, |
1331 | .resume = hotkey_resume, | ||
1015 | .acpi = &ibm_hotkey_acpidriver, | 1332 | .acpi = &ibm_hotkey_acpidriver, |
1016 | }; | 1333 | }; |
1017 | 1334 | ||
@@ -1770,7 +2087,10 @@ static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = { | |||
1770 | .type = ACPI_SYSTEM_NOTIFY, | 2087 | .type = ACPI_SYSTEM_NOTIFY, |
1771 | }, | 2088 | }, |
1772 | { | 2089 | { |
1773 | .hid = IBM_PCI_HID, | 2090 | /* THIS ONE MUST NEVER BE USED FOR DRIVER AUTOLOADING. |
2091 | * We just use it to get notifications of dock hotplug | ||
2092 | * in very old thinkpads */ | ||
2093 | .hid = PCI_ROOT_HID_STRING, | ||
1774 | .notify = dock_notify, | 2094 | .notify = dock_notify, |
1775 | .handle = &pci_handle, | 2095 | .handle = &pci_handle, |
1776 | .type = ACPI_SYSTEM_NOTIFY, | 2096 | .type = ACPI_SYSTEM_NOTIFY, |
@@ -1829,7 +2149,7 @@ static int __init dock_init2(struct ibm_init_struct *iibm) | |||
1829 | static void dock_notify(struct ibm_struct *ibm, u32 event) | 2149 | static void dock_notify(struct ibm_struct *ibm, u32 event) |
1830 | { | 2150 | { |
1831 | int docked = dock_docked(); | 2151 | int docked = dock_docked(); |
1832 | int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, IBM_PCI_HID); | 2152 | int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, PCI_ROOT_HID_STRING); |
1833 | 2153 | ||
1834 | if (event == 1 && !pci) /* 570 */ | 2154 | if (event == 1 && !pci) /* 570 */ |
1835 | acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */ | 2155 | acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */ |
@@ -2389,7 +2709,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm) | |||
2389 | 2709 | ||
2390 | acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv"); | 2710 | acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv"); |
2391 | 2711 | ||
2392 | if (ibm_thinkpad_ec_found && experimental) { | 2712 | if (thinkpad_id.ec_model) { |
2393 | /* | 2713 | /* |
2394 | * Direct EC access mode: sensors at registers | 2714 | * Direct EC access mode: sensors at registers |
2395 | * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for | 2715 | * 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for |
@@ -2533,6 +2853,8 @@ static int thermal_get_sensor(int idx, s32 *value) | |||
2533 | snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx); | 2853 | snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx); |
2534 | if (!acpi_evalf(ec_handle, &t, tmpi, "d")) | 2854 | if (!acpi_evalf(ec_handle, &t, tmpi, "d")) |
2535 | return -EIO; | 2855 | return -EIO; |
2856 | if (t > 127 || t < -127) | ||
2857 | t = TP_EC_THERMAL_TMP_NA; | ||
2536 | *value = t * 1000; | 2858 | *value = t * 1000; |
2537 | return 0; | 2859 | return 0; |
2538 | } | 2860 | } |
@@ -2671,22 +2993,39 @@ static struct ibm_struct ecdump_driver_data = { | |||
2671 | * Backlight/brightness subdriver | 2993 | * Backlight/brightness subdriver |
2672 | */ | 2994 | */ |
2673 | 2995 | ||
2674 | static struct backlight_device *ibm_backlight_device = NULL; | 2996 | static struct backlight_device *ibm_backlight_device; |
2675 | 2997 | ||
2676 | static struct backlight_ops ibm_backlight_data = { | 2998 | static struct backlight_ops ibm_backlight_data = { |
2677 | .get_brightness = brightness_get, | 2999 | .get_brightness = brightness_get, |
2678 | .update_status = brightness_update_status, | 3000 | .update_status = brightness_update_status, |
2679 | }; | 3001 | }; |
2680 | 3002 | ||
3003 | static struct mutex brightness_mutex; | ||
3004 | |||
2681 | static int __init brightness_init(struct ibm_init_struct *iibm) | 3005 | static int __init brightness_init(struct ibm_init_struct *iibm) |
2682 | { | 3006 | { |
2683 | int b; | 3007 | int b; |
2684 | 3008 | ||
2685 | vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n"); | 3009 | vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n"); |
2686 | 3010 | ||
3011 | mutex_init(&brightness_mutex); | ||
3012 | |||
3013 | if (!brightness_mode) { | ||
3014 | if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) | ||
3015 | brightness_mode = 2; | ||
3016 | else | ||
3017 | brightness_mode = 3; | ||
3018 | |||
3019 | dbg_printk(TPACPI_DBG_INIT, "selected brightness_mode=%d\n", | ||
3020 | brightness_mode); | ||
3021 | } | ||
3022 | |||
3023 | if (brightness_mode > 3) | ||
3024 | return -EINVAL; | ||
3025 | |||
2687 | b = brightness_get(NULL); | 3026 | b = brightness_get(NULL); |
2688 | if (b < 0) | 3027 | if (b < 0) |
2689 | return b; | 3028 | return 1; |
2690 | 3029 | ||
2691 | ibm_backlight_device = backlight_device_register( | 3030 | ibm_backlight_device = backlight_device_register( |
2692 | TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL, | 3031 | TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL, |
@@ -2722,34 +3061,79 @@ static int brightness_update_status(struct backlight_device *bd) | |||
2722 | bd->props.brightness : 0); | 3061 | bd->props.brightness : 0); |
2723 | } | 3062 | } |
2724 | 3063 | ||
3064 | /* | ||
3065 | * ThinkPads can read brightness from two places: EC 0x31, or | ||
3066 | * CMOS NVRAM byte 0x5E, bits 0-3. | ||
3067 | */ | ||
2725 | static int brightness_get(struct backlight_device *bd) | 3068 | static int brightness_get(struct backlight_device *bd) |
2726 | { | 3069 | { |
2727 | u8 level; | 3070 | u8 lec = 0, lcmos = 0, level = 0; |
2728 | if (!acpi_ec_read(brightness_offset, &level)) | ||
2729 | return -EIO; | ||
2730 | 3071 | ||
2731 | level &= 0x7; | 3072 | if (brightness_mode & 1) { |
3073 | if (!acpi_ec_read(brightness_offset, &lec)) | ||
3074 | return -EIO; | ||
3075 | lec &= 7; | ||
3076 | level = lec; | ||
3077 | }; | ||
3078 | if (brightness_mode & 2) { | ||
3079 | lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS) | ||
3080 | & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) | ||
3081 | >> TP_NVRAM_POS_LEVEL_BRIGHTNESS; | ||
3082 | level = lcmos; | ||
3083 | } | ||
3084 | |||
3085 | if (brightness_mode == 3 && lec != lcmos) { | ||
3086 | printk(IBM_ERR | ||
3087 | "CMOS NVRAM (%u) and EC (%u) do not agree " | ||
3088 | "on display brightness level\n", | ||
3089 | (unsigned int) lcmos, | ||
3090 | (unsigned int) lec); | ||
3091 | return -EIO; | ||
3092 | } | ||
2732 | 3093 | ||
2733 | return level; | 3094 | return level; |
2734 | } | 3095 | } |
2735 | 3096 | ||
2736 | static int brightness_set(int value) | 3097 | static int brightness_set(int value) |
2737 | { | 3098 | { |
2738 | int cmos_cmd, inc, i; | 3099 | int cmos_cmd, inc, i, res; |
2739 | int current_value = brightness_get(NULL); | 3100 | int current_value; |
3101 | |||
3102 | if (value > 7) | ||
3103 | return -EINVAL; | ||
2740 | 3104 | ||
2741 | value &= 7; | 3105 | res = mutex_lock_interruptible(&brightness_mutex); |
3106 | if (res < 0) | ||
3107 | return res; | ||
3108 | |||
3109 | current_value = brightness_get(NULL); | ||
3110 | if (current_value < 0) { | ||
3111 | res = current_value; | ||
3112 | goto errout; | ||
3113 | } | ||
2742 | 3114 | ||
2743 | cmos_cmd = value > current_value ? TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN; | 3115 | cmos_cmd = value > current_value ? |
3116 | TP_CMOS_BRIGHTNESS_UP : | ||
3117 | TP_CMOS_BRIGHTNESS_DOWN; | ||
2744 | inc = value > current_value ? 1 : -1; | 3118 | inc = value > current_value ? 1 : -1; |
3119 | |||
3120 | res = 0; | ||
2745 | for (i = current_value; i != value; i += inc) { | 3121 | for (i = current_value; i != value; i += inc) { |
2746 | if (issue_thinkpad_cmos_command(cmos_cmd)) | 3122 | if ((brightness_mode & 2) && |
2747 | return -EIO; | 3123 | issue_thinkpad_cmos_command(cmos_cmd)) { |
2748 | if (!acpi_ec_write(brightness_offset, i + inc)) | 3124 | res = -EIO; |
2749 | return -EIO; | 3125 | goto errout; |
3126 | } | ||
3127 | if ((brightness_mode & 1) && | ||
3128 | !acpi_ec_write(brightness_offset, i + inc)) { | ||
3129 | res = -EIO; | ||
3130 | goto errout;; | ||
3131 | } | ||
2750 | } | 3132 | } |
2751 | 3133 | ||
2752 | return 0; | 3134 | errout: |
3135 | mutex_unlock(&brightness_mutex); | ||
3136 | return res; | ||
2753 | } | 3137 | } |
2754 | 3138 | ||
2755 | static int brightness_read(char *p) | 3139 | static int brightness_read(char *p) |
@@ -3273,20 +3657,19 @@ static int __init fan_init(struct ibm_init_struct *iibm) | |||
3273 | * Enable for TP-1Y (T43), TP-78 (R51e), | 3657 | * Enable for TP-1Y (T43), TP-78 (R51e), |
3274 | * TP-76 (R52), TP-70 (T43, R52), which are known | 3658 | * TP-76 (R52), TP-70 (T43, R52), which are known |
3275 | * to be buggy. */ | 3659 | * to be buggy. */ |
3276 | if (fan_control_initial_status == 0x07 && | 3660 | if (fan_control_initial_status == 0x07) { |
3277 | ibm_thinkpad_ec_found && | 3661 | switch (thinkpad_id.ec_model) { |
3278 | ((ibm_thinkpad_ec_found[0] == '1' && | 3662 | case 0x5931: /* TP-1Y */ |
3279 | ibm_thinkpad_ec_found[1] == 'Y') || | 3663 | case 0x3837: /* TP-78 */ |
3280 | (ibm_thinkpad_ec_found[0] == '7' && | 3664 | case 0x3637: /* TP-76 */ |
3281 | (ibm_thinkpad_ec_found[1] == '6' || | 3665 | case 0x3037: /* TP-70 */ |
3282 | ibm_thinkpad_ec_found[1] == '8' || | 3666 | printk(IBM_NOTICE |
3283 | ibm_thinkpad_ec_found[1] == '0')) | 3667 | "fan_init: initial fan status is " |
3284 | )) { | 3668 | "unknown, assuming it is in auto " |
3285 | printk(IBM_NOTICE | 3669 | "mode\n"); |
3286 | "fan_init: initial fan status is " | 3670 | tp_features.fan_ctrl_status_undef = 1; |
3287 | "unknown, assuming it is in auto " | 3671 | ;; |
3288 | "mode\n"); | 3672 | } |
3289 | tp_features.fan_ctrl_status_undef = 1; | ||
3290 | } | 3673 | } |
3291 | } else { | 3674 | } else { |
3292 | printk(IBM_ERR | 3675 | printk(IBM_ERR |
@@ -3474,7 +3857,7 @@ static void fan_watchdog_fire(struct work_struct *ignored) | |||
3474 | 3857 | ||
3475 | static void fan_watchdog_reset(void) | 3858 | static void fan_watchdog_reset(void) |
3476 | { | 3859 | { |
3477 | static int fan_watchdog_active = 0; | 3860 | static int fan_watchdog_active; |
3478 | 3861 | ||
3479 | if (fan_control_access_mode == TPACPI_FAN_WR_NONE) | 3862 | if (fan_control_access_mode == TPACPI_FAN_WR_NONE) |
3480 | return; | 3863 | return; |
@@ -3877,7 +4260,7 @@ static struct ibm_struct fan_driver_data = { | |||
3877 | ****************************************************************************/ | 4260 | ****************************************************************************/ |
3878 | 4261 | ||
3879 | /* /proc support */ | 4262 | /* /proc support */ |
3880 | static struct proc_dir_entry *proc_dir = NULL; | 4263 | static struct proc_dir_entry *proc_dir; |
3881 | 4264 | ||
3882 | /* Subdriver registry */ | 4265 | /* Subdriver registry */ |
3883 | static LIST_HEAD(tpacpi_all_drivers); | 4266 | static LIST_HEAD(tpacpi_all_drivers); |
@@ -4020,13 +4403,30 @@ static void ibm_exit(struct ibm_struct *ibm) | |||
4020 | 4403 | ||
4021 | /* Probing */ | 4404 | /* Probing */ |
4022 | 4405 | ||
4023 | static char *ibm_thinkpad_ec_found = NULL; | 4406 | static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp) |
4024 | |||
4025 | static char* __init check_dmi_for_ec(void) | ||
4026 | { | 4407 | { |
4027 | struct dmi_device *dev = NULL; | 4408 | struct dmi_device *dev = NULL; |
4028 | char ec_fw_string[18]; | 4409 | char ec_fw_string[18]; |
4029 | 4410 | ||
4411 | if (!tp) | ||
4412 | return; | ||
4413 | |||
4414 | memset(tp, 0, sizeof(*tp)); | ||
4415 | |||
4416 | if (dmi_name_in_vendors("IBM")) | ||
4417 | tp->vendor = PCI_VENDOR_ID_IBM; | ||
4418 | else if (dmi_name_in_vendors("LENOVO")) | ||
4419 | tp->vendor = PCI_VENDOR_ID_LENOVO; | ||
4420 | else | ||
4421 | return; | ||
4422 | |||
4423 | tp->bios_version_str = kstrdup(dmi_get_system_info(DMI_BIOS_VERSION), | ||
4424 | GFP_KERNEL); | ||
4425 | if (!tp->bios_version_str) | ||
4426 | return; | ||
4427 | tp->bios_model = tp->bios_version_str[0] | ||
4428 | | (tp->bios_version_str[1] << 8); | ||
4429 | |||
4030 | /* | 4430 | /* |
4031 | * ThinkPad T23 or newer, A31 or newer, R50e or newer, | 4431 | * ThinkPad T23 or newer, A31 or newer, R50e or newer, |
4032 | * X32 or newer, all Z series; Some models must have an | 4432 | * X32 or newer, all Z series; Some models must have an |
@@ -4040,10 +4440,20 @@ static char* __init check_dmi_for_ec(void) | |||
4040 | ec_fw_string) == 1) { | 4440 | ec_fw_string) == 1) { |
4041 | ec_fw_string[sizeof(ec_fw_string) - 1] = 0; | 4441 | ec_fw_string[sizeof(ec_fw_string) - 1] = 0; |
4042 | ec_fw_string[strcspn(ec_fw_string, " ]")] = 0; | 4442 | ec_fw_string[strcspn(ec_fw_string, " ]")] = 0; |
4043 | return kstrdup(ec_fw_string, GFP_KERNEL); | 4443 | |
4444 | tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL); | ||
4445 | tp->ec_model = ec_fw_string[0] | ||
4446 | | (ec_fw_string[1] << 8); | ||
4447 | break; | ||
4044 | } | 4448 | } |
4045 | } | 4449 | } |
4046 | return NULL; | 4450 | |
4451 | tp->model_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_VERSION), | ||
4452 | GFP_KERNEL); | ||
4453 | if (strnicmp(tp->model_str, "ThinkPad", 8) != 0) { | ||
4454 | kfree(tp->model_str); | ||
4455 | tp->model_str = NULL; | ||
4456 | } | ||
4047 | } | 4457 | } |
4048 | 4458 | ||
4049 | static int __init probe_for_thinkpad(void) | 4459 | static int __init probe_for_thinkpad(void) |
@@ -4057,7 +4467,7 @@ static int __init probe_for_thinkpad(void) | |||
4057 | * Non-ancient models have better DMI tagging, but very old models | 4467 | * Non-ancient models have better DMI tagging, but very old models |
4058 | * don't. | 4468 | * don't. |
4059 | */ | 4469 | */ |
4060 | is_thinkpad = dmi_name_in_vendors("ThinkPad"); | 4470 | is_thinkpad = (thinkpad_id.model_str != NULL); |
4061 | 4471 | ||
4062 | /* ec is required because many other handles are relative to it */ | 4472 | /* ec is required because many other handles are relative to it */ |
4063 | IBM_ACPIHANDLE_INIT(ec); | 4473 | IBM_ACPIHANDLE_INIT(ec); |
@@ -4073,7 +4483,7 @@ static int __init probe_for_thinkpad(void) | |||
4073 | * false positives a damn great deal | 4483 | * false positives a damn great deal |
4074 | */ | 4484 | */ |
4075 | if (!is_thinkpad) | 4485 | if (!is_thinkpad) |
4076 | is_thinkpad = dmi_name_in_vendors("IBM"); | 4486 | is_thinkpad = (thinkpad_id.vendor == PCI_VENDOR_ID_IBM); |
4077 | 4487 | ||
4078 | if (!is_thinkpad && !force_load) | 4488 | if (!is_thinkpad && !force_load) |
4079 | return -ENODEV; | 4489 | return -ENODEV; |
@@ -4185,10 +4595,13 @@ static u32 dbg_level; | |||
4185 | module_param_named(debug, dbg_level, uint, 0); | 4595 | module_param_named(debug, dbg_level, uint, 0); |
4186 | 4596 | ||
4187 | static int force_load; | 4597 | static int force_load; |
4188 | module_param(force_load, int, 0); | 4598 | module_param(force_load, bool, 0); |
4189 | 4599 | ||
4190 | static int fan_control_allowed; | 4600 | static int fan_control_allowed; |
4191 | module_param_named(fan_control, fan_control_allowed, int, 0); | 4601 | module_param_named(fan_control, fan_control_allowed, bool, 0); |
4602 | |||
4603 | static int brightness_mode; | ||
4604 | module_param_named(brightness_mode, brightness_mode, int, 0); | ||
4192 | 4605 | ||
4193 | #define IBM_PARAM(feature) \ | 4606 | #define IBM_PARAM(feature) \ |
4194 | module_param_call(feature, set_ibm_param, NULL, NULL, 0) | 4607 | module_param_call(feature, set_ibm_param, NULL, NULL, 0) |
@@ -4216,12 +4629,16 @@ static int __init thinkpad_acpi_module_init(void) | |||
4216 | int ret, i; | 4629 | int ret, i; |
4217 | 4630 | ||
4218 | /* Driver-level probe */ | 4631 | /* Driver-level probe */ |
4632 | |||
4633 | get_thinkpad_model_data(&thinkpad_id); | ||
4219 | ret = probe_for_thinkpad(); | 4634 | ret = probe_for_thinkpad(); |
4220 | if (ret) | 4635 | if (ret) { |
4636 | thinkpad_acpi_module_exit(); | ||
4221 | return ret; | 4637 | return ret; |
4638 | } | ||
4222 | 4639 | ||
4223 | /* Driver initialization */ | 4640 | /* Driver initialization */ |
4224 | ibm_thinkpad_ec_found = check_dmi_for_ec(); | 4641 | |
4225 | IBM_ACPIHANDLE_INIT(ecrd); | 4642 | IBM_ACPIHANDLE_INIT(ecrd); |
4226 | IBM_ACPIHANDLE_INIT(ecwr); | 4643 | IBM_ACPIHANDLE_INIT(ecwr); |
4227 | 4644 | ||
@@ -4265,6 +4682,22 @@ static int __init thinkpad_acpi_module_init(void) | |||
4265 | thinkpad_acpi_module_exit(); | 4682 | thinkpad_acpi_module_exit(); |
4266 | return ret; | 4683 | return ret; |
4267 | } | 4684 | } |
4685 | tpacpi_inputdev = input_allocate_device(); | ||
4686 | if (!tpacpi_inputdev) { | ||
4687 | printk(IBM_ERR "unable to allocate input device\n"); | ||
4688 | thinkpad_acpi_module_exit(); | ||
4689 | return -ENOMEM; | ||
4690 | } else { | ||
4691 | /* Prepare input device, but don't register */ | ||
4692 | tpacpi_inputdev->name = "ThinkPad Extra Buttons"; | ||
4693 | tpacpi_inputdev->phys = IBM_DRVR_NAME "/input0"; | ||
4694 | tpacpi_inputdev->id.bustype = BUS_HOST; | ||
4695 | tpacpi_inputdev->id.vendor = (thinkpad_id.vendor) ? | ||
4696 | thinkpad_id.vendor : | ||
4697 | PCI_VENDOR_ID_IBM; | ||
4698 | tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT; | ||
4699 | tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION; | ||
4700 | } | ||
4268 | for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { | 4701 | for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { |
4269 | ret = ibm_init(&ibms_init[i]); | 4702 | ret = ibm_init(&ibms_init[i]); |
4270 | if (ret >= 0 && *ibms_init[i].param) | 4703 | if (ret >= 0 && *ibms_init[i].param) |
@@ -4274,6 +4707,14 @@ static int __init thinkpad_acpi_module_init(void) | |||
4274 | return ret; | 4707 | return ret; |
4275 | } | 4708 | } |
4276 | } | 4709 | } |
4710 | ret = input_register_device(tpacpi_inputdev); | ||
4711 | if (ret < 0) { | ||
4712 | printk(IBM_ERR "unable to register input device\n"); | ||
4713 | thinkpad_acpi_module_exit(); | ||
4714 | return ret; | ||
4715 | } else { | ||
4716 | tp_features.input_device_registered = 1; | ||
4717 | } | ||
4277 | 4718 | ||
4278 | return 0; | 4719 | return 0; |
4279 | } | 4720 | } |
@@ -4290,6 +4731,13 @@ static void thinkpad_acpi_module_exit(void) | |||
4290 | 4731 | ||
4291 | dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n"); | 4732 | dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n"); |
4292 | 4733 | ||
4734 | if (tpacpi_inputdev) { | ||
4735 | if (tp_features.input_device_registered) | ||
4736 | input_unregister_device(tpacpi_inputdev); | ||
4737 | else | ||
4738 | input_free_device(tpacpi_inputdev); | ||
4739 | } | ||
4740 | |||
4293 | if (tpacpi_hwmon) | 4741 | if (tpacpi_hwmon) |
4294 | hwmon_device_unregister(tpacpi_hwmon); | 4742 | hwmon_device_unregister(tpacpi_hwmon); |
4295 | 4743 | ||
@@ -4302,7 +4750,9 @@ static void thinkpad_acpi_module_exit(void) | |||
4302 | if (proc_dir) | 4750 | if (proc_dir) |
4303 | remove_proc_entry(IBM_PROC_DIR, acpi_root_dir); | 4751 | remove_proc_entry(IBM_PROC_DIR, acpi_root_dir); |
4304 | 4752 | ||
4305 | kfree(ibm_thinkpad_ec_found); | 4753 | kfree(thinkpad_id.bios_version_str); |
4754 | kfree(thinkpad_id.ec_version_str); | ||
4755 | kfree(thinkpad_id.model_str); | ||
4306 | } | 4756 | } |
4307 | 4757 | ||
4308 | module_init(thinkpad_acpi_module_init); | 4758 | module_init(thinkpad_acpi_module_init); |
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h index 72d62f2dab..b7a4a888cc 100644 --- a/drivers/misc/thinkpad_acpi.h +++ b/drivers/misc/thinkpad_acpi.h | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/list.h> | 32 | #include <linux/list.h> |
33 | #include <linux/mutex.h> | 33 | #include <linux/mutex.h> |
34 | 34 | ||
35 | #include <linux/nvram.h> | ||
35 | #include <linux/proc_fs.h> | 36 | #include <linux/proc_fs.h> |
36 | #include <linux/sysfs.h> | 37 | #include <linux/sysfs.h> |
37 | #include <linux/backlight.h> | 38 | #include <linux/backlight.h> |
@@ -39,6 +40,7 @@ | |||
39 | #include <linux/platform_device.h> | 40 | #include <linux/platform_device.h> |
40 | #include <linux/hwmon.h> | 41 | #include <linux/hwmon.h> |
41 | #include <linux/hwmon-sysfs.h> | 42 | #include <linux/hwmon-sysfs.h> |
43 | #include <linux/input.h> | ||
42 | #include <asm/uaccess.h> | 44 | #include <asm/uaccess.h> |
43 | 45 | ||
44 | #include <linux/dmi.h> | 46 | #include <linux/dmi.h> |
@@ -48,6 +50,7 @@ | |||
48 | #include <acpi/acpi_drivers.h> | 50 | #include <acpi/acpi_drivers.h> |
49 | #include <acpi/acnamesp.h> | 51 | #include <acpi/acnamesp.h> |
50 | 52 | ||
53 | #include <linux/pci_ids.h> | ||
51 | 54 | ||
52 | /**************************************************************************** | 55 | /**************************************************************************** |
53 | * Main driver | 56 | * Main driver |
@@ -78,6 +81,11 @@ | |||
78 | #define TP_CMOS_BRIGHTNESS_UP 4 | 81 | #define TP_CMOS_BRIGHTNESS_UP 4 |
79 | #define TP_CMOS_BRIGHTNESS_DOWN 5 | 82 | #define TP_CMOS_BRIGHTNESS_DOWN 5 |
80 | 83 | ||
84 | /* ThinkPad CMOS NVRAM constants */ | ||
85 | #define TP_NVRAM_ADDR_BRIGHTNESS 0x5e | ||
86 | #define TP_NVRAM_MASK_LEVEL_BRIGHTNESS 0x07 | ||
87 | #define TP_NVRAM_POS_LEVEL_BRIGHTNESS 0 | ||
88 | |||
81 | #define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off") | 89 | #define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off") |
82 | #define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") | 90 | #define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") |
83 | #define strlencmp(a,b) (strncmp((a), (b), strlen(b))) | 91 | #define strlencmp(a,b) (strncmp((a), (b), strlen(b))) |
@@ -98,9 +106,13 @@ static const char *str_supported(int is_supported); | |||
98 | #define vdbg_printk(a_dbg_level, format, arg...) | 106 | #define vdbg_printk(a_dbg_level, format, arg...) |
99 | #endif | 107 | #endif |
100 | 108 | ||
109 | /* Input IDs */ | ||
110 | #define TPACPI_HKEY_INPUT_VENDOR PCI_VENDOR_ID_IBM | ||
111 | #define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */ | ||
112 | #define TPACPI_HKEY_INPUT_VERSION 0x4101 | ||
113 | |||
101 | /* ACPI HIDs */ | 114 | /* ACPI HIDs */ |
102 | #define IBM_HKEY_HID "IBM0068" | 115 | #define IBM_HKEY_HID "IBM0068" |
103 | #define IBM_PCI_HID "PNP0A03" | ||
104 | 116 | ||
105 | /* ACPI helpers */ | 117 | /* ACPI helpers */ |
106 | static int __must_check acpi_evalf(acpi_handle handle, | 118 | static int __must_check acpi_evalf(acpi_handle handle, |
@@ -161,6 +173,7 @@ static int parse_strtoul(const char *buf, unsigned long max, | |||
161 | static struct platform_device *tpacpi_pdev; | 173 | static struct platform_device *tpacpi_pdev; |
162 | static struct class_device *tpacpi_hwmon; | 174 | static struct class_device *tpacpi_hwmon; |
163 | static struct platform_driver tpacpi_pdriver; | 175 | static struct platform_driver tpacpi_pdriver; |
176 | static struct input_dev *tpacpi_inputdev; | ||
164 | static int tpacpi_create_driver_attributes(struct device_driver *drv); | 177 | static int tpacpi_create_driver_attributes(struct device_driver *drv); |
165 | static void tpacpi_remove_driver_attributes(struct device_driver *drv); | 178 | static void tpacpi_remove_driver_attributes(struct device_driver *drv); |
166 | 179 | ||
@@ -168,9 +181,7 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv); | |||
168 | static int experimental; | 181 | static int experimental; |
169 | static u32 dbg_level; | 182 | static u32 dbg_level; |
170 | static int force_load; | 183 | static int force_load; |
171 | static char *ibm_thinkpad_ec_found; | ||
172 | 184 | ||
173 | static char* check_dmi_for_ec(void); | ||
174 | static int thinkpad_acpi_module_init(void); | 185 | static int thinkpad_acpi_module_init(void); |
175 | static void thinkpad_acpi_module_exit(void); | 186 | static void thinkpad_acpi_module_exit(void); |
176 | 187 | ||
@@ -197,6 +208,7 @@ struct ibm_struct { | |||
197 | int (*read) (char *); | 208 | int (*read) (char *); |
198 | int (*write) (char *); | 209 | int (*write) (char *); |
199 | void (*exit) (void); | 210 | void (*exit) (void); |
211 | void (*resume) (void); | ||
200 | 212 | ||
201 | struct list_head all_drivers; | 213 | struct list_head all_drivers; |
202 | 214 | ||
@@ -228,12 +240,29 @@ static struct { | |||
228 | u16 bluetooth:1; | 240 | u16 bluetooth:1; |
229 | u16 hotkey:1; | 241 | u16 hotkey:1; |
230 | u16 hotkey_mask:1; | 242 | u16 hotkey_mask:1; |
243 | u16 hotkey_wlsw:1; | ||
231 | u16 light:1; | 244 | u16 light:1; |
232 | u16 light_status:1; | 245 | u16 light_status:1; |
233 | u16 wan:1; | 246 | u16 wan:1; |
234 | u16 fan_ctrl_status_undef:1; | 247 | u16 fan_ctrl_status_undef:1; |
248 | u16 input_device_registered:1; | ||
235 | } tp_features; | 249 | } tp_features; |
236 | 250 | ||
251 | struct thinkpad_id_data { | ||
252 | unsigned int vendor; /* ThinkPad vendor: | ||
253 | * PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */ | ||
254 | |||
255 | char *bios_version_str; /* Something like 1ZET51WW (1.03z) */ | ||
256 | char *ec_version_str; /* Something like 1ZHT51WW-1.04a */ | ||
257 | |||
258 | u16 bios_model; /* Big Endian, TP-1Y = 0x5931, 0 = unknown */ | ||
259 | u16 ec_model; | ||
260 | |||
261 | char *model_str; | ||
262 | }; | ||
263 | |||
264 | static struct thinkpad_id_data thinkpad_id; | ||
265 | |||
237 | static struct list_head tpacpi_all_drivers; | 266 | static struct list_head tpacpi_all_drivers; |
238 | 267 | ||
239 | static struct ibm_init_struct ibms_init[]; | 268 | static struct ibm_init_struct ibms_init[]; |
@@ -300,6 +329,7 @@ static int bluetooth_write(char *buf); | |||
300 | 329 | ||
301 | static struct backlight_device *ibm_backlight_device; | 330 | static struct backlight_device *ibm_backlight_device; |
302 | static int brightness_offset = 0x31; | 331 | static int brightness_offset = 0x31; |
332 | static int brightness_mode; | ||
303 | 333 | ||
304 | static int brightness_init(struct ibm_init_struct *iibm); | 334 | static int brightness_init(struct ibm_init_struct *iibm); |
305 | static void brightness_exit(void); | 335 | static void brightness_exit(void); |
@@ -415,14 +445,14 @@ static int fan_write_cmd_watchdog(const char *cmd, int *rc); | |||
415 | */ | 445 | */ |
416 | 446 | ||
417 | static int hotkey_orig_status; | 447 | static int hotkey_orig_status; |
418 | static int hotkey_orig_mask; | 448 | static u32 hotkey_orig_mask; |
419 | 449 | ||
420 | static struct mutex hotkey_mutex; | 450 | static struct mutex hotkey_mutex; |
421 | 451 | ||
422 | static int hotkey_init(struct ibm_init_struct *iibm); | 452 | static int hotkey_init(struct ibm_init_struct *iibm); |
423 | static void hotkey_exit(void); | 453 | static void hotkey_exit(void); |
424 | static int hotkey_get(int *status, int *mask); | 454 | static int hotkey_get(int *status, u32 *mask); |
425 | static int hotkey_set(int status, int mask); | 455 | static int hotkey_set(int status, u32 mask); |
426 | static void hotkey_notify(struct ibm_struct *ibm, u32 event); | 456 | static void hotkey_notify(struct ibm_struct *ibm, u32 event); |
427 | static int hotkey_read(char *p); | 457 | static int hotkey_read(char *p); |
428 | static int hotkey_write(char *buf); | 458 | static int hotkey_write(char *buf); |
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 3073f67958..f8a602caab 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig | |||
@@ -5,6 +5,7 @@ | |||
5 | 5 | ||
6 | menuconfig NETDEVICES | 6 | menuconfig NETDEVICES |
7 | default y if UML | 7 | default y if UML |
8 | depends on NET | ||
8 | bool "Network device support" | 9 | bool "Network device support" |
9 | ---help--- | 10 | ---help--- |
10 | You can say N here if you don't intend to connect your Linux box to | 11 | You can say N here if you don't intend to connect your Linux box to |
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index 829da9a1d1..2098d0af8f 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig | |||
@@ -155,6 +155,15 @@ config KINGSUN_DONGLE | |||
155 | To compile it as a module, choose M here: the module will be called | 155 | To compile it as a module, choose M here: the module will be called |
156 | kingsun-sir. | 156 | kingsun-sir. |
157 | 157 | ||
158 | config EP7211_DONGLE | ||
159 | tristate "EP7211 I/R support" | ||
160 | depends on IRTTY_SIR && ARCH_EP7211 && IRDA && EXPERIMENTAL | ||
161 | help | ||
162 | Say Y here if you want to build support for the Cirrus logic | ||
163 | EP7211 chipset's infrared module. | ||
164 | |||
165 | |||
166 | |||
158 | comment "Old SIR device drivers" | 167 | comment "Old SIR device drivers" |
159 | 168 | ||
160 | config IRPORT_SIR | 169 | config IRPORT_SIR |
@@ -355,7 +364,7 @@ config WINBOND_FIR | |||
355 | 364 | ||
356 | config TOSHIBA_FIR | 365 | config TOSHIBA_FIR |
357 | tristate "Toshiba Type-O IR Port" | 366 | tristate "Toshiba Type-O IR Port" |
358 | depends on IRDA && PCI && !64BIT | 367 | depends on IRDA && PCI && !64BIT && VIRT_TO_BUS |
359 | help | 368 | help |
360 | Say Y here if you want to build support for the Toshiba Type-O IR | 369 | Say Y here if you want to build support for the Toshiba Type-O IR |
361 | and Donau oboe chipsets. These chipsets are used by the Toshiba | 370 | and Donau oboe chipsets. These chipsets are used by the Toshiba |
diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile index 233a2f9237..2808ef5c7b 100644 --- a/drivers/net/irda/Makefile +++ b/drivers/net/irda/Makefile | |||
@@ -45,6 +45,7 @@ obj-$(CONFIG_MCP2120_DONGLE) += mcp2120-sir.o | |||
45 | obj-$(CONFIG_ACT200L_DONGLE) += act200l-sir.o | 45 | obj-$(CONFIG_ACT200L_DONGLE) += act200l-sir.o |
46 | obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o | 46 | obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o |
47 | obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o | 47 | obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o |
48 | obj-$(CONFIG_EP7211_DONGLE) += ep7211-sir.o | ||
48 | obj-$(CONFIG_KINGSUN_DONGLE) += kingsun-sir.o | 49 | obj-$(CONFIG_KINGSUN_DONGLE) += kingsun-sir.o |
49 | 50 | ||
50 | # The SIR helper module | 51 | # The SIR helper module |
diff --git a/drivers/net/irda/ep7211-sir.c b/drivers/net/irda/ep7211-sir.c new file mode 100644 index 0000000000..831572429b --- /dev/null +++ b/drivers/net/irda/ep7211-sir.c | |||
@@ -0,0 +1,89 @@ | |||
1 | /* | ||
2 | * IR port driver for the Cirrus Logic EP7211 processor. | ||
3 | * | ||
4 | * Copyright 2001, Blue Mug Inc. All rights reserved. | ||
5 | * Copyright 2007, Samuel Ortiz <samuel@sortiz.org> | ||
6 | */ | ||
7 | #include <linux/module.h> | ||
8 | #include <linux/delay.h> | ||
9 | #include <linux/tty.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/spinlock.h> | ||
12 | |||
13 | #include <net/irda/irda.h> | ||
14 | #include <net/irda/irda_device.h> | ||
15 | |||
16 | #include <asm/io.h> | ||
17 | #include <asm/hardware.h> | ||
18 | |||
19 | #include "sir-dev.h" | ||
20 | |||
21 | #define MIN_DELAY 25 /* 15 us, but wait a little more to be sure */ | ||
22 | #define MAX_DELAY 10000 /* 1 ms */ | ||
23 | |||
24 | static int ep7211_open(struct sir_dev *dev); | ||
25 | static int ep7211_close(struct sir_dev *dev); | ||
26 | static int ep7211_change_speed(struct sir_dev *dev, unsigned speed); | ||
27 | static int ep7211_reset(struct sir_dev *dev); | ||
28 | |||
29 | static struct dongle_driver ep7211 = { | ||
30 | .owner = THIS_MODULE, | ||
31 | .driver_name = "EP7211 IR driver", | ||
32 | .type = IRDA_EP7211_DONGLE, | ||
33 | .open = ep7211_open, | ||
34 | .close = ep7211_close, | ||
35 | .reset = ep7211_reset, | ||
36 | .set_speed = ep7211_change_speed, | ||
37 | }; | ||
38 | |||
39 | static int __init ep7211_sir_init(void) | ||
40 | { | ||
41 | return irda_register_dongle(&ep7211); | ||
42 | } | ||
43 | |||
44 | static void __exit ep7211_sir_cleanup(void) | ||
45 | { | ||
46 | irda_unregister_dongle(&ep7211); | ||
47 | } | ||
48 | |||
49 | static int ep7211_open(struct sir_dev *dev) | ||
50 | { | ||
51 | unsigned int syscon; | ||
52 | |||
53 | /* Turn on the SIR encoder. */ | ||
54 | syscon = clps_readl(SYSCON1); | ||
55 | syscon |= SYSCON1_SIREN; | ||
56 | clps_writel(syscon, SYSCON1); | ||
57 | |||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static int ep7211_close(struct sir_dev *dev) | ||
62 | { | ||
63 | unsigned int syscon; | ||
64 | |||
65 | /* Turn off the SIR encoder. */ | ||
66 | syscon = clps_readl(SYSCON1); | ||
67 | syscon &= ~SYSCON1_SIREN; | ||
68 | clps_writel(syscon, SYSCON1); | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static int ep7211_change_speed(struct sir_dev *dev, unsigned speed) | ||
74 | { | ||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | static int ep7211_reset(struct sir_dev *dev) | ||
79 | { | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | MODULE_AUTHOR("Samuel Ortiz <samuel@sortiz.org>"); | ||
84 | MODULE_DESCRIPTION("EP7211 IR dongle driver"); | ||
85 | MODULE_LICENSE("GPL"); | ||
86 | MODULE_ALIAS("irda-dongle-13"); /* IRDA_EP7211_DONGLE */ | ||
87 | |||
88 | module_init(ep7211_sir_init); | ||
89 | module_exit(ep7211_sir_cleanup); | ||
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 35f34665e3..9d8d40d5c8 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
@@ -38,6 +38,9 @@ config RTC_HCTOSYS_DEVICE | |||
38 | clock, usually rtc0. Initialization is done when the system | 38 | clock, usually rtc0. Initialization is done when the system |
39 | starts up, and when it resumes from a low power state. | 39 | starts up, and when it resumes from a low power state. |
40 | 40 | ||
41 | The driver for this RTC device must be loaded before late_initcall | ||
42 | functions run, so it must usually be statically linked. | ||
43 | |||
41 | This clock should be battery-backed, so that it reads the correct | 44 | This clock should be battery-backed, so that it reads the correct |
42 | time when the system boots from a power-off state. Otherwise, your | 45 | time when the system boots from a power-off state. Otherwise, your |
43 | system will need an external clock source (like an NTP server). | 46 | system will need an external clock source (like an NTP server). |
@@ -305,6 +308,16 @@ config RTC_DRV_DS1553 | |||
305 | This driver can also be built as a module. If so, the module | 308 | This driver can also be built as a module. If so, the module |
306 | will be called rtc-ds1553. | 309 | will be called rtc-ds1553. |
307 | 310 | ||
311 | config RTC_DRV_STK17TA8 | ||
312 | tristate "Simtek STK17TA8" | ||
313 | depends on RTC_CLASS | ||
314 | help | ||
315 | If you say yes here you get support for the | ||
316 | Simtek STK17TA8 timekeeping chip. | ||
317 | |||
318 | This driver can also be built as a module. If so, the module | ||
319 | will be called rtc-stk17ta8. | ||
320 | |||
308 | config RTC_DRV_DS1742 | 321 | config RTC_DRV_DS1742 |
309 | tristate "Dallas DS1742/1743" | 322 | tristate "Dallas DS1742/1743" |
310 | depends on RTC_CLASS | 323 | depends on RTC_CLASS |
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 3109af9a16..7ede9e7253 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile | |||
@@ -32,6 +32,7 @@ obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o | |||
32 | obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o | 32 | obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o |
33 | obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o | 33 | obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o |
34 | obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o | 34 | obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o |
35 | obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o | ||
35 | obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o | 36 | obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o |
36 | obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o | 37 | obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o |
37 | obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o | 38 | obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o |
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index f98a83a11a..46da571493 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c | |||
@@ -407,7 +407,7 @@ static __init int ds1553_init(void) | |||
407 | 407 | ||
408 | static __exit void ds1553_exit(void) | 408 | static __exit void ds1553_exit(void) |
409 | { | 409 | { |
410 | return platform_driver_unregister(&ds1553_rtc_driver); | 410 | platform_driver_unregister(&ds1553_rtc_driver); |
411 | } | 411 | } |
412 | 412 | ||
413 | module_init(ds1553_init); | 413 | module_init(ds1553_init); |
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index d1778ae8bc..b2e5481ba3 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c | |||
@@ -263,7 +263,7 @@ static __init int ds1742_init(void) | |||
263 | 263 | ||
264 | static __exit void ds1742_exit(void) | 264 | static __exit void ds1742_exit(void) |
265 | { | 265 | { |
266 | return platform_driver_unregister(&ds1742_rtc_driver); | 266 | platform_driver_unregister(&ds1742_rtc_driver); |
267 | } | 267 | } |
268 | 268 | ||
269 | module_init(ds1742_init); | 269 | module_init(ds1742_init); |
diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c index eee4ee5bb7..a1cd448639 100644 --- a/drivers/rtc/rtc-max6900.c +++ b/drivers/rtc/rtc-max6900.c | |||
@@ -31,17 +31,24 @@ | |||
31 | #define MAX6900_REG_DW 5 /* day of week 1-7 */ | 31 | #define MAX6900_REG_DW 5 /* day of week 1-7 */ |
32 | #define MAX6900_REG_YR 6 /* year 00-99 */ | 32 | #define MAX6900_REG_YR 6 /* year 00-99 */ |
33 | #define MAX6900_REG_CT 7 /* control */ | 33 | #define MAX6900_REG_CT 7 /* control */ |
34 | #define MAX6900_REG_LEN 8 | 34 | /* register 8 is undocumented */ |
35 | #define MAX6900_REG_CENTURY 9 /* century */ | ||
36 | #define MAX6900_REG_LEN 10 | ||
37 | |||
38 | #define MAX6900_BURST_LEN 8 /* can burst r/w first 8 regs */ | ||
35 | 39 | ||
36 | #define MAX6900_REG_CT_WP (1 << 7) /* Write Protect */ | 40 | #define MAX6900_REG_CT_WP (1 << 7) /* Write Protect */ |
37 | 41 | ||
42 | |||
38 | /* | 43 | /* |
39 | * register read/write commands | 44 | * register read/write commands |
40 | */ | 45 | */ |
41 | #define MAX6900_REG_CONTROL_WRITE 0x8e | 46 | #define MAX6900_REG_CONTROL_WRITE 0x8e |
42 | #define MAX6900_REG_BURST_READ 0xbf | 47 | #define MAX6900_REG_CENTURY_WRITE 0x92 |
43 | #define MAX6900_REG_BURST_WRITE 0xbe | 48 | #define MAX6900_REG_CENTURY_READ 0x93 |
44 | #define MAX6900_REG_RESERVED_READ 0x96 | 49 | #define MAX6900_REG_RESERVED_READ 0x96 |
50 | #define MAX6900_REG_BURST_WRITE 0xbe | ||
51 | #define MAX6900_REG_BURST_READ 0xbf | ||
45 | 52 | ||
46 | #define MAX6900_IDLE_TIME_AFTER_WRITE 3 /* specification says 2.5 mS */ | 53 | #define MAX6900_IDLE_TIME_AFTER_WRITE 3 /* specification says 2.5 mS */ |
47 | 54 | ||
@@ -58,19 +65,32 @@ static int max6900_probe(struct i2c_adapter *adapter, int addr, int kind); | |||
58 | 65 | ||
59 | static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf) | 66 | static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf) |
60 | { | 67 | { |
61 | u8 reg_addr[1] = { MAX6900_REG_BURST_READ }; | 68 | u8 reg_burst_read[1] = { MAX6900_REG_BURST_READ }; |
62 | struct i2c_msg msgs[2] = { | 69 | u8 reg_century_read[1] = { MAX6900_REG_CENTURY_READ }; |
70 | struct i2c_msg msgs[4] = { | ||
63 | { | 71 | { |
64 | .addr = client->addr, | 72 | .addr = client->addr, |
65 | .flags = 0, /* write */ | 73 | .flags = 0, /* write */ |
66 | .len = sizeof(reg_addr), | 74 | .len = sizeof(reg_burst_read), |
67 | .buf = reg_addr | 75 | .buf = reg_burst_read |
68 | }, | 76 | }, |
69 | { | 77 | { |
70 | .addr = client->addr, | 78 | .addr = client->addr, |
71 | .flags = I2C_M_RD, | 79 | .flags = I2C_M_RD, |
72 | .len = MAX6900_REG_LEN, | 80 | .len = MAX6900_BURST_LEN, |
73 | .buf = buf | 81 | .buf = buf |
82 | }, | ||
83 | { | ||
84 | .addr = client->addr, | ||
85 | .flags = 0, /* write */ | ||
86 | .len = sizeof(reg_century_read), | ||
87 | .buf = reg_century_read | ||
88 | }, | ||
89 | { | ||
90 | .addr = client->addr, | ||
91 | .flags = I2C_M_RD, | ||
92 | .len = sizeof(buf[MAX6900_REG_CENTURY]), | ||
93 | .buf = &buf[MAX6900_REG_CENTURY] | ||
74 | } | 94 | } |
75 | }; | 95 | }; |
76 | int rc; | 96 | int rc; |
@@ -86,33 +106,58 @@ static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf) | |||
86 | 106 | ||
87 | static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf) | 107 | static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf) |
88 | { | 108 | { |
89 | u8 i2c_buf[MAX6900_REG_LEN + 1] = { MAX6900_REG_BURST_WRITE }; | 109 | u8 i2c_century_buf[1 + 1] = { MAX6900_REG_CENTURY_WRITE }; |
90 | struct i2c_msg msgs[1] = { | 110 | struct i2c_msg century_msgs[1] = { |
91 | { | 111 | { |
92 | .addr = client->addr, | 112 | .addr = client->addr, |
93 | .flags = 0, /* write */ | 113 | .flags = 0, /* write */ |
94 | .len = MAX6900_REG_LEN + 1, | 114 | .len = sizeof(i2c_century_buf), |
95 | .buf = i2c_buf | 115 | .buf = i2c_century_buf |
116 | } | ||
117 | }; | ||
118 | u8 i2c_burst_buf[MAX6900_BURST_LEN + 1] = { MAX6900_REG_BURST_WRITE }; | ||
119 | struct i2c_msg burst_msgs[1] = { | ||
120 | { | ||
121 | .addr = client->addr, | ||
122 | .flags = 0, /* write */ | ||
123 | .len = sizeof(i2c_burst_buf), | ||
124 | .buf = i2c_burst_buf | ||
96 | } | 125 | } |
97 | }; | 126 | }; |
98 | int rc; | 127 | int rc; |
99 | 128 | ||
100 | memcpy(&i2c_buf[1], buf, MAX6900_REG_LEN); | 129 | /* |
130 | * We have to make separate calls to i2c_transfer because of | ||
131 | * the need to delay after each write to the chip. Also, | ||
132 | * we write the century byte first, since we set the write-protect | ||
133 | * bit as part of the burst write. | ||
134 | */ | ||
135 | i2c_century_buf[1] = buf[MAX6900_REG_CENTURY]; | ||
136 | rc = i2c_transfer(client->adapter, century_msgs, | ||
137 | ARRAY_SIZE(century_msgs)); | ||
138 | if (rc != ARRAY_SIZE(century_msgs)) | ||
139 | goto write_failed; | ||
140 | msleep(MAX6900_IDLE_TIME_AFTER_WRITE); | ||
101 | 141 | ||
102 | rc = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); | 142 | memcpy(&i2c_burst_buf[1], buf, MAX6900_BURST_LEN); |
103 | if (rc != ARRAY_SIZE(msgs)) { | 143 | |
104 | dev_err(&client->dev, "%s: register write failed\n", | 144 | rc = i2c_transfer(client->adapter, burst_msgs, ARRAY_SIZE(burst_msgs)); |
105 | __FUNCTION__); | 145 | if (rc != ARRAY_SIZE(burst_msgs)) |
106 | return -EIO; | 146 | goto write_failed; |
107 | } | ||
108 | msleep(MAX6900_IDLE_TIME_AFTER_WRITE); | 147 | msleep(MAX6900_IDLE_TIME_AFTER_WRITE); |
148 | |||
109 | return 0; | 149 | return 0; |
150 | |||
151 | write_failed: | ||
152 | dev_err(&client->dev, "%s: register write failed\n", | ||
153 | __FUNCTION__); | ||
154 | return -EIO; | ||
110 | } | 155 | } |
111 | 156 | ||
112 | static int max6900_i2c_validate_client(struct i2c_client *client) | 157 | static int max6900_i2c_validate_client(struct i2c_client *client) |
113 | { | 158 | { |
114 | u8 regs[MAX6900_REG_LEN]; | 159 | u8 regs[MAX6900_REG_LEN]; |
115 | u8 zero_mask[MAX6900_REG_LEN] = { | 160 | u8 zero_mask[] = { |
116 | 0x80, /* seconds */ | 161 | 0x80, /* seconds */ |
117 | 0x80, /* minutes */ | 162 | 0x80, /* minutes */ |
118 | 0x40, /* hours */ | 163 | 0x40, /* hours */ |
@@ -134,7 +179,7 @@ static int max6900_i2c_validate_client(struct i2c_client *client) | |||
134 | if (rc < 0) | 179 | if (rc < 0) |
135 | return rc; | 180 | return rc; |
136 | 181 | ||
137 | for (i = 0; i < MAX6900_REG_LEN; ++i) { | 182 | for (i = 0; i < ARRAY_SIZE(zero_mask); ++i) { |
138 | if (regs[i] & zero_mask[i]) | 183 | if (regs[i] & zero_mask[i]) |
139 | return -ENODEV; | 184 | return -ENODEV; |
140 | } | 185 | } |
@@ -156,7 +201,8 @@ static int max6900_i2c_read_time(struct i2c_client *client, struct rtc_time *tm) | |||
156 | tm->tm_hour = BCD2BIN(regs[MAX6900_REG_HR] & 0x3f); | 201 | tm->tm_hour = BCD2BIN(regs[MAX6900_REG_HR] & 0x3f); |
157 | tm->tm_mday = BCD2BIN(regs[MAX6900_REG_DT]); | 202 | tm->tm_mday = BCD2BIN(regs[MAX6900_REG_DT]); |
158 | tm->tm_mon = BCD2BIN(regs[MAX6900_REG_MO]) - 1; | 203 | tm->tm_mon = BCD2BIN(regs[MAX6900_REG_MO]) - 1; |
159 | tm->tm_year = BCD2BIN(regs[MAX6900_REG_YR]) + 100; | 204 | tm->tm_year = BCD2BIN(regs[MAX6900_REG_YR]) + |
205 | BCD2BIN(regs[MAX6900_REG_CENTURY]) * 100 - 1900; | ||
160 | tm->tm_wday = BCD2BIN(regs[MAX6900_REG_DW]); | 206 | tm->tm_wday = BCD2BIN(regs[MAX6900_REG_DW]); |
161 | 207 | ||
162 | return 0; | 208 | return 0; |
@@ -189,9 +235,11 @@ static int max6900_i2c_set_time(struct i2c_client *client, | |||
189 | regs[MAX6900_REG_HR] = BIN2BCD(tm->tm_hour); | 235 | regs[MAX6900_REG_HR] = BIN2BCD(tm->tm_hour); |
190 | regs[MAX6900_REG_DT] = BIN2BCD(tm->tm_mday); | 236 | regs[MAX6900_REG_DT] = BIN2BCD(tm->tm_mday); |
191 | regs[MAX6900_REG_MO] = BIN2BCD(tm->tm_mon + 1); | 237 | regs[MAX6900_REG_MO] = BIN2BCD(tm->tm_mon + 1); |
192 | regs[MAX6900_REG_YR] = BIN2BCD(tm->tm_year - 100); | ||
193 | regs[MAX6900_REG_DW] = BIN2BCD(tm->tm_wday); | 238 | regs[MAX6900_REG_DW] = BIN2BCD(tm->tm_wday); |
194 | regs[MAX6900_REG_CT] = MAX6900_REG_CT_WP; /* set write protect */ | 239 | regs[MAX6900_REG_YR] = BIN2BCD(tm->tm_year % 100); |
240 | regs[MAX6900_REG_CENTURY] = BIN2BCD((tm->tm_year + 1900) / 100); | ||
241 | /* set write protect */ | ||
242 | regs[MAX6900_REG_CT] = MAX6900_REG_CT_WP; | ||
195 | 243 | ||
196 | rc = max6900_i2c_write_regs(client, regs); | 244 | rc = max6900_i2c_write_regs(client, regs); |
197 | if (rc < 0) | 245 | if (rc < 0) |
diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c new file mode 100644 index 0000000000..f10d3facec --- /dev/null +++ b/drivers/rtc/rtc-stk17ta8.c | |||
@@ -0,0 +1,420 @@ | |||
1 | /* | ||
2 | * A RTC driver for the Simtek STK17TA8 | ||
3 | * | ||
4 | * By Thomas Hommel <thomas.hommel@gefanuc.com> | ||
5 | * | ||
6 | * Based on the DS1553 driver from | ||
7 | * Atsushi Nemoto <anemo@mba.ocn.ne.jp> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/bcd.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/jiffies.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/rtc.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/io.h> | ||
23 | |||
24 | #define DRV_VERSION "0.1" | ||
25 | |||
26 | #define RTC_REG_SIZE 0x20000 | ||
27 | #define RTC_OFFSET 0x1fff0 | ||
28 | |||
29 | #define RTC_FLAGS (RTC_OFFSET + 0) | ||
30 | #define RTC_CENTURY (RTC_OFFSET + 1) | ||
31 | #define RTC_SECONDS_ALARM (RTC_OFFSET + 2) | ||
32 | #define RTC_MINUTES_ALARM (RTC_OFFSET + 3) | ||
33 | #define RTC_HOURS_ALARM (RTC_OFFSET + 4) | ||
34 | #define RTC_DATE_ALARM (RTC_OFFSET + 5) | ||
35 | #define RTC_INTERRUPTS (RTC_OFFSET + 6) | ||
36 | #define RTC_WATCHDOG (RTC_OFFSET + 7) | ||
37 | #define RTC_CALIBRATION (RTC_OFFSET + 8) | ||
38 | #define RTC_SECONDS (RTC_OFFSET + 9) | ||
39 | #define RTC_MINUTES (RTC_OFFSET + 10) | ||
40 | #define RTC_HOURS (RTC_OFFSET + 11) | ||
41 | #define RTC_DAY (RTC_OFFSET + 12) | ||
42 | #define RTC_DATE (RTC_OFFSET + 13) | ||
43 | #define RTC_MONTH (RTC_OFFSET + 14) | ||
44 | #define RTC_YEAR (RTC_OFFSET + 15) | ||
45 | |||
46 | #define RTC_SECONDS_MASK 0x7f | ||
47 | #define RTC_DAY_MASK 0x07 | ||
48 | #define RTC_CAL_MASK 0x3f | ||
49 | |||
50 | /* Bits in the Calibration register */ | ||
51 | #define RTC_STOP 0x80 | ||
52 | |||
53 | /* Bits in the Flags register */ | ||
54 | #define RTC_FLAGS_AF 0x40 | ||
55 | #define RTC_FLAGS_PF 0x20 | ||
56 | #define RTC_WRITE 0x02 | ||
57 | #define RTC_READ 0x01 | ||
58 | |||
59 | /* Bits in the Interrupts register */ | ||
60 | #define RTC_INTS_AIE 0x40 | ||
61 | |||
62 | struct rtc_plat_data { | ||
63 | struct rtc_device *rtc; | ||
64 | void __iomem *ioaddr; | ||
65 | unsigned long baseaddr; | ||
66 | unsigned long last_jiffies; | ||
67 | int irq; | ||
68 | unsigned int irqen; | ||
69 | int alrm_sec; | ||
70 | int alrm_min; | ||
71 | int alrm_hour; | ||
72 | int alrm_mday; | ||
73 | }; | ||
74 | |||
75 | static int stk17ta8_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
76 | { | ||
77 | struct platform_device *pdev = to_platform_device(dev); | ||
78 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
79 | void __iomem *ioaddr = pdata->ioaddr; | ||
80 | u8 flags; | ||
81 | |||
82 | flags = readb(pdata->ioaddr + RTC_FLAGS); | ||
83 | writeb(flags | RTC_WRITE, pdata->ioaddr + RTC_FLAGS); | ||
84 | |||
85 | writeb(BIN2BCD(tm->tm_year % 100), ioaddr + RTC_YEAR); | ||
86 | writeb(BIN2BCD(tm->tm_mon + 1), ioaddr + RTC_MONTH); | ||
87 | writeb(BIN2BCD(tm->tm_wday) & RTC_DAY_MASK, ioaddr + RTC_DAY); | ||
88 | writeb(BIN2BCD(tm->tm_mday), ioaddr + RTC_DATE); | ||
89 | writeb(BIN2BCD(tm->tm_hour), ioaddr + RTC_HOURS); | ||
90 | writeb(BIN2BCD(tm->tm_min), ioaddr + RTC_MINUTES); | ||
91 | writeb(BIN2BCD(tm->tm_sec) & RTC_SECONDS_MASK, ioaddr + RTC_SECONDS); | ||
92 | writeb(BIN2BCD((tm->tm_year + 1900) / 100), ioaddr + RTC_CENTURY); | ||
93 | |||
94 | writeb(flags & ~RTC_WRITE, pdata->ioaddr + RTC_FLAGS); | ||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | static int stk17ta8_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
99 | { | ||
100 | struct platform_device *pdev = to_platform_device(dev); | ||
101 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
102 | void __iomem *ioaddr = pdata->ioaddr; | ||
103 | unsigned int year, month, day, hour, minute, second, week; | ||
104 | unsigned int century; | ||
105 | u8 flags; | ||
106 | |||
107 | /* give enough time to update RTC in case of continuous read */ | ||
108 | if (pdata->last_jiffies == jiffies) | ||
109 | msleep(1); | ||
110 | pdata->last_jiffies = jiffies; | ||
111 | |||
112 | flags = readb(pdata->ioaddr + RTC_FLAGS); | ||
113 | writeb(flags | RTC_READ, ioaddr + RTC_FLAGS); | ||
114 | second = readb(ioaddr + RTC_SECONDS) & RTC_SECONDS_MASK; | ||
115 | minute = readb(ioaddr + RTC_MINUTES); | ||
116 | hour = readb(ioaddr + RTC_HOURS); | ||
117 | day = readb(ioaddr + RTC_DATE); | ||
118 | week = readb(ioaddr + RTC_DAY) & RTC_DAY_MASK; | ||
119 | month = readb(ioaddr + RTC_MONTH); | ||
120 | year = readb(ioaddr + RTC_YEAR); | ||
121 | century = readb(ioaddr + RTC_CENTURY); | ||
122 | writeb(flags & ~RTC_READ, ioaddr + RTC_FLAGS); | ||
123 | tm->tm_sec = BCD2BIN(second); | ||
124 | tm->tm_min = BCD2BIN(minute); | ||
125 | tm->tm_hour = BCD2BIN(hour); | ||
126 | tm->tm_mday = BCD2BIN(day); | ||
127 | tm->tm_wday = BCD2BIN(week); | ||
128 | tm->tm_mon = BCD2BIN(month) - 1; | ||
129 | /* year is 1900 + tm->tm_year */ | ||
130 | tm->tm_year = BCD2BIN(year) + BCD2BIN(century) * 100 - 1900; | ||
131 | |||
132 | if (rtc_valid_tm(tm) < 0) { | ||
133 | dev_err(dev, "retrieved date/time is not valid.\n"); | ||
134 | rtc_time_to_tm(0, tm); | ||
135 | } | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | static void stk17ta8_rtc_update_alarm(struct rtc_plat_data *pdata) | ||
140 | { | ||
141 | void __iomem *ioaddr = pdata->ioaddr; | ||
142 | unsigned long irqflags; | ||
143 | u8 flags; | ||
144 | |||
145 | spin_lock_irqsave(&pdata->rtc->irq_lock, irqflags); | ||
146 | |||
147 | flags = readb(ioaddr + RTC_FLAGS); | ||
148 | writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS); | ||
149 | |||
150 | writeb(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ? | ||
151 | 0x80 : BIN2BCD(pdata->alrm_mday), | ||
152 | ioaddr + RTC_DATE_ALARM); | ||
153 | writeb(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ? | ||
154 | 0x80 : BIN2BCD(pdata->alrm_hour), | ||
155 | ioaddr + RTC_HOURS_ALARM); | ||
156 | writeb(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ? | ||
157 | 0x80 : BIN2BCD(pdata->alrm_min), | ||
158 | ioaddr + RTC_MINUTES_ALARM); | ||
159 | writeb(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ? | ||
160 | 0x80 : BIN2BCD(pdata->alrm_sec), | ||
161 | ioaddr + RTC_SECONDS_ALARM); | ||
162 | writeb(pdata->irqen ? RTC_INTS_AIE : 0, ioaddr + RTC_INTERRUPTS); | ||
163 | readb(ioaddr + RTC_FLAGS); /* clear interrupts */ | ||
164 | writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS); | ||
165 | spin_unlock_irqrestore(&pdata->rtc->irq_lock, irqflags); | ||
166 | } | ||
167 | |||
168 | static int stk17ta8_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
169 | { | ||
170 | struct platform_device *pdev = to_platform_device(dev); | ||
171 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
172 | |||
173 | if (pdata->irq < 0) | ||
174 | return -EINVAL; | ||
175 | pdata->alrm_mday = alrm->time.tm_mday; | ||
176 | pdata->alrm_hour = alrm->time.tm_hour; | ||
177 | pdata->alrm_min = alrm->time.tm_min; | ||
178 | pdata->alrm_sec = alrm->time.tm_sec; | ||
179 | if (alrm->enabled) | ||
180 | pdata->irqen |= RTC_AF; | ||
181 | stk17ta8_rtc_update_alarm(pdata); | ||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | static int stk17ta8_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) | ||
186 | { | ||
187 | struct platform_device *pdev = to_platform_device(dev); | ||
188 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
189 | |||
190 | if (pdata->irq < 0) | ||
191 | return -EINVAL; | ||
192 | alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday; | ||
193 | alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour; | ||
194 | alrm->time.tm_min = pdata->alrm_min < 0 ? 0 : pdata->alrm_min; | ||
195 | alrm->time.tm_sec = pdata->alrm_sec < 0 ? 0 : pdata->alrm_sec; | ||
196 | alrm->enabled = (pdata->irqen & RTC_AF) ? 1 : 0; | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | static irqreturn_t stk17ta8_rtc_interrupt(int irq, void *dev_id) | ||
201 | { | ||
202 | struct platform_device *pdev = dev_id; | ||
203 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
204 | void __iomem *ioaddr = pdata->ioaddr; | ||
205 | unsigned long events = RTC_IRQF; | ||
206 | |||
207 | /* read and clear interrupt */ | ||
208 | if (!(readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF)) | ||
209 | return IRQ_NONE; | ||
210 | if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80) | ||
211 | events |= RTC_UF; | ||
212 | else | ||
213 | events |= RTC_AF; | ||
214 | rtc_update_irq(pdata->rtc, 1, events); | ||
215 | return IRQ_HANDLED; | ||
216 | } | ||
217 | |||
218 | static void stk17ta8_rtc_release(struct device *dev) | ||
219 | { | ||
220 | struct platform_device *pdev = to_platform_device(dev); | ||
221 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
222 | |||
223 | if (pdata->irq >= 0) { | ||
224 | pdata->irqen = 0; | ||
225 | stk17ta8_rtc_update_alarm(pdata); | ||
226 | } | ||
227 | } | ||
228 | |||
229 | static int stk17ta8_rtc_ioctl(struct device *dev, unsigned int cmd, | ||
230 | unsigned long arg) | ||
231 | { | ||
232 | struct platform_device *pdev = to_platform_device(dev); | ||
233 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
234 | |||
235 | if (pdata->irq < 0) | ||
236 | return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ | ||
237 | switch (cmd) { | ||
238 | case RTC_AIE_OFF: | ||
239 | pdata->irqen &= ~RTC_AF; | ||
240 | stk17ta8_rtc_update_alarm(pdata); | ||
241 | break; | ||
242 | case RTC_AIE_ON: | ||
243 | pdata->irqen |= RTC_AF; | ||
244 | stk17ta8_rtc_update_alarm(pdata); | ||
245 | break; | ||
246 | default: | ||
247 | return -ENOIOCTLCMD; | ||
248 | } | ||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | static const struct rtc_class_ops stk17ta8_rtc_ops = { | ||
253 | .read_time = stk17ta8_rtc_read_time, | ||
254 | .set_time = stk17ta8_rtc_set_time, | ||
255 | .read_alarm = stk17ta8_rtc_read_alarm, | ||
256 | .set_alarm = stk17ta8_rtc_set_alarm, | ||
257 | .release = stk17ta8_rtc_release, | ||
258 | .ioctl = stk17ta8_rtc_ioctl, | ||
259 | }; | ||
260 | |||
261 | static ssize_t stk17ta8_nvram_read(struct kobject *kobj, char *buf, | ||
262 | loff_t pos, size_t size) | ||
263 | { | ||
264 | struct platform_device *pdev = | ||
265 | to_platform_device(container_of(kobj, struct device, kobj)); | ||
266 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
267 | void __iomem *ioaddr = pdata->ioaddr; | ||
268 | ssize_t count; | ||
269 | |||
270 | for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--) | ||
271 | *buf++ = readb(ioaddr + pos++); | ||
272 | return count; | ||
273 | } | ||
274 | |||
275 | static ssize_t stk17ta8_nvram_write(struct kobject *kobj, char *buf, | ||
276 | loff_t pos, size_t size) | ||
277 | { | ||
278 | struct platform_device *pdev = | ||
279 | to_platform_device(container_of(kobj, struct device, kobj)); | ||
280 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
281 | void __iomem *ioaddr = pdata->ioaddr; | ||
282 | ssize_t count; | ||
283 | |||
284 | for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--) | ||
285 | writeb(*buf++, ioaddr + pos++); | ||
286 | return count; | ||
287 | } | ||
288 | |||
289 | static struct bin_attribute stk17ta8_nvram_attr = { | ||
290 | .attr = { | ||
291 | .name = "nvram", | ||
292 | .mode = S_IRUGO | S_IWUGO, | ||
293 | .owner = THIS_MODULE, | ||
294 | }, | ||
295 | .size = RTC_OFFSET, | ||
296 | .read = stk17ta8_nvram_read, | ||
297 | .write = stk17ta8_nvram_write, | ||
298 | }; | ||
299 | |||
300 | static int __init stk17ta8_rtc_probe(struct platform_device *pdev) | ||
301 | { | ||
302 | struct rtc_device *rtc; | ||
303 | struct resource *res; | ||
304 | unsigned int cal; | ||
305 | unsigned int flags; | ||
306 | struct rtc_plat_data *pdata; | ||
307 | void __iomem *ioaddr = NULL; | ||
308 | int ret = 0; | ||
309 | |||
310 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
311 | if (!res) | ||
312 | return -ENODEV; | ||
313 | |||
314 | pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); | ||
315 | if (!pdata) | ||
316 | return -ENOMEM; | ||
317 | pdata->irq = -1; | ||
318 | if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) { | ||
319 | ret = -EBUSY; | ||
320 | goto out; | ||
321 | } | ||
322 | pdata->baseaddr = res->start; | ||
323 | ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE); | ||
324 | if (!ioaddr) { | ||
325 | ret = -ENOMEM; | ||
326 | goto out; | ||
327 | } | ||
328 | pdata->ioaddr = ioaddr; | ||
329 | pdata->irq = platform_get_irq(pdev, 0); | ||
330 | |||
331 | /* turn RTC on if it was not on */ | ||
332 | cal = readb(ioaddr + RTC_CALIBRATION); | ||
333 | if (cal & RTC_STOP) { | ||
334 | cal &= RTC_CAL_MASK; | ||
335 | flags = readb(ioaddr + RTC_FLAGS); | ||
336 | writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS); | ||
337 | writeb(cal, ioaddr + RTC_CALIBRATION); | ||
338 | writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS); | ||
339 | } | ||
340 | if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_PF) | ||
341 | dev_warn(&pdev->dev, "voltage-low detected.\n"); | ||
342 | |||
343 | if (pdata->irq >= 0) { | ||
344 | writeb(0, ioaddr + RTC_INTERRUPTS); | ||
345 | if (request_irq(pdata->irq, stk17ta8_rtc_interrupt, | ||
346 | IRQF_DISABLED | IRQF_SHARED, | ||
347 | pdev->name, pdev) < 0) { | ||
348 | dev_warn(&pdev->dev, "interrupt not available.\n"); | ||
349 | pdata->irq = -1; | ||
350 | } | ||
351 | } | ||
352 | |||
353 | rtc = rtc_device_register(pdev->name, &pdev->dev, | ||
354 | &stk17ta8_rtc_ops, THIS_MODULE); | ||
355 | if (IS_ERR(rtc)) { | ||
356 | ret = PTR_ERR(rtc); | ||
357 | goto out; | ||
358 | } | ||
359 | pdata->rtc = rtc; | ||
360 | pdata->last_jiffies = jiffies; | ||
361 | platform_set_drvdata(pdev, pdata); | ||
362 | ret = sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr); | ||
363 | if (ret) | ||
364 | goto out; | ||
365 | return 0; | ||
366 | out: | ||
367 | if (pdata->rtc) | ||
368 | rtc_device_unregister(pdata->rtc); | ||
369 | if (pdata->irq >= 0) | ||
370 | free_irq(pdata->irq, pdev); | ||
371 | if (ioaddr) | ||
372 | iounmap(ioaddr); | ||
373 | if (pdata->baseaddr) | ||
374 | release_mem_region(pdata->baseaddr, RTC_REG_SIZE); | ||
375 | kfree(pdata); | ||
376 | return ret; | ||
377 | } | ||
378 | |||
379 | static int __devexit stk17ta8_rtc_remove(struct platform_device *pdev) | ||
380 | { | ||
381 | struct rtc_plat_data *pdata = platform_get_drvdata(pdev); | ||
382 | |||
383 | sysfs_remove_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr); | ||
384 | rtc_device_unregister(pdata->rtc); | ||
385 | if (pdata->irq >= 0) { | ||
386 | writeb(0, pdata->ioaddr + RTC_INTERRUPTS); | ||
387 | free_irq(pdata->irq, pdev); | ||
388 | } | ||
389 | iounmap(pdata->ioaddr); | ||
390 | release_mem_region(pdata->baseaddr, RTC_REG_SIZE); | ||
391 | kfree(pdata); | ||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | static struct platform_driver stk17ta8_rtc_driver = { | ||
396 | .probe = stk17ta8_rtc_probe, | ||
397 | .remove = __devexit_p(stk17ta8_rtc_remove), | ||
398 | .driver = { | ||
399 | .name = "stk17ta8", | ||
400 | .owner = THIS_MODULE, | ||
401 | }, | ||
402 | }; | ||
403 | |||
404 | static __init int stk17ta8_init(void) | ||
405 | { | ||
406 | return platform_driver_register(&stk17ta8_rtc_driver); | ||
407 | } | ||
408 | |||
409 | static __exit void stk17ta8_exit(void) | ||
410 | { | ||
411 | return platform_driver_unregister(&stk17ta8_rtc_driver); | ||
412 | } | ||
413 | |||
414 | module_init(stk17ta8_init); | ||
415 | module_exit(stk17ta8_exit); | ||
416 | |||
417 | MODULE_AUTHOR("Thomas Hommel <thomas.hommel@gefanuc.com>"); | ||
418 | MODULE_DESCRIPTION("Simtek STK17TA8 RTC driver"); | ||
419 | MODULE_LICENSE("GPL"); | ||
420 | MODULE_VERSION(DRV_VERSION); | ||
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 0f86895571..86a7ba7bad 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile | |||
@@ -132,6 +132,7 @@ obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsi/ | |||
132 | obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvscsi/ | 132 | obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvscsi/ |
133 | obj-$(CONFIG_SCSI_HPTIOP) += hptiop.o | 133 | obj-$(CONFIG_SCSI_HPTIOP) += hptiop.o |
134 | obj-$(CONFIG_SCSI_STEX) += stex.o | 134 | obj-$(CONFIG_SCSI_STEX) += stex.o |
135 | obj-$(CONFIG_PS3_ROM) += ps3rom.o | ||
135 | 136 | ||
136 | obj-$(CONFIG_ARM) += arm/ | 137 | obj-$(CONFIG_ARM) += arm/ |
137 | 138 | ||
diff --git a/drivers/scsi/ps3rom.c b/drivers/scsi/ps3rom.c new file mode 100644 index 0000000000..b50f1e14f2 --- /dev/null +++ b/drivers/scsi/ps3rom.c | |||
@@ -0,0 +1,533 @@ | |||
1 | /* | ||
2 | * PS3 BD/DVD/CD-ROM Storage Driver | ||
3 | * | ||
4 | * Copyright (C) 2007 Sony Computer Entertainment Inc. | ||
5 | * Copyright 2007 Sony Corp. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published | ||
9 | * by the Free Software Foundation; version 2 of the License. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/cdrom.h> | ||
22 | #include <linux/highmem.h> | ||
23 | |||
24 | #include <scsi/scsi.h> | ||
25 | #include <scsi/scsi_cmnd.h> | ||
26 | #include <scsi/scsi_dbg.h> | ||
27 | #include <scsi/scsi_device.h> | ||
28 | #include <scsi/scsi_host.h> | ||
29 | |||
30 | #include <asm/lv1call.h> | ||
31 | #include <asm/ps3stor.h> | ||
32 | |||
33 | |||
34 | #define DEVICE_NAME "ps3rom" | ||
35 | |||
36 | #define BOUNCE_SIZE (64*1024) | ||
37 | |||
38 | #define PS3ROM_MAX_SECTORS (BOUNCE_SIZE / CD_FRAMESIZE) | ||
39 | |||
40 | |||
41 | struct ps3rom_private { | ||
42 | struct ps3_storage_device *dev; | ||
43 | struct scsi_cmnd *curr_cmd; | ||
44 | }; | ||
45 | |||
46 | |||
47 | #define LV1_STORAGE_SEND_ATAPI_COMMAND (1) | ||
48 | |||
49 | struct lv1_atapi_cmnd_block { | ||
50 | u8 pkt[32]; /* packet command block */ | ||
51 | u32 pktlen; /* should be 12 for ATAPI 8020 */ | ||
52 | u32 blocks; | ||
53 | u32 block_size; | ||
54 | u32 proto; /* transfer mode */ | ||
55 | u32 in_out; /* transfer direction */ | ||
56 | u64 buffer; /* parameter except command block */ | ||
57 | u32 arglen; /* length above */ | ||
58 | }; | ||
59 | |||
60 | enum lv1_atapi_proto { | ||
61 | NON_DATA_PROTO = 0, | ||
62 | PIO_DATA_IN_PROTO = 1, | ||
63 | PIO_DATA_OUT_PROTO = 2, | ||
64 | DMA_PROTO = 3 | ||
65 | }; | ||
66 | |||
67 | enum lv1_atapi_in_out { | ||
68 | DIR_WRITE = 0, /* memory -> device */ | ||
69 | DIR_READ = 1 /* device -> memory */ | ||
70 | }; | ||
71 | |||
72 | |||
73 | static int ps3rom_slave_configure(struct scsi_device *scsi_dev) | ||
74 | { | ||
75 | struct ps3rom_private *priv = shost_priv(scsi_dev->host); | ||
76 | struct ps3_storage_device *dev = priv->dev; | ||
77 | |||
78 | dev_dbg(&dev->sbd.core, "%s:%u: id %u, lun %u, channel %u\n", __func__, | ||
79 | __LINE__, scsi_dev->id, scsi_dev->lun, scsi_dev->channel); | ||
80 | |||
81 | /* | ||
82 | * ATAPI SFF8020 devices use MODE_SENSE_10, | ||
83 | * so we can prohibit MODE_SENSE_6 | ||
84 | */ | ||
85 | scsi_dev->use_10_for_ms = 1; | ||
86 | |||
87 | /* we don't support {READ,WRITE}_6 */ | ||
88 | scsi_dev->use_10_for_rw = 1; | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | * copy data from device into scatter/gather buffer | ||
95 | */ | ||
96 | static int fill_from_dev_buffer(struct scsi_cmnd *cmd, const void *buf) | ||
97 | { | ||
98 | int k, req_len, act_len, len, active; | ||
99 | void *kaddr; | ||
100 | struct scatterlist *sgpnt; | ||
101 | unsigned int buflen; | ||
102 | |||
103 | buflen = cmd->request_bufflen; | ||
104 | if (!buflen) | ||
105 | return 0; | ||
106 | |||
107 | if (!cmd->request_buffer) | ||
108 | return -1; | ||
109 | |||
110 | sgpnt = cmd->request_buffer; | ||
111 | active = 1; | ||
112 | for (k = 0, req_len = 0, act_len = 0; k < cmd->use_sg; ++k, ++sgpnt) { | ||
113 | if (active) { | ||
114 | kaddr = kmap_atomic(sgpnt->page, KM_IRQ0); | ||
115 | len = sgpnt->length; | ||
116 | if ((req_len + len) > buflen) { | ||
117 | active = 0; | ||
118 | len = buflen - req_len; | ||
119 | } | ||
120 | memcpy(kaddr + sgpnt->offset, buf + req_len, len); | ||
121 | flush_kernel_dcache_page(sgpnt->page); | ||
122 | kunmap_atomic(kaddr, KM_IRQ0); | ||
123 | act_len += len; | ||
124 | } | ||
125 | req_len += sgpnt->length; | ||
126 | } | ||
127 | cmd->resid = req_len - act_len; | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | /* | ||
132 | * copy data from scatter/gather into device's buffer | ||
133 | */ | ||
134 | static int fetch_to_dev_buffer(struct scsi_cmnd *cmd, void *buf) | ||
135 | { | ||
136 | int k, req_len, len, fin; | ||
137 | void *kaddr; | ||
138 | struct scatterlist *sgpnt; | ||
139 | unsigned int buflen; | ||
140 | |||
141 | buflen = cmd->request_bufflen; | ||
142 | if (!buflen) | ||
143 | return 0; | ||
144 | |||
145 | if (!cmd->request_buffer) | ||
146 | return -1; | ||
147 | |||
148 | sgpnt = cmd->request_buffer; | ||
149 | for (k = 0, req_len = 0, fin = 0; k < cmd->use_sg; ++k, ++sgpnt) { | ||
150 | kaddr = kmap_atomic(sgpnt->page, KM_IRQ0); | ||
151 | len = sgpnt->length; | ||
152 | if ((req_len + len) > buflen) { | ||
153 | len = buflen - req_len; | ||
154 | fin = 1; | ||
155 | } | ||
156 | memcpy(buf + req_len, kaddr + sgpnt->offset, len); | ||
157 | kunmap_atomic(kaddr, KM_IRQ0); | ||
158 | if (fin) | ||
159 | return req_len + len; | ||
160 | req_len += sgpnt->length; | ||
161 | } | ||
162 | return req_len; | ||
163 | } | ||
164 | |||
165 | static int ps3rom_atapi_request(struct ps3_storage_device *dev, | ||
166 | struct scsi_cmnd *cmd) | ||
167 | { | ||
168 | struct lv1_atapi_cmnd_block atapi_cmnd; | ||
169 | unsigned char opcode = cmd->cmnd[0]; | ||
170 | int res; | ||
171 | u64 lpar; | ||
172 | |||
173 | dev_dbg(&dev->sbd.core, "%s:%u: send ATAPI command 0x%02x\n", __func__, | ||
174 | __LINE__, opcode); | ||
175 | |||
176 | memset(&atapi_cmnd, 0, sizeof(struct lv1_atapi_cmnd_block)); | ||
177 | memcpy(&atapi_cmnd.pkt, cmd->cmnd, 12); | ||
178 | atapi_cmnd.pktlen = 12; | ||
179 | atapi_cmnd.block_size = 1; /* transfer size is block_size * blocks */ | ||
180 | atapi_cmnd.blocks = atapi_cmnd.arglen = cmd->request_bufflen; | ||
181 | atapi_cmnd.buffer = dev->bounce_lpar; | ||
182 | |||
183 | switch (cmd->sc_data_direction) { | ||
184 | case DMA_FROM_DEVICE: | ||
185 | if (cmd->request_bufflen >= CD_FRAMESIZE) | ||
186 | atapi_cmnd.proto = DMA_PROTO; | ||
187 | else | ||
188 | atapi_cmnd.proto = PIO_DATA_IN_PROTO; | ||
189 | atapi_cmnd.in_out = DIR_READ; | ||
190 | break; | ||
191 | |||
192 | case DMA_TO_DEVICE: | ||
193 | if (cmd->request_bufflen >= CD_FRAMESIZE) | ||
194 | atapi_cmnd.proto = DMA_PROTO; | ||
195 | else | ||
196 | atapi_cmnd.proto = PIO_DATA_OUT_PROTO; | ||
197 | atapi_cmnd.in_out = DIR_WRITE; | ||
198 | res = fetch_to_dev_buffer(cmd, dev->bounce_buf); | ||
199 | if (res < 0) | ||
200 | return DID_ERROR << 16; | ||
201 | break; | ||
202 | |||
203 | default: | ||
204 | atapi_cmnd.proto = NON_DATA_PROTO; | ||
205 | break; | ||
206 | } | ||
207 | |||
208 | lpar = ps3_mm_phys_to_lpar(__pa(&atapi_cmnd)); | ||
209 | res = lv1_storage_send_device_command(dev->sbd.dev_id, | ||
210 | LV1_STORAGE_SEND_ATAPI_COMMAND, | ||
211 | lpar, sizeof(atapi_cmnd), | ||
212 | atapi_cmnd.buffer, | ||
213 | atapi_cmnd.arglen, &dev->tag); | ||
214 | if (res == LV1_DENIED_BY_POLICY) { | ||
215 | dev_dbg(&dev->sbd.core, | ||
216 | "%s:%u: ATAPI command 0x%02x denied by policy\n", | ||
217 | __func__, __LINE__, opcode); | ||
218 | return DID_ERROR << 16; | ||
219 | } | ||
220 | |||
221 | if (res) { | ||
222 | dev_err(&dev->sbd.core, | ||
223 | "%s:%u: ATAPI command 0x%02x failed %d\n", __func__, | ||
224 | __LINE__, opcode, res); | ||
225 | return DID_ERROR << 16; | ||
226 | } | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static inline unsigned int srb10_lba(const struct scsi_cmnd *cmd) | ||
232 | { | ||
233 | return cmd->cmnd[2] << 24 | cmd->cmnd[3] << 16 | cmd->cmnd[4] << 8 | | ||
234 | cmd->cmnd[5]; | ||
235 | } | ||
236 | |||
237 | static inline unsigned int srb10_len(const struct scsi_cmnd *cmd) | ||
238 | { | ||
239 | return cmd->cmnd[7] << 8 | cmd->cmnd[8]; | ||
240 | } | ||
241 | |||
242 | static int ps3rom_read_request(struct ps3_storage_device *dev, | ||
243 | struct scsi_cmnd *cmd, u32 start_sector, | ||
244 | u32 sectors) | ||
245 | { | ||
246 | int res; | ||
247 | |||
248 | dev_dbg(&dev->sbd.core, "%s:%u: read %u sectors starting at %u\n", | ||
249 | __func__, __LINE__, sectors, start_sector); | ||
250 | |||
251 | res = lv1_storage_read(dev->sbd.dev_id, | ||
252 | dev->regions[dev->region_idx].id, start_sector, | ||
253 | sectors, 0, dev->bounce_lpar, &dev->tag); | ||
254 | if (res) { | ||
255 | dev_err(&dev->sbd.core, "%s:%u: read failed %d\n", __func__, | ||
256 | __LINE__, res); | ||
257 | return DID_ERROR << 16; | ||
258 | } | ||
259 | |||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | static int ps3rom_write_request(struct ps3_storage_device *dev, | ||
264 | struct scsi_cmnd *cmd, u32 start_sector, | ||
265 | u32 sectors) | ||
266 | { | ||
267 | int res; | ||
268 | |||
269 | dev_dbg(&dev->sbd.core, "%s:%u: write %u sectors starting at %u\n", | ||
270 | __func__, __LINE__, sectors, start_sector); | ||
271 | |||
272 | res = fetch_to_dev_buffer(cmd, dev->bounce_buf); | ||
273 | if (res < 0) | ||
274 | return DID_ERROR << 16; | ||
275 | |||
276 | res = lv1_storage_write(dev->sbd.dev_id, | ||
277 | dev->regions[dev->region_idx].id, start_sector, | ||
278 | sectors, 0, dev->bounce_lpar, &dev->tag); | ||
279 | if (res) { | ||
280 | dev_err(&dev->sbd.core, "%s:%u: write failed %d\n", __func__, | ||
281 | __LINE__, res); | ||
282 | return DID_ERROR << 16; | ||
283 | } | ||
284 | |||
285 | return 0; | ||
286 | } | ||
287 | |||
288 | static int ps3rom_queuecommand(struct scsi_cmnd *cmd, | ||
289 | void (*done)(struct scsi_cmnd *)) | ||
290 | { | ||
291 | struct ps3rom_private *priv = shost_priv(cmd->device->host); | ||
292 | struct ps3_storage_device *dev = priv->dev; | ||
293 | unsigned char opcode; | ||
294 | int res; | ||
295 | |||
296 | #ifdef DEBUG | ||
297 | scsi_print_command(cmd); | ||
298 | #endif | ||
299 | |||
300 | priv->curr_cmd = cmd; | ||
301 | cmd->scsi_done = done; | ||
302 | |||
303 | opcode = cmd->cmnd[0]; | ||
304 | /* | ||
305 | * While we can submit READ/WRITE SCSI commands as ATAPI commands, | ||
306 | * it's recommended for various reasons (performance, error handling, | ||
307 | * ...) to use lv1_storage_{read,write}() instead | ||
308 | */ | ||
309 | switch (opcode) { | ||
310 | case READ_10: | ||
311 | res = ps3rom_read_request(dev, cmd, srb10_lba(cmd), | ||
312 | srb10_len(cmd)); | ||
313 | break; | ||
314 | |||
315 | case WRITE_10: | ||
316 | res = ps3rom_write_request(dev, cmd, srb10_lba(cmd), | ||
317 | srb10_len(cmd)); | ||
318 | break; | ||
319 | |||
320 | default: | ||
321 | res = ps3rom_atapi_request(dev, cmd); | ||
322 | break; | ||
323 | } | ||
324 | |||
325 | if (res) { | ||
326 | memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); | ||
327 | cmd->result = res; | ||
328 | cmd->sense_buffer[0] = 0x70; | ||
329 | cmd->sense_buffer[2] = ILLEGAL_REQUEST; | ||
330 | priv->curr_cmd = NULL; | ||
331 | cmd->scsi_done(cmd); | ||
332 | } | ||
333 | |||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | static int decode_lv1_status(u64 status, unsigned char *sense_key, | ||
338 | unsigned char *asc, unsigned char *ascq) | ||
339 | { | ||
340 | if (((status >> 24) & 0xff) != SAM_STAT_CHECK_CONDITION) | ||
341 | return -1; | ||
342 | |||
343 | *sense_key = (status >> 16) & 0xff; | ||
344 | *asc = (status >> 8) & 0xff; | ||
345 | *ascq = status & 0xff; | ||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static irqreturn_t ps3rom_interrupt(int irq, void *data) | ||
350 | { | ||
351 | struct ps3_storage_device *dev = data; | ||
352 | struct Scsi_Host *host; | ||
353 | struct ps3rom_private *priv; | ||
354 | struct scsi_cmnd *cmd; | ||
355 | int res; | ||
356 | u64 tag, status; | ||
357 | unsigned char sense_key, asc, ascq; | ||
358 | |||
359 | res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status); | ||
360 | /* | ||
361 | * status = -1 may mean that ATAPI transport completed OK, but | ||
362 | * ATAPI command itself resulted CHECK CONDITION | ||
363 | * so, upper layer should issue REQUEST_SENSE to check the sense data | ||
364 | */ | ||
365 | |||
366 | if (tag != dev->tag) | ||
367 | dev_err(&dev->sbd.core, | ||
368 | "%s:%u: tag mismatch, got %lx, expected %lx\n", | ||
369 | __func__, __LINE__, tag, dev->tag); | ||
370 | |||
371 | if (res) { | ||
372 | dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%lx\n", | ||
373 | __func__, __LINE__, res, status); | ||
374 | return IRQ_HANDLED; | ||
375 | } | ||
376 | |||
377 | host = dev->sbd.core.driver_data; | ||
378 | priv = shost_priv(host); | ||
379 | cmd = priv->curr_cmd; | ||
380 | |||
381 | if (!status) { | ||
382 | /* OK, completed */ | ||
383 | if (cmd->sc_data_direction == DMA_FROM_DEVICE) { | ||
384 | res = fill_from_dev_buffer(cmd, dev->bounce_buf); | ||
385 | if (res) { | ||
386 | cmd->result = DID_ERROR << 16; | ||
387 | goto done; | ||
388 | } | ||
389 | } | ||
390 | cmd->result = DID_OK << 16; | ||
391 | goto done; | ||
392 | } | ||
393 | |||
394 | if (cmd->cmnd[0] == REQUEST_SENSE) { | ||
395 | /* SCSI spec says request sense should never get error */ | ||
396 | dev_err(&dev->sbd.core, "%s:%u: end error without autosense\n", | ||
397 | __func__, __LINE__); | ||
398 | cmd->result = DID_ERROR << 16 | SAM_STAT_CHECK_CONDITION; | ||
399 | goto done; | ||
400 | } | ||
401 | |||
402 | if (decode_lv1_status(status, &sense_key, &asc, &ascq)) { | ||
403 | cmd->result = DID_ERROR << 16; | ||
404 | goto done; | ||
405 | } | ||
406 | |||
407 | cmd->sense_buffer[0] = 0x70; | ||
408 | cmd->sense_buffer[2] = sense_key; | ||
409 | cmd->sense_buffer[7] = 16 - 6; | ||
410 | cmd->sense_buffer[12] = asc; | ||
411 | cmd->sense_buffer[13] = ascq; | ||
412 | cmd->result = SAM_STAT_CHECK_CONDITION; | ||
413 | |||
414 | done: | ||
415 | priv->curr_cmd = NULL; | ||
416 | cmd->scsi_done(cmd); | ||
417 | return IRQ_HANDLED; | ||
418 | } | ||
419 | |||
420 | static struct scsi_host_template ps3rom_host_template = { | ||
421 | .name = DEVICE_NAME, | ||
422 | .slave_configure = ps3rom_slave_configure, | ||
423 | .queuecommand = ps3rom_queuecommand, | ||
424 | .can_queue = 1, | ||
425 | .this_id = 7, | ||
426 | .sg_tablesize = SG_ALL, | ||
427 | .cmd_per_lun = 1, | ||
428 | .emulated = 1, /* only sg driver uses this */ | ||
429 | .max_sectors = PS3ROM_MAX_SECTORS, | ||
430 | .use_clustering = ENABLE_CLUSTERING, | ||
431 | .module = THIS_MODULE, | ||
432 | }; | ||
433 | |||
434 | |||
435 | static int __devinit ps3rom_probe(struct ps3_system_bus_device *_dev) | ||
436 | { | ||
437 | struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); | ||
438 | int error; | ||
439 | struct Scsi_Host *host; | ||
440 | struct ps3rom_private *priv; | ||
441 | |||
442 | if (dev->blk_size != CD_FRAMESIZE) { | ||
443 | dev_err(&dev->sbd.core, | ||
444 | "%s:%u: cannot handle block size %lu\n", __func__, | ||
445 | __LINE__, dev->blk_size); | ||
446 | return -EINVAL; | ||
447 | } | ||
448 | |||
449 | dev->bounce_size = BOUNCE_SIZE; | ||
450 | dev->bounce_buf = kmalloc(BOUNCE_SIZE, GFP_DMA); | ||
451 | if (!dev->bounce_buf) | ||
452 | return -ENOMEM; | ||
453 | |||
454 | error = ps3stor_setup(dev, ps3rom_interrupt); | ||
455 | if (error) | ||
456 | goto fail_free_bounce; | ||
457 | |||
458 | host = scsi_host_alloc(&ps3rom_host_template, | ||
459 | sizeof(struct ps3rom_private)); | ||
460 | if (!host) { | ||
461 | dev_err(&dev->sbd.core, "%s:%u: scsi_host_alloc failed\n", | ||
462 | __func__, __LINE__); | ||
463 | goto fail_teardown; | ||
464 | } | ||
465 | |||
466 | priv = shost_priv(host); | ||
467 | dev->sbd.core.driver_data = host; | ||
468 | priv->dev = dev; | ||
469 | |||
470 | /* One device/LUN per SCSI bus */ | ||
471 | host->max_id = 1; | ||
472 | host->max_lun = 1; | ||
473 | |||
474 | error = scsi_add_host(host, &dev->sbd.core); | ||
475 | if (error) { | ||
476 | dev_err(&dev->sbd.core, "%s:%u: scsi_host_alloc failed %d\n", | ||
477 | __func__, __LINE__, error); | ||
478 | error = -ENODEV; | ||
479 | goto fail_host_put; | ||
480 | } | ||
481 | |||
482 | scsi_scan_host(host); | ||
483 | return 0; | ||
484 | |||
485 | fail_host_put: | ||
486 | scsi_host_put(host); | ||
487 | dev->sbd.core.driver_data = NULL; | ||
488 | fail_teardown: | ||
489 | ps3stor_teardown(dev); | ||
490 | fail_free_bounce: | ||
491 | kfree(dev->bounce_buf); | ||
492 | return error; | ||
493 | } | ||
494 | |||
495 | static int ps3rom_remove(struct ps3_system_bus_device *_dev) | ||
496 | { | ||
497 | struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); | ||
498 | struct Scsi_Host *host = dev->sbd.core.driver_data; | ||
499 | |||
500 | scsi_remove_host(host); | ||
501 | ps3stor_teardown(dev); | ||
502 | scsi_host_put(host); | ||
503 | dev->sbd.core.driver_data = NULL; | ||
504 | kfree(dev->bounce_buf); | ||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | static struct ps3_system_bus_driver ps3rom = { | ||
509 | .match_id = PS3_MATCH_ID_STOR_ROM, | ||
510 | .core.name = DEVICE_NAME, | ||
511 | .core.owner = THIS_MODULE, | ||
512 | .probe = ps3rom_probe, | ||
513 | .remove = ps3rom_remove | ||
514 | }; | ||
515 | |||
516 | |||
517 | static int __init ps3rom_init(void) | ||
518 | { | ||
519 | return ps3_system_bus_driver_register(&ps3rom); | ||
520 | } | ||
521 | |||
522 | static void __exit ps3rom_exit(void) | ||
523 | { | ||
524 | ps3_system_bus_driver_unregister(&ps3rom); | ||
525 | } | ||
526 | |||
527 | module_init(ps3rom_init); | ||
528 | module_exit(ps3rom_exit); | ||
529 | |||
530 | MODULE_LICENSE("GPL"); | ||
531 | MODULE_DESCRIPTION("PS3 BD/DVD/CD-ROM Storage Driver"); | ||
532 | MODULE_AUTHOR("Sony Corporation"); | ||
533 | MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_ROM); | ||
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 018884d7a5..b05de30b5d 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c | |||
@@ -303,8 +303,7 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n) | |||
303 | * creates board info from kernel command lines | 303 | * creates board info from kernel command lines |
304 | */ | 304 | */ |
305 | 305 | ||
306 | static void __init_or_module | 306 | static void scan_boardinfo(struct spi_master *master) |
307 | scan_boardinfo(struct spi_master *master) | ||
308 | { | 307 | { |
309 | struct boardinfo *bi; | 308 | struct boardinfo *bi; |
310 | struct device *dev = master->cdev.dev; | 309 | struct device *dev = master->cdev.dev; |
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 0c5644bb59..564cc9b518 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -12,6 +12,13 @@ config VGASTATE | |||
12 | tristate | 12 | tristate |
13 | default n | 13 | default n |
14 | 14 | ||
15 | config VIDEO_OUTPUT_CONTROL | ||
16 | tristate "Lowlevel video output switch controls" | ||
17 | default m | ||
18 | help | ||
19 | This framework adds support for low-level control of the video | ||
20 | output switch. | ||
21 | |||
15 | config FB | 22 | config FB |
16 | tristate "Support for frame buffer devices" | 23 | tristate "Support for frame buffer devices" |
17 | ---help--- | 24 | ---help--- |
@@ -849,6 +856,16 @@ config FB_INTSRAM | |||
849 | Say Y if you want to map Frame Buffer in internal SRAM. Say N if you want | 856 | Say Y if you want to map Frame Buffer in internal SRAM. Say N if you want |
850 | to let frame buffer in external SDRAM. | 857 | to let frame buffer in external SDRAM. |
851 | 858 | ||
859 | config FB_ATMEL_STN | ||
860 | bool "Use a STN display with AT91/AT32 LCD Controller" | ||
861 | depends on FB_ATMEL && MACH_AT91SAM9261EK | ||
862 | default n | ||
863 | help | ||
864 | Say Y if you want to connect a STN LCD display to the AT91/AT32 LCD | ||
865 | Controller. Say N if you want to connect a TFT. | ||
866 | |||
867 | If unsure, say N. | ||
868 | |||
852 | config FB_NVIDIA | 869 | config FB_NVIDIA |
853 | tristate "nVidia Framebuffer Support" | 870 | tristate "nVidia Framebuffer Support" |
854 | depends on FB && PCI | 871 | depends on FB && PCI |
@@ -1796,13 +1813,14 @@ config FB_PS3 | |||
1796 | select FB_SYS_COPYAREA | 1813 | select FB_SYS_COPYAREA |
1797 | select FB_SYS_IMAGEBLIT | 1814 | select FB_SYS_IMAGEBLIT |
1798 | select FB_SYS_FOPS | 1815 | select FB_SYS_FOPS |
1816 | select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE | ||
1799 | ---help--- | 1817 | ---help--- |
1800 | Include support for the virtual frame buffer in the PS3 platform. | 1818 | Include support for the virtual frame buffer in the PS3 platform. |
1801 | 1819 | ||
1802 | config FB_PS3_DEFAULT_SIZE_M | 1820 | config FB_PS3_DEFAULT_SIZE_M |
1803 | int "PS3 default frame buffer size (in MiB)" | 1821 | int "PS3 default frame buffer size (in MiB)" |
1804 | depends on FB_PS3 | 1822 | depends on FB_PS3 |
1805 | default 18 | 1823 | default 9 |
1806 | ---help--- | 1824 | ---help--- |
1807 | This is the default size (in MiB) of the virtual frame buffer in | 1825 | This is the default size (in MiB) of the virtual frame buffer in |
1808 | the PS3. | 1826 | the PS3. |
diff --git a/drivers/video/Makefile b/drivers/video/Makefile index a562f9d69d..518933d490 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile | |||
@@ -123,3 +123,6 @@ obj-$(CONFIG_FB_OF) += offb.o | |||
123 | 123 | ||
124 | # the test framebuffer is last | 124 | # the test framebuffer is last |
125 | obj-$(CONFIG_FB_VIRTUAL) += vfb.o | 125 | obj-$(CONFIG_FB_VIRTUAL) += vfb.o |
126 | |||
127 | #video output switch sysfs driver | ||
128 | obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o | ||
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index e1d5bd0c98..235b618b41 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c | |||
@@ -79,6 +79,29 @@ static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = { | |||
79 | .accel = FB_ACCEL_NONE, | 79 | .accel = FB_ACCEL_NONE, |
80 | }; | 80 | }; |
81 | 81 | ||
82 | static unsigned long compute_hozval(unsigned long xres, unsigned long lcdcon2) | ||
83 | { | ||
84 | unsigned long value; | ||
85 | |||
86 | if (!(cpu_is_at91sam9261() || cpu_is_at32ap7000())) | ||
87 | return xres; | ||
88 | |||
89 | value = xres; | ||
90 | if ((lcdcon2 & ATMEL_LCDC_DISTYPE) != ATMEL_LCDC_DISTYPE_TFT) { | ||
91 | /* STN display */ | ||
92 | if ((lcdcon2 & ATMEL_LCDC_DISTYPE) == ATMEL_LCDC_DISTYPE_STNCOLOR) { | ||
93 | value *= 3; | ||
94 | } | ||
95 | if ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_4 | ||
96 | || ( (lcdcon2 & ATMEL_LCDC_IFWIDTH) == ATMEL_LCDC_IFWIDTH_8 | ||
97 | && (lcdcon2 & ATMEL_LCDC_SCANMOD) == ATMEL_LCDC_SCANMOD_DUAL )) | ||
98 | value = DIV_ROUND_UP(value, 4); | ||
99 | else | ||
100 | value = DIV_ROUND_UP(value, 8); | ||
101 | } | ||
102 | |||
103 | return value; | ||
104 | } | ||
82 | 105 | ||
83 | static void atmel_lcdfb_update_dma(struct fb_info *info, | 106 | static void atmel_lcdfb_update_dma(struct fb_info *info, |
84 | struct fb_var_screeninfo *var) | 107 | struct fb_var_screeninfo *var) |
@@ -181,6 +204,7 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, | |||
181 | var->xoffset = var->yoffset = 0; | 204 | var->xoffset = var->yoffset = 0; |
182 | 205 | ||
183 | switch (var->bits_per_pixel) { | 206 | switch (var->bits_per_pixel) { |
207 | case 1: | ||
184 | case 2: | 208 | case 2: |
185 | case 4: | 209 | case 4: |
186 | case 8: | 210 | case 8: |
@@ -195,8 +219,11 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, | |||
195 | var->blue.offset = 10; | 219 | var->blue.offset = 10; |
196 | var->red.length = var->green.length = var->blue.length = 5; | 220 | var->red.length = var->green.length = var->blue.length = 5; |
197 | break; | 221 | break; |
198 | case 24: | ||
199 | case 32: | 222 | case 32: |
223 | var->transp.offset = 24; | ||
224 | var->transp.length = 8; | ||
225 | /* fall through */ | ||
226 | case 24: | ||
200 | var->red.offset = 0; | 227 | var->red.offset = 0; |
201 | var->green.offset = 8; | 228 | var->green.offset = 8; |
202 | var->blue.offset = 16; | 229 | var->blue.offset = 16; |
@@ -228,8 +255,10 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, | |||
228 | static int atmel_lcdfb_set_par(struct fb_info *info) | 255 | static int atmel_lcdfb_set_par(struct fb_info *info) |
229 | { | 256 | { |
230 | struct atmel_lcdfb_info *sinfo = info->par; | 257 | struct atmel_lcdfb_info *sinfo = info->par; |
258 | unsigned long hozval_linesz; | ||
231 | unsigned long value; | 259 | unsigned long value; |
232 | unsigned long clk_value_khz; | 260 | unsigned long clk_value_khz; |
261 | unsigned long bits_per_line; | ||
233 | 262 | ||
234 | dev_dbg(info->device, "%s:\n", __func__); | 263 | dev_dbg(info->device, "%s:\n", __func__); |
235 | dev_dbg(info->device, " * resolution: %ux%u (%ux%u virtual)\n", | 264 | dev_dbg(info->device, " * resolution: %ux%u (%ux%u virtual)\n", |
@@ -241,12 +270,15 @@ static int atmel_lcdfb_set_par(struct fb_info *info) | |||
241 | 270 | ||
242 | lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0); | 271 | lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0); |
243 | 272 | ||
244 | if (info->var.bits_per_pixel <= 8) | 273 | if (info->var.bits_per_pixel == 1) |
274 | info->fix.visual = FB_VISUAL_MONO01; | ||
275 | else if (info->var.bits_per_pixel <= 8) | ||
245 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; | 276 | info->fix.visual = FB_VISUAL_PSEUDOCOLOR; |
246 | else | 277 | else |
247 | info->fix.visual = FB_VISUAL_TRUECOLOR; | 278 | info->fix.visual = FB_VISUAL_TRUECOLOR; |
248 | 279 | ||
249 | info->fix.line_length = info->var.xres_virtual * (info->var.bits_per_pixel / 8); | 280 | bits_per_line = info->var.xres_virtual * info->var.bits_per_pixel; |
281 | info->fix.line_length = DIV_ROUND_UP(bits_per_line, 8); | ||
250 | 282 | ||
251 | /* Re-initialize the DMA engine... */ | 283 | /* Re-initialize the DMA engine... */ |
252 | dev_dbg(info->device, " * update DMA engine\n"); | 284 | dev_dbg(info->device, " * update DMA engine\n"); |
@@ -262,18 +294,21 @@ static int atmel_lcdfb_set_par(struct fb_info *info) | |||
262 | /* Set pixel clock */ | 294 | /* Set pixel clock */ |
263 | clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; | 295 | clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; |
264 | 296 | ||
265 | value = clk_value_khz / PICOS2KHZ(info->var.pixclock); | 297 | value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock)); |
266 | |||
267 | if (clk_value_khz % PICOS2KHZ(info->var.pixclock)) | ||
268 | value++; | ||
269 | 298 | ||
270 | value = (value / 2) - 1; | 299 | value = (value / 2) - 1; |
300 | dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n", value); | ||
271 | 301 | ||
272 | if (value <= 0) { | 302 | if (value <= 0) { |
273 | dev_notice(info->device, "Bypassing pixel clock divider\n"); | 303 | dev_notice(info->device, "Bypassing pixel clock divider\n"); |
274 | lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS); | 304 | lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS); |
275 | } else | 305 | } else { |
276 | lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, value << ATMEL_LCDC_CLKVAL_OFFSET); | 306 | lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, value << ATMEL_LCDC_CLKVAL_OFFSET); |
307 | info->var.pixclock = KHZ2PICOS(clk_value_khz / (2 * (value + 1))); | ||
308 | dev_dbg(info->device, " updated pixclk: %lu KHz\n", | ||
309 | PICOS2KHZ(info->var.pixclock)); | ||
310 | } | ||
311 | |||
277 | 312 | ||
278 | /* Initialize control register 2 */ | 313 | /* Initialize control register 2 */ |
279 | value = sinfo->default_lcdcon2; | 314 | value = sinfo->default_lcdcon2; |
@@ -311,9 +346,14 @@ static int atmel_lcdfb_set_par(struct fb_info *info) | |||
311 | dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value); | 346 | dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value); |
312 | lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value); | 347 | lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value); |
313 | 348 | ||
349 | /* Horizontal value (aka line size) */ | ||
350 | hozval_linesz = compute_hozval(info->var.xres, | ||
351 | lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2)); | ||
352 | |||
314 | /* Display size */ | 353 | /* Display size */ |
315 | value = (info->var.xres - 1) << ATMEL_LCDC_HOZVAL_OFFSET; | 354 | value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET; |
316 | value |= info->var.yres - 1; | 355 | value |= info->var.yres - 1; |
356 | dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value); | ||
317 | lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value); | 357 | lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value); |
318 | 358 | ||
319 | /* FIFO Threshold: Use formula from data sheet */ | 359 | /* FIFO Threshold: Use formula from data sheet */ |
@@ -421,6 +461,15 @@ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red, | |||
421 | ret = 0; | 461 | ret = 0; |
422 | } | 462 | } |
423 | break; | 463 | break; |
464 | |||
465 | case FB_VISUAL_MONO01: | ||
466 | if (regno < 2) { | ||
467 | val = (regno == 0) ? 0x00 : 0x1F; | ||
468 | lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val); | ||
469 | ret = 0; | ||
470 | } | ||
471 | break; | ||
472 | |||
424 | } | 473 | } |
425 | 474 | ||
426 | return ret; | 475 | return ret; |
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index f46fe95f69..d18b73aafa 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c | |||
@@ -187,7 +187,11 @@ static void vgacon_scrollback_init(int pitch) | |||
187 | } | 187 | } |
188 | } | 188 | } |
189 | 189 | ||
190 | static void vgacon_scrollback_startup(void) | 190 | /* |
191 | * Called only duing init so call of alloc_bootmen is ok. | ||
192 | * Marked __init_refok to silence modpost. | ||
193 | */ | ||
194 | static void __init_refok vgacon_scrollback_startup(void) | ||
191 | { | 195 | { |
192 | vgacon_scrollback = alloc_bootmem(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE | 196 | vgacon_scrollback = alloc_bootmem(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE |
193 | * 1024); | 197 | * 1024); |
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index 3972aa8cf8..646ec823c1 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c | |||
@@ -1067,7 +1067,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) | |||
1067 | info->fix.smem_len = ps3fb_videomemory.size - offset; | 1067 | info->fix.smem_len = ps3fb_videomemory.size - offset; |
1068 | info->pseudo_palette = info->par; | 1068 | info->pseudo_palette = info->par; |
1069 | info->par = NULL; | 1069 | info->par = NULL; |
1070 | info->flags = FBINFO_FLAG_DEFAULT; | 1070 | info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST; |
1071 | 1071 | ||
1072 | retval = fb_alloc_cmap(&info->cmap, 256, 0); | 1072 | retval = fb_alloc_cmap(&info->cmap, 256, 0); |
1073 | if (retval < 0) | 1073 | if (retval < 0) |
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c index 0fe547842c..41381e6183 100644 --- a/drivers/video/riva/fbdev.c +++ b/drivers/video/riva/fbdev.c | |||
@@ -2146,7 +2146,7 @@ static void __devexit rivafb_remove(struct pci_dev *pd) | |||
2146 | * ------------------------------------------------------------------------- */ | 2146 | * ------------------------------------------------------------------------- */ |
2147 | 2147 | ||
2148 | #ifndef MODULE | 2148 | #ifndef MODULE |
2149 | static int __init rivafb_setup(char *options) | 2149 | static int __devinit rivafb_setup(char *options) |
2150 | { | 2150 | { |
2151 | char *this_opt; | 2151 | char *this_opt; |
2152 | 2152 | ||