POK
/home/jaouen/pok_official/pok/trunk/libpok/drivers/rtl8029.c
Go to the documentation of this file.
00001 /*
00002  *                               POK header
00003  *
00004  * The following file is a part of the POK project. Any modification should
00005  * made according to the POK licence. You CANNOT use this file or a part of
00006  * this file is this part of a file for your own project
00007  *
00008  * For more information on the POK licence, please see our LICENCE FILE
00009  *
00010  * Please follow the coding guidelines described in doc/CODING_GUIDELINES
00011  *
00012  *                                      Copyright (c) 2007-2009 POK team
00013  *
00014  * Created by julien on Mon May 18 18:44:51 2009
00015  */
00016 
00024 #ifdef POK_NEEDS_RTL8029
00025 #include "rtl8029.h"
00026 
00027 #include <middleware/port.h>
00028 
00029 // global since there is no way to get device data otherwise...
00030 static s_ne2000_dev dev;
00031 
00032 /*
00033  * We *always* assume page 0 to be selected.
00034  * Two exceptions: initialization and polling.
00035  * Therefore, each time we need to switch to page 1,
00036  * the card is switched to page 0 again when we're done...
00037  */
00038 #define NE2000_SELECT_PAGE(dev, page)                                   \
00039   outb((pok_inb((dev)->addr + NE2000_CR) &                              \
00040         ~(NE2000_CR_PS0 | NE2000_CR_PS1)) | ((page) << 6), (dev)->addr)
00041 
00042 static
00043 ssize_t ne2000_write(const s_ne2000_dev* dev,
00044                      const void*         buf,
00045                      unsigned short      count,
00046                      unsigned short      offset)
00047 {
00048   const char* p = NULL;
00049   ssize_t ret = count;
00050 
00051   // Sets RD2 (abort/complete remote DMA)
00052   outb((pok_inb((dev)->addr + NE2000_CR) & ~(NE2000_CR_RD0 | NE2000_CR_RD1)) |
00053        NE2000_CR_RD2, (dev)->addr);
00054 
00055   /* These two registers set the start address of remote DMA. */
00056   outb(offset, dev->addr + NE2000_RSAR0);
00057   outb(offset >> 8, dev->addr + NE2000_RSAR1);
00058 
00059   /* These two registers set the data byte counts of remote DMA. */
00060   outb(count, dev->addr + NE2000_RBCR0);
00061   outb(count >> 8, dev->addr + NE2000_RBCR1);
00062 
00063   // Sets RD1 (remote write)
00064   outb((pok_inb((dev)->addr + NE2000_CR) & ~(NE2000_CR_RD0 | NE2000_CR_RD2)) |
00065        NE2000_CR_RD1, (dev)->addr);
00066 
00067   for (p = buf; count > 0; count--, p++)
00068   {
00069     outb(*p, dev->addr + NE2000_DMA_PORT);
00070   }
00071 
00072   return (ret);
00073 }
00074 
00075 static
00076 ssize_t ne2000_read(const s_ne2000_dev* dev,
00077                     void*               buf,
00078                     unsigned short      count,
00079                     unsigned short      offset)
00080 {
00081   char* p = NULL;
00082   ssize_t ret = count;
00083 
00084   // Sets RD2 (abort/complete remote DMA)
00085   outb((pok_inb((dev)->addr + NE2000_CR) & ~(NE2000_CR_RD0 | NE2000_CR_RD1)) |
00086        NE2000_CR_RD2, (dev)->addr);
00087 
00088   /* These two registers set the start address of remote DMA. */
00089   outb(offset, dev->addr + NE2000_RSAR0);
00090   outb(offset >> 8, dev->addr + NE2000_RSAR1);
00091 
00092   /* These two registers set the data byte counts of remote DMA. */
00093   outb(count, dev->addr + NE2000_RBCR0);
00094   outb(count >> 8, dev->addr + NE2000_RBCR1);
00095 
00096   // Sets RD0 (remote read)
00097   outb((pok_inb((dev)->addr + NE2000_CR) & ~(NE2000_CR_RD1 | NE2000_CR_RD2)) |
00098        NE2000_CR_RD0, (dev)->addr);
00099 
00100   for (p = buf; count > 0; count--, p++)
00101   {
00102     *p = pok_inb(dev->addr + NE2000_DMA_PORT);
00103   }
00104 
00105   return (ret);
00106 }
00107 
00108 
00113 static inline
00114 void rtl8029_enqueue (pok_packet_t *packet)
00115 {
00116   pok_queue_t*  queue = dev.recv_buf + packet->udp.dst;
00117   uint32_t      off = 0;
00118   uint32_t      i = 0;
00119 
00120   /* overflow? */
00121   if (queue->len + packet->udp.len > RECV_BUF_SZ)
00122   {
00123     printf("rtl8029_read: error: ring buffer %d overflow!\n", packet->udp.dst);
00124     return;
00125   }
00126 
00127   /* at which offset should we start writing? */
00128   off = (queue->off + queue->len) % RECV_BUF_SZ;
00129 
00130   /* copying data from the packet to the circular buffer in the queue */
00131   for (i = 0; i < packet->udp.len; i++)
00132   {
00133     queue->data[off] = packet->data[i];
00134     off = (off + 1) % RECV_BUF_SZ;
00135   }
00136 
00137   /* updating data length in this queue */
00138   queue->len += packet->udp.len;
00139 }
00140 
00146 void rtl8029_read (pok_port_id_t port_id, void* data, uint32_t len)
00147 {
00148   pok_port_id_t global;
00149   pok_ret_t     ret;
00150 
00151   ret = pok_port_virtual_get_global (port_id, &global);
00152 
00153   if (ret == POK_ERRNO_OK)
00154   {
00155     char        *dest = data;
00156     pok_queue_t* queue = dev.recv_buf + global;
00157     uint32_t    size = len < queue->len ? len : queue->len;
00158     uint32_t    copied = 0;
00159 
00160     printf ("[RTL8029] READ DATA FROM LOCAL PORT %d "
00161             "GLOBAL_PORT=%d), size=%d\n", port_id, global, len);
00162 
00163     /* is there something to read ? */
00164     if (queue->len == 0)
00165     {
00166       printf("rtl8029_read: error: empty read ring buffer %d!\n", port_id);
00167       return;
00168     }
00169 
00170     /* copy from the queue to the buffer */
00171     for (copied = 0; copied < size; copied++)
00172     {
00173       dest[copied % RECV_BUF_SZ] = queue->data[queue->off];
00174       queue->off = (queue->off + 1) % RECV_BUF_SZ;
00175     }
00176 
00177     /* updating data length in this queue */
00178     queue->len -= size;
00179   }
00180 }
00181 
00187 void rtl8029_write (pok_port_id_t port_id, const void* data, uint32_t len)
00188 {
00189   uint32_t        nbdest;
00190   uint32_t        tmp;
00191   uint32_t        dest;
00192   pok_ret_t       ret;
00193   char            node2[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
00194   pok_packet_t    packet;
00195   const char*     d;
00196   size_t          cpylen = 0;
00197   size_t          sndlen = 0;
00198   unsigned char state; // ISR state
00199 
00200   ret = pok_port_virtual_nb_destinations (port_id, &nbdest);
00201   if (ret != POK_ERRNO_OK)
00202   {
00203     return;
00204   }
00205 
00206   for (tmp = 0 ; tmp < nbdest ; tmp++)
00207   {
00208     ret = pok_port_virtual_destination (port_id, tmp, &dest);
00209     if (ret == POK_ERRNO_OK)
00210     {
00211       printf ("[RTL8029] SEND DATA THROUGH NETWORK FROM LOCAL PORT %d "
00212               "TO GLOBAL PORT %d, size=%d\n", port_id, dest, len);
00213 
00214       memcpy(packet.eth.src, dev.mac, ETH_MAC_LEN);
00215       memcpy(packet.eth.dst, node2, ETH_MAC_LEN);
00216       packet.eth.ethertype = 0x4242;
00217       packet.udp.src = port_id;
00218       packet.udp.dst = dest;
00219 
00220       for (d = data; len != 0; len -= cpylen, data += cpylen)
00221       {
00222         // too short; let's cut
00223         if (len <= NET_DATA_MINLEN)
00224         {
00225           cpylen = len;
00226           sndlen = ETH_DATA_MINLEN + sizeof(eth_hdr_t);
00227         }
00228         else
00229         {
00230           // too big; let's pad
00231           if (len >= NET_DATA_MAXLEN)
00232           {
00233             cpylen = NET_DATA_MAXLEN;
00234             sndlen = ETH_DATA_MAXLEN + sizeof(eth_hdr_t);
00235           }
00236           // normal
00237           else
00238           {
00239             cpylen = len;
00240             sndlen = sizeof(eth_hdr_t) + sizeof(udp_hdr_t) + cpylen;
00241           }
00242         }
00243 
00244         packet.udp.len = cpylen;
00245         memcpy(&(packet.data), data, cpylen);
00246 
00247         ne2000_write(&dev, &packet, sndlen, NE2000_TXBUF * 256);
00248 
00249         do
00250         {
00251           state = pok_inb(dev.addr + NE2000_ISR);
00252         }
00253         while ((state & NE2000_ISR_RDC) != NE2000_ISR_RDC);
00254 
00255         /* This register sets the start page address of
00256            the packet to the transmitted. */
00257         outb(NE2000_TXBUF, dev.addr + NE2000_TPSR); //?
00258 
00259         /* These two registers set the byte counts of
00260            the packet to be transmitted. */
00261         outb(sndlen, dev.addr + NE2000_TBCR0);
00262         outb(sndlen >> 8, dev.addr + NE2000_TBCR1);
00263 
00264         /* This bit must be set to transmit a packet. */
00265         outb(pok_inb(dev.addr + NE2000_CR) | NE2000_CR_TXP,
00266              dev.addr + NE2000_CR);
00267 
00268         outb(NE2000_ISR_RDC, dev.addr + NE2000_ISR); // Clear RDC bit
00269       }
00270     }
00271   }
00272 }
00273 
00279 void rtl8029_polling ()
00280 {
00281   unsigned char state; // ISR state
00282 
00283   NE2000_SELECT_PAGE(&dev, 0);
00284 
00285   while (1)
00286   {
00287     // do we have an interrupt flag set?
00288     if ((state = pok_inb(dev.addr + NE2000_ISR)) == 0)
00289       continue;
00290 
00291     if (state & NE2000_ISR_PRX)
00292     {
00293       if ((pok_inb(dev.addr + NE2000_RSR) & NE2000_RSR_PRX) == 0)
00294       {
00295         // error
00296       }
00297 
00298       printf("[*]\n");
00299 
00300       /* no errors */
00301       s_ne2000_header   ne2000_hdr;     // ne2000 packet header
00302       unsigned short    offset;         // dma offset
00303       unsigned char     start, end;     // pointers for the ring buffer
00304       pok_packet_t      recv_packet;
00305 
00306       while (1)
00307       {
00308 
00309         /* This register is used to prevent overwrite of the receive buffer ring.
00310            It is typically used as a pointer indicating the last receive buffer
00311            page the host has read.*/
00312         start = pok_inb(dev.addr + NE2000_BNRY) + 1;
00313 
00314         /* This register points to the page address of the first receive
00315            buffer page to be used for a packet reception. */
00316         NE2000_SELECT_PAGE(&dev, 1);
00317         end = pok_inb(dev.addr + NE2000_CURR);
00318         NE2000_SELECT_PAGE(&dev, 0);
00319 
00320         if ((end % NE2000_MEMSZ) == (start % NE2000_MEMSZ) + 1)
00321         {
00322           break;
00323         }
00324 
00325         /* et on decapsule! */
00326         offset = start << 8;
00327         // ne2000 header
00328         offset += ne2000_read(&dev, &ne2000_hdr, sizeof(s_ne2000_header),
00329                               offset);
00330 
00331         ne2000_read(&dev, &recv_packet,
00332                     ne2000_hdr.size - sizeof(s_ne2000_header), offset);
00333         rtl8029_enqueue(&recv_packet);
00334 
00335         // update the BNRY register... almost forgot that
00336         outb(ne2000_hdr.next > NE2000_MEMSZ ?
00337              NE2000_RXBUF - 1 : ne2000_hdr.next - 1, dev.addr + NE2000_BNRY);
00338 
00339       }
00340 
00341       outb(NE2000_ISR_PRX, dev.addr + NE2000_ISR); // Clear PRX flag
00342     }
00343 
00344     if (state & NE2000_ISR_PTX)
00345     {
00346       outb(NE2000_ISR_PTX, dev.addr + NE2000_ISR); // Clear PTX flag
00347     }
00348 
00349     if (state & NE2000_ISR_RXE)
00350     {
00351       outb(NE2000_ISR_RXE, dev.addr + NE2000_ISR); // Clear RXE flag
00352     }
00353 
00354     if (state & NE2000_ISR_TXE)
00355     {
00356       outb(NE2000_ISR_TXE, dev.addr + NE2000_ISR); // Clear TXE flag
00357     }
00358 
00359     if (state & NE2000_ISR_OVW)
00360     {
00361       outb(NE2000_ISR_OVW, dev.addr + NE2000_ISR); // Clear OVW flag
00362     }
00363 
00364     if (state & NE2000_ISR_CNT)
00365     {
00366       outb(NE2000_ISR_CNT, dev.addr + NE2000_ISR); // Clear CNT flag
00367     }
00368 
00369     if (state & NE2000_ISR_RST)
00370     {
00371       outb(NE2000_ISR_RST, dev.addr + NE2000_ISR); // Clear RST bit
00372     }
00373   }
00374 }
00375 
00382 void rtl8029_init ()
00383 {
00384   dev.pci.vendorid = 0x10ec;
00385   dev.pci.deviceid = 0x8029;
00386   dev.pci.io_range = 0x10;
00387 
00388   if (pci_register(&(dev.pci)) != 0)
00389   {
00390     printf("rtl8029: PCI init failed!\n");
00391     return;
00392   }
00393 
00394   dev.addr = dev.pci.bar[0] & (~0x1F);
00395 
00396   unsigned char i = 0;
00397   unsigned char buf[6 * 2]; // used for MAC address
00398 
00399   NE2000_SELECT_PAGE(&dev, 0);
00400 
00401   /* This bit is the STOP command. When it is set, no packets will be
00402      received or transmitted. POWER UP=1. */
00403   outb(NE2000_CR_STP, dev.addr + NE2000_CR);
00404 
00405   // Sets several options... Read the datasheet!
00406   outb(0x00, dev.addr + NE2000_TCR);
00407   outb(NE2000_RCR_AB, dev.addr + NE2000_RCR);
00408   outb(NE2000_DCR_LS | NE2000_DCR_FT1, dev.addr + NE2000_DCR);
00409 
00410   /* The Page Start register sets the start page address
00411      of the receive buffer ring. */
00412   outb(NE2000_RXBUF, dev.addr + NE2000_PSTART);
00413   /* The Page Stop register sets the stop page address
00414      of the receive buffer ring. */
00415   outb(NE2000_MEMSZ, dev.addr + NE2000_PSTOP);
00416   /* This register is used to prevent overwrite of the receive buffer ring.
00417      It is typically used as a pointer indicating the last receive buffer
00418      page the host has read. */
00419   outb(NE2000_RXBUF, dev.addr + NE2000_BNRY);
00420 
00421   /* These two registers set the data byte counts of remote DMA. */
00422   outb(0, dev.addr + NE2000_RBCR0);
00423   outb(0, dev.addr + NE2000_RBCR1);
00424 
00425   NE2000_SELECT_PAGE(&dev, 1);
00426 
00427   /* This register points to the page address of the first receive buffer
00428      page to be used for a packet reception. */
00429   outb(NE2000_RXBUF + 1, dev.addr + NE2000_CURR);
00430 
00431   // Init mac address
00432   /* Here's something I do not understand... Section 6.2.2 of the datasheet
00433      says bytes 00H-05H of the PROM corresponds to the Ethernet ID. But it
00434      looks like each byte of the MAC address is written twice...
00435      Therefore I read 2 * sizeof(mac) and select one of the two bytes
00436      corresponding to the MAC... Weird... Really... */
00437   ne2000_read(&dev, buf, 6 * 2, 0);
00438   for (i = 0; i < 6; i++)
00439     dev.mac[i] = buf[i * 2];
00440 
00441   /* These registers contain my Ethernet node address and are used to compare
00442     the destination address of incoming packets for acceptation or rejection.*/
00443   outb(dev.mac[0], dev.addr + NE2000_PAR0);
00444   outb(dev.mac[1], dev.addr + NE2000_PAR1);
00445   outb(dev.mac[2], dev.addr + NE2000_PAR2);
00446   outb(dev.mac[3], dev.addr + NE2000_PAR3);
00447   outb(dev.mac[4], dev.addr + NE2000_PAR4);
00448   outb(dev.mac[5], dev.addr + NE2000_PAR5);
00449 
00450   NE2000_SELECT_PAGE(&dev, 0);
00451 
00452   // Start command
00453   outb(NE2000_CR_STA, dev.addr + NE2000_CR);
00454 
00455   // Reactivating interrupts
00456   /* ISR register must be cleared after power up. */
00457   outb(0xFF, dev.addr + NE2000_ISR);
00458   /* All bits correspond to the bits in the ISR register. POWER UP=all 0s.
00459      Setting individual bits will enable the corresponding interrupts. */
00460   /* Since POK use polling, ALL interrupts are disabled */
00461   outb(0x00, dev.addr + NE2000_IMR);
00462 
00463   for (i = 0; i < 20; i++) /* TODO: random constant */
00464   {
00465     dev.recv_buf[i].len = 0;
00466     dev.recv_buf[i].off = 0;
00467   }
00468 
00469   return;
00470 }
00471 
00472 #endif