Please wait until the page is fully downloaded and then press the "Expand" button or the blue line numbers.

0113000 /*
0113001  * tc589d.c
0113002  *
0113003  * This file contains a PCMCIA ethernet device driver for the 3com 3c589D
0113004  * ethernet pc card.
0113005  *
0113006  * The valid messages and their parameters are:
0113007  *
0113008    * m_type        DL_PORT DL_PROC DL_COUNT DL_MODE DL_ADDR
0113009  * |------------+----------+---------+----------+---------+---------|
0113010    * | HARDINT       | | | | | |
0113011  * |------------|----------|---------|----------|---------|---------|
0113012    * | DL_WRITE       | port nr | proc nr | count | mode | address |
0113013  * |------------|----------|---------|----------|---------|---------|
0113014    * | DL_WRITEV       | port nr | proc nr | count | mode | address |
0113015  * |------------|----------|---------|----------|---------|---------|
0113016    * | DL_READV       | port nr | proc nr | count | | address |
0113017  * |------------|----------|---------|----------|---------|---------|
0113018    * | DL_INIT       | port nr | proc nr | mode | | address |
0113019  * |------------|----------|---------|----------|---------|---------|
0113020    * | DL_GETSTAT       | port nr | proc nr | | | address |
0113021  * |------------|----------|---------|----------|---------|---------|
0113022    * | DL_STOP       | port_nr | | | |        |
0113023  * |------------|----------|---------|----------|---MM------|---------|
0113024  *
0113025  * The messages sent are:
0113026  *
0113027    * m-type        DL_POR T DL_PROC DL_COUNT DL_STAT DL_CLCK
0113028  * |------------|----------|---------|----------|---------|---------|
0113029  * |DL_TASK_REPL| port nr | proc nr | rd-count | err|stat| clock |
0113030  * |------------|----------|---------|----------|---------|---------|
0113031  *
0113032    * m_type        m3_i1 m3_i2 m3_ca1
0113033  * |------------+---------+-----------+---------------|
0113034  * |DL_INIT_REPL| port nr | last port | ethernet addr |
0113035  * |------------|---------|-----------|---------------|
0113036  *
0113037    * Created:       Oct 2004 by Wangzhi <quakewang@mail.whut.edu.cn>
0113038  * Reference: rtl8139.c by Philip Homburg
0113039      *               3c589_cs.c by Donald Becker
0113040  *
0113041  */
0113042 
0113043 #include "kernel.h"
0113044 
0113045 #include <stdlib.h>
0113046 #include <minix/com.h>
0113047 #include <ibm/portio.h>
0113048 #include <net/hton.h>
0113049 #include <net/gen/ether.h>
0113050 #include <net/gen/eth_io.h>
0113051 
0113052   /* The following "#if ENABLE_TC589" is important, if we do not define        *
0113053      * ENABLE_TC589, this file will not be compile into kernel              */
0113054 #if ENABLE_TC589
0113055 
0113056   /* for timer, but not used, Philip did not remove them, so me too       */
0113057       #define tmra_ut                     timer_t
0113058   #define tmra_inittimer(tp)       tmr_inittimer(tp)
0113059     #define Proc_number(p)              proc_number(p)
0113060       #define debug                     0
0113061     #define RAND_UPDATE              /**/
0113062     #define printW()              ((void)0)
0113063     #define vm_1phys2bus(p)              (p)
0113064 
0113065 #include "assert.h"
0113066 #include "proc.h"
0113067 #include "tc589d.h"
0113068 /* after this we can use "assert" */
0113069 INIT_ASSERT
0113070 
0113071 /* 3C589D Lan PC card's info */
0113072 typedef struct tc
0113073 {
0113074            /* many fields here are same as the rtl8139 driver              */
0113075          port_t tc_base_port;        /* 3C589D card's I/O base */
0113076            int tc_irq;              /* 3C589D card's irq */
0113077            int tc_mode;              
0113078          int tc_flags;
0113079          int tc_client;
0113080          int tc_link_up;
0113081          int tc_got_int;
0113082          int tc_send_int;
0113083          int tc_report_link;
0113084          int tc_clear_rx;
0113085          int tc_need_reset;
0113086          int tc_tx_alive;
0113087          char *tc_model;
0113088          int tc_done;
0113089          int tc_myflags;
0113090 
0113091            /* Rx, this struct is used to record all the packets               *
0113092               * which are stored in the RX queue buffer                      */
0113093          struct
0113094          {
0113095                   int busy;       /* used? */
0113096                   int pack_len;       /* packet length */
0113097                   phys_bytes pack_buf;        /* packet start address in queue */
0113098          } tc_rx_buf[N_RX_BUF];
0113099          vir_bytes tc_read_s;
0113100          int tc_rx_busy;       
0113101          int rhead;       /* queue head point */       
0113102          int whead;       /* queue tail point */
0113103 
0113104          /* Tx */
0113105          struct
0113106          {
0113107                   int busy;
0113108                   int pack_len;
0113109                   phys_bytes pack_buf;
0113110          } tc_tx_buf[NR_TX_BUF];       
0113111          u32_t tc_ertxth;       /* Early Tx Threshold */
0113112            int tc_tx_busy;              
0113113            int tx_rhead;              /* queue head point */       
0113114            int tx_whead;              /* queue tail point */       
0113115 
0113116          /* 'large' items */
0113117          irq_hook_t tc_hook;       /* interrupt hook */
0113118          eth_stat_t tc_stat;
0113119          ether_addr_t tc_address;
0113120          message tc_rx_mess;       /* can queue a read message        */
0113121          message tc_tx_mess;       /* can queue a write message        */
0113122          char tc_name[sizeof("tc589#n")];
0113123          iovec_t tc_iovec[IOVEC_NR];
0113124 }
0113125 tc_t;
0113126 
0113127 /* each card has a info structure */
0113128 tc_t tc_table[TC_PORT_NR];
0113129 
0113130         /* here is the same as the rtl8139 driver                            */
0113131 static int tc_tasknr= ANY;
0113132 static tmra_ut tc_watchdog;
0113133 
0113134     /* Macro, just look like a function, used to read/write a port              */
0113135   #define tc_inb(port, offset)       (inb((port) + (offset)))
0113136   #define tc_inw(port, offset)       (inw((port) + (offset)))
0113137   #define tc_inl(port, offset)       (inl((port) + (offset)))
0113138   #define tc_outb(port, offset, value)       (outb((port) + (offset), (value)))
0113139   #define tc_outw(port, offset, value)       (outw((port) + (offset), (value)))
0113140   #define tc_outl(port, offset, value)       (outl((port) + (offset), (value)))
0113141 
0113142 /* Declare functions used in this file */
0113143         _PROTOTYPE( static void tc_init, (message *mp)                            );
0113144         _PROTOTYPE( static void tc_init_buf, (tc_t *tcp)                            );
0113145       _PROTOTYPE( static void tc_rec_mode, (tc_t *tcp)                     );
0113146 _PROTOTYPE( static void tc_readv, (message *mp, int from_int,
0113147                                                  int vectored)       );
0113148 _PROTOTYPE( static void tc_writev, (message *mp, int from_int,
0113149                                                  int vectored)       );
0113150       _PROTOTYPE( static void tc_check_ints, (tc_t *tcp)                     );
0113151       _PROTOTYPE( static void tc_report_link, (tc_t *tcp)                     );
0113152       _PROTOTYPE( static void tc_getstat, (message *mp)                     );
0113153   _PROTOTYPE( static void reply, (tc_t *tcp, int err, int may_block)       );
0113154   _PROTOTYPE( static void mess_reply, (message *req, message *reply)       );
0113155 _PROTOTYPE( static void put_userdata, (int user_proc,
0113156                   vir_bytes user_addr, vir_bytes count, void *loc_addr)       );
0113157 
0113158       _PROTOTYPE( static int tc_handler, (irq_hook_t *hookp)                     );
0113159 #if __minix_vmd
0113160   _PROTOTYPE( static void tc_watchdog_f, (tmra_ut *tp, tmr_arg_ut arg)       );
0113161 #else
0113162       _PROTOTYPE( static void tc_watchdog_f, (timer_t *tp)                     );
0113163 #endif
0113164 
0113165         _PROTOTYPE( static void init_pcard, (tc_t *tcp)                            );
0113166 static int read_eeprom(short ioaddr, int index);
0113167 static void wait_for_completion(tc_t *tcp, int cmd);
0113168 void out_reg(int socket, u8_t index, u8_t value);
0113169 void tc589_dump(void);
0113170 static void pop_tx_status(void);
0113171 
0113172 /*===========================================================================*
0113173          *                            tc589d_task                             *
0113174  *===========================================================================*/
0113175   /* this function do some initialization at first, then he go into a endless        *
0113176    * loop, he wait for a message and do something according to the message type       *
0113177  */
0113178 void tc589d_task(void)
0113179 {
0113180          message m;
0113181          int i, r;
0113182          tc_t *tcp;
0113183          long v;
0113184 
0113185          /* get this task's process id */
0113186          tc_tasknr= Proc_number(proc_ptr);
0113187 
0113188          /* Claim buffer memory now, before Memory manage takes it all. */
0113189          for (tcp= &tc_table[0]; tcp < tc_table+TC_PORT_NR; tcp++){
0113190                   tc_init_buf(tcp);       
0113191          }
0113192 
0113193          /* endless loop */
0113194          while (TRUE){
0113195                   /* wait for a message from anywhere */
0113196                   if ((r= receive(ANY, &m)) != OK)
0113197                            panic("3c589d: receive failed", r);
0113198 
0113199                   /* do something according to the message type */
0113200                   switch (m.m_type) {
0113201                            case DL_WRITEV:       tc_writev(&m, FALSE, TRUE);       break;
0113202                            case DL_WRITE:       tc_writev(&m, FALSE, FALSE);       break;
0113203                            case DL_READV:       tc_readv(&m, FALSE, TRUE);       break;
0113204                            case DL_INIT:       tc_init(&m);                     break;
0113205                            case DL_GETSTAT: tc_getstat(&m);              break;
0113206                            
0113207                            /* hardware interupt. minix turn everything into message,       *
0113208                             * in minix, a device interrupt handler turn a hardware        *
0113209                             * interrupt into a message to evoke his driver                     *
0113210                                 */                                   
0113211                            case HARD_INT:
0113212                                     tcp= &tc_table[0]; /* minix can only handle one card */
0113213                                     tcp->tc_got_int= 0; /* this interrupt is handled */
0113214                                     assert(tcp->tc_flags & REF_ENABLED);
0113215 
0113216                                     /* check this interrupt is for what */
0113217                                     tc_check_ints(tcp);              
0113218                                     break;
0113219                            default:
0113220                                     panic("3c589d: illegal message", m.m_type);
0113221                   }/* switch */
0113222          }/* while */
0113223 }
0113224 
0113225 /*===========================================================================*
0113226          *                            tc589_dump                             *
0113227  *===========================================================================*/
0113228  /* dump network card's status (when press F5)*/
0113229 void tc589_dump(void)
0113230 {
0113231          tc_t *tcp;
0113232          int i;
0113233 
0113234          printf(" ");
0113235          tcp = &tc_table[0];       /* minix can only handle one card */
0113236          
0113237            /* if system do not find a useable card                              */
0113238          if (tcp->tc_mode == REM_DISABLED)
0113239                   printf("tc589 port %d is disabled ", i);
0113240          if (tcp->tc_mode != REM_ENABLED)
0113241                   return;
0113242 
0113243                /* now print every status of the card                             */
0113244          printf("tc589 statistics of port %d: ", 0);
0113245          printf("recvErr :%8ld       ", tcp->tc_stat.ets_recvErr);
0113246          printf("sendErr :%8ld       ", tcp->tc_stat.ets_sendErr);
0113247          printf("OVW :%8ld ", tcp->tc_stat.ets_OVW);
0113248 
0113249          printf("CRCerr :%8ld       ", tcp->tc_stat.ets_CRCerr);
0113250          printf("frameAll :%8ld       ", tcp->tc_stat.ets_frameAll);
0113251          printf("missedP :%8ld ", tcp->tc_stat.ets_missedP);
0113252 
0113253          printf("packetR :%8ld       ", tcp->tc_stat.ets_packetR);
0113254          printf("packetT :%8ld       ", tcp->tc_stat.ets_packetT);
0113255          printf("transDef :%8ld ", tcp->tc_stat.ets_transDef);
0113256 
0113257          printf("collision :%8ld       ", tcp->tc_stat.ets_collision);
0113258          printf("transAb :%8ld       ", tcp->tc_stat.ets_transAb);
0113259          printf("carrSense :%8ld ", tcp->tc_stat.ets_carrSense);
0113260 
0113261          printf("fifoUnder :%8ld       ", tcp->tc_stat.ets_fifoUnder);
0113262          printf("fifoOver :%8ld       ", tcp->tc_stat.ets_fifoOver);
0113263          printf("CDheartbeat:%8ld ", tcp->tc_stat.ets_CDheartbeat);
0113264 
0113265          printf("OWC :%8ld       ", tcp->tc_stat.ets_OWC);
0113266 
0113267          printf("re_flags = 0x%x ", tcp->tc_flags);
0113268 }
0113269 
0113270 /*===========================================================================*
0113271            *                            tc_init                                    *
0113272  *===========================================================================*/
0113273   /* This is a very important function! And this is the first message this driver       *
0113274    * will receive. After minix kernel setup and begin to run, this driver only do       *
0113275    * a little thing(alloc the buffers), the PC card do not begin to work. When        *
0113276  * the INET network server is started at last, INET will send a INIT message to *
0113277  * this driver and tell driver and the PC card prepare to work. Then this driver*
0113278    * will try to detect and configure the PC card, if all is ok, he will tell       *
0113279    * INET the PC card is ready, and then PC card can receive and send packets       *
0113280  */
0113281 static void tc_init(mp)
0113282 message *mp;
0113283 {
0113284          /* the initialization can only be done once, more will crash your system*/
0113285          static int first_time=1;
0113286 
0113287          int port;
0113288          tc_t *tcp;
0113289          message reply_mess;
0113290          int ioaddr;
0113291 
0113292          /* port? In simple is which card, some minix can handle more than one        *
0113293           * card */
0113294          port = mp->DL_PORT;
0113295          if (port < 0 || port >= TC_PORT_NR) /* bad port */
0113296          {
0113297                   reply_mess.m_type= DL_INIT_REPLY;
0113298                   reply_mess.m3_i1= ENXIO;
0113299                   mess_reply(mp, &reply_mess);
0113300                   return;
0113301          }
0113302          
0113303            /* every card has his structure, very big and very important,               *
0113304                   * you can find everything in it                                    *
0113305           */       
0113306          tcp= &tc_table[port];
0113307          
0113308          /* init pc card only once */       
0113309          if(first_time){
0113310                   first_time= 0;       
0113311                   /* init card, many steps, see below! */
0113312                   init_pcard(tcp);
0113313                   
0113314                   /* report 10M network card and set some registers              */
0113315                   tc_report_link(tcp);       
0113316          } /* first_time */       
0113317 
0113318              /* make sure the card is good and everything is ok                     */
0113319          assert(tcp->tc_mode == REM_ENABLED);
0113320          assert(tcp->tc_flags & REF_ENABLED);
0113321 
0113322          /* see INET want to receive which kind packet, certainly anyone want to       *
0113323           * receive the packet which send to him(the MAC address is the same as
0113324           * his own).
0113325           */
0113326          tcp->tc_flags &= ~(REF_PROMISC | REF_MULTI | REF_BROAD);
0113327          if (mp->DL_MODE & DL_PROMISC_REQ)
0113328                   tcp->tc_flags |= REF_PROMISC;       /* All */
0113329          if (mp->DL_MODE & DL_MULTI_REQ)
0113330                   tcp->tc_flags |= REF_MULTI;       /* mutil broadcast */
0113331          if (mp->DL_MODE & DL_BROAD_REQ)
0113332                   tcp->tc_flags |= REF_BROAD;       /* broadcast */
0113333 
0113334          /* let driver know INET's process id */
0113335          tcp->tc_client = mp->m_source;
0113336 #if 0
0113337          printf("tcp->tc_client tc_init [%d][%d] ", tcp->tc_client, tc_table[0].tc_client);
0113338 #endif
0113339 
0113340          /* set card to receive which kind packet */
0113341          tc_rec_mode(tcp); /* rxFilter */
0113342 
0113343          /* reply the message INIT */
0113344          reply_mess.m_type = DL_INIT_REPLY;
0113345          reply_mess.m3_i1 = mp->DL_PORT;
0113346          reply_mess.m3_i2 = TC_PORT_NR;
0113347 
0113348          /* MAC address of the card, very important! INET will add it to every packet       *
0113349           * sended from this card, and use it to see weather a packet is for this        *
0113350               * card, any wrong you may not receive any useful packet!                     *
0113351           */
0113352          *(ether_addr_t *) reply_mess.m3_ca1 = tcp->tc_address;
0113353 
0113354            /* send INIT reply message to INET, do not let INET wait too long,               *
0113355           * although INET is JUST a server.
0113356           */
0113357          mess_reply(mp, &reply_mess);
0113358 
0113359          return;
0113360 }
0113361 
0113362 /*===========================================================================*
0113363          *                            tc_init_buf                             *
0113364  *===========================================================================*/
0113365       /* alloc almost all big memory buffer used in the driver                     *
0113366  */
0113367 static void tc_init_buf(tcp)
0113368 tc_t *tcp;
0113369 {
0113370          size_t rx_bufsize, tx_bufsize, tot_bufsize;
0113371          phys_bytes buf;
0113372          int i;
0113373          phys_clicks tot_clicks;
0113374          struct memory *memp;
0113375 
0113376 
0113377          /* Total buffer size, RX+TX */
0113378          tx_bufsize= TC589_TX_BUFSIZE;
0113379          rx_bufsize= TC589_RX_BUFSIZE;
0113380          tot_bufsize= tx_bufsize + rx_bufsize;
0113381            /* translate it into clicks, minix use this to alloc memory               */
0113382          tot_clicks = (tot_bufsize + CLICK_SIZE-1) >> CLICK_SHIFT;
0113383 
0113384          /* Allocate buffers, all free system memory are stored in mem array       *
0113385           * they are seperated into several blocks, 0--640K, 640--1M, 1M--XXX       *
0113386           */
0113387          memp= &mem[NR_MEMS];
0113388          
0113389              /* find a big enough block to alloc the buffer in it                      *
0113390           */
0113391          while ((--memp)->size < tot_clicks) {
0113392                   if (memp == mem) panic("No memory for tc589 buffers",NO_NUM);
0113393          }
0113394          
0113395          /* the alloced memory is at the end of original free memory block       */
0113396          memp->size -= tot_clicks;
0113397          
0113398                /* the just alloced memory start address                             */
0113399          buf= (phys_bytes) (memp->base + memp->size) << CLICK_SHIFT;
0113400          
0113401          /* initialize Rx Buffer, get the Rx buffer from the just alloced memory */       
0113402          tc_rx_mem_start= buf;
0113403          tc_rx_mem_end= buf + N_RX_BUF*RX_BUF_BLOCK;
0113404          /* init all the Rx items, all the same */
0113405          for (i= 0; i<N_RX_BUF; i++)       {
0113406                   tcp->tc_rx_buf[i].pack_buf= buf;
0113407                   tcp->tc_rx_buf[i].pack_len= 0;
0113408                   tcp->tc_rx_buf[i].busy= 0;
0113409          }
0113410          
0113411          /* the rest alloced memory is for TX */
0113412          buf += rx_bufsize;        
0113413          /* initialize Tx Buffer items, are NOT all the same, each TX buffer item*
0113414                 * has a small block. See "<--" statements                            *
0113415           */
0113416          for (i= 0; i<NR_TX_BUF; i++)       {
0113417                   tcp->tc_tx_buf[i].pack_buf= buf;        /* <-- */
0113418                   tcp->tc_tx_buf[i].pack_len= 0;
0113419                   tcp->tc_tx_buf[i].busy= 0;
0113420                     buf += TX_BUF_BLOCK;                      /* <-- */
0113421          }
0113422 }
0113423 
0113424 /*===========================================================================*
0113425          *                            tc_rec_mode                             *
0113426  *===========================================================================*/
0113427  /* tell 3C589D to receive which kind packets */
0113428 static void tc_rec_mode(tcp)
0113429 tc_t *tcp;
0113430 {
0113431          int ioaddr;
0113432          
0113433          /* PC card I/O base address */
0113434          ioaddr= tcp->tc_base_port;
0113435          
0113436          /* set the PC card to different receive mode according to the        *
0113437             * tcp->tc_flags, INIT message set the tcp->tc_flags              *       
0113438           */
0113439          if (tcp->tc_flags & REF_PROMISC){
0113440                   tc_outw(ioaddr, EL3_CMD,
0113441                            SetRxFilter | RxStation | RxMulticast |
0113442                                     RxBroadcast | RxProm);
0113443           }else if (tcp->tc_flags & REF_MULTI){
0113444                   tc_outw(ioaddr, EL3_CMD, SetRxFilter | RxStation|RxMulticast|RxBroadcast);
0113445           }else{
0113446                   tc_outw(ioaddr, EL3_CMD, SetRxFilter | RxStation | RxBroadcast);
0113447          }
0113448          
0113449          return;       
0113450 }
0113451 
0113452 /*===========================================================================*
0113453          *                            tc_readv                             *
0113454  *===========================================================================*/
0113455 static void tc_readv(mp, from_int, vectored)
0113456 message *mp;
0113457 int from_int;
0113458 int vectored;
0113459 {
0113460          int i, j, n, o, s, s1, port, tc_client, count, size;
0113461          unsigned amount, totlen, packlen;
0113462          phys_bytes src_phys, dst_phys, iov_src;
0113463          u16_t d_start, d_end;
0113464          u32_t l, rxstat;
0113465          tc_t *tcp;
0113466          iovec_t *iovp;
0113467          /* added */
0113468          int worklimit = 32;
0113469           short status;        
0113470           phys_bytes tc_rx_buf;
0113471           char *rx_buf;
0113472           static int disp_count= 0;
0113473           int ioaddr;
0113474           static int first=0;
0113475          phys_bytes phys_user;
0113476           
0113477 #if 0
0113478          printf("%s,from_int?[0x%x] who[0x%x] ", "readv", from_int, mp->DL_PROC);
0113479 #endif
0113480 
0113481          /* port? In simple is which card, some minix can handle more than one        *
0113482           * card */
0113483          port = mp->DL_PORT;
0113484            if (port < 0 || port >= TC_PORT_NR){              
0113485                   panic("tc589d: illegal port(readv)", port);
0113486          }
0113487          
0113488          /* get this PC card's tc_table structure, all info in it */
0113489          tcp= &tc_table[port];
0113490                   
0113491          /* which process send this message? (mp->DL_PROC) */
0113492          tc_client= mp->DL_PROC;
0113493 
0113494          /* Pay attention! This count is NOT the bytes that this read message        *
0113495           * want to read! This count is this read message want to fill how many        *
0113496           * tcp->tc_iovec[] structures, in other words, this read message contain*
0113497           * how many this read message structures. Each tcp->tc_iovec[] structure*
0113498           * will read a part of a packet.
0113499           */
0113500          count = mp->DL_COUNT;
0113501          
0113502          /* PC card I/O base address */
0113503          ioaddr= tcp->tc_base_port;       
0113504 
0113505 #if 0
0113506          printf("dst procaaaa[%d][%d] ", tcp->tc_client, tc_table[0].tc_client);
0113507 #endif
0113508 
0113509              /* make sure the card is good and everything is ok                     */
0113510          assert(tcp->tc_mode == REM_ENABLED);
0113511          assert(tcp->tc_flags & REF_ENABLED);
0113512 
0113513          /* "!from_int" indicate that this message is not come from receiving        *
0113514           * a packet(just now), so this message is come from INET, which want to *
0113515           * read a buffer.                                                  *
0113516           * "tcp->rhead == tcp->whead", this indicate RX buffer is empty.        *
0113517           *
0113518           * When will a just receiving packet come to here?
0113519           * When INET wanted to read a packet and can not read one just now,       *
0113520           * then a packet arrived, then driver will come here to satisfy INET       *
0113521           * with this just arrived packet.
0113522           *
0113523           * Normal, INET will send a read message and come here. If the RX       *
0113524           * buffer is empty, INET must wait a momnet.
0113525           */
0113526          if (!from_int && (tcp->rhead == tcp->whead))
0113527          {
0113528                   /* Receive buffer is empty, suspend */
0113529                   goto suspend;
0113530          }
0113531 
0113532          /* the received packet's length */
0113533          packlen= tcp->tc_rx_buf[tcp->rhead].pack_len;
0113534 #if 0
0113535          printf("tcp->rhead[%d]whead[%d]plen[%d]", tcp->rhead, tcp->whead, packlen);
0113536   #endif        
0113537 
0113538          /* source addr of packet(in memory) */
0113539          src_phys= tcp->tc_rx_buf[tcp->rhead].pack_buf;
0113540          
0113541          /* now this packet will be handled, then we can handle the next one       */
0113542          tcp->rhead= (tcp->rhead + 1) % N_RX_BUF;
0113543 
0113544          /* "o" is a val(temp) */
0113545          o= 0;
0113546              /* "vectored" indicate this message is make up of many                      *
0113547           * tcp->tc_iovec[] structures, now every read message is this kind       *
0113548           */
0113549          if (vectored)
0113550          {
0113551                   /* init some val */
0113552                   size= 0;
0113553                   
0113554                   /* many(count) "tcp->tc_iovec[] structures" want to be filled,        *
0113555                    * they are in the INET memory space, now we run in protected        *
0113556                    * mode, each process has his own memory space, they all       *
0113557                    * start from address "0", the memory address we used in        *
0113558                    * process is process address space, we must translate it into        *
0113559                    * physical address space, use numap() deal with it. Then we can*
0113560                    * read/write to it, because we are driver and we are in kernel       *
0113561                    */
0113562                   iov_src = numap(tc_client, (vir_bytes)mp->DL_ADDR,
0113563                            count * sizeof(tcp->tc_iovec[0]));
0113564                   if (!iov_src)
0113565                            panic("tc589: umap failed(readv)", NO_NUM);
0113566                            
0113567                   /* handle each vector("tcp->tc_iovec[] structures") in               *
0113568                      * message(count), one loop fill one of them.                      *
0113569                    * One time just copy IOVEC_NR "tcp->tc_iovec[] structures"       *
0113570                    * to kernel memory space and handle them. Why? because        *
0113571                    * the buffer in kernel(tcp->tc_iovec[]) can only hold               *
0113572                    * IOVEC_NR "tcp->tc_iovec[] structures" a time.              *
0113573                   */
0113574                   for (i= 0; i<count; i += IOVEC_NR,
0113575                            iov_src += IOVEC_NR * sizeof(tcp->tc_iovec[0]))
0113576                   {
0113577                            /* do not copy more, just count! */
0113578                            n= IOVEC_NR;
0113579                            if (i+n > count)
0113580                                     n= count-i;
0113581                            /* copy vectors from message to tc_table */
0113582                            phys_copy(iov_src, vir2phys(tcp->tc_iovec),
0113583                                     n * sizeof(tcp->tc_iovec[0]));
0113584 
0113585                            /* fill each vector with packet data */
0113586                            for (j= 0, iovp= tcp->tc_iovec; j<n; j++, iovp++)
0113587                            {
0113588                                     /* this "tcp->tc_iovec[] structure" will hold        *
0113589                                      * how many packet data? iovp->iov_size              *
0113590                                      */                            
0113591                                     s= iovp->iov_size;
0113592                                     
0113593                                     /* the LAST "tcp->tc_iovec[] structure" can        *
0113594                                      * hold packet data less than he declared       *
0113595                                      */
0113596                                     if (size + s > packlen)
0113597                                     {
0113598                                              assert(packlen > size);
0113599                                              /* do not have asked bytes(less) */
0113600                                              s= packlen-size;
0113601                                     }
0113602 
0113603                                     /* get the destination addr from each structure       *
0113604                                      */
0113605                                     dst_phys = numap(tc_client, iovp->iov_addr, s);
0113606                                     if (!dst_phys)
0113607                                              panic("tc589: umap failed ", NO_NUM);
0113608                                              
0113609                                     /* copy a part of the packet to each structure */
0113610                                     phys_copy(src_phys+o, dst_phys, s);
0113611                                     
0113612                                     /* step forward */
0113613                                     size += s;
0113614                                     
0113615                                     /* OK, this read request is satisfied!              */
0113616                                     if (size == packlen)
0113617                                              break;
0113618                                     /* step forward in packet data */
0113619                                     o += s;
0113620                            }/* end of for (j= 0 */
0113621                            
0113622                            /* OK, this read request is satisfied!              */
0113623                            if (size == packlen)
0113624                                     break;
0113625                            /* else:
0113626                             * maybe there are other "tcp->tc_iovec[] structures"        *
0113627                             */
0113628                   }/* end of for (i= 0 */
0113629 
0113630                   /* Some error occured!! */
0113631                   if (size < packlen)
0113632                   {
0113633                            printf("%s!!!!!!!!!!!!!!!!!! ", "size<packlen");
0113634                            assert(size<packlen);
0113635                   }
0113636          }/* end of if (vectored) */
0113637 
0113638          /* this(tcp->tc_read_s) will send back to INET to tell how many bytes       *
0113639           * are read this time.
0113640           */
0113641          tcp->tc_read_s = packlen;
0113642          
0113643          /* set the new flags. very important! many important things in this        *
0113644                 * driver act according to the tc_flags.                            *
0113645           * (tcp->tc_flags & ~REF_READING) indicate: now INET is not wait        *
0113646           * for a packet.                                                 *
0113647           * REF_PACK_RECV indicate: we just satisfy INET a read packet request.       *
0113648           */
0113649          tcp->tc_flags= (tcp->tc_flags & ~REF_READING) | REF_PACK_RECV;
0113650 
0113651          /* if INET send a read message and come here, we must reply INET here        *
0113652           * if "from_int" we will do with it at other place.
0113653           */
0113654          if (!from_int){
0113655                   reply(tcp, OK, FALSE);
0113656          }
0113657 
0113658          return;
0113659 
0113660 suspend:
0113661          /* this is strange, normal this can not occur. */
0113662          if (from_int){
0113663                   /* No need to store any state */
0113664                   return;
0113665          }
0113666 
0113667            /* INET want to read a packet, but the RX buffer is empty.              */
0113668          tcp->tc_rx_mess= *mp;
0113669          
0113670              /* REF_READING indicate: INET is waiting for a packet                     */
0113671          tcp->tc_flags |= REF_READING;
0113672 
0113673          /* this just make INET be able to do other things, otherwise he will        *
0113674           * hang on receiving this message.
0113675           */
0113676          reply(tcp, OK, FALSE);
0113677 }
0113678 
0113679 /*===========================================================================*
0113680          *                            tc_writev                             *
0113681  *===========================================================================*/
0113682 static void tc_writev(mp, from_int, vectored)
0113683 message *mp;
0113684 int from_int;
0113685 int vectored;
0113686 {
0113687          phys_bytes p, t_c_tx_buf, iov_src, phys_user, pack_src;
0113688          phys_bytes src_phys, dst_phys;
0113689          int i, j, n, s, port, count, size;
0113690          int tx_head, tc_client;
0113691          tc_t *tcp;
0113692          iovec_t *iovp;       
0113693          char *tx_buf;
0113694          int ioaddr;
0113695          
0113696          /* port? In simple is which card, some minix can handle more than one        *
0113697           * card */
0113698          port = mp->DL_PORT;
0113699          if (port < 0 || port >= TC_PORT_NR)
0113700                   panic("tc589: illegal port", port);              
0113701          
0113702          /* get this PC card's tc_table structure, all info in it */       
0113703          tcp= &tc_table[0];
0113704          
0113705          /* which process send this message? (mp->DL_PROC) */       
0113706          tc_client= mp->DL_PROC;
0113707 
0113708                  /* this count has two probability.                                   *
0113709               * the first: the same as the tc_readv() function.                     *
0113710           * the second: indicate the bytes want to be sent.
0113711           */
0113712          count = mp->DL_COUNT;
0113713          
0113714          /* PC card I/O base address */
0113715          ioaddr= tcp->tc_base_port;       
0113716          
0113717          /* called from interrupt: indicate TX available! we can send other        *
0113718           * packets now.
0113719           */
0113720          if (from_int)
0113721          {
0113722                   tcp->tc_send_int= FALSE;
0113723                   
0113724                   /* come here is not easy, surely only a good PC card and        *
0113725                    * a good PC card driver can do this.
0113726                    */
0113727                   tcp->tc_tx_alive= TRUE;
0113728 
0113729                   /* send buffered packets now */
0113730                   goto send_pcak;
0113731          }       
0113732          
0113733          /* only INET call can go to here! */
0113734          /* Tx Buffer is full? */
0113735          if(((tcp->tx_whead + 1)%NR_TX_BUF) == tcp->tx_rhead){
0113736                   /* this packet is dropped. */
0113737                   tcp->tc_flags &= ~REF_PACK_SENT;
0113738                   goto suspend;
0113739          }else{
0113740                   /* you see, I am very confident, Now I think this packet will        *
0113741                    * be send, all the folling will be ok. Let's pray.
0113742                    */
0113743                   tcp->tc_flags |= REF_PACK_SENT;
0113744          }
0113745          tcp->tc_flags |= REF_PACK_SENT;
0113746                   
0113747           /* temporarily buffer for the writing packet */
0113748           p= tcp->tc_tx_buf[tcp->tx_whead].pack_buf;
0113749           
0113750              /* "vectored" indicate this message is make up of many                      *
0113751               * tcp->tc_iovec[] structures.                                           *
0113752           * if NOT "vectored" indicate this message contain the packet totally       *
0113753           */
0113754          if (vectored)
0113755          {
0113756                   /* init some val */
0113757                   size= 0;
0113758                   
0113759                   /* many(count) "tcp->tc_iovec[] structures" want to be sent,        *
0113760                    * they are in the INET memory space, now we run in protected        *
0113761                    * mode, each process has his own memory space, they all       *
0113762                    * start from address "0", the memory address we used in        *
0113763                    * process is process address space, we must translate it into        *
0113764                    * physical address space, use numap() deal with it. Then we can*
0113765                    * read/write to it, because we are driver and we are in kernel       *
0113766                    */
0113767                   iov_src = numap(tc_client, (vir_bytes)mp->DL_ADDR,
0113768                            count * sizeof(tcp->tc_iovec[0]));
0113769                   if (!iov_src)
0113770                            panic("tc589: umap failed(writev)", NO_NUM);
0113771 
0113772                   /* handle each vector("tcp->tc_iovec[] structures") in               *
0113773                      * message(count), one loop fill one of them.                      *
0113774                    * One time just copy IOVEC_NR "tcp->tc_iovec[] structures"       *
0113775                    * to kernel memory space and handle them. Why? because        *
0113776                    * the buffer in kernel(tcp->tc_iovec[]) can only hold               *
0113777                    * IOVEC_NR "tcp->tc_iovec[] structures" a time.              *
0113778                   */
0113779                   for (i= 0; i<count; i += IOVEC_NR,
0113780                            iov_src += IOVEC_NR * sizeof(tcp->tc_iovec[0]))
0113781                   {
0113782                            /* compute the vector counts will be processed this time */
0113783                            n= IOVEC_NR;
0113784                            if (i+n > count)
0113785                                     n= count-i;
0113786                                     
0113787                            /* copy vectors from message to tc_table */
0113788                            phys_copy(iov_src, vir2phys(tcp->tc_iovec),
0113789                                     n * sizeof(tcp->tc_iovec[0]));
0113790                            
0113791                            /* process each vector */
0113792                            for (j= 0, iovp= tcp->tc_iovec; j<n; j++, iovp++)
0113793                            {
0113794                                     /* this "tcp->tc_iovec[] structure" hold        *
0113795                                      * how many packet data? iovp->iov_size              *
0113796                                      */
0113797                                     s= iovp->iov_size;
0113798                                     
0113799                                     /* we can not make any packet bigger than the MAX packet. */
0113800                                     if (size + s > ETH_MAX_PACK_SIZE_TAGGED)
0113801                                     {
0113802                                              panic("tc589: invalid packet size",
0113803                                                     NO_NUM);
0113804                                     }
0113805                                     
0113806                                     /* get the source address from each structure       *
0113807                                      */       
0113808                                     phys_user = numap(tc_client, iovp->iov_addr, s);
0113809                                     if (!phys_user)
0113810                                              panic("tc589: umap failed ", NO_NUM);
0113811                                              
0113812                                     /* copy each structure's data to the packet */
0113813                                     phys_copy(phys_user, p, s);
0113814                                     
0113815                                     /* step forward */
0113816                                     size += s;
0113817                                     
0113818                                     /* step forward in packet(constructing) */
0113819                                     p += s;
0113820                                }/* end of for (j= 0 */                                                         
0113821                   }/* end of for (i= 0 */
0113822                   
0113823                   /* size right? do not too small TOO!*/
0113824                   if (size < ETH_MIN_PACK_SIZE)
0113825                            panic("tc589: invalid packet size(too small!!!)", size);       
0113826                            
0113827          }else /* if (vectored) */
0113828          { /* This message hold A packet */
0113829                   
0113830                   /* mp->DL_COUNT is packet length */
0113831                   size= mp->DL_COUNT;
0113832                   
0113833                   /* size right? */
0113834                   if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE_TAGGED)
0113835                            panic("tc589: invalid packet size", size);
0113836                   
0113837                   /* get the source address from the message       *
0113838                    */       
0113839                   phys_user = numap(tc_client, (vir_bytes)mp->DL_ADDR, size);
0113840                   if (!phys_user)
0113841                              panic("tc589: umap failed(writev sigle) ", NO_NUM);                            
0113842                   phys_copy(phys_user, p, size);
0113843          }/* end of if (vectored)(else) */
0113844          
0113845          /* this packet length */
0113846          tcp->tc_tx_buf[tcp->tx_whead].pack_len= size;
0113847          
0113848          /* step forward in queue */
0113849          tcp->tx_whead= (tcp->tx_whead + 1)%NR_TX_BUF;       
0113850          
0113851 send_pcak: /* now really ask the PC card to send the packet. */
0113852 
0113853          /* try to send all the packet which wanted to be sent. */
0113854          for(;tcp->tx_rhead != tcp->tx_whead;){
0113855                   
0113856                   /* get the packets' length which was stored in "pack_len" ago */              
0113857                   size= tcp->tc_tx_buf[tcp->tx_rhead].pack_len;
0113858                   
0113859                   /* get this packet's start memory address */
0113860                   pack_src= tcp->tc_tx_buf[tcp->tx_rhead].pack_buf;
0113861                   
0113862                   /* Does card Tx FIFO have enough free space? Why must "+4"?       *
0113863                    * It is for some other info PC card have to know to send        *
0113864                    * the packet.                                                 *
0113865                    */
0113866                   if (tc_inw(ioaddr, TX_FREE) >= (size+4)) {
0113867                            /* free enough, ok, send this packet to card */
0113868                            tcp->tc_tx_busy= 0;
0113869                   } else{
0113870                            /* free buffer not enough for this packet */
0113871                            /* Interrupt us when the Tx FIFO has enough room for this packet. */
0113872                            tc_outw(ioaddr, EL3_CMD, SetTxThreshold + (size + 4));
0113873                            tcp->tc_tx_busy= 1; /* Tx FIFO is busy now */
0113874                            
0113875                            /* if come from "INT" do not need reply! */
0113876                            if(!from_int)
0113877                                     goto suspend;
0113878                     }                     
0113879          
0113880                   /* send this packet when Tx FIFO is free enough */
0113881                   if(tcp->tc_tx_busy == 0){
0113882                            /* disable IRQ, then PC card can not generate a interrupt        *
0113883                             * until I reenable it. Maybe we need not do this, but              *
0113884                             * I am very concentrative when I do some things; and I        *
0113885                             * found if a interrupt come when I do the following thing       *
0113886                             * my PC card always go wrong; at least, after I did this       *
0113887                                 * my PC card work almost ok.                                   *
0113888                             */
0113889                            disable_irq(&tcp->tc_hook);
0113890 
0113891                            /* Put out the doubleword header..., some info to tell PC card       *
0113892                             * you must reference the 3C589D specification to understand it       *
0113893                             */
0113894                            tc_outw(ioaddr, TX_FIFO, size);
0113895                            tc_outw(ioaddr, TX_FIFO, 0x00);
0113896                                              
0113897                            /* Send this Packet! write the packet to PC card's TX FIFO        *       
0113898                             * Why "size+1"? I think it is a bug in minix, I will tell        *
0113899                             * Kees.J.Bot. This "phys_outsw" function indicate he will       *
0113900                             * send a word(two bytes) a time, but he do not think              *
0113901                             * "size + 1" is the count of words he will send, he just       *
0113902                             * think "size + 1" is the bytes he will send, and in               *
0113903                             * "phys_outsw", "size + 1" will be divided by 2, then he get        *
0113904                             * how many bytes he will write to the port.                     *
0113905                             *                                                         *
0113906                             * I have a painful experience to this "phys_outsw", I               *
0113907                             * always send to this function the words I want to send,       *
0113908                             * but my card just can not send a packet(correct packet),       *
0113909                             * at last I use "sniffer" and I found my card send two        *
0113910                             * packets(after he send many many many), I took a very close       *
0113911                             * look at this two packets, I found the former half part of        *
0113912                             * all the packets my PC card sent is correct, but from the        *        
0113913                             * middle of the packets, all are wrong, then I really        *
0113914                             * understand HOW to use "phys_outsw" function.                     *
0113915                             */
0113916                            phys_outsw(ioaddr+TX_FIFO, pack_src, size + 1);
0113917                            
0113918                            /* added the packet to a doubleword boundary */       
0113919                            if(( (size+1)/2)%2 == 1){
0113920                                     tc_outw(ioaddr, TX_FIFO, 0x0000);
0113921                            }                     
0113922 
0113923                            /* check the TX status, and do some thing to recover it when *
0113924                             * it go wrong.
0113925                             */
0113926                            pop_tx_status();
0113927                            
0113928                            /* enable PC card's IRQ */
0113929                            enable_irq(&tcp->tc_hook);
0113930                   }/* if */
0113931                   
0113932                   /* Now go to send the next buffered packet */
0113933                   tcp->tx_rhead= ((tcp->tx_rhead + 1)%NR_TX_BUF);
0113934          }/* for */
0113935 
0113936          /* If the interrupt handler called, don't send a reply. The reply       *
0113937             * will be sent after all interrupts are handled. But if INET               *
0113938             * called, send the reply here, all the same, just at different              *
0113939             * place.                                                        *
0113940           */
0113941          if (from_int){
0113942                   return;
0113943          }       
0113944          reply(tcp, OK, FALSE);
0113945          
0113946          return;
0113947 
0113948 suspend:
0113949          /* I just let INET do all the complex things, maybe Tx buffer is full       *
0113950           * and this packet is dropped, but I do not do any thing to info       *
0113951           * INET, I just do as usually. I know INET will found he can not       *
0113952             * receive this packet's reply, and he will resend this packet.              *
0113953           * Philip did this, INET want me to do so, so I do it.
0113954           */
0113955          reply(tcp, OK, FALSE);
0113956 }
0113957 
0113958 /*===========================================================================*
0113959          *                            tc_check_ints                             *
0113960  *===========================================================================*/
0113961    /* This function is important, he deal with the interrupt the second time.       *
0113962    * the first time is in "tc_handler()".                                          *
0113963  */
0113964 static void tc_check_ints(tcp)
0113965 tc_t *tcp;
0113966 {
0113967  int status;
0113968  int i = 0;
0113969  int re_flags;
0113970  int worklimit;
0113971  int packlen;
0113972  int ioaddr;
0113973 
0113974           /* this PC card's important status is in "tc_flags" */
0113975           re_flags= tcp->tc_flags;
0113976           
0113977           /* PC card I/O base address */
0113978           ioaddr = tcp->tc_base_port;
0113979 
0113980          /* this is mine, not Philip's. I save some important PC card status        *
0113981               * when I fitst receive this interrupt in "tc_handler".                     *
0113982           */
0113983           status = tcp->tc_myflags;
0113984          
0113985          /* "(status & MY_RXCOMPLETE)" indicate PC card just received a packet.       *
0113986           * "(tcp->tc_flags & REF_READING)" indicate INET is just waiting for       *
0113987           * a packet.
0113988           * If all are TRUE, we must send this packet to INET by call tc_readv()       *
0113989           */
0113990          if ((status & MY_RXCOMPLETE) && (tcp->tc_flags & REF_READING)){
0113991                   
0113992                   /* all readv message type from INET is "DL_READ" */
0113993                      if (tcp->tc_rx_mess.m_type == DL_READV)                     {
0113994                            tc_readv(&tcp->tc_rx_mess, TRUE /* from int */,
0113995                                              TRUE /* vectored */);
0113996                   }              
0113997                   /* Why NOT Acknowledge the IRQ??
0113998                    * because this kind interrupt(received a packet) is not        *
0113999                    * Acknowledge in normal way. When you read the packet from        *
0114000                    * the RX FIFO you will Acknowledge it. See specification.       *
0114001                    */
0114002                   
0114003           }/* if (status & RxComplete) */
0114004           
0114005           /* When PC card'd TX FIFO has enough room again, we will get this        *
0114006            * "MY_TVCOMPLETE" status. Now we can send waiting packets again       *
0114007            * by call tc_writev().                                                 *        
0114008            */
0114009            if (status & MY_TVCOMPLETE) {                      
0114010                   /* There's room in the FIFO for a full-sized packet. */
0114011                   tc_writev(&tcp->tc_tx_mess, TRUE /* from int */,
0114012                                     0 /* not used */);
0114013                   /* Acknowledge the IRQ, then we can receive this interrupt again */
0114014                   tc_outw(ioaddr, EL3_CMD, AckIntr | TxAvailable);
0114015          }
0114016          
0114017          /* When the tc_readv() or tc_writev() is called from here, they will       *
0114018           * send reply here.                                                 *
0114019           */
0114020           if(tcp->tc_flags & (REF_PACK_RECV))
0114021                    reply(tcp, OK, TRUE);
0114022                    
0114023           return;
0114024 }
0114025 
0114026 /*===========================================================================*
0114027          *                            tc_report_link                             *
0114028  *===========================================================================*/
0114029   /* This function is set the PC card's mode 10M/100M, turns on the LED etc        *
0114030      * you must see the specification, tell you the truth, I have seen the               *
0114031      * specification, but I can not understand all of it, this part of code              *
0114032            * is referenced linux 3C589D card driver.                                   *
0114033  */
0114034 static void tc_report_link(tcp)
0114035 tc_t *tcp;
0114036   {       
0114037           int ioaddr;
0114038           u16_t media, errs;
0114039           long flags;
0114040           
0114041           /* PC card I/O base address */
0114042           ioaddr = tcp->tc_base_port;
0114043 
0114044           EL3WINDOW(1);
0114045           /* Check for pending interrupt with expired latency timer: with
0114046           this, we can limp along even if the interrupt is blocked */
0114047           if ((tc_inw(ioaddr, EL3_STATUS) & IntLatch) &&
0114048                            (tc_inb(ioaddr, EL3_TIMER) == 0xff)) {
0114049                   printf("tc_report_link(tcp) interrupt(s) dropped! ");
0114050          }
0114051           
0114052  EL3WINDOW(4);
0114053           media = tc_inw(ioaddr, WN4_MEDIA) & 0xc810;
0114054 
0114055           /* Ignore collisions unless we've had no irq's recently */
0114056          EL3WINDOW(6);
0114057          tc_outw(ioaddr, EL3_CMD, StatsDisable);
0114058          errs = tc_inb(ioaddr, 0);
0114059          tc_outw(ioaddr, EL3_CMD, StatsEnable);
0114060          if (errs) media |= 0x0010;
0114061 
0114062           if (media & 0x8000) {
0114063                   if (media & 0x0800)
0114064                            ;
0114065                   else
0114066                           EL3WINDOW(0);
0114067                             switch (1) {
0114068                             case 0: case 1: tc_outw(ioaddr, 6, 0); break;
0114069                             case 2: tc_outw(ioaddr, 6, 3<<14); break;
0114070                             case 3: tc_outw(ioaddr, 6, 1<<14); break;
0114071                             }
0114072                             /* 10baseT interface, enable link beat and jabber check. */
0114073                             EL3WINDOW(4);
0114074                             tc_outw(ioaddr, WN4_MEDIA, MEDIA_TP);
0114075                             /* On PCMCIA, this just turns on the LED */
0114076                             tc_outw(ioaddr, EL3_CMD, StopCoax);
0114077                             EL3WINDOW(1);                      
0114078 
0114079           }
0114080           if (media & 0x4000) {
0114081                   if (media & 0x0010)
0114082                            ;
0114083                   else
0114084                    printf("flipped to 10base2 ");
0114085           }       
0114086 
0114087  /* Always keep in windows 1 */
0114088           EL3WINDOW(1);
0114089           
0114090          return;       
0114091 }
0114092 
0114093 /*===========================================================================*
0114094          *                            tc_getstat                             *
0114095  *===========================================================================*/
0114096 /* INET want to get PC card's status */
0114097 static void tc_getstat(mp)
0114098 message *mp;
0114099 {
0114100          int port;
0114101          eth_stat_t stats;
0114102          tc_t *tcp;
0114103 
0114104          /* port? In simple is which card, some minix can handle more than one        *
0114105           * card */
0114106          port = mp->DL_PORT;
0114107            if (port < 0 || port >= TC_PORT_NR){              
0114108                   panic("tc589d: illegal port(readv)", port);
0114109          }
0114110          
0114111          /* get this PC card's tc_table structure, all info in it */
0114112          tcp= &tc_table[port];
0114113          lock();       /* Do not let interrupt handler updates stats */
0114114          stats= tcp->tc_stat;
0114115          unlock();
0114116          
0114117          /* just copy the status data to the mp->DL_ADDR address */
0114118          put_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
0114119                   (vir_bytes) sizeof(stats), &stats);
0114120 
0114121          /* reply the INET */
0114122          reply(tcp, OK, FALSE);
0114123 }
0114124 
0114125 
0114126 /*===========================================================================*
0114127            *                            reply                                    *
0114128  *===========================================================================*/
0114129 /* send reply to the INET */
0114130 static void reply(tcp, err, may_block)
0114131 tc_t *tcp;
0114132 int err;
0114133 int may_block;
0114134 {
0114135          message reply;
0114136          int status;
0114137          int r;
0114138 
0114139          /* Reform reply message status, because the flags used in PC card driver        *
0114140           * is not the same as the flags used in INET.
0114141           */
0114142          status = 0;
0114143          
0114144          /* tell INET just send a packet */
0114145          if (tcp->tc_flags & REF_PACK_SENT)
0114146                   status |= DL_PACK_SEND;
0114147                   
0114148          /* tell INET just read a packet */
0114149          if (tcp->tc_flags & REF_PACK_RECV)
0114150                   status |= DL_PACK_RECV;
0114151 
0114152          /* fill the fields of the packet */
0114153          reply.m_type = DL_TASK_REPLY;
0114154          reply.DL_PORT = 0;       /* minix just can have a network card */
0114155          reply.DL_PROC = tcp->tc_client;       /* this message send to who? */
0114156          reply.DL_STAT = status | ((u32_t) err << 16);       /* status + err */
0114157          reply.DL_COUNT = tcp->tc_read_s;       /* the bytes deal with this time */
0114158          reply.DL_CLCK = get_uptime();       /* time(now) */
0114159 
0114160          /* really send this message to its destination process */
0114161          r= send(tcp->tc_client, &reply);
0114162 
0114163          /* this message is blocked? you run in BIG problem or you have VERY bad luck       *
0114164             * to tell you the truth, this is too profound to me, I am studing it.              *
0114165               */                     
0114166          if (r == ELOCKED && may_block)
0114167          {
0114168                   printW(); printf("send locked ");
0114169                   return;
0114170          }
0114171 
0114172          /* send error, BIG problem */
0114173          if (r < 0)
0114174                   panic("tc589d: send failed:", r);
0114175          
0114176          /* reset some very important vals */
0114177          tcp->tc_read_s = 0;
0114178          tcp->tc_flags &= ~(REF_PACK_SENT | REF_PACK_RECV);
0114179 }
0114180 
0114181 
0114182 
0114183 /*===========================================================================*
0114184          *                            mess_reply                             *
0114185  *===========================================================================*/
0114186 /* a simply reply */
0114187 static void mess_reply(req, reply_mess)
0114188 message *req;
0114189 message *reply_mess;
0114190 {
0114191          if (send(req->m_source, reply_mess) != OK)
0114192                   panic("tc589: unable to mess_reply", NO_NUM);
0114193 }
0114194 
0114195 /*===========================================================================*
0114196          *                            put_userdata                             *
0114197  *===========================================================================*/
0114198   /* copy the data from the kernel memory to process memory, only be used in       *
0114199    * tc_getstat().                                                        *
0114200  */
0114201 static void put_userdata(user_proc, user_addr, count, loc_addr)
0114202 int user_proc;
0114203 vir_bytes user_addr;
0114204 vir_bytes count;
0114205 void *loc_addr;
0114206 {
0114207          phys_bytes dst;
0114208 
0114209          dst = numap(user_proc, user_addr, count);
0114210          if (!dst)
0114211                   panic("tc589: umap failed", NO_NUM);
0114212 
0114213          phys_copy(vir2phys(loc_addr), dst, (phys_bytes) count);
0114214 }
0114215 
0114216 
0114217 /*===========================================================================*
0114218          *                            tc_handler                             *
0114219  *===========================================================================*/
0114220 /* This PC card driver's interrupt handler! */
0114221 static int tc_handler(hookp)
0114222 irq_hook_t *hookp;
0114223 {
0114224          int i, port, tx_head, tx_tail, link_up;
0114225          u16_t isr, tsad;
0114226          u32_t tsd, tcr, ertxth;
0114227          tc_t *tcp;
0114228          struct micro_state ms;
0114229          int ioaddr;
0114230          int status, rx_status;
0114231          int packlen;
0114232          phys_bytes phys_user, dst_phys;
0114233          int old_whead;
0114234          int badPack=0;
0114235 
0114236          /* no use */
0114237          RAND_UPDATE
0114238 
0114239          /* this is very important and a little difficult. get the tc_table[]        *       
0114240             * field when receive a interrrupt. You must know the interrupt              *
0114241                   * how to implement to understand it.                                    *
0114242           * but I have a easy way: see Philip how to do it, do it like him.       *
0114243           * this method always works.                                          *
0114244           */
0114245          tcp= structof(tc_t, tc_hook, hookp);
0114246          
0114247          /* PC card I/O base address */
0114248          ioaddr= tcp->tc_base_port;
0114249          
0114250          /* flags of mine */
0114251          tcp->tc_myflags = 0;
0114252          
0114253          /* read PC card's status register to know what has happened? */
0114254           status= tc_inw(ioaddr, EL3_STATUS);
0114255 
0114256          /* PC card has problem! */
0114257          if ((status & 0xe000) != 0x2000) {
0114258                   printf("%s: interrupt from dead card status[%d] ", "tc_handler", status);       
0114259 
0114260                   return 1; /* Reenable interrupt! */
0114261          }
0114262 
0114263          /* get rid of the unuseful bits, then every bit in the status has its meaning */
0114264           status= status& 0xff;
0114265          
0114266          /* deal with each bit in status */       
0114267          
0114268          /* There's room in the FIFO for a full-sized packet. */
0114269            if (status & TxAvailable) {                      
0114270                    /* remove this bit from status(already done) */
0114271                    status &= ~TxAvailable;               
0114272                    
0114273                    
0114274                    /* "!tcp->tc_got_int" protect call "interrupt(tc_tasknr)" many              *
0114275                     * times a time.                                                 *
0114276                     */
0114277                      if (!tcp->tc_got_int){                                     
0114278                             tcp->tc_got_int= TRUE;                             
0114279                                               
0114280                             /* tell the "tc_check_ints()" this good news */
0114281                            tcp->tc_tx_busy= 0;
0114282                             tcp->tc_myflags |= MY_TVCOMPLETE;        
0114283 
0114284                             /* this will generate a message, and this PC card driver       *
0114285                              * will receive a message from "int", then "tc_check_ints()"       *
0114286                              * will be called.                                          *
0114287                              */              
0114288                            interrupt(tc_tasknr);               
0114289                   }
0114290                   
0114291                   /* Acknowledge the IRQ, then we can receive this interrupt again */
0114292                   tc_outw(ioaddr, EL3_CMD, AckIntr | TxAvailable);       
0114293          }
0114294          
0114295          /* send packet complete */
0114296          if (status & TxComplete){
0114297                   
0114298                   /* remove this bit from status(already done) */
0114299                   status &= ~TxComplete;       
0114300                   
0114301                   /* check and update the status */
0114302                   pop_tx_status();
0114303          }
0114304          
0114305          /* status of the PC card */
0114306            if (status & StatsFull){              
0114307           /* remove this bit from status(already done) */       
0114308           status &= ~StatsFull;       
0114309          
0114310           /* Switch to the stats window, and clear all stats by reading.        *
0114311           * see specification.
0114312           */
0114313                  tc_outw(ioaddr, EL3_CMD, StatsDisable);
0114314                    EL3WINDOW(6);
0114315                    for (i = 0; i < 9; i++)
0114316                            tc_inb(ioaddr, i);
0114317                    tc_inw(ioaddr, 10);
0114318                    tc_inw(ioaddr, 12);        
0114319                    EL3WINDOW(1);/* Switch to register set 1 for normal use. */
0114320                    tc_outw(ioaddr, EL3_CMD, StatsEnable); /* Turn on statistics. */
0114321                    
0114322                    /* Acknowledge the IRQ, then we can receive this interrupt again */
0114323                    tc_outw(ioaddr, EL3_CMD, AckIntr | StatsFull);
0114324          }
0114325          
0114326          /* Rx early is unused. */
0114327            if (status & RxEarly) {              
0114328                   /* remove this bit from status(already done) */       
0114329                   status &= ~RxEarly;              
0114330                   
0114331                   /* Acknowledge the IRQ, then we can receive this interrupt again */
0114332                   tc_outw(ioaddr, EL3_CMD, AckIntr | RxEarly);
0114333          }
0114334          
0114335          /* PC card failed! see specification.*/
0114336          if (status & AdapterFailure) {
0114337                   u16_t fifo_diag;
0114338                   
0114339                   /* remove this bit from status(already done) */       
0114340                   status &= ~AdapterFailure;       
0114341          
0114342                   EL3WINDOW(4);
0114343                   fifo_diag = inw(ioaddr + 4);
0114344                   EL3WINDOW(1);
0114345                   printf("adapter failure, FIFO diagnostic register %04x. ", fifo_diag);
0114346                   if (fifo_diag & 0x0400) {
0114347                            /* Tx overrun */
0114348                            wait_for_completion(tcp, TxReset);
0114349                            tc_outw(ioaddr, EL3_CMD, TxEnable);
0114350                   }
0114351                   if (fifo_diag & 0x2000) {
0114352                            /* Rx underrun */
0114353                            wait_for_completion(tcp, RxReset);
0114354                            
0114355                            if (tcp->tc_flags & REF_PROMISC)
0114356                                     tc_outw(ioaddr, EL3_CMD,
0114357                                     SetRxFilter | RxStation | RxMulticast |
0114358                                              RxBroadcast | RxProm);
0114359                            else if (tcp->tc_flags & REF_MULTI)
0114360                                     tc_outw(ioaddr, EL3_CMD, SetRxFilter|
0114361                                              RxStation|RxMulticast|RxBroadcast);
0114362                             else
0114363                                     tc_outw(ioaddr, EL3_CMD, SetRxFilter | RxStation | RxBroadcast);
0114364                            
0114365                            tc_outw(ioaddr, EL3_CMD, RxEnable);
0114366                   }
0114367                   
0114368                   /* Acknowledge the IRQ, then we can receive this interrupt again */
0114369                   tc_outw(ioaddr, EL3_CMD, AckIntr | AdapterFailure);
0114370          }
0114371                   
0114372          /* received a packet */
0114373          if (status & RxComplete)
0114374          {
0114375                   /* remove this bit from status(already done) */       
0114376                   status &= ~RxComplete;
0114377                   
0114378                   /* received packet ++ */
0114379                   tcp->tc_stat.ets_packetR++;
0114380                   
0114381                   /* get packet length */
0114382                   rx_status= tc_inw(ioaddr, RX_STATUS);
0114383                   packlen= rx_status & 0x7ff;
0114384 
0114385                   if(packlen < 60){ /* check packet length */
0114386                            badPack= 1;
0114387                            printf("bad pack!!! ");
0114388                            /* bad packet!!! */
0114389                   /* Now we get the just arriving packet from the Rx FIFO to system       *
0114390                    * memory.                                                        *
0114391                    * it has two probability:                                          *
0114392                    * 1. the RX buffer is full: this packet is dropped, and missedP++,        *              
0114393                    * 2. the RX buffer is free enough: read the packet through the RX FIFO       *
0114394                    */
0114395                   }else if(((tcp->tc_rx_buf[tcp->whead].pack_buf + ((packlen +
0114396                                                      RX_BUF_BLOCK)/RX_BUF_BLOCK)*RX_BUF_BLOCK) >=
0114397                                     tcp->tc_rx_buf[tcp->rhead].pack_buf)&&
0114398                                     (tcp->tc_rx_buf[tcp->whead].pack_buf <
0114399                                     tcp->tc_rx_buf[tcp->rhead].pack_buf)){
0114400                            /* Rx buffer full! */
0114401                            tcp->tc_stat.ets_missedP++;
0114402                         } else { /* 2 */                                   
0114403                   
0114404                              /* save the packet length */                            
0114405                            tcp->tc_rx_buf[tcp->whead].pack_len= packlen;
0114406                            
0114407                            /* read the packet from the Rx FIFO to local buf                      *
0114408                                 * I do NOT like this phys_insw too.                                   *       
0114409                             */                     
0114410                            phys_insw(ioaddr+RX_FIFO, tcp->tc_rx_buf[tcp->whead].pack_buf, packlen+1);
0114411 
0114412                            /* RX buffer go to the next */
0114413                            old_whead= tcp->whead;
0114414                            tcp->whead= (tcp->whead + 1) % N_RX_BUF;
0114415                            
0114416                            /* compute the next RX buffer packet's start address */
0114417                            tcp->tc_rx_buf[tcp->whead].pack_buf= tcp->tc_rx_buf[old_whead].pack_buf +
0114418                                                        ((tcp->tc_rx_buf[old_whead].pack_len +
0114419                                                        RX_BUF_BLOCK)/RX_BUF_BLOCK)*RX_BUF_BLOCK;
0114420                            
0114421                            /* ringed queue, come to end then go from start again */
0114422                            if(tcp->tc_rx_buf[tcp->whead].pack_buf >= tc_rx_mem_end){
0114423                                     tcp->tc_rx_buf[tcp->whead].pack_buf= tc_rx_mem_start;
0114424                            }
0114425                   }
0114426                   
0114427                   /* remove this packet from the RX FIFO */
0114428                   wait_for_completion(tcp, RxDiscard);       
0114429 
0114430                   /* "(tcp->tc_flags & REF_READING)": INET is wait for this packet       *
0114431                     * "!badPack": good packet.
0114432                     */
0114433                    if((tcp->tc_flags & REF_READING) && !badPack){
0114434                             /* tell tc_check_ints() received a packet */
0114435                            tcp->tc_myflags |= MY_RXCOMPLETE;                      
0114436                    }
0114437                    
0114438                    /* "!tcp->tc_got_int" protect call "interrupt(tc_tasknr)" many              *
0114439                     * times a time.                                                 *
0114440                     */
0114441                   if (!tcp->tc_got_int){
0114442                              tcp->tc_got_int= TRUE;                            
0114443                                              
0114444                            /* this will generate a message, and this PC card driver       *
0114445                              * will receive a message from "int", then "tc_check_ints()"       *
0114446                              * will be called.                                          *
0114447                              */              
0114448                            interrupt(tc_tasknr);
0114449                   }
0114450 
0114451                   /* Acknowledge the IRQ, then we can receive this interrupt again */
0114452                   tc_outw(ioaddr, EL3_CMD, AckIntr | RxComplete);
0114453          }
0114454          
0114455          /* these status we do not care */
0114456          status &= ~IntLatch;
0114457          status &= ~IntReq;
0114458 
0114459          /* if when we come here we still have some interrrupt waiting to be deal with       *
0114460           * some thing must go wrong, so info us.
0114461           */
0114462          if (status){
0114463                   printf("tc_handler: unhandled interrupt: status = 0x%04x ",
0114464                            status);
0114465          }
0114466 
0114467          /* Acknowledge this bit, then we can receive INTERRUPT again */
0114468          tc_outw(ioaddr, EL3_CMD, AckIntr | IntLatch);
0114469 
0114470          /* Reenable interrupt! when we receive a interrrupt, system disable        *
0114471           * any other interrupts from the same IRQ.
0114472           */
0114473          return 1;
0114474 }
0114475 
0114476 /*===========================================================================*
0114477          *                            tc_watchdog_f                             *
0114478  *===========================================================================*/
0114479  /* no use here*/
0114480 static void tc_watchdog_f(tp)
0114481 timer_t *tp;
0114482 {
0114483          int i;
0114484          tc_t *tcp;
0114485 
0114486          tmr_arg(&tc_watchdog)->ta_int= 0;
0114487          tmr_settimer(&tc_watchdog, CLOCK, get_uptime()+HZ, tc_watchdog_f);
0114488 
0114489          if (tcp->tc_mode != REM_ENABLED)
0114490                   return;
0114491          if (!(tcp->tc_flags & REF_SEND_AVAIL))
0114492          {
0114493                   /* Assume that an idle system is alive */
0114494                   tcp->tc_tx_alive= TRUE;
0114495                   return;
0114496          }
0114497          if (tcp->tc_tx_alive)
0114498          {
0114499                   tcp->tc_tx_alive= FALSE;
0114500                   return;
0114501          }
0114502            printf("rl_watchdog_f: resetting port %d ", i);              
0114503          tcp->tc_need_reset= TRUE;
0114504          tcp->tc_got_int= TRUE;
0114505          interrupt(tc_tasknr);
0114506 
0114507          return;
0114508 }
0114509 
0114510 
0114511   /* Very important! This function initialize the PC card. Make it ready        *
0114512  * to work, and initialize many variables.
0114513    * To know how to initialize the PC card 3C589D you must read its       *
0114514      * specification. I read it many times and I can not initialize              *
0114515    * my 3C589D card properly, this initialization just make the card       *
0114516    * can work(every time on my laptop, but someone tested it and said        *
0114517      * this initialization did not work every time, but in a word,               *
0114518    * this initialization can make 3C589D PC card work, try several times       *
0114519      * if it can't make your card work, tell me! BUT, remember! if               *
0114520      * it can make your 3C589D PC card work, tell me too!!!)              *
0114521  */
0114522 static void init_pcard(tc_t *tcp)
0114523 {
0114524          int ioaddr;
0114525          static char env_var_fmt[]= "x:d";
0114526          long v, env_iobase, env_irq;
0114527          int i, j;
0114528          u16_t edata;
0114529 
0114530          /* try to get iobase and irq value from "boot parameter"        *
0114531           * What is "boot parameter"? they are before minix boot,       *
0114532           * you press "ESC" key and come to the monitor, then you        *
0114533           * type "set" command, you will see all the "boot parameter"       *
0114534           * and you can set your "boot parameter", you just input       *
0114535           * something like "xxx=yyy", then you set your "boot parameter"       *
0114536                 * "xxx", and it has value "yyy".                            *
0114537             * here your maybe will set "boot parameter" like:              *
0114538             * "TC589D=0x400:6"                                          *
0114539           * but I do not suggest you do that, because default value is        *
0114540           * usually works.                                          *       
0114541           */
W: I cannot find this listed as a default value in the specification. Why do you call it the "default". I did find where _io_base is set to 0x300 in a script on page 92, but I don't really understand where they got this value.


0114542          
0114543          /* Get the I/O base address!                                          */       
0114544          if(env_parse(ENV_VAR, env_var_fmt, 0, &v, 0x0000, 0xffff) == EP_SET){
0114545                   /* TC589D var is set */
0114546                   env_iobase= v;              
0114547          }else{
0114548                   /* TC589D var is not set, use default */
0114549                   env_iobase= 0x300;
0114550          }       
0114551          
0114552          /* Get the interrupt number!                                          */
0114553          if(env_parse(ENV_VAR, env_var_fmt, 1, &v, 0, 15) == EP_SET){
0114554                   /* TC589D var is set */
0114555                   env_irq= v;              
0114556          }else{
0114557                   /* TC589D var is not set, use default */
0114558                   env_irq= 5;
0114559          }       
0114560 
0114561          /* Very important! Reading MAC addresses from card's eeprom, and        *
0114562                 * and save it in "tcp->tc_address.ea_addr".                             *
0114563           */
0114564          printf("%s:", "Reading MAC addresses from card's eeprom");
0114565          for(i=0; i<0x3; i++){
0114566                   edata= read_eeprom(env_iobase, i);
0114567                   tcp->tc_address.ea_addr[i*2+1]= (u8_t)edata;
0114568                   tcp->tc_address.ea_addr[i*2]= (u8_t)(edata>>8);
0114569          }
0114570 
0114571          /* 3c589d PC card I/O port and irq */
0114572              tcp->tc_base_port = env_iobase;                     
0114573          tcp->tc_irq = env_irq;
0114574          
0114575          /* initialize the tc_table[] array */
0114576          tcp->tc_link_up= 0;       /* Unknown */
0114577          tcp->tc_got_int= 0;
0114578          tcp->tc_send_int= 0;
0114579          tcp->tc_report_link= 0;
0114580          tcp->tc_clear_rx= 0;
0114581          tcp->tc_need_reset= 0;
0114582          tcp->tc_tx_alive= 0;
0114583          tcp->tc_read_s= 0;
0114584          tcp->tc_rx_busy= 0;
0114585          tcp->tc_tx_busy= 0;
0114586          tcp->tc_done= 1;
0114587          tcp->rhead= 0;
0114588          tcp->whead= 0;
0114589          tcp->tc_myflags= 0;
0114590          tcp->tx_whead= 0;
0114591          tcp->tx_rhead= 0;       
0114592          tcp->tc_mode == REM_ENABLED;       
0114593          
0114594          
0114595          ioaddr = tcp->tc_base_port;       
0114596 
0114597          /* The following initialize the 3C589D PC card! MUST read        *
0114598           * specification.                                          *
0114599           */
0114600           EL3WINDOW(0);
0114601               tc_outw(ioaddr, 0x4, 0x0001);                     /* Activate board. */        
0114602          /* must be irq 3(12-15), must be f(8-11), must be 0(0-7) */
0114603 
0114604          /* set address reg and resource reg */
0114605          EL3WINDOW(0);
0114606          tc_outw(ioaddr, 0x06, 0x0000);       
W: THIS MEANS THAT THE ETHERNET CARD IS CONFIGURED TO USE TWISTED PAIR, DOESN'T IT? (PAGE 71 OF THE SPECIFICATION). IN THE SPEC, IT ALSO SAYS THAT THE DRIVER MUST ENABLE "LINK BEAT AND JABBER TO START THE TRANSCEIVER". I GUESS THAT'S DONE LATER.


0114607 
0114608          tc_outw(ioaddr, 0x08, 0x3f00);       
0114609          
0114610 
0114611          wait_for_completion(tcp, TxReset);
0114612          wait_for_completion(tcp, RxReset);
0114613 
0114614           tc_outw(ioaddr, EL3_CMD, RxDisable); /* disable the receiver. */
0114615           tc_outw(ioaddr, EL3_CMD, TxDisable); /* Disable transmitter. */
0114616          
0114617          EL3WINDOW(2);
0114618 
0114619          for (i = 0; i < 6; i++){
0114620                   tc_outb(ioaddr, i, tcp->tc_address.ea_addr[i]);       
0114621                   printf("[%x]", tcp->tc_address.ea_addr[i]);
0114622          }
0114623          printf(" ");
0114624                   
0114625          EL3WINDOW(0);
0114626           switch (1) {
0114627                    case 0: case 1: tc_outw(ioaddr, 6, 0); break;
0114628                    case 2: tc_outw(ioaddr, 6, 3<<14); break;
0114629                    case 3: tc_outw(ioaddr, 6, 1<<14); break;
0114630           }
0114631           /* 10baseT interface, enable link beat and jabber check. */
0114632           EL3WINDOW(4);
0114633           tc_outw(ioaddr, WN4_MEDIA, MEDIA_LED | MEDIA_TP);
0114634 
0114635           /* On PCMCIA, this just turns on the LED */
0114636           tc_outw(ioaddr, EL3_CMD, StopCoax);
0114637           EL3WINDOW(1);
0114638           
0114639  /* Switch to the stats window, and clear all stats by reading. */
0114640           tc_outw(ioaddr, EL3_CMD, StatsDisable);
0114641           EL3WINDOW(6);
0114642           for (i = 0; i < 9; i++)
0114643                   tc_inb(ioaddr, i);
0114644           tc_inw(ioaddr, 10);
0114645           tc_inw(ioaddr, 12);
0114646           tc_outw(ioaddr, EL3_CMD, StatsEnable); /* Turn on statistics. */
0114647           
0114648           /* Switch to register set 1 for normal use. */
0114649           EL3WINDOW(1);
0114650 
0114651           /* Accept b-cast and phys addr only. */
0114652           tc_outw(ioaddr, EL3_CMD, SetRxFilter | RxStation | RxBroadcast);
0114653 
0114654           tc_outw(ioaddr, EL3_CMD, SetTxStart|60); /* */
0114655 
0114656           /* Allow status bits to be seen. */
0114657           tc_outw(ioaddr, EL3_CMD, SetStatusEnb | 0xff);
0114658           /* Ack all pending events, and set active indicator mask. */
0114659           tc_outw(ioaddr, EL3_CMD, AckIntr | 0xff);
0114660           tc_outw(ioaddr, EL3_CMD, SetIntrEnb | IntLatch |
0114661                    TxAvailable | RxComplete | AdapterFailure);
0114662                   
0114663                   
0114664                   
0114665           /* VERY important! install interrupt handler! */
0114666           put_irq_handler(&tcp->tc_hook, tcp->tc_irq, tc_handler);
0114667           
0114668           /* enable IRQ, now every thing is ok, we prepare to receive interrupt */
0114669          enable_irq(&tcp->tc_hook);
0114670          
0114671          /* MUST read specification. */
0114672           tc_outw(ioaddr, EL3_CMD, RxEnable); /* Enable the receiver. */
0114673           tc_outw(ioaddr, EL3_CMD, TxEnable); /* Enable transmitter. */
0114674           
0114675          /* init complete! I HOPE everything is ok! At least specification say       *
0114676           * the 3C589D PC card will be ready to work now.
0114677           */
0114678          tcp->tc_mode = REM_ENABLED;
0114679          tcp->tc_flags |= REF_ENABLED;
0114680                   
0114681          return;
0114682 }
0114683 
0114684 /*
0114685  Read a word from the EEPROM using the regular EEPROM access register.
0114686  Assume that we are in register window zero.
0114687 */
0114688 /* MUST read specification. */
0114689 static int read_eeprom(short ioaddr, int index)
0114690 {
0114691  int i;
0114692 
0114693  tc_outw(ioaddr, 10, 0x80 + index);
0114694  /* Reading the eeprom takes 162 us */
0114695  for (i = 1620; i >= 0; i--)
0114696          if ((tc_inw(ioaddr, 10) & 0x8000) == 0)
0114697           break;
0114698  return tc_inw(ioaddr, 12);
0114699 }
0114700 
0114701 /*
0114702  * Use this for commands that may take time to finish
0114703  */
0114704  /* MUST read specification. */
0114705 static void wait_for_completion(tc_t *tcp, int cmd)
0114706 {
0114707          int i = 0xff;
0114708          long j;
0114709          int ioaddr;
0114710 
0114711          ioaddr= tcp->tc_base_port;
0114712          tc_outw(ioaddr, EL3_CMD, cmd);
0114713 
0114714          if(cmd == TotalReset){
0114715                   for(j=0; j<0xfffff; j++){}              
0114716          }
0114717           while (--i > 0)
0114718                   if (!(tc_inw(ioaddr, EL3_STATUS) & 0x1000)) break;
0114719           
0114720           if (i == 0)
0114721                   printf("%s: command 0x%04x did not complete! ",
0114722           "tc589d", cmd);
0114723 }
0114724 
0114725 
0114726 /* check the TX status, and try to recover it. */
0114727 /* MUST read specification. */
0114728 static void pop_tx_status(void)
0114729 {
0114730  int i;
0114731  char tx_status;
0114732  int ioaddr= tc_table[0].tc_base_port;
0114733 
0114734  /* Clear the Tx status stack. */
0114735  for (i = 32; i > 0; i--) {
0114736          tx_status = tc_inb(ioaddr, TX_STATUS);
0114737          if (!(tx_status & 0x84)) {
0114738                   break;
0114739          }
0114740          /* reset transmitter on jabber error or underrun */
0114741          if (tx_status & 0x30)
0114742           wait_for_completion(&tc_table[0], TxReset);
0114743          if (tx_status & 0x38) {
0114744           tc_outw(ioaddr, EL3_CMD, TxEnable);       
0114745          }
0114746          tc_outb(ioaddr, TX_STATUS, 0x00); /* Pop the status stack. */
0114747  }
0114748 }
0114749 
0114750 #endif /* ENABLE_TC589 */
0114751 
0114752 /*
0114753  * tc589.c,v 1.0 2004/10/4 14:58 Wangzhi.
0114754  */