aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86/sony-laptop.c
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2010-01-06 01:49:08 -0500
committerPaul Mundt <lethal@linux-sh.org>2010-01-06 01:49:08 -0500
commitfa94ddea2b29fdda7640672c8a933dbd901f0278 (patch)
tree4e9204f1438f5ed44bff31e2abee598ad775321d /drivers/platform/x86/sony-laptop.c
parent6fbfe8d7cd7e71ceb281c5a1b9de6e5e0dfbf1c8 (diff)
parent56d45b62ce622a003da972428fdbba2b42102efb (diff)
Merge branch 'master' into sh/hw-breakpoints
Diffstat (limited to 'drivers/platform/x86/sony-laptop.c')
-rw-r--r--drivers/platform/x86/sony-laptop.c150
1 files changed, 100 insertions, 50 deletions
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 7a2cc8a5c975..5af53340da6f 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -131,6 +131,7 @@ enum sony_nc_rfkill {
131 N_SONY_RFKILL, 131 N_SONY_RFKILL,
132}; 132};
133 133
134static int sony_rfkill_handle;
134static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL]; 135static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL];
135static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900}; 136static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900};
136static void sony_nc_rfkill_update(void); 137static void sony_nc_rfkill_update(void);
@@ -142,7 +143,7 @@ struct sony_laptop_input_s {
142 atomic_t users; 143 atomic_t users;
143 struct input_dev *jog_dev; 144 struct input_dev *jog_dev;
144 struct input_dev *key_dev; 145 struct input_dev *key_dev;
145 struct kfifo *fifo; 146 struct kfifo fifo;
146 spinlock_t fifo_lock; 147 spinlock_t fifo_lock;
147 struct workqueue_struct *wq; 148 struct workqueue_struct *wq;
148}; 149};
@@ -232,6 +233,7 @@ static int sony_laptop_input_index[] = {
232 56, /* 69 SONYPI_EVENT_VOLUME_INC_PRESSED */ 233 56, /* 69 SONYPI_EVENT_VOLUME_INC_PRESSED */
233 57, /* 70 SONYPI_EVENT_VOLUME_DEC_PRESSED */ 234 57, /* 70 SONYPI_EVENT_VOLUME_DEC_PRESSED */
234 -1, /* 71 SONYPI_EVENT_BRIGHTNESS_PRESSED */ 235 -1, /* 71 SONYPI_EVENT_BRIGHTNESS_PRESSED */
236 58, /* 72 SONYPI_EVENT_MEDIA_PRESSED */
235}; 237};
236 238
237static int sony_laptop_input_keycode_map[] = { 239static int sony_laptop_input_keycode_map[] = {
@@ -293,6 +295,7 @@ static int sony_laptop_input_keycode_map[] = {
293 KEY_F15, /* 55 SONYPI_EVENT_SETTINGKEY_PRESSED */ 295 KEY_F15, /* 55 SONYPI_EVENT_SETTINGKEY_PRESSED */
294 KEY_VOLUMEUP, /* 56 SONYPI_EVENT_VOLUME_INC_PRESSED */ 296 KEY_VOLUMEUP, /* 56 SONYPI_EVENT_VOLUME_INC_PRESSED */
295 KEY_VOLUMEDOWN, /* 57 SONYPI_EVENT_VOLUME_DEC_PRESSED */ 297 KEY_VOLUMEDOWN, /* 57 SONYPI_EVENT_VOLUME_DEC_PRESSED */
298 KEY_MEDIA, /* 58 SONYPI_EVENT_MEDIA_PRESSED */
296}; 299};
297 300
298/* release buttons after a short delay if pressed */ 301/* release buttons after a short delay if pressed */
@@ -300,8 +303,9 @@ static void do_sony_laptop_release_key(struct work_struct *work)
300{ 303{
301 struct sony_laptop_keypress kp; 304 struct sony_laptop_keypress kp;
302 305
303 while (kfifo_get(sony_laptop_input.fifo, (unsigned char *)&kp, 306 while (kfifo_out_locked(&sony_laptop_input.fifo, (unsigned char *)&kp,
304 sizeof(kp)) == sizeof(kp)) { 307 sizeof(kp), &sony_laptop_input.fifo_lock)
308 == sizeof(kp)) {
305 msleep(10); 309 msleep(10);
306 input_report_key(kp.dev, kp.key, 0); 310 input_report_key(kp.dev, kp.key, 0);
307 input_sync(kp.dev); 311 input_sync(kp.dev);
@@ -362,8 +366,9 @@ static void sony_laptop_report_input_event(u8 event)
362 /* we emit the scancode so we can always remap the key */ 366 /* we emit the scancode so we can always remap the key */
363 input_event(kp.dev, EV_MSC, MSC_SCAN, event); 367 input_event(kp.dev, EV_MSC, MSC_SCAN, event);
364 input_sync(kp.dev); 368 input_sync(kp.dev);
365 kfifo_put(sony_laptop_input.fifo, 369 kfifo_in_locked(&sony_laptop_input.fifo,
366 (unsigned char *)&kp, sizeof(kp)); 370 (unsigned char *)&kp, sizeof(kp),
371 &sony_laptop_input.fifo_lock);
367 372
368 if (!work_pending(&sony_laptop_release_key_work)) 373 if (!work_pending(&sony_laptop_release_key_work))
369 queue_work(sony_laptop_input.wq, 374 queue_work(sony_laptop_input.wq,
@@ -385,12 +390,10 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)
385 390
386 /* kfifo */ 391 /* kfifo */
387 spin_lock_init(&sony_laptop_input.fifo_lock); 392 spin_lock_init(&sony_laptop_input.fifo_lock);
388 sony_laptop_input.fifo = 393 error =
389 kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL, 394 kfifo_alloc(&sony_laptop_input.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
390 &sony_laptop_input.fifo_lock); 395 if (error) {
391 if (IS_ERR(sony_laptop_input.fifo)) {
392 printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); 396 printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
393 error = PTR_ERR(sony_laptop_input.fifo);
394 goto err_dec_users; 397 goto err_dec_users;
395 } 398 }
396 399
@@ -474,7 +477,7 @@ err_destroy_wq:
474 destroy_workqueue(sony_laptop_input.wq); 477 destroy_workqueue(sony_laptop_input.wq);
475 478
476err_free_kfifo: 479err_free_kfifo:
477 kfifo_free(sony_laptop_input.fifo); 480 kfifo_free(&sony_laptop_input.fifo);
478 481
479err_dec_users: 482err_dec_users:
480 atomic_dec(&sony_laptop_input.users); 483 atomic_dec(&sony_laptop_input.users);
@@ -500,7 +503,7 @@ static void sony_laptop_remove_input(void)
500 } 503 }
501 504
502 destroy_workqueue(sony_laptop_input.wq); 505 destroy_workqueue(sony_laptop_input.wq);
503 kfifo_free(sony_laptop_input.fifo); 506 kfifo_free(&sony_laptop_input.fifo);
504} 507}
505 508
506/*********** Platform Device ***********/ 509/*********** Platform Device ***********/
@@ -890,6 +893,8 @@ static struct sony_nc_event sony_100_events[] = {
890 { 0x0C, SONYPI_EVENT_FNKEY_RELEASED }, 893 { 0x0C, SONYPI_EVENT_FNKEY_RELEASED },
891 { 0x9f, SONYPI_EVENT_CD_EJECT_PRESSED }, 894 { 0x9f, SONYPI_EVENT_CD_EJECT_PRESSED },
892 { 0x1f, SONYPI_EVENT_ANYBUTTON_RELEASED }, 895 { 0x1f, SONYPI_EVENT_ANYBUTTON_RELEASED },
896 { 0xa1, SONYPI_EVENT_MEDIA_PRESSED },
897 { 0x21, SONYPI_EVENT_ANYBUTTON_RELEASED },
893 { 0, 0 }, 898 { 0, 0 },
894}; 899};
895 900
@@ -961,7 +966,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
961 else 966 else
962 sony_laptop_report_input_event(ev); 967 sony_laptop_report_input_event(ev);
963 } 968 }
964 } else if (sony_find_snc_handle(0x124) == ev) { 969 } else if (sony_find_snc_handle(sony_rfkill_handle) == ev) {
965 sony_nc_rfkill_update(); 970 sony_nc_rfkill_update();
966 return; 971 return;
967 } 972 }
@@ -1067,7 +1072,7 @@ static int sony_nc_rfkill_set(void *data, bool blocked)
1067 if (!blocked) 1072 if (!blocked)
1068 argument |= 0xff0000; 1073 argument |= 0xff0000;
1069 1074
1070 return sony_call_snc_handle(0x124, argument, &result); 1075 return sony_call_snc_handle(sony_rfkill_handle, argument, &result);
1071} 1076}
1072 1077
1073static const struct rfkill_ops sony_rfkill_ops = { 1078static const struct rfkill_ops sony_rfkill_ops = {
@@ -1110,7 +1115,7 @@ static int sony_nc_setup_rfkill(struct acpi_device *device,
1110 if (!rfk) 1115 if (!rfk)
1111 return -ENOMEM; 1116 return -ENOMEM;
1112 1117
1113 sony_call_snc_handle(0x124, 0x200, &result); 1118 sony_call_snc_handle(sony_rfkill_handle, 0x200, &result);
1114 hwblock = !(result & 0x1); 1119 hwblock = !(result & 0x1);
1115 rfkill_set_hw_state(rfk, hwblock); 1120 rfkill_set_hw_state(rfk, hwblock);
1116 1121
@@ -1129,7 +1134,7 @@ static void sony_nc_rfkill_update()
1129 int result; 1134 int result;
1130 bool hwblock; 1135 bool hwblock;
1131 1136
1132 sony_call_snc_handle(0x124, 0x200, &result); 1137 sony_call_snc_handle(sony_rfkill_handle, 0x200, &result);
1133 hwblock = !(result & 0x1); 1138 hwblock = !(result & 0x1);
1134 1139
1135 for (i = 0; i < N_SONY_RFKILL; i++) { 1140 for (i = 0; i < N_SONY_RFKILL; i++) {
@@ -1145,36 +1150,79 @@ static void sony_nc_rfkill_update()
1145 continue; 1150 continue;
1146 } 1151 }
1147 1152
1148 sony_call_snc_handle(0x124, argument, &result); 1153 sony_call_snc_handle(sony_rfkill_handle, argument, &result);
1149 rfkill_set_states(sony_rfkill_devices[i], 1154 rfkill_set_states(sony_rfkill_devices[i],
1150 !(result & 0xf), false); 1155 !(result & 0xf), false);
1151 } 1156 }
1152} 1157}
1153 1158
1154static int sony_nc_rfkill_setup(struct acpi_device *device) 1159static void sony_nc_rfkill_setup(struct acpi_device *device)
1155{ 1160{
1156 int result, ret; 1161 int offset;
1162 u8 dev_code, i;
1163 acpi_status status;
1164 struct acpi_object_list params;
1165 union acpi_object in_obj;
1166 union acpi_object *device_enum;
1167 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
1157 1168
1158 if (sony_find_snc_handle(0x124) == -1) 1169 offset = sony_find_snc_handle(0x124);
1159 return -1; 1170 if (offset == -1) {
1171 offset = sony_find_snc_handle(0x135);
1172 if (offset == -1)
1173 return;
1174 else
1175 sony_rfkill_handle = 0x135;
1176 } else
1177 sony_rfkill_handle = 0x124;
1178 dprintk("Found rkfill handle: 0x%.4x\n", sony_rfkill_handle);
1160 1179
1161 ret = sony_call_snc_handle(0x124, 0xb00, &result); 1180 /* need to read the whole buffer returned by the acpi call to SN06
1162 if (ret) { 1181 * here otherwise we may miss some features
1163 printk(KERN_INFO DRV_PFX 1182 */
1164 "Unable to enumerate rfkill devices: %x\n", ret); 1183 params.count = 1;
1165 return ret; 1184 params.pointer = &in_obj;
1185 in_obj.type = ACPI_TYPE_INTEGER;
1186 in_obj.integer.value = offset;
1187 status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", &params,
1188 &buffer);
1189 if (ACPI_FAILURE(status)) {
1190 dprintk("Radio device enumeration failed\n");
1191 return;
1192 }
1193
1194 device_enum = (union acpi_object *) buffer.pointer;
1195 if (!device_enum || device_enum->type != ACPI_TYPE_BUFFER) {
1196 printk(KERN_ERR "Invalid SN06 return object 0x%.2x\n",
1197 device_enum->type);
1198 goto out_no_enum;
1166 } 1199 }
1167 1200
1168 if (result & 0x1) 1201 /* the buffer is filled with magic numbers describing the devices
1169 sony_nc_setup_rfkill(device, SONY_WIFI); 1202 * available, 0xff terminates the enumeration
1170 if (result & 0x2) 1203 */
1171 sony_nc_setup_rfkill(device, SONY_BLUETOOTH); 1204 while ((dev_code = *(device_enum->buffer.pointer + i)) != 0xff &&
1172 if (result & 0x1c) 1205 i < device_enum->buffer.length) {
1173 sony_nc_setup_rfkill(device, SONY_WWAN); 1206 i++;
1174 if (result & 0x20) 1207 dprintk("Radio devices, looking at 0x%.2x\n", dev_code);
1175 sony_nc_setup_rfkill(device, SONY_WIMAX);
1176 1208
1177 return 0; 1209 if (dev_code == 0 && !sony_rfkill_devices[SONY_WIFI])
1210 sony_nc_setup_rfkill(device, SONY_WIFI);
1211
1212 if (dev_code == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH])
1213 sony_nc_setup_rfkill(device, SONY_BLUETOOTH);
1214
1215 if ((0xf0 & dev_code) == 0x20 &&
1216 !sony_rfkill_devices[SONY_WWAN])
1217 sony_nc_setup_rfkill(device, SONY_WWAN);
1218
1219 if (dev_code == 0x30 && !sony_rfkill_devices[SONY_WIMAX])
1220 sony_nc_setup_rfkill(device, SONY_WIMAX);
1221 }
1222
1223out_no_enum:
1224 kfree(buffer.pointer);
1225 return;
1178} 1226}
1179 1227
1180static int sony_nc_add(struct acpi_device *device) 1228static int sony_nc_add(struct acpi_device *device)
@@ -2079,7 +2127,7 @@ static struct attribute_group spic_attribute_group = {
2079 2127
2080struct sonypi_compat_s { 2128struct sonypi_compat_s {
2081 struct fasync_struct *fifo_async; 2129 struct fasync_struct *fifo_async;
2082 struct kfifo *fifo; 2130 struct kfifo fifo;
2083 spinlock_t fifo_lock; 2131 spinlock_t fifo_lock;
2084 wait_queue_head_t fifo_proc_list; 2132 wait_queue_head_t fifo_proc_list;
2085 atomic_t open_count; 2133 atomic_t open_count;
@@ -2104,12 +2152,12 @@ static int sonypi_misc_open(struct inode *inode, struct file *file)
2104 /* Flush input queue on first open */ 2152 /* Flush input queue on first open */
2105 unsigned long flags; 2153 unsigned long flags;
2106 2154
2107 spin_lock_irqsave(sonypi_compat.fifo->lock, flags); 2155 spin_lock_irqsave(&sonypi_compat.fifo_lock, flags);
2108 2156
2109 if (atomic_inc_return(&sonypi_compat.open_count) == 1) 2157 if (atomic_inc_return(&sonypi_compat.open_count) == 1)
2110 __kfifo_reset(sonypi_compat.fifo); 2158 kfifo_reset(&sonypi_compat.fifo);
2111 2159
2112 spin_unlock_irqrestore(sonypi_compat.fifo->lock, flags); 2160 spin_unlock_irqrestore(&sonypi_compat.fifo_lock, flags);
2113 2161
2114 return 0; 2162 return 0;
2115} 2163}
@@ -2120,17 +2168,18 @@ static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
2120 ssize_t ret; 2168 ssize_t ret;
2121 unsigned char c; 2169 unsigned char c;
2122 2170
2123 if ((kfifo_len(sonypi_compat.fifo) == 0) && 2171 if ((kfifo_len(&sonypi_compat.fifo) == 0) &&
2124 (file->f_flags & O_NONBLOCK)) 2172 (file->f_flags & O_NONBLOCK))
2125 return -EAGAIN; 2173 return -EAGAIN;
2126 2174
2127 ret = wait_event_interruptible(sonypi_compat.fifo_proc_list, 2175 ret = wait_event_interruptible(sonypi_compat.fifo_proc_list,
2128 kfifo_len(sonypi_compat.fifo) != 0); 2176 kfifo_len(&sonypi_compat.fifo) != 0);
2129 if (ret) 2177 if (ret)
2130 return ret; 2178 return ret;
2131 2179
2132 while (ret < count && 2180 while (ret < count &&
2133 (kfifo_get(sonypi_compat.fifo, &c, sizeof(c)) == sizeof(c))) { 2181 (kfifo_out_locked(&sonypi_compat.fifo, &c, sizeof(c),
2182 &sonypi_compat.fifo_lock) == sizeof(c))) {
2134 if (put_user(c, buf++)) 2183 if (put_user(c, buf++))
2135 return -EFAULT; 2184 return -EFAULT;
2136 ret++; 2185 ret++;
@@ -2147,7 +2196,7 @@ static ssize_t sonypi_misc_read(struct file *file, char __user *buf,
2147static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait) 2196static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait)
2148{ 2197{
2149 poll_wait(file, &sonypi_compat.fifo_proc_list, wait); 2198 poll_wait(file, &sonypi_compat.fifo_proc_list, wait);
2150 if (kfifo_len(sonypi_compat.fifo)) 2199 if (kfifo_len(&sonypi_compat.fifo))
2151 return POLLIN | POLLRDNORM; 2200 return POLLIN | POLLRDNORM;
2152 return 0; 2201 return 0;
2153} 2202}
@@ -2309,7 +2358,8 @@ static struct miscdevice sonypi_misc_device = {
2309 2358
2310static void sonypi_compat_report_event(u8 event) 2359static void sonypi_compat_report_event(u8 event)
2311{ 2360{
2312 kfifo_put(sonypi_compat.fifo, (unsigned char *)&event, sizeof(event)); 2361 kfifo_in_locked(&sonypi_compat.fifo, (unsigned char *)&event,
2362 sizeof(event), &sonypi_compat.fifo_lock);
2313 kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN); 2363 kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN);
2314 wake_up_interruptible(&sonypi_compat.fifo_proc_list); 2364 wake_up_interruptible(&sonypi_compat.fifo_proc_list);
2315} 2365}
@@ -2319,11 +2369,11 @@ static int sonypi_compat_init(void)
2319 int error; 2369 int error;
2320 2370
2321 spin_lock_init(&sonypi_compat.fifo_lock); 2371 spin_lock_init(&sonypi_compat.fifo_lock);
2322 sonypi_compat.fifo = kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL, 2372 error =
2323 &sonypi_compat.fifo_lock); 2373 kfifo_alloc(&sonypi_compat.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
2324 if (IS_ERR(sonypi_compat.fifo)) { 2374 if (error) {
2325 printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); 2375 printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
2326 return PTR_ERR(sonypi_compat.fifo); 2376 return error;
2327 } 2377 }
2328 2378
2329 init_waitqueue_head(&sonypi_compat.fifo_proc_list); 2379 init_waitqueue_head(&sonypi_compat.fifo_proc_list);
@@ -2342,14 +2392,14 @@ static int sonypi_compat_init(void)
2342 return 0; 2392 return 0;
2343 2393
2344err_free_kfifo: 2394err_free_kfifo:
2345 kfifo_free(sonypi_compat.fifo); 2395 kfifo_free(&sonypi_compat.fifo);
2346 return error; 2396 return error;
2347} 2397}
2348 2398
2349static void sonypi_compat_exit(void) 2399static void sonypi_compat_exit(void)
2350{ 2400{
2351 misc_deregister(&sonypi_misc_device); 2401 misc_deregister(&sonypi_misc_device);
2352 kfifo_free(sonypi_compat.fifo); 2402 kfifo_free(&sonypi_compat.fifo);
2353} 2403}
2354#else 2404#else
2355static int sonypi_compat_init(void) { return 0; } 2405static int sonypi_compat_init(void) { return 0; }