FreeBSD kernel IICBUS device code
if_ic.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
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32/*
33 * I2C bus IP driver
34 */
35
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/mbuf.h>
39#include <sys/socket.h>
40#include <sys/filio.h>
41#include <sys/sockio.h>
42#include <sys/kernel.h>
43#include <sys/lock.h>
44#include <sys/module.h>
45#include <sys/mutex.h>
46#include <sys/bus.h>
47#include <sys/time.h>
48#include <sys/malloc.h>
49
50#include <net/if.h>
51#include <net/if_var.h>
52#include <net/if_types.h>
53#include <net/netisr.h>
54
55#include <net/route.h>
56#include <netinet/in.h>
57#include <netinet/in_systm.h>
58#include <netinet/in_var.h>
59#include <netinet/ip.h>
60#include <netinet/if_ether.h>
61
62#include <net/bpf.h>
63
64#include <dev/iicbus/iiconf.h>
65#include <dev/iicbus/iicbus.h>
66
67#include "iicbus_if.h"
68
69#define PCF_MASTER_ADDRESS 0xaa
70
71#define ICHDRLEN sizeof(u_int32_t)
72#define ICMTU 1500 /* default mtu */
73
74struct ic_softc {
75 struct ifnet *ic_ifp;
76 device_t ic_dev;
77
78 u_char ic_addr; /* peer I2C address */
79
81
82 char *ic_obuf;
83 char *ic_ifbuf;
84 char *ic_cp;
85
87
89
90 struct mtx ic_lock;
91};
92
93#define IC_SENDING 0x0001
94#define IC_OBUF_BUSY 0x0002
95#define IC_IFBUF_BUSY 0x0004
96#define IC_BUFFERS_BUSY (IC_OBUF_BUSY | IC_IFBUF_BUSY)
97#define IC_BUFFER_WAITER 0x0004
98
99static devclass_t ic_devclass;
100
101static int icprobe(device_t);
102static int icattach(device_t);
103
104static int icioctl(struct ifnet *, u_long, caddr_t);
105static int icoutput(struct ifnet *, struct mbuf *, const struct sockaddr *,
106 struct route *);
107
108static int icintr(device_t, int, char *);
109
110static device_method_t ic_methods[] = {
111 /* device interface */
112 DEVMETHOD(device_probe, icprobe),
113 DEVMETHOD(device_attach, icattach),
114
115 /* iicbus interface */
116 DEVMETHOD(iicbus_intr, icintr),
117
118 { 0, 0 }
119};
120
121static driver_t ic_driver = {
122 "ic",
124 sizeof(struct ic_softc),
125};
126
127static void
128ic_alloc_buffers(struct ic_softc *sc, int mtu)
129{
130 char *obuf, *ifbuf;
131
132 obuf = malloc(mtu + ICHDRLEN, M_DEVBUF, M_WAITOK);
133 ifbuf = malloc(mtu + ICHDRLEN, M_DEVBUF, M_WAITOK);
134
135 mtx_lock(&sc->ic_lock);
136 while (sc->ic_flags & IC_BUFFERS_BUSY) {
138 mtx_sleep(sc, &sc->ic_lock, 0, "icalloc", 0);
139 sc->ic_flags &= ~IC_BUFFER_WAITER;
140 }
141
142 free(sc->ic_obuf, M_DEVBUF);
143 free(sc->ic_ifbuf, M_DEVBUF);
144 sc->ic_obuf = obuf;
145 sc->ic_ifbuf = ifbuf;
146 sc->ic_ifp->if_mtu = mtu;
147 mtx_unlock(&sc->ic_lock);
148}
149
150/*
151 * icprobe()
152 */
153static int
154icprobe(device_t dev)
155{
156 return (BUS_PROBE_NOWILDCARD);
157}
158
159/*
160 * icattach()
161 */
162static int
163icattach(device_t dev)
164{
165 struct ic_softc *sc = (struct ic_softc *)device_get_softc(dev);
166 struct ifnet *ifp;
167
168 ifp = sc->ic_ifp = if_alloc(IFT_PARA);
169 if (ifp == NULL)
170 return (ENOSPC);
171
172 mtx_init(&sc->ic_lock, device_get_nameunit(dev), MTX_NETWORK_LOCK,
173 MTX_DEF);
174 sc->ic_addr = PCF_MASTER_ADDRESS; /* XXX only PCF masters */
175 sc->ic_dev = dev;
176
177 ifp->if_softc = sc;
178 if_initname(ifp, device_get_name(dev), device_get_unit(dev));
179 ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST;
180 ifp->if_ioctl = icioctl;
181 ifp->if_output = icoutput;
182 ifp->if_hdrlen = 0;
183 ifp->if_addrlen = 0;
184 ifp->if_snd.ifq_maxlen = ifqmaxlen;
185
187
188 if_attach(ifp);
189
190 bpfattach(ifp, DLT_NULL, ICHDRLEN);
191
192 return (0);
193}
194
195/*
196 * iciotcl()
197 */
198static int
199icioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
200{
201 struct ic_softc *sc = ifp->if_softc;
202 device_t icdev = sc->ic_dev;
203 device_t parent = device_get_parent(icdev);
204 struct ifaddr *ifa = (struct ifaddr *)data;
205 struct ifreq *ifr = (struct ifreq *)data;
206 int error;
207
208 switch (cmd) {
209
210 case SIOCAIFADDR:
211 case SIOCSIFADDR:
212 if (ifa->ifa_addr->sa_family != AF_INET)
213 return (EAFNOSUPPORT);
214 mtx_lock(&sc->ic_lock);
215 ifp->if_flags |= IFF_UP;
216 goto locked;
217 case SIOCSIFFLAGS:
218 mtx_lock(&sc->ic_lock);
219 locked:
220 if ((!(ifp->if_flags & IFF_UP)) &&
221 (ifp->if_drv_flags & IFF_DRV_RUNNING)) {
222
223 /* XXX disable PCF */
224 ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
225 mtx_unlock(&sc->ic_lock);
226
227 /* IFF_UP is not set, try to release the bus anyway */
228 iicbus_release_bus(parent, icdev);
229 break;
230 }
231 if (((ifp->if_flags & IFF_UP)) &&
232 (!(ifp->if_drv_flags & IFF_DRV_RUNNING))) {
233 mtx_unlock(&sc->ic_lock);
234 if ((error = iicbus_request_bus(parent, icdev,
235 IIC_WAIT | IIC_INTR)))
236 return (error);
237 mtx_lock(&sc->ic_lock);
238 iicbus_reset(parent, IIC_FASTEST, 0, NULL);
239 ifp->if_drv_flags |= IFF_DRV_RUNNING;
240 }
241 mtx_unlock(&sc->ic_lock);
242 break;
243
244 case SIOCSIFMTU:
245 ic_alloc_buffers(sc, ifr->ifr_mtu);
246 break;
247
248 case SIOCGIFMTU:
249 mtx_lock(&sc->ic_lock);
250 ifr->ifr_mtu = sc->ic_ifp->if_mtu;
251 mtx_unlock(&sc->ic_lock);
252 break;
253
254 case SIOCADDMULTI:
255 case SIOCDELMULTI:
256 if (ifr == NULL)
257 return (EAFNOSUPPORT); /* XXX */
258 switch (ifr->ifr_addr.sa_family) {
259 case AF_INET:
260 break;
261 default:
262 return (EAFNOSUPPORT);
263 }
264 break;
265 default:
266 return (EINVAL);
267 }
268 return (0);
269}
270
271/*
272 * icintr()
273 */
274static int
275icintr(device_t dev, int event, char *ptr)
276{
277 struct ic_softc *sc = (struct ic_softc *)device_get_softc(dev);
278 struct mbuf *top;
279 int len;
280
281 mtx_lock(&sc->ic_lock);
282
283 switch (event) {
284
285 case INTR_GENERAL:
286 case INTR_START:
287 sc->ic_cp = sc->ic_ifbuf;
288 sc->ic_xfercnt = 0;
289 sc->ic_flags |= IC_IFBUF_BUSY;
290 break;
291
292 case INTR_STOP:
293
294 /* if any error occurred during transfert,
295 * drop the packet */
296 sc->ic_flags &= ~IC_IFBUF_BUSY;
297 if ((sc->ic_flags & (IC_BUFFERS_BUSY | IC_BUFFER_WAITER)) ==
299 wakeup(&sc);
300 if (sc->ic_iferrs)
301 goto err;
302 if ((len = sc->ic_xfercnt) == 0)
303 break; /* ignore */
304 if (len <= ICHDRLEN)
305 goto err;
306 len -= ICHDRLEN;
307 if_inc_counter(sc->ic_ifp, IFCOUNTER_IPACKETS, 1);
308 if_inc_counter(sc->ic_ifp, IFCOUNTER_IBYTES, len);
309 BPF_TAP(sc->ic_ifp, sc->ic_ifbuf, len + ICHDRLEN);
310 top = m_devget(sc->ic_ifbuf + ICHDRLEN, len, 0, sc->ic_ifp, 0);
311 if (top) {
312 struct epoch_tracker et;
313
314 mtx_unlock(&sc->ic_lock);
315 M_SETFIB(top, sc->ic_ifp->if_fib);
316 NET_EPOCH_ENTER(et);
317 netisr_dispatch(NETISR_IP, top);
318 NET_EPOCH_EXIT(et);
319 mtx_lock(&sc->ic_lock);
320 }
321 break;
322 err:
323 if_printf(sc->ic_ifp, "errors (%d)!\n", sc->ic_iferrs);
324 sc->ic_iferrs = 0; /* reset error count */
325 if_inc_counter(sc->ic_ifp, IFCOUNTER_IERRORS, 1);
326 break;
327
328 case INTR_RECEIVE:
329 if (sc->ic_xfercnt >= sc->ic_ifp->if_mtu + ICHDRLEN) {
330 sc->ic_iferrs++;
331 } else {
332 *sc->ic_cp++ = *ptr;
333 sc->ic_xfercnt++;
334 }
335 break;
336
337 case INTR_NOACK: /* xfer terminated by master */
338 break;
339
340 case INTR_TRANSMIT:
341 *ptr = 0xff; /* XXX */
342 break;
343
344 case INTR_ERROR:
345 sc->ic_iferrs++;
346 break;
347
348 default:
349 panic("%s: unknown event (%d)!", __func__, event);
350 }
351
352 mtx_unlock(&sc->ic_lock);
353 return (0);
354}
355
356/*
357 * icoutput()
358 */
359static int
360icoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
361 struct route *ro)
362{
363 struct ic_softc *sc = ifp->if_softc;
364 device_t icdev = sc->ic_dev;
365 device_t parent = device_get_parent(icdev);
366 int len, sent;
367 struct mbuf *mm;
368 u_char *cp;
369 u_int32_t hdr;
370
371 /* BPF writes need to be handled specially. */
372 if (dst->sa_family == AF_UNSPEC)
373 bcopy(dst->sa_data, &hdr, sizeof(hdr));
374 else
375 hdr = RO_GET_FAMILY(ro, dst);
376
377 mtx_lock(&sc->ic_lock);
378 ifp->if_drv_flags |= IFF_DRV_RUNNING;
379
380 /* already sending? */
381 if (sc->ic_flags & IC_SENDING) {
382 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
383 goto error;
384 }
385
386 /* insert header */
387 bcopy ((char *)&hdr, sc->ic_obuf, ICHDRLEN);
388
389 cp = sc->ic_obuf + ICHDRLEN;
390 len = 0;
391 mm = m;
392 do {
393 if (len + mm->m_len > sc->ic_ifp->if_mtu) {
394 /* packet too large */
395 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
396 goto error;
397 }
398
399 bcopy(mtod(mm,char *), cp, mm->m_len);
400 cp += mm->m_len;
401 len += mm->m_len;
402
403 } while ((mm = mm->m_next));
404
405 BPF_MTAP2(ifp, &hdr, sizeof(hdr), m);
406
408
409 m_freem(m);
410 mtx_unlock(&sc->ic_lock);
411
412 /* send the packet */
413 if (iicbus_block_write(parent, sc->ic_addr, sc->ic_obuf,
414 len + ICHDRLEN, &sent))
415
416 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
417 else {
418 if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
419 if_inc_counter(ifp, IFCOUNTER_OBYTES, len);
420 }
421
422 mtx_lock(&sc->ic_lock);
423 sc->ic_flags &= ~(IC_SENDING | IC_OBUF_BUSY);
424 if ((sc->ic_flags & (IC_BUFFERS_BUSY | IC_BUFFER_WAITER)) ==
426 wakeup(&sc);
427 mtx_unlock(&sc->ic_lock);
428
429 return (0);
430
431error:
432 m_freem(m);
433 mtx_unlock(&sc->ic_lock);
434
435 return(0);
436}
437
static int icintr(device_t, int, char *)
Definition: if_ic.c:275
static int icioctl(struct ifnet *, u_long, caddr_t)
Definition: if_ic.c:199
#define ICMTU
Definition: if_ic.c:72
#define IC_OBUF_BUSY
Definition: if_ic.c:94
static device_method_t ic_methods[]
Definition: if_ic.c:110
static driver_t ic_driver
Definition: if_ic.c:121
#define IC_BUFFER_WAITER
Definition: if_ic.c:97
__FBSDID("$FreeBSD$")
MODULE_VERSION(ic, 1)
#define IC_BUFFERS_BUSY
Definition: if_ic.c:96
#define ICHDRLEN
Definition: if_ic.c:71
static void ic_alloc_buffers(struct ic_softc *sc, int mtu)
Definition: if_ic.c:128
static int icprobe(device_t)
Definition: if_ic.c:154
#define IC_SENDING
Definition: if_ic.c:93
#define IC_IFBUF_BUSY
Definition: if_ic.c:95
MODULE_DEPEND(ic, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER)
static int icoutput(struct ifnet *, struct mbuf *, const struct sockaddr *, struct route *)
Definition: if_ic.c:360
static devclass_t ic_devclass
Definition: if_ic.c:99
DRIVER_MODULE(ic, iicbus, ic_driver, ic_devclass, 0, 0)
static int icattach(device_t)
Definition: if_ic.c:163
#define PCF_MASTER_ADDRESS
Definition: if_ic.c:69
caddr_t data
Definition: iicbb_if.m:61
int event
Definition: iicbus_if.m:54
INTERFACE iicbus
Definition: iicbus_if.m:32
int len
Definition: iicbus_if.m:102
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_release_bus(device_t bus, device_t dev)
Definition: iiconf.c:206
int iicbus_block_write(device_t bus, u_char slave, char *buf, int len, int *sent)
Definition: iiconf.c:393
#define IICBUS_MINVER
Definition: iiconf.h:171
#define INTR_RECEIVE
Definition: iiconf.h:99
#define INTR_START
Definition: iiconf.h:97
#define IIC_WAIT
Definition: iiconf.h:46
#define INTR_GENERAL
Definition: iiconf.h:96
#define INTR_TRANSMIT
Definition: iiconf.h:100
#define IICBUS_MAXVER
Definition: iiconf.h:172
#define iicbus_reset(bus, speed, addr, oldaddr)
Definition: iiconf.h:135
#define IIC_FASTEST
Definition: iiconf.h:83
#define INTR_NOACK
Definition: iiconf.h:102
#define IIC_INTR
Definition: iiconf.h:47
#define IICBUS_PREFVER
Definition: iiconf.h:173
#define INTR_ERROR
Definition: iiconf.h:101
#define INTR_STOP
Definition: iiconf.h:98
device_t dev
Definition: ofw_iicbus_if.m:38
Definition: if_ic.c:74
u_char ic_addr
Definition: if_ic.c:78
char * ic_obuf
Definition: if_ic.c:82
device_t ic_dev
Definition: if_ic.c:76
struct ifnet * ic_ifp
Definition: if_ic.c:75
char * ic_cp
Definition: if_ic.c:84
char * ic_ifbuf
Definition: if_ic.c:83
int ic_flags
Definition: if_ic.c:80
struct mtx ic_lock
Definition: if_ic.c:90
int ic_xfercnt
Definition: if_ic.c:86
int ic_iferrs
Definition: if_ic.c:88