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