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