diff options
| author | malattia@linux.it <malattia@linux.it> | 2007-04-09 13:28:56 -0400 |
|---|---|---|
| committer | Len Brown <len.brown@intel.com> | 2007-04-10 16:01:19 -0400 |
| commit | 49a11deade3c1d9e2d7c88d25899b3a9174d048e (patch) | |
| tree | 61088ddf15aac99aea8343d070393ade5d3d17e9 | |
| parent | 1549ee6fb122400c0767b5f3da2c42abbc4f750a (diff) | |
sony-laptop: additional platform attributes coming from SNY6001
Register additional platform attributes coming from the SPIC (sonypi) driver.
Signed-off-by: Mattia Dongili <malattia@linux.it>
Signed-off-by: Len Brown <len.brown@intel.com>
| -rw-r--r-- | drivers/misc/sony-laptop.c | 205 |
1 files changed, 204 insertions, 1 deletions
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c index cf8d7927dc5c..3e8f3aaa0923 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c | |||
| @@ -774,7 +774,8 @@ static int sony_nc_add(struct acpi_device *device) | |||
| 774 | 774 | ||
| 775 | } | 775 | } |
| 776 | 776 | ||
| 777 | if (sony_pf_add()) | 777 | result = sony_pf_add(); |
| 778 | if (result) | ||
| 778 | goto outbacklight; | 779 | goto outbacklight; |
| 779 | 780 | ||
| 780 | /* create sony_pf sysfs attributes related to the SNC device */ | 781 | /* create sony_pf sysfs attributes related to the SNC device */ |
| @@ -903,6 +904,8 @@ struct sony_pic_irq { | |||
| 903 | 904 | ||
| 904 | struct sony_pic_dev { | 905 | struct sony_pic_dev { |
| 905 | int model; | 906 | int model; |
| 907 | u8 camera_power; | ||
| 908 | u8 bluetooth_power; | ||
| 906 | struct acpi_device *acpi_dev; | 909 | struct acpi_device *acpi_dev; |
| 907 | struct sony_pic_irq *cur_irq; | 910 | struct sony_pic_irq *cur_irq; |
| 908 | struct sony_pic_ioport *cur_ioport; | 911 | struct sony_pic_ioport *cur_ioport; |
| @@ -1181,6 +1184,186 @@ static u8 sony_pic_call2(u8 dev, u8 fn) | |||
| 1181 | return v1; | 1184 | return v1; |
| 1182 | } | 1185 | } |
| 1183 | 1186 | ||
| 1187 | static u8 sony_pic_call3(u8 dev, u8 fn, u8 v) | ||
| 1188 | { | ||
| 1189 | u8 v1; | ||
| 1190 | |||
| 1191 | wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG); | ||
| 1192 | outb(dev, spic_dev.cur_ioport->io.minimum + 4); | ||
| 1193 | wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG); | ||
| 1194 | outb(fn, spic_dev.cur_ioport->io.minimum); | ||
| 1195 | wait_on_command(inb_p(spic_dev.cur_ioport->io.minimum + 4) & 2, ITERATIONS_LONG); | ||
| 1196 | outb(v, spic_dev.cur_ioport->io.minimum); | ||
| 1197 | v1 = inb_p(spic_dev.cur_ioport->io.minimum); | ||
| 1198 | dprintk("sony_pic_call3: 0x%.4x\n", v1); | ||
| 1199 | return v1; | ||
| 1200 | } | ||
| 1201 | |||
| 1202 | /* camera tests and poweron/poweroff */ | ||
| 1203 | #define SONYPI_CAMERA_PICTURE 5 | ||
| 1204 | #define SONYPI_CAMERA_MUTE_MASK 0x40 | ||
| 1205 | #define SONYPI_CAMERA_CONTROL 0x10 | ||
| 1206 | #define SONYPI_CAMERA_STATUS 7 | ||
| 1207 | #define SONYPI_CAMERA_STATUS_READY 0x2 | ||
| 1208 | #define SONYPI_CAMERA_STATUS_POSITION 0x4 | ||
| 1209 | |||
| 1210 | static int sony_pic_camera_ready(void) | ||
| 1211 | { | ||
| 1212 | u8 v; | ||
| 1213 | |||
| 1214 | v = sony_pic_call2(0x8f, SONYPI_CAMERA_STATUS); | ||
| 1215 | return (v != 0xff && (v & SONYPI_CAMERA_STATUS_READY)); | ||
| 1216 | } | ||
| 1217 | |||
| 1218 | static void sony_pic_camera_off(void) | ||
| 1219 | { | ||
| 1220 | wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE, | ||
| 1221 | SONYPI_CAMERA_MUTE_MASK), | ||
| 1222 | ITERATIONS_SHORT); | ||
| 1223 | |||
| 1224 | if (!spic_dev.camera_power) | ||
| 1225 | return; | ||
| 1226 | |||
| 1227 | sony_pic_call2(0x91, 0); | ||
| 1228 | spic_dev.camera_power = 0; | ||
| 1229 | } | ||
| 1230 | |||
| 1231 | static void sony_pic_camera_on(void) | ||
| 1232 | { | ||
| 1233 | int i, j; | ||
| 1234 | |||
| 1235 | if (spic_dev.camera_power) | ||
| 1236 | return; | ||
| 1237 | |||
| 1238 | for (j = 5; j > 0; j--) { | ||
| 1239 | |||
| 1240 | while (sony_pic_call2(0x91, 0x1)) | ||
| 1241 | msleep(10); | ||
| 1242 | sony_pic_call1(0x93); | ||
| 1243 | |||
| 1244 | for (i = 400; i > 0; i--) { | ||
| 1245 | if (sony_pic_camera_ready()) | ||
| 1246 | break; | ||
| 1247 | msleep(10); | ||
| 1248 | } | ||
| 1249 | if (i) | ||
| 1250 | break; | ||
| 1251 | } | ||
| 1252 | |||
| 1253 | if (j == 0) { | ||
| 1254 | printk(KERN_WARNING "sonypi: failed to power on camera\n"); | ||
| 1255 | return; | ||
| 1256 | } | ||
| 1257 | |||
| 1258 | wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTROL, | ||
| 1259 | 0x5a), | ||
| 1260 | ITERATIONS_SHORT); | ||
| 1261 | |||
| 1262 | spic_dev.camera_power = 1; | ||
| 1263 | } | ||
| 1264 | |||
| 1265 | static ssize_t sony_pic_camerapower_store(struct device *dev, | ||
| 1266 | struct device_attribute *attr, | ||
| 1267 | const char *buffer, size_t count) | ||
| 1268 | { | ||
| 1269 | unsigned long value; | ||
| 1270 | if (count > 31) | ||
| 1271 | return -EINVAL; | ||
| 1272 | |||
| 1273 | value = simple_strtoul(buffer, NULL, 10); | ||
| 1274 | if (value) | ||
| 1275 | sony_pic_camera_on(); | ||
| 1276 | else | ||
| 1277 | sony_pic_camera_off(); | ||
| 1278 | |||
| 1279 | return count; | ||
| 1280 | } | ||
| 1281 | |||
| 1282 | static ssize_t sony_pic_camerapower_show(struct device *dev, | ||
| 1283 | struct device_attribute *attr, char *buffer) | ||
| 1284 | { | ||
| 1285 | return snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.camera_power); | ||
| 1286 | } | ||
| 1287 | |||
| 1288 | /* bluetooth subsystem power state */ | ||
| 1289 | static void sony_pic_set_bluetoothpower(u8 state) | ||
| 1290 | { | ||
| 1291 | state = !!state; | ||
| 1292 | if (spic_dev.bluetooth_power == state) | ||
| 1293 | return; | ||
| 1294 | sony_pic_call2(0x96, state); | ||
| 1295 | sony_pic_call1(0x82); | ||
| 1296 | spic_dev.bluetooth_power = state; | ||
| 1297 | } | ||
| 1298 | |||
| 1299 | static ssize_t sony_pic_bluetoothpower_store(struct device *dev, | ||
| 1300 | struct device_attribute *attr, | ||
| 1301 | const char *buffer, size_t count) | ||
| 1302 | { | ||
| 1303 | unsigned long value; | ||
| 1304 | if (count > 31) | ||
| 1305 | return -EINVAL; | ||
| 1306 | |||
| 1307 | value = simple_strtoul(buffer, NULL, 10); | ||
| 1308 | sony_pic_set_bluetoothpower(value); | ||
| 1309 | |||
| 1310 | return count; | ||
| 1311 | } | ||
| 1312 | |||
| 1313 | static ssize_t sony_pic_bluetoothpower_show(struct device *dev, | ||
| 1314 | struct device_attribute *attr, char *buffer) | ||
| 1315 | { | ||
| 1316 | return snprintf(buffer, PAGE_SIZE, "%d\n", spic_dev.bluetooth_power); | ||
| 1317 | } | ||
| 1318 | |||
| 1319 | /* fan speed */ | ||
| 1320 | /* FAN0 information (reverse engineered from ACPI tables) */ | ||
| 1321 | #define SONY_PIC_FAN0_STATUS 0x93 | ||
| 1322 | static ssize_t sony_pic_fanspeed_store(struct device *dev, | ||
| 1323 | struct device_attribute *attr, | ||
| 1324 | const char *buffer, size_t count) | ||
| 1325 | { | ||
| 1326 | unsigned long value; | ||
| 1327 | if (count > 31) | ||
| 1328 | return -EINVAL; | ||
| 1329 | |||
| 1330 | value = simple_strtoul(buffer, NULL, 10); | ||
| 1331 | if (ec_write(SONY_PIC_FAN0_STATUS, value)) | ||
| 1332 | return -EIO; | ||
| 1333 | |||
| 1334 | return count; | ||
| 1335 | } | ||
| 1336 | |||
| 1337 | static ssize_t sony_pic_fanspeed_show(struct device *dev, | ||
| 1338 | struct device_attribute *attr, char *buffer) | ||
| 1339 | { | ||
| 1340 | u8 value = 0; | ||
| 1341 | if (ec_read(SONY_PIC_FAN0_STATUS, &value)) | ||
| 1342 | return -EIO; | ||
| 1343 | |||
| 1344 | return snprintf(buffer, PAGE_SIZE, "%d\n", value); | ||
| 1345 | } | ||
| 1346 | |||
| 1347 | #define SPIC_ATTR(_name, _mode) \ | ||
| 1348 | struct device_attribute spic_attr_##_name = __ATTR(_name, \ | ||
| 1349 | _mode, sony_pic_## _name ##_show, \ | ||
| 1350 | sony_pic_## _name ##_store) | ||
| 1351 | |||
| 1352 | static SPIC_ATTR(camerapower, 0644); | ||
| 1353 | static SPIC_ATTR(bluetoothpower, 0644); | ||
| 1354 | static SPIC_ATTR(fanspeed, 0644); | ||
| 1355 | |||
| 1356 | static struct attribute *spic_attributes[] = { | ||
| 1357 | &spic_attr_camerapower.attr, | ||
| 1358 | &spic_attr_bluetoothpower.attr, | ||
| 1359 | &spic_attr_fanspeed.attr, | ||
| 1360 | NULL | ||
| 1361 | }; | ||
| 1362 | |||
| 1363 | static struct attribute_group spic_attribute_group = { | ||
| 1364 | .attrs = spic_attributes | ||
| 1365 | }; | ||
| 1366 | |||
| 1184 | /* | 1367 | /* |
| 1185 | * ACPI callbacks | 1368 | * ACPI callbacks |
| 1186 | */ | 1369 | */ |
| @@ -1447,6 +1630,10 @@ static int sony_pic_remove(struct acpi_device *device, int type) | |||
| 1447 | 1630 | ||
| 1448 | sony_laptop_remove_input(); | 1631 | sony_laptop_remove_input(); |
| 1449 | 1632 | ||
| 1633 | /* pf attrs */ | ||
| 1634 | sysfs_remove_group(&sony_pf_device->dev.kobj, &spic_attribute_group); | ||
| 1635 | sony_pf_remove(); | ||
| 1636 | |||
| 1450 | list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) { | 1637 | list_for_each_entry_safe(io, tmp_io, &spic_dev.ioports, list) { |
| 1451 | list_del(&io->list); | 1638 | list_del(&io->list); |
| 1452 | kfree(io); | 1639 | kfree(io); |
| @@ -1536,8 +1723,24 @@ static int sony_pic_add(struct acpi_device *device) | |||
| 1536 | goto err_free_irq; | 1723 | goto err_free_irq; |
| 1537 | } | 1724 | } |
| 1538 | 1725 | ||
| 1726 | spic_dev.bluetooth_power = -1; | ||
| 1727 | /* create device attributes */ | ||
| 1728 | result = sony_pf_add(); | ||
| 1729 | if (result) | ||
| 1730 | goto err_disable_device; | ||
| 1731 | |||
| 1732 | result = sysfs_create_group(&sony_pf_device->dev.kobj, &spic_attribute_group); | ||
| 1733 | if (result) | ||
| 1734 | goto err_remove_pf; | ||
| 1735 | |||
| 1539 | return 0; | 1736 | return 0; |
| 1540 | 1737 | ||
| 1738 | err_remove_pf: | ||
| 1739 | sony_pf_remove(); | ||
| 1740 | |||
| 1741 | err_disable_device: | ||
| 1742 | sony_pic_disable(device); | ||
| 1743 | |||
| 1541 | err_free_irq: | 1744 | err_free_irq: |
| 1542 | free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev); | 1745 | free_irq(spic_dev.cur_irq->irq.interrupts[0], &spic_dev); |
| 1543 | 1746 | ||
