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 /drivers/misc/sony-laptop.c | |
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>
Diffstat (limited to 'drivers/misc/sony-laptop.c')
-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 | ||