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