1*6ba12bf3SMatthew Dillon /*-
2*6ba12bf3SMatthew Dillon * Copyright (c) 1998, 2001 Nicolas Souchu
3*6ba12bf3SMatthew Dillon * All rights reserved.
4*6ba12bf3SMatthew Dillon *
5*6ba12bf3SMatthew Dillon * Redistribution and use in source and binary forms, with or without
6*6ba12bf3SMatthew Dillon * modification, are permitted provided that the following conditions
7*6ba12bf3SMatthew Dillon * are met:
8*6ba12bf3SMatthew Dillon * 1. Redistributions of source code must retain the above copyright
9*6ba12bf3SMatthew Dillon * notice, this list of conditions and the following disclaimer.
10*6ba12bf3SMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright
11*6ba12bf3SMatthew Dillon * notice, this list of conditions and the following disclaimer in the
12*6ba12bf3SMatthew Dillon * documentation and/or other materials provided with the distribution.
13*6ba12bf3SMatthew Dillon *
14*6ba12bf3SMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*6ba12bf3SMatthew Dillon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*6ba12bf3SMatthew Dillon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*6ba12bf3SMatthew Dillon * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*6ba12bf3SMatthew Dillon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*6ba12bf3SMatthew Dillon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*6ba12bf3SMatthew Dillon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*6ba12bf3SMatthew Dillon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*6ba12bf3SMatthew Dillon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*6ba12bf3SMatthew Dillon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*6ba12bf3SMatthew Dillon * SUCH DAMAGE.
25*6ba12bf3SMatthew Dillon *
26*6ba12bf3SMatthew Dillon * $FreeBSD: src/sys/dev/smbus/smb.c,v 1.34.8.2 2006/09/22 19:19:16 jhb Exp $
27*6ba12bf3SMatthew Dillon *
28*6ba12bf3SMatthew Dillon */
29*6ba12bf3SMatthew Dillon
30*6ba12bf3SMatthew Dillon #include <sys/param.h>
31*6ba12bf3SMatthew Dillon #include <sys/kernel.h>
32*6ba12bf3SMatthew Dillon #include <sys/systm.h>
33*6ba12bf3SMatthew Dillon #include <sys/device.h>
34*6ba12bf3SMatthew Dillon #include <sys/module.h>
35*6ba12bf3SMatthew Dillon #include <sys/bus.h>
36*6ba12bf3SMatthew Dillon #include <sys/conf.h>
37*6ba12bf3SMatthew Dillon #include <sys/uio.h>
38*6ba12bf3SMatthew Dillon #include <sys/fcntl.h>
39*6ba12bf3SMatthew Dillon
40*6ba12bf3SMatthew Dillon #include <bus/smbus/smbconf.h>
41*6ba12bf3SMatthew Dillon #include <bus/smbus/smbus.h>
42*6ba12bf3SMatthew Dillon #include "smb.h"
43*6ba12bf3SMatthew Dillon
44*6ba12bf3SMatthew Dillon #include "smbus_if.h"
45*6ba12bf3SMatthew Dillon
46*6ba12bf3SMatthew Dillon #define BUFSIZE 1024
47*6ba12bf3SMatthew Dillon
48*6ba12bf3SMatthew Dillon struct smb_softc {
49*6ba12bf3SMatthew Dillon device_t sc_dev;
50*6ba12bf3SMatthew Dillon int sc_count; /* >0 if device opened */
51*6ba12bf3SMatthew Dillon int sc_unit;
52*6ba12bf3SMatthew Dillon cdev_t sc_devnode;
53*6ba12bf3SMatthew Dillon };
54*6ba12bf3SMatthew Dillon
55*6ba12bf3SMatthew Dillon #define SMB_SOFTC(unit) \
56*6ba12bf3SMatthew Dillon ((struct smb_softc *)devclass_get_softc(smb_devclass, (unit)))
57*6ba12bf3SMatthew Dillon
58*6ba12bf3SMatthew Dillon #define SMB_DEVICE(unit) \
59*6ba12bf3SMatthew Dillon (devclass_get_device(smb_devclass, (unit)))
60*6ba12bf3SMatthew Dillon
61*6ba12bf3SMatthew Dillon static void smb_identify(driver_t *driver, device_t parent);
62*6ba12bf3SMatthew Dillon static int smb_probe(device_t);
63*6ba12bf3SMatthew Dillon static int smb_attach(device_t);
64*6ba12bf3SMatthew Dillon static int smb_detach(device_t);
65*6ba12bf3SMatthew Dillon
66*6ba12bf3SMatthew Dillon static devclass_t smb_devclass;
67*6ba12bf3SMatthew Dillon
68*6ba12bf3SMatthew Dillon static device_method_t smb_methods[] = {
69*6ba12bf3SMatthew Dillon /* device interface */
70*6ba12bf3SMatthew Dillon DEVMETHOD(device_identify, smb_identify),
71*6ba12bf3SMatthew Dillon DEVMETHOD(device_probe, smb_probe),
72*6ba12bf3SMatthew Dillon DEVMETHOD(device_attach, smb_attach),
73*6ba12bf3SMatthew Dillon DEVMETHOD(device_detach, smb_detach),
74*6ba12bf3SMatthew Dillon
75*6ba12bf3SMatthew Dillon #if 0
76*6ba12bf3SMatthew Dillon /* bus interface */
77*6ba12bf3SMatthew Dillon DEVMETHOD(bus_driver_added, bus_generic_driver_added),
78*6ba12bf3SMatthew Dillon DEVMETHOD(bus_print_child, bus_generic_print_child),
79*6ba12bf3SMatthew Dillon #endif
80*6ba12bf3SMatthew Dillon
81*6ba12bf3SMatthew Dillon /* smbus interface */
82*6ba12bf3SMatthew Dillon DEVMETHOD(smbus_intr, smbus_generic_intr),
83*6ba12bf3SMatthew Dillon
84*6ba12bf3SMatthew Dillon DEVMETHOD_END
85*6ba12bf3SMatthew Dillon };
86*6ba12bf3SMatthew Dillon
87*6ba12bf3SMatthew Dillon static driver_t smb_driver = {
88*6ba12bf3SMatthew Dillon "smb",
89*6ba12bf3SMatthew Dillon smb_methods,
90*6ba12bf3SMatthew Dillon sizeof(struct smb_softc),
91*6ba12bf3SMatthew Dillon };
92*6ba12bf3SMatthew Dillon
93*6ba12bf3SMatthew Dillon static d_open_t smbopen;
94*6ba12bf3SMatthew Dillon static d_close_t smbclose;
95*6ba12bf3SMatthew Dillon static d_ioctl_t smbioctl;
96*6ba12bf3SMatthew Dillon
97*6ba12bf3SMatthew Dillon static struct dev_ops smb_ops = {
98*6ba12bf3SMatthew Dillon { "smb", 0, 0 },
99*6ba12bf3SMatthew Dillon .d_open = smbopen,
100*6ba12bf3SMatthew Dillon .d_close = smbclose,
101*6ba12bf3SMatthew Dillon .d_ioctl = smbioctl,
102*6ba12bf3SMatthew Dillon };
103*6ba12bf3SMatthew Dillon
104*6ba12bf3SMatthew Dillon static void
smb_identify(driver_t * driver,device_t parent)105*6ba12bf3SMatthew Dillon smb_identify(driver_t *driver, device_t parent)
106*6ba12bf3SMatthew Dillon {
107*6ba12bf3SMatthew Dillon if (device_find_child(parent, "smb", -1) == NULL)
108*6ba12bf3SMatthew Dillon BUS_ADD_CHILD(parent, parent, 0, "smb", -1);
109*6ba12bf3SMatthew Dillon }
110*6ba12bf3SMatthew Dillon
111*6ba12bf3SMatthew Dillon static int
smb_probe(device_t dev)112*6ba12bf3SMatthew Dillon smb_probe(device_t dev)
113*6ba12bf3SMatthew Dillon {
114*6ba12bf3SMatthew Dillon device_set_desc(dev, "SMBus generic I/O");
115*6ba12bf3SMatthew Dillon
116*6ba12bf3SMatthew Dillon /* Allow other subclasses to override this driver. */
117*6ba12bf3SMatthew Dillon return (BUS_PROBE_GENERIC);
118*6ba12bf3SMatthew Dillon }
119*6ba12bf3SMatthew Dillon
120*6ba12bf3SMatthew Dillon static int
smb_attach(device_t dev)121*6ba12bf3SMatthew Dillon smb_attach(device_t dev)
122*6ba12bf3SMatthew Dillon {
123*6ba12bf3SMatthew Dillon struct smb_softc *sc = (struct smb_softc *)device_get_softc(dev);
124*6ba12bf3SMatthew Dillon int unit;
125*6ba12bf3SMatthew Dillon
126*6ba12bf3SMatthew Dillon if (!sc)
127*6ba12bf3SMatthew Dillon return (ENOMEM);
128*6ba12bf3SMatthew Dillon
129*6ba12bf3SMatthew Dillon bzero(sc, sizeof(struct smb_softc *));
130*6ba12bf3SMatthew Dillon unit = device_get_unit(dev);
131*6ba12bf3SMatthew Dillon sc->sc_dev = dev;
132*6ba12bf3SMatthew Dillon sc->sc_unit = unit;
133*6ba12bf3SMatthew Dillon
134*6ba12bf3SMatthew Dillon if (unit & 0x0400) {
135*6ba12bf3SMatthew Dillon sc->sc_devnode = make_dev(&smb_ops, unit,
136*6ba12bf3SMatthew Dillon UID_ROOT, GID_WHEEL, 0600,
137*6ba12bf3SMatthew Dillon "smb%d-%02x", unit >> 11, unit & 1023);
138*6ba12bf3SMatthew Dillon } else {
139*6ba12bf3SMatthew Dillon sc->sc_devnode = make_dev(&smb_ops, unit,
140*6ba12bf3SMatthew Dillon UID_ROOT, GID_WHEEL, 0600, "smb%d", unit);
141*6ba12bf3SMatthew Dillon }
142*6ba12bf3SMatthew Dillon
143*6ba12bf3SMatthew Dillon return (0);
144*6ba12bf3SMatthew Dillon }
145*6ba12bf3SMatthew Dillon
146*6ba12bf3SMatthew Dillon static int
smb_detach(device_t dev)147*6ba12bf3SMatthew Dillon smb_detach(device_t dev)
148*6ba12bf3SMatthew Dillon {
149*6ba12bf3SMatthew Dillon struct smb_softc *sc = (struct smb_softc *)device_get_softc(dev);
150*6ba12bf3SMatthew Dillon
151*6ba12bf3SMatthew Dillon if (sc->sc_devnode)
152*6ba12bf3SMatthew Dillon dev_ops_remove_minor(&smb_ops, device_get_unit(dev));
153*6ba12bf3SMatthew Dillon
154*6ba12bf3SMatthew Dillon return (0);
155*6ba12bf3SMatthew Dillon }
156*6ba12bf3SMatthew Dillon
157*6ba12bf3SMatthew Dillon static int
smbopen(struct dev_open_args * ap)158*6ba12bf3SMatthew Dillon smbopen (struct dev_open_args *ap)
159*6ba12bf3SMatthew Dillon {
160*6ba12bf3SMatthew Dillon cdev_t dev = ap->a_head.a_dev;
161*6ba12bf3SMatthew Dillon struct smb_softc *sc = SMB_SOFTC(minor(dev));
162*6ba12bf3SMatthew Dillon
163*6ba12bf3SMatthew Dillon if (sc == NULL)
164*6ba12bf3SMatthew Dillon return (ENXIO);
165*6ba12bf3SMatthew Dillon
166*6ba12bf3SMatthew Dillon if (sc->sc_count != 0)
167*6ba12bf3SMatthew Dillon return (EBUSY);
168*6ba12bf3SMatthew Dillon
169*6ba12bf3SMatthew Dillon sc->sc_count++;
170*6ba12bf3SMatthew Dillon
171*6ba12bf3SMatthew Dillon return (0);
172*6ba12bf3SMatthew Dillon }
173*6ba12bf3SMatthew Dillon
174*6ba12bf3SMatthew Dillon static int
smbclose(struct dev_close_args * ap)175*6ba12bf3SMatthew Dillon smbclose(struct dev_close_args *ap)
176*6ba12bf3SMatthew Dillon {
177*6ba12bf3SMatthew Dillon cdev_t dev = ap->a_head.a_dev;
178*6ba12bf3SMatthew Dillon struct smb_softc *sc = SMB_SOFTC(minor(dev));
179*6ba12bf3SMatthew Dillon
180*6ba12bf3SMatthew Dillon if (sc == NULL)
181*6ba12bf3SMatthew Dillon return (ENXIO);
182*6ba12bf3SMatthew Dillon
183*6ba12bf3SMatthew Dillon if (sc->sc_count == 0)
184*6ba12bf3SMatthew Dillon /* This is not supposed to happen. */
185*6ba12bf3SMatthew Dillon return (0);
186*6ba12bf3SMatthew Dillon
187*6ba12bf3SMatthew Dillon sc->sc_count--;
188*6ba12bf3SMatthew Dillon
189*6ba12bf3SMatthew Dillon return (0);
190*6ba12bf3SMatthew Dillon }
191*6ba12bf3SMatthew Dillon
192*6ba12bf3SMatthew Dillon #if 0
193*6ba12bf3SMatthew Dillon static int
194*6ba12bf3SMatthew Dillon smbwrite(struct dev_write_args *ap)
195*6ba12bf3SMatthew Dillon {
196*6ba12bf3SMatthew Dillon return (EINVAL);
197*6ba12bf3SMatthew Dillon }
198*6ba12bf3SMatthew Dillon
199*6ba12bf3SMatthew Dillon static int
200*6ba12bf3SMatthew Dillon smbread(struct dev_read_args *ap)
201*6ba12bf3SMatthew Dillon {
202*6ba12bf3SMatthew Dillon return (EINVAL);
203*6ba12bf3SMatthew Dillon }
204*6ba12bf3SMatthew Dillon #endif
205*6ba12bf3SMatthew Dillon
206*6ba12bf3SMatthew Dillon static int
smbioctl(struct dev_ioctl_args * ap)207*6ba12bf3SMatthew Dillon smbioctl(struct dev_ioctl_args *ap)
208*6ba12bf3SMatthew Dillon {
209*6ba12bf3SMatthew Dillon cdev_t dev = ap->a_head.a_dev;
210*6ba12bf3SMatthew Dillon device_t bus; /* smbbus */
211*6ba12bf3SMatthew Dillon char buf[SMB_MAXBLOCKSIZE];
212*6ba12bf3SMatthew Dillon struct smbcmd *s = (struct smbcmd *)ap->a_data;
213*6ba12bf3SMatthew Dillon struct smb_softc *sc = SMB_SOFTC(minor(dev));
214*6ba12bf3SMatthew Dillon device_t smbdev = SMB_DEVICE(minor(dev));
215*6ba12bf3SMatthew Dillon int error;
216*6ba12bf3SMatthew Dillon int unit;
217*6ba12bf3SMatthew Dillon u_char bcount;
218*6ba12bf3SMatthew Dillon
219*6ba12bf3SMatthew Dillon if (sc == NULL)
220*6ba12bf3SMatthew Dillon return (ENXIO);
221*6ba12bf3SMatthew Dillon if (s == NULL)
222*6ba12bf3SMatthew Dillon return (EINVAL);
223*6ba12bf3SMatthew Dillon
224*6ba12bf3SMatthew Dillon /*
225*6ba12bf3SMatthew Dillon * If a specific slave device is being used, override any passed-in
226*6ba12bf3SMatthew Dillon * slave.
227*6ba12bf3SMatthew Dillon */
228*6ba12bf3SMatthew Dillon unit = sc->sc_unit;
229*6ba12bf3SMatthew Dillon if (unit & 0x0400) {
230*6ba12bf3SMatthew Dillon s->slave = unit & 1023;
231*6ba12bf3SMatthew Dillon }
232*6ba12bf3SMatthew Dillon
233*6ba12bf3SMatthew Dillon /*
234*6ba12bf3SMatthew Dillon * NOTE: smbus_*() functions automatically recurse the parent to
235*6ba12bf3SMatthew Dillon * get to the actual device driver.
236*6ba12bf3SMatthew Dillon */
237*6ba12bf3SMatthew Dillon bus = device_get_parent(smbdev); /* smbus */
238*6ba12bf3SMatthew Dillon
239*6ba12bf3SMatthew Dillon /* Allocate the bus. */
240*6ba12bf3SMatthew Dillon if ((error = smbus_request_bus(bus, smbdev,
241*6ba12bf3SMatthew Dillon (ap->a_fflag & O_NONBLOCK) ?
242*6ba12bf3SMatthew Dillon SMB_DONTWAIT : (SMB_WAIT | SMB_INTR))))
243*6ba12bf3SMatthew Dillon return (error);
244*6ba12bf3SMatthew Dillon
245*6ba12bf3SMatthew Dillon switch (ap->a_cmd) {
246*6ba12bf3SMatthew Dillon case SMB_QUICK_WRITE:
247*6ba12bf3SMatthew Dillon error = smbus_error(smbus_quick(bus, s->slave, SMB_QWRITE));
248*6ba12bf3SMatthew Dillon break;
249*6ba12bf3SMatthew Dillon
250*6ba12bf3SMatthew Dillon case SMB_QUICK_READ:
251*6ba12bf3SMatthew Dillon error = smbus_error(smbus_quick(bus, s->slave, SMB_QREAD));
252*6ba12bf3SMatthew Dillon break;
253*6ba12bf3SMatthew Dillon
254*6ba12bf3SMatthew Dillon case SMB_SENDB:
255*6ba12bf3SMatthew Dillon error = smbus_error(smbus_sendb(bus, s->slave, s->cmd));
256*6ba12bf3SMatthew Dillon break;
257*6ba12bf3SMatthew Dillon
258*6ba12bf3SMatthew Dillon case SMB_RECVB:
259*6ba12bf3SMatthew Dillon error = smbus_error(smbus_recvb(bus, s->slave, &s->cmd));
260*6ba12bf3SMatthew Dillon break;
261*6ba12bf3SMatthew Dillon
262*6ba12bf3SMatthew Dillon case SMB_WRITEB:
263*6ba12bf3SMatthew Dillon error = smbus_error(smbus_writeb(bus, s->slave, s->cmd,
264*6ba12bf3SMatthew Dillon s->wdata.byte));
265*6ba12bf3SMatthew Dillon break;
266*6ba12bf3SMatthew Dillon
267*6ba12bf3SMatthew Dillon case SMB_WRITEW:
268*6ba12bf3SMatthew Dillon error = smbus_error(smbus_writew(bus, s->slave, s->cmd,
269*6ba12bf3SMatthew Dillon s->wdata.word));
270*6ba12bf3SMatthew Dillon break;
271*6ba12bf3SMatthew Dillon
272*6ba12bf3SMatthew Dillon case SMB_READB:
273*6ba12bf3SMatthew Dillon error = smbus_error(smbus_readb(bus, s->slave, s->cmd,
274*6ba12bf3SMatthew Dillon &s->rdata.byte));
275*6ba12bf3SMatthew Dillon if (s->rbuf && s->rcount >= 1) {
276*6ba12bf3SMatthew Dillon error = copyout(&s->rdata.byte, s->rbuf, 1);
277*6ba12bf3SMatthew Dillon s->rcount = 1;
278*6ba12bf3SMatthew Dillon }
279*6ba12bf3SMatthew Dillon break;
280*6ba12bf3SMatthew Dillon
281*6ba12bf3SMatthew Dillon case SMB_READW:
282*6ba12bf3SMatthew Dillon error = smbus_error(smbus_readw(bus, s->slave, s->cmd,
283*6ba12bf3SMatthew Dillon &s->rdata.word));
284*6ba12bf3SMatthew Dillon if (s->rbuf && s->rcount >= 2) {
285*6ba12bf3SMatthew Dillon buf[0] = (u_char)s->rdata.word;
286*6ba12bf3SMatthew Dillon buf[1] = (u_char)(s->rdata.word >> 8);
287*6ba12bf3SMatthew Dillon error = copyout(buf, s->rbuf, 2);
288*6ba12bf3SMatthew Dillon s->rcount = 2;
289*6ba12bf3SMatthew Dillon }
290*6ba12bf3SMatthew Dillon break;
291*6ba12bf3SMatthew Dillon
292*6ba12bf3SMatthew Dillon case SMB_PCALL:
293*6ba12bf3SMatthew Dillon error = smbus_error(smbus_pcall(bus, s->slave, s->cmd,
294*6ba12bf3SMatthew Dillon s->wdata.word, &s->rdata.word));
295*6ba12bf3SMatthew Dillon if (s->rbuf && s->rcount >= 2) {
296*6ba12bf3SMatthew Dillon char buf[2];
297*6ba12bf3SMatthew Dillon buf[0] = (u_char)s->rdata.word;
298*6ba12bf3SMatthew Dillon buf[1] = (u_char)(s->rdata.word >> 8);
299*6ba12bf3SMatthew Dillon error = copyout(buf, s->rbuf, 2);
300*6ba12bf3SMatthew Dillon s->rcount = 2;
301*6ba12bf3SMatthew Dillon }
302*6ba12bf3SMatthew Dillon
303*6ba12bf3SMatthew Dillon break;
304*6ba12bf3SMatthew Dillon
305*6ba12bf3SMatthew Dillon case SMB_BWRITE:
306*6ba12bf3SMatthew Dillon if (s->wcount < 0)
307*6ba12bf3SMatthew Dillon s->wcount = 0;
308*6ba12bf3SMatthew Dillon if (s->wcount > SMB_MAXBLOCKSIZE)
309*6ba12bf3SMatthew Dillon s->wcount = SMB_MAXBLOCKSIZE;
310*6ba12bf3SMatthew Dillon if (s->wcount)
311*6ba12bf3SMatthew Dillon error = copyin(s->wbuf, buf, s->wcount);
312*6ba12bf3SMatthew Dillon if (error)
313*6ba12bf3SMatthew Dillon break;
314*6ba12bf3SMatthew Dillon error = smbus_error(smbus_bwrite(bus, s->slave, s->cmd,
315*6ba12bf3SMatthew Dillon s->wcount, buf));
316*6ba12bf3SMatthew Dillon break;
317*6ba12bf3SMatthew Dillon
318*6ba12bf3SMatthew Dillon case SMB_BREAD:
319*6ba12bf3SMatthew Dillon if (s->rcount < 0)
320*6ba12bf3SMatthew Dillon s->rcount = 0;
321*6ba12bf3SMatthew Dillon if (s->rcount > SMB_MAXBLOCKSIZE)
322*6ba12bf3SMatthew Dillon s->rcount = SMB_MAXBLOCKSIZE;
323*6ba12bf3SMatthew Dillon error = smbus_bread(bus, s->slave, s->cmd, &bcount, buf);
324*6ba12bf3SMatthew Dillon error = smbus_error(error);
325*6ba12bf3SMatthew Dillon if (error)
326*6ba12bf3SMatthew Dillon break;
327*6ba12bf3SMatthew Dillon if (s->rcount > bcount)
328*6ba12bf3SMatthew Dillon s->rcount = bcount;
329*6ba12bf3SMatthew Dillon error = copyout(buf, s->rbuf, s->rcount);
330*6ba12bf3SMatthew Dillon break;
331*6ba12bf3SMatthew Dillon
332*6ba12bf3SMatthew Dillon case SMB_TRANS:
333*6ba12bf3SMatthew Dillon if (s->rcount < 0)
334*6ba12bf3SMatthew Dillon s->rcount = 0;
335*6ba12bf3SMatthew Dillon if (s->rcount > SMB_MAXBLOCKSIZE)
336*6ba12bf3SMatthew Dillon s->rcount = SMB_MAXBLOCKSIZE;
337*6ba12bf3SMatthew Dillon if (s->wcount < 0)
338*6ba12bf3SMatthew Dillon s->wcount = 0;
339*6ba12bf3SMatthew Dillon if (s->wcount > SMB_MAXBLOCKSIZE)
340*6ba12bf3SMatthew Dillon s->wcount = SMB_MAXBLOCKSIZE;
341*6ba12bf3SMatthew Dillon if (s->wcount)
342*6ba12bf3SMatthew Dillon error = copyin(s->wbuf, buf, s->wcount);
343*6ba12bf3SMatthew Dillon if (error)
344*6ba12bf3SMatthew Dillon break;
345*6ba12bf3SMatthew Dillon error = smbus_trans(bus, s->slave, s->cmd, s->op,
346*6ba12bf3SMatthew Dillon buf, s->wcount, buf, s->rcount, &s->rcount);
347*6ba12bf3SMatthew Dillon error = smbus_error(error);
348*6ba12bf3SMatthew Dillon if (error == 0)
349*6ba12bf3SMatthew Dillon error = copyout(buf, s->rbuf, s->rcount);
350*6ba12bf3SMatthew Dillon break;
351*6ba12bf3SMatthew Dillon default:
352*6ba12bf3SMatthew Dillon error = ENOTTY;
353*6ba12bf3SMatthew Dillon break;
354*6ba12bf3SMatthew Dillon }
355*6ba12bf3SMatthew Dillon
356*6ba12bf3SMatthew Dillon smbus_release_bus(bus, smbdev);
357*6ba12bf3SMatthew Dillon
358*6ba12bf3SMatthew Dillon return (error);
359*6ba12bf3SMatthew Dillon }
360*6ba12bf3SMatthew Dillon
361*6ba12bf3SMatthew Dillon DRIVER_MODULE(smb, smbus, smb_driver, smb_devclass, NULL, NULL);
362*6ba12bf3SMatthew Dillon MODULE_DEPEND(smb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
363*6ba12bf3SMatthew Dillon MODULE_VERSION(smb, 1);
364