1271b33a6SRui Paulo /*- 2271b33a6SRui Paulo * Copyright (c) 2005 Ruslan Ermilov 3271b33a6SRui Paulo * All rights reserved. 4271b33a6SRui Paulo * 5271b33a6SRui Paulo * Redistribution and use in source and binary forms, with or without 6271b33a6SRui Paulo * modification, are permitted provided that the following conditions 7271b33a6SRui Paulo * are met: 8271b33a6SRui Paulo * 1. Redistributions of source code must retain the above copyright 9271b33a6SRui Paulo * notice, this list of conditions and the following disclaimer. 10271b33a6SRui Paulo * 2. Redistributions in binary form must reproduce the above copyright 11271b33a6SRui Paulo * notice, this list of conditions and the following disclaimer in the 12271b33a6SRui Paulo * documentation and/or other materials provided with the distribution. 13271b33a6SRui Paulo * 14271b33a6SRui Paulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15271b33a6SRui Paulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16271b33a6SRui Paulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17271b33a6SRui Paulo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18271b33a6SRui Paulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19271b33a6SRui Paulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20271b33a6SRui Paulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21271b33a6SRui Paulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22271b33a6SRui Paulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23271b33a6SRui Paulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24271b33a6SRui Paulo * SUCH DAMAGE. 25271b33a6SRui Paulo */ 26271b33a6SRui Paulo 27271b33a6SRui Paulo #include <sys/param.h> 28271b33a6SRui Paulo #include <sys/bus.h> 29271b33a6SRui Paulo #include <sys/kernel.h> 30271b33a6SRui Paulo #include <sys/lock.h> 31271b33a6SRui Paulo #include <sys/module.h> 32271b33a6SRui Paulo #include <sys/mutex.h> 33271b33a6SRui Paulo #include <sys/systm.h> 34271b33a6SRui Paulo 35271b33a6SRui Paulo #include <machine/bus.h> 36271b33a6SRui Paulo #include <machine/resource.h> 37271b33a6SRui Paulo #include <sys/rman.h> 38271b33a6SRui Paulo 39271b33a6SRui Paulo #include <dev/pci/pcivar.h> 40271b33a6SRui Paulo #include <dev/pci/pcireg.h> 41271b33a6SRui Paulo 42271b33a6SRui Paulo #include <dev/smbus/smbconf.h> 43271b33a6SRui Paulo #include "smbus_if.h" 44271b33a6SRui Paulo 45271b33a6SRui Paulo #define NFSMB_DEBUG(x) if (nfsmb_debug) (x) 46271b33a6SRui Paulo 47271b33a6SRui Paulo #ifdef DEBUG 48271b33a6SRui Paulo static int nfsmb_debug = 1; 49271b33a6SRui Paulo #else 50271b33a6SRui Paulo static int nfsmb_debug = 0; 51271b33a6SRui Paulo #endif 52271b33a6SRui Paulo 53271b33a6SRui Paulo /* NVIDIA nForce2/3/4 MCP */ 54271b33a6SRui Paulo #define NFSMB_VENDORID_NVIDIA 0x10de 55271b33a6SRui Paulo #define NFSMB_DEVICEID_NF2_SMB 0x0064 56271b33a6SRui Paulo #define NFSMB_DEVICEID_NF2_ULTRA_SMB 0x0084 57271b33a6SRui Paulo #define NFSMB_DEVICEID_NF3_PRO150_SMB 0x00d4 58271b33a6SRui Paulo #define NFSMB_DEVICEID_NF3_250GB_SMB 0x00e4 59271b33a6SRui Paulo #define NFSMB_DEVICEID_NF4_SMB 0x0052 60271b33a6SRui Paulo #define NFSMB_DEVICEID_NF4_04_SMB 0x0034 61271b33a6SRui Paulo #define NFSMB_DEVICEID_NF4_51_SMB 0x0264 62271b33a6SRui Paulo #define NFSMB_DEVICEID_NF4_55_SMB 0x0368 63271b33a6SRui Paulo #define NFSMB_DEVICEID_NF4_61_SMB 0x03eb 64271b33a6SRui Paulo #define NFSMB_DEVICEID_NF4_65_SMB 0x0446 65271b33a6SRui Paulo #define NFSMB_DEVICEID_NF4_67_SMB 0x0542 66271b33a6SRui Paulo #define NFSMB_DEVICEID_NF4_73_SMB 0x07d8 67271b33a6SRui Paulo #define NFSMB_DEVICEID_NF4_78S_SMB 0x0752 68271b33a6SRui Paulo #define NFSMB_DEVICEID_NF4_79_SMB 0x0aa2 69271b33a6SRui Paulo 70271b33a6SRui Paulo /* PCI Configuration space registers */ 71271b33a6SRui Paulo #define NF2PCI_SMBASE_1 PCIR_BAR(4) 72271b33a6SRui Paulo #define NF2PCI_SMBASE_2 PCIR_BAR(5) 73271b33a6SRui Paulo 74271b33a6SRui Paulo /* 75271b33a6SRui Paulo * ACPI 3.0, Chapter 12, SMBus Host Controller Interface. 76271b33a6SRui Paulo */ 77271b33a6SRui Paulo #define SMB_PRTCL 0x00 /* protocol */ 78271b33a6SRui Paulo #define SMB_STS 0x01 /* status */ 79271b33a6SRui Paulo #define SMB_ADDR 0x02 /* address */ 80271b33a6SRui Paulo #define SMB_CMD 0x03 /* command */ 81271b33a6SRui Paulo #define SMB_DATA 0x04 /* 32 data registers */ 82271b33a6SRui Paulo #define SMB_BCNT 0x24 /* number of data bytes */ 83271b33a6SRui Paulo #define SMB_ALRM_A 0x25 /* alarm address */ 84271b33a6SRui Paulo #define SMB_ALRM_D 0x26 /* 2 bytes alarm data */ 85271b33a6SRui Paulo 86271b33a6SRui Paulo #define SMB_STS_DONE 0x80 87271b33a6SRui Paulo #define SMB_STS_ALRM 0x40 88271b33a6SRui Paulo #define SMB_STS_RES 0x20 89271b33a6SRui Paulo #define SMB_STS_STATUS 0x1f 90271b33a6SRui Paulo #define SMB_STS_OK 0x00 /* OK */ 91271b33a6SRui Paulo #define SMB_STS_UF 0x07 /* Unknown Failure */ 92271b33a6SRui Paulo #define SMB_STS_DANA 0x10 /* Device Address Not Acknowledged */ 93271b33a6SRui Paulo #define SMB_STS_DED 0x11 /* Device Error Detected */ 94271b33a6SRui Paulo #define SMB_STS_DCAD 0x12 /* Device Command Access Denied */ 95271b33a6SRui Paulo #define SMB_STS_UE 0x13 /* Unknown Error */ 96271b33a6SRui Paulo #define SMB_STS_DAD 0x17 /* Device Access Denied */ 97271b33a6SRui Paulo #define SMB_STS_T 0x18 /* Timeout */ 98271b33a6SRui Paulo #define SMB_STS_HUP 0x19 /* Host Unsupported Protocol */ 99271b33a6SRui Paulo #define SMB_STS_B 0x1A /* Busy */ 100271b33a6SRui Paulo #define SMB_STS_PEC 0x1F /* PEC (CRC-8) Error */ 101271b33a6SRui Paulo 102271b33a6SRui Paulo #define SMB_PRTCL_WRITE 0x00 103271b33a6SRui Paulo #define SMB_PRTCL_READ 0x01 104271b33a6SRui Paulo #define SMB_PRTCL_QUICK 0x02 105271b33a6SRui Paulo #define SMB_PRTCL_BYTE 0x04 106271b33a6SRui Paulo #define SMB_PRTCL_BYTE_DATA 0x06 107271b33a6SRui Paulo #define SMB_PRTCL_WORD_DATA 0x08 108271b33a6SRui Paulo #define SMB_PRTCL_BLOCK_DATA 0x0a 109271b33a6SRui Paulo #define SMB_PRTCL_PROC_CALL 0x0c 110271b33a6SRui Paulo #define SMB_PRTCL_BLOCK_PROC_CALL 0x0d 111271b33a6SRui Paulo #define SMB_PRTCL_PEC 0x80 112271b33a6SRui Paulo 113271b33a6SRui Paulo struct nfsmb_softc { 114271b33a6SRui Paulo int rid; 115271b33a6SRui Paulo struct resource *res; 116271b33a6SRui Paulo device_t smbus; 117271b33a6SRui Paulo device_t subdev; 118271b33a6SRui Paulo struct mtx lock; 119271b33a6SRui Paulo }; 120271b33a6SRui Paulo 121271b33a6SRui Paulo #define NFSMB_LOCK(nfsmb) mtx_lock(&(nfsmb)->lock) 122271b33a6SRui Paulo #define NFSMB_UNLOCK(nfsmb) mtx_unlock(&(nfsmb)->lock) 123271b33a6SRui Paulo #define NFSMB_LOCK_ASSERT(nfsmb) mtx_assert(&(nfsmb)->lock, MA_OWNED) 124271b33a6SRui Paulo 125271b33a6SRui Paulo #define NFSMB_SMBINB(nfsmb, register) \ 126271b33a6SRui Paulo (bus_read_1(nfsmb->res, register)) 127271b33a6SRui Paulo #define NFSMB_SMBOUTB(nfsmb, register, value) \ 128271b33a6SRui Paulo (bus_write_1(nfsmb->res, register, value)) 129271b33a6SRui Paulo 130271b33a6SRui Paulo static int nfsmb_detach(device_t dev); 131271b33a6SRui Paulo static int nfsmbsub_detach(device_t dev); 132271b33a6SRui Paulo 133271b33a6SRui Paulo static int 134271b33a6SRui Paulo nfsmbsub_probe(device_t dev) 135271b33a6SRui Paulo { 136271b33a6SRui Paulo 137271b33a6SRui Paulo device_set_desc(dev, "nForce2/3/4 MCP SMBus Controller"); 138271b33a6SRui Paulo return (BUS_PROBE_DEFAULT); 139271b33a6SRui Paulo } 140271b33a6SRui Paulo 141271b33a6SRui Paulo static int 142271b33a6SRui Paulo nfsmb_probe(device_t dev) 143271b33a6SRui Paulo { 144271b33a6SRui Paulo u_int16_t vid; 145271b33a6SRui Paulo u_int16_t did; 146271b33a6SRui Paulo 147271b33a6SRui Paulo vid = pci_get_vendor(dev); 148271b33a6SRui Paulo did = pci_get_device(dev); 149271b33a6SRui Paulo 150271b33a6SRui Paulo if (vid == NFSMB_VENDORID_NVIDIA) { 151271b33a6SRui Paulo switch(did) { 152271b33a6SRui Paulo case NFSMB_DEVICEID_NF2_SMB: 153271b33a6SRui Paulo case NFSMB_DEVICEID_NF2_ULTRA_SMB: 154271b33a6SRui Paulo case NFSMB_DEVICEID_NF3_PRO150_SMB: 155271b33a6SRui Paulo case NFSMB_DEVICEID_NF3_250GB_SMB: 156271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_SMB: 157271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_04_SMB: 158271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_51_SMB: 159271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_55_SMB: 160271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_61_SMB: 161271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_65_SMB: 162271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_67_SMB: 163271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_73_SMB: 164271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_78S_SMB: 165271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_79_SMB: 166271b33a6SRui Paulo device_set_desc(dev, "nForce2/3/4 MCP SMBus Controller"); 167271b33a6SRui Paulo return (BUS_PROBE_DEFAULT); 168271b33a6SRui Paulo } 169271b33a6SRui Paulo } 170271b33a6SRui Paulo 171271b33a6SRui Paulo return (ENXIO); 172271b33a6SRui Paulo } 173271b33a6SRui Paulo 174271b33a6SRui Paulo static int 175271b33a6SRui Paulo nfsmbsub_attach(device_t dev) 176271b33a6SRui Paulo { 177271b33a6SRui Paulo device_t parent; 178271b33a6SRui Paulo struct nfsmb_softc *nfsmbsub_sc = device_get_softc(dev); 179271b33a6SRui Paulo 180271b33a6SRui Paulo parent = device_get_parent(dev); 181271b33a6SRui Paulo 182271b33a6SRui Paulo nfsmbsub_sc->rid = NF2PCI_SMBASE_2; 183271b33a6SRui Paulo 184271b33a6SRui Paulo nfsmbsub_sc->res = bus_alloc_resource_any(parent, SYS_RES_IOPORT, 185271b33a6SRui Paulo &nfsmbsub_sc->rid, RF_ACTIVE); 186271b33a6SRui Paulo if (nfsmbsub_sc->res == NULL) { 187271b33a6SRui Paulo /* Older incarnations of the device used non-standard BARs. */ 188271b33a6SRui Paulo nfsmbsub_sc->rid = 0x54; 189271b33a6SRui Paulo nfsmbsub_sc->res = bus_alloc_resource_any(parent, 190271b33a6SRui Paulo SYS_RES_IOPORT, &nfsmbsub_sc->rid, RF_ACTIVE); 191271b33a6SRui Paulo if (nfsmbsub_sc->res == NULL) { 192271b33a6SRui Paulo device_printf(dev, "could not map i/o space\n"); 193271b33a6SRui Paulo return (ENXIO); 194271b33a6SRui Paulo } 195271b33a6SRui Paulo } 196271b33a6SRui Paulo mtx_init(&nfsmbsub_sc->lock, device_get_nameunit(dev), "nfsmb", 197271b33a6SRui Paulo MTX_DEF); 198271b33a6SRui Paulo 199*5b56413dSWarner Losh nfsmbsub_sc->smbus = device_add_child(dev, "smbus", DEVICE_UNIT_ANY); 200271b33a6SRui Paulo if (nfsmbsub_sc->smbus == NULL) { 201271b33a6SRui Paulo nfsmbsub_detach(dev); 202271b33a6SRui Paulo return (EINVAL); 203271b33a6SRui Paulo } 204271b33a6SRui Paulo 205271b33a6SRui Paulo bus_generic_attach(dev); 206271b33a6SRui Paulo 207271b33a6SRui Paulo return (0); 208271b33a6SRui Paulo } 209271b33a6SRui Paulo 210271b33a6SRui Paulo static int 211271b33a6SRui Paulo nfsmb_attach(device_t dev) 212271b33a6SRui Paulo { 213271b33a6SRui Paulo struct nfsmb_softc *nfsmb_sc = device_get_softc(dev); 214271b33a6SRui Paulo 215271b33a6SRui Paulo /* Allocate I/O space */ 216271b33a6SRui Paulo nfsmb_sc->rid = NF2PCI_SMBASE_1; 217271b33a6SRui Paulo 218271b33a6SRui Paulo nfsmb_sc->res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 219271b33a6SRui Paulo &nfsmb_sc->rid, RF_ACTIVE); 220271b33a6SRui Paulo 221271b33a6SRui Paulo if (nfsmb_sc->res == NULL) { 222271b33a6SRui Paulo /* Older incarnations of the device used non-standard BARs. */ 223271b33a6SRui Paulo nfsmb_sc->rid = 0x50; 224271b33a6SRui Paulo nfsmb_sc->res = bus_alloc_resource_any(dev, 225271b33a6SRui Paulo SYS_RES_IOPORT, &nfsmb_sc->rid, RF_ACTIVE); 226271b33a6SRui Paulo if (nfsmb_sc->res == NULL) { 227271b33a6SRui Paulo device_printf(dev, "could not map i/o space\n"); 228271b33a6SRui Paulo return (ENXIO); 229271b33a6SRui Paulo } 230271b33a6SRui Paulo } 231271b33a6SRui Paulo 232271b33a6SRui Paulo mtx_init(&nfsmb_sc->lock, device_get_nameunit(dev), "nfsmb", MTX_DEF); 233271b33a6SRui Paulo 234271b33a6SRui Paulo /* Allocate a new smbus device */ 235*5b56413dSWarner Losh nfsmb_sc->smbus = device_add_child(dev, "smbus", DEVICE_UNIT_ANY); 236271b33a6SRui Paulo if (!nfsmb_sc->smbus) { 237271b33a6SRui Paulo nfsmb_detach(dev); 238271b33a6SRui Paulo return (EINVAL); 239271b33a6SRui Paulo } 240271b33a6SRui Paulo 241271b33a6SRui Paulo nfsmb_sc->subdev = NULL; 242271b33a6SRui Paulo switch (pci_get_device(dev)) { 243271b33a6SRui Paulo case NFSMB_DEVICEID_NF2_SMB: 244271b33a6SRui Paulo case NFSMB_DEVICEID_NF2_ULTRA_SMB: 245271b33a6SRui Paulo case NFSMB_DEVICEID_NF3_PRO150_SMB: 246271b33a6SRui Paulo case NFSMB_DEVICEID_NF3_250GB_SMB: 247271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_SMB: 248271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_04_SMB: 249271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_51_SMB: 250271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_55_SMB: 251271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_61_SMB: 252271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_65_SMB: 253271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_67_SMB: 254271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_73_SMB: 255271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_78S_SMB: 256271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_79_SMB: 257271b33a6SRui Paulo /* Trying to add secondary device as slave */ 258*5b56413dSWarner Losh nfsmb_sc->subdev = device_add_child(dev, "nfsmb", DEVICE_UNIT_ANY); 259271b33a6SRui Paulo if (!nfsmb_sc->subdev) { 260271b33a6SRui Paulo nfsmb_detach(dev); 261271b33a6SRui Paulo return (EINVAL); 262271b33a6SRui Paulo } 263271b33a6SRui Paulo break; 264271b33a6SRui Paulo default: 265271b33a6SRui Paulo break; 266271b33a6SRui Paulo } 267271b33a6SRui Paulo 268271b33a6SRui Paulo bus_generic_attach(dev); 269271b33a6SRui Paulo 270271b33a6SRui Paulo return (0); 271271b33a6SRui Paulo } 272271b33a6SRui Paulo 273271b33a6SRui Paulo static int 274271b33a6SRui Paulo nfsmbsub_detach(device_t dev) 275271b33a6SRui Paulo { 276271b33a6SRui Paulo device_t parent; 277271b33a6SRui Paulo struct nfsmb_softc *nfsmbsub_sc = device_get_softc(dev); 278271b33a6SRui Paulo 279271b33a6SRui Paulo parent = device_get_parent(dev); 280271b33a6SRui Paulo 281271b33a6SRui Paulo if (nfsmbsub_sc->smbus) { 282271b33a6SRui Paulo device_delete_child(dev, nfsmbsub_sc->smbus); 283271b33a6SRui Paulo nfsmbsub_sc->smbus = NULL; 284271b33a6SRui Paulo } 285271b33a6SRui Paulo mtx_destroy(&nfsmbsub_sc->lock); 286271b33a6SRui Paulo if (nfsmbsub_sc->res) { 287271b33a6SRui Paulo bus_release_resource(parent, SYS_RES_IOPORT, nfsmbsub_sc->rid, 288271b33a6SRui Paulo nfsmbsub_sc->res); 289271b33a6SRui Paulo nfsmbsub_sc->res = NULL; 290271b33a6SRui Paulo } 291271b33a6SRui Paulo return (0); 292271b33a6SRui Paulo } 293271b33a6SRui Paulo 294271b33a6SRui Paulo static int 295271b33a6SRui Paulo nfsmb_detach(device_t dev) 296271b33a6SRui Paulo { 297271b33a6SRui Paulo struct nfsmb_softc *nfsmb_sc = device_get_softc(dev); 298271b33a6SRui Paulo 299271b33a6SRui Paulo if (nfsmb_sc->subdev) { 300271b33a6SRui Paulo device_delete_child(dev, nfsmb_sc->subdev); 301271b33a6SRui Paulo nfsmb_sc->subdev = NULL; 302271b33a6SRui Paulo } 303271b33a6SRui Paulo 304271b33a6SRui Paulo if (nfsmb_sc->smbus) { 305271b33a6SRui Paulo device_delete_child(dev, nfsmb_sc->smbus); 306271b33a6SRui Paulo nfsmb_sc->smbus = NULL; 307271b33a6SRui Paulo } 308271b33a6SRui Paulo 309271b33a6SRui Paulo mtx_destroy(&nfsmb_sc->lock); 310271b33a6SRui Paulo if (nfsmb_sc->res) { 311271b33a6SRui Paulo bus_release_resource(dev, SYS_RES_IOPORT, nfsmb_sc->rid, 312271b33a6SRui Paulo nfsmb_sc->res); 313271b33a6SRui Paulo nfsmb_sc->res = NULL; 314271b33a6SRui Paulo } 315271b33a6SRui Paulo 316271b33a6SRui Paulo return (0); 317271b33a6SRui Paulo } 318271b33a6SRui Paulo 319271b33a6SRui Paulo static int 320271b33a6SRui Paulo nfsmb_callback(device_t dev, int index, void *data) 321271b33a6SRui Paulo { 322271b33a6SRui Paulo int error = 0; 323271b33a6SRui Paulo 324271b33a6SRui Paulo switch (index) { 325271b33a6SRui Paulo case SMB_REQUEST_BUS: 326271b33a6SRui Paulo case SMB_RELEASE_BUS: 327271b33a6SRui Paulo break; 328271b33a6SRui Paulo default: 329271b33a6SRui Paulo error = EINVAL; 330271b33a6SRui Paulo } 331271b33a6SRui Paulo 332271b33a6SRui Paulo return (error); 333271b33a6SRui Paulo } 334271b33a6SRui Paulo 335271b33a6SRui Paulo static int 336271b33a6SRui Paulo nfsmb_wait(struct nfsmb_softc *sc) 337271b33a6SRui Paulo { 338271b33a6SRui Paulo u_char sts; 339271b33a6SRui Paulo int error, count; 340271b33a6SRui Paulo 341271b33a6SRui Paulo NFSMB_LOCK_ASSERT(sc); 342271b33a6SRui Paulo if (NFSMB_SMBINB(sc, SMB_PRTCL) != 0) 343271b33a6SRui Paulo { 344271b33a6SRui Paulo count = 10000; 345271b33a6SRui Paulo do { 346271b33a6SRui Paulo DELAY(500); 347271b33a6SRui Paulo } while (NFSMB_SMBINB(sc, SMB_PRTCL) != 0 && count--); 348271b33a6SRui Paulo if (count == 0) 349271b33a6SRui Paulo return (SMB_ETIMEOUT); 350271b33a6SRui Paulo } 351271b33a6SRui Paulo 352271b33a6SRui Paulo sts = NFSMB_SMBINB(sc, SMB_STS) & SMB_STS_STATUS; 353271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: STS=0x%x\n", sts)); 354271b33a6SRui Paulo 355271b33a6SRui Paulo switch (sts) { 356271b33a6SRui Paulo case SMB_STS_OK: 357271b33a6SRui Paulo error = SMB_ENOERR; 358271b33a6SRui Paulo break; 359271b33a6SRui Paulo case SMB_STS_DANA: 360271b33a6SRui Paulo error = SMB_ENOACK; 361271b33a6SRui Paulo break; 362271b33a6SRui Paulo case SMB_STS_B: 363271b33a6SRui Paulo error = SMB_EBUSY; 364271b33a6SRui Paulo break; 365271b33a6SRui Paulo case SMB_STS_T: 366271b33a6SRui Paulo error = SMB_ETIMEOUT; 367271b33a6SRui Paulo break; 368271b33a6SRui Paulo case SMB_STS_DCAD: 369271b33a6SRui Paulo case SMB_STS_DAD: 370271b33a6SRui Paulo case SMB_STS_HUP: 371271b33a6SRui Paulo error = SMB_ENOTSUPP; 372271b33a6SRui Paulo break; 373271b33a6SRui Paulo default: 374271b33a6SRui Paulo error = SMB_EBUSERR; 375271b33a6SRui Paulo break; 376271b33a6SRui Paulo } 377271b33a6SRui Paulo 378271b33a6SRui Paulo return (error); 379271b33a6SRui Paulo } 380271b33a6SRui Paulo 381271b33a6SRui Paulo static int 382271b33a6SRui Paulo nfsmb_quick(device_t dev, u_char slave, int how) 383271b33a6SRui Paulo { 384271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 385271b33a6SRui Paulo u_char protocol; 386271b33a6SRui Paulo int error; 387271b33a6SRui Paulo 388271b33a6SRui Paulo protocol = SMB_PRTCL_QUICK; 389271b33a6SRui Paulo 390271b33a6SRui Paulo switch (how) { 391271b33a6SRui Paulo case SMB_QWRITE: 392271b33a6SRui Paulo protocol |= SMB_PRTCL_WRITE; 393271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: QWRITE to 0x%x", slave)); 394271b33a6SRui Paulo break; 395271b33a6SRui Paulo case SMB_QREAD: 396271b33a6SRui Paulo protocol |= SMB_PRTCL_READ; 397271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: QREAD to 0x%x", slave)); 398271b33a6SRui Paulo break; 399271b33a6SRui Paulo default: 400271b33a6SRui Paulo panic("%s: unknown QUICK command (%x)!", __func__, how); 401271b33a6SRui Paulo } 402271b33a6SRui Paulo 403271b33a6SRui Paulo NFSMB_LOCK(sc); 404271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 405271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, protocol); 406271b33a6SRui Paulo 407271b33a6SRui Paulo error = nfsmb_wait(sc); 408271b33a6SRui Paulo 409271b33a6SRui Paulo NFSMB_DEBUG(printf(", error=0x%x\n", error)); 410271b33a6SRui Paulo NFSMB_UNLOCK(sc); 411271b33a6SRui Paulo 412271b33a6SRui Paulo return (error); 413271b33a6SRui Paulo } 414271b33a6SRui Paulo 415271b33a6SRui Paulo static int 416271b33a6SRui Paulo nfsmb_sendb(device_t dev, u_char slave, char byte) 417271b33a6SRui Paulo { 418271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 419271b33a6SRui Paulo int error; 420271b33a6SRui Paulo 421271b33a6SRui Paulo NFSMB_LOCK(sc); 422271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_CMD, byte); 423271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 424271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BYTE); 425271b33a6SRui Paulo 426271b33a6SRui Paulo error = nfsmb_wait(sc); 427271b33a6SRui Paulo 428271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error)); 429271b33a6SRui Paulo NFSMB_UNLOCK(sc); 430271b33a6SRui Paulo 431271b33a6SRui Paulo return (error); 432271b33a6SRui Paulo } 433271b33a6SRui Paulo 434271b33a6SRui Paulo static int 435271b33a6SRui Paulo nfsmb_recvb(device_t dev, u_char slave, char *byte) 436271b33a6SRui Paulo { 437271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 438271b33a6SRui Paulo int error; 439271b33a6SRui Paulo 440271b33a6SRui Paulo NFSMB_LOCK(sc); 441271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 442271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BYTE); 443271b33a6SRui Paulo 444271b33a6SRui Paulo if ((error = nfsmb_wait(sc)) == SMB_ENOERR) 445271b33a6SRui Paulo *byte = NFSMB_SMBINB(sc, SMB_DATA); 446271b33a6SRui Paulo 447271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error)); 448271b33a6SRui Paulo NFSMB_UNLOCK(sc); 449271b33a6SRui Paulo 450271b33a6SRui Paulo return (error); 451271b33a6SRui Paulo } 452271b33a6SRui Paulo 453271b33a6SRui Paulo static int 454271b33a6SRui Paulo nfsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 455271b33a6SRui Paulo { 456271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 457271b33a6SRui Paulo int error; 458271b33a6SRui Paulo 459271b33a6SRui Paulo NFSMB_LOCK(sc); 460271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_CMD, cmd); 461271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_DATA, byte); 462271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 463271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BYTE_DATA); 464271b33a6SRui Paulo 465271b33a6SRui Paulo error = nfsmb_wait(sc); 466271b33a6SRui Paulo 467271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error)); 468271b33a6SRui Paulo NFSMB_UNLOCK(sc); 469271b33a6SRui Paulo 470271b33a6SRui Paulo return (error); 471271b33a6SRui Paulo } 472271b33a6SRui Paulo 473271b33a6SRui Paulo static int 474271b33a6SRui Paulo nfsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 475271b33a6SRui Paulo { 476271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 477271b33a6SRui Paulo int error; 478271b33a6SRui Paulo 479271b33a6SRui Paulo NFSMB_LOCK(sc); 480271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_CMD, cmd); 481271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 482271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BYTE_DATA); 483271b33a6SRui Paulo 484271b33a6SRui Paulo if ((error = nfsmb_wait(sc)) == SMB_ENOERR) 485271b33a6SRui Paulo *byte = NFSMB_SMBINB(sc, SMB_DATA); 486271b33a6SRui Paulo 487271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, (unsigned char)*byte, error)); 488271b33a6SRui Paulo NFSMB_UNLOCK(sc); 489271b33a6SRui Paulo 490271b33a6SRui Paulo return (error); 491271b33a6SRui Paulo } 492271b33a6SRui Paulo 493271b33a6SRui Paulo static int 494271b33a6SRui Paulo nfsmb_writew(device_t dev, u_char slave, char cmd, short word) 495271b33a6SRui Paulo { 496271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 497271b33a6SRui Paulo int error; 498271b33a6SRui Paulo 499271b33a6SRui Paulo NFSMB_LOCK(sc); 500271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_CMD, cmd); 501271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_DATA, word); 502271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_DATA + 1, word >> 8); 503271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 504271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_WORD_DATA); 505271b33a6SRui Paulo 506271b33a6SRui Paulo error = nfsmb_wait(sc); 507271b33a6SRui Paulo 508271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error)); 509271b33a6SRui Paulo NFSMB_UNLOCK(sc); 510271b33a6SRui Paulo 511271b33a6SRui Paulo return (error); 512271b33a6SRui Paulo } 513271b33a6SRui Paulo 514271b33a6SRui Paulo static int 515271b33a6SRui Paulo nfsmb_readw(device_t dev, u_char slave, char cmd, short *word) 516271b33a6SRui Paulo { 517271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 518271b33a6SRui Paulo int error; 519271b33a6SRui Paulo 520271b33a6SRui Paulo NFSMB_LOCK(sc); 521271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_CMD, cmd); 522271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 523271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_WORD_DATA); 524271b33a6SRui Paulo 525271b33a6SRui Paulo if ((error = nfsmb_wait(sc)) == SMB_ENOERR) 526271b33a6SRui Paulo *word = NFSMB_SMBINB(sc, SMB_DATA) | 527271b33a6SRui Paulo (NFSMB_SMBINB(sc, SMB_DATA + 1) << 8); 528271b33a6SRui Paulo 529271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, (unsigned short)*word, error)); 530271b33a6SRui Paulo NFSMB_UNLOCK(sc); 531271b33a6SRui Paulo 532271b33a6SRui Paulo return (error); 533271b33a6SRui Paulo } 534271b33a6SRui Paulo 535271b33a6SRui Paulo static int 536271b33a6SRui Paulo nfsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 537271b33a6SRui Paulo { 538271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 539271b33a6SRui Paulo u_char i; 540271b33a6SRui Paulo int error; 541271b33a6SRui Paulo 542271b33a6SRui Paulo if (count < 1 || count > 32) 543271b33a6SRui Paulo return (SMB_EINVAL); 544271b33a6SRui Paulo 545271b33a6SRui Paulo NFSMB_LOCK(sc); 546271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_CMD, cmd); 547271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_BCNT, count); 548271b33a6SRui Paulo for (i = 0; i < count; i++) 549271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_DATA + i, buf[i]); 550271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 551271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BLOCK_DATA); 552271b33a6SRui Paulo 553271b33a6SRui Paulo error = nfsmb_wait(sc); 554271b33a6SRui Paulo 555271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 556271b33a6SRui Paulo NFSMB_UNLOCK(sc); 557271b33a6SRui Paulo 558271b33a6SRui Paulo return (error); 559271b33a6SRui Paulo } 560271b33a6SRui Paulo 561271b33a6SRui Paulo static int 562271b33a6SRui Paulo nfsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) 563271b33a6SRui Paulo { 564271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 565271b33a6SRui Paulo u_char data, len, i; 566271b33a6SRui Paulo int error; 567271b33a6SRui Paulo 568271b33a6SRui Paulo if (*count < 1 || *count > 32) 569271b33a6SRui Paulo return (SMB_EINVAL); 570271b33a6SRui Paulo 571271b33a6SRui Paulo NFSMB_LOCK(sc); 572271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_CMD, cmd); 573271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 574271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BLOCK_DATA); 575271b33a6SRui Paulo 576271b33a6SRui Paulo if ((error = nfsmb_wait(sc)) == SMB_ENOERR) { 577271b33a6SRui Paulo len = NFSMB_SMBINB(sc, SMB_BCNT); 578271b33a6SRui Paulo for (i = 0; i < len; i++) { 579271b33a6SRui Paulo data = NFSMB_SMBINB(sc, SMB_DATA + i); 580271b33a6SRui Paulo if (i < *count) 581271b33a6SRui Paulo buf[i] = data; 582271b33a6SRui Paulo } 583271b33a6SRui Paulo *count = len; 584271b33a6SRui Paulo } 585271b33a6SRui Paulo 586271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, *count, cmd, error)); 587271b33a6SRui Paulo NFSMB_UNLOCK(sc); 588271b33a6SRui Paulo 589271b33a6SRui Paulo return (error); 590271b33a6SRui Paulo } 591271b33a6SRui Paulo 592271b33a6SRui Paulo static device_method_t nfsmb_methods[] = { 593271b33a6SRui Paulo /* Device interface */ 594271b33a6SRui Paulo DEVMETHOD(device_probe, nfsmb_probe), 595271b33a6SRui Paulo DEVMETHOD(device_attach, nfsmb_attach), 596271b33a6SRui Paulo DEVMETHOD(device_detach, nfsmb_detach), 597271b33a6SRui Paulo 598271b33a6SRui Paulo /* SMBus interface */ 599271b33a6SRui Paulo DEVMETHOD(smbus_callback, nfsmb_callback), 600271b33a6SRui Paulo DEVMETHOD(smbus_quick, nfsmb_quick), 601271b33a6SRui Paulo DEVMETHOD(smbus_sendb, nfsmb_sendb), 602271b33a6SRui Paulo DEVMETHOD(smbus_recvb, nfsmb_recvb), 603271b33a6SRui Paulo DEVMETHOD(smbus_writeb, nfsmb_writeb), 604271b33a6SRui Paulo DEVMETHOD(smbus_readb, nfsmb_readb), 605271b33a6SRui Paulo DEVMETHOD(smbus_writew, nfsmb_writew), 606271b33a6SRui Paulo DEVMETHOD(smbus_readw, nfsmb_readw), 607271b33a6SRui Paulo DEVMETHOD(smbus_bwrite, nfsmb_bwrite), 608271b33a6SRui Paulo DEVMETHOD(smbus_bread, nfsmb_bread), 609271b33a6SRui Paulo { 0, 0 } 610271b33a6SRui Paulo }; 611271b33a6SRui Paulo 612271b33a6SRui Paulo static device_method_t nfsmbsub_methods[] = { 613271b33a6SRui Paulo /* Device interface */ 614271b33a6SRui Paulo DEVMETHOD(device_probe, nfsmbsub_probe), 615271b33a6SRui Paulo DEVMETHOD(device_attach, nfsmbsub_attach), 616271b33a6SRui Paulo DEVMETHOD(device_detach, nfsmbsub_detach), 617271b33a6SRui Paulo 618271b33a6SRui Paulo /* SMBus interface */ 619271b33a6SRui Paulo DEVMETHOD(smbus_callback, nfsmb_callback), 620271b33a6SRui Paulo DEVMETHOD(smbus_quick, nfsmb_quick), 621271b33a6SRui Paulo DEVMETHOD(smbus_sendb, nfsmb_sendb), 622271b33a6SRui Paulo DEVMETHOD(smbus_recvb, nfsmb_recvb), 623271b33a6SRui Paulo DEVMETHOD(smbus_writeb, nfsmb_writeb), 624271b33a6SRui Paulo DEVMETHOD(smbus_readb, nfsmb_readb), 625271b33a6SRui Paulo DEVMETHOD(smbus_writew, nfsmb_writew), 626271b33a6SRui Paulo DEVMETHOD(smbus_readw, nfsmb_readw), 627271b33a6SRui Paulo DEVMETHOD(smbus_bwrite, nfsmb_bwrite), 628271b33a6SRui Paulo DEVMETHOD(smbus_bread, nfsmb_bread), 629271b33a6SRui Paulo { 0, 0 } 630271b33a6SRui Paulo }; 631271b33a6SRui Paulo 632271b33a6SRui Paulo static driver_t nfsmb_driver = { 633271b33a6SRui Paulo "nfsmb", 634271b33a6SRui Paulo nfsmb_methods, 635271b33a6SRui Paulo sizeof(struct nfsmb_softc), 636271b33a6SRui Paulo }; 637271b33a6SRui Paulo 638271b33a6SRui Paulo static driver_t nfsmbsub_driver = { 639271b33a6SRui Paulo "nfsmb", 640271b33a6SRui Paulo nfsmbsub_methods, 641271b33a6SRui Paulo sizeof(struct nfsmb_softc), 642271b33a6SRui Paulo }; 643271b33a6SRui Paulo 644bd53cac1SJohn Baldwin DRIVER_MODULE(nfsmb, pci, nfsmb_driver, 0, 0); 645bd53cac1SJohn Baldwin DRIVER_MODULE(nfsmb, nfsmb, nfsmbsub_driver, 0, 0); 646c6d39765SJohn Baldwin DRIVER_MODULE(smbus, nfsmb, smbus_driver, 0, 0); 647271b33a6SRui Paulo 648271b33a6SRui Paulo MODULE_DEPEND(nfsmb, pci, 1, 1, 1); 649271b33a6SRui Paulo MODULE_DEPEND(nfsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 650271b33a6SRui Paulo MODULE_VERSION(nfsmb, 1); 651