1175533Sru/*- 2175533Sru * Copyright (c) 2005 Ruslan Ermilov 3175533Sru * All rights reserved. 4175533Sru * 5175533Sru * Redistribution and use in source and binary forms, with or without 6175533Sru * modification, are permitted provided that the following conditions 7175533Sru * are met: 8175533Sru * 1. Redistributions of source code must retain the above copyright 9175533Sru * notice, this list of conditions and the following disclaimer. 10175533Sru * 2. Redistributions in binary form must reproduce the above copyright 11175533Sru * notice, this list of conditions and the following disclaimer in the 12175533Sru * documentation and/or other materials provided with the distribution. 13175533Sru * 14175533Sru * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15175533Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16175533Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17175533Sru * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18175533Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19175533Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20175533Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21175533Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22175533Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23175533Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24175533Sru * SUCH DAMAGE. 25175533Sru */ 26175533Sru 27153618Sru#include <sys/cdefs.h> 28153618Sru__FBSDID("$FreeBSD$"); 29153618Sru 30153618Sru#include <sys/param.h> 31165951Sjhb#include <sys/bus.h> 32153618Sru#include <sys/kernel.h> 33165951Sjhb#include <sys/lock.h> 34165951Sjhb#include <sys/module.h> 35165951Sjhb#include <sys/mutex.h> 36153618Sru#include <sys/systm.h> 37153618Sru 38153618Sru#include <machine/bus.h> 39153618Sru#include <machine/resource.h> 40153618Sru#include <sys/rman.h> 41153618Sru 42153618Sru#include <dev/pci/pcivar.h> 43153618Sru#include <dev/pci/pcireg.h> 44153618Sru 45153618Sru#include <dev/smbus/smbconf.h> 46153618Sru#include "smbus_if.h" 47153618Sru 48153618Sru#define NFSMB_DEBUG(x) if (nfsmb_debug) (x) 49153618Sru 50153618Sru#ifdef DEBUG 51153618Srustatic int nfsmb_debug = 1; 52153618Sru#else 53153618Srustatic int nfsmb_debug = 0; 54153618Sru#endif 55153618Sru 56153618Sru/* NVIDIA nForce2/3/4 MCP */ 57153618Sru#define NFSMB_VENDORID_NVIDIA 0x10de 58153618Sru#define NFSMB_DEVICEID_NF2_SMB 0x0064 59153618Sru#define NFSMB_DEVICEID_NF2_ULTRA_SMB 0x0084 60153618Sru#define NFSMB_DEVICEID_NF3_PRO150_SMB 0x00d4 61153618Sru#define NFSMB_DEVICEID_NF3_250GB_SMB 0x00e4 62153618Sru#define NFSMB_DEVICEID_NF4_SMB 0x0052 63161450Sru#define NFSMB_DEVICEID_NF4_04_SMB 0x0034 64161450Sru#define NFSMB_DEVICEID_NF4_51_SMB 0x0264 65161450Sru#define NFSMB_DEVICEID_NF4_55_SMB 0x0368 66173525Sremko#define NFSMB_DEVICEID_NF4_61_SMB 0x03eb 67179860Sjoerg#define NFSMB_DEVICEID_NF4_65_SMB 0x0446 68202931Sgavin#define NFSMB_DEVICEID_NF4_67_SMB 0x0542 69202931Sgavin#define NFSMB_DEVICEID_NF4_73_SMB 0x07d8 70202931Sgavin#define NFSMB_DEVICEID_NF4_78S_SMB 0x0752 71202931Sgavin#define NFSMB_DEVICEID_NF4_79_SMB 0x0aa2 72153618Sru 73153618Sru/* PCI Configuration space registers */ 74153618Sru#define NF2PCI_SMBASE_1 PCIR_BAR(4) 75153618Sru#define NF2PCI_SMBASE_2 PCIR_BAR(5) 76153618Sru 77153618Sru/* 78153618Sru * ACPI 3.0, Chapter 12, SMBus Host Controller Interface. 79153618Sru */ 80153618Sru#define SMB_PRTCL 0x00 /* protocol */ 81153618Sru#define SMB_STS 0x01 /* status */ 82153618Sru#define SMB_ADDR 0x02 /* address */ 83153618Sru#define SMB_CMD 0x03 /* command */ 84153618Sru#define SMB_DATA 0x04 /* 32 data registers */ 85153618Sru#define SMB_BCNT 0x24 /* number of data bytes */ 86153618Sru#define SMB_ALRM_A 0x25 /* alarm address */ 87153618Sru#define SMB_ALRM_D 0x26 /* 2 bytes alarm data */ 88153618Sru 89153618Sru#define SMB_STS_DONE 0x80 90153618Sru#define SMB_STS_ALRM 0x40 91153618Sru#define SMB_STS_RES 0x20 92153618Sru#define SMB_STS_STATUS 0x1f 93153618Sru#define SMB_STS_OK 0x00 /* OK */ 94153618Sru#define SMB_STS_UF 0x07 /* Unknown Failure */ 95153618Sru#define SMB_STS_DANA 0x10 /* Device Address Not Acknowledged */ 96153618Sru#define SMB_STS_DED 0x11 /* Device Error Detected */ 97153618Sru#define SMB_STS_DCAD 0x12 /* Device Command Access Denied */ 98153618Sru#define SMB_STS_UE 0x13 /* Unknown Error */ 99153618Sru#define SMB_STS_DAD 0x17 /* Device Access Denied */ 100153618Sru#define SMB_STS_T 0x18 /* Timeout */ 101153618Sru#define SMB_STS_HUP 0x19 /* Host Unsupported Protocol */ 102153618Sru#define SMB_STS_B 0x1A /* Busy */ 103153618Sru#define SMB_STS_PEC 0x1F /* PEC (CRC-8) Error */ 104153618Sru 105153618Sru#define SMB_PRTCL_WRITE 0x00 106153618Sru#define SMB_PRTCL_READ 0x01 107153618Sru#define SMB_PRTCL_QUICK 0x02 108153618Sru#define SMB_PRTCL_BYTE 0x04 109153618Sru#define SMB_PRTCL_BYTE_DATA 0x06 110153618Sru#define SMB_PRTCL_WORD_DATA 0x08 111153618Sru#define SMB_PRTCL_BLOCK_DATA 0x0a 112153618Sru#define SMB_PRTCL_PROC_CALL 0x0c 113153618Sru#define SMB_PRTCL_BLOCK_PROC_CALL 0x0d 114153618Sru#define SMB_PRTCL_PEC 0x80 115153618Sru 116153618Srustruct nfsmb_softc { 117153618Sru int rid; 118153618Sru struct resource *res; 119153618Sru device_t smbus; 120153618Sru device_t subdev; 121165951Sjhb struct mtx lock; 122153618Sru}; 123153618Sru 124165951Sjhb#define NFSMB_LOCK(nfsmb) mtx_lock(&(nfsmb)->lock) 125165951Sjhb#define NFSMB_UNLOCK(nfsmb) mtx_unlock(&(nfsmb)->lock) 126165951Sjhb#define NFSMB_LOCK_ASSERT(nfsmb) mtx_assert(&(nfsmb)->lock, MA_OWNED) 127165951Sjhb 128165951Sjhb#define NFSMB_SMBINB(nfsmb, register) \ 129179622Sjhb (bus_read_1(nfsmb->res, register)) 130153618Sru#define NFSMB_SMBOUTB(nfsmb, register, value) \ 131179622Sjhb (bus_write_1(nfsmb->res, register, value)) 132153618Sru 133165951Sjhbstatic int nfsmb_detach(device_t dev); 134165951Sjhbstatic int nfsmbsub_detach(device_t dev); 135165951Sjhb 136153618Srustatic int 137153618Srunfsmbsub_probe(device_t dev) 138153618Sru{ 139153618Sru 140153618Sru device_set_desc(dev, "nForce2/3/4 MCP SMBus Controller"); 141153618Sru return (BUS_PROBE_DEFAULT); 142153618Sru} 143153618Sru 144153618Srustatic int 145153618Srunfsmb_probe(device_t dev) 146153618Sru{ 147153618Sru u_int16_t vid; 148153618Sru u_int16_t did; 149153618Sru 150153618Sru vid = pci_get_vendor(dev); 151153618Sru did = pci_get_device(dev); 152153618Sru 153153618Sru if (vid == NFSMB_VENDORID_NVIDIA) { 154153618Sru switch(did) { 155153618Sru case NFSMB_DEVICEID_NF2_SMB: 156153618Sru case NFSMB_DEVICEID_NF2_ULTRA_SMB: 157153618Sru case NFSMB_DEVICEID_NF3_PRO150_SMB: 158153618Sru case NFSMB_DEVICEID_NF3_250GB_SMB: 159153618Sru case NFSMB_DEVICEID_NF4_SMB: 160161450Sru case NFSMB_DEVICEID_NF4_04_SMB: 161161450Sru case NFSMB_DEVICEID_NF4_51_SMB: 162161450Sru case NFSMB_DEVICEID_NF4_55_SMB: 163173525Sremko case NFSMB_DEVICEID_NF4_61_SMB: 164179860Sjoerg case NFSMB_DEVICEID_NF4_65_SMB: 165202931Sgavin case NFSMB_DEVICEID_NF4_67_SMB: 166202931Sgavin case NFSMB_DEVICEID_NF4_73_SMB: 167202931Sgavin case NFSMB_DEVICEID_NF4_78S_SMB: 168202931Sgavin case NFSMB_DEVICEID_NF4_79_SMB: 169153618Sru device_set_desc(dev, "nForce2/3/4 MCP SMBus Controller"); 170153618Sru return (BUS_PROBE_DEFAULT); 171153618Sru } 172153618Sru } 173153618Sru 174153618Sru return (ENXIO); 175153618Sru} 176153618Sru 177153618Srustatic int 178153618Srunfsmbsub_attach(device_t dev) 179153618Sru{ 180153618Sru device_t parent; 181153618Sru struct nfsmb_softc *nfsmbsub_sc = device_get_softc(dev); 182153618Sru 183153618Sru parent = device_get_parent(dev); 184153618Sru 185153618Sru nfsmbsub_sc->rid = NF2PCI_SMBASE_2; 186153618Sru 187153618Sru nfsmbsub_sc->res = bus_alloc_resource_any(parent, SYS_RES_IOPORT, 188153618Sru &nfsmbsub_sc->rid, RF_ACTIVE); 189153618Sru if (nfsmbsub_sc->res == NULL) { 190163459Sru /* Older incarnations of the device used non-standard BARs. */ 191163459Sru nfsmbsub_sc->rid = 0x54; 192163459Sru nfsmbsub_sc->res = bus_alloc_resource_any(parent, 193163459Sru SYS_RES_IOPORT, &nfsmbsub_sc->rid, RF_ACTIVE); 194163459Sru if (nfsmbsub_sc->res == NULL) { 195163459Sru device_printf(dev, "could not map i/o space\n"); 196163459Sru return (ENXIO); 197163459Sru } 198153618Sru } 199165951Sjhb mtx_init(&nfsmbsub_sc->lock, device_get_nameunit(dev), "nfsmb", 200165951Sjhb MTX_DEF); 201153618Sru 202153618Sru nfsmbsub_sc->smbus = device_add_child(dev, "smbus", -1); 203165951Sjhb if (nfsmbsub_sc->smbus == NULL) { 204165951Sjhb nfsmbsub_detach(dev); 205153618Sru return (EINVAL); 206165951Sjhb } 207153618Sru 208153618Sru bus_generic_attach(dev); 209153618Sru 210153618Sru return (0); 211153618Sru} 212153618Sru 213153618Srustatic int 214153618Srunfsmb_attach(device_t dev) 215153618Sru{ 216153618Sru struct nfsmb_softc *nfsmb_sc = device_get_softc(dev); 217153618Sru 218153618Sru /* Allocate I/O space */ 219153618Sru nfsmb_sc->rid = NF2PCI_SMBASE_1; 220153618Sru 221153618Sru nfsmb_sc->res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 222153618Sru &nfsmb_sc->rid, RF_ACTIVE); 223153618Sru 224153618Sru if (nfsmb_sc->res == NULL) { 225163459Sru /* Older incarnations of the device used non-standard BARs. */ 226163459Sru nfsmb_sc->rid = 0x50; 227163459Sru nfsmb_sc->res = bus_alloc_resource_any(dev, 228163459Sru SYS_RES_IOPORT, &nfsmb_sc->rid, RF_ACTIVE); 229163459Sru if (nfsmb_sc->res == NULL) { 230163459Sru device_printf(dev, "could not map i/o space\n"); 231163459Sru return (ENXIO); 232163459Sru } 233153618Sru } 234153618Sru 235165951Sjhb mtx_init(&nfsmb_sc->lock, device_get_nameunit(dev), "nfsmb", MTX_DEF); 236153618Sru 237153618Sru /* Allocate a new smbus device */ 238153618Sru nfsmb_sc->smbus = device_add_child(dev, "smbus", -1); 239165951Sjhb if (!nfsmb_sc->smbus) { 240165951Sjhb nfsmb_detach(dev); 241153618Sru return (EINVAL); 242165951Sjhb } 243153618Sru 244153618Sru nfsmb_sc->subdev = NULL; 245153618Sru switch (pci_get_device(dev)) { 246153618Sru case NFSMB_DEVICEID_NF2_SMB: 247153618Sru case NFSMB_DEVICEID_NF2_ULTRA_SMB: 248153618Sru case NFSMB_DEVICEID_NF3_PRO150_SMB: 249153618Sru case NFSMB_DEVICEID_NF3_250GB_SMB: 250153618Sru case NFSMB_DEVICEID_NF4_SMB: 251161450Sru case NFSMB_DEVICEID_NF4_04_SMB: 252161450Sru case NFSMB_DEVICEID_NF4_51_SMB: 253161450Sru case NFSMB_DEVICEID_NF4_55_SMB: 254173525Sremko case NFSMB_DEVICEID_NF4_61_SMB: 255179860Sjoerg case NFSMB_DEVICEID_NF4_65_SMB: 256202931Sgavin case NFSMB_DEVICEID_NF4_67_SMB: 257202931Sgavin case NFSMB_DEVICEID_NF4_73_SMB: 258202931Sgavin case NFSMB_DEVICEID_NF4_78S_SMB: 259202931Sgavin case NFSMB_DEVICEID_NF4_79_SMB: 260153618Sru /* Trying to add secondary device as slave */ 261153618Sru nfsmb_sc->subdev = device_add_child(dev, "nfsmb", -1); 262165951Sjhb if (!nfsmb_sc->subdev) { 263165951Sjhb nfsmb_detach(dev); 264153618Sru return (EINVAL); 265165951Sjhb } 266153618Sru break; 267153618Sru default: 268153618Sru break; 269153618Sru } 270153618Sru 271153618Sru bus_generic_attach(dev); 272153618Sru 273153618Sru return (0); 274153618Sru} 275153618Sru 276153618Srustatic int 277153618Srunfsmbsub_detach(device_t dev) 278153618Sru{ 279153618Sru device_t parent; 280153618Sru struct nfsmb_softc *nfsmbsub_sc = device_get_softc(dev); 281153618Sru 282153618Sru parent = device_get_parent(dev); 283153618Sru 284153618Sru if (nfsmbsub_sc->smbus) { 285153618Sru device_delete_child(dev, nfsmbsub_sc->smbus); 286153618Sru nfsmbsub_sc->smbus = NULL; 287153618Sru } 288165951Sjhb mtx_destroy(&nfsmbsub_sc->lock); 289153618Sru if (nfsmbsub_sc->res) { 290153618Sru bus_release_resource(parent, SYS_RES_IOPORT, nfsmbsub_sc->rid, 291153618Sru nfsmbsub_sc->res); 292153618Sru nfsmbsub_sc->res = NULL; 293153618Sru } 294153618Sru return (0); 295153618Sru} 296153618Sru 297153618Srustatic int 298153618Srunfsmb_detach(device_t dev) 299153618Sru{ 300153618Sru struct nfsmb_softc *nfsmb_sc = device_get_softc(dev); 301153618Sru 302153618Sru if (nfsmb_sc->subdev) { 303153618Sru device_delete_child(dev, nfsmb_sc->subdev); 304153618Sru nfsmb_sc->subdev = NULL; 305153618Sru } 306153618Sru 307153618Sru if (nfsmb_sc->smbus) { 308153618Sru device_delete_child(dev, nfsmb_sc->smbus); 309153618Sru nfsmb_sc->smbus = NULL; 310153618Sru } 311153618Sru 312165951Sjhb mtx_destroy(&nfsmb_sc->lock); 313153618Sru if (nfsmb_sc->res) { 314153618Sru bus_release_resource(dev, SYS_RES_IOPORT, nfsmb_sc->rid, 315153618Sru nfsmb_sc->res); 316153618Sru nfsmb_sc->res = NULL; 317153618Sru } 318153618Sru 319153618Sru return (0); 320153618Sru} 321153618Sru 322153618Srustatic int 323162234Sjhbnfsmb_callback(device_t dev, int index, void *data) 324153618Sru{ 325153618Sru int error = 0; 326153618Sru 327153618Sru switch (index) { 328153618Sru case SMB_REQUEST_BUS: 329153618Sru case SMB_RELEASE_BUS: 330153618Sru break; 331153618Sru default: 332153618Sru error = EINVAL; 333153618Sru } 334153618Sru 335153618Sru return (error); 336153618Sru} 337153618Sru 338153618Srustatic int 339153618Srunfsmb_wait(struct nfsmb_softc *sc) 340153618Sru{ 341153618Sru u_char sts; 342153618Sru int error, count; 343153618Sru 344165951Sjhb NFSMB_LOCK_ASSERT(sc); 345153618Sru if (NFSMB_SMBINB(sc, SMB_PRTCL) != 0) 346153618Sru { 347153618Sru count = 10000; 348153618Sru do { 349153618Sru DELAY(500); 350153618Sru } while (NFSMB_SMBINB(sc, SMB_PRTCL) != 0 && count--); 351153618Sru if (count == 0) 352153618Sru return (SMB_ETIMEOUT); 353153618Sru } 354153618Sru 355153618Sru sts = NFSMB_SMBINB(sc, SMB_STS) & SMB_STS_STATUS; 356153618Sru NFSMB_DEBUG(printf("nfsmb: STS=0x%x\n", sts)); 357153618Sru 358153618Sru switch (sts) { 359153618Sru case SMB_STS_OK: 360153618Sru error = SMB_ENOERR; 361153618Sru break; 362153618Sru case SMB_STS_DANA: 363153618Sru error = SMB_ENOACK; 364153618Sru break; 365153618Sru case SMB_STS_B: 366153618Sru error = SMB_EBUSY; 367153618Sru break; 368153618Sru case SMB_STS_T: 369153618Sru error = SMB_ETIMEOUT; 370153618Sru break; 371153618Sru case SMB_STS_DCAD: 372153618Sru case SMB_STS_DAD: 373153618Sru case SMB_STS_HUP: 374153618Sru error = SMB_ENOTSUPP; 375153618Sru break; 376153618Sru default: 377153618Sru error = SMB_EBUSERR; 378153618Sru break; 379153618Sru } 380153618Sru 381153618Sru return (error); 382153618Sru} 383153618Sru 384153618Srustatic int 385153618Srunfsmb_quick(device_t dev, u_char slave, int how) 386153618Sru{ 387153618Sru struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 388153618Sru u_char protocol; 389153618Sru int error; 390153618Sru 391153618Sru protocol = SMB_PRTCL_QUICK; 392153618Sru 393153618Sru switch (how) { 394153618Sru case SMB_QWRITE: 395153618Sru protocol |= SMB_PRTCL_WRITE; 396153618Sru NFSMB_DEBUG(printf("nfsmb: QWRITE to 0x%x", slave)); 397153618Sru break; 398153618Sru case SMB_QREAD: 399153618Sru protocol |= SMB_PRTCL_READ; 400153618Sru NFSMB_DEBUG(printf("nfsmb: QREAD to 0x%x", slave)); 401153618Sru break; 402153618Sru default: 403153618Sru panic("%s: unknown QUICK command (%x)!", __func__, how); 404153618Sru } 405153618Sru 406165951Sjhb NFSMB_LOCK(sc); 407153618Sru NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 408153618Sru NFSMB_SMBOUTB(sc, SMB_PRTCL, protocol); 409153618Sru 410153618Sru error = nfsmb_wait(sc); 411153618Sru 412153618Sru NFSMB_DEBUG(printf(", error=0x%x\n", error)); 413165951Sjhb NFSMB_UNLOCK(sc); 414153618Sru 415153618Sru return (error); 416153618Sru} 417153618Sru 418153618Srustatic int 419153618Srunfsmb_sendb(device_t dev, u_char slave, char byte) 420153618Sru{ 421153618Sru struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 422153618Sru int error; 423153618Sru 424165951Sjhb NFSMB_LOCK(sc); 425153618Sru NFSMB_SMBOUTB(sc, SMB_CMD, byte); 426153618Sru NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 427153618Sru NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BYTE); 428153618Sru 429153618Sru error = nfsmb_wait(sc); 430153618Sru 431153618Sru NFSMB_DEBUG(printf("nfsmb: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error)); 432165951Sjhb NFSMB_UNLOCK(sc); 433153618Sru 434153618Sru return (error); 435153618Sru} 436153618Sru 437153618Srustatic int 438153618Srunfsmb_recvb(device_t dev, u_char slave, char *byte) 439153618Sru{ 440153618Sru struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 441153618Sru int error; 442153618Sru 443165951Sjhb NFSMB_LOCK(sc); 444153618Sru NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 445153618Sru NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BYTE); 446153618Sru 447153618Sru if ((error = nfsmb_wait(sc)) == SMB_ENOERR) 448153618Sru *byte = NFSMB_SMBINB(sc, SMB_DATA); 449153618Sru 450153618Sru NFSMB_DEBUG(printf("nfsmb: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error)); 451165951Sjhb NFSMB_UNLOCK(sc); 452153618Sru 453153618Sru return (error); 454153618Sru} 455153618Sru 456153618Srustatic int 457153618Srunfsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 458153618Sru{ 459153618Sru struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 460153618Sru int error; 461153618Sru 462165951Sjhb NFSMB_LOCK(sc); 463153618Sru NFSMB_SMBOUTB(sc, SMB_CMD, cmd); 464153618Sru NFSMB_SMBOUTB(sc, SMB_DATA, byte); 465153618Sru NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 466153618Sru NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BYTE_DATA); 467153618Sru 468153618Sru error = nfsmb_wait(sc); 469153618Sru 470153618Sru NFSMB_DEBUG(printf("nfsmb: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error)); 471165951Sjhb NFSMB_UNLOCK(sc); 472153618Sru 473153618Sru return (error); 474153618Sru} 475153618Sru 476153618Srustatic int 477153618Srunfsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 478153618Sru{ 479153618Sru struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 480153618Sru int error; 481153618Sru 482165951Sjhb NFSMB_LOCK(sc); 483153618Sru NFSMB_SMBOUTB(sc, SMB_CMD, cmd); 484153618Sru NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 485153618Sru NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BYTE_DATA); 486153618Sru 487153618Sru if ((error = nfsmb_wait(sc)) == SMB_ENOERR) 488153618Sru *byte = NFSMB_SMBINB(sc, SMB_DATA); 489153618Sru 490153618Sru NFSMB_DEBUG(printf("nfsmb: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, (unsigned char)*byte, error)); 491165951Sjhb NFSMB_UNLOCK(sc); 492153618Sru 493153618Sru return (error); 494153618Sru} 495153618Sru 496153618Srustatic int 497153618Srunfsmb_writew(device_t dev, u_char slave, char cmd, short word) 498153618Sru{ 499153618Sru struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 500153618Sru int error; 501153618Sru 502165951Sjhb NFSMB_LOCK(sc); 503153618Sru NFSMB_SMBOUTB(sc, SMB_CMD, cmd); 504153618Sru NFSMB_SMBOUTB(sc, SMB_DATA, word); 505153618Sru NFSMB_SMBOUTB(sc, SMB_DATA + 1, word >> 8); 506153618Sru NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 507153618Sru NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_WORD_DATA); 508153618Sru 509153618Sru error = nfsmb_wait(sc); 510153618Sru 511153618Sru NFSMB_DEBUG(printf("nfsmb: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error)); 512165951Sjhb NFSMB_UNLOCK(sc); 513153618Sru 514153618Sru return (error); 515153618Sru} 516153618Sru 517153618Srustatic int 518153618Srunfsmb_readw(device_t dev, u_char slave, char cmd, short *word) 519153618Sru{ 520153618Sru struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 521153618Sru int error; 522153618Sru 523165951Sjhb NFSMB_LOCK(sc); 524153618Sru NFSMB_SMBOUTB(sc, SMB_CMD, cmd); 525153618Sru NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 526153618Sru NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_WORD_DATA); 527153618Sru 528153618Sru if ((error = nfsmb_wait(sc)) == SMB_ENOERR) 529153618Sru *word = NFSMB_SMBINB(sc, SMB_DATA) | 530153618Sru (NFSMB_SMBINB(sc, SMB_DATA + 1) << 8); 531153618Sru 532153618Sru NFSMB_DEBUG(printf("nfsmb: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, (unsigned short)*word, error)); 533165951Sjhb NFSMB_UNLOCK(sc); 534153618Sru 535153618Sru return (error); 536153618Sru} 537153618Sru 538153618Srustatic int 539153618Srunfsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 540153618Sru{ 541153618Sru struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 542162234Sjhb u_char i; 543153618Sru int error; 544153618Sru 545162234Sjhb if (count < 1 || count > 32) 546162234Sjhb return (SMB_EINVAL); 547165951Sjhb 548165951Sjhb NFSMB_LOCK(sc); 549153618Sru NFSMB_SMBOUTB(sc, SMB_CMD, cmd); 550162234Sjhb NFSMB_SMBOUTB(sc, SMB_BCNT, count); 551162234Sjhb for (i = 0; i < count; i++) 552153618Sru NFSMB_SMBOUTB(sc, SMB_DATA + i, buf[i]); 553153618Sru NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 554153618Sru NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BLOCK_DATA); 555153618Sru 556153618Sru error = nfsmb_wait(sc); 557153618Sru 558153618Sru NFSMB_DEBUG(printf("nfsmb: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 559165951Sjhb NFSMB_UNLOCK(sc); 560153618Sru 561153618Sru return (error); 562153618Sru} 563153618Sru 564153618Srustatic int 565162234Sjhbnfsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) 566153618Sru{ 567153618Sru struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 568162234Sjhb u_char data, len, i; 569153618Sru int error; 570153618Sru 571162234Sjhb if (*count < 1 || *count > 32) 572162234Sjhb return (SMB_EINVAL); 573165951Sjhb 574165951Sjhb NFSMB_LOCK(sc); 575153618Sru NFSMB_SMBOUTB(sc, SMB_CMD, cmd); 576153618Sru NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 577153618Sru NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BLOCK_DATA); 578153618Sru 579153618Sru if ((error = nfsmb_wait(sc)) == SMB_ENOERR) { 580153618Sru len = NFSMB_SMBINB(sc, SMB_BCNT); 581162234Sjhb for (i = 0; i < len; i++) { 582162234Sjhb data = NFSMB_SMBINB(sc, SMB_DATA + i); 583162234Sjhb if (i < *count) 584162234Sjhb buf[i] = data; 585162234Sjhb } 586162234Sjhb *count = len; 587153618Sru } 588153618Sru 589162234Sjhb NFSMB_DEBUG(printf("nfsmb: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, *count, cmd, error)); 590165951Sjhb NFSMB_UNLOCK(sc); 591153618Sru 592153618Sru return (error); 593153618Sru} 594153618Sru 595153618Srustatic device_method_t nfsmb_methods[] = { 596153618Sru /* Device interface */ 597153618Sru DEVMETHOD(device_probe, nfsmb_probe), 598153618Sru DEVMETHOD(device_attach, nfsmb_attach), 599153618Sru DEVMETHOD(device_detach, nfsmb_detach), 600153618Sru 601153618Sru /* SMBus interface */ 602153618Sru DEVMETHOD(smbus_callback, nfsmb_callback), 603153618Sru DEVMETHOD(smbus_quick, nfsmb_quick), 604153618Sru DEVMETHOD(smbus_sendb, nfsmb_sendb), 605153618Sru DEVMETHOD(smbus_recvb, nfsmb_recvb), 606153618Sru DEVMETHOD(smbus_writeb, nfsmb_writeb), 607153618Sru DEVMETHOD(smbus_readb, nfsmb_readb), 608153618Sru DEVMETHOD(smbus_writew, nfsmb_writew), 609153618Sru DEVMETHOD(smbus_readw, nfsmb_readw), 610153618Sru DEVMETHOD(smbus_bwrite, nfsmb_bwrite), 611153618Sru DEVMETHOD(smbus_bread, nfsmb_bread), 612153618Sru 613153618Sru { 0, 0 } 614153618Sru}; 615153618Sru 616153618Srustatic device_method_t nfsmbsub_methods[] = { 617153618Sru /* Device interface */ 618153618Sru DEVMETHOD(device_probe, nfsmbsub_probe), 619153618Sru DEVMETHOD(device_attach, nfsmbsub_attach), 620153618Sru DEVMETHOD(device_detach, nfsmbsub_detach), 621153618Sru 622153618Sru /* SMBus interface */ 623153618Sru DEVMETHOD(smbus_callback, nfsmb_callback), 624153618Sru DEVMETHOD(smbus_quick, nfsmb_quick), 625153618Sru DEVMETHOD(smbus_sendb, nfsmb_sendb), 626153618Sru DEVMETHOD(smbus_recvb, nfsmb_recvb), 627153618Sru DEVMETHOD(smbus_writeb, nfsmb_writeb), 628153618Sru DEVMETHOD(smbus_readb, nfsmb_readb), 629153618Sru DEVMETHOD(smbus_writew, nfsmb_writew), 630153618Sru DEVMETHOD(smbus_readw, nfsmb_readw), 631153618Sru DEVMETHOD(smbus_bwrite, nfsmb_bwrite), 632153618Sru DEVMETHOD(smbus_bread, nfsmb_bread), 633153618Sru 634153618Sru { 0, 0 } 635153618Sru}; 636153618Sru 637153618Srustatic devclass_t nfsmb_devclass; 638153618Sru 639153618Srustatic driver_t nfsmb_driver = { 640153618Sru "nfsmb", 641153618Sru nfsmb_methods, 642153618Sru sizeof(struct nfsmb_softc), 643153618Sru}; 644153618Sru 645153618Srustatic driver_t nfsmbsub_driver = { 646153618Sru "nfsmb", 647153618Sru nfsmbsub_methods, 648153618Sru sizeof(struct nfsmb_softc), 649153618Sru}; 650153618Sru 651153618SruDRIVER_MODULE(nfsmb, pci, nfsmb_driver, nfsmb_devclass, 0, 0); 652153618SruDRIVER_MODULE(nfsmb, nfsmb, nfsmbsub_driver, nfsmb_devclass, 0, 0); 653162234SjhbDRIVER_MODULE(smbus, nfsmb, smbus_driver, smbus_devclass, 0, 0); 654153618Sru 655153618SruMODULE_DEPEND(nfsmb, pci, 1, 1, 1); 656153618SruMODULE_DEPEND(nfsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 657153618SruMODULE_VERSION(nfsmb, 1); 658