FreeBSD kernel IICBUS device code
iic.c
Go to the documentation of this file.
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 1998, 2001 Nicolas Souchu
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $FreeBSD$
29 *
30 */
31#include <sys/param.h>
32#include <sys/bus.h>
33#include <sys/conf.h>
34#include <sys/fcntl.h>
35#include <sys/lock.h>
36#include <sys/kernel.h>
37#include <sys/malloc.h>
38#include <sys/module.h>
39#include <sys/sx.h>
40#include <sys/systm.h>
41#include <sys/uio.h>
42#include <sys/errno.h>
43
44#include <dev/iicbus/iiconf.h>
45#include <dev/iicbus/iicbus.h>
46#include <dev/iicbus/iic.h>
47
48#include "iicbus_if.h"
49
50struct iic_softc {
51 device_t sc_dev;
52 struct cdev *sc_devnode;
53};
54
56 struct sx lock;
57 struct iic_softc *sc;
58 bool started;
59 uint8_t addr;
60};
61
62
63#define IIC_LOCK(cdp) sx_xlock(&(cdp)->lock)
64#define IIC_UNLOCK(cdp) sx_xunlock(&(cdp)->lock)
65
66static MALLOC_DEFINE(M_IIC, "iic", "I2C device data");
67
68static int iic_probe(device_t);
69static int iic_attach(device_t);
70static int iic_detach(device_t);
71static void iic_identify(driver_t *driver, device_t parent);
72static void iicdtor(void *data);
73static int iicuio_move(struct iic_cdevpriv *priv, struct uio *uio, int last);
74static int iicuio(struct cdev *dev, struct uio *uio, int ioflag);
75static int iicrdwr(struct iic_cdevpriv *priv, struct iic_rdwr_data *d, int flags);
76
77static devclass_t iic_devclass;
78
79static device_method_t iic_methods[] = {
80 /* device interface */
81 DEVMETHOD(device_identify, iic_identify),
82 DEVMETHOD(device_probe, iic_probe),
83 DEVMETHOD(device_attach, iic_attach),
84 DEVMETHOD(device_detach, iic_detach),
85
86 /* iicbus interface */
88
89 { 0, 0 }
90};
91
92static driver_t iic_driver = {
93 "iic",
95 sizeof(struct iic_softc),
96};
97
98static d_open_t iicopen;
99static d_ioctl_t iicioctl;
100
101static struct cdevsw iic_cdevsw = {
102 .d_version = D_VERSION,
103 .d_open = iicopen,
104 .d_read = iicuio,
105 .d_write = iicuio,
106 .d_ioctl = iicioctl,
107 .d_name = "iic",
108};
109
110static void
111iic_identify(driver_t *driver, device_t parent)
112{
113
114 if (device_find_child(parent, "iic", -1) == NULL)
115 BUS_ADD_CHILD(parent, 0, "iic", -1);
116}
117
118static int
119iic_probe(device_t dev)
120{
121 if (iicbus_get_addr(dev) > 0)
122 return (ENXIO);
123
124 device_set_desc(dev, "I2C generic I/O");
125
126 return (0);
127}
128
129static int
131{
132 struct iic_softc *sc;
133
134 sc = device_get_softc(dev);
135 sc->sc_dev = dev;
136 sc->sc_devnode = make_dev(&iic_cdevsw, device_get_unit(dev),
137 UID_ROOT, GID_WHEEL,
138 0600, "iic%d", device_get_unit(dev));
139 if (sc->sc_devnode == NULL) {
140 device_printf(dev, "failed to create character device\n");
141 return (ENXIO);
142 }
143 sc->sc_devnode->si_drv1 = sc;
144
145 return (0);
146}
147
148static int
150{
151 struct iic_softc *sc;
152
153 sc = device_get_softc(dev);
154
155 if (sc->sc_devnode)
156 destroy_dev(sc->sc_devnode);
157
158 return (0);
159}
160
161static int
162iicopen(struct cdev *dev, int flags, int fmt, struct thread *td)
163{
164 struct iic_cdevpriv *priv;
165 int error;
166
167 priv = malloc(sizeof(*priv), M_IIC, M_WAITOK | M_ZERO);
168
169 sx_init(&priv->lock, "iic");
170 priv->sc = dev->si_drv1;
171
172 error = devfs_set_cdevpriv(priv, iicdtor);
173 if (error != 0)
174 free(priv, M_IIC);
175
176 return (error);
177}
178
179static void
181{
182 device_t iicdev, parent;
183 struct iic_cdevpriv *priv;
184
185 priv = data;
186 KASSERT(priv != NULL, ("iic cdevpriv should not be NULL!"));
187
188 iicdev = priv->sc->sc_dev;
189 parent = device_get_parent(iicdev);
190
191 if (priv->started) {
192 iicbus_stop(parent);
193 iicbus_reset(parent, IIC_UNKNOWN, 0, NULL);
194 iicbus_release_bus(parent, iicdev);
195 }
196
197 sx_destroy(&priv->lock);
198 free(priv, M_IIC);
199}
200
201static int
202iicuio_move(struct iic_cdevpriv *priv, struct uio *uio, int last)
203{
204 device_t parent;
205 int error, num_bytes, transferred_bytes, written_bytes;
206 char buffer[128];
207
208 parent = device_get_parent(priv->sc->sc_dev);
209 error = 0;
210
211 /*
212 * We can only transfer up to sizeof(buffer) bytes in 1 shot, so loop until
213 * everything has been transferred.
214 */
215 while ((error == 0) && (uio->uio_resid > 0)) {
216
217 num_bytes = MIN(uio->uio_resid, sizeof(buffer));
218 transferred_bytes = 0;
219
220 if (uio->uio_rw == UIO_WRITE) {
221 error = uiomove(buffer, num_bytes, uio);
222
223 while ((error == 0) && (transferred_bytes < num_bytes)) {
224 written_bytes = 0;
225 error = iicbus_write(parent, &buffer[transferred_bytes],
226 num_bytes - transferred_bytes, &written_bytes, 0);
227 transferred_bytes += written_bytes;
228 }
229
230 } else if (uio->uio_rw == UIO_READ) {
231 error = iicbus_read(parent, buffer,
232 num_bytes, &transferred_bytes,
233 ((uio->uio_resid <= sizeof(buffer)) ? last : 0), 0);
234 if (error == 0)
235 error = uiomove(buffer, transferred_bytes, uio);
236 }
237 }
238
239 return (error);
240}
241
242static int
243iicuio(struct cdev *dev, struct uio *uio, int ioflag)
244{
245 device_t parent;
246 struct iic_cdevpriv *priv;
247 int error;
248 uint8_t addr;
249
250 priv = NULL;
251 error = devfs_get_cdevpriv((void**)&priv);
252
253 if (error != 0)
254 return (error);
255 KASSERT(priv != NULL, ("iic cdevpriv should not be NULL!"));
256
257 IIC_LOCK(priv);
258 if (priv->started || (priv->addr == 0)) {
259 IIC_UNLOCK(priv);
260 return (ENXIO);
261 }
262 parent = device_get_parent(priv->sc->sc_dev);
263
264 error = iicbus_request_bus(parent, priv->sc->sc_dev,
265 (ioflag & O_NONBLOCK) ? IIC_DONTWAIT : (IIC_WAIT | IIC_INTR));
266 if (error != 0) {
267 IIC_UNLOCK(priv);
268 return (error);
269 }
270
271 if (uio->uio_rw == UIO_READ)
272 addr = priv->addr | LSB;
273 else
274 addr = priv->addr & ~LSB;
275
276 error = iicbus_start(parent, addr, 0);
277 if (error != 0)
278 {
279 iicbus_release_bus(parent, priv->sc->sc_dev);
280 IIC_UNLOCK(priv);
281 return (error);
282 }
283
284 error = iicuio_move(priv, uio, IIC_LAST_READ);
285
286 iicbus_stop(parent);
287 iicbus_release_bus(parent, priv->sc->sc_dev);
288 IIC_UNLOCK(priv);
289 return (error);
290}
291
292static int
293iicrdwr(struct iic_cdevpriv *priv, struct iic_rdwr_data *d, int flags)
294{
295 struct iic_msg *buf, *m;
296 void **usrbufs;
297 device_t iicdev, parent;
298 int error;
299 uint32_t i;
300
301 iicdev = priv->sc->sc_dev;
302 parent = device_get_parent(iicdev);
303 error = 0;
304
305 if (d->nmsgs > IIC_RDRW_MAX_MSGS)
306 return (EINVAL);
307
308 buf = malloc(sizeof(*d->msgs) * d->nmsgs, M_IIC, M_WAITOK);
309
310 error = copyin(d->msgs, buf, sizeof(*d->msgs) * d->nmsgs);
311 if (error != 0) {
312 free(buf, M_IIC);
313 return (error);
314 }
315
316 /* Alloc kernel buffers for userland data, copyin write data */
317 usrbufs = malloc(sizeof(void *) * d->nmsgs, M_IIC, M_WAITOK | M_ZERO);
318
319 for (i = 0; i < d->nmsgs; i++) {
320 m = &(buf[i]);
321 usrbufs[i] = m->buf;
322
323 /*
324 * At least init the buffer to NULL so we can safely free() it later.
325 * If the copyin() to buf failed, don't try to malloc bogus m->len.
326 */
327 m->buf = NULL;
328 if (error != 0)
329 continue;
330
331 /* m->len is uint16_t, so allocation size is capped at 64K. */
332 m->buf = malloc(m->len, M_IIC, M_WAITOK);
333 if (!(m->flags & IIC_M_RD))
334 error = copyin(usrbufs[i], m->buf, m->len);
335 }
336
337 if (error == 0)
338 error = iicbus_request_bus(parent, iicdev,
339 (flags & O_NONBLOCK) ? IIC_DONTWAIT : (IIC_WAIT | IIC_INTR));
340
341 if (error == 0) {
342 error = iicbus_transfer(iicdev, buf, d->nmsgs);
343 iicbus_release_bus(parent, iicdev);
344 }
345
346 /* Copyout all read segments, free up kernel buffers */
347 for (i = 0; i < d->nmsgs; i++) {
348 m = &(buf[i]);
349 if ((error == 0) && (m->flags & IIC_M_RD))
350 error = copyout(m->buf, usrbufs[i], m->len);
351 free(m->buf, M_IIC);
352 }
353
354 free(usrbufs, M_IIC);
355 free(buf, M_IIC);
356 return (error);
357}
358
359static int
360iicioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, struct thread *td)
361{
362 device_t parent, iicdev;
363 struct iiccmd *s;
364 struct uio ubuf;
365 struct iovec uvec;
366 struct iic_cdevpriv *priv;
367 int error;
368
369 s = (struct iiccmd *)data;
370 error = devfs_get_cdevpriv((void**)&priv);
371 if (error != 0)
372 return (error);
373
374 KASSERT(priv != NULL, ("iic cdevpriv should not be NULL!"));
375
376 iicdev = priv->sc->sc_dev;
377 parent = device_get_parent(iicdev);
378 IIC_LOCK(priv);
379
380
381 switch (cmd) {
382 case I2CSTART:
383 if (priv->started) {
384 error = EINVAL;
385 break;
386 }
387 error = iicbus_request_bus(parent, iicdev,
388 (flags & O_NONBLOCK) ? IIC_DONTWAIT : (IIC_WAIT | IIC_INTR));
389
390 if (error == 0)
391 error = iicbus_start(parent, s->slave, 0);
392
393 if (error == 0) {
394 priv->addr = s->slave;
395 priv->started = true;
396 } else
397 iicbus_release_bus(parent, iicdev);
398
399 break;
400
401 case I2CSTOP:
402 if (priv->started) {
403 error = iicbus_stop(parent);
404 iicbus_release_bus(parent, iicdev);
405 priv->started = false;
406 }
407
408 break;
409
410 case I2CRSTCARD:
411 /*
412 * Bus should be owned before we reset it.
413 * We allow the bus to be already owned as the result of an in-progress
414 * sequence; however, bus reset will always be followed by release
415 * (a new start is presumably needed for I/O anyway). */
416 if (!priv->started)
417 error = iicbus_request_bus(parent, iicdev,
418 (flags & O_NONBLOCK) ? IIC_DONTWAIT : (IIC_WAIT | IIC_INTR));
419
420 if (error == 0) {
421 error = iicbus_reset(parent, IIC_UNKNOWN, 0, NULL);
422 /*
423 * Ignore IIC_ENOADDR as it only means we have a master-only
424 * controller.
425 */
426 if (error == IIC_ENOADDR)
427 error = 0;
428
429 iicbus_release_bus(parent, iicdev);
430 priv->started = false;
431 }
432 break;
433
434 case I2CWRITE:
435 if (!priv->started) {
436 error = EINVAL;
437 break;
438 }
439 uvec.iov_base = s->buf;
440 uvec.iov_len = s->count;
441 ubuf.uio_iov = &uvec;
442 ubuf.uio_iovcnt = 1;
443 ubuf.uio_segflg = UIO_USERSPACE;
444 ubuf.uio_td = td;
445 ubuf.uio_resid = s->count;
446 ubuf.uio_offset = 0;
447 ubuf.uio_rw = UIO_WRITE;
448 error = iicuio_move(priv, &ubuf, 0);
449 break;
450
451 case I2CREAD:
452 if (!priv->started) {
453 error = EINVAL;
454 break;
455 }
456 uvec.iov_base = s->buf;
457 uvec.iov_len = s->count;
458 ubuf.uio_iov = &uvec;
459 ubuf.uio_iovcnt = 1;
460 ubuf.uio_segflg = UIO_USERSPACE;
461 ubuf.uio_td = td;
462 ubuf.uio_resid = s->count;
463 ubuf.uio_offset = 0;
464 ubuf.uio_rw = UIO_READ;
465 error = iicuio_move(priv, &ubuf, s->last);
466 break;
467
468 case I2CRDWR:
469 /*
470 * The rdwr list should be a self-contained set of
471 * transactions. Fail if another transaction is in progress.
472 */
473 if (priv->started) {
474 error = EINVAL;
475 break;
476 }
477
478 error = iicrdwr(priv, (struct iic_rdwr_data *)data, flags);
479
480 break;
481
482 case I2CRPTSTART:
483 if (!priv->started) {
484 error = EINVAL;
485 break;
486 }
487 error = iicbus_repeated_start(parent, s->slave, 0);
488 break;
489
490 case I2CSADDR:
491 priv->addr = *((uint8_t*)data);
492 break;
493
494 default:
495 error = ENOTTY;
496 }
497
498 IIC_UNLOCK(priv);
499 return (error);
500}
501
MODULE_DEPEND(iic, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER)
static int iicuio(struct cdev *dev, struct uio *uio, int ioflag)
Definition: iic.c:243
static int iic_attach(device_t)
Definition: iic.c:130
static devclass_t iic_devclass
Definition: iic.c:77
static struct cdevsw iic_cdevsw
Definition: iic.c:101
static driver_t iic_driver
Definition: iic.c:92
static int iic_probe(device_t)
Definition: iic.c:119
static void iic_identify(driver_t *driver, device_t parent)
Definition: iic.c:111
#define IIC_UNLOCK(cdp)
Definition: iic.c:64
DRIVER_MODULE(iic, iicbus, iic_driver, iic_devclass, 0, 0)
#define IIC_LOCK(cdp)
Definition: iic.c:63
static int iicrdwr(struct iic_cdevpriv *priv, struct iic_rdwr_data *d, int flags)
Definition: iic.c:293
static int iic_detach(device_t)
Definition: iic.c:149
static d_open_t iicopen
Definition: iic.c:98
static device_method_t iic_methods[]
Definition: iic.c:79
static void iicdtor(void *data)
Definition: iic.c:180
MODULE_VERSION(iic, 1)
static d_ioctl_t iicioctl
Definition: iic.c:99
static MALLOC_DEFINE(M_IIC, "iic", "I2C device data")
static int iicuio_move(struct iic_cdevpriv *priv, struct uio *uio, int last)
Definition: iic.c:202
#define I2CSTOP
Definition: iic.h:64
#define I2CSTART
Definition: iic.h:63
#define I2CRPTSTART
Definition: iic.h:69
#define I2CRDWR
Definition: iic.h:68
#define IIC_M_RD
Definition: iic.h:42
#define I2CRSTCARD
Definition: iic.h:65
#define I2CREAD
Definition: iic.h:67
#define IIC_RDRW_MAX_MSGS
Definition: iic.h:61
#define I2CWRITE
Definition: iic.h:66
#define I2CSADDR
Definition: iic.h:70
caddr_t data
Definition: iicbb_if.m:61
u_char addr
Definition: iicbb_if.m:116
int iicbus_generic_intr(device_t dev, int event, char *buf)
Definition: iicbus.c:280
char * buf
Definition: iicbus_if.m:55
int last
Definition: iicbus_if.m:104
INTERFACE iicbus
Definition: iicbus_if.m:32
int iicbus_request_bus(device_t bus, device_t dev, int how)
Definition: iiconf.c:138
void iicbus_intr(device_t bus, int event, char *buf)
Definition: iiconf.c:97
int iicbus_transfer(device_t bus, struct iic_msg *msgs, uint32_t nmsgs)
Definition: iiconf.c:442
int iicbus_read(device_t bus, char *buf, int len, int *read, int last, int delay)
Definition: iiconf.c:339
int iicbus_release_bus(device_t bus, device_t dev)
Definition: iiconf.c:206
int iicbus_write(device_t bus, const char *buf, int len, int *sent, int timeout)
Definition: iiconf.c:321
int iicbus_stop(device_t bus)
Definition: iiconf.c:298
int iicbus_repeated_start(device_t bus, u_char slave, int timeout)
Definition: iiconf.c:276
int iicbus_start(device_t bus, u_char slave, int timeout)
Definition: iiconf.c:254
#define IICBUS_MINVER
Definition: iiconf.h:171
#define IIC_ENOADDR
Definition: iiconf.h:116
#define IIC_DONTWAIT
Definition: iiconf.h:44
#define IIC_WAIT
Definition: iiconf.h:46
#define IIC_LAST_READ
Definition: iiconf.h:85
#define LSB
Definition: iiconf.h:39
#define IICBUS_MAXVER
Definition: iiconf.h:172
#define iicbus_reset(bus, speed, addr, oldaddr)
Definition: iiconf.h:135
#define IIC_INTR
Definition: iiconf.h:47
#define IICBUS_PREFVER
Definition: iiconf.h:173
#define IIC_UNKNOWN
Definition: iiconf.h:80
device_t dev
Definition: ofw_iicbus_if.m:38
struct iic_softc * sc
Definition: iic.c:57
uint8_t addr
Definition: iic.c:59
bool started
Definition: iic.c:58
struct sx lock
Definition: iic.c:56
Definition: iic.h:38
uint16_t len
Definition: iic.h:45
uint8_t * buf
Definition: iic.h:46
uint16_t flags
Definition: iic.h:40
struct iic_msg * msgs
Definition: iic.h:57
uint32_t nmsgs
Definition: iic.h:58
Definition: iic.c:50
device_t sc_dev
Definition: iic.c:51
struct cdev * sc_devnode
Definition: iic.c:52
Definition: iic.h:49
int count
Definition: iic.h:51
u_char slave
Definition: iic.h:50
char * buf
Definition: iic.h:53
int last
Definition: iic.h:52