1 /* $NetBSD: usb_subr_30.c,v 1.4 2019/03/01 11:06:56 pgoyette 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.4 2019/03/01 11:06:56 pgoyette 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 66 Static void usb_copy_old_devinfo(struct usb_device_info_old *, 67 const struct usb_device_info *); 68 69 Static void 70 usb_copy_old_devinfo(struct usb_device_info_old *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 126 static int 127 usbd_fill_deviceinfo_old(struct usbd_device *dev, 128 struct usb_device_info_old *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 int i, j, err; 135 136 di->udi_bus = device_unit(dev->ud_bus->ub_usbctl); 137 di->udi_addr = dev->ud_addr; 138 di->udi_cookie = dev->ud_cookie; 139 (*do_devinfo_vp)(dev, di->udi_vendor, sizeof(di->udi_vendor), 140 di->udi_product, sizeof(di->udi_product), usedev, 0); 141 (*do_printBCD)(di->udi_release, sizeof(di->udi_release), 142 UGETW(dev->ud_ddesc.bcdDevice)); 143 di->udi_vendorNo = UGETW(dev->ud_ddesc.idVendor); 144 di->udi_productNo = UGETW(dev->ud_ddesc.idProduct); 145 di->udi_releaseNo = UGETW(dev->ud_ddesc.bcdDevice); 146 di->udi_class = dev->ud_ddesc.bDeviceClass; 147 di->udi_subclass = dev->ud_ddesc.bDeviceSubClass; 148 di->udi_protocol = dev->ud_ddesc.bDeviceProtocol; 149 di->udi_config = dev->ud_config; 150 di->udi_power = dev->ud_selfpowered ? 0 : dev->ud_power; 151 di->udi_speed = dev->ud_speed; 152 153 if (dev->ud_subdevlen > 0) { 154 for (i = 0, j = 0; i < dev->ud_subdevlen && 155 j < USB_MAX_DEVNAMES; i++) { 156 if (!dev->ud_subdevs[i]) 157 continue; 158 strncpy(di->udi_devnames[j], 159 device_xname(dev->ud_subdevs[i]), USB_MAX_DEVNAMELEN); 160 di->udi_devnames[j][USB_MAX_DEVNAMELEN-1] = '\0'; 161 j++; 162 } 163 } else { 164 j = 0; 165 } 166 for (/* j is set */; j < USB_MAX_DEVNAMES; j++) 167 di->udi_devnames[j][0] = 0; /* empty */ 168 169 if (!dev->ud_hub) { 170 di->udi_nports = 0; 171 return 0; 172 } 173 174 const int nports = dev->ud_hub->uh_hubdesc.bNbrPorts; 175 for (i = 1; i <= __arraycount(di->udi_ports) && i <= nports; 176 i++) { 177 p = &dev->ud_hub->uh_ports[i - 1]; 178 if (p->up_dev) 179 err = p->up_dev->ud_addr; 180 else { 181 const int s = UGETW(p->up_status.wPortStatus); 182 if (s & UPS_PORT_ENABLED) 183 err = USB_PORT_ENABLED; 184 else if (s & UPS_SUSPEND) 185 err = USB_PORT_SUSPENDED; 186 else if (s & UPS_PORT_POWER) 187 err = USB_PORT_POWERED; 188 else 189 err = USB_PORT_DISABLED; 190 } 191 di->udi_ports[i - 1] = err; 192 } 193 di->udi_nports = nports; 194 195 return 0; 196 } 197 198 static int 199 usb_copy_to_old30(struct usb_event *ue, struct usb_event_old *ueo, 200 struct uio *uio) 201 { 202 203 ueo->ue_type = ue->ue_type; 204 memcpy(&ueo->ue_time, &ue->ue_time, sizeof(struct timespec)); 205 switch (ue->ue_type) { 206 case USB_EVENT_DEVICE_ATTACH: 207 case USB_EVENT_DEVICE_DETACH: 208 usb_copy_old_devinfo(&ueo->u.ue_device, 209 &ue->u.ue_device); 210 break; 211 212 case USB_EVENT_CTRLR_ATTACH: 213 case USB_EVENT_CTRLR_DETACH: 214 ueo->u.ue_ctrlr.ue_bus=ue->u.ue_ctrlr.ue_bus; 215 break; 216 217 case USB_EVENT_DRIVER_ATTACH: 218 case USB_EVENT_DRIVER_DETACH: 219 ueo->u.ue_driver.ue_cookie=ue->u.ue_driver.ue_cookie; 220 memcpy(ueo->u.ue_driver.ue_devname, 221 ue->u.ue_driver.ue_devname, 222 sizeof(ue->u.ue_driver.ue_devname)); 223 break; 224 default: 225 ; 226 } 227 228 return 0; 229 } 230 231 void 232 usb_30_init(void) 233 { 234 235 MODULE_HOOK_SET(usb_subr_fill_30_hook, "usb_30", 236 usbd_fill_deviceinfo_old); 237 MODULE_HOOK_SET(usb_subr_copy_30_hook, "usb_30", usb_copy_to_old30); 238 } 239 240 void 241 usb_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