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