36#ifdef USB_GLOBAL_INCLUDE_FILE
37#include USB_GLOBAL_INCLUDE_FILE
39#include <sys/stdint.h>
40#include <sys/stddef.h>
45#include <sys/kernel.h>
47#include <sys/module.h>
50#include <sys/condvar.h>
51#include <sys/sysctl.h>
53#include <sys/unistd.h>
54#include <sys/callout.h>
55#include <sys/malloc.h>
62#define USB_DEBUG_VAR uhub_debug
79#include <contrib/dev/acpica/include/acpi.h>
80#include <contrib/dev/acpica/include/accommon.h>
81#include <dev/acpica/acpivar.h>
84#define ACPI_PLD_SIZE 20
87#define ACPI_UPC_CONNECTABLE 0x80000000
88#define ACPI_UPC_PORTTYPE(x) ((x)&0xff)
103 ACPI_DEVICE_INFO *devinfo;
109 ret = AcpiGetObjectInfo(ah, &devinfo);
110 if (ACPI_SUCCESS(ret)) {
111 if ((devinfo->Valid & ACPI_VALID_ADR) &&
112 (devinfo->Address == 0)) {
113 ret = AE_CTRL_TERMINATE;
124 const char *typelist[] = {
"TypeA",
"MiniAB",
"Express",
125 "USB3-A",
"USB3-B",
"USB-MicroB",
126 "USB3-MicroAB",
"USB3-PowerB",
127 "TypeC-USB2",
"TypeC-Switch",
129 const int last =
sizeof(typelist) /
sizeof(typelist[0]);
132 return "Proprietary";
135 return (
type < last) ? typelist[
type] :
"Unknown";
146 buf.Length = ACPI_ALLOCATE_BUFFER;
148 if (AcpiEvaluateObject(ah,
"_UPC", NULL, &buf) == AE_OK) {
149 ACPI_OBJECT *obj = buf.Pointer;
150 UINT64 porttypenum, conn;
151 uint8_t *connectable;
153 acpi_PkgInt(obj, 0, &conn);
154 acpi_PkgInt(obj, 1, &porttypenum);
155 connectable = conn ?
"" :
"non";
157 port->
upc = porttypenum;
161 device_printf(
dev,
"Port %u %sconnectable %s\n",
166 device_get_sysctl_ctx(
dev),
169 CTLFLAG_RD | CTLFLAG_MPSAFE,
170 SYSCTL_NULL_U32_PTR, port->
upc,
171 "UPC value. MSB is visible flag");
173 AcpiOsFree(buf.Pointer);
184 sbuf_new_for_sysctl(&sb, NULL, 256,
req);
185 sbuf_printf(&sb,
"Handle %s\n", acpi_name(port->
handle));
186 if (port->
upc == 0xffffffff) {
187 sbuf_printf(&sb,
"\tNo information\n");
190 sbuf_printf(&sb,
"\t");
192 sbuf_printf(&sb,
"Connectable ");
196 if ((port->
pld[0] & 0x80) == 0) {
198 "\tColor:#%02x%02x%02x\n",
199 port->
pld[1], port->
pld[2],
202 sbuf_printf(&sb,
"\tWidth %d mm Height %d mm\n",
203 port->
pld[4] | (port->
pld[5] << 8),
204 port->
pld[6] | (port->
pld[7] << 8));
205 if (port->
pld[8] & 1) {
206 sbuf_printf(&sb,
"\tVisible\n");
208 if (port->
pld[8] & 2) {
209 sbuf_printf(&sb,
"\tDock\n");
211 if (port->
pld[8] & 4) {
212 sbuf_printf(&sb,
"\tLid\n");
214 int panelpos = (port->
pld[8] >> 3) & 7;
215 const char *panposstr[] = {
"Top",
"Bottom",
"Left",
216 "Right",
"Front",
"Back",
217 "Unknown",
"Invalid"};
218 const char *shapestr[] = {
219 "Round",
"Oval",
"Square",
"VRect",
"HRect",
220 "VTrape",
"HTrape",
"Unknown",
"Chamferd",
221 "Rsvd",
"Rsvd",
"Rsvd",
"Rsvd",
222 "Rsvd",
"Rsvd",
"Rsvd",
"Rsvd"};
224 sbuf_printf(&sb,
"\tPanelPosition: %s\n", panposstr[panelpos]);
226 const char *posstr[] = {
"Upper",
"Center",
229 sbuf_printf(&sb,
"\tVertPosition: %s\n",
230 posstr[(port->
pld[8] >> 6) & 3]);
231 sbuf_printf(&sb,
"\tHorizPosition: %s\n",
232 posstr[(port->
pld[9]) & 3]);
234 sbuf_printf(&sb,
"\tShape: %s\n",
235 shapestr[(port->
pld[9] >> 2) & 0xf]);
236 sbuf_printf(&sb,
"\tGroup Orientation %s\n",
237 ((port->
pld[9] >> 6) & 1) ?
"Vertical" :
239 sbuf_printf(&sb,
"\tGroupToken %x\n",
241 | (port->
pld[10] << 1)) & 0xff);
242 sbuf_printf(&sb,
"\tGroupPosition %x\n",
243 ((port->
pld[10] >> 7)
244 | (port->
pld[11] << 1)) & 0xff);
245 sbuf_printf(&sb,
"\t%s %s %s\n",
246 (port->
pld[11] & 0x80) ?
248 (port->
pld[12] & 1) ?
"Eject" :
"",
249 (port->
pld[12] & 2) ?
"OSPM" :
""
252 if ((port->
pld[0] & 0x7f) >= 2) {
253 sbuf_printf(&sb,
"\tVOFF%d mm HOFF %dmm",
254 port->
pld[16] | (port->
pld[17] << 8),
255 port->
pld[18] | (port->
pld[19] << 8));
259 error = sbuf_finish(&sb);
272 buf.Length = ACPI_ALLOCATE_BUFFER;
274 if (AcpiEvaluateObject(ah,
"_PLD", NULL, &buf) == AE_OK) {
276 unsigned char *resbuf;
281 if (obj->Type == ACPI_TYPE_PACKAGE
282 && obj->Package.Elements[0].Type == ACPI_TYPE_BUFFER) {
285 obj1 = &obj->Package.Elements[0];
286 len = obj1->Buffer.Length;
287 resbuf = obj1->Buffer.Pointer;
288 }
else if (obj->Type == ACPI_TYPE_BUFFER) {
289 len = obj->Buffer.Length;
290 resbuf = obj->Buffer.Pointer;
295 memcpy(port->
pld, resbuf,
len);
297 device_get_sysctl_ctx(
dev), tree, OID_AUTO,
298 "pldraw", CTLFLAG_RD | CTLFLAG_MPSAFE,
299 port->
pld,
len,
"A",
"Raw PLD value");
302 device_printf(
dev,
"Revision:%d\n",
304 if ((resbuf[0] & 0x80) == 0) {
306 "Color:#%02x%02x%02x\n",
307 resbuf[1], resbuf[2],
310 device_printf(
dev,
"Width %d mm Height %d mm\n",
311 resbuf[4] | (resbuf[5] << 8),
312 resbuf[6] | (resbuf[7] << 8));
314 device_printf(
dev,
"Visible\n");
317 device_printf(
dev,
"Dock\n");
320 device_printf(
dev,
"Lid\n");
322 device_printf(
dev,
"PanelPosition: %d\n",
323 (resbuf[8] >> 3) & 7);
324 device_printf(
dev,
"VertPosition: %d\n",
325 (resbuf[8] >> 6) & 3);
326 device_printf(
dev,
"HorizPosition: %d\n",
328 device_printf(
dev,
"Shape: %d\n",
329 (resbuf[9] >> 2) & 0xf);
330 device_printf(
dev,
"80: %02x, %02x, %02x\n",
331 resbuf[9], resbuf[10], resbuf[11]);
332 device_printf(
dev,
"96: %02x, %02x, %02x, %02x\n",
333 resbuf[12], resbuf[13],
334 resbuf[14], resbuf[15]);
336 if ((resbuf[0] & 0x7f) >= 2) {
337 device_printf(
dev,
"VOFF%d mm HOFF %dmm",
338 resbuf[16] | (resbuf[17] << 8),
339 resbuf[18] | (resbuf[19] << 8));
343 AcpiOsFree(buf.Pointer);
355 grand = device_get_parent(device_get_parent(
dev));
357 if ((gah = acpi_get_handle(grand)) == NULL)
360 return (AcpiWalkNamespace(ACPI_TYPE_DEVICE, gah, 1,
367 ACPI_DEVICE_INFO *devinfo;
372 ret = AcpiGetObjectInfo(
ah, &devinfo);
373 if (ACPI_SUCCESS(ret)) {
374 if ((devinfo->Valid & ACPI_VALID_ADR) &&
375 (devinfo->Address > 0) &&
376 (devinfo->Address <= (uint64_t)sc->
nports)) {
377 char buf[] =
"portXXX";
378 struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(
dev);
379 struct sysctl_oid *oid;
380 struct sysctl_oid_list *tree;
382 snprintf(buf,
sizeof(buf),
"port%ju",
383 (uintmax_t)devinfo->Address);
384 oid = SYSCTL_ADD_NODE(ctx,
385 SYSCTL_CHILDREN(device_get_sysctl_tree(
dev)),
386 OID_AUTO, buf, CTLFLAG_RD | CTLFLAG_MPSAFE,
388 tree = SYSCTL_CHILDREN(oid);
390 sc->
port[devinfo->Address - 1].
upc = 0xffffffff;
393 SYSCTL_ADD_PROC(device_get_sysctl_ctx(
dev), tree,
395 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE,
396 &sc->
port[devinfo->Address - 1], 0,
407 return (AcpiWalkNamespace(ACPI_TYPE_DEVICE,
419 if (acpi_disabled(
"usb"))
423 if (ACPI_SUCCESS(
status) && ah != NULL &&
426 return (BUS_PROBE_DEFAULT + 1);
436 if (acpi_disabled(
"usb"))
439 ah = acpi_get_handle(
dev);
445 return (BUS_PROBE_DEFAULT + 1);
460 M_USBDEV, M_WAITOK | M_ZERO);
463 if (ACPI_SUCCESS(
status)){
475 free(sc->
port, M_USBDEV);
506 sc->
ah = acpi_get_handle(
dev);
508 if (sc->
ah == NULL) {
533 if ((idx == ACPI_IVAR_HANDLE) &&
537 *res = (uintptr_t)
ah;
552 sbuf_printf(sb,
" handle=%s", acpi_name(
ah));
559 if (strcmp(locator, BUS_LOCATOR_ACPI) == 0)
560 return (acpi_get_acpi_device_path(
bus,
child, locator, sb));
uint8_t pld[ACPI_PLD_SIZE]
struct acpi_uhub_port * port
struct usb_device * sc_udev
void uhub_find_iface_index(struct usb_hub *hub, device_t child, struct hub_result *res)
static int acpi_uhub_parse_upc(device_t dev, unsigned int p, ACPI_HANDLE ah, struct sysctl_oid_list *poid)
static int acpi_uhub_child_location(device_t parent, device_t child, struct sbuf *sb)
static int acpi_uhub_root_attach(device_t dev)
static driver_t acpi_uhub_driver
DRIVER_MODULE(uacpi, uhub, acpi_uhub_driver, uhub_devclass, 0, 0)
static int acpi_uhub_probe(device_t dev)
static int acpi_uhub_attach(device_t dev)
MODULE_DEPEND(uacpi, acpi, 1, 1, 1)
static device_method_t acpi_uhub_root_methods[]
static int acpi_uhub_root_probe(device_t dev)
static ACPI_STATUS acpi_usb_hub_port_probe_cb(ACPI_HANDLE ah, UINT32 lv, void *ctx, void **rv)
#define ACPI_UPC_CONNECTABLE
static int acpi_uhub_detach(device_t dev)
static int acpi_uhub_read_ivar(device_t dev, device_t child, int idx, uintptr_t *res)
static ACPI_STATUS acpi_usb_hub_port_probe(device_t dev, ACPI_HANDLE ah)
static devclass_t uhub_devclass
static UINT32 acpi_uhub_find_rh_cb(ACPI_HANDLE ah, UINT32 nl, void *ctx, void **status)
static int acpi_uhub_port_sysctl(SYSCTL_HANDLER_ARGS)
static int acpi_uhub_get_device_path(device_t bus, device_t child, const char *locator, struct sbuf *sb)
static kobj_class_t uhub_baseclasses[]
static int acpi_uhub_attach_common(device_t dev)
static device_method_t acpi_uhub_methods[]
static const char * acpi_uhub_upc_type(uint8_t type)
static driver_t acpi_uhub_root_driver
static int acpi_uhub_parse_pld(device_t dev, unsigned int p, ACPI_HANDLE ah, struct sysctl_oid_list *tree)
static ACPI_STATUS acpi_uhub_find_rh(device_t dev, ACPI_HANDLE *ah)
bus_child_location_t uhub_child_location
device_attach_t uhub_attach
bus_get_device_path_t uhub_get_device_path
device_probe_t uhub_probe
device_detach_t uhub_detach