alpm.c revision 49195
1/*- 2 * Copyright (c) 1998, 1999 Nicolas Souchu 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $Id: alpm.c,v 1.5 1999/07/03 20:17:00 peter Exp $ 27 * 28 */ 29 30/* 31 * Power Management support for the Acer M15x3 chipsets 32 */ 33#include <sys/param.h> 34#include <sys/kernel.h> 35#include <sys/systm.h> 36#include <sys/module.h> 37#include <sys/bus.h> 38#include <sys/conf.h> 39#include <sys/buf.h> 40#include <sys/uio.h> 41#include <sys/malloc.h> 42 43#include <machine/clock.h> 44 45#include <machine/bus_pio.h> 46#include <machine/bus_memio.h> 47#include <machine/bus.h> 48 49#include <pci/pcivar.h> 50#include <pci/pcireg.h> 51 52#include <dev/iicbus/iiconf.h> 53#include <dev/smbus/smbconf.h> 54#include "smbus_if.h" 55 56#include "alpm.h" 57 58#define ALPM_DEBUG(x) if (alpm_debug) (x) 59 60#ifdef DEBUG 61static int alpm_debug = 1; 62#else 63static int alpm_debug = 0; 64#endif 65 66#define ACER_M1543_PMU_ID 0x710110b9 67 68/* Uncomment this line to force another I/O base address for SMB */ 69/* #define ALPM_SMBIO_BASE_ADDR 0x3a80 */ 70 71/* I/O registers offsets - the base address is programmed via the 72 * SMBBA PCI configuration register 73 */ 74#define SMBSTS 0x0 /* SMBus host/slave status register */ 75#define SMBCMD 0x1 /* SMBus host/slave command register */ 76#define SMBSTART 0x2 /* start to generate programmed cycle */ 77#define SMBHADDR 0x3 /* host address register */ 78#define SMBHDATA 0x4 /* data A register for host controller */ 79#define SMBHDATB 0x5 /* data B register for host controller */ 80#define SMBHBLOCK 0x6 /* block register for host controller */ 81#define SMBHCMD 0x7 /* command register for host controller */ 82 83/* SMBSTS masks */ 84#define TERMINATE 0x80 85#define BUS_COLLI 0x40 86#define DEVICE_ERR 0x20 87#define SMI_I_STS 0x10 88#define HST_BSY 0x08 89#define IDL_STS 0x04 90#define HSTSLV_STS 0x02 91#define HSTSLV_BSY 0x01 92 93/* SMBCMD masks */ 94#define SMB_BLK_CLR 0x80 95#define T_OUT_CMD 0x08 96#define ABORT_HOST 0x04 97 98/* SMBus commands */ 99#define SMBQUICK 0x00 100#define SMBSRBYTE 0x10 /* send/receive byte */ 101#define SMBWRBYTE 0x20 /* write/read byte */ 102#define SMBWRWORD 0x30 /* write/read word */ 103#define SMBWRBLOCK 0x40 /* write/read block */ 104 105/* PCI configuration registers and masks 106 */ 107#define COM 0x4 108#define COM_ENABLE_IO 0x1 109 110#define SMBBA 0x14 111 112#define ATPC 0x5b 113#define ATPC_SMBCTRL 0x04 114 115#define SMBHSI 0xe0 116#define SMBHSI_SLAVE 0x2 117#define SMBHSI_HOST 0x1 118 119#define SMBHCBC 0xe2 120#define SMBHCBC_CLOCK 0x70 121 122#define SMBCLOCK_149K 0x0 123#define SMBCLOCK_74K 0x20 124#define SMBCLOCK_37K 0x40 125#define SMBCLOCK_223K 0x80 126#define SMBCLOCK_111K 0xa0 127#define SMBCLOCK_55K 0xc0 128 129struct alpm_data { 130 int base; 131 bus_space_tag_t smbst; 132 bus_space_handle_t smbsh; 133 pcici_t tag; 134}; 135struct alpm_data alpmdata[NALPM]; 136 137struct alsmb_softc { 138 int base; 139 device_t smbus; 140 struct alpm_data *alpm; 141}; 142 143#define ALPM_SMBINB(alsmb,register) \ 144 (bus_space_read_1(alsmb->alpm->smbst, alsmb->alpm->smbsh, register)) 145#define ALPM_SMBOUTB(alsmb,register,value) \ 146 (bus_space_write_1(alsmb->alpm->smbst, alsmb->alpm->smbsh, register, value)) 147 148static int alsmb_probe(device_t); 149static int alsmb_attach(device_t); 150static int alsmb_smb_callback(device_t, int, caddr_t *); 151static int alsmb_smb_quick(device_t dev, u_char slave, int how); 152static int alsmb_smb_sendb(device_t dev, u_char slave, char byte); 153static int alsmb_smb_recvb(device_t dev, u_char slave, char *byte); 154static int alsmb_smb_writeb(device_t dev, u_char slave, char cmd, char byte); 155static int alsmb_smb_readb(device_t dev, u_char slave, char cmd, char *byte); 156static int alsmb_smb_writew(device_t dev, u_char slave, char cmd, short word); 157static int alsmb_smb_readw(device_t dev, u_char slave, char cmd, short *word); 158static int alsmb_smb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); 159static int alsmb_smb_bread(device_t dev, u_char slave, char cmd, u_char count, char *byte); 160 161static devclass_t alsmb_devclass; 162 163static device_method_t alsmb_methods[] = { 164 /* device interface */ 165 DEVMETHOD(device_probe, alsmb_probe), 166 DEVMETHOD(device_attach, alsmb_attach), 167 168 /* bus interface */ 169 DEVMETHOD(bus_print_child, bus_generic_print_child), 170 171 /* smbus interface */ 172 DEVMETHOD(smbus_callback, alsmb_smb_callback), 173 DEVMETHOD(smbus_quick, alsmb_smb_quick), 174 DEVMETHOD(smbus_sendb, alsmb_smb_sendb), 175 DEVMETHOD(smbus_recvb, alsmb_smb_recvb), 176 DEVMETHOD(smbus_writeb, alsmb_smb_writeb), 177 DEVMETHOD(smbus_readb, alsmb_smb_readb), 178 DEVMETHOD(smbus_writew, alsmb_smb_writew), 179 DEVMETHOD(smbus_readw, alsmb_smb_readw), 180 DEVMETHOD(smbus_bwrite, alsmb_smb_bwrite), 181 DEVMETHOD(smbus_bread, alsmb_smb_bread), 182 183 { 0, 0 } 184}; 185 186static driver_t alsmb_driver = { 187 "alsmb", 188 alsmb_methods, 189 sizeof(struct alsmb_softc), 190}; 191 192static const char* alpm_pci_probe(pcici_t tag, pcidi_t type); 193static void alpm_pci_attach(pcici_t tag, int unit); 194 195static u_long alpm_count; 196 197static struct pci_device alpm_device = { 198 "alpm", 199 alpm_pci_probe, 200 alpm_pci_attach, 201 &alpm_count 202}; 203 204COMPAT_PCI_DRIVER (alpm, alpm_device); 205 206static const char* 207alpm_pci_probe(pcici_t tag, pcidi_t type) 208{ 209 if (type == ACER_M1543_PMU_ID) 210 return ("AcerLabs M15x3 Power Management Unit"); 211 212 return ((char *)0); 213} 214 215static void 216alpm_pci_attach(pcici_t tag, int unit) 217{ 218 struct alpm_data *alpm; 219 u_long l; 220 221 if (unit >= NALPM) { 222 printf("alpm%d: attach: only %d units configured.\n", 223 unit, NALPM); 224 return; 225 } 226 alpm = &alpmdata[unit]; 227 228 alpm->tag = tag; 229 230 /* Unlock SMBIO base register access */ 231 l = pci_cfgread(tag, ATPC, 1); 232 pci_cfgwrite(tag, ATPC, l & ~ATPC_SMBCTRL, 1); 233 234 if (bootverbose) { 235 l = pci_cfgread(tag, SMBHSI, 1); 236 printf("alsmb%d: %s/%s", unit, 237 (l & SMBHSI_HOST) ? "host":"nohost", 238 (l & SMBHSI_SLAVE) ? "slave":"noslave"); 239 240 l = pci_cfgread(tag, SMBHCBC, 1); 241 switch (l & SMBHCBC_CLOCK) { 242 case SMBCLOCK_149K: 243 printf(" 149K"); 244 break; 245 case SMBCLOCK_74K: 246 printf(" 74K"); 247 break; 248 case SMBCLOCK_37K: 249 printf(" 37K"); 250 break; 251 case SMBCLOCK_223K: 252 printf(" 223K"); 253 break; 254 case SMBCLOCK_111K: 255 printf(" 111K"); 256 break; 257 case SMBCLOCK_55K: 258 printf(" 55K"); 259 break; 260 } 261 } 262 263 alpm->smbst = I386_BUS_SPACE_IO; 264 265#ifdef ALPM_SMBIO_BASE_ADDR 266 /* disable I/O */ 267 l = pci_cfgread(tag, COM, 2); 268 pci_cfgwrite(tag, COM, l & ~COM_ENABLE_IO, 2); 269 270 /* set the I/O base address */ 271 pci_cfgwrite(tag, SMBBA, ALPM_SMBIO_BASE_ADDR | 0x1, 4); 272 273 /* enable I/O */ 274 pci_cfgwrite(tag, COM, l | COM_ENABLE_IO, 2); 275 276 alpm->smbsh = ALPM_SMBIO_BASE_ADDR; 277#else 278 alpm->smbsh = pci_cfgread(tag, SMBBA, 4) & ~0x1; 279#endif 280 if (bootverbose) 281 printf(" at 0x%x\n", alpm->smbsh); 282 283 /* XXX add the I2C interface to the root_bus until pcibus is ready */ 284 device_add_child(root_bus, "alsmb", unit, NULL); 285 286 return; 287} 288 289/* 290 * Not a real probe, we know the device exists since the device has 291 * been added after the successfull pci probe. 292 */ 293static int 294alsmb_probe(device_t dev) 295{ 296 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 297 298 sc->alpm = &alpmdata[device_get_unit(dev)]; 299 300 device_set_desc(dev, "Aladdin IV/V/Pro2 SMBus controller"); 301 302 return (0); 303} 304 305static int 306alsmb_attach(device_t dev) 307{ 308 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 309 310 /* allocate a new smbus device */ 311 sc->smbus = smbus_alloc_bus(dev); 312 313 /* probe and attach the smbus */ 314 device_probe_and_attach(sc->smbus); 315 316 return (0); 317} 318 319static int 320alsmb_smb_callback(device_t dev, int index, caddr_t *data) 321{ 322 int error = 0; 323 324 switch (index) { 325 case SMB_REQUEST_BUS: 326 case SMB_RELEASE_BUS: 327 /* ok, bus allocation accepted */ 328 break; 329 default: 330 error = EINVAL; 331 } 332 333 return (error); 334} 335 336static int 337alsmb_clear(struct alsmb_softc *sc) 338{ 339 ALPM_SMBOUTB(sc, SMBSTS, 0xff); 340 DELAY(10); 341 342 return (0); 343} 344 345#if 0 346static int 347alsmb_abort(struct alsmb_softc *sc) 348{ 349 ALPM_SMBOUTB(sc, SMBCMD, T_OUT_CMD | ABORT_HOST); 350 351 return (0); 352} 353#endif 354 355static int 356alsmb_idle(struct alsmb_softc *sc) 357{ 358 u_char sts; 359 360 sts = ALPM_SMBINB(sc, SMBSTS); 361 362 ALPM_DEBUG(printf("alpm: idle? STS=0x%x\n", sts)); 363 364 return (sts & IDL_STS); 365} 366 367/* 368 * Poll the SMBus controller 369 */ 370static int 371alsmb_wait(struct alsmb_softc *sc) 372{ 373 int count = 10000; 374 u_char sts; 375 int error; 376 377 /* wait for command to complete and SMBus controller is idle */ 378 while(count--) { 379 DELAY(10); 380 sts = ALPM_SMBINB(sc, SMBSTS); 381 if (sts & SMI_I_STS) 382 break; 383 } 384 385 ALPM_DEBUG(printf("alpm: STS=0x%x\n", sts)); 386 387 error = SMB_ENOERR; 388 389 if (!count) 390 error |= SMB_ETIMEOUT; 391 392 if (sts & TERMINATE) 393 error |= SMB_EABORT; 394 395 if (sts & BUS_COLLI) 396 error |= SMB_ENOACK; 397 398 if (sts & DEVICE_ERR) 399 error |= SMB_EBUSERR; 400 401 if (error != SMB_ENOERR) 402 alsmb_clear(sc); 403 404 return (error); 405} 406 407static int 408alsmb_smb_quick(device_t dev, u_char slave, int how) 409{ 410 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 411 int error; 412 413 alsmb_clear(sc); 414 if (!alsmb_idle(sc)) 415 return (EBUSY); 416 417 switch (how) { 418 case SMB_QWRITE: 419 ALPM_DEBUG(printf("alpm: QWRITE to 0x%x", slave)); 420 ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); 421 break; 422 case SMB_QREAD: 423 ALPM_DEBUG(printf("alpm: QREAD to 0x%x", slave)); 424 ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); 425 break; 426 default: 427 panic("%s: unknown QUICK command (%x)!", __FUNCTION__, 428 how); 429 } 430 ALPM_SMBOUTB(sc, SMBCMD, SMBQUICK); 431 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 432 433 error = alsmb_wait(sc); 434 435 ALPM_DEBUG(printf(", error=0x%x\n", error)); 436 437 return (error); 438} 439 440static int 441alsmb_smb_sendb(device_t dev, u_char slave, char byte) 442{ 443 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 444 int error; 445 446 alsmb_clear(sc); 447 if (!alsmb_idle(sc)) 448 return (SMB_EBUSY); 449 450 ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); 451 ALPM_SMBOUTB(sc, SMBCMD, SMBSRBYTE); 452 ALPM_SMBOUTB(sc, SMBHDATA, byte); 453 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 454 455 error = alsmb_wait(sc); 456 457 ALPM_DEBUG(printf("alpm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error)); 458 459 return (error); 460} 461 462static int 463alsmb_smb_recvb(device_t dev, u_char slave, char *byte) 464{ 465 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 466 int error; 467 468 alsmb_clear(sc); 469 if (!alsmb_idle(sc)) 470 return (SMB_EBUSY); 471 472 ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); 473 ALPM_SMBOUTB(sc, SMBCMD, SMBSRBYTE); 474 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 475 476 if ((error = alsmb_wait(sc)) == SMB_ENOERR) 477 *byte = ALPM_SMBINB(sc, SMBHDATA); 478 479 ALPM_DEBUG(printf("alpm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error)); 480 481 return (error); 482} 483 484static int 485alsmb_smb_writeb(device_t dev, u_char slave, char cmd, char byte) 486{ 487 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 488 int error; 489 490 alsmb_clear(sc); 491 if (!alsmb_idle(sc)) 492 return (SMB_EBUSY); 493 494 ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); 495 ALPM_SMBOUTB(sc, SMBCMD, SMBWRBYTE); 496 ALPM_SMBOUTB(sc, SMBHDATA, byte); 497 ALPM_SMBOUTB(sc, SMBHCMD, cmd); 498 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 499 500 error = alsmb_wait(sc); 501 502 ALPM_DEBUG(printf("alpm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error)); 503 504 return (error); 505} 506 507static int 508alsmb_smb_readb(device_t dev, u_char slave, char cmd, char *byte) 509{ 510 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 511 int error; 512 513 alsmb_clear(sc); 514 if (!alsmb_idle(sc)) 515 return (SMB_EBUSY); 516 517 ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); 518 ALPM_SMBOUTB(sc, SMBCMD, SMBWRBYTE); 519 ALPM_SMBOUTB(sc, SMBHCMD, cmd); 520 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 521 522 if ((error = alsmb_wait(sc)) == SMB_ENOERR) 523 *byte = ALPM_SMBINB(sc, SMBHDATA); 524 525 ALPM_DEBUG(printf("alpm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error)); 526 527 return (error); 528} 529 530static int 531alsmb_smb_writew(device_t dev, u_char slave, char cmd, short word) 532{ 533 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 534 int error; 535 536 alsmb_clear(sc); 537 if (!alsmb_idle(sc)) 538 return (SMB_EBUSY); 539 540 ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); 541 ALPM_SMBOUTB(sc, SMBCMD, SMBWRWORD); 542 ALPM_SMBOUTB(sc, SMBHDATA, word & 0x00ff); 543 ALPM_SMBOUTB(sc, SMBHDATB, (word & 0xff00) >> 8); 544 ALPM_SMBOUTB(sc, SMBHCMD, cmd); 545 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 546 547 error = alsmb_wait(sc); 548 549 ALPM_DEBUG(printf("alpm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error)); 550 551 return (error); 552} 553 554static int 555alsmb_smb_readw(device_t dev, u_char slave, char cmd, short *word) 556{ 557 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 558 int error; 559 u_char high, low; 560 561 alsmb_clear(sc); 562 if (!alsmb_idle(sc)) 563 return (SMB_EBUSY); 564 565 ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); 566 ALPM_SMBOUTB(sc, SMBCMD, SMBWRWORD); 567 ALPM_SMBOUTB(sc, SMBHCMD, cmd); 568 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 569 570 if ((error = alsmb_wait(sc)) == SMB_ENOERR) { 571 low = ALPM_SMBINB(sc, SMBHDATA); 572 high = ALPM_SMBINB(sc, SMBHDATB); 573 574 *word = ((high & 0xff) << 8) | (low & 0xff); 575 } 576 577 ALPM_DEBUG(printf("alpm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error)); 578 579 return (error); 580} 581 582static int 583alsmb_smb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 584{ 585 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 586 u_char remain, len, i; 587 int error = SMB_ENOERR; 588 589 alsmb_clear(sc); 590 if(!alsmb_idle(sc)) 591 return (SMB_EBUSY); 592 593 remain = count; 594 while (remain) { 595 len = min(remain, 32); 596 597 ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); 598 599 /* set the cmd and reset the 600 * 32-byte long internal buffer */ 601 ALPM_SMBOUTB(sc, SMBCMD, SMBWRBLOCK | SMB_BLK_CLR); 602 603 ALPM_SMBOUTB(sc, SMBHDATA, len); 604 605 /* fill the 32-byte internal buffer */ 606 for (i=0; i<len; i++) { 607 ALPM_SMBOUTB(sc, SMBHBLOCK, buf[count-remain+i]); 608 DELAY(2); 609 } 610 ALPM_SMBOUTB(sc, SMBHCMD, cmd); 611 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 612 613 if ((error = alsmb_wait(sc)) != SMB_ENOERR) 614 goto error; 615 616 remain -= len; 617 } 618 619error: 620 ALPM_DEBUG(printf("alpm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 621 622 return (error); 623} 624 625static int 626alsmb_smb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) 627{ 628 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 629 u_char remain, len, i; 630 int error = SMB_ENOERR; 631 632 alsmb_clear(sc); 633 if (!alsmb_idle(sc)) 634 return (SMB_EBUSY); 635 636 remain = count; 637 while (remain) { 638 ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); 639 640 /* set the cmd and reset the 641 * 32-byte long internal buffer */ 642 ALPM_SMBOUTB(sc, SMBCMD, SMBWRBLOCK | SMB_BLK_CLR); 643 644 ALPM_SMBOUTB(sc, SMBHCMD, cmd); 645 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 646 647 if ((error = alsmb_wait(sc)) != SMB_ENOERR) 648 goto error; 649 650 len = ALPM_SMBINB(sc, SMBHDATA); 651 652 /* read the 32-byte internal buffer */ 653 for (i=0; i<len; i++) { 654 buf[count-remain+i] = ALPM_SMBINB(sc, SMBHBLOCK); 655 DELAY(2); 656 } 657 658 remain -= len; 659 } 660error: 661 ALPM_DEBUG(printf("alpm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 662 663 return (error); 664} 665 666DRIVER_MODULE(alsmb, root, alsmb_driver, alsmb_devclass, 0, 0); 667