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 + -
显示快捷键?