1 1.7 christos /* $NetBSD: usb_subr_30.c,v 1.7 2023/07/31 17:41:17 christos Exp $ */ 2 1.2 pgoyette /* $FreeBSD: src/sys/dev/usb/usb_subr.c,v 1.18 1999/11/17 22:33:47 n_hibma Exp $ */ 3 1.2 pgoyette 4 1.2 pgoyette /* 5 1.2 pgoyette * Copyright (c) 1998, 2004 The NetBSD Foundation, Inc. 6 1.2 pgoyette * All rights reserved. 7 1.2 pgoyette * 8 1.2 pgoyette * This code is derived from software contributed to The NetBSD Foundation 9 1.2 pgoyette * by Lennart Augustsson (lennart (at) augustsson.net) at 10 1.2 pgoyette * Carlstedt Research & Technology. 11 1.2 pgoyette * 12 1.2 pgoyette * Redistribution and use in source and binary forms, with or without 13 1.2 pgoyette * modification, are permitted provided that the following conditions 14 1.2 pgoyette * are met: 15 1.2 pgoyette * 1. Redistributions of source code must retain the above copyright 16 1.2 pgoyette * notice, this list of conditions and the following disclaimer. 17 1.2 pgoyette * 2. Redistributions in binary form must reproduce the above copyright 18 1.2 pgoyette * notice, this list of conditions and the following disclaimer in the 19 1.2 pgoyette * documentation and/or other materials provided with the distribution. 20 1.2 pgoyette * 21 1.2 pgoyette * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 1.2 pgoyette * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 1.2 pgoyette * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 1.2 pgoyette * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 1.2 pgoyette * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 1.2 pgoyette * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 1.2 pgoyette * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 1.2 pgoyette * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 1.2 pgoyette * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 1.2 pgoyette * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 1.2 pgoyette * POSSIBILITY OF SUCH DAMAGE. 32 1.2 pgoyette */ 33 1.2 pgoyette 34 1.2 pgoyette #include <sys/cdefs.h> 35 1.7 christos __KERNEL_RCSID(0, "$NetBSD: usb_subr_30.c,v 1.7 2023/07/31 17:41:17 christos Exp $"); 36 1.2 pgoyette 37 1.2 pgoyette #ifdef _KERNEL_OPT 38 1.2 pgoyette #include "opt_compat_netbsd.h" 39 1.2 pgoyette #include "opt_usb.h" 40 1.2 pgoyette #endif 41 1.2 pgoyette 42 1.2 pgoyette #include <sys/param.h> 43 1.2 pgoyette #include <sys/systm.h> 44 1.2 pgoyette #include <sys/kernel.h> 45 1.2 pgoyette #include <sys/kmem.h> 46 1.2 pgoyette #include <sys/device.h> 47 1.2 pgoyette #include <sys/select.h> 48 1.2 pgoyette #include <sys/proc.h> 49 1.2 pgoyette 50 1.2 pgoyette #include <sys/bus.h> 51 1.2 pgoyette #include <sys/module.h> 52 1.2 pgoyette #include <sys/compat_stub.h> 53 1.2 pgoyette 54 1.2 pgoyette #include <compat/common/compat_mod.h> 55 1.2 pgoyette 56 1.2 pgoyette #include <dev/usb/usb.h> 57 1.2 pgoyette 58 1.2 pgoyette #include <dev/usb/usbdi.h> 59 1.2 pgoyette #include <dev/usb/usbdi_util.h> 60 1.2 pgoyette #include <dev/usb/usbdivar.h> 61 1.2 pgoyette #include <dev/usb/usbdevs.h> 62 1.2 pgoyette #include <dev/usb/usb_quirks.h> 63 1.2 pgoyette #include <dev/usb/usb_verbose.h> 64 1.2 pgoyette #include <dev/usb/usbhist.h> 65 1.2 pgoyette 66 1.7 christos static void usb_copy30_devinfo(struct usb_device_info30 *, 67 1.2 pgoyette const struct usb_device_info *); 68 1.2 pgoyette 69 1.7 christos static void 70 1.7 christos usb_copy30_devinfo(struct usb_device_info30 *uo, 71 1.2 pgoyette const struct usb_device_info *ue) 72 1.2 pgoyette { 73 1.2 pgoyette const unsigned char *p; 74 1.2 pgoyette unsigned char *q; 75 1.2 pgoyette int i, n; 76 1.2 pgoyette 77 1.2 pgoyette uo->udi_bus = ue->udi_bus; 78 1.2 pgoyette uo->udi_addr = ue->udi_addr; 79 1.2 pgoyette uo->udi_cookie = ue->udi_cookie; 80 1.2 pgoyette for (i = 0, p = (const unsigned char *)ue->udi_product, 81 1.2 pgoyette q = (unsigned char *)uo->udi_product; 82 1.2 pgoyette *p && i < USB_MAX_STRING_LEN - 1; p++) { 83 1.2 pgoyette if (*p < 0x80) 84 1.2 pgoyette q[i++] = *p; 85 1.2 pgoyette else { 86 1.2 pgoyette q[i++] = '?'; 87 1.2 pgoyette if ((*p & 0xe0) == 0xe0) 88 1.2 pgoyette p++; 89 1.2 pgoyette p++; 90 1.2 pgoyette } 91 1.2 pgoyette } 92 1.2 pgoyette q[i] = 0; 93 1.2 pgoyette 94 1.2 pgoyette for (i = 0, p = ue->udi_vendor, q = uo->udi_vendor; 95 1.2 pgoyette *p && i < USB_MAX_STRING_LEN - 1; p++) { 96 1.2 pgoyette if (* p < 0x80) 97 1.2 pgoyette q[i++] = *p; 98 1.2 pgoyette else { 99 1.2 pgoyette q[i++] = '?'; 100 1.2 pgoyette p++; 101 1.2 pgoyette if ((*p & 0xe0) == 0xe0) 102 1.2 pgoyette p++; 103 1.2 pgoyette } 104 1.2 pgoyette } 105 1.2 pgoyette q[i] = 0; 106 1.2 pgoyette 107 1.2 pgoyette memcpy(uo->udi_release, ue->udi_release, sizeof(uo->udi_release)); 108 1.2 pgoyette 109 1.2 pgoyette uo->udi_productNo = ue->udi_productNo; 110 1.2 pgoyette uo->udi_vendorNo = ue->udi_vendorNo; 111 1.2 pgoyette uo->udi_releaseNo = ue->udi_releaseNo; 112 1.2 pgoyette uo->udi_class = ue->udi_class; 113 1.2 pgoyette uo->udi_subclass = ue->udi_subclass; 114 1.2 pgoyette uo->udi_protocol = ue->udi_protocol; 115 1.2 pgoyette uo->udi_config = ue->udi_config; 116 1.2 pgoyette uo->udi_speed = ue->udi_speed; 117 1.2 pgoyette uo->udi_power = ue->udi_power; 118 1.2 pgoyette uo->udi_nports = ue->udi_nports; 119 1.2 pgoyette 120 1.2 pgoyette for (n=0; n<USB_MAX_DEVNAMES; n++) 121 1.2 pgoyette memcpy(uo->udi_devnames[n], 122 1.2 pgoyette ue->udi_devnames[n], USB_MAX_DEVNAMELEN); 123 1.2 pgoyette memcpy(uo->udi_ports, ue->udi_ports, sizeof(uo->udi_ports)); 124 1.2 pgoyette } 125 1.2 pgoyette 126 1.2 pgoyette static int 127 1.7 christos usbd_fill_deviceinfo30(struct usbd_device *dev, 128 1.7 christos struct usb_device_info30 *di, int usedev, 129 1.2 pgoyette void (*do_devinfo_vp)(struct usbd_device *, char *, size_t, char *, 130 1.2 pgoyette size_t, int, int), 131 1.2 pgoyette int (*do_printBCD)(char *cp, size_t l, int bcd)) 132 1.2 pgoyette { 133 1.2 pgoyette struct usbd_port *p; 134 1.5 christos size_t i, j; 135 1.5 christos int err; 136 1.2 pgoyette 137 1.2 pgoyette di->udi_bus = device_unit(dev->ud_bus->ub_usbctl); 138 1.2 pgoyette di->udi_addr = dev->ud_addr; 139 1.2 pgoyette di->udi_cookie = dev->ud_cookie; 140 1.2 pgoyette (*do_devinfo_vp)(dev, di->udi_vendor, sizeof(di->udi_vendor), 141 1.2 pgoyette di->udi_product, sizeof(di->udi_product), usedev, 0); 142 1.2 pgoyette (*do_printBCD)(di->udi_release, sizeof(di->udi_release), 143 1.2 pgoyette UGETW(dev->ud_ddesc.bcdDevice)); 144 1.2 pgoyette di->udi_vendorNo = UGETW(dev->ud_ddesc.idVendor); 145 1.2 pgoyette di->udi_productNo = UGETW(dev->ud_ddesc.idProduct); 146 1.2 pgoyette di->udi_releaseNo = UGETW(dev->ud_ddesc.bcdDevice); 147 1.2 pgoyette di->udi_class = dev->ud_ddesc.bDeviceClass; 148 1.2 pgoyette di->udi_subclass = dev->ud_ddesc.bDeviceSubClass; 149 1.2 pgoyette di->udi_protocol = dev->ud_ddesc.bDeviceProtocol; 150 1.2 pgoyette di->udi_config = dev->ud_config; 151 1.2 pgoyette di->udi_power = dev->ud_selfpowered ? 0 : dev->ud_power; 152 1.2 pgoyette di->udi_speed = dev->ud_speed; 153 1.2 pgoyette 154 1.2 pgoyette if (dev->ud_subdevlen > 0) { 155 1.2 pgoyette for (i = 0, j = 0; i < dev->ud_subdevlen && 156 1.2 pgoyette j < USB_MAX_DEVNAMES; i++) { 157 1.2 pgoyette if (!dev->ud_subdevs[i]) 158 1.2 pgoyette continue; 159 1.2 pgoyette strncpy(di->udi_devnames[j], 160 1.2 pgoyette device_xname(dev->ud_subdevs[i]), USB_MAX_DEVNAMELEN); 161 1.2 pgoyette di->udi_devnames[j][USB_MAX_DEVNAMELEN-1] = '\0'; 162 1.2 pgoyette j++; 163 1.2 pgoyette } 164 1.2 pgoyette } else { 165 1.2 pgoyette j = 0; 166 1.2 pgoyette } 167 1.2 pgoyette for (/* j is set */; j < USB_MAX_DEVNAMES; j++) 168 1.2 pgoyette di->udi_devnames[j][0] = 0; /* empty */ 169 1.2 pgoyette 170 1.2 pgoyette if (!dev->ud_hub) { 171 1.2 pgoyette di->udi_nports = 0; 172 1.2 pgoyette return 0; 173 1.2 pgoyette } 174 1.2 pgoyette 175 1.5 christos const u_int nports = dev->ud_hub->uh_hubdesc.bNbrPorts; 176 1.2 pgoyette for (i = 1; i <= __arraycount(di->udi_ports) && i <= nports; 177 1.2 pgoyette i++) { 178 1.2 pgoyette p = &dev->ud_hub->uh_ports[i - 1]; 179 1.2 pgoyette if (p->up_dev) 180 1.2 pgoyette err = p->up_dev->ud_addr; 181 1.2 pgoyette else { 182 1.2 pgoyette const int s = UGETW(p->up_status.wPortStatus); 183 1.2 pgoyette if (s & UPS_PORT_ENABLED) 184 1.2 pgoyette err = USB_PORT_ENABLED; 185 1.2 pgoyette else if (s & UPS_SUSPEND) 186 1.2 pgoyette err = USB_PORT_SUSPENDED; 187 1.2 pgoyette else if (s & UPS_PORT_POWER) 188 1.2 pgoyette err = USB_PORT_POWERED; 189 1.2 pgoyette else 190 1.2 pgoyette err = USB_PORT_DISABLED; 191 1.2 pgoyette } 192 1.2 pgoyette di->udi_ports[i - 1] = err; 193 1.2 pgoyette } 194 1.2 pgoyette di->udi_nports = nports; 195 1.2 pgoyette 196 1.2 pgoyette return 0; 197 1.2 pgoyette } 198 1.2 pgoyette 199 1.2 pgoyette static int 200 1.7 christos usb_copy_to30(struct usb_event *ue, struct usb_event30 *ueo, 201 1.2 pgoyette struct uio *uio) 202 1.2 pgoyette { 203 1.2 pgoyette 204 1.2 pgoyette ueo->ue_type = ue->ue_type; 205 1.2 pgoyette memcpy(&ueo->ue_time, &ue->ue_time, sizeof(struct timespec)); 206 1.2 pgoyette switch (ue->ue_type) { 207 1.2 pgoyette case USB_EVENT_DEVICE_ATTACH: 208 1.2 pgoyette case USB_EVENT_DEVICE_DETACH: 209 1.7 christos usb_copy30_devinfo(&ueo->u.ue_device, 210 1.2 pgoyette &ue->u.ue_device); 211 1.2 pgoyette break; 212 1.2 pgoyette 213 1.2 pgoyette case USB_EVENT_CTRLR_ATTACH: 214 1.2 pgoyette case USB_EVENT_CTRLR_DETACH: 215 1.2 pgoyette ueo->u.ue_ctrlr.ue_bus=ue->u.ue_ctrlr.ue_bus; 216 1.2 pgoyette break; 217 1.2 pgoyette 218 1.2 pgoyette case USB_EVENT_DRIVER_ATTACH: 219 1.2 pgoyette case USB_EVENT_DRIVER_DETACH: 220 1.2 pgoyette ueo->u.ue_driver.ue_cookie=ue->u.ue_driver.ue_cookie; 221 1.2 pgoyette memcpy(ueo->u.ue_driver.ue_devname, 222 1.2 pgoyette ue->u.ue_driver.ue_devname, 223 1.2 pgoyette sizeof(ue->u.ue_driver.ue_devname)); 224 1.2 pgoyette break; 225 1.2 pgoyette default: 226 1.2 pgoyette ; 227 1.2 pgoyette } 228 1.2 pgoyette 229 1.2 pgoyette return 0; 230 1.2 pgoyette } 231 1.2 pgoyette 232 1.2 pgoyette void 233 1.2 pgoyette usb_30_init(void) 234 1.2 pgoyette { 235 1.2 pgoyette 236 1.7 christos MODULE_HOOK_SET(usb_subr_fill_30_hook, usbd_fill_deviceinfo30); 237 1.7 christos MODULE_HOOK_SET(usb_subr_copy_30_hook, usb_copy_to30); 238 1.2 pgoyette } 239 1.2 pgoyette 240 1.2 pgoyette void 241 1.2 pgoyette usb_30_fini(void) 242 1.2 pgoyette { 243 1.2 pgoyette 244 1.4 pgoyette MODULE_HOOK_UNSET(usb_subr_fill_30_hook); 245 1.4 pgoyette MODULE_HOOK_UNSET(usb_subr_copy_30_hook); 246 1.2 pgoyette } 247