📄 cs8900.c
字号:
BUSCTL_ENBL_IRQ | ( ( i_cnf & I_CNF_ANY_ISA_DMA ) ? BUSCTL_RST_RXDMA : 0 ) | BUSCTL_ENBL_MEM | 0x200 | /* Fix this ( ( i_cnf & I_CNF_SHARED ) ? BUSCTL_ENBL_MEM : 0 ) | */ ( ( i_cnf & I_CNF_ISA_DMA_64K ) ? BUSCTL_RX_DMA_64K : 0 ) ); if (cs8900->cfg.duplex){ cs8900_wpktpage ( iobase, CS8900_TESTCTL, TESTCTL_FDX); } return( 0 );}int cs8900_register_device( void *handle, io_net_self_t *ion, void *dll_hdl){ cs8900_dev_t *cs8900 = (cs8900_dev_t *)handle; pthread_attr_t pattr; pthread_mutexattr_t mattr; struct sched_param param; uint16_t lan;#if 0 timer_t timerid; struct sigevent event; struct itimerspec value;#endif cs8900->ion = ion; cs8900->dll_hdl = dll_hdl; if (cs8900_config(cs8900)) return (-1); if ((cs8900->chid = ChannelCreate(_NTO_CHF_DISCONNECT | _NTO_CHF_UNBLOCK)) == -1 || (cs8900->coid = ConnectAttach(0, 0, cs8900->chid, _NTO_SIDE_CHANNEL, 0)) == -1) { nic_slogf(_SLOGC_NETWORK, _SLOG_ERROR, "devn-crys8900: Unable to attach channel and connection"); return (-1); }#if 0 event.sigev_notify = SIGEV_PULSE; event.sigev_code = NIC_TIMER_EVENT; event.sigev_coid = cs8900->coid; event.sigev_priority = NIC_PRIORITY; if( timer_create( CLOCK_REALTIME, &event, &timerid ) == -1 ) { return( -1 ); } value.it_value.tv_sec = value.it_interval.tv_sec = 2; value.it_value.tv_nsec = value.it_interval.tv_nsec = 0; if( timer_settime( timerid, 0, &value, NULL ) == -1 ) { return( -1 ); }#endif pthread_mutexattr_init( &mattr ); mattr.flags = PTHREAD_RECURSIVE_ENABLE; if (pthread_mutex_init(&cs8900->mutex, &mattr) == -1) { nic_slogf(_SLOGC_NETWORK, _SLOG_ERROR, "devn-crys8900: Unable to initialize mutex"); return (-1); } pthread_attr_init(&pattr); pthread_attr_setschedpolicy(&pattr, SCHED_RR); param.sched_priority = cs8900->cfg.priority; pthread_attr_setschedparam(&pattr, ¶m); pthread_attr_setinheritsched(&pattr, PTHREAD_EXPLICIT_SCHED); cs8900->event.sigev_notify = SIGEV_PULSE; cs8900->event.sigev_coid = cs8900->coid; cs8900->event.sigev_code = NIC_INTERRUPT_EVENT; cs8900->event.sigev_priority = cs8900->cfg.priority; cs8900_initialize( cs8900 ); /* create the interface thread */ if (pthread_create(&cs8900->tid, &pattr, (void *)cs8900_driver_thread, cs8900)) { nic_slogf(_SLOGC_NETWORK, _SLOG_ERROR, "devn-crys8900: Unable to create driver thread"); return (-1); } cs8900_entry.func_hdl = (void *) cs8900; cs8900_entry.top_type = cs8900->cfg.uptype; if ( cs8900->cfg.lan != -1 ) { cs8900_entry.flags |= _REG_ENDPOINT_ARG ; lan = cs8900->cfg.lan; } if (ion_register(dll_hdl, &cs8900_entry, &cs8900->reg_hdl, &cs8900->cell, &lan) < 0) return (-1); if (!cs8900->max_pkts) cs8900->max_pkts = 100; cs8900->ion->devctl(cs8900->reg_hdl, DCMD_IO_NET_MAX_QUEUE, &cs8900->max_pkts, sizeof(cs8900->max_pkts), NULL); cs8900->cfg.lan = lan; if ((cs8900->iid = InterruptAttachEvent(cs8900->cfg.irq[0], &cs8900->event, _NTO_INTR_FLAGS_TRK_MSK)) == -1) { nic_slogf(_SLOGC_NETWORK, _SLOG_ERROR, "devn-crys8900: InterruptAttachEvent failed"); perror("InterruptAttachEvent failed\n"); return (-1); } return (0);}void cs8900_process_interrupt( void *handle ){ int status; int iobase; nic_ethernet_stats_t *estats; cs8900_dev_t *cs8900 = (cs8900_dev_t *)handle; estats = &cs8900->stats.un.estats; iobase = cs8900->iobase; while( cs8900->istat = status = inle16( iobase + CS8900_PORT_ISQ ) ) { switch( status & ISQ_EVENT_MASK ) { case ISQ_RXEVENT: cs8900_receive( cs8900 ); break; case ISQ_TXEVENT: cs8900_transmit_complete( cs8900 ); break; case ISQ_BUFEVENT: if( status & BUFEVENT_RXDMA ) { cs8900_receive( cs8900 ); } /* We check BusST Rdy4TxNow since revision B of the CS8920 */ /* has a problem where the Rdy4Tx interrupt may not occur */ /* every time when DMA is used for receive operation. */ if( ( status & BUFEVENT_RDY4TX ) || ( cs8900_rpktpage( iobase, CS8900_BUSST ) & BUSSTAT_RDY4TXNOW ) ) { cs8900_variant_load( cs8900 ); } if( status & BUFEVENT_TXUNDERRUN ) { estats->internal_tx_errors++; cs8900_transmit_complete( cs8900 ); } break; case ISQ_RXMISS: estats->internal_rx_errors += ( status >> 6 ); break; case ISQ_TXCOLL: estats->single_collisions += ( status >> 6 ); break; } } InterruptUnmask( cs8900->cfg.irq[0], cs8900->iid );}void cs8900_event_handler( void *handle ){ struct _pulse pulse; iov_t iov; int rcvid; cs8900_dev_t *cs8900 = (cs8900_dev_t *)handle; SETIOV( &iov, &pulse, sizeof( pulse ) ); while( 1 ) { if( ( rcvid = MsgReceivev( cs8900->chid, &iov, 1, NULL ) ) == -1 ) { if( errno == ESRCH ) { pthread_exit( NULL ); } continue; } pthread_mutex_lock( &cs8900->mutex ); switch( pulse.code ) { case NIC_INTERRUPT_EVENT: cs8900_process_interrupt( cs8900 ); break;/* case NIC_TIMER_EVENT: *//* cs8900_timer( cs8900 ); *//* break; */ default: if( rcvid ) { MsgReplyv( rcvid, ENOTSUP, &iov, 1 ); } break; } pthread_mutex_unlock( &cs8900->mutex ); }}void *cs8900_driver_thread( void *data ){ cs8900_event_handler( (cs8900_dev_t *)data ); return( NULL );}int cs8900_flush( int reg_hdl, void *hdl ){ cs8900_dev_t *cs8900 = (cs8900_dev_t *)hdl; npkt_t *npkt; npkt_t *tmp; pthread_mutex_lock( &cs8900->mutex ); npkt = cs8900->nhead; cs8900->nhead = cs8900->ntail = NULL; pthread_mutex_unlock( &cs8900->mutex ); for( ; npkt; npkt = tmp ) { tmp = npkt->next; ion_tx_complete(cs8900->reg_hdl, npkt); } return( 0 );}int cs8900_setup_multicast( void *handle ){ cs8900_dev_t *cs8900 = (cs8900_dev_t *)handle; uint8_t hash_table[8]; int linectl, iobase, i; iobase = cs8900->iobase; memset (hash_table, 0, sizeof(hash_table)); for (i = 0; i < CS8900_MULTICAST_ENTRIES; i++) { if (cs8900->multicast_counts[i]) hash_table[i >> 3] |= (1 << (i & 7)); } /* Disable the receiver */ linectl = cs8900_rpktpage( iobase, CS8900_LINECTL ); linectl &= ~LINECTL_RXON; cs8900_wpktpage( iobase, CS8900_LINECTL, linectl ); /* Program the Hash Table */ for (i = 0; i < 8; i++) { outle16(iobase + CS8900_PORT_PKTPG, CS8900_LAF + i); out8(iobase + CS8900_PORT_PKTPG_DATA, hash_table[i]); } /* Enable the receiver */ linectl |= LINECTL_RXON; cs8900_wpktpage(iobase, CS8900_LINECTL, linectl); return 0;}npkt_t *cs8900_alloc_npkt(void *handle, size_t size){ cs8900_dev_t *cs8900 = (cs8900_dev_t *) handle; npkt_t *npkt; net_buf_t *nb; net_iov_t *iov; char *ptr; if ((npkt = ion_alloc_npkt(sizeof(net_buf_t) + sizeof(net_iov_t), (void **) &nb)) == NULL) return (NULL); if ((ptr = ion_alloc(size, 0)) == NULL) { ion_free(npkt); return(NULL); } TAILQ_INSERT_HEAD(&npkt->buffers, nb, ptrs); iov = (net_iov_t *)(nb + 1); nb->niov = 1; nb->net_iov = iov; iov->iov_base = (void *) ptr; iov->iov_len = size; iov->iov_phys = (paddr_t)(ion_mphys(iov->iov_base)); npkt->org_data = ptr; npkt->next = NULL; npkt->tot_iov = 1; return (npkt);}int cs8900_advertise(int reg_hdl, void *func_hdl){ npkt_t *npkt; net_buf_t *nb; net_iov_t *iov; cs8900_dev_t *cs8900 = (cs8900_dev_t *) func_hdl; io_net_msg_dl_advert_t *ap; if ((npkt = ion_alloc_npkt(sizeof(*nb) + sizeof *iov, (void **)&nb)) == NULL) return(0); if ((ap = ion_alloc(sizeof(*ap), 0)) == NULL) { ion_free(npkt); return (0); } TAILQ_INSERT_HEAD(&npkt->buffers, nb, ptrs); iov = (net_iov_t *)(nb + 1); nb->niov = 1; nb->net_iov = iov; iov->iov_base = ap; iov->iov_len = sizeof *ap; memset(ap, 0x00, sizeof *ap); ap->type = _IO_NET_MSG_DL_ADVERT; ap->iflags = (IFF_SIMPLEX | IFF_BROADCAST | IFF_RUNNING); if (cs8900->cfg.flags & NIC_FLAG_MULTICAST) ap->iflags |= IFF_MULTICAST; ap->mtu_min = 0; ap->mtu_max = cs8900->cfg.mtu; ap->mtu_preferred = cs8900->cfg.mtu; strcpy(ap->up_type, cs8900->cfg.uptype); itoa(cs8900->cfg.lan, ap->up_type + 2, 10); strcpy(ap->dl.sdl_data, ap->up_type); ap->dl.sdl_len = sizeof(struct sockaddr_dl); ap->dl.sdl_family = AF_LINK; ap->dl.sdl_index = cs8900->cfg.lan; ap->dl.sdl_type = IFT_ETHER; ap->dl.sdl_nlen = strlen(ap->dl.sdl_data); /* not null terminated */ ap->dl.sdl_alen = 6; memcpy(ap->dl.sdl_data + ap->dl.sdl_nlen, cs8900->cfg.current_address, 6); npkt->org_data = ap; npkt->flags |= _NPKT_MSG; npkt->iface = 0; npkt->tot_iov = 1; npkt->framelen = sizeof *ap; if (ion_add_done( cs8900->reg_hdl, npkt, cs8900 ) == -1) { ion_free(ap); ion_free(npkt); return(0); } atomic_add(&cs8900->rx_active, 1); if (ion_rx_packets(cs8900->reg_hdl, npkt, 0, 0, cs8900->cell, cs8900->cfg.lan, 0) == 0) ion_tx_complete(cs8900->reg_hdl, npkt); return(0);}int cs8900_rpktpage( int iobase, int portno ){ outle16( iobase + CS8900_PORT_PKTPG, portno ); return( inle16( iobase + CS8900_PORT_PKTPG_DATA ) );}void cs8900_wpktpage( int iobase, int portno, int value ){ outle16( iobase + CS8900_PORT_PKTPG, portno ); outle16( iobase + CS8900_PORT_PKTPG_DATA, value );}#ifdef __X86__static const struct _8237_regs{ int maddr; /* memory address register */ int tcount; /* terminal count register */ int pagereg; /* dma page select register */ int stat; /* status register */ int mask; /* mask register */ int mode; /* mode register */ int sync_cmd; /* Synchronize HI/LOW register access */ int reset_cmd; /* Reset the 8237 */ int enable_cmd; /* enable all dma channels */ int set_mask; /* write mask register */} _8237_regtable[] = { /* addr count page stat/cmd mask mode sync rst enable wmask */ { 0x00, 0x01, 0x87, 0x08, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, { 0x02, 0x03, 0x83, 0x08, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, { 0x04, 0x05, 0x81, 0x08, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, { 0x06, 0x07, 0x82, 0x08, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, { 0xc0, 0xc2, 0x8f, 0xd0, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde }, { 0xc4, 0xc6, 0x8b, 0xd0, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde }, { 0xc8, 0xca, 0x89, 0xd0, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde }, { 0xcc, 0xce, 0x8a, 0xd0, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde }};#define DMA_READ 0x08 /* xfer memory to I/O device */#define DMA_WRITE 0x04 /* xfer I/O device to memory */void setup_8237( int mode, int chnl, paddr_t dptr, int cnt ){ const struct _8237_regs *dp; ushort_t page; ushort_t addr; dp = _8237_regtable + chnl; page = dptr >> 16; addr = dptr >> 1; if( chnl > 3 ) { chnl &= 3; cnt /= 2; } cnt--; out8( dp->mask, 0x04 | chnl ); out8( dp->sync_cmd, 0 ); /* reset flip flop */ out8( dp->mode, mode | chnl ); out8( dp->maddr, addr ); out8( dp->maddr, addr >> 8 ); out8( dp->pagereg, page ); out8( dp->tcount, cnt ); out8( dp->tcount, cnt >> 8 ); out8( dp->mask, chnl );}#endif/***************************************************************************** All multicast processing. ****************************************************************************/int cs8900_do_multicast (cs8900_dev_t *cs8900, struct _io_net_msg_mcast *msg, int *ret){ return (ENOTSUP);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -