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/iicbus/if_ic.c,v 1.8 1999/12/29 04:35:39 peter Exp $ 27 * $DragonFly: src/sys/dev/netif/ic/if_ic.c,v 1.18 2008/01/06 16:55:50 swildner Exp $ 28 */ 29 30 /* 31 * I2C bus IP driver 32 */ 33 34 #ifdef _KERNEL 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/proc.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/module.h> 44 #include <sys/bus.h> 45 #include <sys/time.h> 46 #include <sys/malloc.h> 47 #include <sys/thread2.h> 48 49 #include <net/if.h> 50 #include <net/ifq_var.h> 51 #include <net/if_types.h> 52 #include <net/netisr.h> 53 54 #endif 55 #include <sys/mbuf.h> 56 #include <sys/socket.h> 57 #include <net/netisr.h> 58 #include <net/route.h> 59 #include <netinet/in.h> 60 #include <netinet/in_systm.h> 61 #include <netinet/in_var.h> 62 #include <netinet/ip.h> 63 #include <netinet/if_ether.h> 64 65 #include <net/bpf.h> 66 67 #include <bus/iicbus/iiconf.h> 68 #include <bus/iicbus/iicbus.h> 69 70 #include "iicbus_if.h" 71 72 #define PCF_MASTER_ADDRESS 0xaa 73 74 #define ICHDRLEN sizeof(uint32_t) 75 #define ICMTU 1500 /* default mtu */ 76 77 struct ic_softc { 78 struct ifnet ic_if; 79 80 u_char ic_addr; /* peer I2C address */ 81 82 int ic_sending; 83 84 char *ic_obuf; 85 char *ic_ifbuf; 86 char *ic_cp; 87 88 int ic_xfercnt; 89 90 int ic_iferrs; 91 }; 92 93 static devclass_t ic_devclass; 94 95 static int icprobe(device_t); 96 static int icattach(device_t); 97 98 static int icioctl(struct ifnet *, u_long, caddr_t, struct ucred *); 99 static int icoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 100 struct rtentry *); 101 102 static void icintr(device_t, int, char *); 103 104 static device_method_t ic_methods[] = { 105 /* device interface */ 106 DEVMETHOD(device_probe, icprobe), 107 DEVMETHOD(device_attach, icattach), 108 109 /* iicbus interface */ 110 DEVMETHOD(iicbus_intr, icintr), 111 112 { 0, 0 } 113 }; 114 115 static driver_t ic_driver = { 116 "ic", 117 ic_methods, 118 sizeof(struct ic_softc), 119 }; 120 121 /* 122 * icprobe() 123 */ 124 static int 125 icprobe(device_t dev) 126 { 127 return (0); 128 } 129 130 /* 131 * icattach() 132 */ 133 static int 134 icattach(device_t dev) 135 { 136 struct ic_softc *sc = (struct ic_softc *)device_get_softc(dev); 137 struct ifnet *ifp = &sc->ic_if; 138 139 sc->ic_addr = PCF_MASTER_ADDRESS; /* XXX only PCF masters */ 140 141 ifp->if_softc = sc; 142 if_initname(ifp, "ic", device_get_unit(dev)); 143 ifp->if_mtu = ICMTU; 144 ifp->if_flags = IFF_SIMPLEX | IFF_POINTOPOINT | IFF_MULTICAST; 145 ifp->if_ioctl = icioctl; 146 ifp->if_output = icoutput; 147 ifp->if_type = IFT_PARA; 148 ifp->if_hdrlen = 0; 149 ifp->if_addrlen = 0; 150 ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN); 151 152 if_attach(ifp, NULL); 153 154 bpfattach(ifp, DLT_NULL, ICHDRLEN); 155 156 return (0); 157 } 158 159 /* 160 * iciotcl() 161 */ 162 static int 163 icioctl(struct ifnet *ifp, u_long cmd, caddr_t data, struct ucred *cr) 164 { 165 device_t icdev = devclass_get_device(ic_devclass, ifp->if_dunit); 166 device_t parent = device_get_parent(icdev); 167 struct ic_softc *sc = (struct ic_softc *)device_get_softc(icdev); 168 169 struct ifaddr *ifa = (struct ifaddr *)data; 170 struct ifreq *ifr = (struct ifreq *)data; 171 172 u_char *iptr, *optr; 173 int error; 174 175 switch (cmd) { 176 177 case SIOCSIFDSTADDR: 178 case SIOCAIFADDR: 179 case SIOCSIFADDR: 180 if (ifa->ifa_addr->sa_family != AF_INET) 181 return EAFNOSUPPORT; 182 ifp->if_flags |= IFF_UP; 183 /* FALLTHROUGH */ 184 case SIOCSIFFLAGS: 185 if ((!(ifp->if_flags & IFF_UP)) && (ifp->if_flags & IFF_RUNNING)) { 186 187 /* XXX disable PCF */ 188 ifp->if_flags &= ~IFF_RUNNING; 189 190 /* IFF_UP is not set, try to release the bus anyway */ 191 iicbus_release_bus(parent, icdev); 192 break; 193 } 194 if (((ifp->if_flags & IFF_UP)) && (!(ifp->if_flags & IFF_RUNNING))) { 195 196 if ((error = iicbus_request_bus(parent, icdev, IIC_WAIT|IIC_INTR))) 197 return (error); 198 199 sc->ic_obuf = kmalloc(sc->ic_if.if_mtu + ICHDRLEN, 200 M_DEVBUF, M_WAITOK); 201 202 sc->ic_ifbuf = kmalloc(sc->ic_if.if_mtu + ICHDRLEN, 203 M_DEVBUF, M_WAITOK); 204 205 iicbus_reset(parent, IIC_FASTEST, 0, NULL); 206 207 ifp->if_flags |= IFF_RUNNING; 208 } 209 break; 210 211 case SIOCSIFMTU: 212 /* save previous buffers */ 213 iptr = sc->ic_ifbuf; 214 optr = sc->ic_obuf; 215 216 /* allocate input buffer */ 217 sc->ic_ifbuf = kmalloc(ifr->ifr_mtu+ICHDRLEN, M_DEVBUF, M_WAITOK); 218 219 /* allocate output buffer */ 220 sc->ic_ifbuf = kmalloc(ifr->ifr_mtu+ICHDRLEN, M_DEVBUF, M_WAITOK); 221 222 if (iptr) 223 kfree(iptr,M_DEVBUF); 224 225 if (optr) 226 kfree(optr,M_DEVBUF); 227 228 sc->ic_if.if_mtu = ifr->ifr_mtu; 229 break; 230 231 case SIOCGIFMTU: 232 ifr->ifr_mtu = sc->ic_if.if_mtu; 233 break; 234 235 case SIOCADDMULTI: 236 case SIOCDELMULTI: 237 if (ifr == 0) { 238 return EAFNOSUPPORT; /* XXX */ 239 } 240 switch (ifr->ifr_addr.sa_family) { 241 242 case AF_INET: 243 break; 244 245 default: 246 return EAFNOSUPPORT; 247 } 248 break; 249 250 default: 251 return EINVAL; 252 } 253 return 0; 254 } 255 256 /* 257 * icintr() 258 */ 259 static void 260 icintr (device_t dev, int event, char *ptr) 261 { 262 struct ic_softc *sc = (struct ic_softc *)device_get_softc(dev); 263 int unit = device_get_unit(dev); 264 int len; 265 struct mbuf *top; 266 267 crit_enter(); 268 269 switch (event) { 270 271 case INTR_GENERAL: 272 case INTR_START: 273 sc->ic_cp = sc->ic_ifbuf; 274 sc->ic_xfercnt = 0; 275 break; 276 277 case INTR_STOP: 278 279 /* if any error occured during transfert, 280 * drop the packet */ 281 if (sc->ic_iferrs) 282 goto err; 283 284 if ((len = sc->ic_xfercnt) == 0) 285 break; /* ignore */ 286 287 if (len <= ICHDRLEN) 288 goto err; 289 290 len -= ICHDRLEN; 291 sc->ic_if.if_ipackets ++; 292 sc->ic_if.if_ibytes += len; 293 294 BPF_TAP(&sc->ic_if, sc->ic_ifbuf, len + ICHDRLEN); 295 296 top = m_devget(sc->ic_ifbuf + ICHDRLEN, len, 0, &sc->ic_if, 0); 297 298 if (top) 299 netisr_queue(NETISR_IP, top); 300 break; 301 302 err: 303 kprintf("ic%d: errors (%d)!\n", unit, sc->ic_iferrs); 304 305 sc->ic_iferrs = 0; /* reset error count */ 306 sc->ic_if.if_ierrors ++; 307 308 break; 309 310 case INTR_RECEIVE: 311 if (sc->ic_xfercnt >= sc->ic_if.if_mtu+ICHDRLEN) { 312 sc->ic_iferrs ++; 313 314 } else { 315 *sc->ic_cp++ = *ptr; 316 sc->ic_xfercnt ++; 317 } 318 break; 319 320 case INTR_NOACK: /* xfer terminated by master */ 321 break; 322 323 case INTR_TRANSMIT: 324 *ptr = 0xff; /* XXX */ 325 break; 326 327 case INTR_ERROR: 328 sc->ic_iferrs ++; 329 break; 330 331 default: 332 panic("%s: unknown event (%d)!", __func__, event); 333 } 334 335 crit_exit(); 336 } 337 338 /* 339 * icoutput() 340 */ 341 static int 342 icoutput(struct ifnet *ifp, struct mbuf *m, 343 struct sockaddr *dst, struct rtentry *rt) 344 { 345 device_t icdev = devclass_get_device(ic_devclass, ifp->if_dunit); 346 device_t parent = device_get_parent(icdev); 347 struct ic_softc *sc = (struct ic_softc *)device_get_softc(icdev); 348 int len, sent; 349 struct mbuf *mm; 350 u_char *cp; 351 uint32_t hdr = dst->sa_family; 352 353 ifp->if_flags |= IFF_RUNNING; 354 355 crit_enter(); 356 357 /* already sending? */ 358 if (sc->ic_sending) { 359 ifp->if_oerrors ++; 360 goto error; 361 } 362 363 /* insert header */ 364 bcopy ((char *)&hdr, sc->ic_obuf, ICHDRLEN); 365 366 cp = sc->ic_obuf + ICHDRLEN; 367 len = 0; 368 mm = m; 369 do { 370 if (len + mm->m_len > sc->ic_if.if_mtu) { 371 /* packet to large */ 372 ifp->if_oerrors ++; 373 goto error; 374 } 375 376 bcopy(mtod(mm,char *), cp, mm->m_len); 377 cp += mm->m_len; 378 len += mm->m_len; 379 380 } while ((mm = mm->m_next)); 381 382 if (ifp->if_bpf) 383 bpf_ptap(ifp->if_bpf, m, &hdr, ICHDRLEN); 384 385 sc->ic_sending = 1; 386 387 m_freem(m); 388 389 crit_exit(); 390 391 /* send the packet */ 392 if (iicbus_block_write(parent, sc->ic_addr, sc->ic_obuf, 393 len + ICHDRLEN, &sent)) 394 395 ifp->if_oerrors ++; 396 else { 397 ifp->if_opackets ++; 398 ifp->if_obytes += len; 399 } 400 401 sc->ic_sending = 0; 402 403 return (0); 404 405 error: 406 m_freem(m); 407 crit_exit(); 408 409 return(0); 410 } 411 412 DRIVER_MODULE(if_ic, iicbus, ic_driver, ic_devclass, 0, 0); 413 MODULE_DEPEND(if_ic, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); 414 MODULE_VERSION(if_ic, 1); 415