1*271b33a6SRui Paulo /*- 2*271b33a6SRui Paulo * Copyright (c) 2005 Ruslan Ermilov 3*271b33a6SRui Paulo * All rights reserved. 4*271b33a6SRui Paulo * 5*271b33a6SRui Paulo * Redistribution and use in source and binary forms, with or without 6*271b33a6SRui Paulo * modification, are permitted provided that the following conditions 7*271b33a6SRui Paulo * are met: 8*271b33a6SRui Paulo * 1. Redistributions of source code must retain the above copyright 9*271b33a6SRui Paulo * notice, this list of conditions and the following disclaimer. 10*271b33a6SRui Paulo * 2. Redistributions in binary form must reproduce the above copyright 11*271b33a6SRui Paulo * notice, this list of conditions and the following disclaimer in the 12*271b33a6SRui Paulo * documentation and/or other materials provided with the distribution. 13*271b33a6SRui Paulo * 14*271b33a6SRui Paulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*271b33a6SRui Paulo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*271b33a6SRui Paulo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*271b33a6SRui Paulo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*271b33a6SRui Paulo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*271b33a6SRui Paulo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*271b33a6SRui Paulo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*271b33a6SRui Paulo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*271b33a6SRui Paulo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*271b33a6SRui Paulo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*271b33a6SRui Paulo * SUCH DAMAGE. 25*271b33a6SRui Paulo */ 26*271b33a6SRui Paulo 27*271b33a6SRui Paulo #include <sys/cdefs.h> 28*271b33a6SRui Paulo __FBSDID("$FreeBSD$"); 29*271b33a6SRui Paulo 30*271b33a6SRui Paulo #include <sys/param.h> 31*271b33a6SRui Paulo #include <sys/bus.h> 32*271b33a6SRui Paulo #include <sys/kernel.h> 33*271b33a6SRui Paulo #include <sys/lock.h> 34*271b33a6SRui Paulo #include <sys/module.h> 35*271b33a6SRui Paulo #include <sys/mutex.h> 36*271b33a6SRui Paulo #include <sys/systm.h> 37*271b33a6SRui Paulo 38*271b33a6SRui Paulo #include <machine/bus.h> 39*271b33a6SRui Paulo #include <machine/resource.h> 40*271b33a6SRui Paulo #include <sys/rman.h> 41*271b33a6SRui Paulo 42*271b33a6SRui Paulo #include <dev/pci/pcivar.h> 43*271b33a6SRui Paulo #include <dev/pci/pcireg.h> 44*271b33a6SRui Paulo 45*271b33a6SRui Paulo #include <dev/smbus/smbconf.h> 46*271b33a6SRui Paulo #include "smbus_if.h" 47*271b33a6SRui Paulo 48*271b33a6SRui Paulo #define NFSMB_DEBUG(x) if (nfsmb_debug) (x) 49*271b33a6SRui Paulo 50*271b33a6SRui Paulo #ifdef DEBUG 51*271b33a6SRui Paulo static int nfsmb_debug = 1; 52*271b33a6SRui Paulo #else 53*271b33a6SRui Paulo static int nfsmb_debug = 0; 54*271b33a6SRui Paulo #endif 55*271b33a6SRui Paulo 56*271b33a6SRui Paulo /* NVIDIA nForce2/3/4 MCP */ 57*271b33a6SRui Paulo #define NFSMB_VENDORID_NVIDIA 0x10de 58*271b33a6SRui Paulo #define NFSMB_DEVICEID_NF2_SMB 0x0064 59*271b33a6SRui Paulo #define NFSMB_DEVICEID_NF2_ULTRA_SMB 0x0084 60*271b33a6SRui Paulo #define NFSMB_DEVICEID_NF3_PRO150_SMB 0x00d4 61*271b33a6SRui Paulo #define NFSMB_DEVICEID_NF3_250GB_SMB 0x00e4 62*271b33a6SRui Paulo #define NFSMB_DEVICEID_NF4_SMB 0x0052 63*271b33a6SRui Paulo #define NFSMB_DEVICEID_NF4_04_SMB 0x0034 64*271b33a6SRui Paulo #define NFSMB_DEVICEID_NF4_51_SMB 0x0264 65*271b33a6SRui Paulo #define NFSMB_DEVICEID_NF4_55_SMB 0x0368 66*271b33a6SRui Paulo #define NFSMB_DEVICEID_NF4_61_SMB 0x03eb 67*271b33a6SRui Paulo #define NFSMB_DEVICEID_NF4_65_SMB 0x0446 68*271b33a6SRui Paulo #define NFSMB_DEVICEID_NF4_67_SMB 0x0542 69*271b33a6SRui Paulo #define NFSMB_DEVICEID_NF4_73_SMB 0x07d8 70*271b33a6SRui Paulo #define NFSMB_DEVICEID_NF4_78S_SMB 0x0752 71*271b33a6SRui Paulo #define NFSMB_DEVICEID_NF4_79_SMB 0x0aa2 72*271b33a6SRui Paulo 73*271b33a6SRui Paulo /* PCI Configuration space registers */ 74*271b33a6SRui Paulo #define NF2PCI_SMBASE_1 PCIR_BAR(4) 75*271b33a6SRui Paulo #define NF2PCI_SMBASE_2 PCIR_BAR(5) 76*271b33a6SRui Paulo 77*271b33a6SRui Paulo /* 78*271b33a6SRui Paulo * ACPI 3.0, Chapter 12, SMBus Host Controller Interface. 79*271b33a6SRui Paulo */ 80*271b33a6SRui Paulo #define SMB_PRTCL 0x00 /* protocol */ 81*271b33a6SRui Paulo #define SMB_STS 0x01 /* status */ 82*271b33a6SRui Paulo #define SMB_ADDR 0x02 /* address */ 83*271b33a6SRui Paulo #define SMB_CMD 0x03 /* command */ 84*271b33a6SRui Paulo #define SMB_DATA 0x04 /* 32 data registers */ 85*271b33a6SRui Paulo #define SMB_BCNT 0x24 /* number of data bytes */ 86*271b33a6SRui Paulo #define SMB_ALRM_A 0x25 /* alarm address */ 87*271b33a6SRui Paulo #define SMB_ALRM_D 0x26 /* 2 bytes alarm data */ 88*271b33a6SRui Paulo 89*271b33a6SRui Paulo #define SMB_STS_DONE 0x80 90*271b33a6SRui Paulo #define SMB_STS_ALRM 0x40 91*271b33a6SRui Paulo #define SMB_STS_RES 0x20 92*271b33a6SRui Paulo #define SMB_STS_STATUS 0x1f 93*271b33a6SRui Paulo #define SMB_STS_OK 0x00 /* OK */ 94*271b33a6SRui Paulo #define SMB_STS_UF 0x07 /* Unknown Failure */ 95*271b33a6SRui Paulo #define SMB_STS_DANA 0x10 /* Device Address Not Acknowledged */ 96*271b33a6SRui Paulo #define SMB_STS_DED 0x11 /* Device Error Detected */ 97*271b33a6SRui Paulo #define SMB_STS_DCAD 0x12 /* Device Command Access Denied */ 98*271b33a6SRui Paulo #define SMB_STS_UE 0x13 /* Unknown Error */ 99*271b33a6SRui Paulo #define SMB_STS_DAD 0x17 /* Device Access Denied */ 100*271b33a6SRui Paulo #define SMB_STS_T 0x18 /* Timeout */ 101*271b33a6SRui Paulo #define SMB_STS_HUP 0x19 /* Host Unsupported Protocol */ 102*271b33a6SRui Paulo #define SMB_STS_B 0x1A /* Busy */ 103*271b33a6SRui Paulo #define SMB_STS_PEC 0x1F /* PEC (CRC-8) Error */ 104*271b33a6SRui Paulo 105*271b33a6SRui Paulo #define SMB_PRTCL_WRITE 0x00 106*271b33a6SRui Paulo #define SMB_PRTCL_READ 0x01 107*271b33a6SRui Paulo #define SMB_PRTCL_QUICK 0x02 108*271b33a6SRui Paulo #define SMB_PRTCL_BYTE 0x04 109*271b33a6SRui Paulo #define SMB_PRTCL_BYTE_DATA 0x06 110*271b33a6SRui Paulo #define SMB_PRTCL_WORD_DATA 0x08 111*271b33a6SRui Paulo #define SMB_PRTCL_BLOCK_DATA 0x0a 112*271b33a6SRui Paulo #define SMB_PRTCL_PROC_CALL 0x0c 113*271b33a6SRui Paulo #define SMB_PRTCL_BLOCK_PROC_CALL 0x0d 114*271b33a6SRui Paulo #define SMB_PRTCL_PEC 0x80 115*271b33a6SRui Paulo 116*271b33a6SRui Paulo struct nfsmb_softc { 117*271b33a6SRui Paulo int rid; 118*271b33a6SRui Paulo struct resource *res; 119*271b33a6SRui Paulo device_t smbus; 120*271b33a6SRui Paulo device_t subdev; 121*271b33a6SRui Paulo struct mtx lock; 122*271b33a6SRui Paulo }; 123*271b33a6SRui Paulo 124*271b33a6SRui Paulo #define NFSMB_LOCK(nfsmb) mtx_lock(&(nfsmb)->lock) 125*271b33a6SRui Paulo #define NFSMB_UNLOCK(nfsmb) mtx_unlock(&(nfsmb)->lock) 126*271b33a6SRui Paulo #define NFSMB_LOCK_ASSERT(nfsmb) mtx_assert(&(nfsmb)->lock, MA_OWNED) 127*271b33a6SRui Paulo 128*271b33a6SRui Paulo #define NFSMB_SMBINB(nfsmb, register) \ 129*271b33a6SRui Paulo (bus_read_1(nfsmb->res, register)) 130*271b33a6SRui Paulo #define NFSMB_SMBOUTB(nfsmb, register, value) \ 131*271b33a6SRui Paulo (bus_write_1(nfsmb->res, register, value)) 132*271b33a6SRui Paulo 133*271b33a6SRui Paulo static int nfsmb_detach(device_t dev); 134*271b33a6SRui Paulo static int nfsmbsub_detach(device_t dev); 135*271b33a6SRui Paulo 136*271b33a6SRui Paulo static int 137*271b33a6SRui Paulo nfsmbsub_probe(device_t dev) 138*271b33a6SRui Paulo { 139*271b33a6SRui Paulo 140*271b33a6SRui Paulo device_set_desc(dev, "nForce2/3/4 MCP SMBus Controller"); 141*271b33a6SRui Paulo return (BUS_PROBE_DEFAULT); 142*271b33a6SRui Paulo } 143*271b33a6SRui Paulo 144*271b33a6SRui Paulo static int 145*271b33a6SRui Paulo nfsmb_probe(device_t dev) 146*271b33a6SRui Paulo { 147*271b33a6SRui Paulo u_int16_t vid; 148*271b33a6SRui Paulo u_int16_t did; 149*271b33a6SRui Paulo 150*271b33a6SRui Paulo vid = pci_get_vendor(dev); 151*271b33a6SRui Paulo did = pci_get_device(dev); 152*271b33a6SRui Paulo 153*271b33a6SRui Paulo if (vid == NFSMB_VENDORID_NVIDIA) { 154*271b33a6SRui Paulo switch(did) { 155*271b33a6SRui Paulo case NFSMB_DEVICEID_NF2_SMB: 156*271b33a6SRui Paulo case NFSMB_DEVICEID_NF2_ULTRA_SMB: 157*271b33a6SRui Paulo case NFSMB_DEVICEID_NF3_PRO150_SMB: 158*271b33a6SRui Paulo case NFSMB_DEVICEID_NF3_250GB_SMB: 159*271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_SMB: 160*271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_04_SMB: 161*271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_51_SMB: 162*271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_55_SMB: 163*271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_61_SMB: 164*271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_65_SMB: 165*271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_67_SMB: 166*271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_73_SMB: 167*271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_78S_SMB: 168*271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_79_SMB: 169*271b33a6SRui Paulo device_set_desc(dev, "nForce2/3/4 MCP SMBus Controller"); 170*271b33a6SRui Paulo return (BUS_PROBE_DEFAULT); 171*271b33a6SRui Paulo } 172*271b33a6SRui Paulo } 173*271b33a6SRui Paulo 174*271b33a6SRui Paulo return (ENXIO); 175*271b33a6SRui Paulo } 176*271b33a6SRui Paulo 177*271b33a6SRui Paulo static int 178*271b33a6SRui Paulo nfsmbsub_attach(device_t dev) 179*271b33a6SRui Paulo { 180*271b33a6SRui Paulo device_t parent; 181*271b33a6SRui Paulo struct nfsmb_softc *nfsmbsub_sc = device_get_softc(dev); 182*271b33a6SRui Paulo 183*271b33a6SRui Paulo parent = device_get_parent(dev); 184*271b33a6SRui Paulo 185*271b33a6SRui Paulo nfsmbsub_sc->rid = NF2PCI_SMBASE_2; 186*271b33a6SRui Paulo 187*271b33a6SRui Paulo nfsmbsub_sc->res = bus_alloc_resource_any(parent, SYS_RES_IOPORT, 188*271b33a6SRui Paulo &nfsmbsub_sc->rid, RF_ACTIVE); 189*271b33a6SRui Paulo if (nfsmbsub_sc->res == NULL) { 190*271b33a6SRui Paulo /* Older incarnations of the device used non-standard BARs. */ 191*271b33a6SRui Paulo nfsmbsub_sc->rid = 0x54; 192*271b33a6SRui Paulo nfsmbsub_sc->res = bus_alloc_resource_any(parent, 193*271b33a6SRui Paulo SYS_RES_IOPORT, &nfsmbsub_sc->rid, RF_ACTIVE); 194*271b33a6SRui Paulo if (nfsmbsub_sc->res == NULL) { 195*271b33a6SRui Paulo device_printf(dev, "could not map i/o space\n"); 196*271b33a6SRui Paulo return (ENXIO); 197*271b33a6SRui Paulo } 198*271b33a6SRui Paulo } 199*271b33a6SRui Paulo mtx_init(&nfsmbsub_sc->lock, device_get_nameunit(dev), "nfsmb", 200*271b33a6SRui Paulo MTX_DEF); 201*271b33a6SRui Paulo 202*271b33a6SRui Paulo nfsmbsub_sc->smbus = device_add_child(dev, "smbus", -1); 203*271b33a6SRui Paulo if (nfsmbsub_sc->smbus == NULL) { 204*271b33a6SRui Paulo nfsmbsub_detach(dev); 205*271b33a6SRui Paulo return (EINVAL); 206*271b33a6SRui Paulo } 207*271b33a6SRui Paulo 208*271b33a6SRui Paulo bus_generic_attach(dev); 209*271b33a6SRui Paulo 210*271b33a6SRui Paulo return (0); 211*271b33a6SRui Paulo } 212*271b33a6SRui Paulo 213*271b33a6SRui Paulo static int 214*271b33a6SRui Paulo nfsmb_attach(device_t dev) 215*271b33a6SRui Paulo { 216*271b33a6SRui Paulo struct nfsmb_softc *nfsmb_sc = device_get_softc(dev); 217*271b33a6SRui Paulo 218*271b33a6SRui Paulo /* Allocate I/O space */ 219*271b33a6SRui Paulo nfsmb_sc->rid = NF2PCI_SMBASE_1; 220*271b33a6SRui Paulo 221*271b33a6SRui Paulo nfsmb_sc->res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 222*271b33a6SRui Paulo &nfsmb_sc->rid, RF_ACTIVE); 223*271b33a6SRui Paulo 224*271b33a6SRui Paulo if (nfsmb_sc->res == NULL) { 225*271b33a6SRui Paulo /* Older incarnations of the device used non-standard BARs. */ 226*271b33a6SRui Paulo nfsmb_sc->rid = 0x50; 227*271b33a6SRui Paulo nfsmb_sc->res = bus_alloc_resource_any(dev, 228*271b33a6SRui Paulo SYS_RES_IOPORT, &nfsmb_sc->rid, RF_ACTIVE); 229*271b33a6SRui Paulo if (nfsmb_sc->res == NULL) { 230*271b33a6SRui Paulo device_printf(dev, "could not map i/o space\n"); 231*271b33a6SRui Paulo return (ENXIO); 232*271b33a6SRui Paulo } 233*271b33a6SRui Paulo } 234*271b33a6SRui Paulo 235*271b33a6SRui Paulo mtx_init(&nfsmb_sc->lock, device_get_nameunit(dev), "nfsmb", MTX_DEF); 236*271b33a6SRui Paulo 237*271b33a6SRui Paulo /* Allocate a new smbus device */ 238*271b33a6SRui Paulo nfsmb_sc->smbus = device_add_child(dev, "smbus", -1); 239*271b33a6SRui Paulo if (!nfsmb_sc->smbus) { 240*271b33a6SRui Paulo nfsmb_detach(dev); 241*271b33a6SRui Paulo return (EINVAL); 242*271b33a6SRui Paulo } 243*271b33a6SRui Paulo 244*271b33a6SRui Paulo nfsmb_sc->subdev = NULL; 245*271b33a6SRui Paulo switch (pci_get_device(dev)) { 246*271b33a6SRui Paulo case NFSMB_DEVICEID_NF2_SMB: 247*271b33a6SRui Paulo case NFSMB_DEVICEID_NF2_ULTRA_SMB: 248*271b33a6SRui Paulo case NFSMB_DEVICEID_NF3_PRO150_SMB: 249*271b33a6SRui Paulo case NFSMB_DEVICEID_NF3_250GB_SMB: 250*271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_SMB: 251*271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_04_SMB: 252*271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_51_SMB: 253*271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_55_SMB: 254*271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_61_SMB: 255*271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_65_SMB: 256*271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_67_SMB: 257*271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_73_SMB: 258*271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_78S_SMB: 259*271b33a6SRui Paulo case NFSMB_DEVICEID_NF4_79_SMB: 260*271b33a6SRui Paulo /* Trying to add secondary device as slave */ 261*271b33a6SRui Paulo nfsmb_sc->subdev = device_add_child(dev, "nfsmb", -1); 262*271b33a6SRui Paulo if (!nfsmb_sc->subdev) { 263*271b33a6SRui Paulo nfsmb_detach(dev); 264*271b33a6SRui Paulo return (EINVAL); 265*271b33a6SRui Paulo } 266*271b33a6SRui Paulo break; 267*271b33a6SRui Paulo default: 268*271b33a6SRui Paulo break; 269*271b33a6SRui Paulo } 270*271b33a6SRui Paulo 271*271b33a6SRui Paulo bus_generic_attach(dev); 272*271b33a6SRui Paulo 273*271b33a6SRui Paulo return (0); 274*271b33a6SRui Paulo } 275*271b33a6SRui Paulo 276*271b33a6SRui Paulo static int 277*271b33a6SRui Paulo nfsmbsub_detach(device_t dev) 278*271b33a6SRui Paulo { 279*271b33a6SRui Paulo device_t parent; 280*271b33a6SRui Paulo struct nfsmb_softc *nfsmbsub_sc = device_get_softc(dev); 281*271b33a6SRui Paulo 282*271b33a6SRui Paulo parent = device_get_parent(dev); 283*271b33a6SRui Paulo 284*271b33a6SRui Paulo if (nfsmbsub_sc->smbus) { 285*271b33a6SRui Paulo device_delete_child(dev, nfsmbsub_sc->smbus); 286*271b33a6SRui Paulo nfsmbsub_sc->smbus = NULL; 287*271b33a6SRui Paulo } 288*271b33a6SRui Paulo mtx_destroy(&nfsmbsub_sc->lock); 289*271b33a6SRui Paulo if (nfsmbsub_sc->res) { 290*271b33a6SRui Paulo bus_release_resource(parent, SYS_RES_IOPORT, nfsmbsub_sc->rid, 291*271b33a6SRui Paulo nfsmbsub_sc->res); 292*271b33a6SRui Paulo nfsmbsub_sc->res = NULL; 293*271b33a6SRui Paulo } 294*271b33a6SRui Paulo return (0); 295*271b33a6SRui Paulo } 296*271b33a6SRui Paulo 297*271b33a6SRui Paulo static int 298*271b33a6SRui Paulo nfsmb_detach(device_t dev) 299*271b33a6SRui Paulo { 300*271b33a6SRui Paulo struct nfsmb_softc *nfsmb_sc = device_get_softc(dev); 301*271b33a6SRui Paulo 302*271b33a6SRui Paulo if (nfsmb_sc->subdev) { 303*271b33a6SRui Paulo device_delete_child(dev, nfsmb_sc->subdev); 304*271b33a6SRui Paulo nfsmb_sc->subdev = NULL; 305*271b33a6SRui Paulo } 306*271b33a6SRui Paulo 307*271b33a6SRui Paulo if (nfsmb_sc->smbus) { 308*271b33a6SRui Paulo device_delete_child(dev, nfsmb_sc->smbus); 309*271b33a6SRui Paulo nfsmb_sc->smbus = NULL; 310*271b33a6SRui Paulo } 311*271b33a6SRui Paulo 312*271b33a6SRui Paulo mtx_destroy(&nfsmb_sc->lock); 313*271b33a6SRui Paulo if (nfsmb_sc->res) { 314*271b33a6SRui Paulo bus_release_resource(dev, SYS_RES_IOPORT, nfsmb_sc->rid, 315*271b33a6SRui Paulo nfsmb_sc->res); 316*271b33a6SRui Paulo nfsmb_sc->res = NULL; 317*271b33a6SRui Paulo } 318*271b33a6SRui Paulo 319*271b33a6SRui Paulo return (0); 320*271b33a6SRui Paulo } 321*271b33a6SRui Paulo 322*271b33a6SRui Paulo static int 323*271b33a6SRui Paulo nfsmb_callback(device_t dev, int index, void *data) 324*271b33a6SRui Paulo { 325*271b33a6SRui Paulo int error = 0; 326*271b33a6SRui Paulo 327*271b33a6SRui Paulo switch (index) { 328*271b33a6SRui Paulo case SMB_REQUEST_BUS: 329*271b33a6SRui Paulo case SMB_RELEASE_BUS: 330*271b33a6SRui Paulo break; 331*271b33a6SRui Paulo default: 332*271b33a6SRui Paulo error = EINVAL; 333*271b33a6SRui Paulo } 334*271b33a6SRui Paulo 335*271b33a6SRui Paulo return (error); 336*271b33a6SRui Paulo } 337*271b33a6SRui Paulo 338*271b33a6SRui Paulo static int 339*271b33a6SRui Paulo nfsmb_wait(struct nfsmb_softc *sc) 340*271b33a6SRui Paulo { 341*271b33a6SRui Paulo u_char sts; 342*271b33a6SRui Paulo int error, count; 343*271b33a6SRui Paulo 344*271b33a6SRui Paulo NFSMB_LOCK_ASSERT(sc); 345*271b33a6SRui Paulo if (NFSMB_SMBINB(sc, SMB_PRTCL) != 0) 346*271b33a6SRui Paulo { 347*271b33a6SRui Paulo count = 10000; 348*271b33a6SRui Paulo do { 349*271b33a6SRui Paulo DELAY(500); 350*271b33a6SRui Paulo } while (NFSMB_SMBINB(sc, SMB_PRTCL) != 0 && count--); 351*271b33a6SRui Paulo if (count == 0) 352*271b33a6SRui Paulo return (SMB_ETIMEOUT); 353*271b33a6SRui Paulo } 354*271b33a6SRui Paulo 355*271b33a6SRui Paulo sts = NFSMB_SMBINB(sc, SMB_STS) & SMB_STS_STATUS; 356*271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: STS=0x%x\n", sts)); 357*271b33a6SRui Paulo 358*271b33a6SRui Paulo switch (sts) { 359*271b33a6SRui Paulo case SMB_STS_OK: 360*271b33a6SRui Paulo error = SMB_ENOERR; 361*271b33a6SRui Paulo break; 362*271b33a6SRui Paulo case SMB_STS_DANA: 363*271b33a6SRui Paulo error = SMB_ENOACK; 364*271b33a6SRui Paulo break; 365*271b33a6SRui Paulo case SMB_STS_B: 366*271b33a6SRui Paulo error = SMB_EBUSY; 367*271b33a6SRui Paulo break; 368*271b33a6SRui Paulo case SMB_STS_T: 369*271b33a6SRui Paulo error = SMB_ETIMEOUT; 370*271b33a6SRui Paulo break; 371*271b33a6SRui Paulo case SMB_STS_DCAD: 372*271b33a6SRui Paulo case SMB_STS_DAD: 373*271b33a6SRui Paulo case SMB_STS_HUP: 374*271b33a6SRui Paulo error = SMB_ENOTSUPP; 375*271b33a6SRui Paulo break; 376*271b33a6SRui Paulo default: 377*271b33a6SRui Paulo error = SMB_EBUSERR; 378*271b33a6SRui Paulo break; 379*271b33a6SRui Paulo } 380*271b33a6SRui Paulo 381*271b33a6SRui Paulo return (error); 382*271b33a6SRui Paulo } 383*271b33a6SRui Paulo 384*271b33a6SRui Paulo static int 385*271b33a6SRui Paulo nfsmb_quick(device_t dev, u_char slave, int how) 386*271b33a6SRui Paulo { 387*271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 388*271b33a6SRui Paulo u_char protocol; 389*271b33a6SRui Paulo int error; 390*271b33a6SRui Paulo 391*271b33a6SRui Paulo protocol = SMB_PRTCL_QUICK; 392*271b33a6SRui Paulo 393*271b33a6SRui Paulo switch (how) { 394*271b33a6SRui Paulo case SMB_QWRITE: 395*271b33a6SRui Paulo protocol |= SMB_PRTCL_WRITE; 396*271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: QWRITE to 0x%x", slave)); 397*271b33a6SRui Paulo break; 398*271b33a6SRui Paulo case SMB_QREAD: 399*271b33a6SRui Paulo protocol |= SMB_PRTCL_READ; 400*271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: QREAD to 0x%x", slave)); 401*271b33a6SRui Paulo break; 402*271b33a6SRui Paulo default: 403*271b33a6SRui Paulo panic("%s: unknown QUICK command (%x)!", __func__, how); 404*271b33a6SRui Paulo } 405*271b33a6SRui Paulo 406*271b33a6SRui Paulo NFSMB_LOCK(sc); 407*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 408*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, protocol); 409*271b33a6SRui Paulo 410*271b33a6SRui Paulo error = nfsmb_wait(sc); 411*271b33a6SRui Paulo 412*271b33a6SRui Paulo NFSMB_DEBUG(printf(", error=0x%x\n", error)); 413*271b33a6SRui Paulo NFSMB_UNLOCK(sc); 414*271b33a6SRui Paulo 415*271b33a6SRui Paulo return (error); 416*271b33a6SRui Paulo } 417*271b33a6SRui Paulo 418*271b33a6SRui Paulo static int 419*271b33a6SRui Paulo nfsmb_sendb(device_t dev, u_char slave, char byte) 420*271b33a6SRui Paulo { 421*271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 422*271b33a6SRui Paulo int error; 423*271b33a6SRui Paulo 424*271b33a6SRui Paulo NFSMB_LOCK(sc); 425*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_CMD, byte); 426*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 427*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BYTE); 428*271b33a6SRui Paulo 429*271b33a6SRui Paulo error = nfsmb_wait(sc); 430*271b33a6SRui Paulo 431*271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error)); 432*271b33a6SRui Paulo NFSMB_UNLOCK(sc); 433*271b33a6SRui Paulo 434*271b33a6SRui Paulo return (error); 435*271b33a6SRui Paulo } 436*271b33a6SRui Paulo 437*271b33a6SRui Paulo static int 438*271b33a6SRui Paulo nfsmb_recvb(device_t dev, u_char slave, char *byte) 439*271b33a6SRui Paulo { 440*271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 441*271b33a6SRui Paulo int error; 442*271b33a6SRui Paulo 443*271b33a6SRui Paulo NFSMB_LOCK(sc); 444*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 445*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BYTE); 446*271b33a6SRui Paulo 447*271b33a6SRui Paulo if ((error = nfsmb_wait(sc)) == SMB_ENOERR) 448*271b33a6SRui Paulo *byte = NFSMB_SMBINB(sc, SMB_DATA); 449*271b33a6SRui Paulo 450*271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error)); 451*271b33a6SRui Paulo NFSMB_UNLOCK(sc); 452*271b33a6SRui Paulo 453*271b33a6SRui Paulo return (error); 454*271b33a6SRui Paulo } 455*271b33a6SRui Paulo 456*271b33a6SRui Paulo static int 457*271b33a6SRui Paulo nfsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 458*271b33a6SRui Paulo { 459*271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 460*271b33a6SRui Paulo int error; 461*271b33a6SRui Paulo 462*271b33a6SRui Paulo NFSMB_LOCK(sc); 463*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_CMD, cmd); 464*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_DATA, byte); 465*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 466*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BYTE_DATA); 467*271b33a6SRui Paulo 468*271b33a6SRui Paulo error = nfsmb_wait(sc); 469*271b33a6SRui Paulo 470*271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error)); 471*271b33a6SRui Paulo NFSMB_UNLOCK(sc); 472*271b33a6SRui Paulo 473*271b33a6SRui Paulo return (error); 474*271b33a6SRui Paulo } 475*271b33a6SRui Paulo 476*271b33a6SRui Paulo static int 477*271b33a6SRui Paulo nfsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 478*271b33a6SRui Paulo { 479*271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 480*271b33a6SRui Paulo int error; 481*271b33a6SRui Paulo 482*271b33a6SRui Paulo NFSMB_LOCK(sc); 483*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_CMD, cmd); 484*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 485*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BYTE_DATA); 486*271b33a6SRui Paulo 487*271b33a6SRui Paulo if ((error = nfsmb_wait(sc)) == SMB_ENOERR) 488*271b33a6SRui Paulo *byte = NFSMB_SMBINB(sc, SMB_DATA); 489*271b33a6SRui Paulo 490*271b33a6SRui 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)); 491*271b33a6SRui Paulo NFSMB_UNLOCK(sc); 492*271b33a6SRui Paulo 493*271b33a6SRui Paulo return (error); 494*271b33a6SRui Paulo } 495*271b33a6SRui Paulo 496*271b33a6SRui Paulo static int 497*271b33a6SRui Paulo nfsmb_writew(device_t dev, u_char slave, char cmd, short word) 498*271b33a6SRui Paulo { 499*271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 500*271b33a6SRui Paulo int error; 501*271b33a6SRui Paulo 502*271b33a6SRui Paulo NFSMB_LOCK(sc); 503*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_CMD, cmd); 504*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_DATA, word); 505*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_DATA + 1, word >> 8); 506*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 507*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_WORD_DATA); 508*271b33a6SRui Paulo 509*271b33a6SRui Paulo error = nfsmb_wait(sc); 510*271b33a6SRui Paulo 511*271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error)); 512*271b33a6SRui Paulo NFSMB_UNLOCK(sc); 513*271b33a6SRui Paulo 514*271b33a6SRui Paulo return (error); 515*271b33a6SRui Paulo } 516*271b33a6SRui Paulo 517*271b33a6SRui Paulo static int 518*271b33a6SRui Paulo nfsmb_readw(device_t dev, u_char slave, char cmd, short *word) 519*271b33a6SRui Paulo { 520*271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 521*271b33a6SRui Paulo int error; 522*271b33a6SRui Paulo 523*271b33a6SRui Paulo NFSMB_LOCK(sc); 524*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_CMD, cmd); 525*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 526*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_WORD_DATA); 527*271b33a6SRui Paulo 528*271b33a6SRui Paulo if ((error = nfsmb_wait(sc)) == SMB_ENOERR) 529*271b33a6SRui Paulo *word = NFSMB_SMBINB(sc, SMB_DATA) | 530*271b33a6SRui Paulo (NFSMB_SMBINB(sc, SMB_DATA + 1) << 8); 531*271b33a6SRui Paulo 532*271b33a6SRui 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)); 533*271b33a6SRui Paulo NFSMB_UNLOCK(sc); 534*271b33a6SRui Paulo 535*271b33a6SRui Paulo return (error); 536*271b33a6SRui Paulo } 537*271b33a6SRui Paulo 538*271b33a6SRui Paulo static int 539*271b33a6SRui Paulo nfsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 540*271b33a6SRui Paulo { 541*271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 542*271b33a6SRui Paulo u_char i; 543*271b33a6SRui Paulo int error; 544*271b33a6SRui Paulo 545*271b33a6SRui Paulo if (count < 1 || count > 32) 546*271b33a6SRui Paulo return (SMB_EINVAL); 547*271b33a6SRui Paulo 548*271b33a6SRui Paulo NFSMB_LOCK(sc); 549*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_CMD, cmd); 550*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_BCNT, count); 551*271b33a6SRui Paulo for (i = 0; i < count; i++) 552*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_DATA + i, buf[i]); 553*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 554*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BLOCK_DATA); 555*271b33a6SRui Paulo 556*271b33a6SRui Paulo error = nfsmb_wait(sc); 557*271b33a6SRui Paulo 558*271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 559*271b33a6SRui Paulo NFSMB_UNLOCK(sc); 560*271b33a6SRui Paulo 561*271b33a6SRui Paulo return (error); 562*271b33a6SRui Paulo } 563*271b33a6SRui Paulo 564*271b33a6SRui Paulo static int 565*271b33a6SRui Paulo nfsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) 566*271b33a6SRui Paulo { 567*271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev); 568*271b33a6SRui Paulo u_char data, len, i; 569*271b33a6SRui Paulo int error; 570*271b33a6SRui Paulo 571*271b33a6SRui Paulo if (*count < 1 || *count > 32) 572*271b33a6SRui Paulo return (SMB_EINVAL); 573*271b33a6SRui Paulo 574*271b33a6SRui Paulo NFSMB_LOCK(sc); 575*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_CMD, cmd); 576*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave); 577*271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BLOCK_DATA); 578*271b33a6SRui Paulo 579*271b33a6SRui Paulo if ((error = nfsmb_wait(sc)) == SMB_ENOERR) { 580*271b33a6SRui Paulo len = NFSMB_SMBINB(sc, SMB_BCNT); 581*271b33a6SRui Paulo for (i = 0; i < len; i++) { 582*271b33a6SRui Paulo data = NFSMB_SMBINB(sc, SMB_DATA + i); 583*271b33a6SRui Paulo if (i < *count) 584*271b33a6SRui Paulo buf[i] = data; 585*271b33a6SRui Paulo } 586*271b33a6SRui Paulo *count = len; 587*271b33a6SRui Paulo } 588*271b33a6SRui Paulo 589*271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, *count, cmd, error)); 590*271b33a6SRui Paulo NFSMB_UNLOCK(sc); 591*271b33a6SRui Paulo 592*271b33a6SRui Paulo return (error); 593*271b33a6SRui Paulo } 594*271b33a6SRui Paulo 595*271b33a6SRui Paulo static device_method_t nfsmb_methods[] = { 596*271b33a6SRui Paulo /* Device interface */ 597*271b33a6SRui Paulo DEVMETHOD(device_probe, nfsmb_probe), 598*271b33a6SRui Paulo DEVMETHOD(device_attach, nfsmb_attach), 599*271b33a6SRui Paulo DEVMETHOD(device_detach, nfsmb_detach), 600*271b33a6SRui Paulo 601*271b33a6SRui Paulo /* SMBus interface */ 602*271b33a6SRui Paulo DEVMETHOD(smbus_callback, nfsmb_callback), 603*271b33a6SRui Paulo DEVMETHOD(smbus_quick, nfsmb_quick), 604*271b33a6SRui Paulo DEVMETHOD(smbus_sendb, nfsmb_sendb), 605*271b33a6SRui Paulo DEVMETHOD(smbus_recvb, nfsmb_recvb), 606*271b33a6SRui Paulo DEVMETHOD(smbus_writeb, nfsmb_writeb), 607*271b33a6SRui Paulo DEVMETHOD(smbus_readb, nfsmb_readb), 608*271b33a6SRui Paulo DEVMETHOD(smbus_writew, nfsmb_writew), 609*271b33a6SRui Paulo DEVMETHOD(smbus_readw, nfsmb_readw), 610*271b33a6SRui Paulo DEVMETHOD(smbus_bwrite, nfsmb_bwrite), 611*271b33a6SRui Paulo DEVMETHOD(smbus_bread, nfsmb_bread), 612*271b33a6SRui Paulo 613*271b33a6SRui Paulo { 0, 0 } 614*271b33a6SRui Paulo }; 615*271b33a6SRui Paulo 616*271b33a6SRui Paulo static device_method_t nfsmbsub_methods[] = { 617*271b33a6SRui Paulo /* Device interface */ 618*271b33a6SRui Paulo DEVMETHOD(device_probe, nfsmbsub_probe), 619*271b33a6SRui Paulo DEVMETHOD(device_attach, nfsmbsub_attach), 620*271b33a6SRui Paulo DEVMETHOD(device_detach, nfsmbsub_detach), 621*271b33a6SRui Paulo 622*271b33a6SRui Paulo /* SMBus interface */ 623*271b33a6SRui Paulo DEVMETHOD(smbus_callback, nfsmb_callback), 624*271b33a6SRui Paulo DEVMETHOD(smbus_quick, nfsmb_quick), 625*271b33a6SRui Paulo DEVMETHOD(smbus_sendb, nfsmb_sendb), 626*271b33a6SRui Paulo DEVMETHOD(smbus_recvb, nfsmb_recvb), 627*271b33a6SRui Paulo DEVMETHOD(smbus_writeb, nfsmb_writeb), 628*271b33a6SRui Paulo DEVMETHOD(smbus_readb, nfsmb_readb), 629*271b33a6SRui Paulo DEVMETHOD(smbus_writew, nfsmb_writew), 630*271b33a6SRui Paulo DEVMETHOD(smbus_readw, nfsmb_readw), 631*271b33a6SRui Paulo DEVMETHOD(smbus_bwrite, nfsmb_bwrite), 632*271b33a6SRui Paulo DEVMETHOD(smbus_bread, nfsmb_bread), 633*271b33a6SRui Paulo 634*271b33a6SRui Paulo { 0, 0 } 635*271b33a6SRui Paulo }; 636*271b33a6SRui Paulo 637*271b33a6SRui Paulo static devclass_t nfsmb_devclass; 638*271b33a6SRui Paulo 639*271b33a6SRui Paulo static driver_t nfsmb_driver = { 640*271b33a6SRui Paulo "nfsmb", 641*271b33a6SRui Paulo nfsmb_methods, 642*271b33a6SRui Paulo sizeof(struct nfsmb_softc), 643*271b33a6SRui Paulo }; 644*271b33a6SRui Paulo 645*271b33a6SRui Paulo static driver_t nfsmbsub_driver = { 646*271b33a6SRui Paulo "nfsmb", 647*271b33a6SRui Paulo nfsmbsub_methods, 648*271b33a6SRui Paulo sizeof(struct nfsmb_softc), 649*271b33a6SRui Paulo }; 650*271b33a6SRui Paulo 651*271b33a6SRui Paulo DRIVER_MODULE(nfsmb, pci, nfsmb_driver, nfsmb_devclass, 0, 0); 652*271b33a6SRui Paulo DRIVER_MODULE(nfsmb, nfsmb, nfsmbsub_driver, nfsmb_devclass, 0, 0); 653*271b33a6SRui Paulo DRIVER_MODULE(smbus, nfsmb, smbus_driver, smbus_devclass, 0, 0); 654*271b33a6SRui Paulo 655*271b33a6SRui Paulo MODULE_DEPEND(nfsmb, pci, 1, 1, 1); 656*271b33a6SRui Paulo MODULE_DEPEND(nfsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 657*271b33a6SRui Paulo MODULE_VERSION(nfsmb, 1); 658