Annotation of sys/dev/pci/if_art.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_art.c,v 1.13 2006/01/26 16:51:00 claudio Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2004,2005 Internet Business Solutions AG, Zurich, Switzerland
! 5: * Written by: Claudio Jeker <jeker@accoom.net>
! 6: *
! 7: * Permission to use, copy, modify, and distribute this software for any
! 8: * purpose with or without fee is hereby granted, provided that the above
! 9: * copyright notice and this permission notice appear in all copies.
! 10: *
! 11: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 12: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 13: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 14: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 15: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 16: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 17: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 18: */
! 19:
! 20: #include <sys/param.h>
! 21: #include <sys/types.h>
! 22:
! 23: #include <sys/device.h>
! 24: #include <sys/proc.h>
! 25: #include <sys/socket.h>
! 26: #include <sys/sockio.h>
! 27: #include <sys/syslog.h>
! 28: #include <sys/systm.h>
! 29:
! 30: #include <machine/bus.h>
! 31:
! 32: #include <net/if.h>
! 33: #include <net/if_media.h>
! 34: #include <net/if_sppp.h>
! 35:
! 36: #include <dev/pci/musyccvar.h>
! 37: #include <dev/pci/if_art.h>
! 38:
! 39: #define ART_E1_MASK 0xffffffff
! 40: #define ART_T1_MASK 0x01fffffe
! 41:
! 42: int art_match(struct device *, void *, void *);
! 43: void art_softc_attach(struct device *, struct device *, void *);
! 44:
! 45: int art_ioctl(struct ifnet *, u_long, caddr_t);
! 46: int art_ifm_change(struct ifnet *);
! 47: void art_ifm_status(struct ifnet *, struct ifmediareq *);
! 48: int art_ifm_options(struct ifnet *, struct channel_softc *, u_int);
! 49: void art_onesec(void *);
! 50: void art_linkstate(void *);
! 51: u_int32_t art_mask_tsmap(u_int, u_int32_t);
! 52:
! 53: struct cfattach art_ca = {
! 54: sizeof(struct art_softc), art_match, art_softc_attach
! 55: };
! 56:
! 57: struct cfdriver art_cd = {
! 58: NULL, "art", DV_DULL
! 59: };
! 60:
! 61: int
! 62: art_match(struct device *parent, void *match, void *aux)
! 63: {
! 64: struct musycc_attach_args *ma = aux;
! 65:
! 66: if (ma->ma_type == MUSYCC_FRAMER_BT8370)
! 67: return (1);
! 68: return (0);
! 69: }
! 70:
! 71: /*
! 72: * used for the one second timer
! 73: */
! 74: extern int hz;
! 75:
! 76: void
! 77: art_softc_attach(struct device *parent, struct device *self, void *aux)
! 78: {
! 79: struct art_softc *sc = (struct art_softc *)self;
! 80: struct musycc_softc *psc = (struct musycc_softc *)parent;
! 81: struct musycc_attach_args *ma = aux;
! 82:
! 83: printf(" \"%s\"", ma->ma_product);
! 84:
! 85: if (ebus_attach_device(&sc->art_ebus, psc, ma->ma_base,
! 86: ma->ma_size) != 0) {
! 87: printf(": could not map framer\n");
! 88: return;
! 89: }
! 90:
! 91: /* set basic values */
! 92: sc->art_port = ma->ma_port;
! 93: sc->art_slot = ma->ma_slot;
! 94: sc->art_gnum = ma->ma_gnum;
! 95: sc->art_type = ma->ma_flags & 0x03;
! 96:
! 97: sc->art_channel = musycc_channel_create(self->dv_xname, 1);
! 98: if (sc->art_channel == NULL) {
! 99: printf(": could not alloc channel descriptor\n");
! 100: return;
! 101: }
! 102:
! 103: if (musycc_channel_attach(psc, sc->art_channel, self, sc->art_gnum) ==
! 104: -1) {
! 105: printf(": unable to attach to hdlc controller\n");
! 106: return;
! 107: }
! 108:
! 109: ifmedia_init(&sc->art_ifm, 0, art_ifm_change, art_ifm_status);
! 110: ifmedia_add(&sc->art_ifm,
! 111: IFM_MAKEWORD(IFM_TDM, IFM_TDM_T1, 0, 0), 0, NULL);
! 112: ifmedia_add(&sc->art_ifm,
! 113: IFM_MAKEWORD(IFM_TDM, IFM_TDM_T1_AMI, 0, 0), 0, NULL);
! 114: ifmedia_add(&sc->art_ifm,
! 115: IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1, 0, 0), 0, NULL);
! 116: ifmedia_add(&sc->art_ifm,
! 117: IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1_G704, 0, 0), 0, NULL);
! 118: ifmedia_add(&sc->art_ifm,
! 119: IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1_G704_CRC4, 0, 0), 0, NULL);
! 120:
! 121: ifmedia_add(&sc->art_ifm,
! 122: IFM_MAKEWORD(IFM_TDM, IFM_TDM_T1, IFM_TDM_MASTER, 0), 0, NULL);
! 123: ifmedia_add(&sc->art_ifm,
! 124: IFM_MAKEWORD(IFM_TDM, IFM_TDM_T1_AMI, IFM_TDM_MASTER, 0), 0, NULL);
! 125: ifmedia_add(&sc->art_ifm,
! 126: IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1, IFM_TDM_MASTER, 0), 0, NULL);
! 127: ifmedia_add(&sc->art_ifm,
! 128: IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1_G704, IFM_TDM_MASTER, 0), 0, NULL);
! 129: ifmedia_add(&sc->art_ifm,
! 130: IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1_G704_CRC4, IFM_TDM_MASTER, 0),
! 131: 0, NULL);
! 132:
! 133: ifmedia_add(&sc->art_ifm,
! 134: IFM_MAKEWORD(IFM_TDM, IFM_TDM_T1, IFM_TDM_PPP, 0), 0, NULL);
! 135: ifmedia_add(&sc->art_ifm,
! 136: IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1, IFM_TDM_PPP, 0), 0, NULL);
! 137: ifmedia_add(&sc->art_ifm,
! 138: IFM_MAKEWORD(IFM_TDM, IFM_TDM_T1_AMI, IFM_TDM_PPP, 0), 0, NULL);
! 139: ifmedia_add(&sc->art_ifm,
! 140: IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1_G704, IFM_TDM_PPP, 0), 0, NULL);
! 141: ifmedia_add(&sc->art_ifm,
! 142: IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1_G704_CRC4, IFM_TDM_PPP, 0), 0,
! 143: NULL);
! 144:
! 145: ifmedia_add(&sc->art_ifm,
! 146: IFM_MAKEWORD(IFM_TDM, IFM_TDM_T1, IFM_TDM_PPP | IFM_TDM_MASTER, 0),
! 147: 0, NULL);
! 148: ifmedia_add(&sc->art_ifm,
! 149: IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1, IFM_TDM_PPP | IFM_TDM_MASTER, 0),
! 150: 0, NULL);
! 151: ifmedia_add(&sc->art_ifm,
! 152: IFM_MAKEWORD(IFM_TDM, IFM_TDM_T1_AMI, IFM_TDM_PPP | IFM_TDM_MASTER,
! 153: 0), 0, NULL);
! 154: ifmedia_add(&sc->art_ifm,
! 155: IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1_G704, IFM_TDM_PPP |
! 156: IFM_TDM_MASTER, 0), 0, NULL);
! 157: ifmedia_add(&sc->art_ifm,
! 158: IFM_MAKEWORD(IFM_TDM, IFM_TDM_E1_G704_CRC4, IFM_TDM_PPP |
! 159: IFM_TDM_MASTER, 0), 0, NULL);
! 160:
! 161: printf("\n");
! 162:
! 163: if (bt8370_reset(sc) != 0)
! 164: return;
! 165:
! 166: /* Initialize timeout for statistics update. */
! 167: timeout_set(&sc->art_onesec, art_onesec, sc);
! 168:
! 169: ifmedia_set(&sc->art_ifm, IFM_TDM|IFM_TDM_E1_G704_CRC4);
! 170: sc->art_media = sc->art_ifm.ifm_media;
! 171:
! 172: bt8370_set_frame_mode(sc, sc->art_type, IFM_TDM_E1_G704_CRC4, 0);
! 173: musycc_attach_sppp(sc->art_channel, art_ioctl);
! 174:
! 175: /* Set linkstate hook to track link state changes done by sppp. */
! 176: sc->art_linkstatehook = hook_establish(
! 177: sc->art_channel->cc_ifp->if_linkstatehooks, 0, art_linkstate, sc);
! 178:
! 179: /* Schedule the timeout one second from now. */
! 180: timeout_add(&sc->art_onesec, hz);
! 181: }
! 182:
! 183: /* interface ioctl */
! 184: int
! 185: art_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
! 186: {
! 187: struct ifreq *ifr = (struct ifreq*) data;
! 188: struct channel_softc *cc = ifp->if_softc;
! 189: struct art_softc *ac = (struct art_softc *)cc->cc_parent;
! 190: u_int32_t tsmap;
! 191: int s, rv = 0;
! 192:
! 193: s = splnet();
! 194: switch (command) {
! 195: case SIOCSIFADDR:
! 196: if ((rv = musycc_init_channel(cc, ac->art_slot)))
! 197: break;
! 198: rv = sppp_ioctl(ifp, command, data);
! 199: break;
! 200: case SIOCSIFTIMESLOT:
! 201: if ((rv = suser(curproc, 0)) != 0)
! 202: break;
! 203: rv = copyin(ifr->ifr_data, &tsmap, sizeof(tsmap));
! 204: if (rv)
! 205: break;
! 206: if (art_mask_tsmap(IFM_SUBTYPE(ac->art_media), tsmap) !=
! 207: tsmap) {
! 208: rv = EINVAL;
! 209: break;
! 210: }
! 211: if (ac->art_type == ART_SBI_SINGLE &&
! 212: (IFM_SUBTYPE(ac->art_media) == IFM_TDM_T1 ||
! 213: IFM_SUBTYPE(ac->art_media) == IFM_TDM_T1_AMI))
! 214: /*
! 215: * need to adjust timeslot mask for T1 on single port
! 216: * cards. There timeslot 0-23 are usable not 1-24
! 217: */
! 218: tsmap >>= 1;
! 219:
! 220: cc->cc_tslots = tsmap;
! 221: rv = musycc_init_channel(cc, ac->art_slot);
! 222: break;
! 223: case SIOCGIFTIMESLOT:
! 224: tsmap = cc->cc_tslots;
! 225: if (ac->art_type == ART_SBI_SINGLE &&
! 226: (IFM_SUBTYPE(ac->art_media) == IFM_TDM_T1 ||
! 227: IFM_SUBTYPE(ac->art_media) == IFM_TDM_T1_AMI))
! 228: tsmap <<= 1;
! 229: rv = copyout(&tsmap, ifr->ifr_data, sizeof(tsmap));
! 230: break;
! 231: case SIOCSIFFLAGS:
! 232: /*
! 233: * If interface is marked up and not running, then start it.
! 234: * If it is marked down and running, stop it.
! 235: */
! 236: if (ifr->ifr_flags & IFF_UP && cc->cc_state != CHAN_RUNNING) {
! 237: if ((rv = musycc_init_channel(cc, ac->art_slot)))
! 238: break;
! 239: } else if ((ifr->ifr_flags & IFF_UP) == 0 &&
! 240: cc->cc_state == CHAN_RUNNING)
! 241: musycc_stop_channel(cc);
! 242: rv = sppp_ioctl(ifp, command, data);
! 243: break;
! 244: case SIOCSIFMEDIA:
! 245: case SIOCGIFMEDIA:
! 246: if (ac != NULL)
! 247: rv = ifmedia_ioctl(ifp, ifr, &ac->art_ifm, command);
! 248: else
! 249: rv = EINVAL;
! 250: break;
! 251: default:
! 252: rv = sppp_ioctl(ifp, command, data);
! 253: break;
! 254: }
! 255: splx(s);
! 256: return (rv);
! 257: }
! 258:
! 259: int
! 260: art_ifm_change(struct ifnet *ifp)
! 261: {
! 262: struct channel_softc *cc = ifp->if_softc;
! 263: struct art_softc *ac = (struct art_softc *)cc->cc_parent;
! 264: struct ifmedia *ifm = &ac->art_ifm;
! 265: int rv, s, baudrate;
! 266:
! 267: ACCOOM_PRINTF(2, ("%s: art_ifm_change %08x\n", ifp->if_xname,
! 268: ifm->ifm_media));
! 269:
! 270: if (IFM_TYPE(ifm->ifm_media) != IFM_TDM)
! 271: return (EINVAL);
! 272:
! 273: /* OPTIONS (controller mode hdlc, ppp, eoe) */
! 274: if ((rv = art_ifm_options(ifp, cc, IFM_OPTIONS(ifm->ifm_media))) != 0)
! 275: return (rv);
! 276:
! 277: /* SUBTYPE (framing mode T1/E1) + MODE (clocking master/slave) */
! 278: if (IFM_SUBTYPE(ifm->ifm_media) != IFM_SUBTYPE(ac->art_media) ||
! 279: IFM_MODE(ifm->ifm_media) != IFM_MODE(ac->art_media)) {
! 280: ACCOOM_PRINTF(0, ("%s: art_ifm_change type %d mode %x\n",
! 281: ifp->if_xname, IFM_SUBTYPE(ifm->ifm_media),
! 282: IFM_MODE(ifm->ifm_media)));
! 283:
! 284: bt8370_set_frame_mode(ac, ac->art_type,
! 285: IFM_SUBTYPE(ifm->ifm_media), IFM_MODE(ifm->ifm_media));
! 286:
! 287: if (IFM_SUBTYPE(ifm->ifm_media) != IFM_SUBTYPE(ac->art_media)) {
! 288: /* adjust timeslot map on media change */
! 289: cc->cc_tslots = art_mask_tsmap(
! 290: IFM_SUBTYPE(ifm->ifm_media), cc->cc_tslots);
! 291:
! 292: if (ac->art_type == ART_SBI_SINGLE &&
! 293: (IFM_SUBTYPE(ifm->ifm_media) == IFM_TDM_T1 ||
! 294: IFM_SUBTYPE(ifm->ifm_media) == IFM_TDM_T1_AMI) &&
! 295: (IFM_SUBTYPE(ac->art_media) != IFM_TDM_T1 &&
! 296: IFM_SUBTYPE(ac->art_media) != IFM_TDM_T1_AMI))
! 297: /*
! 298: * need to adjust timeslot mask for T1 on
! 299: * single port cards. There timeslot 0-23 are
! 300: * usable not 1-24
! 301: */
! 302: cc->cc_tslots >>= 1;
! 303: else if (ac->art_type == ART_SBI_SINGLE &&
! 304: (IFM_SUBTYPE(ifm->ifm_media) != IFM_TDM_T1 &&
! 305: IFM_SUBTYPE(ifm->ifm_media) != IFM_TDM_T1_AMI) &&
! 306: (IFM_SUBTYPE(ac->art_media) == IFM_TDM_T1 ||
! 307: IFM_SUBTYPE(ac->art_media) == IFM_TDM_T1_AMI))
! 308: /* undo the last adjustment */
! 309: cc->cc_tslots <<= 1;
! 310: }
! 311:
! 312: /* re-init the card */
! 313: if ((rv = musycc_init_channel(cc, ac->art_slot)))
! 314: return (rv);
! 315: }
! 316:
! 317: baudrate = ifmedia_baudrate(ac->art_media);
! 318: if (baudrate != ifp->if_baudrate) {
! 319: ifp->if_baudrate = baudrate;
! 320: s = splsoftnet();
! 321: if_link_state_change(ifp), baudrate;
! 322: splx(s);
! 323: }
! 324:
! 325: ac->art_media = ifm->ifm_media;
! 326:
! 327: return (0);
! 328: }
! 329:
! 330: void
! 331: art_ifm_status(struct ifnet *ifp, struct ifmediareq *ifmreq)
! 332: {
! 333: struct art_softc *ac;
! 334:
! 335: ac = (struct art_softc *)
! 336: ((struct channel_softc *)ifp->if_softc)->cc_parent;
! 337: ifmreq->ifm_status = IFM_AVALID;
! 338: if (ifp->if_link_state == LINK_STATE_UP)
! 339: ifmreq->ifm_status |= IFM_ACTIVE;
! 340: ifmreq->ifm_active = ac->art_media;
! 341:
! 342: return;
! 343: }
! 344:
! 345: int
! 346: art_ifm_options(struct ifnet *ifp, struct channel_softc *cc, u_int options)
! 347: {
! 348: struct art_softc *ac = (struct art_softc *)cc->cc_parent;
! 349: u_int flags = cc->cc_ppp.pp_flags;
! 350: int rv;
! 351:
! 352: if (options == IFM_TDM_PPP) {
! 353: flags &= ~PP_CISCO;
! 354: flags |= PP_KEEPALIVE;
! 355: } else if (options == 0) {
! 356: flags |= PP_CISCO;
! 357: flags |= PP_KEEPALIVE;
! 358: } else {
! 359: ACCOOM_PRINTF(0, ("%s: Unsupported ifmedia options\n",
! 360: ifp->if_xname));
! 361: return (EINVAL);
! 362: }
! 363: if (flags != cc->cc_ppp.pp_flags) {
! 364: musycc_stop_channel(cc);
! 365: cc->cc_ppp.pp_flags = flags;
! 366: if ((rv = musycc_init_channel(cc, ac->art_slot)))
! 367: return (rv);
! 368: return (sppp_ioctl(ifp, SIOCSIFFLAGS, NULL));
! 369: }
! 370: return (0);
! 371: }
! 372:
! 373: void
! 374: art_onesec(void *arg)
! 375: {
! 376: struct art_softc *ac = arg;
! 377: struct ifnet *ifp = ac->art_channel->cc_ifp;
! 378: struct sppp *ppp = &ac->art_channel->cc_ppp;
! 379: int s, rv, link_state;
! 380:
! 381: rv = bt8370_link_status(ac);
! 382: switch (rv) {
! 383: case 1:
! 384: link_state = LINK_STATE_UP;
! 385: /* set green led */
! 386: ebus_set_led(ac->art_channel, 1, MUSYCC_LED_GREEN);
! 387: break;
! 388: case 0:
! 389: link_state = LINK_STATE_DOWN;
! 390: /* set green led and red led as well */
! 391: ebus_set_led(ac->art_channel, 1,
! 392: MUSYCC_LED_GREEN | MUSYCC_LED_RED);
! 393: break;
! 394: default:
! 395: link_state = LINK_STATE_DOWN;
! 396: /* turn green led off */
! 397: ebus_set_led(ac->art_channel, 0, MUSYCC_LED_GREEN);
! 398: break;
! 399: }
! 400:
! 401: if (link_state != ifp->if_link_state) {
! 402: s = splsoftnet();
! 403: if (link_state == LINK_STATE_UP)
! 404: ppp->pp_up(ppp);
! 405: else
! 406: ppp->pp_down(ppp);
! 407: splx(s);
! 408: }
! 409:
! 410: /*
! 411: * run musycc onesec job
! 412: */
! 413: musycc_tick(ac->art_channel);
! 414:
! 415: /*
! 416: * Schedule another timeout one second from now.
! 417: */
! 418: timeout_add(&ac->art_onesec, hz);
! 419: }
! 420:
! 421: void
! 422: art_linkstate(void *arg)
! 423: {
! 424: struct art_softc *ac = arg;
! 425: struct ifnet *ifp = ac->art_channel->cc_ifp;
! 426:
! 427: if (ifp->if_link_state == LINK_STATE_UP)
! 428: /* turn red led off */
! 429: ebus_set_led(ac->art_channel, 0, MUSYCC_LED_RED);
! 430: else
! 431: /* turn red led on */
! 432: ebus_set_led(ac->art_channel, 1, MUSYCC_LED_RED);
! 433: }
! 434:
! 435: u_int32_t
! 436: art_mask_tsmap(u_int mode, u_int32_t tsmap)
! 437: {
! 438: switch (mode) {
! 439: case IFM_TDM_E1:
! 440: case IFM_TDM_E1_G704:
! 441: case IFM_TDM_E1_G704_CRC4:
! 442: return (tsmap & ART_E1_MASK);
! 443: case IFM_TDM_T1_AMI:
! 444: case IFM_TDM_T1:
! 445: return (tsmap & ART_T1_MASK);
! 446: default:
! 447: return (tsmap);
! 448: }
! 449: }
CVSweb