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