Commit | Line | Data |
---|---|---|
984263bc MD |
1 | /*- |
2 | * Copyright (c) 1998 Nicolas Souchu | |
3 | * All rights reserved. | |
4 | * | |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions | |
7 | * are met: | |
8 | * 1. Redistributions of source code must retain the above copyright | |
9 | * notice, this list of conditions and the following disclaimer. | |
10 | * 2. Redistributions in binary form must reproduce the above copyright | |
11 | * notice, this list of conditions and the following disclaimer in the | |
12 | * documentation and/or other materials provided with the distribution. | |
13 | * | |
14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
24 | * SUCH DAMAGE. | |
25 | * | |
26 | * $FreeBSD: src/sys/dev/smbus/smb.c,v 1.20 1999/11/18 05:44:56 peter Exp $ | |
b13267a5 | 27 | * $DragonFly: src/sys/bus/smbus/smb.c,v 1.9 2006/09/10 01:26:33 dillon Exp $ |
984263bc MD |
28 | * |
29 | */ | |
30 | #include <sys/param.h> | |
31 | #include <sys/kernel.h> | |
32 | #include <sys/systm.h> | |
33 | #include <sys/module.h> | |
34 | #include <sys/bus.h> | |
35 | #include <sys/conf.h> | |
36 | #include <sys/buf.h> | |
37 | #include <sys/uio.h> | |
38 | #include <sys/malloc.h> | |
39 | #include <sys/fcntl.h> | |
40 | ||
41 | #include <machine/clock.h> | |
42 | ||
1f2de5d4 MD |
43 | #include "smbconf.h" |
44 | #include "smbus.h" | |
984263bc MD |
45 | #include <machine/smb.h> |
46 | ||
47 | #include "smbus_if.h" | |
48 | ||
49 | #define BUFSIZE 1024 | |
50 | ||
51 | struct smb_softc { | |
52 | ||
53 | int sc_addr; /* address on smbus */ | |
54 | int sc_count; /* >0 if device opened */ | |
55 | ||
56 | char *sc_cp; /* output buffer pointer */ | |
57 | ||
58 | char sc_buffer[BUFSIZE]; /* output buffer */ | |
59 | char sc_inbuf[BUFSIZE]; /* input buffer */ | |
60 | }; | |
61 | ||
62 | #define IIC_SOFTC(unit) \ | |
63 | ((struct smb_softc *)devclass_get_softc(smb_devclass, (unit))) | |
64 | ||
65 | #define IIC_DEVICE(unit) \ | |
66 | (devclass_get_device(smb_devclass, (unit))) | |
67 | ||
68 | static int smb_probe(device_t); | |
69 | static int smb_attach(device_t); | |
70 | ||
71 | static devclass_t smb_devclass; | |
72 | ||
73 | static device_method_t smb_methods[] = { | |
74 | /* device interface */ | |
75 | DEVMETHOD(device_probe, smb_probe), | |
76 | DEVMETHOD(device_attach, smb_attach), | |
77 | ||
78 | /* smbus interface */ | |
79 | DEVMETHOD(smbus_intr, smbus_generic_intr), | |
80 | ||
81 | { 0, 0 } | |
82 | }; | |
83 | ||
84 | static driver_t smb_driver = { | |
85 | "smb", | |
86 | smb_methods, | |
87 | sizeof(struct smb_softc), | |
88 | }; | |
89 | ||
90 | static d_open_t smbopen; | |
91 | static d_close_t smbclose; | |
92 | static d_write_t smbwrite; | |
93 | static d_read_t smbread; | |
94 | static d_ioctl_t smbioctl; | |
95 | ||
96 | #define CDEV_MAJOR 106 | |
fef8985e MD |
97 | static struct dev_ops smb_ops = { |
98 | { "smb", CDEV_MAJOR, 0 }, | |
99 | .d_open = smbopen, | |
100 | .d_close = smbclose, | |
101 | .d_read = smbread, | |
102 | .d_write = smbwrite, | |
103 | .d_ioctl = smbioctl, | |
984263bc MD |
104 | }; |
105 | ||
106 | /* | |
107 | * smbprobe() | |
108 | */ | |
109 | static int | |
110 | smb_probe(device_t dev) | |
111 | { | |
112 | struct smb_softc *sc = (struct smb_softc *)device_get_softc(dev); | |
113 | ||
114 | sc->sc_addr = smbus_get_addr(dev); | |
115 | ||
116 | /* XXX detect chip with start/stop conditions */ | |
117 | ||
118 | return (0); | |
119 | } | |
120 | ||
121 | /* | |
122 | * smbattach() | |
123 | */ | |
124 | static int | |
125 | smb_attach(device_t dev) | |
126 | { | |
3e82b46c MD |
127 | make_dev(&smb_ops, device_get_unit(dev), |
128 | UID_ROOT, GID_WHEEL, | |
129 | 0600, "smb%d", device_get_unit(dev)); | |
984263bc MD |
130 | return (0); |
131 | } | |
132 | ||
133 | static int | |
fef8985e | 134 | smbopen (struct dev_open_args *ap) |
984263bc | 135 | { |
b13267a5 | 136 | cdev_t dev = ap->a_head.a_dev; |
984263bc MD |
137 | struct smb_softc *sc = IIC_SOFTC(minor(dev)); |
138 | ||
139 | if (!sc) | |
140 | return (EINVAL); | |
141 | ||
142 | if (sc->sc_count) | |
143 | return (EBUSY); | |
144 | ||
145 | sc->sc_count++; | |
146 | ||
147 | return (0); | |
148 | } | |
149 | ||
150 | static int | |
fef8985e | 151 | smbclose(struct dev_close_args *ap) |
984263bc | 152 | { |
b13267a5 | 153 | cdev_t dev = ap->a_head.a_dev; |
984263bc MD |
154 | struct smb_softc *sc = IIC_SOFTC(minor(dev)); |
155 | ||
156 | if (!sc) | |
157 | return (EINVAL); | |
158 | ||
159 | if (!sc->sc_count) | |
160 | return (EINVAL); | |
161 | ||
162 | sc->sc_count--; | |
163 | ||
164 | return (0); | |
165 | } | |
166 | ||
167 | static int | |
fef8985e | 168 | smbwrite(struct dev_write_args *ap) |
984263bc | 169 | { |
984263bc MD |
170 | return (EINVAL); |
171 | } | |
172 | ||
173 | static int | |
fef8985e | 174 | smbread(struct dev_read_args *ap) |
984263bc | 175 | { |
984263bc MD |
176 | return (EINVAL); |
177 | } | |
178 | ||
179 | static int | |
fef8985e | 180 | smbioctl(struct dev_ioctl_args *ap) |
984263bc | 181 | { |
b13267a5 | 182 | cdev_t dev = ap->a_head.a_dev; |
984263bc MD |
183 | device_t smbdev = IIC_DEVICE(minor(dev)); |
184 | struct smb_softc *sc = IIC_SOFTC(minor(dev)); | |
185 | device_t parent = device_get_parent(smbdev); | |
186 | ||
187 | int error = 0; | |
fef8985e | 188 | struct smbcmd *s = (struct smbcmd *)ap->a_data; |
984263bc MD |
189 | |
190 | if (!sc || !s) | |
191 | return (EINVAL); | |
192 | ||
193 | /* allocate the bus */ | |
194 | if ((error = smbus_request_bus(parent, smbdev, | |
fef8985e | 195 | (ap->a_fflag & O_NONBLOCK) ? SMB_DONTWAIT : (SMB_WAIT | SMB_INTR)))) |
984263bc MD |
196 | return (error); |
197 | ||
fef8985e | 198 | switch (ap->a_cmd) { |
984263bc MD |
199 | case SMB_QUICK_WRITE: |
200 | error = smbus_error(smbus_quick(parent, s->slave, SMB_QWRITE)); | |
201 | break; | |
202 | ||
203 | case SMB_QUICK_READ: | |
204 | error = smbus_error(smbus_quick(parent, s->slave, SMB_QREAD)); | |
205 | break; | |
206 | ||
207 | case SMB_SENDB: | |
208 | error = smbus_error(smbus_sendb(parent, s->slave, s->cmd)); | |
209 | break; | |
210 | ||
211 | case SMB_RECVB: | |
212 | error = smbus_error(smbus_recvb(parent, s->slave, &s->cmd)); | |
213 | break; | |
214 | ||
215 | case SMB_WRITEB: | |
216 | error = smbus_error(smbus_writeb(parent, s->slave, s->cmd, | |
217 | s->data.byte)); | |
218 | break; | |
219 | ||
220 | case SMB_WRITEW: | |
221 | error = smbus_error(smbus_writew(parent, s->slave, | |
222 | s->cmd, s->data.word)); | |
223 | break; | |
224 | ||
225 | case SMB_READB: | |
226 | if (s->data.byte_ptr) | |
227 | error = smbus_error(smbus_readb(parent, s->slave, | |
228 | s->cmd, s->data.byte_ptr)); | |
229 | break; | |
230 | ||
231 | case SMB_READW: | |
232 | if (s->data.word_ptr) | |
233 | error = smbus_error(smbus_readw(parent, s->slave, | |
234 | s->cmd, s->data.word_ptr)); | |
235 | break; | |
236 | ||
237 | case SMB_PCALL: | |
238 | if (s->data.process.rdata) | |
239 | error = smbus_error(smbus_pcall(parent, s->slave, s->cmd, | |
240 | s->data.process.sdata, s->data.process.rdata)); | |
241 | break; | |
242 | ||
243 | case SMB_BWRITE: | |
244 | if (s->count && s->data.byte_ptr) | |
245 | error = smbus_error(smbus_bwrite(parent, s->slave, | |
246 | s->cmd, s->count, s->data.byte_ptr)); | |
247 | break; | |
248 | ||
249 | case SMB_BREAD: | |
250 | if (s->count && s->data.byte_ptr) | |
251 | error = smbus_error(smbus_bread(parent, s->slave, | |
252 | s->cmd, s->count, s->data.byte_ptr)); | |
253 | break; | |
254 | ||
255 | default: | |
256 | error = ENODEV; | |
257 | } | |
258 | ||
259 | /* release the bus */ | |
260 | smbus_release_bus(parent, smbdev); | |
261 | ||
262 | return (error); | |
263 | } | |
264 | ||
265 | DRIVER_MODULE(smb, smbus, smb_driver, smb_devclass, 0, 0); |