Renamed tpl_drv_* to api_drv_* (a more fitting name)
[tpg/acess2.git] / Modules / Network / PCnet-FASTIII / pcnet-fast3.c
1 /*
2  * Acess2 PCnet-FAST III Driver
3  * - By John Hodge (thePowersGang)
4  */
5 #define DEBUG   0
6 #define VERSION ((0<<8)|10)
7 #include <acess.h>
8 #include <modules.h>
9 #include <fs_devfs.h>
10 #include <drv_pci.h>
11 #include <api_drv_network.h>
12 #include <semaphore.h>
13
14 // === CONSTANTS ===
15 #define VENDOR_ID       0x1022
16 #define DEVICE_ID       0x2000
17
18 enum eRegs
19 {
20         REG_APROM0      = 0x00,
21         REG_APROM4      = 0x04,
22         REG_APROM8      = 0x08,
23         REG_APROMC      = 0x0C,
24         REG_RDP         = 0x10, // 16 bit
25         REG_RAP         = 0x14, // 8-bit
26         REG_RESET       = 0x18, // 16-bit
27         REG_BDP         = 0x1C, // 16-bit
28 };
29
30 enum eCSR_Regs
31 {
32         CSR_STATUS,     // CSR0 - Am79C973/Am79C975 Controller Status
33         CSR_IBA0,       // CSR1 - Initialization Block Address[15:0]
34         CSR_IBA1,       // CSR2 - Initialization Block Address[31:16]
35         CSR_INTMASK,    // CSR3 - Interrupt Masks and Deferral Control
36         
37         CSR_MAC0 = 12,  // CSR12 - Physical Address[15:0]
38         CSR_MAC1 = 13,  // CSR13 - Physical Address[31:16]
39         CSR_MAC2 = 14,  // CSR14 - Physical Address[47:32]
40         CSR_MODE = 15,  // CSR15 - Mode
41         
42         CSR_RXBASE0 = 24,       // CSR24 - Base Address of Receive Ring Lower
43         CSR_RXBASE1 = 25,       // CSR25 - Base Address of Receive Ring Upper
44         CSR_TXBASE0 = 30,       // CSR26 - Base Address of Transmit Ring Lower
45         CSR_TXBASE1 = 31,       // CSR27 - Base Address of Transmit Ring Upper
46         
47         CSR_RXLENGTH = 76,      // CSR76 - Receive Ring Length
48         CSR_TXLENGTH = 78,      // CSR78 - Transmit Ring Length
49 };
50
51 enum eBCR_Regs
52 {
53         BCR_PHYCS = 32, // BCR32 - Internal PHY Control and Status
54         BCR_PHYADDR,    // BCR33 - Internal PHY Address
55         BCR_PHYMGMT,    // BCR34 - Internal PHY Management Data
56 };
57
58 // === TYPES ===
59 typedef struct sCard
60 {
61         Uint16  IOBase;
62         Uint8   IRQ;
63         
64          int    NumWaitingPackets;
65         
66         char    Name[2];
67         tVFS_Node       Node;
68         Uint8   MacAddr[6];
69 }       tCard;
70
71 // === PROTOTYPES ===
72  int    PCnet3_Install(char **Options);
73 char    *PCnet3_ReadDir(tVFS_Node *Node, int Pos);
74 tVFS_Node       *PCnet3_FindDir(tVFS_Node *Node, const char *Filename);
75  int    PCnet3_RootIOCtl(tVFS_Node *Node, int ID, void *Arg);
76 Uint64  PCnet3_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
77 Uint64  PCnet3_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
78  int    PCnet3_IOCtl(tVFS_Node *Node, int ID, void *Arg);
79 void    PCnet3_IRQHandler(int Num);
80
81 // === GLOBALS ===
82 MODULE_DEFINE(0, VERSION, PCnet3, PCnet3_Install, NULL, NULL);
83 tDevFS_Driver   gPCnet3_DriverInfo = {
84         NULL, "PCnet3",
85         {
86         .NumACLs = 1,
87         .ACLs = &gVFS_ACL_EveryoneRX,
88         .Flags = VFS_FFLAG_DIRECTORY,
89         .ReadDir = PCnet3_ReadDir,
90         .FindDir = PCnet3_FindDir,
91         .IOCtl = PCnet3_RootIOCtl
92         }
93 };
94  int    giPCnet3_CardCount;
95 tCard   *gaPCnet3_Cards;
96
97 // === CODE ===
98 /**
99  * \brief Installs the PCnet3 Driver
100  */
101 int PCnet3_Install(char **Options)
102 {
103          int    id = -1;
104          int    i = 0;
105         Uint16  base;
106         tCard   *card;
107         
108         giPCnet3_CardCount = PCI_CountDevices(VENDOR_ID, DEVICE_ID);
109         Log_Debug("PCnet3", "%i cards", giPCnet3_CardCount);
110         
111         if( giPCnet3_CardCount == 0 )   return MODULE_ERR_NOTNEEDED;
112         
113         gaPCnet3_Cards = calloc( giPCnet3_CardCount, sizeof(tCard) );
114         
115         while( (id = PCI_GetDevice(VENDOR_ID, DEVICE_ID, i)) != -1 )
116         {
117                 card = &gaPCnet3_Cards[i];
118                 base = PCI_GetBAR( id, 0 );
119                 if( !(base & 1) ) {
120                         Log_Warning("PCnet3", "Driver does not support MMIO, skipping card");
121                         card->IOBase = 0;
122                         card->IRQ = 0;
123                         continue ;
124                 }
125                 base &= ~1;
126                 card->IOBase = base;
127                 card->IRQ = PCI_GetIRQ( id );
128                 
129                 // Install IRQ Handler
130                 IRQ_AddHandler(card->IRQ, PCnet3_IRQHandler);
131                 
132                 
133                 
134                 Log_Log("PCnet3", "Card %i 0x%04x, IRQ %i %02x:%02x:%02x:%02x:%02x:%02x",
135                         i, card->IOBase, card->IRQ,
136                         card->MacAddr[0], card->MacAddr[1], card->MacAddr[2],
137                         card->MacAddr[3], card->MacAddr[4], card->MacAddr[5]
138                         );
139                 
140                 i ++;
141         }
142         
143         gPCnet3_DriverInfo.RootNode.Size = giPCnet3_CardCount;
144         DevFS_AddDevice( &gPCnet3_DriverInfo );
145         
146         return MODULE_ERR_OK;
147 }
148
149 // --- Root Functions ---
150 char *PCnet3_ReadDir(tVFS_Node *Node, int Pos)
151 {
152         if( Pos < 0 || Pos >= giPCnet3_CardCount )      return NULL;
153         
154         return strdup( gaPCnet3_Cards[Pos].Name );
155 }
156
157 tVFS_Node *PCnet3_FindDir(tVFS_Node *Node, const char *Filename)
158 {
159         //TODO: It might be an idea to supprt >10 cards
160         if(Filename[0] == '\0' || Filename[1] != '\0')  return NULL;
161         if(Filename[0] < '0' || Filename[0] > '9')      return NULL;
162         return &gaPCnet3_Cards[ Filename[0]-'0' ].Node;
163 }
164
165 const char *csaPCnet3_RootIOCtls[] = {DRV_IOCTLNAMES, NULL};
166 int PCnet3_RootIOCtl(tVFS_Node *Node, int ID, void *Data)
167 {
168         ENTER("pNode iID pData", Node, ID, Data);
169         switch(ID)
170         {
171         BASE_IOCTLS(DRV_TYPE_NETWORK, "PCnet3", VERSION, csaPCnet3_RootIOCtls);
172         }
173         LEAVE('i', 0);
174         return 0;
175 }
176
177 // --- File Functions ---
178 Uint64 PCnet3_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
179 {
180         tCard   *card = Node->ImplPtr;
181         Uint16  read_ofs, pkt_length;
182          int    new_read_ofs;
183
184         ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
185
186 retry:
187         if( Semaphore_Wait( &card->ReadSemaphore, 1 ) != 1 )
188         {
189                 LEAVE_RET('i', 0);
190         }
191         
192         Mutex_Acquire( &card->ReadMutex );
193         
194         read_ofs = inw( card->IOBase + CAPR );
195         LOG("raw read_ofs = %i", read_ofs);
196         read_ofs = (read_ofs + 0x10) & 0xFFFF;
197         LOG("read_ofs = %i", read_ofs);
198         
199         pkt_length = *(Uint16*)&card->ReceiveBuffer[read_ofs+2];
200         
201         // Calculate new read offset
202         new_read_ofs = read_ofs + pkt_length + 4;
203         new_read_ofs = (new_read_ofs + 3) & ~3; // Align
204         if(new_read_ofs > card->ReceiveBufferLength) {
205                 LOG("wrapping read_ofs");
206                 new_read_ofs -= card->ReceiveBufferLength;
207         }
208         new_read_ofs -= 0x10;   // I dunno
209         LOG("new_read_ofs = %i", new_read_ofs);
210         
211         // Check for errors
212         if( *(Uint16*)&card->ReceiveBuffer[read_ofs] & 0x1E ) {
213                 // Update CAPR
214                 outw(card->IOBase + CAPR, new_read_ofs);
215                 Mutex_Release( &card->ReadMutex );
216                 goto retry;     // I feel evil
217         }
218         
219         // Get packet
220         if( Length > pkt_length )       Length = pkt_length;
221         memcpy(Buffer, &card->ReceiveBuffer[read_ofs+4], Length);
222         
223         // Update CAPR
224         outw(card->IOBase + CAPR, new_read_ofs);
225         
226         Mutex_Release( &card->ReadMutex );
227         
228         LEAVE('i', Length);
229         
230         return Length;
231 }
232
233 Uint64 PCnet3_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
234 {
235          int    td;
236         Uint32  status;
237         tCard   *card = Node->ImplPtr;
238         
239         if( Length > 1500 )     return 0;       // MTU exceeded
240         
241         ENTER("pNode XLength pBuffer", Node, Length, Buffer);
242         
243         // TODO: Implement a semaphore for avaliable transmit buffers
244
245         // Find an avaliable descriptor
246         Mutex_Acquire(&card->CurTXProtector);
247         td = card->CurTXDescriptor;
248         card->CurTXDescriptor ++;
249         card->CurTXDescriptor %= 4;
250         Mutex_Release(&card->CurTXProtector);
251         // - Lock it
252         Mutex_Acquire( &card->TransmitInUse[td] );
253         
254         LOG("td = %i", td);
255         
256         // Transmit using descriptor `td`
257         LOG("card->PhysTransmitBuffers[td] = %P", card->PhysTransmitBuffers[td]);
258         outd(card->IOBase + TSAD0 + td*4, card->PhysTransmitBuffers[td]);
259         LOG("card->TransmitBuffers[td] = %p", card->TransmitBuffers[td]);
260         // Copy to buffer
261         memcpy(card->TransmitBuffers[td], Buffer, Length);
262         // Start
263         status = 0;
264         status |= Length & 0x1FFF;      // 0-12: Length
265         status |= 0 << 13;      // 13: OWN bit
266         status |= (0 & 0x3F) << 16;     // 16-21: Early TX threshold (zero atm, TODO: check)
267         LOG("status = 0x%08x", status);
268         outd(card->IOBase + TSD0 + td*4, status);
269         
270         LEAVE('i', (int)Length);
271         
272         return Length;
273 }
274
275 const char *csaPCnet3_NodeIOCtls[] = {DRV_IOCTLNAMES, NULL};
276 int PCnet3_IOCtl(tVFS_Node *Node, int ID, void *Data)
277 {
278         tCard   *card = Node->ImplPtr;
279         ENTER("pNode iID pData", Node, ID, Data);
280         switch(ID)
281         {
282         BASE_IOCTLS(DRV_TYPE_NETWORK, "PCnet3", VERSION, csaPCnet3_NodeIOCtls);
283         case NET_IOCTL_GETMAC:
284                 if( !CheckMem(Data, 6) ) {
285                         LEAVE('i', -1);
286                         return -1;
287                 }
288                 memcpy( Data, card->MacAddr, 6 );
289                 LEAVE('i', 1);
290                 return 1;
291         }
292         LEAVE('i', 0);
293         return 0;
294 }
295
296 void PCnet3_IRQHandler(int Num)
297 {
298          int    i, j;
299         tCard   *card;
300         Uint16  status;
301
302         LOG("Num = %i", Num);
303         
304         for( i = 0; i < giPCnet3_CardCount; i ++ )
305         {
306                 card = &gaPCnet3_Cards[i];
307                 if( Num != card->IRQ )  break;
308                 
309                 status = inw(card->IOBase + ISR);
310                 LOG("status = 0x%02x", status);
311                 
312                 // Transmit OK, a transmit descriptor is now free
313                 if( status & FLAG_ISR_TOK )
314                 {
315                         for( j = 0; j < 4; j ++ )
316                         {
317                                 if( ind(card->IOBase + TSD0 + j*4) & 0x8000 ) { // TSD TOK
318                                         Mutex_Release( &card->TransmitInUse[j] );
319                                         // TODO: Update semaphore once implemented
320                                 }
321                         }
322                         outw(card->IOBase + ISR, FLAG_ISR_TOK);
323                 }
324                 
325                 // Recieve OK, inform read
326                 if( status & FLAG_ISR_ROK )
327                 {
328                          int    read_ofs, end_ofs;
329                          int    packet_count = 0;
330                          int    len;
331                         
332                         // Scan recieve buffer for packets
333                         end_ofs = inw(card->IOBase + CBA);
334                         read_ofs = card->SeenOfs;
335                         LOG("read_ofs = %i, end_ofs = %i", read_ofs, end_ofs);
336                         if( read_ofs > end_ofs )
337                         {
338                                 while( read_ofs < card->ReceiveBufferLength )
339                                 {
340                                         packet_count ++;
341                                         len = *(Uint16*)&card->ReceiveBuffer[read_ofs+2];
342                                         LOG("%i 0x%x Pkt Hdr: 0x%04x, len: 0x%04x",
343                                                 packet_count, read_ofs,
344                                                 *(Uint16*)&card->ReceiveBuffer[read_ofs],
345                                                 len
346                                                 );
347                                         if(len > 2000) {
348                                                 Log_Warning("PCnet3", "IRQ: Packet in buffer exceeds sanity (%i>2000)", len);
349                                         }
350                                         read_ofs += len + 4;
351                                         read_ofs = (read_ofs + 3) & ~3; // Align
352                                 }
353                                 read_ofs -= card->ReceiveBufferLength;
354                                 LOG("wrapped read_ofs");
355                         }
356                         while( read_ofs < end_ofs )
357                         {
358                                 packet_count ++;
359                                 LOG("%i 0x%x Pkt Hdr: 0x%04x, len: 0x%04x",
360                                         packet_count, read_ofs,
361                                         *(Uint16*)&card->ReceiveBuffer[read_ofs],
362                                         *(Uint16*)&card->ReceiveBuffer[read_ofs+2]
363                                         );
364                                 read_ofs += *(Uint16*)&card->ReceiveBuffer[read_ofs+2] + 4;
365                                 read_ofs = (read_ofs + 3) & ~3; // Align
366                         }
367                         if( read_ofs != end_ofs ) {
368                                 Log_Warning("PCnet3", "IRQ: read_ofs (%i) != end_ofs(%i)", read_ofs, end_ofs);
369                                 read_ofs = end_ofs;
370                         }
371                         card->SeenOfs = read_ofs;
372                         
373                         LOG("packet_count = %i, read_ofs = 0x%x", packet_count, read_ofs);
374                         
375                         if( packet_count )
376                         {
377                                 if( Semaphore_Signal( &card->ReadSemaphore, packet_count ) != packet_count ) {
378                                         // Oops?
379                                 }
380                                 VFS_MarkAvaliable( &card->Node, 1 );
381                         }
382                         
383                         outw(card->IOBase + ISR, FLAG_ISR_ROK);
384                 }
385         }
386 }

UCC git Repository :: git.ucc.asn.au