lpt.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,383 行 · 第 1/3 页
C
1,383 行
* Process an ioctl request. */static intlpioctl (struct ifnet *ifp, u_long cmd, caddr_t data){ struct lpt_softc *sc = lpt_sc + ifp->if_unit; struct ifaddr *ifa = (struct ifaddr *)data; struct ifreq *ifr = (struct ifreq *)data; u_char *ptr; switch (cmd) { case SIOCSIFDSTADDR: case SIOCAIFADDR: case SIOCSIFADDR: if (ifa->ifa_addr->sa_family != AF_INET) return EAFNOSUPPORT; ifp->if_flags |= IFF_UP; /* FALLTHROUGH */ case SIOCSIFFLAGS: if ((!(ifp->if_flags & IFF_UP)) && (ifp->if_flags & IFF_RUNNING)) { outb(sc->sc_port + lpt_control, 0x00); ifp->if_flags &= ~IFF_RUNNING; break; } if (((ifp->if_flags & IFF_UP)) && (!(ifp->if_flags & IFF_RUNNING))) { if (lpinittables()) return ENOBUFS; sc->sc_ifbuf = malloc(sc->sc_if.if_mtu + MLPIPHDRLEN, M_DEVBUF, M_WAITOK); if (!sc->sc_ifbuf) return ENOBUFS; outb(sc->sc_port + lpt_control, LPC_ENA); ifp->if_flags |= IFF_RUNNING; } break; case SIOCSIFMTU: ptr = sc->sc_ifbuf; sc->sc_ifbuf = malloc(ifr->ifr_mtu+MLPIPHDRLEN, M_DEVBUF, M_NOWAIT); if (!sc->sc_ifbuf) { sc->sc_ifbuf = ptr; return ENOBUFS; } if (ptr) free(ptr,M_DEVBUF); sc->sc_if.if_mtu = ifr->ifr_mtu; break; case SIOCGIFMTU: ifr->ifr_mtu = sc->sc_if.if_mtu; break; case SIOCADDMULTI: case SIOCDELMULTI: if (ifr == 0) { return EAFNOSUPPORT; /* XXX */ } switch (ifr->ifr_addr.sa_family) {#ifdef INET case AF_INET: break;#endif default: return EAFNOSUPPORT; } break; default: lprintf(("LP:ioctl(0x%lx)\n", cmd)); return EINVAL; } return 0;}static __inline intclpoutbyte (u_char byte, int spin, int data_port, int status_port){ outb(data_port, ctxmitl[byte]); while (inb(status_port) & CLPIP_SHAKE) if (--spin == 0) { return 1; } outb(data_port, ctxmith[byte]); while (!(inb(status_port) & CLPIP_SHAKE)) if (--spin == 0) { return 1; } return 0;}static __inline intclpinbyte (int spin, int data_port, int status_port){ int c, cl; while((inb(status_port) & CLPIP_SHAKE)) if(!--spin) { return -1; } cl = inb(status_port); outb(data_port, 0x10); while(!(inb(status_port) & CLPIP_SHAKE)) if(!--spin) { return -1; } c = inb(status_port); outb(data_port, 0x00); return (ctrecvl[cl] | ctrecvh[c]);}static voidlpintr (int unit){ struct lpt_softc *sc = lpt_sc + unit; register int lpt_data_port = sc->sc_port + lpt_data; register int lpt_stat_port = sc->sc_port + lpt_status; int lpt_ctrl_port = sc->sc_port + lpt_control; int len, s, j; u_char *bp; u_char c, cl; struct mbuf *top; s = splhigh(); if (sc->sc_if.if_flags & IFF_LINK0) { /* Ack. the request */ outb(lpt_data_port, 0x01); /* Get the packet length */ j = clpinbyte(LPMAXSPIN2, lpt_data_port, lpt_stat_port); if (j == -1) goto err; len = j; j = clpinbyte(LPMAXSPIN2, lpt_data_port, lpt_stat_port); if (j == -1) goto err; len = len + (j << 8); if (len > sc->sc_if.if_mtu + MLPIPHDRLEN) goto err; bp = sc->sc_ifbuf; while (len--) { j = clpinbyte(LPMAXSPIN2, lpt_data_port, lpt_stat_port); if (j == -1) { goto err; } *bp++ = j; } /* Get and ignore checksum */ j = clpinbyte(LPMAXSPIN2, lpt_data_port, lpt_stat_port); if (j == -1) { goto err; } len = bp - sc->sc_ifbuf; if (len <= CLPIPHDRLEN) goto err; sc->sc_iferrs = 0; if (IF_QFULL(&ipintrq)) { lprintf(("DROP")); IF_DROP(&ipintrq); goto done; } len -= CLPIPHDRLEN; sc->sc_if.if_ipackets++; sc->sc_if.if_ibytes += len; top = m_devget(sc->sc_ifbuf + CLPIPHDRLEN, len, 0, &sc->sc_if, 0); if (top) { IF_ENQUEUE(&ipintrq, top); schednetisr(NETISR_IP); } goto done; } while ((inb(lpt_stat_port) & LPIP_SHAKE)) { len = sc->sc_if.if_mtu + LPIPHDRLEN; bp = sc->sc_ifbuf; while (len--) { cl = inb(lpt_stat_port); outb(lpt_data_port, 8); j = LPMAXSPIN2; while((inb(lpt_stat_port) & LPIP_SHAKE)) if(!--j) goto err; c = inb(lpt_stat_port); outb(lpt_data_port, 0); *bp++= trecvh[cl] | trecvl[c]; j = LPMAXSPIN2; while (!((cl=inb(lpt_stat_port)) & LPIP_SHAKE)) { if (cl != c && (((cl = inb(lpt_stat_port)) ^ 0xb8) & 0xf8) == (c & 0xf8)) goto end; if (!--j) goto err; } } end: len = bp - sc->sc_ifbuf; if (len <= LPIPHDRLEN) goto err; sc->sc_iferrs = 0; if (IF_QFULL(&ipintrq)) { lprintf(("DROP")); IF_DROP(&ipintrq); goto done; }#if NBPFILTER > 0 if (sc->sc_if.if_bpf) { bpf_tap(&sc->sc_if, sc->sc_ifbuf, len); }#endif len -= LPIPHDRLEN; sc->sc_if.if_ipackets++; sc->sc_if.if_ibytes += len; top = m_devget(sc->sc_ifbuf + LPIPHDRLEN, len, 0, &sc->sc_if, 0); if (top) { IF_ENQUEUE(&ipintrq, top); schednetisr(NETISR_IP); } } goto done; err: outb(lpt_data_port, 0); lprintf(("R")); sc->sc_if.if_ierrors++; sc->sc_iferrs++; /* * We are not able to send receive anything for now, * so stop wasting our time */ if (sc->sc_iferrs > LPMAXERRS) { printf("lp%d: Too many errors, Going off-line.\n", unit); outb(lpt_ctrl_port, 0x00); sc->sc_if.if_flags &= ~IFF_RUNNING; sc->sc_iferrs=0; } done: splx(s); return;}static __inline intlpoutbyte (u_char byte, int spin, int data_port, int status_port){ outb(data_port, txmith[byte]); while (!(inb(status_port) & LPIP_SHAKE)) if (--spin == 0) return 1; outb(data_port, txmitl[byte]); while (inb(status_port) & LPIP_SHAKE) if (--spin == 0) return 1; return 0;}static intlpoutput (struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rt){ register int lpt_data_port = lpt_sc[ifp->if_unit].sc_port + lpt_data; register int lpt_stat_port = lpt_sc[ifp->if_unit].sc_port + lpt_status; int lpt_ctrl_port = lpt_sc[ifp->if_unit].sc_port + lpt_control; int s, err; struct mbuf *mm; u_char *cp = "\0\0"; u_char chksum = 0; int count = 0; int i; int spin; /* We need a sensible value if we abort */ cp++; ifp->if_flags |= IFF_RUNNING; err = 1; /* assume we're aborting because of an error */ s = splhigh(); /* Suspend (on laptops) or receive-errors might have taken us offline */ outb(lpt_ctrl_port, LPC_ENA); if (ifp->if_flags & IFF_LINK0) { if (!(inb(lpt_stat_port) & CLPIP_SHAKE)) { lprintf(("&")); lptintr(ifp->if_unit); } /* Alert other end to pending packet */ spin = LPMAXSPIN1; outb(lpt_data_port, 0x08); while ((inb(lpt_stat_port) & 0x08) == 0) if (--spin == 0) { goto nend; } /* Calculate length of packet, then send that */ count += 14; /* Ethernet header len */ mm = m; for (mm = m; mm; mm = mm->m_next) { count += mm->m_len; } if (clpoutbyte(count & 0xFF, LPMAXSPIN1, lpt_data_port, lpt_stat_port)) goto nend; if (clpoutbyte((count >> 8) & 0xFF, LPMAXSPIN1, lpt_data_port, lpt_stat_port)) goto nend; /* Send dummy ethernet header */ for (i = 0; i < 12; i++) { if (clpoutbyte(i, LPMAXSPIN1, lpt_data_port, lpt_stat_port)) goto nend; chksum += i; } if (clpoutbyte(0x08, LPMAXSPIN1, lpt_data_port, lpt_stat_port)) goto nend; if (clpoutbyte(0x00, LPMAXSPIN1, lpt_data_port, lpt_stat_port)) goto nend; chksum += 0x08 + 0x00; /* Add into checksum */ mm = m; do { cp = mtod(mm, u_char *); while (mm->m_len--) { chksum += *cp; if (clpoutbyte(*cp++, LPMAXSPIN2, lpt_data_port, lpt_stat_port)) goto nend; } } while ((mm = mm->m_next)); /* Send checksum */ if (clpoutbyte(chksum, LPMAXSPIN2, lpt_data_port, lpt_stat_port)) goto nend; /* Go quiescent */ outb(lpt_data_port, 0); err = 0; /* No errors */ nend: if (err) { /* if we didn't timeout... */ ifp->if_oerrors++; lprintf(("X")); } else { ifp->if_opackets++; ifp->if_obytes += m->m_pkthdr.len; } m_freem(m); if (!(inb(lpt_stat_port) & CLPIP_SHAKE)) { lprintf(("^")); lptintr(ifp->if_unit); } (void) splx(s); return 0; } if (inb(lpt_stat_port) & LPIP_SHAKE) { lprintf(("&")); lptintr(ifp->if_unit); } if (lpoutbyte(0x08, LPMAXSPIN1, lpt_data_port, lpt_stat_port)) goto end; if (lpoutbyte(0x00, LPMAXSPIN2, lpt_data_port, lpt_stat_port)) goto end; mm = m; do { cp = mtod(mm,u_char *); while (mm->m_len--) if (lpoutbyte(*cp++, LPMAXSPIN2, lpt_data_port, lpt_stat_port)) goto end; } while ((mm = mm->m_next)); err = 0; /* no errors were encountered */ end: --cp; outb(lpt_data_port, txmitl[*cp] ^ 0x17); if (err) { /* if we didn't timeout... */ ifp->if_oerrors++; lprintf(("X")); } else { ifp->if_opackets++; ifp->if_obytes += m->m_pkthdr.len;#if NBPFILTER > 0 if (ifp->if_bpf) { /* * We need to prepend the packet type as * a two byte field. Cons up a dummy header * to pacify bpf. This is safe because bpf * will only read from the mbuf (i.e., it won't * try to free it or keep a pointer to it). */ struct mbuf m0; u_short hdr = 0x800; m0.m_next = m; m0.m_len = 2; m0.m_data = (char *)&hdr; bpf_mtap(ifp, &m0); }#endif } m_freem(m); if (inb(lpt_stat_port) & LPIP_SHAKE) { lprintf(("^")); lptintr(ifp->if_unit); } (void) splx(s); return 0;}#endif /* INET */static lpt_devsw_installed = 0;static void lpt_drvinit(void *unused){ dev_t dev; if( ! lpt_devsw_installed ) { dev = makedev(CDEV_MAJOR, 0); cdevsw_add(&dev,&lpt_cdevsw, NULL); lpt_devsw_installed = 1; }}SYSINIT(lptdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,lpt_drvinit,NULL)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?