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
nfsmbsub_probe(device_t dev)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
nfsmb_probe(device_t dev)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
nfsmbsub_attach(device_t dev)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
1995b56413dSWarner 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
20518250ec6SJohn Baldwin bus_attach_children(dev);
206271b33a6SRui Paulo
207271b33a6SRui Paulo return (0);
208271b33a6SRui Paulo }
209271b33a6SRui Paulo
210271b33a6SRui Paulo static int
nfsmb_attach(device_t dev)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 */
2355b56413dSWarner 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 */
2585b56413dSWarner 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
26818250ec6SJohn Baldwin bus_attach_children(dev);
269271b33a6SRui Paulo
270271b33a6SRui Paulo return (0);
271271b33a6SRui Paulo }
272271b33a6SRui Paulo
273271b33a6SRui Paulo static int
nfsmbsub_detach(device_t dev)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);
278*11a91178SJohn Baldwin int error;
279271b33a6SRui Paulo
280271b33a6SRui Paulo parent = device_get_parent(dev);
281271b33a6SRui Paulo
282*11a91178SJohn Baldwin error = bus_generic_detach(dev);
283*11a91178SJohn Baldwin if (error != 0)
284*11a91178SJohn Baldwin return (error);
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
nfsmb_detach(device_t dev)295271b33a6SRui Paulo nfsmb_detach(device_t dev)
296271b33a6SRui Paulo {
297271b33a6SRui Paulo struct nfsmb_softc *nfsmb_sc = device_get_softc(dev);
298*11a91178SJohn Baldwin int error;
299271b33a6SRui Paulo
300*11a91178SJohn Baldwin error = bus_generic_detach(dev);
301*11a91178SJohn Baldwin if (error != 0)
302*11a91178SJohn Baldwin return (error);
303271b33a6SRui Paulo
304271b33a6SRui Paulo mtx_destroy(&nfsmb_sc->lock);
305271b33a6SRui Paulo if (nfsmb_sc->res) {
306271b33a6SRui Paulo bus_release_resource(dev, SYS_RES_IOPORT, nfsmb_sc->rid,
307271b33a6SRui Paulo nfsmb_sc->res);
308271b33a6SRui Paulo nfsmb_sc->res = NULL;
309271b33a6SRui Paulo }
310271b33a6SRui Paulo
311271b33a6SRui Paulo return (0);
312271b33a6SRui Paulo }
313271b33a6SRui Paulo
314271b33a6SRui Paulo static int
nfsmb_callback(device_t dev,int index,void * data)315271b33a6SRui Paulo nfsmb_callback(device_t dev, int index, void *data)
316271b33a6SRui Paulo {
317271b33a6SRui Paulo int error = 0;
318271b33a6SRui Paulo
319271b33a6SRui Paulo switch (index) {
320271b33a6SRui Paulo case SMB_REQUEST_BUS:
321271b33a6SRui Paulo case SMB_RELEASE_BUS:
322271b33a6SRui Paulo break;
323271b33a6SRui Paulo default:
324271b33a6SRui Paulo error = EINVAL;
325271b33a6SRui Paulo }
326271b33a6SRui Paulo
327271b33a6SRui Paulo return (error);
328271b33a6SRui Paulo }
329271b33a6SRui Paulo
330271b33a6SRui Paulo static int
nfsmb_wait(struct nfsmb_softc * sc)331271b33a6SRui Paulo nfsmb_wait(struct nfsmb_softc *sc)
332271b33a6SRui Paulo {
333271b33a6SRui Paulo u_char sts;
334271b33a6SRui Paulo int error, count;
335271b33a6SRui Paulo
336271b33a6SRui Paulo NFSMB_LOCK_ASSERT(sc);
337271b33a6SRui Paulo if (NFSMB_SMBINB(sc, SMB_PRTCL) != 0)
338271b33a6SRui Paulo {
339271b33a6SRui Paulo count = 10000;
340271b33a6SRui Paulo do {
341271b33a6SRui Paulo DELAY(500);
342271b33a6SRui Paulo } while (NFSMB_SMBINB(sc, SMB_PRTCL) != 0 && count--);
343271b33a6SRui Paulo if (count == 0)
344271b33a6SRui Paulo return (SMB_ETIMEOUT);
345271b33a6SRui Paulo }
346271b33a6SRui Paulo
347271b33a6SRui Paulo sts = NFSMB_SMBINB(sc, SMB_STS) & SMB_STS_STATUS;
348271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: STS=0x%x\n", sts));
349271b33a6SRui Paulo
350271b33a6SRui Paulo switch (sts) {
351271b33a6SRui Paulo case SMB_STS_OK:
352271b33a6SRui Paulo error = SMB_ENOERR;
353271b33a6SRui Paulo break;
354271b33a6SRui Paulo case SMB_STS_DANA:
355271b33a6SRui Paulo error = SMB_ENOACK;
356271b33a6SRui Paulo break;
357271b33a6SRui Paulo case SMB_STS_B:
358271b33a6SRui Paulo error = SMB_EBUSY;
359271b33a6SRui Paulo break;
360271b33a6SRui Paulo case SMB_STS_T:
361271b33a6SRui Paulo error = SMB_ETIMEOUT;
362271b33a6SRui Paulo break;
363271b33a6SRui Paulo case SMB_STS_DCAD:
364271b33a6SRui Paulo case SMB_STS_DAD:
365271b33a6SRui Paulo case SMB_STS_HUP:
366271b33a6SRui Paulo error = SMB_ENOTSUPP;
367271b33a6SRui Paulo break;
368271b33a6SRui Paulo default:
369271b33a6SRui Paulo error = SMB_EBUSERR;
370271b33a6SRui Paulo break;
371271b33a6SRui Paulo }
372271b33a6SRui Paulo
373271b33a6SRui Paulo return (error);
374271b33a6SRui Paulo }
375271b33a6SRui Paulo
376271b33a6SRui Paulo static int
nfsmb_quick(device_t dev,u_char slave,int how)377271b33a6SRui Paulo nfsmb_quick(device_t dev, u_char slave, int how)
378271b33a6SRui Paulo {
379271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
380271b33a6SRui Paulo u_char protocol;
381271b33a6SRui Paulo int error;
382271b33a6SRui Paulo
383271b33a6SRui Paulo protocol = SMB_PRTCL_QUICK;
384271b33a6SRui Paulo
385271b33a6SRui Paulo switch (how) {
386271b33a6SRui Paulo case SMB_QWRITE:
387271b33a6SRui Paulo protocol |= SMB_PRTCL_WRITE;
388271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: QWRITE to 0x%x", slave));
389271b33a6SRui Paulo break;
390271b33a6SRui Paulo case SMB_QREAD:
391271b33a6SRui Paulo protocol |= SMB_PRTCL_READ;
392271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: QREAD to 0x%x", slave));
393271b33a6SRui Paulo break;
394271b33a6SRui Paulo default:
395271b33a6SRui Paulo panic("%s: unknown QUICK command (%x)!", __func__, how);
396271b33a6SRui Paulo }
397271b33a6SRui Paulo
398271b33a6SRui Paulo NFSMB_LOCK(sc);
399271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
400271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, protocol);
401271b33a6SRui Paulo
402271b33a6SRui Paulo error = nfsmb_wait(sc);
403271b33a6SRui Paulo
404271b33a6SRui Paulo NFSMB_DEBUG(printf(", error=0x%x\n", error));
405271b33a6SRui Paulo NFSMB_UNLOCK(sc);
406271b33a6SRui Paulo
407271b33a6SRui Paulo return (error);
408271b33a6SRui Paulo }
409271b33a6SRui Paulo
410271b33a6SRui Paulo static int
nfsmb_sendb(device_t dev,u_char slave,char byte)411271b33a6SRui Paulo nfsmb_sendb(device_t dev, u_char slave, char byte)
412271b33a6SRui Paulo {
413271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
414271b33a6SRui Paulo int error;
415271b33a6SRui Paulo
416271b33a6SRui Paulo NFSMB_LOCK(sc);
417271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_CMD, byte);
418271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
419271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BYTE);
420271b33a6SRui Paulo
421271b33a6SRui Paulo error = nfsmb_wait(sc);
422271b33a6SRui Paulo
423271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error));
424271b33a6SRui Paulo NFSMB_UNLOCK(sc);
425271b33a6SRui Paulo
426271b33a6SRui Paulo return (error);
427271b33a6SRui Paulo }
428271b33a6SRui Paulo
429271b33a6SRui Paulo static int
nfsmb_recvb(device_t dev,u_char slave,char * byte)430271b33a6SRui Paulo nfsmb_recvb(device_t dev, u_char slave, char *byte)
431271b33a6SRui Paulo {
432271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
433271b33a6SRui Paulo int error;
434271b33a6SRui Paulo
435271b33a6SRui Paulo NFSMB_LOCK(sc);
436271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
437271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BYTE);
438271b33a6SRui Paulo
439271b33a6SRui Paulo if ((error = nfsmb_wait(sc)) == SMB_ENOERR)
440271b33a6SRui Paulo *byte = NFSMB_SMBINB(sc, SMB_DATA);
441271b33a6SRui Paulo
442271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error));
443271b33a6SRui Paulo NFSMB_UNLOCK(sc);
444271b33a6SRui Paulo
445271b33a6SRui Paulo return (error);
446271b33a6SRui Paulo }
447271b33a6SRui Paulo
448271b33a6SRui Paulo static int
nfsmb_writeb(device_t dev,u_char slave,char cmd,char byte)449271b33a6SRui Paulo nfsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
450271b33a6SRui Paulo {
451271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
452271b33a6SRui Paulo int error;
453271b33a6SRui Paulo
454271b33a6SRui Paulo NFSMB_LOCK(sc);
455271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
456271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_DATA, byte);
457271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
458271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BYTE_DATA);
459271b33a6SRui Paulo
460271b33a6SRui Paulo error = nfsmb_wait(sc);
461271b33a6SRui Paulo
462271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error));
463271b33a6SRui Paulo NFSMB_UNLOCK(sc);
464271b33a6SRui Paulo
465271b33a6SRui Paulo return (error);
466271b33a6SRui Paulo }
467271b33a6SRui Paulo
468271b33a6SRui Paulo static int
nfsmb_readb(device_t dev,u_char slave,char cmd,char * byte)469271b33a6SRui Paulo nfsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
470271b33a6SRui Paulo {
471271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
472271b33a6SRui Paulo int error;
473271b33a6SRui Paulo
474271b33a6SRui Paulo NFSMB_LOCK(sc);
475271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
476271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
477271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BYTE_DATA);
478271b33a6SRui Paulo
479271b33a6SRui Paulo if ((error = nfsmb_wait(sc)) == SMB_ENOERR)
480271b33a6SRui Paulo *byte = NFSMB_SMBINB(sc, SMB_DATA);
481271b33a6SRui Paulo
482271b33a6SRui 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));
483271b33a6SRui Paulo NFSMB_UNLOCK(sc);
484271b33a6SRui Paulo
485271b33a6SRui Paulo return (error);
486271b33a6SRui Paulo }
487271b33a6SRui Paulo
488271b33a6SRui Paulo static int
nfsmb_writew(device_t dev,u_char slave,char cmd,short word)489271b33a6SRui Paulo nfsmb_writew(device_t dev, u_char slave, char cmd, short word)
490271b33a6SRui Paulo {
491271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
492271b33a6SRui Paulo int error;
493271b33a6SRui Paulo
494271b33a6SRui Paulo NFSMB_LOCK(sc);
495271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
496271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_DATA, word);
497271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_DATA + 1, word >> 8);
498271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
499271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_WORD_DATA);
500271b33a6SRui Paulo
501271b33a6SRui Paulo error = nfsmb_wait(sc);
502271b33a6SRui Paulo
503271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error));
504271b33a6SRui Paulo NFSMB_UNLOCK(sc);
505271b33a6SRui Paulo
506271b33a6SRui Paulo return (error);
507271b33a6SRui Paulo }
508271b33a6SRui Paulo
509271b33a6SRui Paulo static int
nfsmb_readw(device_t dev,u_char slave,char cmd,short * word)510271b33a6SRui Paulo nfsmb_readw(device_t dev, u_char slave, char cmd, short *word)
511271b33a6SRui Paulo {
512271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
513271b33a6SRui Paulo int error;
514271b33a6SRui Paulo
515271b33a6SRui Paulo NFSMB_LOCK(sc);
516271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
517271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
518271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_WORD_DATA);
519271b33a6SRui Paulo
520271b33a6SRui Paulo if ((error = nfsmb_wait(sc)) == SMB_ENOERR)
521271b33a6SRui Paulo *word = NFSMB_SMBINB(sc, SMB_DATA) |
522271b33a6SRui Paulo (NFSMB_SMBINB(sc, SMB_DATA + 1) << 8);
523271b33a6SRui Paulo
524271b33a6SRui 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));
525271b33a6SRui Paulo NFSMB_UNLOCK(sc);
526271b33a6SRui Paulo
527271b33a6SRui Paulo return (error);
528271b33a6SRui Paulo }
529271b33a6SRui Paulo
530271b33a6SRui Paulo static int
nfsmb_bwrite(device_t dev,u_char slave,char cmd,u_char count,char * buf)531271b33a6SRui Paulo nfsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
532271b33a6SRui Paulo {
533271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
534271b33a6SRui Paulo u_char i;
535271b33a6SRui Paulo int error;
536271b33a6SRui Paulo
537271b33a6SRui Paulo if (count < 1 || count > 32)
538271b33a6SRui Paulo return (SMB_EINVAL);
539271b33a6SRui Paulo
540271b33a6SRui Paulo NFSMB_LOCK(sc);
541271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
542271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_BCNT, count);
543271b33a6SRui Paulo for (i = 0; i < count; i++)
544271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_DATA + i, buf[i]);
545271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
546271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_WRITE | SMB_PRTCL_BLOCK_DATA);
547271b33a6SRui Paulo
548271b33a6SRui Paulo error = nfsmb_wait(sc);
549271b33a6SRui Paulo
550271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
551271b33a6SRui Paulo NFSMB_UNLOCK(sc);
552271b33a6SRui Paulo
553271b33a6SRui Paulo return (error);
554271b33a6SRui Paulo }
555271b33a6SRui Paulo
556271b33a6SRui Paulo static int
nfsmb_bread(device_t dev,u_char slave,char cmd,u_char * count,char * buf)557271b33a6SRui Paulo nfsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
558271b33a6SRui Paulo {
559271b33a6SRui Paulo struct nfsmb_softc *sc = (struct nfsmb_softc *)device_get_softc(dev);
560271b33a6SRui Paulo u_char data, len, i;
561271b33a6SRui Paulo int error;
562271b33a6SRui Paulo
563271b33a6SRui Paulo if (*count < 1 || *count > 32)
564271b33a6SRui Paulo return (SMB_EINVAL);
565271b33a6SRui Paulo
566271b33a6SRui Paulo NFSMB_LOCK(sc);
567271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_CMD, cmd);
568271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_ADDR, slave);
569271b33a6SRui Paulo NFSMB_SMBOUTB(sc, SMB_PRTCL, SMB_PRTCL_READ | SMB_PRTCL_BLOCK_DATA);
570271b33a6SRui Paulo
571271b33a6SRui Paulo if ((error = nfsmb_wait(sc)) == SMB_ENOERR) {
572271b33a6SRui Paulo len = NFSMB_SMBINB(sc, SMB_BCNT);
573271b33a6SRui Paulo for (i = 0; i < len; i++) {
574271b33a6SRui Paulo data = NFSMB_SMBINB(sc, SMB_DATA + i);
575271b33a6SRui Paulo if (i < *count)
576271b33a6SRui Paulo buf[i] = data;
577271b33a6SRui Paulo }
578271b33a6SRui Paulo *count = len;
579271b33a6SRui Paulo }
580271b33a6SRui Paulo
581271b33a6SRui Paulo NFSMB_DEBUG(printf("nfsmb: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, *count, cmd, error));
582271b33a6SRui Paulo NFSMB_UNLOCK(sc);
583271b33a6SRui Paulo
584271b33a6SRui Paulo return (error);
585271b33a6SRui Paulo }
586271b33a6SRui Paulo
587271b33a6SRui Paulo static device_method_t nfsmb_methods[] = {
588271b33a6SRui Paulo /* Device interface */
589271b33a6SRui Paulo DEVMETHOD(device_probe, nfsmb_probe),
590271b33a6SRui Paulo DEVMETHOD(device_attach, nfsmb_attach),
591271b33a6SRui Paulo DEVMETHOD(device_detach, nfsmb_detach),
592271b33a6SRui Paulo
593271b33a6SRui Paulo /* SMBus interface */
594271b33a6SRui Paulo DEVMETHOD(smbus_callback, nfsmb_callback),
595271b33a6SRui Paulo DEVMETHOD(smbus_quick, nfsmb_quick),
596271b33a6SRui Paulo DEVMETHOD(smbus_sendb, nfsmb_sendb),
597271b33a6SRui Paulo DEVMETHOD(smbus_recvb, nfsmb_recvb),
598271b33a6SRui Paulo DEVMETHOD(smbus_writeb, nfsmb_writeb),
599271b33a6SRui Paulo DEVMETHOD(smbus_readb, nfsmb_readb),
600271b33a6SRui Paulo DEVMETHOD(smbus_writew, nfsmb_writew),
601271b33a6SRui Paulo DEVMETHOD(smbus_readw, nfsmb_readw),
602271b33a6SRui Paulo DEVMETHOD(smbus_bwrite, nfsmb_bwrite),
603271b33a6SRui Paulo DEVMETHOD(smbus_bread, nfsmb_bread),
604271b33a6SRui Paulo { 0, 0 }
605271b33a6SRui Paulo };
606271b33a6SRui Paulo
607271b33a6SRui Paulo static device_method_t nfsmbsub_methods[] = {
608271b33a6SRui Paulo /* Device interface */
609271b33a6SRui Paulo DEVMETHOD(device_probe, nfsmbsub_probe),
610271b33a6SRui Paulo DEVMETHOD(device_attach, nfsmbsub_attach),
611271b33a6SRui Paulo DEVMETHOD(device_detach, nfsmbsub_detach),
612271b33a6SRui Paulo
613271b33a6SRui Paulo /* SMBus interface */
614271b33a6SRui Paulo DEVMETHOD(smbus_callback, nfsmb_callback),
615271b33a6SRui Paulo DEVMETHOD(smbus_quick, nfsmb_quick),
616271b33a6SRui Paulo DEVMETHOD(smbus_sendb, nfsmb_sendb),
617271b33a6SRui Paulo DEVMETHOD(smbus_recvb, nfsmb_recvb),
618271b33a6SRui Paulo DEVMETHOD(smbus_writeb, nfsmb_writeb),
619271b33a6SRui Paulo DEVMETHOD(smbus_readb, nfsmb_readb),
620271b33a6SRui Paulo DEVMETHOD(smbus_writew, nfsmb_writew),
621271b33a6SRui Paulo DEVMETHOD(smbus_readw, nfsmb_readw),
622271b33a6SRui Paulo DEVMETHOD(smbus_bwrite, nfsmb_bwrite),
623271b33a6SRui Paulo DEVMETHOD(smbus_bread, nfsmb_bread),
624271b33a6SRui Paulo { 0, 0 }
625271b33a6SRui Paulo };
626271b33a6SRui Paulo
627271b33a6SRui Paulo static driver_t nfsmb_driver = {
628271b33a6SRui Paulo "nfsmb",
629271b33a6SRui Paulo nfsmb_methods,
630271b33a6SRui Paulo sizeof(struct nfsmb_softc),
631271b33a6SRui Paulo };
632271b33a6SRui Paulo
633271b33a6SRui Paulo static driver_t nfsmbsub_driver = {
634271b33a6SRui Paulo "nfsmb",
635271b33a6SRui Paulo nfsmbsub_methods,
636271b33a6SRui Paulo sizeof(struct nfsmb_softc),
637271b33a6SRui Paulo };
638271b33a6SRui Paulo
639bd53cac1SJohn Baldwin DRIVER_MODULE(nfsmb, pci, nfsmb_driver, 0, 0);
640bd53cac1SJohn Baldwin DRIVER_MODULE(nfsmb, nfsmb, nfsmbsub_driver, 0, 0);
641c6d39765SJohn Baldwin DRIVER_MODULE(smbus, nfsmb, smbus_driver, 0, 0);
642271b33a6SRui Paulo
643271b33a6SRui Paulo MODULE_DEPEND(nfsmb, pci, 1, 1, 1);
644271b33a6SRui Paulo MODULE_DEPEND(nfsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
645271b33a6SRui Paulo MODULE_VERSION(nfsmb, 1);
646