grub2: bring back build of aros-side grub2 tools
[AROS.git] / workbench / devs / networks / sis900 / unit.c
blob4574efe95bcabc7625a5a71f0ae144466e519537
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/oop.h>
42 #include <proto/timer.h>
43 #include <proto/utility.h>
45 #include <stdlib.h>
46 #include <stdio.h>
48 #include "sis900.h"
49 #include "unit.h"
50 #include LC_LIBDEFS_FILE
53 * Report incoming events to all hyphotetical event receivers
55 VOID ReportEvents(struct SiS900Base *SiS900DeviceBase, struct SiS900Unit *unit, ULONG events)
57 struct IOSana2Req *request, *tail, *next_request;
58 struct List *list;
60 list = &unit->sis900u_request_ports[EVENT_QUEUE]->mp_MsgList;
61 next_request = (APTR)list->lh_Head;
62 tail = (APTR)&list->lh_Tail;
64 /* Go through list of event listeners. If send messages to receivers if event found */
65 Disable();
66 while(next_request != tail)
68 request = next_request;
69 next_request = (APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
71 if((request->ios2_WireError&events) != 0)
73 request->ios2_WireError = events;
74 Remove((APTR)request);
75 ReplyMsg((APTR)request);
78 Enable();
80 return;
83 struct TypeStats *FindTypeStats(struct SiS900Base *SiS900DeviceBase, struct SiS900Unit *unit,
84 struct MinList *list, ULONG packet_type)
86 struct TypeStats *stats, *tail;
87 BOOL found = FALSE;
89 stats = (APTR)list->mlh_Head;
90 tail = (APTR)&list->mlh_Tail;
92 while(stats != tail && !found)
94 if(stats->packet_type == packet_type)
95 found = TRUE;
96 else
97 stats = (APTR)stats->node.mln_Succ;
100 if(!found)
101 stats = NULL;
103 return stats;
106 void FlushUnit(LIBBASETYPEPTR LIBBASE, struct SiS900Unit *unit, UBYTE last_queue, BYTE error)
108 struct IORequest *request;
109 UBYTE i;
110 struct Opener *opener, *tail;
112 D(bug("%s unit.FlushUnit\n", unit->sis900u_name));
114 /* Abort queued operations */
116 for (i=0; i <= last_queue; i++)
118 while ((request = (APTR)GetMsg(unit->sis900u_request_ports[i])) != NULL)
120 request->io_Error = IOERR_ABORTED;
121 ReplyMsg((struct Message *)request);
125 opener = (APTR)unit->sis900u_Openers.mlh_Head;
126 tail = (APTR)unit->sis900u_Openers.mlh_Tail;
128 /* Flush every opener's read queue */
130 while(opener != tail)
132 while ((request = (APTR)GetMsg(&opener->read_port)) != NULL)
134 request->io_Error = error;
135 ReplyMsg((struct Message *)request);
137 opener = (struct Opener *)opener->node.mln_Succ;
142 * Interrupt handler called whenever SiS900 NIC interface generates interrupt.
143 * It's duty is to iterate throgh RX queue searching for new packets.
145 * Please note, that allthough multicast support could be done on interface
146 * basis, it is done in this function as result of quick integration of both
147 * the forcedeth driver (IFF_ALLMULTI flag) and etherling3 driver (AddressMatch
148 * filter function).
150 static AROS_INTH1(SiS900_RX_IntF, struct SiS900Unit *, unit)
152 AROS_INTFUNC_INIT
154 struct SiS900Base *SiS900DeviceBase = unit->sis900u_device;
155 struct TypeStats *tracker;
156 ULONG packet_type;
157 struct Opener *opener, *opener_tail;
158 struct IOSana2Req *request, *request_tail;
159 BOOL accepted, is_orphan;
161 unsigned int entry = unit->cur_rx % NUM_RX_DESC;
162 ULONG rx_status = unit->rx_ring[entry].cmdsts;
164 D(bug("[%s]: SiS900_RX_IntF() !!!!\n", unit->sis900u_name));
165 D(bug("[%s]: SiS900_RX_IntF: cur_rx:%4.4d, dirty_rx:%4.4d status:0x%8.8x\n", unit->sis900u_name, unit->cur_rx, unit->dirty_rx, rx_status));
167 while (rx_status & OWN)
169 unsigned int rx_size;
170 // int i;
171 struct eth_frame *frame;
173 rx_size = (rx_status & DSIZE) - CRC_SIZE;
175 if (rx_status & (ABORT|OVERRUN|TOOLONG|RUNT|RXISERR|CRCERR|FAERR))
177 /* corrupted packet received */
178 D(bug("[%s]: SiS900_RX_IntF: Corrupted packet received, buffer status = 0x%8.8x.\n", unit->sis900u_name, rx_status));
179 // unit->stats.rx_errors++;
180 if (rx_status & OVERRUN)
182 // unit->stats.rx_over_errors++;
184 if (rx_status & (TOOLONG|RUNT))
186 // unit->stats.rx_length_errors++;
188 if (rx_status & (RXISERR | FAERR))
190 // unit->stats.rx_frame_errors++;
192 if (rx_status & CRCERR)
194 // unit->stats.rx_crc_errors++;
196 /* reset buffer descriptor state */
197 unit->rx_ring[entry].cmdsts = RX_BUF_SIZE;
199 else
201 /* got a valid packet - forward it to the network core */
202 frame = unit->rx_buffers[entry];
203 is_orphan = TRUE;
205 /* Dump contents of frame if DEBUG enabled */
206 #ifdef DEBUG
208 int j;
209 for (j=0; j<64; j++) {
210 if ((j%16) == 0)
211 D(bug("\n%03x:", j));
212 D(bug(" %02x", ((unsigned char*)frame)[j]));
214 D(bug("\n"));
216 #endif
218 /* Check for address validity */
219 if(AddressFilter(LIBBASE, unit, frame->eth_packet_dest))
221 /* Packet is addressed to this driver */
222 packet_type = AROS_BE2WORD(frame->eth_packet_type);
223 D(bug("[%s]: SiS900_RX_IntF: Packet IP accepted with type = %d\n", unit->sis900u_name, packet_type));
225 opener = (APTR)unit->sis900u_Openers.mlh_Head;
226 opener_tail = (APTR)&unit->sis900u_Openers.mlh_Tail;
228 /* Offer packet to every opener */
229 while(opener != opener_tail)
231 request = (APTR)opener->read_port.mp_MsgList.lh_Head;
232 request_tail = (APTR)&opener->read_port.mp_MsgList.lh_Tail;
233 accepted = FALSE;
235 /* Offer packet to each request until it's accepted */
236 while((request != request_tail) && !accepted)
238 if((request->ios2_PacketType == packet_type)
239 || ((request->ios2_PacketType <= ETH_MTU)
240 && (packet_type <= ETH_MTU)))
242 D(bug("[%s]: SiS900_RX_IntF: copy packet for opener ..\n", unit->sis900u_name));
243 CopyPacket(LIBBASE, unit, request, rx_size, packet_type, frame);
244 accepted = TRUE;
246 request =
247 (struct IOSana2Req *)request->ios2_Req.io_Message.mn_Node.ln_Succ;
250 if(accepted)
251 is_orphan = FALSE;
253 opener = (APTR)opener->node.mln_Succ;
256 /* If packet was unwanted, give it to S2_READORPHAN request */
257 if(is_orphan)
259 unit->sis900u_stats.UnknownTypesReceived++;
261 if(!IsMsgPortEmpty(unit->sis900u_request_ports[ADOPT_QUEUE]))
263 CopyPacket(LIBBASE, unit,
264 (APTR)unit->sis900u_request_ports[ADOPT_QUEUE]->
265 mp_MsgList.lh_Head, rx_size, packet_type, frame);
266 D(bug("[%s]: SiS900_RX_IntF: packet copied to orphan queue\n", unit->sis900u_name));
270 /* Update remaining statistics */
272 tracker =
273 FindTypeStats(LIBBASE, unit, &unit->sis900u_type_trackers, packet_type);
275 if(tracker != NULL)
277 tracker->stats.PacketsReceived++;
278 tracker->stats.BytesReceived += rx_size;
281 unit->sis900u_stats.PacketsReceived++;
283 unit->rx_ring[entry].cmdsts = RX_BUF_SIZE;
284 unit->dirty_rx++;
286 unit->cur_rx++;
287 entry = unit->cur_rx % NUM_RX_DESC;
288 rx_status = unit->rx_ring[entry].cmdsts;
291 return FALSE;
293 AROS_INTFUNC_EXIT
297 * Interrupt generated by Cause() to push new packets into the NIC interface
299 static AROS_INTH1(SiS900_TX_IntF, struct SiS900Unit *,unit)
301 AROS_INTFUNC_INIT
303 struct SiS900Base *SiS900DeviceBase = unit->sis900u_device;
304 long ioaddr = unit->sis900u_BaseMem;
305 BOOL proceed = FALSE; /* Fails by default */
307 unsigned int entry;
308 unsigned int index_cur_tx, index_dirty_tx;
309 unsigned int count_dirty_tx;
311 D(bug("[%s]: SiS900_TX_IntF()\n", unit->sis900u_name));
313 /* send packet only if there is free space on tx queue. Otherwise do nothing */
314 if (!netif_queue_stopped(unit))
316 UWORD packet_size, data_size;
317 struct IOSana2Req *request;
318 struct Opener *opener;
319 UBYTE *buffer;
320 ULONG wire_error=0;
321 BYTE error;
322 struct MsgPort *port;
323 struct TypeStats *tracker;
325 proceed = TRUE; /* Success by default */
326 port = unit->sis900u_request_ports[WRITE_QUEUE];
328 /* Still no error and there are packets to be sent? */
329 while(proceed && (!IsMsgPortEmpty(port)))
331 entry = unit->cur_tx % NUM_TX_DESC;
332 error = 0;
334 request = (APTR)port->mp_MsgList.lh_Head;
335 data_size = packet_size = request->ios2_DataLength;
337 opener = (APTR)request->ios2_BufferManagement;
339 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
341 packet_size += ETH_PACKET_DATA;
342 CopyMem(request->ios2_DstAddr, &((struct eth_frame *)unit->tx_buffers[entry])->eth_packet_dest, ETH_ADDRESSSIZE);
343 CopyMem(unit->sis900u_dev_addr, &((struct eth_frame *)unit->tx_buffers[entry])->eth_packet_source, ETH_ADDRESSSIZE);
344 ((struct eth_frame *)unit->tx_buffers[entry])->eth_packet_type = AROS_WORD2BE(request->ios2_PacketType);
346 buffer = (UBYTE *)&((struct eth_frame *)(IPTR)unit->tx_buffers[entry])->eth_packet_data;
348 else
349 buffer = unit->tx_buffers[entry];
351 if (!opener->tx_function(buffer, request->ios2_Data, data_size))
353 error = S2ERR_NO_RESOURCES;
354 wire_error = S2WERR_BUFF_ERROR;
355 ReportEvents(LIBBASE, unit,
356 S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF
357 | S2EVENT_TX);
360 /* Now the packet is already in TX buffer, update flags for NIC */
361 if (error == 0)
363 Disable();
364 D(bug("[%s]: SiS900_TX_IntF: packet %d @ %x [type = %d] queued for transmission.", unit->sis900u_name, entry, unit->tx_buffers[entry], ((struct eth_frame *)unit->tx_buffers[entry])->eth_packet_type));
366 /* DEBUG? Dump frame if so */
367 #ifdef DEBUG
369 int j;
370 for (j=0; j<64; j++) {
371 if ((j%16) == 0)
372 D(bug("\n%03x:", j));
373 D(bug(" %02x", ((unsigned char*)unit->tx_buffers[entry])[j]));
375 D(bug("\n"));
377 #endif
379 Enable();
381 /* Set the ring details for the packet .. */
382 unit->tx_ring[entry].cmdsts = (OWN | packet_size);
383 LONGOUT(ioaddr + cr, TxENA | LONGIN(ioaddr + cr));
385 unit->cur_tx ++;
386 index_cur_tx = unit->cur_tx;
387 index_dirty_tx = unit->dirty_tx;
389 for (count_dirty_tx = 0; index_cur_tx != index_dirty_tx; index_dirty_tx++)
390 count_dirty_tx ++;
392 D(bug("[%s]: SiS900_TX_IntF: Packet Queued.\n", unit->sis900u_name));
395 /* Reply packet */
397 request->ios2_Req.io_Error = error;
398 request->ios2_WireError = wire_error;
399 Disable();
400 Remove((APTR)request);
401 Enable();
402 ReplyMsg((APTR)request);
404 /* Update statistics */
406 if(error == 0)
408 tracker = FindTypeStats(LIBBASE, unit, &unit->sis900u_type_trackers,
409 request->ios2_PacketType);
410 if(tracker != NULL)
412 tracker->stats.PacketsSent++;
413 tracker->stats.BytesSent += packet_size;
419 /* Was there success? Enable incomming of new packets */
420 if(proceed)
421 unit->sis900u_request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
422 else
423 unit->sis900u_request_ports[WRITE_QUEUE]->mp_Flags = PA_IGNORE;
425 return FALSE;
427 AROS_INTFUNC_EXIT
431 * Handle timeouts and other strange cases
433 static AROS_INTH1(SiS900_TimeoutHandlerF, struct SiS900Unit *, unit)
435 AROS_INTFUNC_INIT
437 // struct timeval time;
438 // struct Device *TimerBase = unit->sis900u_TimerSlowReq->tr_node.io_Device;
440 // GetSysTime(&time);
441 //D(bug("[%s]: SiS900_TimeoutHandlerF()\n", unit->sis900u_name));
444 * If timeout timer is expected, and time elapsed - regenerate the
445 * interrupt handler
447 // if (unit->sis900u_toutNEED && (CmpTime(&time, &unit->sis900u_toutPOLL ) < 0))
448 // {
449 // unit->sis900u_toutNEED = FALSE;
450 //Cause(&unit->sis900u_tx_end_int);
451 // }
452 return FALSE;
454 AROS_INTFUNC_EXIT
458 * The interrupt handler - schedules code execution to proper handlers
460 static AROS_INTH1(SiS900_IntHandlerF, struct SiS900Unit *, unit)
462 AROS_INTFUNC_INIT
464 long ioaddr = unit->sis900u_BaseMem;
465 // ULONG events;
466 int boguscnt = 20;
467 // int i, link_changed;
468 ULONG status;
469 // struct Device *TimerBase = unit->sis900u_TimerSlowReq->tr_node.io_Device;
470 // struct timeval time;
472 D(bug("[%s]: SiS900_IntHandlerF()!!!!!!!\n", unit->sis900u_name));
474 do {
475 status = LONGIN(ioaddr + isr);
477 if ((status & (HIBERR|TxURN|TxERR|TxIDLE|RxORN|RxERR|RxOK)) == 0)
479 /* nothing intresting happened */
480 D(bug("[%s]: SiS900_IntHandlerF: Nothing for us ..\n", unit->sis900u_name));
481 break;
484 /* why dow't we break after Tx/Rx case ?? keyword: full-duplex */
485 if (status & (RxORN | RxERR | RxOK))
487 D(bug("[%s]: SiS900_IntHandlerF: Rx Detected!\n", unit->sis900u_name));
488 /* Rx interrupt */
489 Cause(&unit->sis900u_rx_int);
492 if (status & (TxURN | TxERR | TxIDLE))
494 D(bug("[%s]: SiS900_IntHandlerF: End of Tx Detected\n", unit->sis900u_name));
495 /* Tx interrupt */
496 for (; unit->dirty_tx != unit->cur_tx; unit->dirty_tx++) {
497 unsigned int entry;
498 ULONG tx_status;
500 entry = unit->dirty_tx % NUM_TX_DESC;
501 tx_status = unit->tx_ring[entry].cmdsts;
503 if (tx_status & OWN) {
504 /* The packet is not transmitted yet (owned by hardware) !
505 * Note: the interrupt is generated only when Tx Machine
506 * is idle, so this is an almost impossible case */
507 break;
510 if (tx_status & (ABORT | UNDERRUN | OWCOLL)) {
511 /* packet unsuccessfully transmitted */
512 D(bug("[%s]: SiS900_IntHandlerF: Transmit error, Tx status %8.8x.\n", unit->sis900u_name, tx_status));
513 // unit->stats.tx_errors++;
514 if (tx_status & UNDERRUN)
516 // unit->stats.tx_fifo_errors++;
518 if (tx_status & ABORT)
520 // unit->stats.tx_aborted_errors++;
522 if (tx_status & NOCARRIER)
524 // unit->stats.tx_carrier_errors++;
526 if (tx_status & OWCOLL)
528 // unit->stats.tx_window_errors++;
530 } else {
531 /* packet successfully transmitted */
532 // sis_priv->stats.collisions += (tx_status & COLCNT) >> 16;
533 // sis_priv->stats.tx_bytes += tx_status & DSIZE;
534 unit->sis900u_stats.PacketsSent++;
536 /* Mark the buffer as usable again ... */
537 unit->tx_ring[entry].cmdsts = 0;
541 /* something strange happened !!! */
542 if (status & HIBERR) {
543 D(bug("[%s]: SiS900_IntHandlerF: Abnormal interrupt, status %#8.8x\n", unit->sis900u_name, status));
544 break;
546 if (--boguscnt < 0) {
547 D(bug("[%s]: SiS900_IntHandlerF: Too much work at interrupt, interrupt status = %#8.8x\n", unit->sis900u_name, status));
548 break;
550 } while (1);
552 D(bug("[%s]: SiS900_IntHandlerF: exiting interrupt, interrupt status = 0x%#8.8x\n", unit->sis900u_name, LONGIN(ioaddr + isr)));
554 return FALSE;
556 AROS_INTFUNC_EXIT
559 VOID CopyPacket(struct SiS900Base *SiS900DeviceBase, struct SiS900Unit *unit,
560 struct IOSana2Req *request, UWORD packet_size, UWORD packet_type,
561 struct eth_frame *buffer)
563 struct Opener *opener;
564 BOOL filtered = FALSE;
565 UBYTE *ptr;
566 const UBYTE broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
568 D(bug("[%s]: CopyPacket(packet @ %x, len = %d)\n", unit->sis900u_name, buffer, packet_size));
570 /* Set multicast and broadcast flags */
572 request->ios2_Req.io_Flags &= ~(SANA2IOF_BCAST | SANA2IOF_MCAST);
573 if (memcmp(buffer->eth_packet_dest, broadcast, 6) == 0)
575 request->ios2_Req.io_Flags |= SANA2IOF_BCAST;
576 D(bug("[%s]: CopyPacket: BROADCAST Flag set\n", unit->sis900u_name));
578 else if((buffer->eth_packet_dest[0] & 0x1) != 0)
580 request->ios2_Req.io_Flags |= SANA2IOF_MCAST;
581 D(bug("[%s]: CopyPacket: MULTICAST Flag set\n", unit->sis900u_name));
584 /* Set source and destination addresses and packet type */
585 CopyMem(buffer->eth_packet_source, request->ios2_SrcAddr, ETH_ADDRESSSIZE);
586 CopyMem(buffer->eth_packet_dest, request->ios2_DstAddr, ETH_ADDRESSSIZE);
587 request->ios2_PacketType = packet_type;
589 /* Adjust for cooked packet request */
591 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
593 packet_size -= ETH_PACKET_DATA;
594 ptr = (UBYTE*)&buffer->eth_packet_data[0];
596 else
598 ptr = (UBYTE*)buffer;
601 request->ios2_DataLength = packet_size;
603 D(bug("[%s]: CopyPacket: packet @ %x (%d bytes)\n", unit->sis900u_name, ptr, packet_size));
605 /* Filter packet */
607 opener = request->ios2_BufferManagement;
608 if((request->ios2_Req.io_Command == CMD_READ) &&
609 (opener->filter_hook != NULL))
610 if(!CallHookPkt(opener->filter_hook, request, ptr))
612 D(bug("[%s]: CopyPacket: packet filtered\n", unit->sis900u_name));
613 filtered = TRUE;
616 if(!filtered)
618 /* Copy packet into opener's buffer and reply packet */
619 D(bug("[%s]: CopyPacket: opener recieve packet .. ", unit->sis900u_name));
620 if(!opener->rx_function(request->ios2_Data, ptr, packet_size))
622 D(bug("ERROR occured!!\n"));
623 request->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
624 request->ios2_WireError = S2WERR_BUFF_ERROR;
625 ReportEvents(LIBBASE, unit, S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF | S2EVENT_RX);
627 else
629 D(bug("SUCCESS!!\n"));
631 Disable();
632 Remove((APTR)request);
633 Enable();
634 ReplyMsg((APTR)request);
635 D(bug("[%s]: CopyPacket: opener notified.\n", unit->sis900u_name));
639 BOOL AddressFilter(struct SiS900Base *SiS900DeviceBase, struct SiS900Unit *unit, UBYTE *address)
641 struct AddressRange *range, *tail;
642 BOOL accept = TRUE;
643 ULONG address_left;
644 UWORD address_right;
646 /* Check whether address is unicast/broadcast or multicast */
648 address_left = AROS_BE2LONG(*((ULONG *)address));
649 address_right = AROS_BE2WORD(*((UWORD *)(address + 4)));
651 if((address_left & 0x01000000) != 0 &&
652 !(address_left == 0xffffffff && address_right == 0xffff))
654 /* Check if this multicast address is wanted */
656 range = (APTR)unit->sis900u_multicast_ranges.mlh_Head;
657 tail = (APTR)&unit->sis900u_multicast_ranges.mlh_Tail;
658 accept = FALSE;
660 while((range != tail) && !accept)
662 if((address_left > range->lower_bound_left ||
663 (address_left == range->lower_bound_left &&
664 address_right >= range->lower_bound_right)) &&
665 (address_left < range->upper_bound_left ||
666 (address_left == range->upper_bound_left &&
667 address_right <= range->upper_bound_right)))
668 accept = TRUE;
669 range = (APTR)range->node.mln_Succ;
672 if(!accept)
673 unit->sis900u_special_stats[S2SS_ETHERNET_BADMULTICAST & 0xffff]++;
675 return accept;
679 * Unit process
681 AROS_UFH3(void, SiS900_Schedular,
682 AROS_UFHA(STRPTR, argPtr, A0),
683 AROS_UFHA(ULONG, argSize, D0),
684 AROS_UFHA(struct ExecBase *, SysBase, A6))
686 AROS_USERFUNC_INIT
688 struct SiS900Startup *sm_UD = FindTask(NULL)->tc_UserData;
689 struct SiS900Unit *unit = sm_UD->sis900sm_Unit;
691 LIBBASETYPEPTR LIBBASE = unit->sis900u_device;
692 struct MsgPort *reply_port, *input;
694 D(bug("%s SiS900_Schedular()\n", unit->sis900u_name));
695 D(bug("%s SiS900_Schedular: Setting device up\n", unit->sis900u_name));
697 reply_port = CreateMsgPort();
698 input = CreateMsgPort();
700 unit->sis900u_input_port = input;
702 unit->sis900u_TimerSlowPort = CreateMsgPort();
704 if (unit->sis900u_TimerSlowPort)
706 unit->sis900u_TimerSlowReq = (struct timerequest *)
707 CreateIORequest((struct MsgPort *)unit->sis900u_TimerSlowPort, sizeof(struct timerequest));
709 if (unit->sis900u_TimerSlowReq)
711 if (!OpenDevice("timer.device", UNIT_VBLANK,
712 (struct IORequest *)unit->sis900u_TimerSlowReq, 0))
714 struct Message *msg = AllocVec(sizeof(struct Message), MEMF_PUBLIC|MEMF_CLEAR);
715 ULONG sigset;
717 D(bug("%s SiS900_Schedular: Got VBLANK unit of timer.device\n", unit->sis900u_name));
719 sis900func_initialize(unit);
721 msg->mn_ReplyPort = reply_port;
722 msg->mn_Length = sizeof(struct Message);
724 D(bug("%s SiS900_Schedular: Setup complete. Sending handshake\n", unit->sis900u_name));
725 PutMsg(sm_UD->sis900sm_SyncPort, msg);
726 WaitPort(reply_port);
727 GetMsg(reply_port);
729 FreeVec(msg);
731 D(bug("%s SiS900_Schedular: entering forever loop ... \n", unit->sis900u_name));
733 unit->sis900u_signal_0 = AllocSignal(-1);
734 unit->sis900u_signal_1 = AllocSignal(-1);
735 unit->sis900u_signal_2 = AllocSignal(-1);
736 unit->sis900u_signal_3 = AllocSignal(-1);
738 sigset = 1 << input->mp_SigBit |
739 1 << unit->sis900u_signal_0 |
740 1 << unit->sis900u_signal_1 |
741 1 << unit->sis900u_signal_2 |
742 1 << unit->sis900u_signal_3;
743 for(;;)
745 ULONG recvd = Wait(sigset);
746 if (recvd & unit->sis900u_signal_0)
749 * Shutdown process. Driver should close everything
750 * already and waits for our process to complete. Free
751 * memory allocared here and kindly return.
753 sis900func_deinitialize(unit);
754 CloseDevice((struct IORequest *)unit->sis900u_TimerSlowReq);
755 DeleteIORequest((struct IORequest *)unit->sis900u_TimerSlowReq);
756 DeleteMsgPort(unit->sis900u_TimerSlowPort);
757 DeleteMsgPort(input);
758 DeleteMsgPort(reply_port);
760 D(bug("%s SiS900_Schedular: Process shutdown.\n", unit->sis900u_name));
761 return;
763 else if (recvd & (1 << input->mp_SigBit))
765 struct IOSana2Req *io;
767 /* Handle incoming transactions */
768 while ((io = (struct IOSana2Req *)GetMsg(input))!= NULL)
770 D(bug("%s SiS900_Schedular: Handle incomming transaction.\n", unit->sis900u_name));
771 ObtainSemaphore(&unit->sis900u_unit_lock);
772 handle_request(LIBBASE, io);
775 else
777 D(bug("%s SiS900_Schedular: Handle incomming signal.\n", unit->sis900u_name));
778 /* Handle incoming signals */
785 AROS_USERFUNC_EXIT
789 * Create new SiS900 ethernet device unit
791 struct SiS900Unit *CreateUnit(struct SiS900Base *SiS900DeviceBase, OOP_Object *pciDevice, char * CardName, char * CardChipset)
793 struct SiS900Unit *unit = NULL;
794 BOOL success = TRUE;
795 int i;
797 D(bug("[SiS900] CreateUnit()\n"));
799 if ((unit = AllocMem(sizeof(struct SiS900Unit), MEMF_PUBLIC | MEMF_CLEAR)) != NULL)
801 IPTR DeviceID = 0, RevisionID = 0, HostRevisionID = 0, base = 0, len;
802 OOP_Object *driver = NULL;
804 D(bug("[SiS900] CreateUnit: Unit allocated @ %x\n", unit));
806 unit->sis900u_UnitNum = SiS900DeviceBase->sis900b_UnitCount++;
808 unit->sis900u_Sana2Info.HardwareType = S2WireType_Ethernet;
809 unit->sis900u_Sana2Info.MTU = ETH_MTU;
810 unit->sis900u_Sana2Info.AddrFieldSize = 8 * ETH_ADDRESSSIZE;
812 if ((unit->sis900u_name = AllocVec(7 + (unit->sis900u_UnitNum/10) + 2, MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
814 FreeMem(unit, sizeof(struct SiS900Unit));
815 return NULL;
818 sprintf((char *)unit->sis900u_name, "sis900.%d", unit->sis900u_UnitNum);
820 OOP_GetAttr(pciDevice, aHidd_PCIDevice_ProductID, &DeviceID);
821 OOP_GetAttr(pciDevice, aHidd_PCIDevice_RevisionID, &RevisionID);
822 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Driver, (APTR)&driver);
824 /* TODO: Get the host bridge revision!! */
825 /* // save our host bridge revision
826 dev = pci_get_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_630, NULL);
827 if (dev) {
828 pci_read_config_byte(dev, PCI_CLASS_REVISION, &sis_priv->host_bridge_rev);
829 pci_dev_put(dev);
832 unit->sis900u_rtl_cardname = CardName;
833 unit->sis900u_rtl_chipname = CardChipset;
835 unit->sis900u_PCIDevice = pciDevice;
836 unit->sis900u_PCIDriver = driver;
838 unit->sis900u_device = SiS900DeviceBase;
839 unit->sis900u_DeviceID = DeviceID;
840 unit->sis900u_RevisionID = RevisionID;
841 unit->sis900u_HostRevisionID = HostRevisionID;
843 unit->sis900u_mtu = unit->sis900u_Sana2Info.MTU;
845 InitSemaphore(&unit->sis900u_unit_lock);
846 NEWLIST(&unit->sis900u_Openers);
847 NEWLIST(&unit->sis900u_multicast_ranges);
848 NEWLIST(&unit->sis900u_type_trackers);
850 OOP_GetAttr(pciDevice, aHidd_PCIDevice_INTLine, &unit->sis900u_IRQ);
851 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base1, &unit->sis900u_BaseIO);
852 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Base0, &base);
853 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Size0, &len);
855 D(bug("%s CreateUnit: INT:%d, base1:%x, base0:%x, size0:%d\n", unit->sis900u_name,
856 unit->sis900u_IRQ, unit->sis900u_BaseIO,
857 base, len));
859 unit->sis900u_BaseMem = (IPTR)HIDD_PCIDriver_MapPCI(driver, (APTR)base, len);
860 unit->sis900u_SizeMem = len;
862 if (unit->sis900u_BaseMem)
864 struct TagItem attrs[] = {
865 { aHidd_PCIDevice_isIO, TRUE },
866 { aHidd_PCIDevice_isMEM, TRUE },
867 { aHidd_PCIDevice_isMaster, TRUE },
868 { TAG_DONE, 0 },
870 OOP_SetAttrs(pciDevice, (struct TagItem *)&attrs);
872 D(bug("%s CreateUnit: PCI_BaseMem @ %x\n", unit->sis900u_name, unit->sis900u_BaseMem));
873 if ((unit->tx_ring = AllocMem(TX_TOTAL_SIZE, MEMF_PUBLIC|MEMF_CLEAR)) != NULL)
876 if ((unit->tx_ring_dma = HIDD_PCIDriver_CPUtoPCI(unit->sis900u_PCIDriver, unit->tx_ring)) == NULL)
878 D(bug("[%s]: CreateUnit: Failed to Map Tx Ring Buffer Descriptors DMA \n", unit->sis900u_name));
879 return NULL;
882 else
884 D(bug("[%s]: CreateUnit: Failed to Allocate Tx Ring Buffer Descriptors\n", unit->sis900u_name));
885 return NULL;
887 D(bug("[%s]: CreateUnit: Tx Ring Buffer Descriptors @ %p [DMA @ %p]\n", unit->sis900u_name, unit->tx_ring, unit->tx_ring_dma));
889 if ((unit->rx_ring = AllocMem(RX_TOTAL_SIZE, MEMF_PUBLIC|MEMF_CLEAR)) != NULL)
892 if ((unit->rx_ring_dma = HIDD_PCIDriver_CPUtoPCI(unit->sis900u_PCIDriver, unit->rx_ring)) == NULL)
894 D(bug("[%s]: CreateUnit: Failed to Map Rx Ring Buffer Descriptors DMA\n", unit->sis900u_name));
895 return NULL;
898 else
900 D(bug("[%s]: CreateUnit: Failed to Allocate Rx Ring Buffer Descriptors DMA\n", unit->sis900u_name));
901 return NULL;
903 D(bug("[%s]: CreateUnit: Rx Ring Buffer Descriptors @ %p [DMA @ %p]\n", unit->sis900u_name, unit->rx_ring, unit->rx_ring_dma));
906 struct Message *msg;
908 unit->sis900u_irqhandler.is_Node.ln_Type = NT_INTERRUPT;
909 unit->sis900u_irqhandler.is_Node.ln_Pri = 100;
910 unit->sis900u_irqhandler.is_Node.ln_Name = LIBBASE->sis900b_Device.dd_Library.lib_Node.ln_Name;
911 unit->sis900u_irqhandler.is_Code = (VOID_FUNC)SiS900_IntHandlerF;
912 unit->sis900u_irqhandler.is_Data = unit;
914 unit->sis900u_touthandler.is_Node.ln_Type = NT_INTERRUPT;
915 unit->sis900u_touthandler.is_Node.ln_Pri = 100;
916 unit->sis900u_touthandler.is_Node.ln_Name = LIBBASE->sis900b_Device.dd_Library.lib_Node.ln_Name;
917 unit->sis900u_touthandler.is_Code = (VOID_FUNC)SiS900_TimeoutHandlerF;
918 unit->sis900u_touthandler.is_Data = unit;
920 unit->sis900u_rx_int.is_Node.ln_Type = NT_INTERRUPT;
921 unit->sis900u_rx_int.is_Node.ln_Name = unit->sis900u_name;
922 unit->sis900u_rx_int.is_Code = (VOID_FUNC)SiS900_RX_IntF;
923 unit->sis900u_rx_int.is_Data = unit;
925 unit->sis900u_tx_int.is_Node.ln_Type = NT_INTERRUPT;
926 unit->sis900u_tx_int.is_Node.ln_Name = unit->sis900u_name;
927 unit->sis900u_tx_int.is_Code = (VOID_FUNC)SiS900_TX_IntF;
928 unit->sis900u_tx_int.is_Data = unit;
930 for (i=0; i < REQUEST_QUEUE_COUNT; i++)
932 struct MsgPort *port;
934 if ((port = AllocMem(sizeof(struct MsgPort), MEMF_PUBLIC | MEMF_CLEAR)) == NULL) success = FALSE;
936 if (success)
938 unit->sis900u_request_ports[i] = port;
939 NEWLIST(&port->mp_MsgList);
940 port->mp_Flags = PA_IGNORE;
941 port->mp_SigTask = &unit->sis900u_tx_int;
945 unit->sis900u_request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
947 if (success)
949 struct SiS900Startup *sm_UD;
950 UBYTE tmpbuff[100];
952 if ((sm_UD = AllocMem(sizeof(struct SiS900Startup), MEMF_PUBLIC | MEMF_CLEAR)) != NULL)
954 sprintf((char *)tmpbuff, SiS900_TASK_NAME, unit->sis900u_name);
956 sm_UD->sis900sm_SyncPort = CreateMsgPort();
957 sm_UD->sis900sm_Unit = unit;
959 unit->sis900u_Process = CreateNewProcTags(
960 NP_Entry, (IPTR)SiS900_Schedular,
961 NP_Name, tmpbuff,
962 NP_Synchronous , FALSE,
963 NP_Priority, 0,
964 NP_UserData, (IPTR)sm_UD,
965 NP_StackSize, 140960,
966 TAG_DONE);
968 WaitPort(sm_UD->sis900sm_SyncPort);
969 msg = GetMsg(sm_UD->sis900sm_SyncPort);
970 ReplyMsg(msg);
971 DeleteMsgPort(sm_UD->sis900sm_SyncPort);
972 FreeMem(sm_UD, sizeof(struct SiS900Startup));
974 D(bug("[%s] CreateUnit: Device Initialised. Unit %d @ %p\n", unit->sis900u_name, unit->sis900u_UnitNum, unit));
975 return unit;
978 else
980 D(bug("[%s]: ERRORS occured during Device setup - ABORTING\n", unit->sis900u_name));
984 else
986 D(bug("[SiS900] PANIC! Couldn't get MMIO area. Aborting\n"));
989 DeleteUnit(SiS900DeviceBase, unit);
990 return NULL;
994 * DeleteUnit - removes selected unit. Frees all resources and structures.
996 * The caller should be sure, that given unit is really ready to be freed.
999 void DeleteUnit(struct SiS900Base *SiS900DeviceBase, struct SiS900Unit *Unit)
1001 int i;
1003 D(bug("[SiS900] DeleteUnit()\n"));
1005 if (Unit)
1007 if (Unit->sis900u_Process)
1009 Signal(&Unit->sis900u_Process->pr_Task, Unit->sis900u_signal_0);
1012 for (i=0; i < REQUEST_QUEUE_COUNT; i++)
1014 if (Unit->sis900u_request_ports[i] != NULL)
1015 FreeMem(Unit->sis900u_request_ports[i], sizeof(struct MsgPort));
1017 Unit->sis900u_request_ports[i] = NULL;
1020 if (Unit->sis900u_BaseMem)
1022 HIDD_PCIDriver_UnmapPCI(Unit->sis900u_PCIDriver,
1023 (APTR)Unit->sis900u_BaseMem,
1024 Unit->sis900u_SizeMem);
1027 FreeMem(Unit, sizeof(struct SiS900Unit));
1031 static struct AddressRange *FindMulticastRange(LIBBASETYPEPTR LIBBASE, struct SiS900Unit *unit,
1032 ULONG lower_bound_left, UWORD lower_bound_right, ULONG upper_bound_left, UWORD upper_bound_right)
1034 struct AddressRange *range, *tail;
1035 BOOL found = FALSE;
1037 range = (APTR)unit->sis900u_multicast_ranges.mlh_Head;
1038 tail = (APTR)&unit->sis900u_multicast_ranges.mlh_Tail;
1040 while((range != tail) && !found)
1042 if((lower_bound_left == range->lower_bound_left) &&
1043 (lower_bound_right == range->lower_bound_right) &&
1044 (upper_bound_left == range->upper_bound_left) &&
1045 (upper_bound_right == range->upper_bound_right))
1046 found = TRUE;
1047 else
1048 range = (APTR)range->node.mln_Succ;
1051 if(!found)
1052 range = NULL;
1054 return range;
1057 BOOL AddMulticastRange(LIBBASETYPEPTR LIBBASE, struct SiS900Unit *unit, const UBYTE *lower_bound,
1058 const UBYTE *upper_bound)
1060 struct AddressRange *range;
1061 ULONG lower_bound_left, upper_bound_left;
1062 UWORD lower_bound_right, upper_bound_right;
1064 lower_bound_left = AROS_BE2LONG(*((ULONG *)lower_bound));
1065 lower_bound_right = AROS_BE2WORD(*((UWORD *)(lower_bound + 4)));
1066 upper_bound_left = AROS_BE2LONG(*((ULONG *)upper_bound));
1067 upper_bound_right = AROS_BE2WORD(*((UWORD *)(upper_bound + 4)));
1069 range = FindMulticastRange(LIBBASE, unit, lower_bound_left, lower_bound_right,
1070 upper_bound_left, upper_bound_right);
1072 if(range != NULL)
1073 range->add_count++;
1074 else
1076 range = AllocMem(sizeof(struct AddressRange), MEMF_PUBLIC);
1077 if(range != NULL)
1079 range->lower_bound_left = lower_bound_left;
1080 range->lower_bound_right = lower_bound_right;
1081 range->upper_bound_left = upper_bound_left;
1082 range->upper_bound_right = upper_bound_right;
1083 range->add_count = 1;
1085 Disable();
1086 AddTail((APTR)&unit->sis900u_multicast_ranges, (APTR)range);
1087 Enable();
1089 if (unit->sis900u_range_count++ == 0)
1091 unit->sis900u_ifflags |= IFF_ALLMULTI;
1092 sis900func_set_multicast(unit);
1097 return range != NULL;
1100 BOOL RemMulticastRange(LIBBASETYPEPTR LIBBASE, struct SiS900Unit *unit, const UBYTE *lower_bound, const UBYTE *upper_bound)
1102 struct AddressRange *range;
1103 ULONG lower_bound_left, upper_bound_left;
1104 UWORD lower_bound_right, upper_bound_right;
1106 lower_bound_left = AROS_BE2LONG(*((ULONG *)lower_bound));
1107 lower_bound_right = AROS_BE2WORD(*((UWORD *)(lower_bound + 4)));
1108 upper_bound_left = AROS_BE2LONG(*((ULONG *)upper_bound));
1109 upper_bound_right = AROS_BE2WORD(*((UWORD *)(upper_bound + 4)));
1111 range = FindMulticastRange(LIBBASE, unit, lower_bound_left, lower_bound_right,
1112 upper_bound_left, upper_bound_right);
1114 if(range != NULL)
1116 if(--range->add_count == 0)
1118 Disable();
1119 Remove((APTR)range);
1120 Enable();
1121 FreeMem(range, sizeof(struct AddressRange));
1123 if (--unit->sis900u_range_count == 0)
1125 unit->sis900u_ifflags &= ~IFF_ALLMULTI;
1126 sis900func_set_multicast(unit);
1130 return range != NULL;