diff options
author | Richard Hughes <richard@hughsie.com> | 2015-05-27 10:36:35 +0100 |
---|---|---|
committer | Richard Hughes <richard@hughsie.com> | 2015-05-28 08:43:26 +0100 |
commit | eb14cf6ee090ba953b819d28bb2def6f86130555 (patch) | |
tree | f6536861974ff6652165f52c42d718f109fbd18b | |
parent | 8a9cd0cfbcfe80623a258fd8d0fea7d788d395bb (diff) | |
download | colord-eb14cf6ee090ba953b819d28bb2def6f86130555.tar.gz |
colorhug: Handle low-level commands when in Sensor HID mode
-rw-r--r-- | lib/colorhug/ch-common.h | 1 | ||||
-rw-r--r-- | lib/colorhug/ch-device.c | 262 | ||||
-rw-r--r-- | lib/colorhug/ch-self-test.c | 35 | ||||
-rw-r--r-- | rules/69-cd-sensors.rules.in | 1 |
4 files changed, 295 insertions, 4 deletions
diff --git a/lib/colorhug/ch-common.h b/lib/colorhug/ch-common.h index f58abce..bcf1c65 100644 --- a/lib/colorhug/ch-common.h +++ b/lib/colorhug/ch-common.h @@ -40,6 +40,7 @@ G_BEGIN_DECLS #define CH_USB_PID_FIRMWARE 0x1001 #define CH_USB_PID_FIRMWARE2 0x1004 #define CH_USB_PID_FIRMWARE_ALS 0x1007 /* since 1.2.9 */ +#define CH_USB_PID_FIRMWARE_ALS_SENSOR_HID 0x1008 /* since 1.2.11 */ #define CH_USB_PID_FIRMWARE_PLUS 0x1002 #define CH_USB_CONFIG 0x0001 #define CH_USB_INTERFACE 0x0000 diff --git a/lib/colorhug/ch-device.c b/lib/colorhug/ch-device.c index 0ef05b8..0063f44 100644 --- a/lib/colorhug/ch-device.c +++ b/lib/colorhug/ch-device.c @@ -125,6 +125,7 @@ ch_device_get_mode (GUsbDevice *device) state = CH_DEVICE_MODE_FIRMWARE_PLUS; break; case CH_USB_PID_FIRMWARE_ALS: + case CH_USB_PID_FIRMWARE_ALS_SENSOR_HID: state = CH_DEVICE_MODE_FIRMWARE_ALS; break; default: @@ -166,6 +167,8 @@ typedef struct { gsize buffer_out_len; guint8 cmd; guint retried_cnt; + guint8 report_type; /* only for Sensor HID */ + guint report_length; /* only for Sensor HID */ } ChDeviceHelper; /** @@ -382,6 +385,192 @@ ch_device_emulate_cb (gpointer user_data) return G_SOURCE_REMOVE; } +#define CH_REPORT_ALS 0x00 +#define CH_REPORT_HID_SENSOR 0x01 +#define CH_REPORT_SENSOR_SETTINGS 0x02 +#define CH_REPORT_SYSTEM_SETTINGS 0x03 +#define CH_SENSOR_HID_REPORT_GET 0x01 +#define CH_SENSOR_HID_REPORT_SET 0x09 +#define CH_SENSOR_HID_FEATURE 0x0300 + +/** + * ch_device_sensor_hid_set_cb: + **/ +static void +ch_device_sensor_hid_set_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GError *error = NULL; + gssize actual_len; + GUsbDevice *device = G_USB_DEVICE (source_object); + ChDeviceHelper *helper = (ChDeviceHelper *) user_data; + + /* get the result */ + actual_len = g_usb_device_control_transfer_finish (device, + res, + &error); + if (actual_len != helper->report_length) { + g_simple_async_result_take_error (helper->res, error); + g_simple_async_result_complete_in_idle (helper->res); + ch_device_free_helper (helper); + return; + } +// ch_print_data_buffer ("reply", helper->buffer, helper->report_length); + + /* success */ + g_simple_async_result_set_op_res_gboolean (helper->res, TRUE); + g_simple_async_result_complete_in_idle (helper->res); + ch_device_free_helper (helper); +} + +/** + * ch_device_sensor_hid_report_cb: + **/ +static void +ch_device_sensor_hid_report_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GError *error = NULL; + gsize actual_len; + GUsbDevice *device = G_USB_DEVICE (source_object); + ChDeviceHelper *helper = (ChDeviceHelper *) user_data; + + /* get the result */ + actual_len = g_usb_device_interrupt_transfer_finish (device, + res, + &error); + if ((gssize) actual_len < 0) { + g_simple_async_result_take_error (helper->res, error); + g_simple_async_result_complete_in_idle (helper->res); + ch_device_free_helper (helper); + return; + } + + /* copy out data */ + memcpy (helper->buffer_out, helper->buffer + 3, 4); + + /* success */ + g_simple_async_result_set_op_res_gboolean (helper->res, TRUE); + g_simple_async_result_complete_in_idle (helper->res); + ch_device_free_helper (helper); +} + +/** + * ch_device_sensor_hid_get_cb: + **/ +static void +ch_device_sensor_hid_get_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GError *error = NULL; + gssize actual_len; + gboolean another_request_required = FALSE; + GUsbDevice *device = G_USB_DEVICE (source_object); + ChDeviceHelper *helper = (ChDeviceHelper *) user_data; + + /* get the result */ + actual_len = g_usb_device_control_transfer_finish (device, + res, + &error); + if (actual_len != helper->report_length) { + g_simple_async_result_take_error (helper->res, error); + g_simple_async_result_complete_in_idle (helper->res); + ch_device_free_helper (helper); + return; + } +// ch_print_data_buffer ("reply", helper->buffer, helper->report_length); + + switch (helper->cmd) { + case CH_CMD_TAKE_READING_RAW: + memcpy(helper->buffer_out, helper->buffer + 3, 4); + break; + case CH_CMD_GET_COLOR_SELECT: + memcpy(helper->buffer_out, helper->buffer + 1, 1); + break; + case CH_CMD_GET_INTEGRAL_TIME: + memcpy(helper->buffer_out, helper->buffer + 4, 2); + break; + case CH_CMD_GET_LEDS: + memcpy(helper->buffer_out, helper->buffer + 2, 1); + break; + case CH_CMD_GET_MULTIPLIER: + memcpy(helper->buffer_out, helper->buffer + 3, 1); + break; + case CH_CMD_GET_FIRMWARE_VERSION: + memcpy(helper->buffer_out, helper->buffer + 2, 6); + break; + case CH_CMD_GET_HARDWARE_VERSION: + memcpy(helper->buffer_out, helper->buffer + 1, 1); + break; + case CH_CMD_GET_SERIAL_NUMBER: + memcpy(helper->buffer_out, helper->buffer + 8, 4); + break; + case CH_CMD_SET_COLOR_SELECT: + memcpy(helper->buffer + 1, helper->buffer_orig + 1, 1); + another_request_required = TRUE; + break; + case CH_CMD_SET_INTEGRAL_TIME: + memcpy(helper->buffer + 4, helper->buffer_orig + 1, 2); + another_request_required = TRUE; + break; + case CH_CMD_SET_LEDS: + memcpy(helper->buffer + 2, helper->buffer_orig + 1, 1); + another_request_required = TRUE; + break; + case CH_CMD_SET_MULTIPLIER: + memcpy(helper->buffer + 3, helper->buffer_orig + 1, 1); + another_request_required = TRUE; + break; + case CH_CMD_SET_FLASH_SUCCESS: + memcpy(helper->buffer + 13, helper->buffer_orig + 1, 1); + another_request_required = TRUE; + break; + case CH_CMD_RESET: + helper->buffer[12] = 1; + another_request_required = TRUE; + break; + case CH_CMD_SET_SERIAL_NUMBER: + memcpy(helper->buffer + 8, helper->buffer_orig + 1, 4); + another_request_required = TRUE; + break; + default: + g_simple_async_result_set_error (helper->res, + CH_DEVICE_ERROR, + CH_ERROR_UNKNOWN_CMD, + "No Sensor HID support for 0x%02x", + helper->cmd); + g_simple_async_result_complete_in_idle (helper->res); + ch_device_free_helper (helper); + return; + } + + /* getting the value was enough */ + if (!another_request_required) { + g_simple_async_result_set_op_res_gboolean (helper->res, TRUE); + g_simple_async_result_complete_in_idle (helper->res); + ch_device_free_helper (helper); + return; + } + +// ch_print_data_buffer ("request", helper->buffer, helper->report_length); + g_usb_device_control_transfer_async (device, + G_USB_DEVICE_DIRECTION_HOST_TO_DEVICE, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_RECIPIENT_INTERFACE, + CH_SENSOR_HID_REPORT_SET, + CH_SENSOR_HID_FEATURE | helper->report_type, + 0x0000, + helper->buffer, + helper->report_length, + CH_DEVICE_USB_TIMEOUT, + helper->cancellable, + ch_device_sensor_hid_set_cb, + helper); +} + /** * ch_device_write_command_async: * @device: A #GUsbDevice @@ -466,6 +655,79 @@ ch_device_write_command_async (GUsbDevice *device, "ChCommonDeviceBusy", GUINT_TO_POINTER (TRUE)); + /* handle ALS in sensor-hid mode differently */ + if (g_usb_device_get_pid (device) == CH_USB_PID_FIRMWARE_ALS_SENSOR_HID) { + + /* try to map the commands to Sensor HID requests */ + switch (helper->cmd) { + case CH_CMD_TAKE_READING_RAW: + helper->report_type = CH_REPORT_ALS; + helper->report_length = 7; + break; + case CH_CMD_GET_COLOR_SELECT: + case CH_CMD_GET_INTEGRAL_TIME: + case CH_CMD_GET_LEDS: + case CH_CMD_GET_MULTIPLIER: + case CH_CMD_SET_COLOR_SELECT: + case CH_CMD_SET_INTEGRAL_TIME: + case CH_CMD_SET_LEDS: + case CH_CMD_SET_MULTIPLIER: + helper->report_type = CH_REPORT_SENSOR_SETTINGS; + helper->report_length = 6; + break; + case CH_CMD_GET_FIRMWARE_VERSION: + case CH_CMD_GET_HARDWARE_VERSION: + case CH_CMD_GET_SERIAL_NUMBER: + case CH_CMD_RESET: + case CH_CMD_SET_FLASH_SUCCESS: + case CH_CMD_SET_SERIAL_NUMBER: + helper->report_type = CH_REPORT_SYSTEM_SETTINGS; + helper->report_length = 14; + break; + default: + g_simple_async_result_set_error (helper->res, + CH_DEVICE_ERROR, + CH_ERROR_UNKNOWN_CMD, + "No Sensor HID support for 0x%02x", + helper->cmd); + g_simple_async_result_complete_in_idle (helper->res); + ch_device_free_helper (helper); + return; + } + + /* need to use this rather than feature control */ + if (helper->report_type == CH_REPORT_ALS) { + g_usb_device_interrupt_transfer_async (helper->device, + CH_USB_HID_EP_IN, + helper->buffer, + helper->report_length, + CH_DEVICE_USB_TIMEOUT, + helper->cancellable, + ch_device_sensor_hid_report_cb, + helper); + return; + } + + /* do control transfer */ + memset(helper->buffer, '\0', helper->report_length); +// ch_print_data_buffer ("request", helper->buffer, helper->report_length); + g_usb_device_control_transfer_async (device, + G_USB_DEVICE_DIRECTION_DEVICE_TO_HOST, + G_USB_DEVICE_REQUEST_TYPE_CLASS, + G_USB_DEVICE_RECIPIENT_INTERFACE, + CH_SENSOR_HID_REPORT_GET, + CH_SENSOR_HID_FEATURE | helper->report_type, + 0x0000, + helper->buffer, + helper->report_length, + CH_DEVICE_USB_TIMEOUT, + helper->cancellable, + ch_device_sensor_hid_get_cb, + helper); + return; + + } + /* do interrupt transfer */ g_usb_device_interrupt_transfer_async (helper->device, CH_USB_HID_EP_OUT, diff --git a/lib/colorhug/ch-self-test.c b/lib/colorhug/ch-self-test.c index 22ab5fc..cdef73f 100644 --- a/lib/colorhug/ch-self-test.c +++ b/lib/colorhug/ch-self-test.c @@ -461,8 +461,14 @@ ch_client_get_default (GError **error) } device = g_usb_context_find_by_vid_pid (usb_ctx, CH_USB_VID, - CH_USB_PID_FIRMWARE, - error); + CH_USB_PID_FIRMWARE_ALS_SENSOR_HID, + NULL); + if (device == NULL) { + device = g_usb_context_find_by_vid_pid (usb_ctx, + CH_USB_VID, + CH_USB_PID_FIRMWARE, + error); + } if (device == NULL) goto out; g_debug ("Found ColorHug device %s", @@ -506,7 +512,7 @@ ch_test_state_func (void) device_queue = ch_device_queue_new (); ch_device_queue_set_leds (device_queue, device, - 3, + 1, 0, 0x00, 0x00); @@ -525,7 +531,7 @@ ch_test_state_func (void) &error); g_assert_no_error (error); g_assert (ret); - g_assert_cmpint (leds, ==, 3); + g_assert_cmpint (leds, ==, 1); /* verify color select */ if (ch_device_get_mode (device) == CH_DEVICE_MODE_FIRMWARE) { @@ -667,6 +673,13 @@ ch_test_eeprom_func (void) /* load the device */ device = ch_client_get_default (&error); + if (device != NULL && g_usb_device_get_pid (device) != CH_USB_PID_FIRMWARE) { + ret = g_usb_device_close (device, &error); + g_assert_no_error (error); + g_assert (ret); + g_debug ("not capable device, skipping tests"); + return; + } if (device == NULL && g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_NO_DEVICE)) { @@ -996,6 +1009,13 @@ ch_test_reading_xyz_func (void) /* load the device */ device = ch_client_get_default (&error); + if (device != NULL && g_usb_device_get_pid (device) != CH_USB_PID_FIRMWARE) { + ret = g_usb_device_close (device, &error); + g_assert_no_error (error); + g_assert (ret); + g_debug ("not capable device, skipping tests"); + return; + } if (device == NULL && g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_NO_DEVICE)) { @@ -1137,6 +1157,13 @@ ch_test_incomplete_request_func (void) /* load the device */ device = ch_client_get_default (&error); + if (device != NULL && g_usb_device_get_pid (device) != CH_USB_PID_FIRMWARE) { + ret = g_usb_device_close (device, &error); + g_assert_no_error (error); + g_assert (ret); + g_debug ("not capable device, skipping tests"); + return; + } if (device == NULL && g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_NO_DEVICE)) { diff --git a/rules/69-cd-sensors.rules.in b/rules/69-cd-sensors.rules.in index f97ab05..5e0213e 100644 --- a/rules/69-cd-sensors.rules.in +++ b/rules/69-cd-sensors.rules.in @@ -92,6 +92,7 @@ ATTRS{idVendor}=="273f", ATTRS{idProduct}=="1002", ENV{COLORD_SENSOR_KIND}="colo # ColorHug ALS ATTRS{idVendor}=="273f", ATTRS{idProduct}=="1006", ENV{COLORD_SENSOR_KIND}="colorhug-als", ENV{COLORD_IGNORE}="1" ATTRS{idVendor}=="273f", ATTRS{idProduct}=="1007", ENV{COLORD_SENSOR_KIND}="colorhug-als", ENV{COLORD_IGNORE}="1" +ATTRS{idVendor}=="273f", ATTRS{idProduct}=="1008", ENV{COLORD_SENSOR_KIND}="colorhug-als", ENV{COLORD_IGNORE}="1" # color calibration device ENV{COLORD_SENSOR_KIND}=="*?", ENV{COLOR_MEASUREMENT_DEVICE}="1" |