1 /* $OpenBSD: ujoy.c,v 1.4 2022/07/02 08:50:42 visa Exp $ */ 2 3 /* 4 * Copyright (c) 2021 Thomas Frohwein <thfr@openbsd.org> 5 * Copyright (c) 2021 Bryan Steele <brynet@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/param.h> 21 #include <sys/systm.h> 22 #include <sys/kernel.h> 23 #include <sys/malloc.h> 24 #include <sys/signalvar.h> 25 #include <sys/device.h> 26 #include <sys/ioctl.h> 27 #include <sys/conf.h> 28 #include <sys/tty.h> 29 #include <sys/proc.h> 30 #include <sys/vnode.h> 31 #include <sys/fcntl.h> 32 33 #include <dev/usb/usb.h> 34 #include <dev/usb/usbhid.h> 35 36 #include <dev/usb/usbdevs.h> 37 #include <dev/usb/usbdi.h> 38 #include <dev/usb/usbdi_util.h> 39 40 #include <dev/usb/uhidev.h> 41 #include <dev/usb/uhid.h> 42 43 int ujoy_match(struct device *, void *, void *); 44 45 struct cfdriver ujoy_cd = { 46 NULL, "ujoy", DV_DULL 47 }; 48 49 const struct cfattach ujoy_ca = { 50 sizeof(struct uhid_softc), 51 ujoy_match, 52 uhid_attach, 53 uhid_detach, 54 }; 55 56 /* 57 * XXX workaround: 58 * 59 * This is a copy of sys/dev/hid/hid.c:hid_is_collection(), synced up to the 60 * NetBSD version. Our current hid_is_collection() is not playing nice with 61 * all HID devices like the PS4 controller. But applying this version 62 * globally breaks other HID devices like ims(4) and imt(4). Until our global 63 * hid_is_collection() can't be fixed to play nice with all HID devices, we 64 * go for this dedicated ujoy(4) version. 65 */ 66 int 67 ujoy_hid_is_collection(const void *desc, int size, uint8_t id, int32_t usage) 68 { 69 struct hid_data *hd; 70 struct hid_item hi; 71 uint32_t coll_usage = ~0; 72 73 hd = hid_start_parse(desc, size, hid_input); 74 if (hd == NULL) 75 return (0); 76 77 while (hid_get_item(hd, &hi)) { 78 if (hi.kind == hid_collection && 79 hi.collection == HCOLL_APPLICATION) 80 coll_usage = hi.usage; 81 82 if (hi.kind == hid_endcollection) 83 coll_usage = ~0; 84 85 if (hi.kind == hid_input && 86 coll_usage == usage && 87 hi.report_ID == id) { 88 hid_end_parse(hd); 89 return (1); 90 } 91 } 92 hid_end_parse(hd); 93 94 return (0); 95 } 96 97 int 98 ujoy_match(struct device *parent, void *match, void *aux) 99 { 100 struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux; 101 int size; 102 void *desc; 103 int ret = UMATCH_NONE; 104 105 if (UHIDEV_CLAIM_MULTIPLE_REPORTID(uha)) 106 return (ret); 107 108 /* Find the general usage page and gamecontroller collections */ 109 uhidev_get_report_desc(uha->parent, &desc, &size); 110 111 if (ujoy_hid_is_collection(desc, size, uha->reportid, 112 HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_JOYSTICK))) 113 ret = UMATCH_IFACECLASS; 114 115 if (ujoy_hid_is_collection(desc, size, uha->reportid, 116 HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_GAME_PAD))) 117 ret = UMATCH_IFACECLASS; 118 119 return (ret); 120 } 121 122 int 123 ujoyopen(dev_t dev, int flag, int mode, struct proc *p) 124 { 125 /* Restrict ujoy devices to read operations */ 126 if ((flag & FWRITE)) 127 return (EPERM); 128 return (uhid_do_open(dev, flag, mode, p)); 129 } 130 131 int 132 ujoyioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) 133 { 134 switch (cmd) { 135 case FIONBIO: 136 case FIOASYNC: 137 case USB_GET_DEVICEINFO: 138 case USB_GET_REPORT: 139 case USB_GET_REPORT_DESC: 140 case USB_GET_REPORT_ID: 141 break; 142 default: 143 return (EPERM); 144 } 145 146 return (uhidioctl(dev, cmd, addr, flag, p)); 147 } 148