alpm.c revision 48528
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.4 1999/05/09 17:06:38 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 void alsmb_print_child(device_t, device_t); 151static int alsmb_smb_callback(device_t, int, caddr_t *); 152static int alsmb_smb_quick(device_t dev, u_char slave, int how); 153static int alsmb_smb_sendb(device_t dev, u_char slave, char byte); 154static int alsmb_smb_recvb(device_t dev, u_char slave, char *byte); 155static int alsmb_smb_writeb(device_t dev, u_char slave, char cmd, char byte); 156static int alsmb_smb_readb(device_t dev, u_char slave, char cmd, char *byte); 157static int alsmb_smb_writew(device_t dev, u_char slave, char cmd, short word); 158static int alsmb_smb_readw(device_t dev, u_char slave, char cmd, short *word); 159static int alsmb_smb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); 160static int alsmb_smb_bread(device_t dev, u_char slave, char cmd, u_char count, char *byte); 161 162static devclass_t alsmb_devclass; 163 164static device_method_t alsmb_methods[] = { 165 /* device interface */ 166 DEVMETHOD(device_probe, alsmb_probe), 167 DEVMETHOD(device_attach, alsmb_attach), 168 169 /* bus interface */ 170 DEVMETHOD(bus_print_child, alsmb_print_child), 171 172 /* smbus interface */ 173 DEVMETHOD(smbus_callback, alsmb_smb_callback), 174 DEVMETHOD(smbus_quick, alsmb_smb_quick), 175 DEVMETHOD(smbus_sendb, alsmb_smb_sendb), 176 DEVMETHOD(smbus_recvb, alsmb_smb_recvb), 177 DEVMETHOD(smbus_writeb, alsmb_smb_writeb), 178 DEVMETHOD(smbus_readb, alsmb_smb_readb), 179 DEVMETHOD(smbus_writew, alsmb_smb_writew), 180 DEVMETHOD(smbus_readw, alsmb_smb_readw), 181 DEVMETHOD(smbus_bwrite, alsmb_smb_bwrite), 182 DEVMETHOD(smbus_bread, alsmb_smb_bread), 183 184 { 0, 0 } 185}; 186 187static driver_t alsmb_driver = { 188 "alsmb", 189 alsmb_methods, 190 sizeof(struct alsmb_softc), 191}; 192 193static const char* alpm_pci_probe(pcici_t tag, pcidi_t type); 194static void alpm_pci_attach(pcici_t tag, int unit); 195 196static u_long alpm_count; 197 198static struct pci_device alpm_device = { 199 "alpm", 200 alpm_pci_probe, 201 alpm_pci_attach, 202 &alpm_count 203}; 204 205COMPAT_PCI_DRIVER (alpm, alpm_device); 206 207static const char* 208alpm_pci_probe(pcici_t tag, pcidi_t type) 209{ 210 if (type == ACER_M1543_PMU_ID) 211 return ("AcerLabs M15x3 Power Management Unit"); 212 213 return ((char *)0); 214} 215 216static void 217alpm_pci_attach(pcici_t tag, int unit) 218{ 219 struct alpm_data *alpm; 220 u_long l; 221 222 if (unit >= NALPM) { 223 printf("alpm%d: attach: only %d units configured.\n", 224 unit, NALPM); 225 return; 226 } 227 alpm = &alpmdata[unit]; 228 229 alpm->tag = tag; 230 231 /* Unlock SMBIO base register access */ 232 l = pci_cfgread(tag, ATPC, 1); 233 pci_cfgwrite(tag, ATPC, l & ~ATPC_SMBCTRL, 1); 234 235 if (bootverbose) { 236 l = pci_cfgread(tag, SMBHSI, 1); 237 printf("alsmb%d: %s/%s", unit, 238 (l & SMBHSI_HOST) ? "host":"nohost", 239 (l & SMBHSI_SLAVE) ? "slave":"noslave"); 240 241 l = pci_cfgread(tag, SMBHCBC, 1); 242 switch (l & SMBHCBC_CLOCK) { 243 case SMBCLOCK_149K: 244 printf(" 149K"); 245 break; 246 case SMBCLOCK_74K: 247 printf(" 74K"); 248 break; 249 case SMBCLOCK_37K: 250 printf(" 37K"); 251 break; 252 case SMBCLOCK_223K: 253 printf(" 223K"); 254 break; 255 case SMBCLOCK_111K: 256 printf(" 111K"); 257 break; 258 case SMBCLOCK_55K: 259 printf(" 55K"); 260 break; 261 } 262 } 263 264 alpm->smbst = I386_BUS_SPACE_IO; 265 266#ifdef ALPM_SMBIO_BASE_ADDR 267 /* disable I/O */ 268 l = pci_cfgread(tag, COM, 2); 269 pci_cfgwrite(tag, COM, l & ~COM_ENABLE_IO, 2); 270 271 /* set the I/O base address */ 272 pci_cfgwrite(tag, SMBBA, ALPM_SMBIO_BASE_ADDR | 0x1, 4); 273 274 /* enable I/O */ 275 pci_cfgwrite(tag, COM, l | COM_ENABLE_IO, 2); 276 277 alpm->smbsh = ALPM_SMBIO_BASE_ADDR; 278#else 279 alpm->smbsh = pci_cfgread(tag, SMBBA, 4) & ~0x1; 280#endif 281 if (bootverbose) 282 printf(" at 0x%x\n", alpm->smbsh); 283 284 /* XXX add the I2C interface to the root_bus until pcibus is ready */ 285 device_add_child(root_bus, "alsmb", unit, NULL); 286 287 return; 288} 289 290/* 291 * Not a real probe, we know the device exists since the device has 292 * been added after the successfull pci probe. 293 */ 294static int 295alsmb_probe(device_t dev) 296{ 297 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 298 299 sc->alpm = &alpmdata[device_get_unit(dev)]; 300 301 device_set_desc(dev, "Aladdin IV/V/Pro2 SMBus controller"); 302 303 return (0); 304} 305 306static int 307alsmb_attach(device_t dev) 308{ 309 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 310 311 /* allocate a new smbus device */ 312 sc->smbus = smbus_alloc_bus(dev); 313 314 /* probe and attach the smbus */ 315 device_probe_and_attach(sc->smbus); 316 317 return (0); 318} 319 320static void 321alsmb_print_child(device_t bus, device_t dev) 322{ 323 printf(" on %s%d", device_get_name(bus), device_get_unit(bus)); 324 325 return; 326} 327 328static int 329alsmb_smb_callback(device_t dev, int index, caddr_t *data) 330{ 331 int error = 0; 332 333 switch (index) { 334 case SMB_REQUEST_BUS: 335 case SMB_RELEASE_BUS: 336 /* ok, bus allocation accepted */ 337 break; 338 default: 339 error = EINVAL; 340 } 341 342 return (error); 343} 344 345static int 346alsmb_clear(struct alsmb_softc *sc) 347{ 348 ALPM_SMBOUTB(sc, SMBSTS, 0xff); 349 DELAY(10); 350 351 return (0); 352} 353 354#if 0 355static int 356alsmb_abort(struct alsmb_softc *sc) 357{ 358 ALPM_SMBOUTB(sc, SMBCMD, T_OUT_CMD | ABORT_HOST); 359 360 return (0); 361} 362#endif 363 364static int 365alsmb_idle(struct alsmb_softc *sc) 366{ 367 u_char sts; 368 369 sts = ALPM_SMBINB(sc, SMBSTS); 370 371 ALPM_DEBUG(printf("alpm: idle? STS=0x%x\n", sts)); 372 373 return (sts & IDL_STS); 374} 375 376/* 377 * Poll the SMBus controller 378 */ 379static int 380alsmb_wait(struct alsmb_softc *sc) 381{ 382 int count = 10000; 383 u_char sts; 384 int error; 385 386 /* wait for command to complete and SMBus controller is idle */ 387 while(count--) { 388 DELAY(10); 389 sts = ALPM_SMBINB(sc, SMBSTS); 390 if (sts & SMI_I_STS) 391 break; 392 } 393 394 ALPM_DEBUG(printf("alpm: STS=0x%x\n", sts)); 395 396 error = SMB_ENOERR; 397 398 if (!count) 399 error |= SMB_ETIMEOUT; 400 401 if (sts & TERMINATE) 402 error |= SMB_EABORT; 403 404 if (sts & BUS_COLLI) 405 error |= SMB_ENOACK; 406 407 if (sts & DEVICE_ERR) 408 error |= SMB_EBUSERR; 409 410 if (error != SMB_ENOERR) 411 alsmb_clear(sc); 412 413 return (error); 414} 415 416static int 417alsmb_smb_quick(device_t dev, u_char slave, int how) 418{ 419 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 420 int error; 421 422 alsmb_clear(sc); 423 if (!alsmb_idle(sc)) 424 return (EBUSY); 425 426 switch (how) { 427 case SMB_QWRITE: 428 ALPM_DEBUG(printf("alpm: QWRITE to 0x%x", slave)); 429 ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); 430 break; 431 case SMB_QREAD: 432 ALPM_DEBUG(printf("alpm: QREAD to 0x%x", slave)); 433 ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); 434 break; 435 default: 436 panic("%s: unknown QUICK command (%x)!", __FUNCTION__, 437 how); 438 } 439 ALPM_SMBOUTB(sc, SMBCMD, SMBQUICK); 440 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 441 442 error = alsmb_wait(sc); 443 444 ALPM_DEBUG(printf(", error=0x%x\n", error)); 445 446 return (error); 447} 448 449static int 450alsmb_smb_sendb(device_t dev, u_char slave, char byte) 451{ 452 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 453 int error; 454 455 alsmb_clear(sc); 456 if (!alsmb_idle(sc)) 457 return (SMB_EBUSY); 458 459 ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); 460 ALPM_SMBOUTB(sc, SMBCMD, SMBSRBYTE); 461 ALPM_SMBOUTB(sc, SMBHDATA, byte); 462 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 463 464 error = alsmb_wait(sc); 465 466 ALPM_DEBUG(printf("alpm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error)); 467 468 return (error); 469} 470 471static int 472alsmb_smb_recvb(device_t dev, u_char slave, char *byte) 473{ 474 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 475 int error; 476 477 alsmb_clear(sc); 478 if (!alsmb_idle(sc)) 479 return (SMB_EBUSY); 480 481 ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); 482 ALPM_SMBOUTB(sc, SMBCMD, SMBSRBYTE); 483 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 484 485 if ((error = alsmb_wait(sc)) == SMB_ENOERR) 486 *byte = ALPM_SMBINB(sc, SMBHDATA); 487 488 ALPM_DEBUG(printf("alpm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error)); 489 490 return (error); 491} 492 493static int 494alsmb_smb_writeb(device_t dev, u_char slave, char cmd, char byte) 495{ 496 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 497 int error; 498 499 alsmb_clear(sc); 500 if (!alsmb_idle(sc)) 501 return (SMB_EBUSY); 502 503 ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); 504 ALPM_SMBOUTB(sc, SMBCMD, SMBWRBYTE); 505 ALPM_SMBOUTB(sc, SMBHDATA, byte); 506 ALPM_SMBOUTB(sc, SMBHCMD, cmd); 507 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 508 509 error = alsmb_wait(sc); 510 511 ALPM_DEBUG(printf("alpm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error)); 512 513 return (error); 514} 515 516static int 517alsmb_smb_readb(device_t dev, u_char slave, char cmd, char *byte) 518{ 519 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 520 int error; 521 522 alsmb_clear(sc); 523 if (!alsmb_idle(sc)) 524 return (SMB_EBUSY); 525 526 ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); 527 ALPM_SMBOUTB(sc, SMBCMD, SMBWRBYTE); 528 ALPM_SMBOUTB(sc, SMBHCMD, cmd); 529 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 530 531 if ((error = alsmb_wait(sc)) == SMB_ENOERR) 532 *byte = ALPM_SMBINB(sc, SMBHDATA); 533 534 ALPM_DEBUG(printf("alpm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error)); 535 536 return (error); 537} 538 539static int 540alsmb_smb_writew(device_t dev, u_char slave, char cmd, short word) 541{ 542 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 543 int error; 544 545 alsmb_clear(sc); 546 if (!alsmb_idle(sc)) 547 return (SMB_EBUSY); 548 549 ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); 550 ALPM_SMBOUTB(sc, SMBCMD, SMBWRWORD); 551 ALPM_SMBOUTB(sc, SMBHDATA, word & 0x00ff); 552 ALPM_SMBOUTB(sc, SMBHDATB, (word & 0xff00) >> 8); 553 ALPM_SMBOUTB(sc, SMBHCMD, cmd); 554 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 555 556 error = alsmb_wait(sc); 557 558 ALPM_DEBUG(printf("alpm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error)); 559 560 return (error); 561} 562 563static int 564alsmb_smb_readw(device_t dev, u_char slave, char cmd, short *word) 565{ 566 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 567 int error; 568 u_char high, low; 569 570 alsmb_clear(sc); 571 if (!alsmb_idle(sc)) 572 return (SMB_EBUSY); 573 574 ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); 575 ALPM_SMBOUTB(sc, SMBCMD, SMBWRWORD); 576 ALPM_SMBOUTB(sc, SMBHCMD, cmd); 577 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 578 579 if ((error = alsmb_wait(sc)) == SMB_ENOERR) { 580 low = ALPM_SMBINB(sc, SMBHDATA); 581 high = ALPM_SMBINB(sc, SMBHDATB); 582 583 *word = ((high & 0xff) << 8) | (low & 0xff); 584 } 585 586 ALPM_DEBUG(printf("alpm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error)); 587 588 return (error); 589} 590 591static int 592alsmb_smb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 593{ 594 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 595 u_char remain, len, i; 596 int error = SMB_ENOERR; 597 598 alsmb_clear(sc); 599 if(!alsmb_idle(sc)) 600 return (SMB_EBUSY); 601 602 remain = count; 603 while (remain) { 604 len = min(remain, 32); 605 606 ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); 607 608 /* set the cmd and reset the 609 * 32-byte long internal buffer */ 610 ALPM_SMBOUTB(sc, SMBCMD, SMBWRBLOCK | SMB_BLK_CLR); 611 612 ALPM_SMBOUTB(sc, SMBHDATA, len); 613 614 /* fill the 32-byte internal buffer */ 615 for (i=0; i<len; i++) { 616 ALPM_SMBOUTB(sc, SMBHBLOCK, buf[count-remain+i]); 617 DELAY(2); 618 } 619 ALPM_SMBOUTB(sc, SMBHCMD, cmd); 620 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 621 622 if ((error = alsmb_wait(sc)) != SMB_ENOERR) 623 goto error; 624 625 remain -= len; 626 } 627 628error: 629 ALPM_DEBUG(printf("alpm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 630 631 return (error); 632} 633 634static int 635alsmb_smb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) 636{ 637 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 638 u_char remain, len, i; 639 int error = SMB_ENOERR; 640 641 alsmb_clear(sc); 642 if (!alsmb_idle(sc)) 643 return (SMB_EBUSY); 644 645 remain = count; 646 while (remain) { 647 ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); 648 649 /* set the cmd and reset the 650 * 32-byte long internal buffer */ 651 ALPM_SMBOUTB(sc, SMBCMD, SMBWRBLOCK | SMB_BLK_CLR); 652 653 ALPM_SMBOUTB(sc, SMBHCMD, cmd); 654 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 655 656 if ((error = alsmb_wait(sc)) != SMB_ENOERR) 657 goto error; 658 659 len = ALPM_SMBINB(sc, SMBHDATA); 660 661 /* read the 32-byte internal buffer */ 662 for (i=0; i<len; i++) { 663 buf[count-remain+i] = ALPM_SMBINB(sc, SMBHBLOCK); 664 DELAY(2); 665 } 666 667 remain -= len; 668 } 669error: 670 ALPM_DEBUG(printf("alpm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 671 672 return (error); 673} 674 675DRIVER_MODULE(alsmb, root, alsmb_driver, alsmb_devclass, 0, 0); 676