summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Hughes <richard@hughsie.com>2015-05-27 10:36:35 +0100
committerRichard Hughes <richard@hughsie.com>2015-05-28 08:43:26 +0100
commiteb14cf6ee090ba953b819d28bb2def6f86130555 (patch)
treef6536861974ff6652165f52c42d718f109fbd18b
parent8a9cd0cfbcfe80623a258fd8d0fea7d788d395bb (diff)
downloadcolord-eb14cf6ee090ba953b819d28bb2def6f86130555.tar.gz
colorhug: Handle low-level commands when in Sensor HID mode
-rw-r--r--lib/colorhug/ch-common.h1
-rw-r--r--lib/colorhug/ch-device.c262
-rw-r--r--lib/colorhug/ch-self-test.c35
-rw-r--r--rules/69-cd-sensors.rules.in1
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"