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,
22 #include <exec/types.h>
23 #include <exec/resident.h>
25 #include <exec/ports.h>
26 #include <exec/errors.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>
50 #include LC_LIBDEFS_FILE
53 volatile UBYTE
readb(APTR base
)
57 volatile void writeb(UBYTE val
, APTR base
)
63 volatile UWORD
readw(APTR base
)
67 volatile void writew(UWORD val
, APTR base
)
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
)
122 static int pcnet32_check_16(APTR base
)
124 writew(88, base
+ 0x12);
125 return (readw( base
+ 0x12) == 88);
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
)
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
;
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 */
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
);
206 struct TypeStats
*FindTypeStats(struct PCN32Base
*PCNet32Base
, struct PCN32Unit
*unit
,
207 struct MinList
*list
, ULONG packet_type
)
209 struct TypeStats
*stats
, *tail
;
212 stats
= (APTR
)list
->mlh_Head
;
213 tail
= (APTR
)&list
->mlh_Tail
;
215 while(stats
!= tail
&& !found
)
217 if(stats
->packet_type
== packet_type
)
220 stats
= (APTR
)stats
->node
.mln_Succ
;
229 void FlushUnit(LIBBASETYPEPTR LIBBASE
, struct PCN32Unit
*unit
, UBYTE last_queue
, BYTE error
)
231 struct IORequest
*request
;
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 */
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
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
))
286 struct PCN32Base
*PCNet32Base
= unit
->pcnu_device
;
287 struct fe_priv
*np
= unit
->pcnu_fe_priv
;
289 struct TypeStats
*tracker
;
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
));
298 /* Endless loop, with break from inside */
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
++;
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
++;
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
++;
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
++;
359 if (Flags
& (1 << 13)) { // Framing Error
360 ReportEvents(LIBBASE
, unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_RX
);
361 unit
->pcnu_stats
.BadData
++;
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
];
371 /* Dump contents of frame if DEBUG enabled */
375 for (j
=0; j
<64; j
++) {
377 D(bug("\n%03x:", j
));
378 D(bug(" %02x", ((unsigned char*)frame
)[j
]));
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
;
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
);
413 (struct IOSana2Req
*)request
->ios2_Req
.io_Message
.mn_Node
.ln_Succ
;
419 opener
= (APTR
)opener
->node
.mln_Succ
;
422 /* If packet was unwanted, give it to S2_READORPHAN request */
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 */
439 FindTypeStats(LIBBASE
, unit
, &unit
->pcnu_type_trackers
, packet_type
);
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
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
))
467 struct fe_priv
*np
= unit
->pcnu_fe_priv
;
468 struct PCN32Base
*PCNet32Base
= unit
->pcnu_device
;
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
;
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
;
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
;
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
524 /* Now the packet is already in TX buffer, update flags for NIC */
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 */
534 for (j
=0; j
<64; j
++) {
536 D(bug("\n%03x:", j
));
537 D(bug(" %02x", ((unsigned char*)&np
->tx_buffer
[nr
])[j
]));
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
));
557 request
->ios2_Req
.io_Error
= error
;
558 request
->ios2_WireError
= wire_error
;
560 Remove((APTR
)request
);
562 ReplyMsg((APTR
)request
);
564 /* Update statistics */
568 tracker
= FindTypeStats(LIBBASE
, unit
, &unit
->pcnu_type_trackers
,
569 request
->ios2_PacketType
);
572 tracker
->stats
.PacketsSent
++;
573 tracker
->stats
.BytesSent
+= packet_size
;
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
);
594 /* Was there success? Enable incomming of new packets */
596 unit
->pcnu_request_ports
[WRITE_QUEUE
]->mp_Flags
= PA_SOFTINT
;
598 unit
->pcnu_request_ports
[WRITE_QUEUE
]->mp_Flags
= PA_IGNORE
;
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
))
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
));
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;
663 D(bug("%s: PCN32_TX_End_Int: TxRing packet unused ..??\n", unit
->pcnu_name
));
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
;
684 struct Device
*TimerBase
= dev
->pcnu_TimerSlowReq
->tr_node
.io_Device
;
687 //D(bug("%s: PCN32_TimeoutHandler()\n", dev->pcnu_name));
690 * If timeout timer is expected, and time elapsed - regenerate the
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.
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
;
719 struct Device
*TimerBase
= dev
->pcnu_TimerSlowReq
->tr_node
.io_Device
;
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?
742 if ( csr_0
& (1 << 2) ) // (STOP) Chipset is stopped
748 if ( csr_0
& (1 << 4) ) // (TXON) Transmitter ON?
755 D(bug("[TXON:OFF]"));
758 if ( csr_0
& (1 << 5) ) // (RXON) Reciever ON?
765 D(bug("[RXON:OFF]"));
768 if ( csr_0
& (1 << 8) ) // (IDON) Initialisation Done?
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
));
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
;
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];
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
));
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
));
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
);
871 D(bug("SUCCESS!!\n"));
874 Remove((APTR
)request
);
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
;
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
;
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
)))
911 range
= (APTR
)range
->node
.mln_Succ
;
915 unit
->pcnu_special_stats
[S2SS_ETHERNET_BADMULTICAST
& 0xffff]++;
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
))
930 struct PCN32Unit
*dev
= FindTask(NULL
)->tc_UserData
;
931 LIBBASETYPEPTR LIBBASE
= dev
->pcnu_device
;
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
);
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
);
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
;
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"));
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
);
1022 D(bug("[pcnet32] PCN32_Schedular: Handle incomming signal.\n"));
1023 /* Handle incoming signals */
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
;
1042 D(bug("[pcnet32] CreateUnit()\n"));
1046 IPTR DeviceID
, base
, len
;
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
},
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(
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
;
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
;
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
;
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
;
1186 D(bug("%s: Error - Unsupported chipset .. (unknown data size)\n", unit
->pcnu_name
));
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
)
1205 unit
->pcnu_pcnet_chipname
= "PCnet/PCI 79c970";
1209 unit
->pcnu_pcnet_chipname
= "PCnet/PCI II 79c970A";
1210 unit
->pcnu_pcnet_supported
|= support_fdx
;
1214 unit
->pcnu_pcnet_chipname
= "PCnet/FAST 79c971";
1215 unit
->pcnu_pcnet_supported
|= (support_fdx
| support_mii
| support_fset
| support_ltint
);
1219 unit
->pcnu_pcnet_chipname
= "PCnet/FAST+ 79c972";
1220 unit
->pcnu_pcnet_supported
|= (support_fdx
| support_mii
| support_fset
);
1224 unit
->pcnu_pcnet_chipname
= "PCnet/FAST III 79c973";
1225 unit
->pcnu_pcnet_supported
|= (support_fdx
| support_mii
);
1229 unit
->pcnu_pcnet_chipname
= "PCnet/FAST III 79c975";
1230 unit
->pcnu_pcnet_supported
|= (support_fdx
| support_mii
);
1234 unit
->pcnu_pcnet_chipname
= "PCnet/Home 79c978";
1235 unit
->pcnu_pcnet_supported
|= support_fdx
;
1237 #warning "TODO: PCnet/Home needs extra set up .."
1240 D(bug("%s: ERROR - Unsupported Chipset (unknown revision)\n", unit
->pcnu_name
));
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
));
1255 if (((unit
->pcnu_pcnet_chiprevision
+1) & 0xfffe) == 0x2624)
1257 i
= unit
->read_csr(unit
->pcnu_BaseMem
, 80) & 0x0c00; /* Check tx_start_pt */
1259 D(bug("%s: tx_start_pt(0x%hX):", unit
->pcnu_name
, i
));
1263 D(bug(" 20 bytes,"));
1266 D(bug(" 64 bytes,"));
1269 D(bug(" 128 bytes,"));
1272 D(bug("~220 bytes,"));
1276 i
= unit
->read_bcr(unit
->pcnu_BaseMem
, 18); /* Check burst/bus control */
1278 D(bug(" BCR18(%hX):", i
& 0xffff));
1280 D(bug("BurstWrEn "));
1282 D(bug("BurstRdEn "));
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);
1304 LIBBASE
->pcnb_syncport
= CreateMsgPort();
1306 unit
->pcnu_Process
= CreateNewProcTags(
1307 NP_Entry
, (IPTR
)PCN32_Schedular
,
1308 NP_Name
, PCNET32_TASK_NAME
,
1310 NP_UserData
, (IPTR
)unit
,
1311 NP_StackSize
, 140960,
1314 WaitPort(LIBBASE
->pcnb_syncport
);
1315 msg
= GetMsg(LIBBASE
->pcnb_syncport
);
1317 DeleteMsgPort(LIBBASE
->pcnb_syncport
);
1319 D(bug("[pcnet32] Unit up and running\n"));
1325 D(bug("%s: ERRORS occured during Device setup - ABORTING\n", unit
->pcnu_name
));
1331 D(bug("[pcnet32] PANIC! Couldn't get MMIO area. Aborting\n"));
1333 DeleteUnit(PCNet32Base
, unit
);
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
)
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
;
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
))
1401 range
= (APTR
)range
->node
.mln_Succ
;
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
);
1429 range
= AllocMem(sizeof(struct AddressRange
), MEMF_PUBLIC
);
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;
1439 AddTail((APTR
)&unit
->pcnu_multicast_ranges
, (APTR
)range
);
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
);
1469 if(--range
->add_count
== 0)
1472 Remove((APTR
)range
);
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
;