diff options
| -rw-r--r-- | drivers/hid/hid-sony.c | 149 |
1 files changed, 124 insertions, 25 deletions
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index b41356cacc14..243722bbc3ed 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c | |||
| @@ -773,6 +773,8 @@ struct sony_sc { | |||
| 773 | __u8 battery_charging; | 773 | __u8 battery_charging; |
| 774 | __u8 battery_capacity; | 774 | __u8 battery_capacity; |
| 775 | __u8 led_state[MAX_LEDS]; | 775 | __u8 led_state[MAX_LEDS]; |
| 776 | __u8 led_delay_on[MAX_LEDS]; | ||
| 777 | __u8 led_delay_off[MAX_LEDS]; | ||
| 776 | __u8 led_count; | 778 | __u8 led_count; |
| 777 | }; | 779 | }; |
| 778 | 780 | ||
| @@ -1168,6 +1170,7 @@ static void sony_led_set_brightness(struct led_classdev *led, | |||
| 1168 | struct sony_sc *drv_data; | 1170 | struct sony_sc *drv_data; |
| 1169 | 1171 | ||
| 1170 | int n; | 1172 | int n; |
| 1173 | int force_update; | ||
| 1171 | 1174 | ||
| 1172 | drv_data = hid_get_drvdata(hdev); | 1175 | drv_data = hid_get_drvdata(hdev); |
| 1173 | if (!drv_data) { | 1176 | if (!drv_data) { |
| @@ -1175,13 +1178,29 @@ static void sony_led_set_brightness(struct led_classdev *led, | |||
| 1175 | return; | 1178 | return; |
| 1176 | } | 1179 | } |
| 1177 | 1180 | ||
| 1181 | /* | ||
| 1182 | * The Sixaxis on USB will override any LED settings sent to it | ||
| 1183 | * and keep flashing all of the LEDs until the PS button is pressed. | ||
| 1184 | * Updates, even if redundant, must be always be sent to the | ||
| 1185 | * controller to avoid having to toggle the state of an LED just to | ||
| 1186 | * stop the flashing later on. | ||
| 1187 | */ | ||
| 1188 | force_update = !!(drv_data->quirks & SIXAXIS_CONTROLLER_USB); | ||
| 1189 | |||
| 1178 | for (n = 0; n < drv_data->led_count; n++) { | 1190 | for (n = 0; n < drv_data->led_count; n++) { |
| 1179 | if (led == drv_data->leds[n]) { | 1191 | if (led == drv_data->leds[n] && (force_update || |
| 1180 | if (value != drv_data->led_state[n]) { | 1192 | (value != drv_data->led_state[n] || |
| 1181 | drv_data->led_state[n] = value; | 1193 | drv_data->led_delay_on[n] || |
| 1182 | sony_set_leds(drv_data, drv_data->led_state, | 1194 | drv_data->led_delay_off[n]))) { |
| 1183 | drv_data->led_count); | 1195 | |
| 1184 | } | 1196 | drv_data->led_state[n] = value; |
| 1197 | |||
| 1198 | /* Setting the brightness stops the blinking */ | ||
| 1199 | drv_data->led_delay_on[n] = 0; | ||
| 1200 | drv_data->led_delay_off[n] = 0; | ||
| 1201 | |||
| 1202 | sony_set_leds(drv_data, drv_data->led_state, | ||
| 1203 | drv_data->led_count); | ||
| 1185 | break; | 1204 | break; |
| 1186 | } | 1205 | } |
| 1187 | } | 1206 | } |
| @@ -1209,6 +1228,53 @@ static enum led_brightness sony_led_get_brightness(struct led_classdev *led) | |||
| 1209 | return LED_OFF; | 1228 | return LED_OFF; |
| 1210 | } | 1229 | } |
| 1211 | 1230 | ||
| 1231 | static int sony_led_blink_set(struct led_classdev *led, unsigned long *delay_on, | ||
| 1232 | unsigned long *delay_off) | ||
| 1233 | { | ||
| 1234 | struct device *dev = led->dev->parent; | ||
| 1235 | struct hid_device *hdev = container_of(dev, struct hid_device, dev); | ||
| 1236 | struct sony_sc *drv_data = hid_get_drvdata(hdev); | ||
| 1237 | int n; | ||
| 1238 | __u8 new_on, new_off; | ||
| 1239 | |||
| 1240 | if (!drv_data) { | ||
| 1241 | hid_err(hdev, "No device data\n"); | ||
| 1242 | return -EINVAL; | ||
| 1243 | } | ||
| 1244 | |||
| 1245 | /* Max delay is 255 deciseconds or 2550 milliseconds */ | ||
| 1246 | if (*delay_on > 2550) | ||
| 1247 | *delay_on = 2550; | ||
| 1248 | if (*delay_off > 2550) | ||
| 1249 | *delay_off = 2550; | ||
| 1250 | |||
| 1251 | /* Blink at 1 Hz if both values are zero */ | ||
| 1252 | if (!*delay_on && !*delay_off) | ||
| 1253 | *delay_on = *delay_off = 500; | ||
| 1254 | |||
| 1255 | new_on = *delay_on / 10; | ||
| 1256 | new_off = *delay_off / 10; | ||
| 1257 | |||
| 1258 | for (n = 0; n < drv_data->led_count; n++) { | ||
| 1259 | if (led == drv_data->leds[n]) | ||
| 1260 | break; | ||
| 1261 | } | ||
| 1262 | |||
| 1263 | /* This LED is not registered on this device */ | ||
| 1264 | if (n >= drv_data->led_count) | ||
| 1265 | return -EINVAL; | ||
| 1266 | |||
| 1267 | /* Don't schedule work if the values didn't change */ | ||
| 1268 | if (new_on != drv_data->led_delay_on[n] || | ||
| 1269 | new_off != drv_data->led_delay_off[n]) { | ||
| 1270 | drv_data->led_delay_on[n] = new_on; | ||
| 1271 | drv_data->led_delay_off[n] = new_off; | ||
| 1272 | schedule_work(&drv_data->state_worker); | ||
| 1273 | } | ||
| 1274 | |||
| 1275 | return 0; | ||
| 1276 | } | ||
| 1277 | |||
| 1212 | static void sony_leds_remove(struct sony_sc *sc) | 1278 | static void sony_leds_remove(struct sony_sc *sc) |
| 1213 | { | 1279 | { |
| 1214 | struct led_classdev *led; | 1280 | struct led_classdev *led; |
| @@ -1232,22 +1298,23 @@ static int sony_leds_init(struct sony_sc *sc) | |||
| 1232 | { | 1298 | { |
| 1233 | struct hid_device *hdev = sc->hdev; | 1299 | struct hid_device *hdev = sc->hdev; |
| 1234 | int n, ret = 0; | 1300 | int n, ret = 0; |
| 1235 | int max_brightness; | 1301 | int use_ds4_names; |
| 1236 | int use_colors; | ||
| 1237 | struct led_classdev *led; | 1302 | struct led_classdev *led; |
| 1238 | size_t name_sz; | 1303 | size_t name_sz; |
| 1239 | char *name; | 1304 | char *name; |
| 1240 | size_t name_len; | 1305 | size_t name_len; |
| 1241 | const char *name_fmt; | 1306 | const char *name_fmt; |
| 1242 | static const char * const color_str[] = { "red", "green", "blue" }; | 1307 | static const char * const ds4_name_str[] = { "red", "green", "blue", |
| 1308 | "global" }; | ||
| 1243 | __u8 initial_values[MAX_LEDS] = { 0 }; | 1309 | __u8 initial_values[MAX_LEDS] = { 0 }; |
| 1310 | __u8 max_brightness[MAX_LEDS] = { 1 }; | ||
| 1311 | __u8 use_hw_blink[MAX_LEDS] = { 0 }; | ||
| 1244 | 1312 | ||
| 1245 | BUG_ON(!(sc->quirks & SONY_LED_SUPPORT)); | 1313 | BUG_ON(!(sc->quirks & SONY_LED_SUPPORT)); |
| 1246 | 1314 | ||
| 1247 | if (sc->quirks & BUZZ_CONTROLLER) { | 1315 | if (sc->quirks & BUZZ_CONTROLLER) { |
| 1248 | sc->led_count = 4; | 1316 | sc->led_count = 4; |
| 1249 | max_brightness = 1; | 1317 | use_ds4_names = 0; |
| 1250 | use_colors = 0; | ||
| 1251 | name_len = strlen("::buzz#"); | 1318 | name_len = strlen("::buzz#"); |
| 1252 | name_fmt = "%s::buzz%d"; | 1319 | name_fmt = "%s::buzz%d"; |
| 1253 | /* Validate expected report characteristics. */ | 1320 | /* Validate expected report characteristics. */ |
| @@ -1255,16 +1322,18 @@ static int sony_leds_init(struct sony_sc *sc) | |||
| 1255 | return -ENODEV; | 1322 | return -ENODEV; |
| 1256 | } else if (sc->quirks & DUALSHOCK4_CONTROLLER) { | 1323 | } else if (sc->quirks & DUALSHOCK4_CONTROLLER) { |
| 1257 | dualshock4_set_leds_from_id(sc->device_id, initial_values); | 1324 | dualshock4_set_leds_from_id(sc->device_id, initial_values); |
| 1258 | sc->led_count = 3; | 1325 | initial_values[3] = 1; |
| 1259 | max_brightness = 255; | 1326 | sc->led_count = 4; |
| 1260 | use_colors = 1; | 1327 | memset(max_brightness, 255, 3); |
| 1328 | use_hw_blink[3] = 1; | ||
| 1329 | use_ds4_names = 1; | ||
| 1261 | name_len = 0; | 1330 | name_len = 0; |
| 1262 | name_fmt = "%s:%s"; | 1331 | name_fmt = "%s:%s"; |
| 1263 | } else { | 1332 | } else { |
| 1264 | sixaxis_set_leds_from_id(sc->device_id, initial_values); | 1333 | sixaxis_set_leds_from_id(sc->device_id, initial_values); |
| 1265 | sc->led_count = 4; | 1334 | sc->led_count = 4; |
| 1266 | max_brightness = 1; | 1335 | memset(use_hw_blink, 1, 4); |
| 1267 | use_colors = 0; | 1336 | use_ds4_names = 0; |
| 1268 | name_len = strlen("::sony#"); | 1337 | name_len = strlen("::sony#"); |
| 1269 | name_fmt = "%s::sony%d"; | 1338 | name_fmt = "%s::sony%d"; |
| 1270 | } | 1339 | } |
| @@ -1280,8 +1349,8 @@ static int sony_leds_init(struct sony_sc *sc) | |||
| 1280 | 1349 | ||
| 1281 | for (n = 0; n < sc->led_count; n++) { | 1350 | for (n = 0; n < sc->led_count; n++) { |
| 1282 | 1351 | ||
| 1283 | if (use_colors) | 1352 | if (use_ds4_names) |
| 1284 | name_sz = strlen(dev_name(&hdev->dev)) + strlen(color_str[n]) + 2; | 1353 | name_sz = strlen(dev_name(&hdev->dev)) + strlen(ds4_name_str[n]) + 2; |
| 1285 | 1354 | ||
| 1286 | led = kzalloc(sizeof(struct led_classdev) + name_sz, GFP_KERNEL); | 1355 | led = kzalloc(sizeof(struct led_classdev) + name_sz, GFP_KERNEL); |
| 1287 | if (!led) { | 1356 | if (!led) { |
| @@ -1291,16 +1360,20 @@ static int sony_leds_init(struct sony_sc *sc) | |||
| 1291 | } | 1360 | } |
| 1292 | 1361 | ||
| 1293 | name = (void *)(&led[1]); | 1362 | name = (void *)(&led[1]); |
| 1294 | if (use_colors) | 1363 | if (use_ds4_names) |
| 1295 | snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), color_str[n]); | 1364 | snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), |
| 1365 | ds4_name_str[n]); | ||
| 1296 | else | 1366 | else |
| 1297 | snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), n + 1); | 1367 | snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), n + 1); |
| 1298 | led->name = name; | 1368 | led->name = name; |
| 1299 | led->brightness = initial_values[n]; | 1369 | led->brightness = initial_values[n]; |
| 1300 | led->max_brightness = max_brightness; | 1370 | led->max_brightness = max_brightness[n]; |
| 1301 | led->brightness_get = sony_led_get_brightness; | 1371 | led->brightness_get = sony_led_get_brightness; |
| 1302 | led->brightness_set = sony_led_set_brightness; | 1372 | led->brightness_set = sony_led_set_brightness; |
| 1303 | 1373 | ||
| 1374 | if (use_hw_blink[n]) | ||
| 1375 | led->blink_set = sony_led_blink_set; | ||
| 1376 | |||
| 1304 | sc->leds[n] = led; | 1377 | sc->leds[n] = led; |
| 1305 | 1378 | ||
| 1306 | ret = led_classdev_register(&hdev->dev, led); | 1379 | ret = led_classdev_register(&hdev->dev, led); |
| @@ -1323,6 +1396,7 @@ error_leds: | |||
| 1323 | static void sixaxis_state_worker(struct work_struct *work) | 1396 | static void sixaxis_state_worker(struct work_struct *work) |
| 1324 | { | 1397 | { |
| 1325 | struct sony_sc *sc = container_of(work, struct sony_sc, state_worker); | 1398 | struct sony_sc *sc = container_of(work, struct sony_sc, state_worker); |
| 1399 | int n; | ||
| 1326 | union sixaxis_output_report_01 report = { | 1400 | union sixaxis_output_report_01 report = { |
| 1327 | .buf = { | 1401 | .buf = { |
| 1328 | 0x01, | 1402 | 0x01, |
| @@ -1346,6 +1420,22 @@ static void sixaxis_state_worker(struct work_struct *work) | |||
| 1346 | report.data.leds_bitmap |= sc->led_state[2] << 3; | 1420 | report.data.leds_bitmap |= sc->led_state[2] << 3; |
| 1347 | report.data.leds_bitmap |= sc->led_state[3] << 4; | 1421 | report.data.leds_bitmap |= sc->led_state[3] << 4; |
| 1348 | 1422 | ||
| 1423 | /* | ||
| 1424 | * The LEDs in the report are indexed in reverse order to their | ||
| 1425 | * corresponding light on the controller. | ||
| 1426 | * Index 0 = LED 4, index 1 = LED 3, etc... | ||
| 1427 | * | ||
| 1428 | * In the case of both delay values being zero (blinking disabled) the | ||
| 1429 | * default report values should be used or the controller LED will be | ||
| 1430 | * always off. | ||
| 1431 | */ | ||
| 1432 | for (n = 0; n < 4; n++) { | ||
| 1433 | if (sc->led_delay_on[n] || sc->led_delay_off[n]) { | ||
| 1434 | report.data.led[3 - n].duty_off = sc->led_delay_off[n]; | ||
| 1435 | report.data.led[3 - n].duty_on = sc->led_delay_on[n]; | ||
| 1436 | } | ||
| 1437 | } | ||
| 1438 | |||
| 1349 | hid_hw_raw_request(sc->hdev, report.data.report_id, report.buf, | 1439 | hid_hw_raw_request(sc->hdev, report.data.report_id, report.buf, |
| 1350 | sizeof(report), HID_OUTPUT_REPORT, HID_REQ_SET_REPORT); | 1440 | sizeof(report), HID_OUTPUT_REPORT, HID_REQ_SET_REPORT); |
| 1351 | } | 1441 | } |
| @@ -1360,7 +1450,7 @@ static void dualshock4_state_worker(struct work_struct *work) | |||
| 1360 | 1450 | ||
| 1361 | if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) { | 1451 | if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) { |
| 1362 | buf[0] = 0x05; | 1452 | buf[0] = 0x05; |
| 1363 | buf[1] = 0x03; | 1453 | buf[1] = 0xFF; |
| 1364 | offset = 4; | 1454 | offset = 4; |
| 1365 | } else { | 1455 | } else { |
| 1366 | buf[0] = 0x11; | 1456 | buf[0] = 0x11; |
| @@ -1376,9 +1466,18 @@ static void dualshock4_state_worker(struct work_struct *work) | |||
| 1376 | offset += 2; | 1466 | offset += 2; |
| 1377 | #endif | 1467 | #endif |
| 1378 | 1468 | ||
| 1379 | buf[offset++] = sc->led_state[0]; | 1469 | /* LED 3 is the global control */ |
| 1380 | buf[offset++] = sc->led_state[1]; | 1470 | if (sc->led_state[3]) { |
| 1381 | buf[offset++] = sc->led_state[2]; | 1471 | buf[offset++] = sc->led_state[0]; |
| 1472 | buf[offset++] = sc->led_state[1]; | ||
| 1473 | buf[offset++] = sc->led_state[2]; | ||
| 1474 | } else { | ||
| 1475 | offset += 3; | ||
| 1476 | } | ||
| 1477 | |||
| 1478 | /* If both delay values are zero the DualShock 4 disables blinking. */ | ||
| 1479 | buf[offset++] = sc->led_delay_on[3]; | ||
| 1480 | buf[offset++] = sc->led_delay_off[3]; | ||
| 1382 | 1481 | ||
| 1383 | if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) | 1482 | if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) |
| 1384 | hid_hw_output_report(hdev, buf, 32); | 1483 | hid_hw_output_report(hdev, buf, 32); |
