1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2020 Vladimir Kondratyev <wulf@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 /* 30 * Consumer Controls usage page driver 31 * https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf 32 */ 33 34 #include <sys/param.h> 35 #include <sys/bitstring.h> 36 #include <sys/bus.h> 37 #include <sys/kernel.h> 38 #include <sys/module.h> 39 #include <sys/sysctl.h> 40 41 #include <dev/evdev/input.h> 42 #include <dev/evdev/evdev.h> 43 44 #include <dev/hid/hid.h> 45 #include <dev/hid/hidbus.h> 46 #include <dev/hid/hidmap.h> 47 48 static hidmap_cb_t hcons_rel_volume_cb; 49 50 #define HCONS_MAP_KEY(usage, code) \ 51 { HIDMAP_KEY(HUP_CONSUMER, usage, code) } 52 #define HCONS_MAP_ABS(usage, code) \ 53 { HIDMAP_ABS(HUP_CONSUMER, usage, code) } 54 #define HCONS_MAP_REL(usage, code) \ 55 { HIDMAP_REL(HUP_CONSUMER, usage, code) } 56 #define HCONS_MAP_REL_CB(usage, callback) \ 57 { HIDMAP_REL_CB(HUP_CONSUMER, usage, &callback) } 58 59 static const struct hidmap_item hcons_map[] = { 60 HCONS_MAP_KEY(0x030, KEY_POWER), 61 HCONS_MAP_KEY(0x031, KEY_RESTART), 62 HCONS_MAP_KEY(0x032, KEY_SLEEP), 63 HCONS_MAP_KEY(0x034, KEY_SLEEP), 64 HCONS_MAP_KEY(0x035, KEY_KBDILLUMTOGGLE), 65 HCONS_MAP_KEY(0x036, BTN_MISC), 66 HCONS_MAP_KEY(0x040, KEY_MENU), /* Menu */ 67 HCONS_MAP_KEY(0x041, KEY_SELECT), /* Menu Pick */ 68 HCONS_MAP_KEY(0x042, KEY_UP), /* Menu Up */ 69 HCONS_MAP_KEY(0x043, KEY_DOWN), /* Menu Down */ 70 HCONS_MAP_KEY(0x044, KEY_LEFT), /* Menu Left */ 71 HCONS_MAP_KEY(0x045, KEY_RIGHT), /* Menu Right */ 72 HCONS_MAP_KEY(0x046, KEY_ESC), /* Menu Escape */ 73 HCONS_MAP_KEY(0x047, KEY_KPPLUS), /* Menu Value Increase */ 74 HCONS_MAP_KEY(0x048, KEY_KPMINUS), /* Menu Value Decrease */ 75 HCONS_MAP_KEY(0x060, KEY_INFO), /* Data On Screen */ 76 HCONS_MAP_KEY(0x061, KEY_SUBTITLE), /* Closed Caption */ 77 HCONS_MAP_KEY(0x063, KEY_VCR), /* VCR/TV */ 78 HCONS_MAP_KEY(0x065, KEY_CAMERA), /* Snapshot */ 79 HCONS_MAP_KEY(0x069, KEY_RED), 80 HCONS_MAP_KEY(0x06a, KEY_GREEN), 81 HCONS_MAP_KEY(0x06b, KEY_BLUE), 82 HCONS_MAP_KEY(0x06c, KEY_YELLOW), 83 HCONS_MAP_KEY(0x06d, KEY_ASPECT_RATIO), 84 HCONS_MAP_KEY(0x06f, KEY_BRIGHTNESSUP), 85 HCONS_MAP_KEY(0x070, KEY_BRIGHTNESSDOWN), 86 HCONS_MAP_KEY(0x072, KEY_BRIGHTNESS_TOGGLE), 87 HCONS_MAP_KEY(0x073, KEY_BRIGHTNESS_MIN), 88 HCONS_MAP_KEY(0x074, KEY_BRIGHTNESS_MAX), 89 HCONS_MAP_KEY(0x075, KEY_BRIGHTNESS_AUTO), 90 HCONS_MAP_KEY(0x079, KEY_KBDILLUMUP), 91 HCONS_MAP_KEY(0x07a, KEY_KBDILLUMDOWN), 92 HCONS_MAP_KEY(0x07c, KEY_KBDILLUMTOGGLE), 93 HCONS_MAP_KEY(0x082, KEY_VIDEO_NEXT), 94 HCONS_MAP_KEY(0x083, KEY_LAST), 95 HCONS_MAP_KEY(0x084, KEY_ENTER), 96 HCONS_MAP_KEY(0x088, KEY_PC), 97 HCONS_MAP_KEY(0x089, KEY_TV), 98 HCONS_MAP_KEY(0x08a, KEY_WWW), 99 HCONS_MAP_KEY(0x08b, KEY_DVD), 100 HCONS_MAP_KEY(0x08c, KEY_PHONE), 101 HCONS_MAP_KEY(0x08d, KEY_PROGRAM), 102 HCONS_MAP_KEY(0x08e, KEY_VIDEOPHONE), 103 HCONS_MAP_KEY(0x08f, KEY_GAMES), 104 HCONS_MAP_KEY(0x090, KEY_MEMO), 105 HCONS_MAP_KEY(0x091, KEY_CD), 106 HCONS_MAP_KEY(0x092, KEY_VCR), 107 HCONS_MAP_KEY(0x093, KEY_TUNER), 108 HCONS_MAP_KEY(0x094, KEY_EXIT), 109 HCONS_MAP_KEY(0x095, KEY_HELP), 110 HCONS_MAP_KEY(0x096, KEY_TAPE), 111 HCONS_MAP_KEY(0x097, KEY_TV2), 112 HCONS_MAP_KEY(0x098, KEY_SAT), 113 HCONS_MAP_KEY(0x09a, KEY_PVR), 114 HCONS_MAP_KEY(0x09c, KEY_CHANNELUP), 115 HCONS_MAP_KEY(0x09d, KEY_CHANNELDOWN), 116 HCONS_MAP_KEY(0x0a0, KEY_VCR2), 117 HCONS_MAP_KEY(0x0b0, KEY_PLAY), 118 HCONS_MAP_KEY(0x0b1, KEY_PAUSE), 119 HCONS_MAP_KEY(0x0b2, KEY_RECORD), 120 HCONS_MAP_KEY(0x0b3, KEY_FASTFORWARD), 121 HCONS_MAP_KEY(0x0b4, KEY_REWIND), 122 HCONS_MAP_KEY(0x0b5, KEY_NEXTSONG), 123 HCONS_MAP_KEY(0x0b6, KEY_PREVIOUSSONG), 124 HCONS_MAP_KEY(0x0b7, KEY_STOPCD), 125 HCONS_MAP_KEY(0x0b8, KEY_EJECTCD), 126 HCONS_MAP_KEY(0x0bc, KEY_MEDIA_REPEAT), 127 HCONS_MAP_KEY(0x0b9, KEY_SHUFFLE), 128 HCONS_MAP_KEY(0x0bf, KEY_SLOW), 129 HCONS_MAP_KEY(0x0cd, KEY_PLAYPAUSE), 130 HCONS_MAP_KEY(0x0cf, KEY_VOICECOMMAND), 131 HCONS_MAP_ABS(0x0e0, ABS_VOLUME), 132 HCONS_MAP_REL_CB(0x0e0, hcons_rel_volume_cb), 133 HCONS_MAP_KEY(0x0e2, KEY_MUTE), 134 HCONS_MAP_KEY(0x0e5, KEY_BASSBOOST), 135 HCONS_MAP_KEY(0x0e9, KEY_VOLUMEUP), 136 HCONS_MAP_KEY(0x0ea, KEY_VOLUMEDOWN), 137 HCONS_MAP_KEY(0x0f5, KEY_SLOW), 138 HCONS_MAP_KEY(0x181, KEY_BUTTONCONFIG), 139 HCONS_MAP_KEY(0x182, KEY_BOOKMARKS), 140 HCONS_MAP_KEY(0x183, KEY_CONFIG), 141 HCONS_MAP_KEY(0x184, KEY_WORDPROCESSOR), 142 HCONS_MAP_KEY(0x185, KEY_EDITOR), 143 HCONS_MAP_KEY(0x186, KEY_SPREADSHEET), 144 HCONS_MAP_KEY(0x187, KEY_GRAPHICSEDITOR), 145 HCONS_MAP_KEY(0x188, KEY_PRESENTATION), 146 HCONS_MAP_KEY(0x189, KEY_DATABASE), 147 HCONS_MAP_KEY(0x18a, KEY_MAIL), 148 HCONS_MAP_KEY(0x18b, KEY_NEWS), 149 HCONS_MAP_KEY(0x18c, KEY_VOICEMAIL), 150 HCONS_MAP_KEY(0x18d, KEY_ADDRESSBOOK), 151 HCONS_MAP_KEY(0x18e, KEY_CALENDAR), 152 HCONS_MAP_KEY(0x18f, KEY_TASKMANAGER), 153 HCONS_MAP_KEY(0x190, KEY_JOURNAL), 154 HCONS_MAP_KEY(0x191, KEY_FINANCE), 155 HCONS_MAP_KEY(0x192, KEY_CALC), 156 HCONS_MAP_KEY(0x193, KEY_PLAYER), 157 HCONS_MAP_KEY(0x194, KEY_FILE), 158 HCONS_MAP_KEY(0x196, KEY_WWW), 159 HCONS_MAP_KEY(0x199, KEY_CHAT), 160 HCONS_MAP_KEY(0x19c, KEY_LOGOFF), 161 HCONS_MAP_KEY(0x19e, KEY_COFFEE), 162 HCONS_MAP_KEY(0x19f, KEY_CONTROLPANEL), 163 HCONS_MAP_KEY(0x1a2, KEY_APPSELECT), 164 HCONS_MAP_KEY(0x1a3, KEY_NEXT), 165 HCONS_MAP_KEY(0x1a4, KEY_PREVIOUS), 166 HCONS_MAP_KEY(0x1a6, KEY_HELP), 167 HCONS_MAP_KEY(0x1a7, KEY_DOCUMENTS), 168 HCONS_MAP_KEY(0x1ab, KEY_SPELLCHECK), 169 HCONS_MAP_KEY(0x1ae, KEY_KEYBOARD), 170 HCONS_MAP_KEY(0x1b1, KEY_SCREENSAVER), 171 HCONS_MAP_KEY(0x1b4, KEY_FILE), 172 HCONS_MAP_KEY(0x1b6, KEY_IMAGES), 173 HCONS_MAP_KEY(0x1b7, KEY_AUDIO), 174 HCONS_MAP_KEY(0x1b8, KEY_VIDEO), 175 HCONS_MAP_KEY(0x1bc, KEY_MESSENGER), 176 HCONS_MAP_KEY(0x1bd, KEY_INFO), 177 HCONS_MAP_KEY(0x1cb, KEY_ASSISTANT), 178 HCONS_MAP_KEY(0x201, KEY_NEW), 179 HCONS_MAP_KEY(0x202, KEY_OPEN), 180 HCONS_MAP_KEY(0x203, KEY_CLOSE), 181 HCONS_MAP_KEY(0x204, KEY_EXIT), 182 HCONS_MAP_KEY(0x207, KEY_SAVE), 183 HCONS_MAP_KEY(0x208, KEY_PRINT), 184 HCONS_MAP_KEY(0x209, KEY_PROPS), 185 HCONS_MAP_KEY(0x21a, KEY_UNDO), 186 HCONS_MAP_KEY(0x21b, KEY_COPY), 187 HCONS_MAP_KEY(0x21c, KEY_CUT), 188 HCONS_MAP_KEY(0x21d, KEY_PASTE), 189 HCONS_MAP_KEY(0x21f, KEY_FIND), 190 HCONS_MAP_KEY(0x221, KEY_SEARCH), 191 HCONS_MAP_KEY(0x222, KEY_GOTO), 192 HCONS_MAP_KEY(0x223, KEY_HOMEPAGE), 193 HCONS_MAP_KEY(0x224, KEY_BACK), 194 HCONS_MAP_KEY(0x225, KEY_FORWARD), 195 HCONS_MAP_KEY(0x226, KEY_STOP), 196 HCONS_MAP_KEY(0x227, KEY_REFRESH), 197 HCONS_MAP_KEY(0x22a, KEY_BOOKMARKS), 198 HCONS_MAP_KEY(0x22d, KEY_ZOOMIN), 199 HCONS_MAP_KEY(0x22e, KEY_ZOOMOUT), 200 HCONS_MAP_KEY(0x22f, KEY_ZOOMRESET), 201 HCONS_MAP_KEY(0x232, KEY_FULL_SCREEN), 202 HCONS_MAP_KEY(0x233, KEY_SCROLLUP), 203 HCONS_MAP_KEY(0x234, KEY_SCROLLDOWN), 204 HCONS_MAP_REL(0x238, REL_HWHEEL), /* AC Pan */ 205 HCONS_MAP_KEY(0x23d, KEY_EDIT), 206 HCONS_MAP_KEY(0x25f, KEY_CANCEL), 207 HCONS_MAP_KEY(0x269, KEY_INSERT), 208 HCONS_MAP_KEY(0x26a, KEY_DELETE), 209 HCONS_MAP_KEY(0x279, KEY_REDO), 210 HCONS_MAP_KEY(0x289, KEY_REPLY), 211 HCONS_MAP_KEY(0x28b, KEY_FORWARDMAIL), 212 HCONS_MAP_KEY(0x28c, KEY_SEND), 213 HCONS_MAP_KEY(0x29d, KEY_KBD_LAYOUT_NEXT), 214 HCONS_MAP_KEY(0x2c7, KEY_KBDINPUTASSIST_PREV), 215 HCONS_MAP_KEY(0x2c8, KEY_KBDINPUTASSIST_NEXT), 216 HCONS_MAP_KEY(0x2c9, KEY_KBDINPUTASSIST_PREVGROUP), 217 HCONS_MAP_KEY(0x2ca, KEY_KBDINPUTASSIST_NEXTGROUP), 218 HCONS_MAP_KEY(0x2cb, KEY_KBDINPUTASSIST_ACCEPT), 219 HCONS_MAP_KEY(0x2cc, KEY_KBDINPUTASSIST_CANCEL), 220 HCONS_MAP_KEY(0x29f, KEY_SCALE), 221 }; 222 223 static const struct hid_device_id hcons_devs[] = { 224 { HID_TLC(HUP_CONSUMER, HUC_CONTROL) }, 225 }; 226 227 /* 228 * Emulate relative Consumer volume usage with pressing 229 * VOLUMEUP and VOLUMEDOWN keys appropriate number of times 230 */ 231 static int 232 hcons_rel_volume_cb(HIDMAP_CB_ARGS) 233 { 234 struct evdev_dev *evdev = HIDMAP_CB_GET_EVDEV(); 235 int32_t code; 236 int nrepeats; 237 238 switch (HIDMAP_CB_GET_STATE()) { 239 case HIDMAP_CB_IS_ATTACHING: 240 evdev_support_event(evdev, EV_KEY); 241 evdev_support_key(evdev, KEY_VOLUMEUP); 242 evdev_support_key(evdev, KEY_VOLUMEDOWN); 243 break; 244 case HIDMAP_CB_IS_RUNNING: 245 /* Nothing to report. */ 246 if (ctx.data == 0) 247 return (ENOMSG); 248 code = ctx.data > 0 ? KEY_VOLUMEUP : KEY_VOLUMEDOWN; 249 for (nrepeats = abs(ctx.data); nrepeats > 0; nrepeats--) { 250 evdev_push_key(evdev, code, 1); 251 evdev_push_key(evdev, code, 0); 252 } 253 break; 254 default: 255 break; 256 } 257 258 return (0); 259 } 260 261 static int 262 hcons_probe(device_t dev) 263 { 264 return (HIDMAP_PROBE(device_get_softc(dev), dev, 265 hcons_devs, hcons_map, "Consumer Control")); 266 } 267 268 static int 269 hcons_attach(device_t dev) 270 { 271 return (hidmap_attach(device_get_softc(dev))); 272 } 273 274 static int 275 hcons_detach(device_t dev) 276 { 277 return (hidmap_detach(device_get_softc(dev))); 278 } 279 280 static device_method_t hcons_methods[] = { 281 DEVMETHOD(device_probe, hcons_probe), 282 DEVMETHOD(device_attach, hcons_attach), 283 DEVMETHOD(device_detach, hcons_detach), 284 285 DEVMETHOD_END 286 }; 287 288 DEFINE_CLASS_0(hcons, hcons_driver, hcons_methods, sizeof(struct hidmap)); 289 DRIVER_MODULE(hcons, hidbus, hcons_driver, NULL, NULL); 290 MODULE_DEPEND(hcons, hid, 1, 1, 1); 291 MODULE_DEPEND(hcons, hidbus, 1, 1, 1); 292 MODULE_DEPEND(hcons, hidmap, 1, 1, 1); 293 MODULE_DEPEND(hcons, evdev, 1, 1, 1); 294 MODULE_VERSION(hcons, 1); 295 HID_PNP_INFO(hcons_devs); 296