Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / workbench / devs / networks / pcnet32 / unit.c
blob1472790fee64d27c8d748aa612ad9d992ef884ef
1 /*
2 * $Id$
3 */
5 /*
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston,
19 MA 02111-1307, USA.
22 #include <exec/types.h>
23 #include <exec/resident.h>
24 #include <exec/io.h>
25 #include <exec/ports.h>
26 #include <exec/errors.h>
28 #include <aros/io.h>
30 #include <devices/sana2.h>
31 #include <devices/sana2specialstats.h>
32 #include <devices/newstyle.h>
33 #include <devices/timer.h>
35 #include <utility/utility.h>
36 #include <utility/tagitem.h>
37 #include <utility/hooks.h>
39 #include <proto/exec.h>
40 #include <proto/dos.h>
41 #include <proto/battclock.h>
42 #include <proto/oop.h>
43 #include <proto/timer.h>
44 #include <proto/utility.h>
46 #include <stdlib.h>
48 #include "pcnet32.h"
49 #include "unit.h"
50 #include LC_LIBDEFS_FILE
52 /* BYTE IO */
53 volatile UBYTE readb(APTR base)
55 return BYTEIN(base);
57 volatile void writeb(UBYTE val, APTR base)
59 BYTEOUT(base, val);
62 /* WORD IO */
63 volatile UWORD readw(APTR base)
65 return WORDIN(base);
67 volatile void writew(UWORD val, APTR base)
69 WORDOUT(base, val);
72 /* LONG IO */
73 volatile ULONG readl(APTR base)
75 return *((ULONG*)base);
77 volatile void writel(ULONG val, APTR base)
79 *((ULONG*)base) = val;
82 /* 16/32bit control funcs */
83 static UWORD pcnet32_readcsr_16(APTR base, int index)
85 writew( index, base + 0x12);
86 return readw( base + 0x10);
89 static void pcnet32_writecsr_16(APTR base, int index, UWORD val)
91 writew( index, base + 0x12);
92 writew( val, base + 0x10);
95 static UWORD pcnet32_readbcr_16(APTR base, int index)
97 writew( index, base + 0x12);
98 return readw( base + 0x16);
101 static void pcnet32_writebcr_16(APTR base, int index, UWORD val)
103 writew( index, base + 0x12);
104 writew( val, base + 0x16);
107 static UWORD pcnet32_readrap_16(APTR base)
109 return readw(base + 0x12);
112 static void pcnet32_writerap_16(APTR base, UWORD val)
114 writew( val, base + 0x12);
117 static void pcnet32_reset_16(APTR base)
119 readw(base + 0x14);
122 static int pcnet32_check_16(APTR base)
124 writew(88, base + 0x12);
125 return (readw( base + 0x12) == 88);
128 /**/
130 static UWORD pcnet32_readcsr_32(APTR base, int index)
132 writel( index, base + 0x14);
133 return (readl( base + 0x10) & 0xffff);
136 static void pcnet32_writecsr_32(APTR base, int index, UWORD val)
138 writel( index, base + 0x14);
139 writel( val, base + 0x10);
142 static UWORD pcnet32_readbcr_32(APTR base, int index)
144 writel( index, base + 0x14);
145 return (readl( base + 0x1c) & 0xffff);
148 static void pcnet32_writebcr_32(APTR base, int index, UWORD val)
150 writel( index, base + 0x14);
151 writel( val, base + 0x1c);
154 static UWORD pcnet32_readrap_32(APTR base)
156 return (readl(base + 0x14) & 0xffff);
159 static void pcnet32_writerap_32(APTR base, UWORD val)
161 writel( val, base + 0x14);
164 static void pcnet32_reset_32(APTR base)
166 readl(base + 0x18);
169 static int pcnet32_check_32(APTR base)
171 writel(88, base + 0x14);
172 return ((readw( base + 0x14) & 0xffff) == 88);
176 * Report incoming events to all hyphotetical event receivers
178 VOID ReportEvents(struct PCN32Base *PCNet32Base, struct PCN32Unit *unit, ULONG events)
180 struct IOSana2Req *request, *tail, *next_request;
181 struct List *list;
183 list = &unit->pcnu_request_ports[EVENT_QUEUE]->mp_MsgList;
184 next_request = (APTR)list->lh_Head;
185 tail = (APTR)&list->lh_Tail;
187 /* Go through list of event listeners. If send messages to receivers if event found */
188 Disable();
189 while(next_request != tail)
191 request = next_request;
192 next_request = (APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
194 if((request->ios2_WireError&events) != 0)
196 request->ios2_WireError = events;
197 Remove((APTR)request);
198 ReplyMsg((APTR)request);
201 Enable();
203 return;
206 struct TypeStats *FindTypeStats(struct PCN32Base *PCNet32Base, struct PCN32Unit *unit,
207 struct MinList *list, ULONG packet_type)
209 struct TypeStats *stats, *tail;
210 BOOL found = FALSE;
212 stats = (APTR)list->mlh_Head;
213 tail = (APTR)&list->mlh_Tail;
215 while(stats != tail && !found)
217 if(stats->packet_type == packet_type)
218 found = TRUE;
219 else
220 stats = (APTR)stats->node.mln_Succ;
223 if(!found)
224 stats = NULL;
226 return stats;
229 void FlushUnit(LIBBASETYPEPTR LIBBASE, struct PCN32Unit *unit, UBYTE last_queue, BYTE error)
231 struct IORequest *request;
232 UBYTE i;
233 struct Opener *opener, *tail;
235 D(bug("[pcnet32] unit.FlushUnit\n"));
237 /* Abort queued operations */
239 for (i=0; i <= last_queue; i++)
241 while ((request = (APTR)GetMsg(unit->pcnu_request_ports[i])) != NULL)
243 request->io_Error = IOERR_ABORTED;
244 ReplyMsg((struct Message *)request);
248 opener = (APTR)unit->pcnu_Openers.mlh_Head;
249 tail = (APTR)unit->pcnu_Openers.mlh_Tail;
251 /* Flush every opener's read queue */
253 while(opener != tail)
255 while ((request = (APTR)GetMsg(&opener->read_port)) != NULL)
257 request->io_Error = error;
258 ReplyMsg((struct Message *)request);
260 opener = (struct Opener *)opener->node.mln_Succ;
264 static inline void pci_push(UBYTE *base)
266 /* force out pending posted writes */
267 readl(base);
271 * Interrupt handler called whenever pcnet32 NIC interface generates interrupt.
272 * It's duty is to iterate throgh RX queue searching for new packets.
274 * Please note, that allthough multicast support could be done on interface
275 * basis, it is done in this function as result of quick integration of both
276 * the forcedeth driver (IFF_ALLMULTI flag) and etherling3 driver (AddressMatch
277 * filter function).
279 AROS_UFH3(void, PCN32_RX_Int,
280 AROS_UFHA(struct PCN32Unit *, unit, A1),
281 AROS_UFHA(APTR, dummy, A5),
282 AROS_UFHA(struct ExecBase *,SysBase, A6))
284 AROS_USERFUNC_INIT
286 struct PCN32Base *PCNet32Base = unit->pcnu_device;
287 struct fe_priv *np = unit->pcnu_fe_priv;
288 UWORD Flags;
289 struct TypeStats *tracker;
290 ULONG packet_type;
291 struct Opener *opener, *opener_tail;
292 struct IOSana2Req *request, *request_tail;
293 BOOL accepted, is_orphan;
295 D(bug("%s: PCN32_RX_Int() !!!!\n", unit->pcnu_name));
296 np->cur_rx = 0;
298 /* Endless loop, with break from inside */
299 for(;;)
301 int i;
302 UWORD len=0;
303 struct eth_frame *frame;
305 if (np->cur_rx >= RX_RING_SIZE)
306 break; /* we scanned the whole ring - do not continue */
308 /* Get the in-queue number */
309 i = np->cur_rx % RX_RING_SIZE;
310 Flags = AROS_LE2WORD(((struct rx_ring_desc *)np->ring_addr)[i].BufferStatus);
311 len = AROS_LE2WORD(((struct rx_ring_desc *)np->ring_addr)[i].BufferMsgLength);
313 D(bug("%s: PCN32_RX_Int: looking at packet %d:%d, Flags 0x%x, len %d\n",
314 unit->pcnu_name, np->cur_rx, i, Flags, len));
316 /* Do we own the packet or the chipset? */
317 if ((Flags & (1 << 15))!=0)
319 D(bug("%s: PCN32_RX_Int: packet owned by chipset\n", unit->pcnu_name));
320 goto next_pkt; /* still owned by hardware, */
323 D(bug("%s: PCN32_RX_Int: packet is for us\n", unit->pcnu_name));
325 /* the packet is for us - get it :) */
327 if (Flags & (1 << 7)) { // Bus Parity Error
328 D(bug("%s: PCN32_RX_Int: packet has Bus Parity error!\n", unit->pcnu_name));
329 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
330 unit->pcnu_stats.BadData++;
331 goto next_pkt;
334 if (Flags & (1 << 8)) { // End of Packet
335 D(bug("%s: PCN32_RX_Int: END of Packet\n", unit->pcnu_name));
337 if (Flags & (1 << 9)) { // Start of Packet
338 D(bug("%s: PCN32_RX_Int: START of Packet\n", unit->pcnu_name));
341 if (Flags & (1 << 10)) { // Buffer Error
342 D(bug("%s: PCN32_RX_Int: packet has CRC error!\n", unit->pcnu_name));
343 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
344 unit->pcnu_stats.BadData++;
345 goto next_pkt;
347 if (Flags & (1 << 11)) { // CRC Error
348 D(bug("%s: PCN32_RX_Int: packet has CRC error!\n", unit->pcnu_name));
349 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
350 unit->pcnu_stats.BadData++;
351 goto next_pkt;
353 if (Flags & (1 << 12)) { // OVERFLOW Error
354 D(bug("%s: PCN32_RX_Int: packet has OVERFLOW error!\n", unit->pcnu_name));
355 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
356 unit->pcnu_stats.BadData++;
357 goto next_pkt;
359 if (Flags & (1 << 13)) { // Framing Error
360 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX);
361 unit->pcnu_stats.BadData++;
362 goto next_pkt;
365 D(bug("%s: PCN32_RX_Int: packet doesnt report errors\n", unit->pcnu_name));
367 /* got a valid packet - forward it to the network core */
368 frame = &np->rx_buffer[i];
369 is_orphan = TRUE;
371 /* Dump contents of frame if DEBUG enabled */
372 #ifdef DEBUG
374 int j;
375 for (j=0; j<64; j++) {
376 if ((j%16) == 0)
377 D(bug("\n%03x:", j));
378 D(bug(" %02x", ((unsigned char*)frame)[j]));
380 D(bug("\n"));
382 #endif
384 /* Check for address validity */
385 if(AddressFilter(LIBBASE, unit, frame->eth_packet_dest))
387 /* Packet is addressed to this driver */
388 packet_type = AROS_BE2WORD(frame->eth_packet_type);
389 D(bug("%s: PCN32_RX_Int: Packet IP accepted with type = %d\n", unit->pcnu_name, packet_type));
391 opener = (APTR)unit->pcnu_Openers.mlh_Head;
392 opener_tail = (APTR)&unit->pcnu_Openers.mlh_Tail;
394 /* Offer packet to every opener */
395 while(opener != opener_tail)
397 request = (APTR)opener->read_port.mp_MsgList.lh_Head;
398 request_tail = (APTR)&opener->read_port.mp_MsgList.lh_Tail;
399 accepted = FALSE;
401 /* Offer packet to each request until it's accepted */
402 while((request != request_tail) && !accepted)
404 if((request->ios2_PacketType == packet_type)
405 || ((request->ios2_PacketType <= ETH_MTU)
406 && (packet_type <= ETH_MTU)))
408 D(bug("%s: PCN32_RX_Int: copy packet for opener ..\n", unit->pcnu_name));
409 CopyPacket(LIBBASE, unit, request, len, packet_type, frame);
410 accepted = TRUE;
412 request =
413 (struct IOSana2Req *)request->ios2_Req.io_Message.mn_Node.ln_Succ;
416 if(accepted)
417 is_orphan = FALSE;
419 opener = (APTR)opener->node.mln_Succ;
422 /* If packet was unwanted, give it to S2_READORPHAN request */
423 if(is_orphan)
425 unit->pcnu_stats.UnknownTypesReceived++;
427 if(!IsMsgPortEmpty(unit->pcnu_request_ports[ADOPT_QUEUE]))
429 CopyPacket(LIBBASE, unit,
430 (APTR)unit->pcnu_request_ports[ADOPT_QUEUE]->
431 mp_MsgList.lh_Head, len, packet_type, frame);
432 D(bug("%s: PCN32_RX_Int: packet copied to orphan queue\n", unit->pcnu_name));
436 /* Update remaining statistics */
438 tracker =
439 FindTypeStats(LIBBASE, unit, &unit->pcnu_type_trackers, packet_type);
441 if(tracker != NULL)
443 tracker->stats.PacketsReceived++;
444 tracker->stats.BytesReceived += len;
448 unit->pcnu_stats.PacketsReceived++;
449 ((struct rx_ring_desc *)np->ring_addr)[i].BufferStatus = AROS_WORD2LE((1 << 8)|(1 << 9)|(1 << 15)); // Mark packet as available again
450 next_pkt:
451 np->cur_rx++;
454 AROS_USERFUNC_EXIT
458 * Interrupt generated by Cause() to push new packets into the NIC interface
460 AROS_UFH3(void, PCN32_TX_Int,
461 AROS_UFHA(struct PCN32Unit *, unit, A1),
462 AROS_UFHA(APTR, dummy, A5),
463 AROS_UFHA(struct ExecBase *,SysBase, A6))
465 AROS_USERFUNC_INIT
467 struct fe_priv *np = unit->pcnu_fe_priv;
468 struct PCN32Base *PCNet32Base = unit->pcnu_device;
469 int nr, try_count=1;
470 BOOL proceed = FALSE; /* Fails by default */
472 D(bug("%s: PCN32_TX_Int()\n", unit->pcnu_name));
474 /* send packet only if there is free space on tx queue. Otherwise do nothing */
475 if (!netif_queue_stopped(unit))
477 UWORD packet_size, data_size;
478 struct IOSana2Req *request;
479 struct Opener *opener;
480 UBYTE *buffer;
481 ULONG wire_error=0;
482 BYTE error;
483 struct MsgPort *port;
484 struct TypeStats *tracker;
486 proceed = TRUE; /* Success by default */
487 port = unit->pcnu_request_ports[WRITE_QUEUE];
489 /* Still no error and there are packets to be sent? */
490 while(proceed && (!IsMsgPortEmpty(port)))
492 nr = np->next_tx % TX_RING_SIZE;
493 error = 0;
495 if (!((((struct tx_ring_desc *)np->ring_addr)[nr + RX_RING_SIZE].BufferStatus) & (1 << 15)))
498 request = (APTR)port->mp_MsgList.lh_Head;
499 data_size = packet_size = request->ios2_DataLength;
501 opener = (APTR)request->ios2_BufferManagement;
503 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
505 packet_size += ETH_PACKET_DATA;
506 CopyMem(request->ios2_DstAddr, np->tx_buffer[nr].eth_packet_dest, ETH_ADDRESSSIZE);
507 CopyMem(unit->pcnu_dev_addr, np->tx_buffer[nr].eth_packet_source, ETH_ADDRESSSIZE);
508 np->tx_buffer[nr].eth_packet_type = AROS_WORD2BE(request->ios2_PacketType);
510 buffer = np->tx_buffer[nr].eth_packet_data;
512 else
513 buffer = (UBYTE*)&np->tx_buffer[nr];
515 if (!opener->tx_function(buffer, request->ios2_Data, data_size))
517 error = S2ERR_NO_RESOURCES;
518 wire_error = S2WERR_BUFF_ERROR;
519 ReportEvents(LIBBASE, unit,
520 S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF
521 | S2EVENT_TX);
524 /* Now the packet is already in TX buffer, update flags for NIC */
525 if (error == 0)
527 Disable();
528 D(bug("%s: PCN32_TX_Int: packet %d:%d [type = %d] queued for transmission.", unit->pcnu_name, np->next_tx, nr, np->tx_buffer[nr].eth_packet_type));
530 /* DEBUG? Dump frame if so */
531 #ifdef DEBUG
533 int j;
534 for (j=0; j<64; j++) {
535 if ((j%16) == 0)
536 D(bug("\n%03x:", j));
537 D(bug(" %02x", ((unsigned char*)&np->tx_buffer[nr])[j]));
539 D(bug("\n"));
541 #endif
543 Enable();
545 /* Set the ring details for the packet .. */
546 ((struct tx_ring_desc *)np->ring_addr)[nr + RX_RING_SIZE].BufferLength = AROS_WORD2LE(-packet_size);
547 ((struct tx_ring_desc *)np->ring_addr)[nr + RX_RING_SIZE].Misc = 0x00000000;
548 ((struct tx_ring_desc *)np->ring_addr)[nr + RX_RING_SIZE].PacketBuffer = AROS_LONG2LE((IPTR)&np->tx_buffer[nr]);
549 ((struct tx_ring_desc *)np->ring_addr)[nr + RX_RING_SIZE].BufferStatus = AROS_WORD2LE(0x8300);
551 unit->write_csr(unit->pcnu_BaseMem,0, ((1 << 6)|(1 << 3))); /* .. And trigger an imediate Tx poll */
552 D(bug("%s: PCN32_TX_Int: send poll triggered.\n", unit->pcnu_name));
555 /* Reply packet */
557 request->ios2_Req.io_Error = error;
558 request->ios2_WireError = wire_error;
559 Disable();
560 Remove((APTR)request);
561 Enable();
562 ReplyMsg((APTR)request);
564 /* Update statistics */
566 if(error == 0)
568 tracker = FindTypeStats(LIBBASE, unit, &unit->pcnu_type_trackers,
569 request->ios2_PacketType);
570 if(tracker != NULL)
572 tracker->stats.PacketsSent++;
573 tracker->stats.BytesSent += packet_size;
576 try_count=0;
578 np->next_tx++;
579 try_count++;
582 * If we've just run out of free space on the TX queue, stop
583 * it and give up pushing further frames
585 if ( (try_count + 1) >= TX_RING_SIZE)
587 D(bug("%s: output queue full!. Stopping [count = %d, TX_RING_SIZE = %d\n", unit->pcnu_name, try_count, TX_RING_SIZE));
588 netif_stop_queue(unit);
589 proceed = FALSE;
594 /* Was there success? Enable incomming of new packets */
595 if(proceed)
596 unit->pcnu_request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
597 else
598 unit->pcnu_request_ports[WRITE_QUEUE]->mp_Flags = PA_IGNORE;
600 AROS_USERFUNC_EXIT
604 * Interrupt used to restart the real one
606 AROS_UFH3(void, PCN32_TX_End_Int,
607 AROS_UFHA(struct PCN32Unit *, unit, A1),
608 AROS_UFHA(APTR, dummy, A5),
609 AROS_UFHA(struct ExecBase *,SysBase, A6))
611 AROS_USERFUNC_INIT
613 struct PCN32Base *PCNet32Base = unit->pcnu_device;
614 struct PCN32Unit *dev = unit;
615 struct fe_priv *np = dev->pcnu_fe_priv;
616 UBYTE *base = (UBYTE*) dev->pcnu_BaseMem;
618 D(bug("%s: PCN32_TX_End_Int()\n", unit->pcnu_name));
620 int i;
621 UWORD Flags;
623 for(i = 0; i < TX_RING_SIZE; i++)
625 Flags = AROS_LE2WORD(((struct tx_ring_desc *)np->ring_addr)[i + RX_RING_SIZE].BufferStatus);
626 /* Do we own the packet or the chipset? */
627 D(bug("%s: PCN32_TX_End_Int: looking at TxRing packet %d:, Flags 0x%x\n",
628 unit->pcnu_name, i, Flags));
629 if ((Flags & (1 << 15))==0)
631 D(bug("%s: PCN32_TX_End_Int: TxRing packet %d owned by us\n", unit->pcnu_name, i));
632 #warning "TODO: We should report send errors here .."
634 if (Flags & (1 << 14))
636 D(bug("%s: PCN32_TX_End_Int: Errors occured transmitting packet\n", unit->pcnu_name));
637 if (Flags & (1 << 11))
639 D(bug("%s: PCN32_TX_End_Int: packet reports CRC Error\n", unit->pcnu_name));
642 if (Flags & (1 << 12))
644 D(bug("%s: PCN32_TX_End_Int: packet reports OVERFLOW error\n", unit->pcnu_name));
647 if (Flags & (1 << 13))
649 D(bug("%s: PCN32_TX_End_Int: packet reports FRAMING error\n", unit->pcnu_name));
651 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_TX);
653 else unit->pcnu_stats.PacketsSent++;
655 if ((Flags & (1 << 8))||(Flags &(1 << 9))) //(ENP | STP)
657 D(bug("%s: PCN32_TX_End_Int: freeing TxRing packet for use\n", unit->pcnu_name));
658 ((struct tx_ring_desc *)np->ring_addr)[i + RX_RING_SIZE].BufferStatus = 0;
659 ((struct tx_ring_desc *)np->ring_addr)[i + RX_RING_SIZE].PacketBuffer = 0;
661 else
663 D(bug("%s: PCN32_TX_End_Int: TxRing packet unused ..??\n", unit->pcnu_name));
668 AROS_USERFUNC_EXIT
672 * Maximum number of loops until we assume that a bit in the irq mask
673 * is stuck. Overridable with module param.
675 static const int max_interrupt_work = 5;
678 * Handle timeouts and other strange cases
680 static void PCN32_TimeoutHandler(HIDDT_IRQ_Handler *irq, HIDDT_IRQ_HwInfo *hw)
682 struct PCN32Unit *dev = (struct PCN32Unit *) irq->h_Data;
683 struct timeval time;
684 struct Device *TimerBase = dev->pcnu_TimerSlowReq->tr_node.io_Device;
686 GetSysTime(&time);
687 //D(bug("%s: PCN32_TimeoutHandler()\n", dev->pcnu_name));
690 * If timeout timer is expected, and time elapsed - regenerate the
691 * interrupt handler
693 if (dev->pcnu_toutNEED && (CmpTime(&time, &dev->pcnu_toutPOLL ) < 0))
695 dev->pcnu_toutNEED = FALSE;
696 Cause(&dev->pcnu_tx_end_int);
701 * The interrupt handler - schedules code execution to proper handlers depending
702 * on the message from nForce.
704 * NOTE.
706 * Don't be surprised - this driver used to restart itself several times, in
707 * order to handle events which occur when the driver was handling previous
708 * events. It reduces the latency and amount of dropped packets. Additionally,
709 * this interrupt may put itself into deep sleep (or just quit) and restarts
710 * after certain amount of time (POLL_WAIT).
712 static void PCN32_IntHandler(HIDDT_IRQ_Handler *irq, HIDDT_IRQ_HwInfo *hw)
714 struct PCN32Unit *dev = (struct PCN32Unit *) irq->h_Data;
715 struct fe_priv *np = dev->pcnu_fe_priv;
716 UBYTE *base = (UBYTE*) dev->pcnu_BaseMem;
717 ULONG events;
718 int i;
719 struct Device *TimerBase = dev->pcnu_TimerSlowReq->tr_node.io_Device;
720 struct timeval time;
722 GetSysTime(&time);
723 int csr_0 = 0;
724 int csr_4 = 0;
725 D(bug("%s: PCN32_IntHandler()!!!!!!!\n", dev->pcnu_name));
727 while ( (csr_0 = dev->read_csr(dev->pcnu_BaseMem, 0)) & (1 << 7))
729 dev->write_csr(dev->pcnu_BaseMem, 0, csr_0);
730 D(bug("%s: PCN32_IntHandler: csr[0] : %x\n", dev->pcnu_name, csr_0));
732 if ( csr_0 & (1 << 0) ) // (INIT) is the card initialising?
734 D(bug("%s: PCN32_IntHandler: Chipset init detected .. ", dev->pcnu_name));
735 BOOL have_Tx = FALSE, have_Rx = FALSE;
737 if ( csr_0 & (1 << 1) ) // (STRT) Start/ed/ing?
739 D(bug("[STRT]"));
742 if ( csr_0 & (1 << 2) ) // (STOP) Chipset is stopped
744 D(bug("[STOP]"));
745 have_Tx = TRUE;
748 if ( csr_0 & (1 << 4) ) // (TXON) Transmitter ON?
750 D(bug("[TXON]"));
751 have_Tx = TRUE;
753 else
755 D(bug("[TXON:OFF]"));
758 if ( csr_0 & (1 << 5) ) // (RXON) Reciever ON?
760 D(bug("[RXON]"));
761 have_Rx = TRUE;
763 else
765 D(bug("[RXON:OFF]"));
768 if ( csr_0 & (1 << 8) ) // (IDON) Initialisation Done?
770 D(bug("[IDON]"));
772 D(bug("\n"));
773 if ((!(have_Tx))&&(!(have_Rx)))
775 D(bug("%s: PCN32_IntHandler: Chipset is OFFLINE!\n", dev->pcnu_name));
779 if ( csr_0 & (1 << 10) ) // (RINT) Chipset has Recieved packet(s)
781 D(bug("%s: PCN32_IntHandler: Packet Reception detected!\n", dev->pcnu_name));
782 Cause(&dev->pcnu_rx_int);
785 if ( csr_0 & (1 << 9) ) // (TINT) Chipset has Sent packet(s)
787 D(bug("%s: PCN32_IntHandler: Packet Transmition detected!\n", dev->pcnu_name));
788 Cause(&dev->pcnu_tx_end_int);
791 if ( csr_0 & (1 << 15) ) // (ERR) Chipset has Reported an ERROR
793 D(bug("%s: PCN32_IntHandler: (ERR) ERROR Detected\n", dev->pcnu_name));
794 break;
798 return;
801 VOID CopyPacket(struct PCN32Base *PCNet32Base, struct PCN32Unit *unit,
802 struct IOSana2Req *request, UWORD packet_size, UWORD packet_type,
803 struct eth_frame *buffer)
805 struct Opener *opener;
806 BOOL filtered = FALSE;
807 UBYTE *ptr;
809 D(bug("%s: CopyPacket(packet @ %x, len = %d)\n", unit->pcnu_name, buffer, packet_size));
811 /* Set multicast and broadcast flags */
813 request->ios2_Req.io_Flags &= ~(SANA2IOF_BCAST | SANA2IOF_MCAST);
814 if((*((ULONG *)(buffer->eth_packet_dest)) == 0xffffffff) &&
815 (*((UWORD *)(buffer->eth_packet_dest + 4)) == 0xffff))
817 request->ios2_Req.io_Flags |= SANA2IOF_BCAST;
818 D(bug("%s: CopyPacket: BROADCAST Flag set\n", unit->pcnu_name));
820 else if((buffer->eth_packet_dest[0] & 0x1) != 0)
822 request->ios2_Req.io_Flags |= SANA2IOF_MCAST;
823 D(bug("%s: CopyPacket: MULTICAST Flag set\n", unit->pcnu_name));
826 /* Set source and destination addresses and packet type */
827 CopyMem(buffer->eth_packet_source, request->ios2_SrcAddr, ETH_ADDRESSSIZE);
828 CopyMem(buffer->eth_packet_dest, request->ios2_DstAddr, ETH_ADDRESSSIZE);
829 request->ios2_PacketType = packet_type;
831 /* Adjust for cooked packet request */
833 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
835 packet_size -= ETH_PACKET_DATA;
836 ptr = (UBYTE*)&buffer->eth_packet_data[0];
838 else
840 ptr = (UBYTE*)buffer;
843 request->ios2_DataLength = packet_size;
845 D(bug("%s: CopyPacket: packet @ %x (%d bytes)\n", unit->pcnu_name, ptr, packet_size));
847 /* Filter packet */
849 opener = request->ios2_BufferManagement;
850 if((request->ios2_Req.io_Command == CMD_READ) &&
851 (opener->filter_hook != NULL))
852 if(!CallHookPkt(opener->filter_hook, request, ptr))
854 D(bug("%s: CopyPacket: packet filtered\n", unit->pcnu_name));
855 filtered = TRUE;
858 if(!filtered)
860 /* Copy packet into opener's buffer and reply packet */
861 D(bug("%s: CopyPacket: opener recieve packet .. ", unit->pcnu_name));
862 if(!opener->rx_function(request->ios2_Data, ptr, packet_size))
864 D(bug("ERROR occured!!\n"));
865 request->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
866 request->ios2_WireError = S2WERR_BUFF_ERROR;
867 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF | S2EVENT_RX);
869 else
871 D(bug("SUCCESS!!\n"));
873 Disable();
874 Remove((APTR)request);
875 Enable();
876 ReplyMsg((APTR)request);
877 D(bug("%s: CopyPacket: opener notified.\n", unit->pcnu_name));
881 BOOL AddressFilter(struct PCN32Base *PCNet32Base, struct PCN32Unit *unit, UBYTE *address)
883 struct AddressRange *range, *tail;
884 BOOL accept = TRUE;
885 ULONG address_left;
886 UWORD address_right;
888 /* Check whether address is unicast/broadcast or multicast */
890 address_left = AROS_BE2LONG(*((ULONG *)address));
891 address_right = AROS_BE2WORD(*((UWORD *)(address + 4)));
893 if((address_left & 0x01000000) != 0 &&
894 !(address_left == 0xffffffff && address_right == 0xffff))
896 /* Check if this multicast address is wanted */
898 range = (APTR)unit->pcnu_multicast_ranges.mlh_Head;
899 tail = (APTR)&unit->pcnu_multicast_ranges.mlh_Tail;
900 accept = FALSE;
902 while((range != tail) && !accept)
904 if((address_left > range->lower_bound_left ||
905 (address_left == range->lower_bound_left &&
906 address_right >= range->lower_bound_right)) &&
907 (address_left < range->upper_bound_left ||
908 (address_left == range->upper_bound_left &&
909 address_right <= range->upper_bound_right)))
910 accept = TRUE;
911 range = (APTR)range->node.mln_Succ;
914 if(!accept)
915 unit->pcnu_special_stats[S2SS_ETHERNET_BADMULTICAST & 0xffff]++;
917 return accept;
921 * Unit process
923 AROS_UFH3(void, PCN32_Schedular,
924 AROS_UFHA(STRPTR, argPtr, A0),
925 AROS_UFHA(ULONG, argSize, D0),
926 AROS_UFHA(struct ExecBase *, SysBase, A6))
928 AROS_USERFUNC_INIT
930 struct PCN32Unit *dev = FindTask(NULL)->tc_UserData;
931 LIBBASETYPEPTR LIBBASE = dev->pcnu_device;
932 APTR BattClockBase;
933 struct MsgPort *reply_port, *input;
935 D(bug("[pcnet32] PCN32_Schedular()\n"));
936 D(bug("[pcnet32] PCN32_Schedular: Setting device up\n"));
938 reply_port = CreateMsgPort();
939 input = CreateMsgPort();
941 dev->pcnu_input_port = input;
943 /* Randomize the generator with current time */
944 BattClockBase = OpenResource("battclock.resource");
945 srandom(ReadBattClock());
947 dev->pcnu_TimerSlowPort = CreateMsgPort();
949 if (dev->pcnu_TimerSlowPort)
951 dev->pcnu_TimerSlowReq = (struct timerequest *)
952 CreateIORequest((struct MsgPort *)dev->pcnu_TimerSlowPort, sizeof(struct timerequest));
954 if (dev->pcnu_TimerSlowReq)
956 if (!OpenDevice("timer.device", UNIT_VBLANK,
957 (struct IORequest *)dev->pcnu_TimerSlowReq, 0))
959 struct Message *msg = AllocVec(sizeof(struct Message), MEMF_PUBLIC|MEMF_CLEAR);
960 ULONG sigset;
962 D(bug("[pcnet32] PCN32_Schedular: Got VBLANK unit of timer.device\n"));
964 dev->initialize(dev);
966 msg->mn_ReplyPort = reply_port;
967 msg->mn_Length = sizeof(struct Message);
969 D(bug("[pcnet32] PCN32_Schedular: Setup complete. Sending handshake\n"));
970 PutMsg(LIBBASE->pcnb_syncport, msg);
971 WaitPort(reply_port);
972 GetMsg(reply_port);
974 FreeVec(msg);
976 D(bug("[pcnet32] PCN32_Schedular: entering forever loop ... \n"));
978 dev->pcnu_signal_0 = AllocSignal(-1);
979 dev->pcnu_signal_1 = AllocSignal(-1);
980 dev->pcnu_signal_2 = AllocSignal(-1);
981 dev->pcnu_signal_3 = AllocSignal(-1);
983 sigset = 1 << input->mp_SigBit |
984 1 << dev->pcnu_signal_0 |
985 1 << dev->pcnu_signal_1 |
986 1 << dev->pcnu_signal_2 |
987 1 << dev->pcnu_signal_3;
988 for(;;)
990 ULONG recvd = Wait(sigset);
991 if (recvd & dev->pcnu_signal_0)
994 * Shutdown process. Driver should close everything
995 * already and waits for our process to complete. Free
996 * memory allocared here and kindly return.
998 dev->deinitialize(dev);
999 CloseDevice((struct IORequest *)dev->pcnu_TimerSlowReq);
1000 DeleteIORequest((struct IORequest *)dev->pcnu_TimerSlowReq);
1001 DeleteMsgPort(dev->pcnu_TimerSlowPort);
1002 DeleteMsgPort(input);
1003 DeleteMsgPort(reply_port);
1005 D(bug("[pcnet32] PCN32_Schedular: Process shutdown.\n"));
1006 return;
1008 else if (recvd & (1 << input->mp_SigBit))
1010 struct IOSana2Req *io;
1012 /* Handle incoming transactions */
1013 while ((io = (struct IOSana2Req *)GetMsg(input))!= NULL);
1015 D(bug("[pcnet32] PCN32_Schedular: Handle incomming transaction.\n"));
1016 ObtainSemaphore(&dev->pcnu_unit_lock);
1017 handle_request(LIBBASE, io);
1020 else
1022 D(bug("[pcnet32] PCN32_Schedular: Handle incomming signal.\n"));
1023 /* Handle incoming signals */
1030 AROS_USERFUNC_EXIT
1034 * Create new pcnet32 ethernet device unit
1036 struct PCN32Unit *CreateUnit(struct PCN32Base *PCNet32Base, OOP_Object *pciDevice)
1038 struct PCN32Unit *unit = AllocMem(sizeof(struct PCN32Unit), MEMF_PUBLIC | MEMF_CLEAR);
1039 BOOL success = TRUE;
1040 int i;
1042 D(bug("[pcnet32] CreateUnit()\n"));
1044 if (unit != NULL)
1046 IPTR DeviceID, base, len;
1047 OOP_Object *driver;
1049 OOP_GetAttr(pciDevice, aHidd_PCIDevice_ProductID, &DeviceID);
1050 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Driver, (APTR)&driver);
1052 unit->pcnu_device = PCNet32Base;
1053 unit->pcnu_DeviceID = DeviceID;
1054 unit->pcnu_mtu = ETH_MTU;
1055 unit->pcnu_PCIDevice = pciDevice;
1056 unit->pcnu_PCIDriver = driver;
1058 InitSemaphore(&unit->pcnu_unit_lock);
1059 NEWLIST(&unit->pcnu_Openers);
1060 NEWLIST(&unit->pcnu_multicast_ranges);
1061 NEWLIST(&unit->pcnu_type_trackers);
1063 OOP_GetAttr(pciDevice, aHidd_PCIDevice_INTLine, &unit->pcnu_IRQ);
1064 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base1, &unit->pcnu_BaseIO);
1065 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base0, &base);
1066 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Size0, &len);
1068 unit->pcnu_BaseMem = (IPTR)HIDD_PCIDriver_MapPCI(driver, (APTR)base, len);
1069 unit->pcnu_SizeMem = len;
1071 if (unit->pcnu_BaseMem)
1073 struct TagItem attrs[] = {
1074 { aHidd_PCIDevice_isIO, TRUE },
1075 { aHidd_PCIDevice_isMEM, TRUE },
1076 { aHidd_PCIDevice_isMaster, TRUE },
1077 { TAG_DONE, 0 },
1079 OOP_SetAttrs(pciDevice, (struct TagItem *)&attrs);
1081 unit->pcnu_name = "[pcnet32.0]";
1083 unit->pcnu_fe_priv = AllocMem(sizeof(struct fe_priv), MEMF_PUBLIC|MEMF_CLEAR);
1085 unit->pcnu_fe_priv->fep_pcnet_init_block = HIDD_PCIDriver_AllocPCIMem(
1086 driver,
1087 sizeof(struct pcnet32_init_block));
1089 unit->pcnu_UnitNum = 0;
1091 pcn32_get_functions(unit);
1093 if (unit->pcnu_fe_priv)
1095 unit->pcnu_fe_priv->pci_dev = unit;
1096 InitSemaphore(&unit->pcnu_fe_priv->lock);
1098 unit->pcnu_irqhandler = AllocMem(sizeof(HIDDT_IRQ_Handler), MEMF_PUBLIC|MEMF_CLEAR);
1099 unit->pcnu_touthandler = AllocMem(sizeof(HIDDT_IRQ_Handler), MEMF_PUBLIC|MEMF_CLEAR);
1101 if (unit->pcnu_irqhandler && unit->pcnu_touthandler)
1103 struct Message *msg;
1105 unit->pcnu_irqhandler->h_Node.ln_Pri = 100;
1106 unit->pcnu_irqhandler->h_Node.ln_Name = LIBBASE->pcnb_Device.dd_Library.lib_Node.ln_Name;
1107 unit->pcnu_irqhandler->h_Code = PCN32_IntHandler;
1108 unit->pcnu_irqhandler->h_Data = unit;
1110 unit->pcnu_touthandler->h_Node.ln_Pri = 100;
1111 unit->pcnu_touthandler->h_Node.ln_Name = LIBBASE->pcnb_Device.dd_Library.lib_Node.ln_Name;
1112 unit->pcnu_touthandler->h_Code = PCN32_TimeoutHandler;
1113 unit->pcnu_touthandler->h_Data = unit;
1115 unit->pcnu_rx_int.is_Node.ln_Name = unit->pcnu_name;
1116 unit->pcnu_rx_int.is_Code = PCN32_RX_Int;
1117 unit->pcnu_rx_int.is_Data = unit;
1119 unit->pcnu_tx_int.is_Node.ln_Name = unit->pcnu_name;
1120 unit->pcnu_tx_int.is_Code = PCN32_TX_Int;
1121 unit->pcnu_tx_int.is_Data = unit;
1123 unit->pcnu_tx_end_int.is_Node.ln_Name = unit->pcnu_name;
1124 unit->pcnu_tx_end_int.is_Code = PCN32_TX_End_Int;
1125 unit->pcnu_tx_end_int.is_Data = unit;
1127 for (i=0; i < REQUEST_QUEUE_COUNT; i++)
1129 struct MsgPort *port = AllocMem(sizeof(struct MsgPort), MEMF_PUBLIC | MEMF_CLEAR);
1130 unit->pcnu_request_ports[i] = port;
1132 if (port == NULL) success = FALSE;
1134 if (success)
1136 NEWLIST(&port->mp_MsgList);
1137 port->mp_Flags = PA_IGNORE;
1138 port->mp_SigTask = &unit->pcnu_tx_int;
1142 unit->pcnu_request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
1144 if (success)
1146 D(bug("%s: Initialise Dev @ %x, IOBase @ %x\n", unit->pcnu_name, unit, unit->pcnu_BaseMem));
1148 pcnet32_reset_16(unit->pcnu_BaseMem);
1150 D(bug("%s: Chipset RESET\n", unit->pcnu_name));
1152 i = pcnet32_readcsr_16(unit->pcnu_BaseMem, 0); // Check for 16bit/32bit chip IO
1153 BOOL check = pcnet32_check_16(unit->pcnu_BaseMem);
1155 if ((i == 4)&&(check))
1157 D(bug("%s: Using 16bit I/O Funcs\n", unit->pcnu_name));
1158 unit->read_csr = pcnet32_readcsr_16;
1159 unit->write_csr = pcnet32_writecsr_16;
1160 unit->read_bcr = pcnet32_readbcr_16;
1161 unit->write_bcr = pcnet32_writebcr_16;
1162 unit->read_rap = pcnet32_readrap_16;
1163 unit->write_rap = pcnet32_writerap_16;
1164 unit->reset = pcnet32_reset_16;
1166 else
1168 pcnet32_reset_32(unit->pcnu_BaseMem); // 32bit reset..
1170 i = pcnet32_readcsr_32(unit->pcnu_BaseMem, 0);
1171 check = pcnet32_check_32(unit->pcnu_BaseMem);
1173 if ((i == 4)&&(check))
1175 D(bug("%s: Using 32bit I/O Funcs\n", unit->pcnu_name));
1176 unit->read_csr = pcnet32_readcsr_32;
1177 unit->write_csr = pcnet32_writecsr_32;
1178 unit->read_bcr = pcnet32_readbcr_32;
1179 unit->write_bcr = pcnet32_writebcr_32;
1180 unit->read_rap = pcnet32_readrap_32;
1181 unit->write_rap = pcnet32_writerap_32;
1182 unit->reset = pcnet32_reset_32;
1184 else
1186 D(bug("%s: Error - Unsupported chipset .. (unknown data size)\n", unit->pcnu_name));
1187 success = FALSE;
1191 if (success)
1193 i = (unit->read_csr(unit->pcnu_BaseMem, 88) | ( unit->read_csr(unit->pcnu_BaseMem, 89) << 16));
1195 unit->pcnu_pcnet_chiprevision = (i >> 12) & 0xffff;
1197 D(bug("%s: PCnet chip version %x [%x]\n", unit->pcnu_name, i, unit->pcnu_pcnet_chiprevision));
1199 unit->pcnu_pcnet_supported = 0;
1201 switch (unit->pcnu_pcnet_chiprevision)
1203 case 0x2420:
1204 case 0x2430:
1205 unit->pcnu_pcnet_chipname = "PCnet/PCI 79c970";
1206 break;
1208 case 0x2621:
1209 unit->pcnu_pcnet_chipname = "PCnet/PCI II 79c970A";
1210 unit->pcnu_pcnet_supported |= support_fdx;
1211 break;
1213 case 0x2623:
1214 unit->pcnu_pcnet_chipname = "PCnet/FAST 79c971";
1215 unit->pcnu_pcnet_supported |= (support_fdx | support_mii | support_fset | support_ltint );
1216 break;
1218 case 0x2624:
1219 unit->pcnu_pcnet_chipname = "PCnet/FAST+ 79c972";
1220 unit->pcnu_pcnet_supported |= (support_fdx | support_mii | support_fset );
1221 break;
1223 case 0x2625:
1224 unit->pcnu_pcnet_chipname = "PCnet/FAST III 79c973";
1225 unit->pcnu_pcnet_supported |= (support_fdx | support_mii );
1226 break;
1228 case 0x2627:
1229 unit->pcnu_pcnet_chipname = "PCnet/FAST III 79c975";
1230 unit->pcnu_pcnet_supported |= (support_fdx | support_mii );
1231 break;
1233 case 0x2626:
1234 unit->pcnu_pcnet_chipname = "PCnet/Home 79c978";
1235 unit->pcnu_pcnet_supported |= support_fdx;
1237 #warning "TODO: PCnet/Home needs extra set up .."
1238 break;
1239 default:
1240 D(bug("%s: ERROR - Unsupported Chipset (unknown revision)\n", unit->pcnu_name));
1241 success = FALSE;
1243 #if defined(DEBUG)
1244 D(bug("%s: Found %s chipset based NIC\n", unit->pcnu_name, unit->pcnu_pcnet_chipname));
1245 if (unit->pcnu_pcnet_supported & support_fdx)
1246 D(bug("%s: Chip Supports Full Duplex\n", unit->pcnu_name));
1247 if (unit->pcnu_pcnet_supported & support_mii)
1248 D(bug("%s: Chip Supports MII\n", unit->pcnu_name));
1249 if (unit->pcnu_pcnet_supported & support_fset)
1250 D(bug("%s: Chip Supports FSET\n", unit->pcnu_name));
1251 if (unit->pcnu_pcnet_supported & support_ltint)
1252 D(bug("%s: Chip Supports LTINT\n", unit->pcnu_name));
1253 #endif
1255 if (((unit->pcnu_pcnet_chiprevision +1) & 0xfffe) == 0x2624)
1257 i = unit->read_csr(unit->pcnu_BaseMem, 80) & 0x0c00; /* Check tx_start_pt */
1258 #if defined(DEBUG)
1259 D(bug("%s: tx_start_pt(0x%hX):", unit->pcnu_name, i));
1260 switch(i >> 10)
1262 case 0:
1263 D(bug(" 20 bytes,"));
1264 break;
1265 case 1:
1266 D(bug(" 64 bytes,"));
1267 break;
1268 case 2:
1269 D(bug(" 128 bytes,"));
1270 break;
1271 case 3:
1272 D(bug("~220 bytes,"));
1273 break;
1275 #endif
1276 i = unit->read_bcr(unit->pcnu_BaseMem, 18); /* Check burst/bus control */
1277 #if defined(DEBUG)
1278 D(bug(" BCR18(%hX):", i & 0xffff));
1279 if (i & (1 << 5))
1280 D(bug("BurstWrEn "));
1281 if (i & (1 << 6))
1282 D(bug("BurstRdEn "));
1283 if (i & (1 << 7))
1284 D(bug("32bitIO "));
1285 if (i & (1 << 11))
1286 D(bug("NoUFlow "));
1287 #endif
1288 i = unit->read_bcr(unit->pcnu_BaseMem, 25);
1289 D(bug(" SRAMSIZE=0x%hX,", i << 8));
1290 i = unit->read_bcr(unit->pcnu_BaseMem, 26);
1291 D(bug(" SRAM_BND=0x%hX,", i << 8));
1292 i = unit->read_bcr(unit->pcnu_BaseMem, 27);
1293 #if defined(DEBUG)
1294 if (i & (1 << 14))
1295 D(bug("LowLatRx"));
1296 #endif
1297 D(bug("\n"));
1302 if (success)
1304 LIBBASE->pcnb_syncport = CreateMsgPort();
1306 unit->pcnu_Process = CreateNewProcTags(
1307 NP_Entry, (IPTR)PCN32_Schedular,
1308 NP_Name, PCNET32_TASK_NAME,
1309 NP_Priority, 0,
1310 NP_UserData, (IPTR)unit,
1311 NP_StackSize, 140960,
1312 TAG_DONE);
1314 WaitPort(LIBBASE->pcnb_syncport);
1315 msg = GetMsg(LIBBASE->pcnb_syncport);
1316 ReplyMsg(msg);
1317 DeleteMsgPort(LIBBASE->pcnb_syncport);
1319 D(bug("[pcnet32] Unit up and running\n"));
1321 return unit;
1323 else
1325 D(bug("%s: ERRORS occured during Device setup - ABORTING\n", unit->pcnu_name));
1330 else
1331 D(bug("[pcnet32] PANIC! Couldn't get MMIO area. Aborting\n"));
1333 DeleteUnit(PCNet32Base, unit);
1334 return NULL;
1338 * DeleteUnit - removes selected unit. Frees all resources and structures.
1340 * The caller should be sure, that given unit is really ready to be freed.
1343 void DeleteUnit(struct PCN32Base *PCNet32Base, struct PCN32Unit *Unit)
1345 int i;
1346 if (Unit)
1348 if (Unit->pcnu_Process)
1350 Signal(&Unit->pcnu_Process->pr_Task, Unit->pcnu_signal_0);
1353 for (i=0; i < REQUEST_QUEUE_COUNT; i++)
1355 if (Unit->pcnu_request_ports[i] != NULL)
1356 FreeMem(Unit->pcnu_request_ports[i], sizeof(struct MsgPort));
1358 Unit->pcnu_request_ports[i] = NULL;
1361 if (Unit->pcnu_irqhandler)
1363 FreeMem(Unit->pcnu_irqhandler, sizeof(HIDDT_IRQ_Handler));
1364 LIBBASE->pcnb_irq = NULL;
1367 if (Unit->pcnu_fe_priv)
1369 FreeMem(Unit->pcnu_fe_priv, sizeof(struct fe_priv));
1370 Unit->pcnu_fe_priv = NULL;
1373 if (Unit->pcnu_BaseMem)
1375 HIDD_PCIDriver_UnmapPCI(Unit->pcnu_PCIDriver,
1376 (APTR)Unit->pcnu_BaseMem,
1377 Unit->pcnu_SizeMem);
1380 FreeMem(Unit, sizeof(struct PCN32Unit));
1384 static struct AddressRange *FindMulticastRange(LIBBASETYPEPTR LIBBASE, struct PCN32Unit *unit,
1385 ULONG lower_bound_left, UWORD lower_bound_right, ULONG upper_bound_left, UWORD upper_bound_right)
1387 struct AddressRange *range, *tail;
1388 BOOL found = FALSE;
1390 range = (APTR)unit->pcnu_multicast_ranges.mlh_Head;
1391 tail = (APTR)&unit->pcnu_multicast_ranges.mlh_Tail;
1393 while((range != tail) && !found)
1395 if((lower_bound_left == range->lower_bound_left) &&
1396 (lower_bound_right == range->lower_bound_right) &&
1397 (upper_bound_left == range->upper_bound_left) &&
1398 (upper_bound_right == range->upper_bound_right))
1399 found = TRUE;
1400 else
1401 range = (APTR)range->node.mln_Succ;
1404 if(!found)
1405 range = NULL;
1407 return range;
1410 BOOL AddMulticastRange(LIBBASETYPEPTR LIBBASE, struct PCN32Unit *unit, const UBYTE *lower_bound,
1411 const UBYTE *upper_bound)
1413 struct AddressRange *range;
1414 ULONG lower_bound_left, upper_bound_left;
1415 UWORD lower_bound_right, upper_bound_right;
1417 lower_bound_left = AROS_BE2LONG(*((ULONG *)lower_bound));
1418 lower_bound_right = AROS_BE2WORD(*((UWORD *)(lower_bound + 4)));
1419 upper_bound_left = AROS_BE2LONG(*((ULONG *)upper_bound));
1420 upper_bound_right = AROS_BE2WORD(*((UWORD *)(upper_bound + 4)));
1422 range = FindMulticastRange(LIBBASE, unit, lower_bound_left, lower_bound_right,
1423 upper_bound_left, upper_bound_right);
1425 if(range != NULL)
1426 range->add_count++;
1427 else
1429 range = AllocMem(sizeof(struct AddressRange), MEMF_PUBLIC);
1430 if(range != NULL)
1432 range->lower_bound_left = lower_bound_left;
1433 range->lower_bound_right = lower_bound_right;
1434 range->upper_bound_left = upper_bound_left;
1435 range->upper_bound_right = upper_bound_right;
1436 range->add_count = 1;
1438 Disable();
1439 AddTail((APTR)&unit->pcnu_multicast_ranges, (APTR)range);
1440 Enable();
1442 if (unit->pcnu_range_count++ == 0)
1444 unit->pcnu_flags |= IFF_ALLMULTI;
1445 unit->set_multicast(unit);
1450 return range != NULL;
1453 BOOL RemMulticastRange(LIBBASETYPEPTR LIBBASE, struct PCN32Unit *unit, const UBYTE *lower_bound, const UBYTE *upper_bound)
1455 struct AddressRange *range;
1456 ULONG lower_bound_left, upper_bound_left;
1457 UWORD lower_bound_right, upper_bound_right;
1459 lower_bound_left = AROS_BE2LONG(*((ULONG *)lower_bound));
1460 lower_bound_right = AROS_BE2WORD(*((UWORD *)(lower_bound + 4)));
1461 upper_bound_left = AROS_BE2LONG(*((ULONG *)upper_bound));
1462 upper_bound_right = AROS_BE2WORD(*((UWORD *)(upper_bound + 4)));
1464 range = FindMulticastRange(LIBBASE, unit, lower_bound_left, lower_bound_right,
1465 upper_bound_left, upper_bound_right);
1467 if(range != NULL)
1469 if(--range->add_count == 0)
1471 Disable();
1472 Remove((APTR)range);
1473 Enable();
1474 FreeMem(range, sizeof(struct AddressRange));
1476 if (--unit->pcnu_range_count == 0)
1478 unit->pcnu_flags &= ~IFF_ALLMULTI;
1479 unit->set_multicast(unit);
1483 return range != NULL;