summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStrony Zhang - Solaris China Team <Strony.Zhang@Sun.COM>2009-03-31 11:47:56 +0800
committerStrony Zhang - Solaris China Team <Strony.Zhang@Sun.COM>2009-03-31 11:47:56 +0800
commit827f5d6bce8ec1c2fd4f4b5b6351acce7dbd41ca (patch)
tree87dab92f2ed5c5e8082a3eb87fc3e17efc805006
parent3e77939308ff7e5a63416257d959388a0c37505f (diff)
downloadillumos-joyent-827f5d6bce8ec1c2fd4f4b5b6351acce7dbd41ca.tar.gz
6662693 req Microsoft Wireless keyboard mouse support
-rw-r--r--usr/src/uts/common/io/usb/clients/hid/hid.c15
-rw-r--r--usr/src/uts/common/io/usb/clients/hidparser/hidparser.c71
-rw-r--r--usr/src/uts/common/io/usb/clients/usbkbm/usbkbm.c98
-rw-r--r--usr/src/uts/common/sys/usb/clients/hidparser/hid_parser_driver.h22
-rw-r--r--usr/src/uts/common/sys/usb/clients/hidparser/hidparser.h4
-rw-r--r--usr/src/uts/common/sys/usb/clients/usbkbm/usbkbm.h4
6 files changed, 176 insertions, 38 deletions
diff --git a/usr/src/uts/common/io/usb/clients/hid/hid.c b/usr/src/uts/common/io/usb/clients/hid/hid.c
index f458366ad7..7205ae76bf 100644
--- a/usr/src/uts/common/io/usb/clients/hid/hid.c
+++ b/usr/src/uts/common/io/usb/clients/hid/hid.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -583,6 +583,19 @@ hid_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
break;
default:
+ /*
+ * If the report descriptor has the GD mouse collection in
+ * its multiple collection, create a minor node and support it.
+ * It is used on some advanced keyboard/mouse set.
+ */
+ if (hidparser_lookup_usage_collection(
+ hidp->hid_report_descr, HID_GENERIC_DESKTOP,
+ HID_GD_MOUSE) != HIDPARSER_FAILURE) {
+ (void) strcpy(minor_name, "mouse");
+
+ break;
+ }
+
if (hidparser_get_top_level_collection_usage(
hidp->hid_report_descr, &usage_page, &usage) !=
HIDPARSER_FAILURE) {
diff --git a/usr/src/uts/common/io/usb/clients/hidparser/hidparser.c b/usr/src/uts/common/io/usb/clients/hidparser/hidparser.c
index ff94a2f841..3fb1e4ee87 100644
--- a/usr/src/uts/common/io/usb/clients/hidparser/hidparser.c
+++ b/usr/src/uts/common/io/usb/clients/hidparser/hidparser.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -733,6 +733,75 @@ hidparser_get_main_item_data_descr_main(entity_item_t *parser_handle,
return (HIDPARSER_NOT_FOUND);
}
+/*
+ * hidparser_lookup_usage_collection:
+ * Look up the collection specified by the usage page and usage id
+ */
+int
+hidparser_lookup_usage_collection(hidparser_handle_t parse_handle,
+ uint_t lusage_page,
+ uint_t lusage_id)
+{
+ entity_item_t *current;
+ entity_attribute_t *attribute;
+ int found_usage_id = 0;
+ int found_page = 0;
+ uint32_t usage;
+ uint_t usage_page;
+ uint_t usage_id;
+
+ if ((parse_handle == NULL) ||
+ (parse_handle->hidparser_handle_parse_tree == NULL))
+ return (HIDPARSER_FAILURE);
+
+ current = parse_handle->hidparser_handle_parse_tree;
+ while (current != NULL) {
+
+ if (current->entity_item_type != R_ITEM_COLLECTION) {
+ current = current->entity_item_right_sibling;
+ continue;
+ }
+
+ attribute = current->entity_item_attributes;
+ found_usage_id = 0;
+ found_page = 0;
+
+ while (attribute != NULL) {
+ if (attribute->entity_attribute_tag == R_ITEM_USAGE) {
+ found_usage_id = 1;
+ usage = hidparser_find_unsigned_val(attribute);
+ usage_id = HID_USAGE_ID(usage);
+ if (attribute->entity_attribute_length == 3) {
+ if (HID_USAGE_PAGE(usage)) {
+ found_page = 1;
+ usage_page =
+ HID_USAGE_PAGE(usage);
+ }
+ }
+ if (found_page) {
+ goto check_usage;
+ }
+ } else if (attribute->entity_attribute_tag ==
+ R_ITEM_USAGE_PAGE) {
+ found_page = 1;
+ usage_page =
+ attribute->entity_attribute_value[0];
+ if (found_usage_id) {
+ goto check_usage;
+ }
+ }
+ attribute = attribute->entity_attribute_next;
+ }
+check_usage:
+ if ((usage_page == lusage_page) && (usage_id == lusage_id))
+ return (HIDPARSER_SUCCESS);
+ else
+ current = current->entity_item_right_sibling;
+ }
+
+ return (HIDPARSER_FAILURE);
+}
+
/*
* hidparser_get_top_level_collection_usage:
diff --git a/usr/src/uts/common/io/usb/clients/usbkbm/usbkbm.c b/usr/src/uts/common/io/usb/clients/usbkbm/usbkbm.c
index 53d0648de3..7bcbea43e6 100644
--- a/usr/src/uts/common/io/usb/clients/usbkbm/usbkbm.c
+++ b/usr/src/uts/common/io/usb/clients/usbkbm/usbkbm.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -78,8 +78,9 @@ static enum kbtrans_message_response usbkbm_ioctl(queue_t *, mblk_t *);
static int usbkbm_kioccmd(usbkbm_state_t *, mblk_t *, char, size_t *);
static void usbkbm_usb2pc_xlate(usbkbm_state_t *, int, enum keystate);
static void usbkbm_wrap_kbtrans(usbkbm_state_t *, int, enum keystate);
-static int usbkbm_set_protocol(usbkbm_state_t *, uint16_t);
-static int usbkbm_get_vid_pid(usbkbm_state_t *);
+static int usbkbm_get_protocol(usbkbm_state_t *);
+static int usbkbm_set_protocol(usbkbm_state_t *, uint16_t);
+static int usbkbm_get_vid_pid(usbkbm_state_t *);
/* stream qinit functions defined here */
static int usbkbm_open(queue_t *, dev_t *, int, int, cred_t *);
@@ -113,7 +114,7 @@ struct kbtrans_callbacks kbd_usb_callbacks = {
*/
/* This variable saves the LED state across hotplugging. */
-static uchar_t usbkbm_led_state = 0;
+static uchar_t usbkbm_led_state = 0;
/* This variable saves the layout state */
static uint16_t usbkbm_layout = 0;
@@ -490,14 +491,20 @@ usbkbm_open(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp)
qprocson(q);
+ if (ret = usbkbm_get_protocol(usbkbmd)) {
+
+ return (ret);
+ }
+
+ if (usbkbmd->protocol != SET_BOOT_PROTOCOL) {
/*
- * The hid module already configured this keyboard for report mode,
- * but usbkbm only knows how to deal with boot-protocol mode,
+ * The current usbkbm only knows how to deal with boot-protocol mode,
* so switch into boot-protocol mode now.
*/
- if (ret = usbkbm_set_protocol(usbkbmd, SET_BOOT_PROTOCOL)) {
+ if (ret = usbkbm_set_protocol(usbkbmd, SET_BOOT_PROTOCOL)) {
- return (ret);
+ return (ret);
+ }
}
/*
@@ -1134,15 +1141,11 @@ static void
usbkbm_mctl_receive(register queue_t *q, register mblk_t *mp)
{
register usbkbm_state_t *usbkbmd = (usbkbm_state_t *)q->q_ptr;
- register struct iocblk *iocp, mctlmsg;
+ register struct iocblk *iocp;
caddr_t data = NULL;
- mblk_t *reply_mp, *mctl_ptr;
+ mblk_t *reply_mp;
uchar_t new_buffer[USBKBM_MAXPKTSIZE];
- size_t size;
- hid_req_t buf;
- size_t len = sizeof (buf);
-
-
+ size_t size;
iocp = (struct iocblk *)mp->b_rptr;
if (mp->b_cont != NULL)
@@ -1259,21 +1262,6 @@ usbkbm_mctl_receive(register queue_t *q, register mblk_t *mp)
break;
case HID_CONNECT_EVENT:
- mctlmsg.ioc_cmd = HID_SET_PROTOCOL;
- mctlmsg.ioc_count = 0;
- buf.hid_req_version_no = HID_VERSION_V_0;
- buf.hid_req_wValue = SET_BOOT_PROTOCOL;
- buf.hid_req_wLength = 0;
- mctl_ptr = usba_mk_mctl(mctlmsg, &buf, len);
- if (mctl_ptr == NULL) {
- USB_DPRINTF_L2(PRINT_MASK_ALL, usbkbm_log_handle,
- "usbkbm_mctl_receive HID_CONNECT_EVENT: "
- "Set protocol failed");
- } else {
- putnext(usbkbmd->usbkbm_writeq, mctl_ptr);
- }
-
- /* FALLTHRU */
case HID_FULL_POWER :
USB_DPRINTF_L3(PRINT_MASK_ALL, usbkbm_log_handle,
"usbkbm_mctl_receive restore LEDs");
@@ -1285,6 +1273,15 @@ usbkbm_mctl_receive(register queue_t *q, register mblk_t *mp)
freemsg(mp);
break;
+ case HID_GET_PROTOCOL:
+ if ((data != NULL) && (iocp->ioc_count == 1) &&
+ (MBLKL(mp->b_cont) == iocp->ioc_count)) {
+ bcopy(data, &usbkbmd->protocol, iocp->ioc_count);
+ }
+ freemsg(mp);
+ usbkbmd->usbkbm_flags &= ~USBKBM_QWAIT;
+
+ break;
default:
putnext(q, mp);
@@ -1455,7 +1452,7 @@ static ushort_t usbkbm_get_state(usbkbm_state_t *usbkbmd)
* get called with an unpacked key (scancode) and state (press/release).
* We pass it to the generic keyboard module.
*
- * 'index' and the function pointers:
+ * 'index' and the function pointers:
* Map USB scancodes to PC scancodes by lookup table.
* This fix is mainly meant for x86 platforms. For SPARC systems
* this fix doesn't change the way in which the scancodes are processed.
@@ -1983,3 +1980,42 @@ usbkbm_get_vid_pid(usbkbm_state_t *usbkbmd)
return (0);
}
+
+/*
+ * usbkbm_get_protocol
+ * Issue a M_CTL to hid to get the device info
+ */
+static int
+usbkbm_get_protocol(usbkbm_state_t *usbkbmd)
+{
+ struct iocblk mctlmsg;
+ mblk_t *mctl_ptr;
+ queue_t *q = usbkbmd->usbkbm_readq;
+
+ mctlmsg.ioc_cmd = HID_GET_PROTOCOL;
+ mctlmsg.ioc_count = 0;
+
+ mctl_ptr = usba_mk_mctl(mctlmsg, NULL, 0);
+ if (mctl_ptr == NULL) {
+ (void) kbtrans_streams_fini(usbkbmd->usbkbm_kbtrans);
+ qprocsoff(q);
+ kmem_free(usbkbmd, sizeof (usbkbm_state_t));
+
+ return (ENOMEM);
+ }
+
+ putnext(usbkbmd->usbkbm_writeq, mctl_ptr);
+ usbkbmd->usbkbm_flags |= USBKBM_QWAIT;
+ while (usbkbmd->usbkbm_flags & USBKBM_QWAIT) {
+ if (qwait_sig(q) == 0) {
+ usbkbmd->usbkbm_flags = 0;
+ (void) kbtrans_streams_fini(usbkbmd->usbkbm_kbtrans);
+ qprocsoff(q);
+ kmem_free(usbkbmd, sizeof (usbkbm_state_t));
+
+ return (EINTR);
+ }
+ }
+
+ return (0);
+}
diff --git a/usr/src/uts/common/sys/usb/clients/hidparser/hid_parser_driver.h b/usr/src/uts/common/sys/usb/clients/hidparser/hid_parser_driver.h
index d056e76668..c864bd905e 100644
--- a/usr/src/uts/common/sys/usb/clients/hidparser/hid_parser_driver.h
+++ b/usr/src/uts/common/sys/usb/clients/hidparser/hid_parser_driver.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -94,13 +94,31 @@ int hidparser_free_report_descriptor_handle(hidparser_handle_t parse_handle);
*
* Return values:
* HID_PARSER_SUCCESS - no errors
- * HID_PARSER_FAIOURE - unspecified error
+ * HID_PARSER_FAILURE - unspecified error
*
*/
int hidparser_get_top_level_collection_usage(hidparser_handle_t parse_handle,
uint_t *usage_page,
uint_t *usage);
+/*
+ * hidparser_lookup_usage_collection:
+ * Look up the collection specified by the usage page and usage id.
+ *
+ * Arguments:
+ * parse_handle: parser handle
+ * lusage_page: specified usage page
+ * lusage_id: specified usage
+ *
+ * Return values:
+ * HID_PARSER_SUCCESS - found the specified collection
+ * HID_PARSER_FAILURE - error or not found
+ */
+int
+hidparser_lookup_usage_collection(hidparser_handle_t parse_handle,
+ uint_t lusage_page,
+ uint_t lusage_id);
+
#ifdef __cplusplus
}
diff --git a/usr/src/uts/common/sys/usb/clients/hidparser/hidparser.h b/usr/src/uts/common/sys/usb/clients/hidparser/hidparser.h
index a9b53ef960..4484de163e 100644
--- a/usr/src/uts/common/sys/usb/clients/hidparser/hidparser.h
+++ b/usr/src/uts/common/sys/usb/clients/hidparser/hidparser.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -49,7 +49,7 @@ typedef struct hidparser_handle_impl *hidparser_handle_t;
#define HID_REPORT_ID_UNDEFINED 0
-#define USAGE_MAX 20 /* Max no. of usages in a report */
+#define USAGE_MAX 100 /* Max no. of usages in a report */
typedef struct hidparser_usage_info {
uint16_t usage_page;
diff --git a/usr/src/uts/common/sys/usb/clients/usbkbm/usbkbm.h b/usr/src/uts/common/sys/usb/clients/usbkbm/usbkbm.h
index 77920bd767..ac01056eb1 100644
--- a/usr/src/uts/common/sys/usb/clients/usbkbm/usbkbm.h
+++ b/usr/src/uts/common/sys/usb/clients/usbkbm/usbkbm.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -152,6 +152,8 @@ typedef struct usbkbm_state {
poll_keystate_t *usbkbm_polled_buffer_head;
poll_keystate_t *usbkbm_polled_buffer_tail;
+ /* Boot protocol or report protocol */
+ uint8_t protocol;
} usbkbm_state_t;
#define USB_PRESSED 0x00 /* key was pressed */