diff options
author | Alex Wilson <alex.wilson@joyent.com> | 2017-01-05 17:16:10 -0800 |
---|---|---|
committer | Alex Wilson <alex.wilson@joyent.com> | 2017-01-10 00:39:05 +0000 |
commit | ef863daaba22cc716ed3cfc450359044c2e6dde6 (patch) | |
tree | bf61f0c400667c2676f6d4aa29ed1760beeab182 | |
parent | a20de2b86d0939a58dfb2f51057f86b1cbbdc7e3 (diff) | |
download | illumos-joyent-ef863daaba22cc716ed3cfc450359044c2e6dde6.tar.gz |
OS-5887 want ugen nodes for devices attached by hid
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Joshua M. Clulow <jmc@joyent.com>
-rw-r--r-- | usr/src/uts/common/io/usb/clients/hid/hid.c | 212 | ||||
-rw-r--r-- | usr/src/uts/common/sys/usb/clients/hid/hidminor.h | 19 | ||||
-rw-r--r-- | usr/src/uts/common/sys/usb/clients/hid/hidvar.h | 5 |
3 files changed, 221 insertions, 15 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 249941d03c..2c9c88a3ec 100644 --- a/usr/src/uts/common/io/usb/clients/hid/hid.c +++ b/usr/src/uts/common/io/usb/clients/hid/hid.c @@ -21,7 +21,7 @@ /* * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2016 Joyent, Inc. + * Copyright 2017 Joyent, Inc. */ @@ -139,6 +139,12 @@ static int hid_info(dev_info_t *, ddi_info_cmd_t, void *, void **); static int hid_attach(dev_info_t *, ddi_attach_cmd_t); static int hid_detach(dev_info_t *, ddi_detach_cmd_t); static int hid_power(dev_info_t *, int, int); +/* These are to enable ugen support: */ +static int hid_chropen(dev_t *, int, int, cred_t *); +static int hid_chrclose(dev_t, int, int, cred_t *); +static int hid_read(dev_t, struct uio *, cred_t *); +static int hid_write(dev_t, struct uio *, cred_t *); +static int hid_poll(dev_t, short, int, short *, struct pollhead **); /* * Warlock is not aware of the automatic locking mechanisms for @@ -198,18 +204,18 @@ struct streamtab hid_streamtab = { }; struct cb_ops hid_cb_ops = { - nulldev, /* open */ - nulldev, /* close */ + hid_chropen, /* open */ + hid_chrclose, /* close */ nulldev, /* strategy */ nulldev, /* print */ nulldev, /* dump */ - nulldev, /* read */ - nulldev, /* write */ + hid_read, /* read */ + hid_write, /* write */ nulldev, /* ioctl */ nulldev, /* devmap */ nulldev, /* mmap */ nulldev, /* segmap */ - nochpoll, /* poll */ + hid_poll, /* poll */ ddi_prop_op, /* cb_prop_op */ &hid_streamtab, /* streamtab */ D_MP | D_MTPERQ @@ -349,6 +355,7 @@ hid_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) usb_alt_if_data_t *altif_data; char minor_name[HID_MINOR_NAME_LEN]; usb_ep_data_t *ep_data; + usb_ugen_info_t usb_ugen_info; switch (cmd) { case DDI_ATTACH: @@ -490,6 +497,28 @@ hid_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) usb_free_dev_data(dip, dev_data); hidp->hid_dev_data = NULL; + if (usb_owns_device(dip)) { + /* Get a ugen handle. */ + bzero(&usb_ugen_info, sizeof (usb_ugen_info)); + + usb_ugen_info.usb_ugen_flags = 0; + usb_ugen_info.usb_ugen_minor_node_ugen_bits_mask = + (dev_t)HID_MINOR_UGEN_BITS_MASK; + usb_ugen_info.usb_ugen_minor_node_instance_mask = + (dev_t)HID_MINOR_INSTANCE_MASK; + hidp->hid_ugen_hdl = usb_ugen_get_hdl(dip, &usb_ugen_info); + + if (usb_ugen_attach(hidp->hid_ugen_hdl, cmd) != + USB_SUCCESS) { + USB_DPRINTF_L2(PRINT_MASK_ATTA, + hidp->hid_log_handle, + "usb_ugen_attach failed"); + + usb_ugen_release_hdl(hidp->hid_ugen_hdl); + hidp->hid_ugen_hdl = NULL; + } + } + /* * Don't get the report descriptor if parsing hid descriptor earlier * failed since device probably won't return valid report descriptor @@ -768,6 +797,149 @@ hid_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) return (rval); } +static int +hid_chropen(dev_t *devp, int flag, int sflag, cred_t *credp) +{ + int rval; + minor_t minor = getminor(*devp); + int instance; + hid_state_t *hidp; + + instance = HID_MINOR_TO_INSTANCE(minor); + + hidp = ddi_get_soft_state(hid_statep, instance); + if (hidp == NULL) { + return (ENXIO); + } + + if (!HID_IS_UGEN_OPEN(minor)) { + return (ENXIO); + } + + hid_pm_busy_component(hidp); + (void) pm_raise_power(hidp->hid_dip, 0, USB_DEV_OS_FULL_PWR); + + mutex_enter(&hidp->hid_mutex); + + rval = usb_ugen_open(hidp->hid_ugen_hdl, devp, flag, + sflag, credp); + + mutex_exit(&hidp->hid_mutex); + + if (rval != 0) { + hid_pm_idle_component(hidp); + } + + return (rval); +} + +static int +hid_chrclose(dev_t dev, int flag, int otyp, cred_t *credp) +{ + int rval; + minor_t minor = getminor(dev); + int instance; + hid_state_t *hidp; + + instance = HID_MINOR_TO_INSTANCE(minor); + + hidp = ddi_get_soft_state(hid_statep, instance); + if (hidp == NULL) { + return (ENXIO); + } + + if (!HID_IS_UGEN_OPEN(minor)) { + return (ENXIO); + } + + mutex_enter(&hidp->hid_mutex); + + rval = usb_ugen_close(hidp->hid_ugen_hdl, dev, flag, + otyp, credp); + + mutex_exit(&hidp->hid_mutex); + + if (rval == 0) { + hid_pm_idle_component(hidp); + } + + return (rval); +} + +static int +hid_read(dev_t dev, struct uio *uiop, cred_t *credp) +{ + int rval; + minor_t minor = getminor(dev); + int instance; + hid_state_t *hidp; + + instance = HID_MINOR_TO_INSTANCE(minor); + + hidp = ddi_get_soft_state(hid_statep, instance); + if (hidp == NULL) { + return (ENXIO); + } + + if (!HID_IS_UGEN_OPEN(minor)) { + return (ENXIO); + } + + rval = usb_ugen_read(hidp->hid_ugen_hdl, dev, uiop, credp); + + return (rval); +} + +static int +hid_write(dev_t dev, struct uio *uiop, cred_t *credp) +{ + int rval; + minor_t minor = getminor(dev); + int instance; + hid_state_t *hidp; + + instance = HID_MINOR_TO_INSTANCE(minor); + + hidp = ddi_get_soft_state(hid_statep, instance); + if (hidp == NULL) { + return (ENXIO); + } + + if (!HID_IS_UGEN_OPEN(minor)) { + return (ENXIO); + } + + rval = usb_ugen_write(hidp->hid_ugen_hdl, dev, uiop, credp); + + return (rval); +} + +static int +hid_poll(dev_t dev, short events, int anyyet, short *reventsp, + struct pollhead **phpp) +{ + int rval; + minor_t minor = getminor(dev); + int instance; + hid_state_t *hidp; + + instance = HID_MINOR_TO_INSTANCE(minor); + + hidp = ddi_get_soft_state(hid_statep, instance); + if (hidp == NULL) { + return (ENXIO); + } + + if (!HID_IS_UGEN_OPEN(minor)) { + return (ENXIO); + } + + rval = usb_ugen_poll(hidp->hid_ugen_hdl, dev, events, anyyet, + reventsp, phpp); + + return (rval); +} + /* * hid_open : * Open entry point: Opens the interrupt pipe. Sets up queues. @@ -786,13 +958,21 @@ hid_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) hidp = ddi_get_soft_state(hid_statep, instance); if (hidp == NULL) { - return (ENXIO); } USB_DPRINTF_L4(PRINT_MASK_OPEN, hidp->hid_log_handle, "hid_open: Begin"); + /* + * If this is a ugen device, return ENOSTR (no streams). This will + * cause spec_open to try hid_chropen from our regular ops_cb instead + * (and thus treat us as a plain character device). + */ + if (HID_IS_UGEN_OPEN(minor)) { + return (ENOSTR); + } + if (sflag) { /* clone open NOT supported here */ return (ENXIO); @@ -802,6 +982,8 @@ hid_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) return (EIO); } + mutex_enter(&hidp->hid_mutex); + /* * This is a workaround: * Currently, if we open an already disconnected device, and send @@ -811,7 +993,6 @@ hid_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp) * The consconfig_dacf module need this interface to detect if the * device is already disconnnected. */ - mutex_enter(&hidp->hid_mutex); if (HID_IS_INTERNAL_OPEN(minor) && (hidp->hid_dev_state == USB_DEV_DISCONNECTED)) { mutex_exit(&hidp->hid_mutex); @@ -1687,6 +1868,11 @@ hid_cpr_suspend(hid_state_t *hidp) } mutex_exit(&hidp->hid_mutex); + if ((retval == USB_SUCCESS) && hidp->hid_ugen_hdl != NULL) { + retval = usb_ugen_detach(hidp->hid_ugen_hdl, + DDI_SUSPEND); + } + return (retval); } @@ -1698,6 +1884,10 @@ hid_cpr_resume(hid_state_t *hidp) "hid_cpr_resume: dip=0x%p", (void *)hidp->hid_dip); hid_restore_device_state(hidp->hid_dip, hidp); + + if (hidp->hid_ugen_hdl != NULL) { + (void) usb_ugen_attach(hidp->hid_ugen_hdl, DDI_RESUME); + } } @@ -2135,6 +2325,12 @@ hid_detach_cleanup(dev_info_t *dip, hid_state_t *hidp) hidp->hid_pm = NULL; } + if (hidp->hid_ugen_hdl != NULL) { + rval = usb_ugen_detach(hidp->hid_ugen_hdl, DDI_DETACH); + VERIFY0(rval); + usb_ugen_release_hdl(hidp->hid_ugen_hdl); + } + mutex_exit(&hidp->hid_mutex); if (hidp->hid_report_descr != NULL) { diff --git a/usr/src/uts/common/sys/usb/clients/hid/hidminor.h b/usr/src/uts/common/sys/usb/clients/hid/hidminor.h index c96f914a70..f1b209faad 100644 --- a/usr/src/uts/common/sys/usb/clients/hid/hidminor.h +++ b/usr/src/uts/common/sys/usb/clients/hid/hidminor.h @@ -20,7 +20,7 @@ */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright 2017 Joyent, Inc. */ #ifndef _SYS_USB_HIDMINOR_H @@ -44,21 +44,28 @@ extern "C" { * transparent. * * So we change minor node numbering scheme to be: - * external node minor num == instance << 1 - * internal node minor num == instance << 1 | 0x1 + * external node minor num == instance << 9 + * internal node minor num == instance << 9 | 0x100 * (There are only internal nodes for keyboard/mouse now.) + * + * The 8 bits of the LSB are used for ugen minor numbering (hence the use + * of the first bit of the next byte for the "internal" flag) */ -#define HID_MINOR_BITS_MASK 0x1 +#define HID_MINOR_BITS_MASK 0x1ff +#define HID_MINOR_UGEN_BITS_MASK 0xff #define HID_MINOR_INSTANCE_MASK ~HID_MINOR_BITS_MASK -#define HID_MINOR_INSTANCE_SHIFT 1 +#define HID_MINOR_INSTANCE_SHIFT 9 -#define HID_MINOR_INTERNAL 0x1 +#define HID_MINOR_INTERNAL 0x100 #define HID_MINOR_MAKE_INTERNAL(minor) \ ((minor) | HID_MINOR_INTERNAL) #define HID_IS_INTERNAL_OPEN(minor) \ (((minor) & HID_MINOR_INTERNAL)) +#define HID_IS_UGEN_OPEN(minor) \ + (((minor) & HID_MINOR_UGEN_BITS_MASK)) + #define HID_MINOR_TO_INSTANCE(minor) \ (((minor) & HID_MINOR_INSTANCE_MASK) >> \ HID_MINOR_INSTANCE_SHIFT) diff --git a/usr/src/uts/common/sys/usb/clients/hid/hidvar.h b/usr/src/uts/common/sys/usb/clients/hid/hidvar.h index e9a25ea894..ee68f0088a 100644 --- a/usr/src/uts/common/sys/usb/clients/hid/hidvar.h +++ b/usr/src/uts/common/sys/usb/clients/hid/hidvar.h @@ -21,7 +21,7 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright 2017 Joyent, Inc. */ #ifndef _SYS_USB_HIDVAR_H @@ -33,6 +33,7 @@ extern "C" { #endif #include <sys/usb/usba/usbai_private.h> +#include <sys/usb/usba/usba_ugen.h> /* * HID : This header file contains the internal structures @@ -222,6 +223,8 @@ typedef struct hid_state { queue_t *hid_inuse_rq; int hid_internal_flag; /* see below */ int hid_external_flag; /* see below */ + + usb_ugen_hdl_t hid_ugen_hdl; /* ugen support */ } hid_state_t; /* warlock directives, stable data */ |