1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2023 Vladimir Kondratyev <wulf@FreeBSD.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <sys/param.h>
29 #include <sys/bus.h>
30 #include <sys/endian.h>
31 #include <sys/kernel.h>
32 #include <sys/malloc.h>
33 #include <sys/module.h>
34 #include <sys/rman.h>
35 #include <sys/sbuf.h>
36 #include <sys/systm.h>
37
38 #include <machine/resource.h>
39
40 #include <contrib/dev/acpica/include/acpi.h>
41 #include <contrib/dev/acpica/include/accommon.h>
42 #include <contrib/dev/acpica/include/amlcode.h>
43 #include <dev/acpica/acpivar.h>
44
45 #include <dev/spibus/spibusvar.h>
46
47 /*
48 * Make a copy of ACPI_RESOURCE_SPI_SERIALBUS type and replace "pointer to ACPI
49 * object name string" field with pointer to ACPI object itself.
50 * This saves us extra strdup()/free() pair on acpi_spibus_get_acpi_res call.
51 */
52 typedef ACPI_RESOURCE_SPI_SERIALBUS ACPI_SPIBUS_RESOURCE_SPI_SERIALBUS;
53 #define ResourceSource_Handle ResourceSource.StringPtr
54
55 /* Hooks for the ACPI CA debugging infrastructure. */
56 #define _COMPONENT ACPI_BUS
57 ACPI_MODULE_NAME("SPI")
58
59 #if defined (__amd64__) || defined (__i386__)
60 static bool is_apple;
61 #endif
62
63 struct acpi_spibus_ivar {
64 struct spibus_ivar super_ivar;
65 ACPI_HANDLE handle;
66 };
67
68 static inline bool
acpi_resource_is_spi_serialbus(ACPI_RESOURCE * res)69 acpi_resource_is_spi_serialbus(ACPI_RESOURCE *res)
70 {
71 return (res->Type == ACPI_RESOURCE_TYPE_SERIAL_BUS &&
72 res->Data.CommonSerialBus.Type == ACPI_RESOURCE_SERIAL_TYPE_SPI);
73 }
74
75 static ACPI_STATUS
acpi_spibus_get_acpi_res_cb(ACPI_RESOURCE * res,void * context)76 acpi_spibus_get_acpi_res_cb(ACPI_RESOURCE *res, void *context)
77 {
78 ACPI_SPIBUS_RESOURCE_SPI_SERIALBUS *sb = context;
79 ACPI_STATUS status;
80 ACPI_HANDLE handle;
81
82 if (acpi_resource_is_spi_serialbus(res)) {
83 status = AcpiGetHandle(ACPI_ROOT_OBJECT,
84 res->Data.SpiSerialBus.ResourceSource.StringPtr, &handle);
85 if (ACPI_FAILURE(status))
86 return (status);
87 memcpy(sb, &res->Data.SpiSerialBus,
88 sizeof(ACPI_SPIBUS_RESOURCE_SPI_SERIALBUS));
89 /*
90 * replace "pointer to ACPI object name string" field
91 * with pointer to ACPI object itself.
92 */
93 sb->ResourceSource_Handle = handle;
94 return (AE_CTRL_TERMINATE);
95 } else if (res->Type == ACPI_RESOURCE_TYPE_END_TAG)
96 return (AE_NOT_FOUND);
97
98 return (AE_OK);
99 }
100
101 static void
acpi_spibus_dump_res(device_t dev,ACPI_SPIBUS_RESOURCE_SPI_SERIALBUS * sb)102 acpi_spibus_dump_res(device_t dev, ACPI_SPIBUS_RESOURCE_SPI_SERIALBUS *sb)
103 {
104 device_printf(dev, "found ACPI child\n");
105 printf(" DeviceSelection: 0x%04hx\n", sb->DeviceSelection);
106 printf(" ConnectionSpeed: %uHz\n", sb->ConnectionSpeed);
107 printf(" WireMode: %s\n",
108 sb->WireMode == ACPI_SPI_4WIRE_MODE ?
109 "FourWireMode" : "ThreeWireMode");
110 printf(" DevicePolarity: %s\n",
111 sb->DevicePolarity == ACPI_SPI_ACTIVE_LOW ?
112 "PolarityLow" : "PolarityHigh");
113 printf(" DataBitLength: %uBit\n", sb->DataBitLength);
114 printf(" ClockPhase: %s\n",
115 sb->ClockPhase == ACPI_SPI_FIRST_PHASE ?
116 "ClockPhaseFirst" : "ClockPhaseSecond");
117 printf(" ClockPolarity: %s\n",
118 sb->ClockPolarity == ACPI_SPI_START_LOW ?
119 "ClockPolarityLow" : "ClockPolarityHigh");
120 printf(" SlaveMode: %s\n",
121 sb->SlaveMode == ACPI_CONTROLLER_INITIATED ?
122 "ControllerInitiated" : "DeviceInitiated");
123 printf(" ConnectionSharing: %s\n", sb->ConnectionSharing == 0 ?
124 "Exclusive" : "Shared");
125 }
126
127 static int
acpi_spibus_get_acpi_res(device_t spibus,ACPI_HANDLE dev,struct spibus_ivar * res)128 acpi_spibus_get_acpi_res(device_t spibus, ACPI_HANDLE dev,
129 struct spibus_ivar *res)
130 {
131 ACPI_SPIBUS_RESOURCE_SPI_SERIALBUS sb;
132
133 /*
134 * Read "SPI Serial Bus Connection Resource Descriptor"
135 * described in p.19.6.126 of ACPI specification.
136 */
137 bzero(&sb, sizeof(ACPI_SPIBUS_RESOURCE_SPI_SERIALBUS));
138 if (ACPI_FAILURE(AcpiWalkResources(dev, "_CRS",
139 acpi_spibus_get_acpi_res_cb, &sb)))
140 return (ENXIO);
141 if (sb.ResourceSource_Handle !=
142 acpi_get_handle(device_get_parent(spibus)))
143 return (ENXIO);
144 if (bootverbose)
145 acpi_spibus_dump_res(spibus, &sb);
146 /*
147 * The Windows Baytrail and Braswell SPI host controller
148 * drivers uses 1 as the first (and only) value for ACPI
149 * DeviceSelection.
150 */
151 if (sb.DeviceSelection != 0 &&
152 (acpi_MatchHid(sb.ResourceSource_Handle, "80860F0E") ||
153 acpi_MatchHid(sb.ResourceSource_Handle, "8086228E")))
154 res->cs = sb.DeviceSelection - 1;
155 else
156 res->cs = sb.DeviceSelection;
157 res->mode =
158 (sb.ClockPhase != ACPI_SPI_FIRST_PHASE ? SPIBUS_MODE_CPHA : 0) |
159 (sb.ClockPolarity != ACPI_SPI_START_LOW ? SPIBUS_MODE_CPOL : 0);
160 res->clock = sb.ConnectionSpeed;
161
162 return (0);
163 }
164
165 #if defined (__amd64__) || defined (__i386__)
166 static int
acpi_spibus_get_apple_res(device_t spibus,ACPI_HANDLE dev,struct spibus_ivar * ivar)167 acpi_spibus_get_apple_res(device_t spibus, ACPI_HANDLE dev,
168 struct spibus_ivar *ivar)
169 {
170 /* a0b5b7c6-1318-441c-b0c9-fe695eaf949b */
171 static const uint8_t apple_guid[ACPI_UUID_LENGTH] = {
172 0xC6, 0xB7, 0xB5, 0xA0, 0x18, 0x13, 0x1C, 0x44,
173 0xB0, 0xC9, 0xFE, 0x69, 0x5E, 0xAF, 0x94, 0x9B,
174 };
175 ACPI_BUFFER buf;
176 ACPI_OBJECT *pkg, *comp;
177 ACPI_HANDLE parent;
178 char *k;
179 uint64_t val;
180
181 /* Apple does not use _CRS but nested devices for SPI slaves */
182 if (ACPI_FAILURE(AcpiGetParent(dev, &parent)))
183 return (ENXIO);
184 if (parent != acpi_get_handle(device_get_parent(spibus)))
185 return (ENXIO);
186 if (ACPI_FAILURE(acpi_EvaluateDSMTyped(dev, apple_guid,
187 1, 1, NULL, &buf, ACPI_TYPE_PACKAGE)))
188 return (ENXIO);
189
190 pkg = ((ACPI_OBJECT *)buf.Pointer);
191 if (pkg->Package.Count % 2 != 0) {
192 device_printf(spibus, "_DSM length %d not even\n",
193 pkg->Package.Count);
194 AcpiOsFree(pkg);
195 return (ENXIO);
196 }
197
198 if (bootverbose)
199 device_printf(spibus, "found ACPI child\n");
200
201 for (comp = pkg->Package.Elements;
202 comp < pkg->Package.Elements + pkg->Package.Count;
203 comp += 2) {
204
205 if (comp[0].Type != ACPI_TYPE_STRING ||
206 comp[1].Type != ACPI_TYPE_BUFFER) {
207 device_printf(spibus, "expected string+buffer, "
208 "got %d+%d\n", comp[0].Type, comp[1].Type);
209 continue;
210 }
211 k = comp[0].String.Pointer;
212 val = comp[1].Buffer.Length >= 8 ?
213 *(uint64_t *)comp[1].Buffer.Pointer : 0;
214
215 if (bootverbose)
216 printf(" %s: %ju\n", k, (intmax_t)val);
217
218 if (strcmp(k, "spiSclkPeriod") == 0) {
219 if (val != 0)
220 ivar->clock = 1000000000 / val;
221 } else if (strcmp(k, "spiSPO") == 0) {
222 if (val != 0)
223 ivar->mode |= SPIBUS_MODE_CPOL;
224 } else if (strcmp(k, "spiSPH") == 0) {
225 if (val != 0)
226 ivar->mode |= SPIBUS_MODE_CPHA;
227 } else if (strcmp(k, "spiCSDelay") == 0) {
228 ivar->cs_delay = val;
229 }
230 }
231
232 AcpiOsFree(pkg);
233
234 return (0);
235 }
236 #endif
237
238 static int
acpi_spibus_delete_acpi_child(ACPI_HANDLE handle)239 acpi_spibus_delete_acpi_child(ACPI_HANDLE handle)
240 {
241 device_t acpi_child, acpi0;
242
243 /* Delete existing child of acpi bus */
244 acpi_child = acpi_get_device(handle);
245 if (acpi_child != NULL) {
246 acpi0 = devclass_get_device(devclass_find("acpi"), 0);
247 if (device_get_parent(acpi_child) != acpi0)
248 return (ENXIO);
249
250 if (device_is_attached(acpi_child))
251 return (ENXIO);
252
253 if (device_delete_child(acpi0, acpi_child) != 0)
254 return (ENXIO);
255 }
256
257 return (0);
258 }
259
260 static device_t
acpi_spibus_add_child(device_t dev,u_int order,const char * name,int unit)261 acpi_spibus_add_child(device_t dev, u_int order, const char *name, int unit)
262 {
263 return (spibus_add_child_common(
264 dev, order, name, unit, sizeof(struct acpi_spibus_ivar)));
265 }
266
267 static ACPI_STATUS
acpi_spibus_enumerate_child(ACPI_HANDLE handle,UINT32 level,void * context,void ** result)268 acpi_spibus_enumerate_child(ACPI_HANDLE handle, UINT32 level,
269 void *context, void **result)
270 {
271 device_t spibus, child;
272 struct spibus_ivar res;
273 ACPI_STATUS status;
274 UINT32 sta;
275 bool found = false;
276
277 spibus = context;
278
279 /*
280 * If no _STA method or if it failed, then assume that
281 * the device is present.
282 */
283 if (!ACPI_FAILURE(acpi_GetInteger(handle, "_STA", &sta)) &&
284 !ACPI_DEVICE_PRESENT(sta))
285 return (AE_OK);
286
287 if (!acpi_has_hid(handle))
288 return (AE_OK);
289
290 bzero(&res, sizeof(res));
291 if (acpi_spibus_get_acpi_res(spibus, handle, &res) == 0)
292 found = true;
293 #if defined (__amd64__) || defined (__i386__)
294 if (!found && is_apple &&
295 acpi_spibus_get_apple_res(spibus, handle, &res) == 0)
296 found = true;
297 #endif
298 if (!found || res.clock == 0)
299 return (AE_OK);
300
301 /* Delete existing child of acpi bus */
302 if (acpi_spibus_delete_acpi_child(handle) != 0)
303 return (AE_OK);
304
305 child = BUS_ADD_CHILD(spibus, 0, NULL, -1);
306 if (child == NULL) {
307 device_printf(spibus, "add child failed\n");
308 return (AE_OK);
309 }
310
311 spibus_set_cs(child, res.cs);
312 spibus_set_mode(child, res.mode);
313 spibus_set_clock(child, res.clock);
314 spibus_set_cs_delay(child, res.cs_delay);
315 acpi_set_handle(child, handle);
316 acpi_parse_resources(child, handle, &acpi_res_parse_set, NULL);
317
318 /*
319 * Update ACPI-CA to use the IIC enumerated device_t for this handle.
320 */
321 status = AcpiAttachData(handle, acpi_fake_objhandler, child);
322 if (ACPI_FAILURE(status))
323 printf("WARNING: Unable to attach object data to %s - %s\n",
324 acpi_name(handle), AcpiFormatException(status));
325
326 return (AE_OK);
327 }
328
329 static ACPI_STATUS
acpi_spibus_enumerate_children(device_t dev)330 acpi_spibus_enumerate_children(device_t dev)
331 {
332 return (AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
333 ACPI_UINT32_MAX, acpi_spibus_enumerate_child, NULL, dev, NULL));
334 }
335
336 static void
acpi_spibus_set_power_children(device_t dev,int state,bool all_children)337 acpi_spibus_set_power_children(device_t dev, int state, bool all_children)
338 {
339 device_t *devlist;
340 int i, numdevs;
341
342 if (device_get_children(dev, &devlist, &numdevs) != 0)
343 return;
344
345 for (i = 0; i < numdevs; i++)
346 if (all_children || device_is_attached(devlist[i]) != 0)
347 acpi_set_powerstate(devlist[i], state);
348
349 free(devlist, M_TEMP);
350 }
351
352 static int
acpi_spibus_probe(device_t dev)353 acpi_spibus_probe(device_t dev)
354 {
355 ACPI_HANDLE handle;
356 device_t controller;
357
358 if (acpi_disabled("spibus"))
359 return (ENXIO);
360
361 controller = device_get_parent(dev);
362 if (controller == NULL)
363 return (ENXIO);
364
365 handle = acpi_get_handle(controller);
366 if (handle == NULL)
367 return (ENXIO);
368
369 device_set_desc(dev, "SPI bus (ACPI-hinted)");
370 return (BUS_PROBE_DEFAULT + 1);
371 }
372
373 static int
acpi_spibus_attach(device_t dev)374 acpi_spibus_attach(device_t dev)
375 {
376
377 #if defined (__amd64__) || defined (__i386__)
378 char *vendor = kern_getenv("smbios.bios.vendor");
379 if (vendor != NULL &&
380 (strcmp(vendor, "Apple Inc.") == 0 ||
381 strcmp(vendor, "Apple Computer, Inc.") == 0))
382 is_apple = true;
383 #endif
384
385 if (ACPI_FAILURE(acpi_spibus_enumerate_children(dev)))
386 device_printf(dev, "children enumeration failed\n");
387
388 acpi_spibus_set_power_children(dev, ACPI_STATE_D0, true);
389 return (spibus_attach(dev));
390 }
391
392 static int
acpi_spibus_detach(device_t dev)393 acpi_spibus_detach(device_t dev)
394 {
395 acpi_spibus_set_power_children(dev, ACPI_STATE_D3, false);
396
397 return (spibus_detach(dev));
398 }
399
400 static int
acpi_spibus_suspend(device_t dev)401 acpi_spibus_suspend(device_t dev)
402 {
403 acpi_spibus_set_power_children(dev, ACPI_STATE_D3, false);
404
405 return (bus_generic_suspend(dev));
406 }
407
408 static int
acpi_spibus_resume(device_t dev)409 acpi_spibus_resume(device_t dev)
410 {
411 acpi_spibus_set_power_children(dev, ACPI_STATE_D0, false);
412
413 return (bus_generic_resume(dev));
414 }
415
416 #ifndef INTRNG
417 /* Mostly copy of acpi_alloc_resource() */
418 static struct resource *
acpi_spibus_alloc_resource(device_t dev,device_t child,int type,int * rid,rman_res_t start,rman_res_t end,rman_res_t count,u_int flags)419 acpi_spibus_alloc_resource(device_t dev, device_t child, int type, int *rid,
420 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
421 {
422 ACPI_RESOURCE ares;
423 struct resource_list *rl;
424 struct resource *res;
425
426 if (device_get_parent(child) != dev)
427 return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
428 type, rid, start, end, count, flags));
429
430 rl = BUS_GET_RESOURCE_LIST(dev, child);
431 if (rl == NULL)
432 return (NULL);
433
434 res = resource_list_alloc(rl, dev, child, type, rid,
435 start, end, count, flags);
436 if (res != NULL && type == SYS_RES_IRQ &&
437 ACPI_SUCCESS(acpi_lookup_irq_resource(child, *rid, res, &ares)))
438 acpi_config_intr(child, &ares);
439
440 return (res);
441 }
442 #endif
443
444 /*
445 * If this device is an ACPI child but no one claimed it, attempt
446 * to power it off. We'll power it back up when a driver is added.
447 */
448 static void
acpi_spibus_probe_nomatch(device_t bus,device_t child)449 acpi_spibus_probe_nomatch(device_t bus, device_t child)
450 {
451 spibus_probe_nomatch(bus, child);
452 acpi_set_powerstate(child, ACPI_STATE_D3);
453 }
454
455 /*
456 * If a new driver has a chance to probe a child, first power it up.
457 */
458 static void
acpi_spibus_driver_added(device_t dev,driver_t * driver)459 acpi_spibus_driver_added(device_t dev, driver_t *driver)
460 {
461 device_t child, *devlist;
462 int i, numdevs;
463
464 DEVICE_IDENTIFY(driver, dev);
465 if (device_get_children(dev, &devlist, &numdevs) != 0)
466 return;
467
468 for (i = 0; i < numdevs; i++) {
469 child = devlist[i];
470 if (device_get_state(child) == DS_NOTPRESENT) {
471 acpi_set_powerstate(child, ACPI_STATE_D0);
472 if (device_probe_and_attach(child) != 0)
473 acpi_set_powerstate(child, ACPI_STATE_D3);
474 }
475 }
476 free(devlist, M_TEMP);
477 }
478
479 static void
acpi_spibus_child_deleted(device_t bus,device_t child)480 acpi_spibus_child_deleted(device_t bus, device_t child)
481 {
482 struct acpi_spibus_ivar *devi = device_get_ivars(child);
483
484 if (acpi_get_device(devi->handle) == child)
485 AcpiDetachData(devi->handle, acpi_fake_objhandler);
486 }
487
488 static int
acpi_spibus_read_ivar(device_t bus,device_t child,int which,uintptr_t * res)489 acpi_spibus_read_ivar(device_t bus, device_t child, int which, uintptr_t *res)
490 {
491 struct acpi_spibus_ivar *devi = device_get_ivars(child);
492
493 switch (which) {
494 case ACPI_IVAR_HANDLE:
495 *res = (uintptr_t)devi->handle;
496 break;
497 default:
498 return (spibus_read_ivar(bus, child, which, res));
499 }
500
501 return (0);
502 }
503
504 static int
acpi_spibus_write_ivar(device_t bus,device_t child,int which,uintptr_t val)505 acpi_spibus_write_ivar(device_t bus, device_t child, int which, uintptr_t val)
506 {
507 struct acpi_spibus_ivar *devi = device_get_ivars(child);
508
509 switch (which) {
510 case ACPI_IVAR_HANDLE:
511 if (devi->handle != NULL)
512 return (EINVAL);
513 devi->handle = (ACPI_HANDLE)val;
514 break;
515 default:
516 return (spibus_write_ivar(bus, child, which, val));
517 }
518
519 return (0);
520 }
521
522 /* Location hint for devctl(8). Concatenate IIC and ACPI hints. */
523 static int
acpi_spibus_child_location(device_t bus,device_t child,struct sbuf * sb)524 acpi_spibus_child_location(device_t bus, device_t child, struct sbuf *sb)
525 {
526 struct acpi_spibus_ivar *devi = device_get_ivars(child);
527 int error;
528
529 /* read SPI location hint string into the buffer. */
530 error = spibus_child_location(bus, child, sb);
531 if (error != 0)
532 return (error);
533
534 /* Place ACPI string right after IIC one's terminating NUL. */
535 if (devi->handle != NULL)
536 sbuf_printf(sb, " handle=%s", acpi_name(devi->handle));
537
538 return (0);
539 }
540
541 /* PnP information for devctl(8). */
542 static int
acpi_spibus_child_pnpinfo(device_t bus,device_t child,struct sbuf * sb)543 acpi_spibus_child_pnpinfo(device_t bus, device_t child, struct sbuf *sb)
544 {
545 struct acpi_spibus_ivar *devi = device_get_ivars(child);
546
547 return (
548 devi->handle == NULL ? ENOTSUP : acpi_pnpinfo(devi->handle, sb));
549 }
550
551 static device_method_t acpi_spibus_methods[] = {
552 /* Device interface */
553 DEVMETHOD(device_probe, acpi_spibus_probe),
554 DEVMETHOD(device_attach, acpi_spibus_attach),
555 DEVMETHOD(device_detach, acpi_spibus_detach),
556 DEVMETHOD(device_suspend, acpi_spibus_suspend),
557 DEVMETHOD(device_resume, acpi_spibus_resume),
558
559 /* Bus interface */
560 #ifndef INTRNG
561 DEVMETHOD(bus_alloc_resource, acpi_spibus_alloc_resource),
562 #endif
563 DEVMETHOD(bus_add_child, acpi_spibus_add_child),
564 DEVMETHOD(bus_child_deleted, spibus_child_deleted),
565 DEVMETHOD(bus_probe_nomatch, acpi_spibus_probe_nomatch),
566 DEVMETHOD(bus_driver_added, acpi_spibus_driver_added),
567 DEVMETHOD(bus_child_deleted, acpi_spibus_child_deleted),
568 DEVMETHOD(bus_read_ivar, acpi_spibus_read_ivar),
569 DEVMETHOD(bus_write_ivar, acpi_spibus_write_ivar),
570 DEVMETHOD(bus_child_location, acpi_spibus_child_location),
571 DEVMETHOD(bus_child_pnpinfo, acpi_spibus_child_pnpinfo),
572 DEVMETHOD(bus_get_device_path, acpi_get_acpi_device_path),
573
574 DEVMETHOD_END,
575 };
576
577 DEFINE_CLASS_1(spibus, acpi_spibus_driver, acpi_spibus_methods,
578 sizeof(struct spibus_softc), spibus_driver);
579 DRIVER_MODULE(acpi_spibus, spi, acpi_spibus_driver, NULL, NULL);
580 MODULE_VERSION(acpi_spibus, 1);
581 MODULE_DEPEND(acpi_spibus, acpi, 1, 1, 1);
582