alpm.c revision 70606
1/*- 2 * Copyright (c) 1998, 1999, 2001 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 * $FreeBSD: head/sys/pci/alpm.c 70606 2001-01-02 21:19:32Z nsouch $ 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/uio.h> 39 40 41#include <machine/bus_pio.h> 42#include <machine/bus_memio.h> 43#include <machine/bus.h> 44#include <machine/resource.h> 45#include <sys/rman.h> 46 47#include <pci/pcivar.h> 48#include <pci/pcireg.h> 49 50#include <dev/iicbus/iiconf.h> 51#include <dev/smbus/smbconf.h> 52#include "smbus_if.h" 53 54#include "alpm.h" 55 56#define ALPM_DEBUG(x) if (alpm_debug) (x) 57 58#ifdef DEBUG 59static int alpm_debug = 1; 60#else 61static int alpm_debug = 0; 62#endif 63 64#define ACER_M1543_PMU_ID 0x710110b9 65 66/* Uncomment this line to force another I/O base address for SMB */ 67/* #define ALPM_SMBIO_BASE_ADDR 0x3a80 */ 68 69/* I/O registers offsets - the base address is programmed via the 70 * SMBBA PCI configuration register 71 */ 72#define SMBSTS 0x0 /* SMBus host/slave status register */ 73#define SMBCMD 0x1 /* SMBus host/slave command register */ 74#define SMBSTART 0x2 /* start to generate programmed cycle */ 75#define SMBHADDR 0x3 /* host address register */ 76#define SMBHDATA 0x4 /* data A register for host controller */ 77#define SMBHDATB 0x5 /* data B register for host controller */ 78#define SMBHBLOCK 0x6 /* block register for host controller */ 79#define SMBHCMD 0x7 /* command register for host controller */ 80 81/* SMBSTS masks */ 82#define TERMINATE 0x80 83#define BUS_COLLI 0x40 84#define DEVICE_ERR 0x20 85#define SMI_I_STS 0x10 86#define HST_BSY 0x08 87#define IDL_STS 0x04 88#define HSTSLV_STS 0x02 89#define HSTSLV_BSY 0x01 90 91/* SMBCMD masks */ 92#define SMB_BLK_CLR 0x80 93#define T_OUT_CMD 0x08 94#define ABORT_HOST 0x04 95 96/* SMBus commands */ 97#define SMBQUICK 0x00 98#define SMBSRBYTE 0x10 /* send/receive byte */ 99#define SMBWRBYTE 0x20 /* write/read byte */ 100#define SMBWRWORD 0x30 /* write/read word */ 101#define SMBWRBLOCK 0x40 /* write/read block */ 102 103/* PCI configuration registers and masks 104 */ 105#define COM 0x4 106#define COM_ENABLE_IO 0x1 107 108#define SMBBA 0x14 109 110#define ATPC 0x5b 111#define ATPC_SMBCTRL 0x04 /* XX linux has this as 0x6 */ 112 113#define SMBHSI 0xe0 114#define SMBHSI_SLAVE 0x2 115#define SMBHSI_HOST 0x1 116 117#define SMBHCBC 0xe2 118#define SMBHCBC_CLOCK 0x70 119 120#define SMBCLOCK_149K 0x0 121#define SMBCLOCK_74K 0x20 122#define SMBCLOCK_37K 0x40 123#define SMBCLOCK_223K 0x80 124#define SMBCLOCK_111K 0xa0 125#define SMBCLOCK_55K 0xc0 126 127struct alpm_data { 128 int base; 129 bus_space_tag_t smbst; 130 bus_space_handle_t smbsh; 131}; 132 133struct alsmb_softc { 134 int base; 135 device_t smbus; 136 struct alpm_data *alpm; 137}; 138 139#define ALPM_SMBINB(alsmb,register) \ 140 (bus_space_read_1(alsmb->alpm->smbst, alsmb->alpm->smbsh, register)) 141#define ALPM_SMBOUTB(alsmb,register,value) \ 142 (bus_space_write_1(alsmb->alpm->smbst, alsmb->alpm->smbsh, register, value)) 143 144static int alsmb_probe(device_t); 145static int alsmb_attach(device_t); 146static int alsmb_smb_callback(device_t, int, caddr_t *); 147static int alsmb_smb_quick(device_t dev, u_char slave, int how); 148static int alsmb_smb_sendb(device_t dev, u_char slave, char byte); 149static int alsmb_smb_recvb(device_t dev, u_char slave, char *byte); 150static int alsmb_smb_writeb(device_t dev, u_char slave, char cmd, char byte); 151static int alsmb_smb_readb(device_t dev, u_char slave, char cmd, char *byte); 152static int alsmb_smb_writew(device_t dev, u_char slave, char cmd, short word); 153static int alsmb_smb_readw(device_t dev, u_char slave, char cmd, short *word); 154static int alsmb_smb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); 155static int alsmb_smb_bread(device_t dev, u_char slave, char cmd, u_char count, char *byte); 156 157static devclass_t alsmb_devclass; 158 159static device_method_t alsmb_methods[] = { 160 /* device interface */ 161 DEVMETHOD(device_probe, alsmb_probe), 162 DEVMETHOD(device_attach, alsmb_attach), 163 164 /* bus interface */ 165 DEVMETHOD(bus_print_child, bus_generic_print_child), 166 167 /* smbus interface */ 168 DEVMETHOD(smbus_callback, alsmb_smb_callback), 169 DEVMETHOD(smbus_quick, alsmb_smb_quick), 170 DEVMETHOD(smbus_sendb, alsmb_smb_sendb), 171 DEVMETHOD(smbus_recvb, alsmb_smb_recvb), 172 DEVMETHOD(smbus_writeb, alsmb_smb_writeb), 173 DEVMETHOD(smbus_readb, alsmb_smb_readb), 174 DEVMETHOD(smbus_writew, alsmb_smb_writew), 175 DEVMETHOD(smbus_readw, alsmb_smb_readw), 176 DEVMETHOD(smbus_bwrite, alsmb_smb_bwrite), 177 DEVMETHOD(smbus_bread, alsmb_smb_bread), 178 179 { 0, 0 } 180}; 181 182static driver_t alsmb_driver = { 183 "alsmb", 184 alsmb_methods, 185 sizeof(struct alsmb_softc), 186}; 187 188static int alpm_pci_probe(device_t dev); 189static int alpm_pci_attach(device_t dev); 190 191static devclass_t alpm_devclass; 192 193static device_method_t alpm_pci_methods[] = { 194 /* device interface */ 195 DEVMETHOD(device_probe, alpm_pci_probe), 196 DEVMETHOD(device_attach, alpm_pci_attach), 197 198 { 0, 0 } 199}; 200 201static driver_t alpm_pci_driver = { 202 "alpm", 203 alpm_pci_methods, 204 sizeof(struct alpm_data) 205}; 206 207 208static int 209alpm_pci_probe(device_t dev) 210{ 211 if (pci_get_devid(dev) == ACER_M1543_PMU_ID) { 212 device_set_desc(dev, 213 "AcerLabs M15x3 Power Management Unit"); 214 return 0; 215 } else { 216 return ENXIO; 217 } 218} 219 220static int 221alpm_pci_attach(device_t dev) 222{ 223 int rid, unit; 224 u_int32_t l; 225 struct alpm_data *alpm; 226 struct resource *res; 227 device_t smbinterface; 228 229 alpm = device_get_softc(dev); 230 unit = device_get_unit(dev); 231 232 /* Unlock SMBIO base register access */ 233 l = pci_read_config(dev, ATPC, 1); 234 pci_write_config(dev, ATPC, l & ~ATPC_SMBCTRL, 1); 235 236 /* 237 * XX linux sets clock to 74k, should we? 238 l = pci_read_config(dev, SMBHCBC, 1); 239 l &= 0x1f; 240 l |= SMBCLOCK_74K; 241 pci_write_config(dev, SMBHCBC, l, 1); 242 */ 243 244 if (bootverbose) { 245 l = pci_read_config(dev, SMBHSI, 1); 246 printf("alsmb%d: %s/%s", unit, 247 (l & SMBHSI_HOST) ? "host":"nohost", 248 (l & SMBHSI_SLAVE) ? "slave":"noslave"); 249 250 l = pci_read_config(dev, SMBHCBC, 1); 251 switch (l & SMBHCBC_CLOCK) { 252 case SMBCLOCK_149K: 253 printf(" 149K"); 254 break; 255 case SMBCLOCK_74K: 256 printf(" 74K"); 257 break; 258 case SMBCLOCK_37K: 259 printf(" 37K"); 260 break; 261 case SMBCLOCK_223K: 262 printf(" 223K"); 263 break; 264 case SMBCLOCK_111K: 265 printf(" 111K"); 266 break; 267 case SMBCLOCK_55K: 268 printf(" 55K"); 269 break; 270 } 271 } 272 273#ifdef ALPM_SMBIO_BASE_ADDR 274 /* XX will this even work anymore? */ 275 /* disable I/O */ 276 l = pci_read_config(dev, COM, 2); 277 pci_write_config(dev, COM, l & ~COM_ENABLE_IO, 2); 278 279 /* set the I/O base address */ 280 pci_write_config(dev, SMBBA, ALPM_SMBIO_BASE_ADDR | 0x1, 4); 281 282 /* enable I/O */ 283 pci_write_config(dev, COM, l | COM_ENABLE_IO, 2); 284 285#endif 286 rid = SMBBA; 287 res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 288 0,~0,1,RF_ACTIVE); 289 if (res == NULL) { 290 device_printf(dev,"Could not allocate Bus space\n"); 291 return ENXIO; 292 } 293 alpm->smbst = rman_get_bustag(res); 294 alpm->smbsh = rman_get_bushandle(res); 295 296 if (bootverbose) 297 printf(" at 0x%x\n", alpm->smbsh); 298 299 smbinterface = device_add_child(dev, "alsmb", unit); 300 if (!smbinterface) 301 device_printf(dev, "could not add SMBus device\n"); 302 else 303 device_probe_and_attach(smbinterface); 304 return 0; 305} 306 307/* 308 * Not a real probe, we know the device exists since the device has 309 * been added after the successfull pci probe. 310 */ 311static int 312alsmb_probe(device_t dev) 313{ 314 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 315 316 /* allocate a new smbus device */ 317 sc->smbus = smbus_alloc_bus(dev); 318 if (!sc->smbus) 319 return (EINVAL); 320 device_set_desc(dev, "Aladdin IV/V/Pro2 SMBus controller"); 321 322 return (0); 323} 324 325static int 326alsmb_attach(device_t dev) 327{ 328 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 329 330 sc->alpm = device_get_softc(device_get_parent(dev)); 331 332 /* probe and attach the smbus */ 333 device_probe_and_attach(sc->smbus); 334 335 return (0); 336} 337 338static int 339alsmb_smb_callback(device_t dev, int index, caddr_t *data) 340{ 341 int error = 0; 342 343 switch (index) { 344 case SMB_REQUEST_BUS: 345 case SMB_RELEASE_BUS: 346 /* ok, bus allocation accepted */ 347 break; 348 default: 349 error = EINVAL; 350 } 351 352 return (error); 353} 354 355static int 356alsmb_clear(struct alsmb_softc *sc) 357{ 358 ALPM_SMBOUTB(sc, SMBSTS, 0xff); 359 DELAY(10); 360 361 return (0); 362} 363 364#if 0 365static int 366alsmb_abort(struct alsmb_softc *sc) 367{ 368 ALPM_SMBOUTB(sc, SMBCMD, T_OUT_CMD | ABORT_HOST); 369 370 return (0); 371} 372#endif 373 374static int 375alsmb_idle(struct alsmb_softc *sc) 376{ 377 u_char sts; 378 379 sts = ALPM_SMBINB(sc, SMBSTS); 380 381 ALPM_DEBUG(printf("alpm: idle? STS=0x%x\n", sts)); 382 383 return (sts & IDL_STS); 384} 385 386/* 387 * Poll the SMBus controller 388 */ 389static int 390alsmb_wait(struct alsmb_softc *sc) 391{ 392 int count = 10000; 393 u_char sts = 0; 394 int error; 395 396 /* wait for command to complete and SMBus controller is idle */ 397 while(count--) { 398 DELAY(10); 399 sts = ALPM_SMBINB(sc, SMBSTS); 400 if (sts & SMI_I_STS) 401 break; 402 } 403 404 ALPM_DEBUG(printf("alpm: STS=0x%x\n", sts)); 405 406 error = SMB_ENOERR; 407 408 if (!count) 409 error |= SMB_ETIMEOUT; 410 411 if (sts & TERMINATE) 412 error |= SMB_EABORT; 413 414 if (sts & BUS_COLLI) 415 error |= SMB_ENOACK; 416 417 if (sts & DEVICE_ERR) 418 error |= SMB_EBUSERR; 419 420 if (error != SMB_ENOERR) 421 alsmb_clear(sc); 422 423 return (error); 424} 425 426static int 427alsmb_smb_quick(device_t dev, u_char slave, int how) 428{ 429 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 430 int error; 431 432 alsmb_clear(sc); 433 if (!alsmb_idle(sc)) 434 return (EBUSY); 435 436 switch (how) { 437 case SMB_QWRITE: 438 ALPM_DEBUG(printf("alpm: QWRITE to 0x%x", slave)); 439 ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); 440 break; 441 case SMB_QREAD: 442 ALPM_DEBUG(printf("alpm: QREAD to 0x%x", slave)); 443 ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); 444 break; 445 default: 446 panic("%s: unknown QUICK command (%x)!", __FUNCTION__, 447 how); 448 } 449 ALPM_SMBOUTB(sc, SMBCMD, SMBQUICK); 450 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 451 452 error = alsmb_wait(sc); 453 454 ALPM_DEBUG(printf(", error=0x%x\n", error)); 455 456 return (error); 457} 458 459static int 460alsmb_smb_sendb(device_t dev, u_char slave, char byte) 461{ 462 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 463 int error; 464 465 alsmb_clear(sc); 466 if (!alsmb_idle(sc)) 467 return (SMB_EBUSY); 468 469 ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); 470 ALPM_SMBOUTB(sc, SMBCMD, SMBSRBYTE); 471 ALPM_SMBOUTB(sc, SMBHDATA, byte); 472 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 473 474 error = alsmb_wait(sc); 475 476 ALPM_DEBUG(printf("alpm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error)); 477 478 return (error); 479} 480 481static int 482alsmb_smb_recvb(device_t dev, u_char slave, char *byte) 483{ 484 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 485 int error; 486 487 alsmb_clear(sc); 488 if (!alsmb_idle(sc)) 489 return (SMB_EBUSY); 490 491 ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); 492 ALPM_SMBOUTB(sc, SMBCMD, SMBSRBYTE); 493 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 494 495 if ((error = alsmb_wait(sc)) == SMB_ENOERR) 496 *byte = ALPM_SMBINB(sc, SMBHDATA); 497 498 ALPM_DEBUG(printf("alpm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error)); 499 500 return (error); 501} 502 503static int 504alsmb_smb_writeb(device_t dev, u_char slave, char cmd, char byte) 505{ 506 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 507 int error; 508 509 alsmb_clear(sc); 510 if (!alsmb_idle(sc)) 511 return (SMB_EBUSY); 512 513 ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); 514 ALPM_SMBOUTB(sc, SMBCMD, SMBWRBYTE); 515 ALPM_SMBOUTB(sc, SMBHDATA, byte); 516 ALPM_SMBOUTB(sc, SMBHCMD, cmd); 517 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 518 519 error = alsmb_wait(sc); 520 521 ALPM_DEBUG(printf("alpm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error)); 522 523 return (error); 524} 525 526static int 527alsmb_smb_readb(device_t dev, u_char slave, char cmd, char *byte) 528{ 529 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 530 int error; 531 532 alsmb_clear(sc); 533 if (!alsmb_idle(sc)) 534 return (SMB_EBUSY); 535 536 ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); 537 ALPM_SMBOUTB(sc, SMBCMD, SMBWRBYTE); 538 ALPM_SMBOUTB(sc, SMBHCMD, cmd); 539 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 540 541 if ((error = alsmb_wait(sc)) == SMB_ENOERR) 542 *byte = ALPM_SMBINB(sc, SMBHDATA); 543 544 ALPM_DEBUG(printf("alpm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error)); 545 546 return (error); 547} 548 549static int 550alsmb_smb_writew(device_t dev, u_char slave, char cmd, short word) 551{ 552 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 553 int error; 554 555 alsmb_clear(sc); 556 if (!alsmb_idle(sc)) 557 return (SMB_EBUSY); 558 559 ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); 560 ALPM_SMBOUTB(sc, SMBCMD, SMBWRWORD); 561 ALPM_SMBOUTB(sc, SMBHDATA, word & 0x00ff); 562 ALPM_SMBOUTB(sc, SMBHDATB, (word & 0xff00) >> 8); 563 ALPM_SMBOUTB(sc, SMBHCMD, cmd); 564 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 565 566 error = alsmb_wait(sc); 567 568 ALPM_DEBUG(printf("alpm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error)); 569 570 return (error); 571} 572 573static int 574alsmb_smb_readw(device_t dev, u_char slave, char cmd, short *word) 575{ 576 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 577 int error; 578 u_char high, low; 579 580 alsmb_clear(sc); 581 if (!alsmb_idle(sc)) 582 return (SMB_EBUSY); 583 584 ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); 585 ALPM_SMBOUTB(sc, SMBCMD, SMBWRWORD); 586 ALPM_SMBOUTB(sc, SMBHCMD, cmd); 587 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 588 589 if ((error = alsmb_wait(sc)) == SMB_ENOERR) { 590 low = ALPM_SMBINB(sc, SMBHDATA); 591 high = ALPM_SMBINB(sc, SMBHDATB); 592 593 *word = ((high & 0xff) << 8) | (low & 0xff); 594 } 595 596 ALPM_DEBUG(printf("alpm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error)); 597 598 return (error); 599} 600 601static int 602alsmb_smb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 603{ 604 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 605 u_char remain, len, i; 606 int error = SMB_ENOERR; 607 608 alsmb_clear(sc); 609 if(!alsmb_idle(sc)) 610 return (SMB_EBUSY); 611 612 remain = count; 613 while (remain) { 614 len = min(remain, 32); 615 616 ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); 617 618 /* set the cmd and reset the 619 * 32-byte long internal buffer */ 620 ALPM_SMBOUTB(sc, SMBCMD, SMBWRBLOCK | SMB_BLK_CLR); 621 622 ALPM_SMBOUTB(sc, SMBHDATA, len); 623 624 /* fill the 32-byte internal buffer */ 625 for (i=0; i<len; i++) { 626 ALPM_SMBOUTB(sc, SMBHBLOCK, buf[count-remain+i]); 627 DELAY(2); 628 } 629 ALPM_SMBOUTB(sc, SMBHCMD, cmd); 630 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 631 632 if ((error = alsmb_wait(sc)) != SMB_ENOERR) 633 goto error; 634 635 remain -= len; 636 } 637 638error: 639 ALPM_DEBUG(printf("alpm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 640 641 return (error); 642} 643 644static int 645alsmb_smb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) 646{ 647 struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); 648 u_char remain, len, i; 649 int error = SMB_ENOERR; 650 651 alsmb_clear(sc); 652 if (!alsmb_idle(sc)) 653 return (SMB_EBUSY); 654 655 remain = count; 656 while (remain) { 657 ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); 658 659 /* set the cmd and reset the 660 * 32-byte long internal buffer */ 661 ALPM_SMBOUTB(sc, SMBCMD, SMBWRBLOCK | SMB_BLK_CLR); 662 663 ALPM_SMBOUTB(sc, SMBHCMD, cmd); 664 ALPM_SMBOUTB(sc, SMBSTART, 0xff); 665 666 if ((error = alsmb_wait(sc)) != SMB_ENOERR) 667 goto error; 668 669 len = ALPM_SMBINB(sc, SMBHDATA); 670 671 /* read the 32-byte internal buffer */ 672 for (i=0; i<len; i++) { 673 buf[count-remain+i] = ALPM_SMBINB(sc, SMBHBLOCK); 674 DELAY(2); 675 } 676 677 remain -= len; 678 } 679error: 680 ALPM_DEBUG(printf("alpm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 681 682 return (error); 683} 684 685DRIVER_MODULE(alpm, pci, alpm_pci_driver, alpm_devclass, 0, 0); 686DRIVER_MODULE(alsmb, alpm, alsmb_driver, alsmb_devclass, 0, 0); 687