diff options
author | Strony Zhang - Solaris China Team <Strony.Zhang@Sun.COM> | 2009-03-31 11:47:56 +0800 |
---|---|---|
committer | Strony Zhang - Solaris China Team <Strony.Zhang@Sun.COM> | 2009-03-31 11:47:56 +0800 |
commit | 827f5d6bce8ec1c2fd4f4b5b6351acce7dbd41ca (patch) | |
tree | 87dab92f2ed5c5e8082a3eb87fc3e17efc805006 | |
parent | 3e77939308ff7e5a63416257d959388a0c37505f (diff) | |
download | illumos-joyent-827f5d6bce8ec1c2fd4f4b5b6351acce7dbd41ca.tar.gz |
6662693 req Microsoft Wireless keyboard mouse support
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 */ |