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 */
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);
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 */