grub2: bring back build of aros-side grub2 tools
[AROS.git] / workbench / devs / networks / intelpro100 / unit.c
blob8a9e61467333aa08a3901e53d14c933851000095
1 /*
3 Copyright (C) 2001-2012 Neil Cafferkey
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 MA 02111-1307, USA.
23 #include <exec/memory.h>
24 #include <exec/execbase.h>
25 #include <exec/errors.h>
27 #include <proto/exec.h>
28 #ifndef __amigaos4__
29 #include <proto/alib.h>
30 #else
31 #include <clib/alib_protos.h>
32 #endif
33 #include <proto/utility.h>
34 #include <proto/timer.h>
36 #include "device.h"
37 #include "intelpro100.h"
38 #include "mii.h"
39 #include "dp83840.h"
41 #include "unit_protos.h"
42 #include "request_protos.h"
45 #define TASK_PRIORITY 0
46 #define STACK_SIZE 4096
47 #define CONFIG_DATA_LEN 6
48 #define STAT_COUNT 16
49 #define MAX_MCAST_ENTRIES 100
50 #define MCAST_CB_SIZE (PROCB_COUNT * sizeof(ULONG) + sizeof(UWORD) \
51 + ETH_ADDRESSSIZE * MAX_MCAST_ENTRIES)
53 #ifndef AbsExecBase
54 #define AbsExecBase sys_base
55 #endif
57 static VOID InitialiseAdapter(struct DevUnit *unit, struct DevBase *base);
58 static VOID FillConfigData(struct DevUnit *unit, ULONG *tcb,
59 struct DevBase *base);
60 static struct AddressRange *FindMulticastRange(struct DevUnit *unit,
61 ULONG lower_bound_left, UWORD lower_bound_right, ULONG upper_bound_left,
62 UWORD upper_bound_right, struct DevBase *base);
63 static VOID SetMulticast(struct DevUnit *unit, struct DevBase *base);
64 static BOOL StatusInt(REG(a1, struct DevUnit *unit), REG(a5, APTR int_code));
65 static VOID RXInt(REG(a1, struct DevUnit *unit), REG(a5, APTR int_code));
66 static VOID CopyPacket(struct DevUnit *unit, struct IOSana2Req *request,
67 UWORD packet_size, UWORD packet_type, UBYTE *buffer,
68 struct DevBase *base);
69 static BOOL AddressFilter(struct DevUnit *unit, UBYTE *address,
70 struct DevBase *base);
71 static VOID TXInt(REG(a1, struct DevUnit *unit), REG(a5, APTR int_code));
72 static VOID TXEndInt(REG(a1, struct DevUnit *unit),
73 REG(a5, APTR int_code));
74 static VOID ReportEvents(struct DevUnit *unit, ULONG events,
75 struct DevBase *base);
76 static VOID UnitTask(struct ExecBase *sys_base);
77 static UWORD GetEEPROMAddressSize(struct DevUnit *unit,
78 struct DevBase *base);
79 static UWORD ReadEEPROM(struct DevUnit *unit, UWORD index,
80 struct DevBase *base);
81 static ULONG ReadEEPROMBits(struct DevUnit *unit, UBYTE count,
82 struct DevBase *base);
83 static VOID WriteEEPROMBits(struct DevUnit *unit, ULONG value, UBYTE count,
84 struct DevBase *base);
85 static BOOL ReadEEPROMBit(struct DevUnit *unit, struct DevBase *base);
86 static BOOL WriteEEPROMBit(struct DevUnit *unit, BOOL is_one,
87 struct DevBase *base);
88 static UWORD ReadMII(struct DevUnit *unit, UWORD phy_no, UWORD reg_no,
89 struct DevBase *base);
90 static VOID WriteMII(struct DevUnit *unit, UWORD phy_no, UWORD reg_no,
91 UWORD value, struct DevBase *base);
92 static VOID BusyMicroDelay(ULONG micros, struct DevBase *base);
96 static const ULONG config_data[] =
98 8 << PROCB_CF0B_RXFIFOLIM | 22 << PROCB_CF0B_SIZE,
99 1 << PROCB_CF1B_UNDERRUNRETRIES | PROCB_CF1F_DISCARDRUNTS
100 | PROCB_CF1F_STDSTATS | PROCB_CF1F_STDTXBLOCK | 0x00020000,
101 2 << PROCB_CF2B_PREAMBLETYPE | PROCB_CF2F_NOSOURCEINSERT | 0x00060001,
102 0xf200 << PROCB_CF3B_ARPFILTER | 6 << PROCB_CF3B_IFS | 0x48000000,
103 PROCB_CF4F_USEFDPIN | PROCB_CF4F_PADDING | 0x00f04000,
104 0x053f
108 #ifdef __amigaos4__
109 #undef AddTask
110 #define AddTask(task, initial_pc, final_pc) \
111 IExec->AddTask(task, initial_pc, final_pc, NULL)
112 #endif
113 #ifdef __MORPHOS__
114 static const struct EmulLibEntry mos_task_trap =
116 TRAP_LIB,
118 (APTR)UnitTask
120 #define UnitTask &mos_task_trap
121 #endif
122 #ifdef __AROS__
123 #undef AddTask
124 #define AddTask(task, initial_pc, final_pc) \
125 ({ \
126 struct TagItem _task_tags[] = \
127 {{TASKTAG_ARG1, (IPTR)SysBase}, {TAG_END, 0}}; \
128 NewAddTask(task, initial_pc, final_pc, _task_tags); \
130 #endif
133 /****i* intelpro100.device/CreateUnit **************************************
135 * NAME
136 * CreateUnit -- Create a unit.
138 * SYNOPSIS
139 * unit = CreateUnit(index, card, io_tags, bus)
141 * struct DevUnit *CreateUnit(ULONG, APTR, struct TagItem *, UWORD);
143 * FUNCTION
144 * Creates a new unit.
146 ****************************************************************************
150 struct DevUnit *CreateUnit(ULONG index, APTR card,
151 struct TagItem *io_tags, UWORD bus, struct DevBase *base)
153 BOOL success = TRUE;
154 struct DevUnit *unit;
155 struct Task *task;
156 struct MsgPort *port;
157 UBYTE i;
158 APTR stack;
159 ULONG *tcb, *next_tcb, *rcb, *next_rcb, dma_size;
160 APTR rx_int_function, tx_int_function;
162 unit = AllocMem(sizeof(struct DevUnit), MEMF_CLEAR | MEMF_PUBLIC);
163 if(unit == NULL)
164 success = FALSE;
166 if(success)
168 /* Initialise lists etc. */
170 InitSemaphore(&unit->access_lock);
171 NewList((APTR)&unit->openers);
172 NewList((APTR)&unit->type_trackers);
173 NewList((APTR)&unit->multicast_ranges);
174 NewList((APTR)&unit->tx_requests);
176 unit->index = index;
177 unit->device = base;
178 unit->card = card;
179 unit->bus = bus;
181 /* Store I/O hooks */
183 unit->ByteIn =
184 (APTR)GetTagData(IOTAG_ByteIn, (UPINT)NULL, io_tags);
185 unit->ByteOut =
186 (APTR)GetTagData(IOTAG_ByteOut, (UPINT)NULL, io_tags);
187 unit->LEWordIn =
188 (APTR)GetTagData(IOTAG_LEWordIn, (UPINT)NULL, io_tags);
189 unit->LELongIn =
190 (APTR)GetTagData(IOTAG_LELongIn, (UPINT)NULL, io_tags);
191 unit->LEWordOut =
192 (APTR)GetTagData(IOTAG_LEWordOut, (UPINT)NULL, io_tags);
193 unit->LELongOut =
194 (APTR)GetTagData(IOTAG_LELongOut, (UPINT)NULL, io_tags);
195 unit->AllocDMAMem =
196 (APTR)GetTagData(IOTAG_AllocDMAMem, (UPINT)NULL, io_tags);
197 unit->FreeDMAMem =
198 (APTR)GetTagData(IOTAG_FreeDMAMem, (UPINT)NULL, io_tags);
199 if(unit->ByteIn == NULL
200 || unit->ByteOut == NULL
201 || unit->LEWordIn == NULL
202 || unit->LEWordOut == NULL || unit->LELongIn == NULL
203 || unit->LELongOut == NULL
204 || unit->AllocDMAMem == NULL || unit->FreeDMAMem == NULL)
205 success = FALSE;
207 /* Allocate buffer for adapter to writes statistics to */
209 unit->stats_buffer =
210 AllocVec(sizeof(ULONG) * (STAT_COUNT + 1), MEMF_PUBLIC);
211 if(unit->stats_buffer == NULL)
212 success = FALSE;
215 if(success)
217 /* Initialise network adapter hardware */
219 InitialiseAdapter(unit, base);
220 unit->flags |= UNITF_HAVEADAPTER;
222 /* Create the message ports for queuing requests */
224 for(i = 0; i < REQUEST_QUEUE_COUNT; i++)
226 unit->request_ports[i] = port = AllocMem(sizeof(struct MsgPort),
227 MEMF_PUBLIC | MEMF_CLEAR);
228 if(port == NULL)
229 success = FALSE;
231 if(success)
233 NewList(&port->mp_MsgList);
234 port->mp_Flags = PA_IGNORE;
235 port->mp_SigTask = &unit->tx_int;
239 /* Allocate and initialise packet/command descriptors */
241 unit->tx_buffer = AllocVec(ETH_MAXPACKETSIZE, MEMF_PUBLIC);
242 next_tcb = unit->first_tcb = unit->tcbs =
243 AllocVec(TCB_SIZE * TX_SLOT_COUNT, MEMF_PUBLIC | MEMF_CLEAR);
244 next_rcb = unit->rcbs =
245 AllocVec(RCB_SIZE * RX_SLOT_COUNT, MEMF_PUBLIC | MEMF_CLEAR);
246 unit->multicast_cb = AllocVec(PROCB_COUNT * sizeof(ULONG)
247 + sizeof(UWORD) + ETH_ADDRESSSIZE * MAX_MCAST_ENTRIES,
248 MEMF_PUBLIC | MEMF_CLEAR);
250 if(next_tcb == NULL || next_rcb == NULL || unit->tx_buffer == NULL
251 || unit->multicast_cb == NULL)
252 success = FALSE;
255 if(success)
257 /* Construct TX ring */
259 for(i = 0; i < TX_SLOT_COUNT; i++)
261 tcb = next_tcb;
262 next_tcb = tcb + TCB_SIZE / sizeof(ULONG);
263 tcb[PROCB_NEXT] = MakeLELong((ULONG)(IPTR)next_tcb);
265 tcb[PROCB_NEXT] = MakeLELong((ULONG)(IPTR)unit->tcbs);
266 unit->last_tcb = tcb;
268 /* Construct RX ring */
270 for(i = 0; i < RX_SLOT_COUNT; i++)
272 rcb = next_rcb;
273 next_rcb = rcb + RCB_SIZE / sizeof(ULONG);
274 rcb[PROCB_NEXT] = MakeLELong((ULONG)(IPTR)next_rcb);
275 rcb[PROCB_RXINFO] =
276 MakeLELong(ETH_MAXPACKETSIZE << PROCB_RXINFOB_BUFFERSIZE);
278 rcb[PROCB_CONTROL] = MakeLELong(PROCB_CONTROLF_SUSPEND);
279 rcb[PROCB_NEXT] = MakeLELong((ULONG)(IPTR)unit->rcbs);
280 unit->last_rcb = rcb;
281 dma_size = RCB_SIZE * RX_SLOT_COUNT;
282 CachePreDMA(unit->rcbs, &dma_size, 0);
284 /* Record maximum speed in BPS */
286 unit->speed = 100000000;
288 /* Initialise status, transmit and receive interrupts */
290 unit->status_int.is_Code = (APTR)StatusInt;
291 unit->status_int.is_Data = unit;
293 rx_int_function = RXInt;
294 unit->rx_int.is_Node.ln_Name =
295 base->device.dd_Library.lib_Node.ln_Name;
296 unit->rx_int.is_Node.ln_Pri = 16;
297 unit->rx_int.is_Code = rx_int_function;
298 unit->rx_int.is_Data = unit;
300 tx_int_function = TXInt;
301 unit->tx_int.is_Node.ln_Name =
302 base->device.dd_Library.lib_Node.ln_Name;
303 unit->tx_int.is_Code = tx_int_function;
304 unit->tx_int.is_Data = unit;
306 unit->tx_end_int.is_Node.ln_Name =
307 base->device.dd_Library.lib_Node.ln_Name;
308 unit->tx_end_int.is_Code = TXEndInt;
309 unit->tx_end_int.is_Data = unit;
311 unit->request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
314 if(success)
316 /* Create a new task */
318 unit->task = task =
319 AllocMem(sizeof(struct Task), MEMF_PUBLIC | MEMF_CLEAR);
320 if(task == NULL)
321 success = FALSE;
324 if(success)
326 /* Allocate stack */
328 stack = AllocMem(STACK_SIZE, MEMF_PUBLIC);
329 if(stack == NULL)
330 success = FALSE;
333 if(success)
335 /* Initialise and start task */
337 task->tc_Node.ln_Type = NT_TASK;
338 task->tc_Node.ln_Pri = TASK_PRIORITY;
339 task->tc_Node.ln_Name =
340 base->device.dd_Library.lib_Node.ln_Name;
341 task->tc_SPUpper = stack + STACK_SIZE;
342 task->tc_SPLower = stack;
343 task->tc_SPReg = stack + STACK_SIZE;
344 NewList(&task->tc_MemEntry);
346 if(AddTask(task, UnitTask, NULL) == NULL)
347 success = FALSE;
350 /* Send the unit to the new task */
352 if(success)
353 task->tc_UserData = unit;
355 if(!success)
357 DeleteUnit(unit, base);
358 unit = NULL;
361 return unit;
366 /****i* intelpro100.device/DeleteUnit **************************************
368 * NAME
369 * DeleteUnit -- Delete a unit.
371 * SYNOPSIS
372 * DeleteUnit(unit)
374 * VOID DeleteUnit(struct DevUnit *);
376 * FUNCTION
377 * Deletes a unit.
379 * INPUTS
380 * unit - Device unit (can be NULL).
382 * RESULT
383 * None.
385 ****************************************************************************
389 VOID DeleteUnit(struct DevUnit *unit, struct DevBase *base)
391 UBYTE i;
392 struct Task *task;
394 if(unit != NULL)
396 task = unit->task;
397 if(task != NULL)
399 if(task->tc_UserData != NULL)
400 RemTask(task);
401 if(task->tc_SPLower != NULL)
402 FreeMem(task->tc_SPLower, STACK_SIZE);
403 FreeMem(task, sizeof(struct Task));
406 for(i = 0; i < REQUEST_QUEUE_COUNT; i++)
408 if(unit->request_ports[i] != NULL)
409 FreeMem(unit->request_ports[i], sizeof(struct MsgPort));
412 if((unit->flags & UNITF_ONLINE) != 0) /* Needed! */
413 GoOffline(unit, base);
415 FreeVec(unit->multicast_cb);
416 FreeVec(unit->rcbs);
417 FreeVec(unit->tcbs);
418 FreeVec(unit->tx_buffer);
419 FreeVec(unit->stats_buffer);
421 FreeMem(unit, sizeof(struct DevUnit));
424 return;
429 /****i* intelpro100.device/InitialiseAdapter *******************************
431 * NAME
432 * InitialiseAdapter -- Initialise network adapter hardware.
434 * SYNOPSIS
435 * InitialiseAdapter(unit)
437 * VOID InitialiseAdapter(struct DevUnit *);
439 * INPUTS
440 * unit
442 * RESULT
443 * None.
445 ****************************************************************************
449 static VOID InitialiseAdapter(struct DevUnit *unit, struct DevBase *base)
451 UBYTE *p, i;
452 UWORD address_part;
454 /* Reset card */
456 unit->LELongOut(unit->card, PROREG_PORT, 0);
457 BusyMicroDelay(10, base);
459 /* Get default MAC address */
461 unit->eeprom_addr_size = GetEEPROMAddressSize(unit, base);
462 p = unit->default_address;
464 for(i = 0; i < ETH_ADDRESSSIZE / sizeof(UWORD); i++)
466 address_part = ReadEEPROM(unit, PROROM_ADDRESS0 + i, base);
467 *p++ = address_part & 0xff;
468 *p++ = address_part >> 8;
471 /* Set up statistics dump area */
473 unit->LELongOut(unit->card, PROREG_GENPTR, (ULONG)(IPTR)unit->stats_buffer);
474 unit->LEWordOut(unit->card, PROREG_COMMAND, PRO_CUCMD_SETSTATSBUFFER);
475 while(unit->LEWordIn(unit->card, PROREG_COMMAND) != 0);
477 /* Return */
479 return;
484 /****i* intelpro100.device/ConfigureAdapter ********************************
486 * NAME
487 * ConfigureAdapter -- Put adapter online for the first time.
489 * SYNOPSIS
490 * ConfigureAdapter(unit)
492 * VOID ConfigureAdapter(struct DevUnit *);
494 * INPUTS
495 * unit
497 * RESULT
498 * None.
500 ****************************************************************************
504 VOID ConfigureAdapter(struct DevUnit *unit, struct DevBase *base)
506 ULONG *tcb, dma_size;
507 UWORD phy_type, phy_no, config;
509 /* Set MAC address */
511 tcb = (ULONG *)(IPTR)LELong(unit->last_tcb[PROCB_NEXT]);
512 tcb[PROCB_CONTROL] = MakeLELong(PROACT_SETADDRESS);
513 CopyMem(&unit->address, tcb + PROCB_ADDRESS, ETH_ADDRESSSIZE);
515 /* Set other parameters */
517 tcb = (ULONG *)(IPTR)LELong(tcb[PROCB_NEXT]);
518 tcb[PROCB_CONTROL] =
519 MakeLELong(PROACT_CONFIGURE | PROCB_CONTROLF_SUSPEND);
520 unit->phy_info = ReadEEPROM(unit, PROROM_PHYINFO0, base);
521 FillConfigData(unit, tcb, base);
522 unit->last_tcb = tcb;
524 dma_size = TCB_SIZE * TX_SLOT_COUNT;
525 CachePreDMA(unit->tcbs, &dma_size, 0);
527 /* DP83840-specific configuration */
529 phy_type = unit->phy_info & PROROM_PHYINFO0F_TYPE;
530 if(phy_type == PRO_PHY_DP83840 || phy_type == PRO_PHY_DP83840A)
532 phy_no = unit->phy_info & PROROM_PHYINFO0F_ADDR;
533 config = ReadMII(unit, phy_no, MII_PCR, base);
534 config |= 0x400 | MII_PCRF_NOLINKMON | MII_PCRF_LED4DUPLEX;
535 WriteMII(unit, phy_no, MII_PCR, config, base);
538 /* Go online */
540 unit->LELongOut(unit->card, PROREG_GENPTR, (ULONG)(IPTR)unit->tcbs);
541 unit->LEWordOut(unit->card, PROREG_COMMAND, PRO_CUCMD_START);
542 while(unit->LEWordIn(unit->card, PROREG_COMMAND) != 0);
543 GoOnline(unit, base);
545 /* Return */
547 return;
552 /****i* intelpro100.device/FillConfigData **********************************
554 * NAME
555 * FillConfigData -- Fill in the data for a configuration command.
557 * SYNOPSIS
558 * FillConfigData(unit, tcb)
560 * VOID FillConfigData(struct DevUnit *, ULONG *);
562 * INPUTS
563 * unit - A unit of this device.
564 * tcb - The configuration command block.
566 * RESULT
567 * None.
569 ****************************************************************************
573 static VOID FillConfigData(struct DevUnit *unit, ULONG *tcb,
574 struct DevBase *base)
576 UBYTE i;
577 const ULONG *p;
578 ULONG *q;
580 /* Copy constant parameters from template */
582 for(p = config_data, q = tcb + PROCB_CF0, i = 0; i < CONFIG_DATA_LEN;
583 i++)
584 *q++ = MakeLELong(*p++);
585 unit->last_tcb = tcb;
587 /* Decide on promiscuous mode */
589 if((unit->flags & UNITF_PROM) != 0)
590 tcb[PROCB_CF3] |= MakeLELong(PROCB_CF3F_PROM);
592 /* AUI or MII? */
594 if((unit->phy_info & PROROM_PHYINFO0F_AUI) != 0)
595 tcb[PROCB_CF3] |= MakeLELong(PROCB_CF3F_CDT);
596 else
597 tcb[PROCB_CF2] |= MakeLELong(PROCB_CF2F_MIIMODE);
599 /* Accept all multicasts? */
601 if((unit->flags & UNITF_ALLMCAST ) != 0)
603 tcb[PROCB_CF5] |= MakeLELong(PROCB_CF5F_ALLMCAST);
606 /* Return */
608 return;
613 /****i* intelpro100.device/GoOnline ****************************************
615 * NAME
616 * GoOnline -- Put the adapter online.
618 * SYNOPSIS
619 * GoOnline(unit)
621 * VOID GoOnline(struct DevUnit *);
623 * INPUTS
624 * unit - A unit of this device.
626 * RESULT
627 * None.
629 ****************************************************************************
633 VOID GoOnline(struct DevUnit *unit, struct DevBase *base)
635 /* Enable the transceiver */
637 unit->flags |= UNITF_ONLINE;
639 unit->LELongOut(unit->card, PROREG_GENPTR,
640 LELong(unit->last_rcb[PROCB_NEXT]));
641 unit->LEWordOut(unit->card, PROREG_COMMAND, PRO_RUCMD_START);
642 while(unit->LEWordIn(unit->card, PROREG_COMMAND) != 0);
644 /* Record start time and report Online event */
646 GetSysTime(&unit->stats.LastStart);
647 ReportEvents(unit, S2EVENT_ONLINE, base);
649 return;
654 /****i* intelpro100.device/GoOffline ***************************************
656 * NAME
657 * GoOffline -- Put the adpater offline.
659 * SYNOPSIS
660 * GoOffline(unit)
662 * VOID GoOffline(struct DevUnit *);
664 * INPUTS
665 * unit - A unit of this device.
667 * RESULT
668 * None.
670 ****************************************************************************
674 VOID GoOffline(struct DevUnit *unit, struct DevBase *base)
676 unit->flags &= ~UNITF_ONLINE;
678 if((unit->flags & UNITF_HAVEADAPTER) != 0)
680 /* Stop reception */
682 unit->LEWordOut(unit->card, PROREG_COMMAND, PRO_RUCMD_ABORT);
684 /* Update statistics */
686 UpdateStats(unit, base);
689 /* Flush pending read and write requests */
691 FlushUnit(unit, WRITE_QUEUE, S2ERR_OUTOFSERVICE, base);
693 /* Report Offline event and return */
695 ReportEvents(unit, S2EVENT_OFFLINE, base);
696 return;
701 /****i* intelpro100.device/AddMulticastRange *******************************
703 * NAME
704 * AddMulticastRange
706 * SYNOPSIS
707 * success = AddMulticastRange(unit, lower_bound, upper_bound)
709 * BOOL AddMulticastRange(struct DevUnit *, UBYTE *, UBYTE *);
711 ****************************************************************************
715 BOOL AddMulticastRange(struct DevUnit *unit, const UBYTE *lower_bound,
716 const UBYTE *upper_bound, struct DevBase *base)
718 struct AddressRange *range;
719 ULONG lower_bound_left, upper_bound_left;
720 UWORD lower_bound_right, upper_bound_right;
722 lower_bound_left = BELong(*((ULONG *)lower_bound));
723 lower_bound_right = BEWord(*((UWORD *)(lower_bound + 4)));
724 upper_bound_left = BELong(*((ULONG *)upper_bound));
725 upper_bound_right = BEWord(*((UWORD *)(upper_bound + 4)));
727 range = FindMulticastRange(unit, lower_bound_left, lower_bound_right,
728 upper_bound_left, upper_bound_right, base);
730 if(range != NULL)
731 range->add_count++;
732 else
734 range = AllocMem(sizeof(struct AddressRange), MEMF_PUBLIC);
735 if(range != NULL)
737 range->lower_bound_left = lower_bound_left;
738 range->lower_bound_right = lower_bound_right;
739 range->upper_bound_left = upper_bound_left;
740 range->upper_bound_right = upper_bound_right;
741 range->add_count = 1;
743 Disable();
744 AddTail((APTR)&unit->multicast_ranges, (APTR)range);
745 Enable();
749 return range != NULL;
754 /****i* intelpro100.device/RemMulticastRange *******************************
756 * NAME
757 * RemMulticastRange
759 * SYNOPSIS
760 * found = RemMulticastRange(unit, lower_bound, upper_bound)
762 * BOOL RemMulticastRange(struct DevUnit *, UBYTE *, UBYTE *);
764 ****************************************************************************
768 BOOL RemMulticastRange(struct DevUnit *unit, const UBYTE *lower_bound,
769 const UBYTE *upper_bound, struct DevBase *base)
771 struct AddressRange *range;
772 ULONG lower_bound_left, upper_bound_left;
773 UWORD lower_bound_right, upper_bound_right;
775 lower_bound_left = BELong(*((ULONG *)lower_bound));
776 lower_bound_right = BEWord(*((UWORD *)(lower_bound + 4)));
777 upper_bound_left = BELong(*((ULONG *)upper_bound));
778 upper_bound_right = BEWord(*((UWORD *)(upper_bound + 4)));
780 range = FindMulticastRange(unit, lower_bound_left, lower_bound_right,
781 upper_bound_left, upper_bound_right, base);
783 if(range != NULL)
785 if(--range->add_count == 0)
787 Disable();
788 Remove((APTR)range);
789 Enable();
790 FreeMem(range, sizeof(struct AddressRange));
794 return range != NULL;
799 /****i* intelpro100.device/FindMulticastRange ******************************
801 * NAME
802 * FindMulticastRange
804 * SYNOPSIS
805 * range = FindMulticastRange(unit, lower_bound_left,
806 * lower_bound_right, upper_bound_left, upper_bound_right)
808 * struct AddressRange *FindMulticastRange(struct DevUnit *, ULONG,
809 * UWORD, ULONG, UWORD);
811 ****************************************************************************
815 static struct AddressRange *FindMulticastRange(struct DevUnit *unit,
816 ULONG lower_bound_left, UWORD lower_bound_right, ULONG upper_bound_left,
817 UWORD upper_bound_right, struct DevBase *base)
819 struct AddressRange *range, *tail;
820 BOOL found = FALSE;
822 range = (APTR)unit->multicast_ranges.mlh_Head;
823 tail = (APTR)&unit->multicast_ranges.mlh_Tail;
825 while((range != tail) && !found)
827 if((lower_bound_left == range->lower_bound_left) &&
828 (lower_bound_right == range->lower_bound_right) &&
829 (upper_bound_left == range->upper_bound_left) &&
830 (upper_bound_right == range->upper_bound_right))
831 found = TRUE;
832 else
833 range = (APTR)range->node.mln_Succ;
836 if(!found)
837 range = NULL;
839 return range;
844 /****i* intelpro100.device/SetMulticast ************************************
846 * NAME
847 * SetMulticast
849 * SYNOPSIS
850 * SetMulticast(unit)
852 * VOID SetMulticast(struct DevUnit *);
854 * FUNCTION
855 * Fills in the unit's multicast list TCB, but does not send it to the
856 * device.
858 ****************************************************************************
862 static VOID SetMulticast(struct DevUnit *unit, struct DevBase *base)
864 ULONG *tcb, address_left;
865 UWORD address_right, i = 0, *p;
866 struct AddressRange *range, *tail;
867 BOOL range_ended;
869 tcb = unit->multicast_cb;
871 if((unit->flags & UNITF_PROM) == 0)
873 /* Fill in multicast list */
875 range = (APTR)unit->multicast_ranges.mlh_Head;
876 tail = (APTR)&unit->multicast_ranges.mlh_Tail;
877 p = (UWORD *)(tcb + PROCB_COUNT);
878 p++;
879 while(range != tail && i < MAX_MCAST_ENTRIES)
881 address_left = range->lower_bound_left;
882 address_right = range->lower_bound_right;
883 range_ended = FALSE;
885 while(!range_ended && i++ < MAX_MCAST_ENTRIES)
887 *p++ = MakeBEWord((UWORD)(address_left >> 16));
888 *p++ = MakeBEWord((UWORD)(address_left));
889 *p++ = MakeBEWord((UWORD)(address_right));
891 if(address_left == range->upper_bound_left &&
892 address_right == range->upper_bound_right)
894 range_ended = TRUE;
896 if(++address_right == 0)
897 address_left++;
900 if(range_ended)
901 range = (APTR)range->node.mln_Succ;
903 p = (UWORD *)(tcb + PROCB_COUNT);
904 *p = MakeLEWord(ETH_ADDRESSSIZE * i);
906 /* Accept all multicasts if there are too many addresses */
908 if(range != tail)
909 unit->flags |= UNITF_ALLMCAST;
910 else
911 unit->flags &= ~UNITF_ALLMCAST;
914 return;
919 /****i* intelpro100.device/FindTypeStats ***********************************
921 * NAME
922 * FindTypeStats
924 * SYNOPSIS
925 * stats = FindTypeStats(unit, list,
926 * packet_type)
928 * struct TypeStats *FindTypeStats(struct DevUnit *, struct MinList *,
929 * ULONG);
931 ****************************************************************************
935 struct TypeStats *FindTypeStats(struct DevUnit *unit, struct MinList *list,
936 ULONG packet_type, struct DevBase *base)
938 struct TypeStats *stats, *tail;
939 BOOL found = FALSE;
941 stats = (APTR)list->mlh_Head;
942 tail = (APTR)&list->mlh_Tail;
944 while((stats != tail) && !found)
946 if(stats->packet_type == packet_type)
947 found = TRUE;
948 else
949 stats = (APTR)stats->node.mln_Succ;
952 if(!found)
953 stats = NULL;
955 return stats;
960 /****i* intelpro100.device/FlushUnit ***************************************
962 * NAME
963 * FlushUnit
965 * SYNOPSIS
966 * FlushUnit(unit, last_queue, error)
968 * VOID FlushUnit(struct DevUnit *, UBYTE, BYTE);
970 ****************************************************************************
974 VOID FlushUnit(struct DevUnit *unit, UBYTE last_queue, BYTE error,
975 struct DevBase *base)
977 struct IORequest *request;
978 UBYTE i;
979 struct Opener *opener, *tail;
981 /* Abort queued requests */
983 for(i = 0; i <= last_queue; i++)
985 while((request = (APTR)GetMsg(unit->request_ports[i])) != NULL)
987 request->io_Error = IOERR_ABORTED;
988 ReplyMsg((APTR)request);
992 #if 1
993 opener = (APTR)unit->openers.mlh_Head;
994 tail = (APTR)&unit->openers.mlh_Tail;
996 /* Flush every opener's read queue */
998 while(opener != tail)
1000 while((request = (APTR)GetMsg(&opener->read_port)) != NULL)
1002 request->io_Error = error;
1003 ReplyMsg((APTR)request);
1005 opener = (APTR)opener->node.mln_Succ;
1008 #else
1009 opener = request->ios2_BufferManagement;
1010 while((request = (APTR)GetMsg(&opener->read_port)) != NULL)
1012 request->io_Error = IOERR_ABORTED;
1013 ReplyMsg((APTR)request);
1015 #endif
1017 /* Return */
1019 return;
1024 /****i* intelpro100.device/StatusInt ***************************************
1026 * NAME
1027 * StatusInt
1029 * SYNOPSIS
1030 * finished = StatusInt(unit)
1032 * BOOL StatusInt(struct DevUnit *);
1034 * INPUTS
1035 * unit - A unit of this device.
1037 * RESULT
1038 * finished - Always FALSE.
1040 ****************************************************************************
1044 static BOOL StatusInt(REG(a1, struct DevUnit *unit), REG(a5, APTR int_code))
1046 struct DevBase *base;
1047 UWORD ints;
1049 base = unit->device;
1050 ints = unit->ByteIn(unit->card, PROREG_INTSTATUS);
1052 if(ints != 0)
1054 /* Handle interrupts */
1056 if((ints & PROINTF_GENERAL) != 0)
1057 Cause(&unit->tx_end_int);
1058 if((ints & PROINTF_RXDONE) != 0)
1059 Cause(&unit->rx_int);
1061 /* Acknowledge interrupts */
1063 unit->ByteOut(unit->card, PROREG_INTSTATUS, ints);
1066 return FALSE;
1071 /****i* intelpro100.device/RXInt *******************************************
1073 * NAME
1074 * RXInt
1076 * SYNOPSIS
1077 * RXInt(unit)
1079 * VOID RXInt(struct DevUnit *);
1081 * INPUTS
1082 * unit - A unit of this device.
1083 * int_code - Unused.
1085 * RESULT
1086 * None.
1088 ****************************************************************************
1092 static VOID RXInt(REG(a1, struct DevUnit *unit), REG(a5, APTR int_code))
1094 UWORD packet_size;
1095 struct DevBase *base;
1096 BOOL is_orphan, accepted;
1097 ULONG rx_status_le, rx_info, packet_type, *rcb, *last_rcb, dma_size;
1098 UBYTE *buffer;
1099 struct IOSana2Req *request, *request_tail;
1100 struct Opener *opener, *opener_tail;
1101 struct TypeStats *tracker;
1103 base = unit->device;
1104 last_rcb = unit->last_rcb;
1105 rcb = (ULONG *)(IPTR)LELong(last_rcb[PROCB_NEXT]);
1107 dma_size = RCB_SIZE;
1108 CachePostDMA(rcb, &dma_size, 0);
1109 while(((rx_status_le = rcb[PROCB_CONTROL])
1110 & MakeLELong(PROCB_CONTROLF_DONE)) != 0)
1112 if((rx_status_le & MakeLELong(PROCB_CONTROLF_OK)) != 0)
1114 is_orphan = TRUE;
1115 rx_info = LELong(rcb[PROCB_RXINFO]);
1116 packet_size = rx_info & PROCB_RXINFOF_FRAMESIZE;
1117 buffer = (UBYTE *)(rcb + PROCB_BUFFER);
1119 if(AddressFilter(unit, buffer + ETH_PACKET_DEST, base))
1121 packet_type = BEWord(*((UWORD *)(buffer + ETH_PACKET_TYPE)));
1123 opener = (APTR)unit->openers.mlh_Head;
1124 opener_tail = (APTR)&unit->openers.mlh_Tail;
1126 /* Offer packet to every opener */
1128 while(opener != opener_tail)
1130 request = (APTR)opener->read_port.mp_MsgList.lh_Head;
1131 request_tail = (APTR)&opener->read_port.mp_MsgList.lh_Tail;
1132 accepted = FALSE;
1134 /* Offer packet to each request until it's accepted */
1136 while((request != request_tail) && !accepted)
1138 if(request->ios2_PacketType == packet_type)
1140 CopyPacket(unit, request, packet_size, packet_type,
1141 buffer, base);
1142 accepted = TRUE;
1144 request =
1145 (APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
1148 if(accepted)
1149 is_orphan = FALSE;
1150 opener = (APTR)opener->node.mln_Succ;
1153 /* If packet was unwanted, give it to S2_READORPHAN request */
1155 if(is_orphan)
1157 unit->stats.UnknownTypesReceived++;
1158 if(!IsMsgPortEmpty(unit->request_ports[ADOPT_QUEUE]))
1160 CopyPacket(unit,
1161 (APTR)unit->request_ports[ADOPT_QUEUE]->
1162 mp_MsgList.lh_Head, packet_size, packet_type, buffer,
1163 base);
1167 /* Update remaining statistics */
1169 tracker =
1170 FindTypeStats(unit, &unit->type_trackers, packet_type, base);
1171 if(tracker != NULL)
1173 tracker->stats.PacketsReceived++;
1174 tracker->stats.BytesReceived += packet_size;
1178 else
1180 unit->stats.BadData++;
1181 ReportEvents(unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX,
1182 base);
1185 rcb[PROCB_CONTROL] = MakeLELong(PROCB_CONTROLF_SUSPEND);
1186 rcb[PROCB_RXINFO] =
1187 MakeLELong(ETH_MAXPACKETSIZE << PROCB_RXINFOB_BUFFERSIZE);
1189 /* Clear suspend flag from previous CB without touching bits that
1190 adapter may be writing to; and resume execution */
1192 *(((UBYTE *)last_rcb + PROCB_CONTROL) + 3) = 0;
1193 dma_size = RCB_SIZE;
1194 CachePreDMA(last_rcb, &dma_size, 0);
1195 if(TRUE)
1196 unit->LEWordOut(unit->card, PROREG_COMMAND, PRO_RUCMD_RESUME);
1198 last_rcb = rcb;
1199 rcb = (ULONG *)(IPTR)LELong(rcb[PROCB_NEXT]);
1202 /* Return */
1204 unit->last_rcb = last_rcb;
1205 return;
1210 /****i* intelpro100.device/CopyPacket **************************************
1212 * NAME
1213 * CopyPacket
1215 * SYNOPSIS
1216 * CopyPacket(unit, request, packet_size, packet_type,
1217 * buffer)
1219 * VOID CopyPacket(struct DevUnit *, struct IOSana2Req *, UWORD, UWORD,
1220 * UBYTE *);
1222 ****************************************************************************
1226 static VOID CopyPacket(struct DevUnit *unit, struct IOSana2Req *request,
1227 UWORD packet_size, UWORD packet_type, UBYTE *buffer,
1228 struct DevBase *base)
1230 struct Opener *opener;
1231 BOOL filtered = FALSE;
1233 /* Set multicast and broadcast flags */
1235 request->ios2_Req.io_Flags &= ~(SANA2IOF_BCAST | SANA2IOF_MCAST);
1236 if((*((ULONG *)(buffer + ETH_PACKET_DEST)) == 0xffffffff) &&
1237 (*((UWORD *)(buffer + ETH_PACKET_DEST + 4)) == 0xffff))
1238 request->ios2_Req.io_Flags |= SANA2IOF_BCAST;
1239 else if((buffer[ETH_PACKET_DEST] & 0x1) != 0)
1240 request->ios2_Req.io_Flags |= SANA2IOF_MCAST;
1242 /* Set source and destination addresses and packet type */
1244 CopyMem(buffer + ETH_PACKET_SOURCE, request->ios2_SrcAddr,
1245 ETH_ADDRESSSIZE);
1246 CopyMem(buffer + ETH_PACKET_DEST, request->ios2_DstAddr,
1247 ETH_ADDRESSSIZE);
1248 request->ios2_PacketType = packet_type;
1250 /* Adjust for cooked packet request */
1252 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
1254 packet_size -= ETH_PACKET_DATA;
1255 buffer += ETH_PACKET_DATA;
1257 #ifdef USE_HACKS
1258 else
1259 packet_size += 4; /* Needed for Shapeshifter & Fusion */
1260 #endif
1261 request->ios2_DataLength = packet_size;
1263 /* Filter packet */
1265 opener = request->ios2_BufferManagement;
1266 if((request->ios2_Req.io_Command == CMD_READ) &&
1267 (opener->filter_hook != NULL))
1268 if(!CallHookPkt(opener->filter_hook, request, buffer))
1269 filtered = TRUE;
1271 if(!filtered)
1273 /* Copy packet into opener's buffer and reply packet */
1275 if(!opener->rx_function(request->ios2_Data, buffer, packet_size))
1277 request->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
1278 request->ios2_WireError = S2WERR_BUFF_ERROR;
1279 ReportEvents(unit,
1280 S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF | S2EVENT_RX,
1281 base);
1283 Remove((APTR)request);
1284 ReplyMsg((APTR)request);
1287 return;
1292 /****i* intelpro100.device/AddressFilter ***********************************
1294 * NAME
1295 * AddressFilter
1297 * SYNOPSIS
1298 * accept = AddressFilter(unit, address)
1300 * BOOL AddressFilter(struct DevUnit *, UBYTE *);
1302 ****************************************************************************
1306 static BOOL AddressFilter(struct DevUnit *unit, UBYTE *address,
1307 struct DevBase *base)
1309 struct AddressRange *range, *tail;
1310 BOOL accept = TRUE;
1311 ULONG address_left;
1312 UWORD address_right;
1314 /* Check whether address is unicast/broadcast or multicast */
1316 address_left = BELong(*((ULONG *)address));
1317 address_right = BEWord(*((UWORD *)(address + 4)));
1319 if((address_left & 0x01000000) != 0 &&
1320 !(address_left == 0xffffffff && address_right == 0xffff))
1322 /* Check if this multicast address is wanted */
1324 range = (APTR)unit->multicast_ranges.mlh_Head;
1325 tail = (APTR)&unit->multicast_ranges.mlh_Tail;
1326 accept = FALSE;
1328 while((range != tail) && !accept)
1330 if(((address_left > range->lower_bound_left) ||
1331 (address_left == range->lower_bound_left) &&
1332 (address_right >= range->lower_bound_right)) &&
1333 ((address_left < range->upper_bound_left) ||
1334 (address_left == range->upper_bound_left) &&
1335 (address_right <= range->upper_bound_right)))
1336 accept = TRUE;
1337 range = (APTR)range->node.mln_Succ;
1340 if(!accept)
1341 unit->special_stats[S2SS_ETHERNET_BADMULTICAST & 0xffff]++;
1344 return accept;
1349 /****i* intelpro100.device/TXInt *******************************************
1351 * NAME
1352 * TXInt
1354 * SYNOPSIS
1355 * TXInt(unit)
1357 * VOID TXInt(struct DevUnit *);
1359 * INPUTS
1360 * unit - A unit of this device.
1361 * int_code - Unused.
1363 * RESULT
1364 * None.
1366 ****************************************************************************
1368 * Note that when the CU is resumed, the adapter examines the suspend flag
1369 * again in the command that caused the suspension. If the flag is set, the
1370 * CU will be suspended without executing any new commands. This means that
1371 * all TCBs can't be in use at the same time, and the dynamically inserted
1372 * multicast list command can't have its suspend flag set.
1376 static VOID TXInt(REG(a1, struct DevUnit *unit), REG(a5, APTR int_code))
1378 struct DevBase *base;
1379 UWORD packet_size, data_size, *p, *q, i;
1380 struct IOSana2Req *request;
1381 BOOL proceed = TRUE;
1382 struct Opener *opener;
1383 ULONG wire_error, *tcb, *last_tcb, *mcast_cb, *fragment, dma_size,
1384 action;
1385 UBYTE *(*dma_tx_function)(REG(a0, APTR));
1386 BYTE error;
1387 UBYTE *buffer;
1388 struct MsgPort *port;
1390 base = unit->device;
1391 port = unit->request_ports[WRITE_QUEUE];
1393 while(proceed && !IsMsgPortEmpty(port))
1395 last_tcb = unit->last_tcb;
1396 tcb = (ULONG *)(IPTR)LELong(last_tcb[PROCB_NEXT]);
1398 /* Ensure there are at least two free CBs available (two are needed
1399 for setting the multicast filter) and that neither the TX nor the
1400 multicast buffer is currently in use */
1402 if((ULONG *)(IPTR)LELong(((ULONG *)(IPTR)LELong(tcb[PROCB_NEXT]))[PROCB_NEXT])
1403 != unit->first_tcb
1404 && (unit->flags & (UNITF_TXBUFFERINUSE | UNITF_MCASTBUFFERINUSE))
1405 == 0)
1407 error = 0;
1408 request = (APTR)GetMsg(port);
1409 request->ios2_Req.io_Message.mn_Node.ln_Type = NT_FREEMSG;
1411 switch(request->ios2_Req.io_Command)
1413 case CMD_WRITE:
1414 case S2_MULTICAST:
1415 case S2_BROADCAST:
1416 action = PROACT_TX;
1417 break;
1418 default:
1419 action = PROACT_CONFIGURE;
1422 if(action == PROACT_TX)
1424 /* Handle TX request */
1426 data_size = packet_size = request->ios2_DataLength;
1428 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
1429 packet_size += ETH_HEADERSIZE;
1431 /* Write packet preamble */
1433 tcb[PROCB_CONTROL] =
1434 MakeLELong(PROACT_TX | PROCB_CONTROLF_SUSPEND
1435 | PROCB_CONTROLF_INT | PROCB_CONTROLF_FLEXIBLE);
1436 fragment = tcb + PROCB_EXTFRAGS;
1437 tcb[PROCB_FRAGMENTS] = MakeLELong((ULONG)(IPTR)fragment);
1439 /* Write packet header */
1441 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
1443 buffer = (UBYTE *)(tcb + PROCB_EXTBUFFER);
1444 tcb[PROCB_TXINFO] =
1445 MakeLELong(2 << PROCB_TXINFOB_FRAGCOUNT
1446 | 1 << PROCB_TXINFOB_THRESHOLD
1447 | PROCB_TXINFOF_EOF);
1448 fragment[PROFRAG_ADDR] = MakeLELong((ULONG)(IPTR)buffer);
1449 fragment[PROFRAG_LEN] = MakeLELong(ETH_HEADERSIZE);
1451 p = (UWORD *)buffer;
1452 for(i = 0, q = (UWORD *)request->ios2_DstAddr;
1453 i < ETH_ADDRESSSIZE / 2; i++)
1454 *p++ = *q++;
1455 for(i = 0, q = (UWORD *)unit->address;
1456 i < ETH_ADDRESSSIZE / 2; i++)
1457 *p++ = *q++;
1458 *p++ = MakeBEWord(request->ios2_PacketType);
1459 buffer = (UBYTE *)p;
1461 fragment += PRO_FRAGLEN;
1463 else
1465 tcb[PROCB_TXINFO] =
1466 MakeLELong(1 << PROCB_TXINFOB_FRAGCOUNT
1467 | 1 << PROCB_TXINFOB_THRESHOLD
1468 | PROCB_TXINFOF_EOF);
1471 /* Get packet data */
1473 opener = (APTR)request->ios2_BufferManagement;
1474 dma_tx_function = opener->dma_tx_function;
1475 if(dma_tx_function != NULL)
1476 buffer = dma_tx_function(request->ios2_Data);
1477 else
1478 buffer = NULL;
1480 if(buffer == NULL)
1482 buffer = unit->tx_buffer;
1483 if(opener->tx_function(buffer, request->ios2_Data,
1484 data_size))
1486 unit->flags |= UNITF_TXBUFFERINUSE;
1488 else
1490 error = S2ERR_NO_RESOURCES;
1491 wire_error = S2WERR_BUFF_ERROR;
1492 ReportEvents(unit,
1493 S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF
1494 | S2EVENT_TX, base);
1498 /* Put pointer to packet data into descriptor */
1500 if(error == 0)
1502 dma_size = data_size;
1503 CachePreDMA(buffer, &dma_size, DMA_ReadFromRAM);
1504 fragment[PROFRAG_ADDR] = MakeLELong((ULONG)(IPTR)buffer);
1505 fragment[PROFRAG_LEN] = MakeLELong(data_size);
1508 else
1510 /* Update multicast reception filter */
1512 SetMulticast(unit, base);
1513 if((unit->flags & UNITF_ALLMCAST) == 0)
1515 tcb[PROCB_CONTROL] = MakeLELong(PROACT_NOP);
1516 mcast_cb = unit->multicast_cb;
1517 mcast_cb[PROCB_CONTROL] = MakeLELong(PROACT_SETMCAST);
1518 mcast_cb[PROCB_NEXT] = tcb[PROCB_NEXT];
1519 tcb[PROCB_NEXT] = MakeLELong((ULONG)(IPTR)mcast_cb);
1520 unit->link_cb = tcb;
1521 tcb = (ULONG *)(IPTR)LELong(mcast_cb[PROCB_NEXT]);
1522 tcb[PROCB_CONTROL] = MakeLELong(PROACT_CONFIGURE
1523 | PROCB_CONTROLF_SUSPEND | PROCB_CONTROLF_INT);
1524 FillConfigData(unit, tcb, base);
1525 unit->flags |= UNITF_MCASTBUFFERINUSE;
1527 else
1529 tcb[PROCB_CONTROL] = MakeLELong(PROACT_CONFIGURE
1530 | PROCB_CONTROLF_SUSPEND | PROCB_CONTROLF_INT);
1531 FillConfigData(unit, tcb, base);
1535 if(error == 0)
1537 /* Clear suspend flag from previous CB without touching bits
1538 that adapter may be writing to; and resume execution */
1540 if(last_tcb[PROCB_CONTROL] != 0)
1541 *(((UBYTE *)last_tcb + PROCB_CONTROL) + 3) =
1542 PROCB_CONTROLF_INT >> 24;
1543 dma_size = TCB_SIZE * TX_SLOT_COUNT;
1544 CachePreDMA(unit->tcbs, &dma_size, 0);
1545 dma_size = MCAST_CB_SIZE;
1546 CachePreDMA(unit->multicast_cb, &dma_size, 0);
1547 if((unit->ByteIn(unit->card, PROREG_STATUS)
1548 & PROREG_STATUSF_CUSTATE)
1549 == (PRO_CUSTATE_SUSPENDED << PROREG_STATUSB_CUSTATE))
1551 unit->LEWordOut(unit->card, PROREG_COMMAND,
1552 PRO_CUCMD_RESUME);
1555 AddTail((APTR)&unit->tx_requests, (APTR)request);
1556 unit->last_tcb = tcb;
1558 else
1560 /* Return failed request */
1562 request->ios2_Req.io_Error = error;
1563 request->ios2_WireError = wire_error;
1564 ReplyMsg((APTR)request);
1565 tcb[PROCB_CONTROL] = 0;
1568 else
1569 proceed = FALSE;
1572 if(proceed)
1573 unit->request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
1574 else
1575 unit->request_ports[WRITE_QUEUE]->mp_Flags = PA_IGNORE;
1577 return;
1582 /****i* intelpro100.device/TXEndInt ****************************************
1584 * NAME
1585 * TXEndInt
1587 * SYNOPSIS
1588 * TXEndInt(unit)
1590 * VOID TXEndInt(struct DevUnit *);
1592 * INPUTS
1593 * unit - A unit of this device.
1594 * int_code - Unused.
1596 * RESULT
1597 * None.
1599 ****************************************************************************
1601 * It appears to be safe to assume that there will always be at least one
1602 * completed packet whenever this interrupt is called.
1606 static VOID TXEndInt(REG(a1, struct DevUnit *unit), REG(a5, APTR int_code))
1608 UWORD data_size, packet_size;
1609 UBYTE *buffer;
1610 struct DevBase *base;
1611 struct IOSana2Req *request;
1612 ULONG *tcb, *fragment, dma_size, action;
1613 struct TypeStats *tracker;
1615 /* Retire sent packets and configuration commands */
1617 base = unit->device;
1618 dma_size = TCB_SIZE * TX_SLOT_COUNT;
1619 CachePostDMA(unit->tcbs, &dma_size, 0);
1620 dma_size = MCAST_CB_SIZE;
1621 CachePostDMA(unit->multicast_cb, &dma_size, 0);
1623 for(tcb = unit->first_tcb;
1624 (tcb[PROCB_CONTROL] & MakeLELong(PROCB_CONTROLF_DONE)) != 0;
1625 tcb = (ULONG *)(IPTR)LELong(tcb[PROCB_NEXT]))
1627 action = LELong(tcb[PROCB_CONTROL]) & PROCB_CONTROLF_ACTION;
1629 if(action == PROACT_TX || action == PROACT_CONFIGURE
1630 && (unit->link_cb != NULL
1631 || (tcb[PROCB_CF5] & PROCB_CF5F_ALLMCAST) != 0))
1633 request = (APTR)RemHead((APTR)&unit->tx_requests);
1635 if(action == PROACT_TX)
1637 /* Mark end of DMA */
1639 data_size = packet_size = request->ios2_DataLength;
1640 fragment = (ULONG *)(IPTR)LELong(tcb[PROCB_FRAGMENTS]);
1642 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
1644 packet_size += ETH_HEADERSIZE;
1645 fragment += PRO_FRAGLEN;
1648 buffer = (UBYTE *)(IPTR)LELong(fragment[PROFRAG_ADDR]);
1649 dma_size = data_size;
1650 CachePostDMA(buffer, &dma_size, DMA_ReadFromRAM);
1652 /* Check if unit's buffer is now free */
1654 if(buffer == unit->tx_buffer)
1655 unit->flags &= ~UNITF_TXBUFFERINUSE;
1657 /* Update statistics */
1659 tracker = FindTypeStats(unit, &unit->type_trackers,
1660 request->ios2_PacketType, base);
1661 if(tracker != NULL)
1663 tracker->stats.PacketsSent++;
1664 tracker->stats.BytesSent += packet_size;
1667 else if(action == PROACT_CONFIGURE)
1669 /* Mark end of multicast update */
1671 if(unit->link_cb != NULL)
1673 unit->link_cb[PROCB_NEXT] = MakeLELong((ULONG)(IPTR)tcb);
1674 unit->flags &= ~UNITF_MCASTBUFFERINUSE;
1675 unit->link_cb = NULL;
1679 /* Reply request */
1681 request->ios2_Req.io_Error = 0;
1682 ReplyMsg((APTR)request);
1685 /* Mark CB as unused/clear suspend flag */
1687 tcb[PROCB_CONTROL] = 0;
1690 dma_size = TCB_SIZE * TX_SLOT_COUNT;
1691 CachePreDMA(unit->tcbs, &dma_size, 0);
1693 unit->first_tcb = tcb;
1695 /* Restart downloads if they had stopped */
1697 if(unit->request_ports[WRITE_QUEUE]->mp_Flags == PA_IGNORE)
1698 Cause(&unit->tx_int);
1700 return;
1705 /****i* intelpro100.device/UpdateStats *************************************
1707 * NAME
1708 * UpdateStats
1710 * SYNOPSIS
1711 * UpdateStats(unit)
1713 * VOID UpdateStats(struct DevUnit *);
1715 * INPUTS
1716 * unit - A unit of this device.
1718 * RESULT
1719 * None.
1721 ****************************************************************************
1725 VOID UpdateStats(struct DevUnit *unit, struct DevBase *base)
1727 ULONG dma_size, *buffer;
1729 buffer = unit->stats_buffer;
1730 buffer[STAT_COUNT] = 0;
1731 dma_size = sizeof(ULONG) * STAT_COUNT;
1732 CachePreDMA(unit->stats_buffer, &dma_size, 0);
1733 unit->ByteOut(unit->card, PROREG_COMMAND, PRO_CUCMD_DUMPRESETSTATS);
1734 while(buffer[STAT_COUNT] != MakeLELong(0xa007))
1736 dma_size = sizeof(ULONG) * STAT_COUNT;
1737 CachePostDMA(unit->stats_buffer, &dma_size, 0);
1740 unit->stats.Overruns += LELong(buffer[PROSTAT_RXOVERRUNS]);
1741 unit->stats.PacketsSent += LELong(buffer[PROSTAT_TXFRAMESOK]);
1742 unit->stats.PacketsReceived += LELong(buffer[PROSTAT_RXFRAMESOK]);
1743 unit->special_stats[S2SS_ETHERNET_RETRIES & 0xffff] +=
1744 LELong(buffer[PROSTAT_FRAMESDEFERRED]);
1745 unit->special_stats[S2SS_ETHERNET_FIFO_UNDERRUNS & 0xffff] +=
1746 LELong(buffer[PROSTAT_TXUNDERRUNS]);
1748 return;
1753 /****i* intelpro100.device/ReportEvents ************************************
1755 * NAME
1756 * ReportEvents
1758 * SYNOPSIS
1759 * ReportEvents(unit, events)
1761 * VOID ReportEvents(struct DevUnit *, ULONG);
1763 * INPUTS
1764 * unit - A unit of this device.
1765 * events - A mask of events to report.
1767 * RESULT
1768 * None.
1770 ****************************************************************************
1774 static VOID ReportEvents(struct DevUnit *unit, ULONG events,
1775 struct DevBase *base)
1777 struct IOSana2Req *request, *tail, *next_request;
1778 struct List *list;
1780 list = &unit->request_ports[EVENT_QUEUE]->mp_MsgList;
1781 next_request = (APTR)list->lh_Head;
1782 tail = (APTR)&list->lh_Tail;
1784 Disable();
1785 while(next_request != tail)
1787 request = next_request;
1788 next_request = (APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
1790 if((request->ios2_WireError & events) != 0)
1792 request->ios2_WireError = events;
1793 Remove((APTR)request);
1794 ReplyMsg((APTR)request);
1797 Enable();
1799 return;
1804 /****i* intelpro100.device/UnitTask ****************************************
1806 * NAME
1807 * UnitTask
1809 * SYNOPSIS
1810 * UnitTask()
1812 * VOID UnitTask();
1814 * FUNCTION
1815 * Completes deferred requests.
1817 ****************************************************************************
1821 #ifdef __MORPHOS__
1822 #undef UnitTask
1823 #endif
1825 static VOID UnitTask(struct ExecBase *sys_base)
1827 struct Task *task;
1828 struct IORequest *request;
1829 struct DevUnit *unit;
1830 struct DevBase *base;
1831 struct MsgPort *general_port;
1832 ULONG signals, wait_signals, general_port_signal;
1834 /* Get parameters */
1836 task = AbsExecBase->ThisTask;
1837 unit = task->tc_UserData;
1838 base = unit->device;
1840 /* Activate general request port */
1842 general_port = unit->request_ports[GENERAL_QUEUE];
1843 general_port->mp_SigTask = task;
1844 general_port->mp_SigBit = AllocSignal(-1);
1845 general_port_signal = 1 << general_port->mp_SigBit;
1846 general_port->mp_Flags = PA_SIGNAL;
1848 /* Allocate a signal for notification of card removal */
1850 wait_signals = (1 << general_port->mp_SigBit);
1852 /* Tell ourselves to check port for old messages */
1854 Signal(task, general_port_signal);
1856 /* Infinite loop to service requests and signals */
1858 while(TRUE)
1860 signals = Wait(wait_signals);
1862 if((signals & general_port_signal) != 0)
1864 while((request = (APTR)GetMsg(general_port)) != NULL)
1866 /* Service the request as soon as the unit is free */
1868 ObtainSemaphore(&unit->access_lock);
1869 ServiceRequest((APTR)request, base);
1877 /****i* intelpro100.device/GetEEPROMAddressSize ****************************
1879 * NAME
1880 * GetEEPROMAddressSize
1882 * SYNOPSIS
1883 * size = GetEEPROMAddressSize(unit)
1885 * UWORD GetEEPROMAddressSize(struct DevUnit *);
1887 * INPUTS
1888 * unit - A unit of this device.
1890 * RESULT
1891 * size - Width of EEPROM addresses.
1893 ****************************************************************************
1895 * Although the manual doesn't make it explicit, chip select must be asserted
1896 * before setting any other bits, at least on the i82557.
1900 static UWORD GetEEPROMAddressSize(struct DevUnit *unit,
1901 struct DevBase *base)
1903 UWORD size;
1905 unit->LEWordOut(unit->card, PROREG_EEPROM, PROREG_EEPROMF_SELECT);
1906 WriteEEPROMBits(unit, 0x6, 3, base);
1907 for(size = 1; WriteEEPROMBit(unit, FALSE, base); size++);
1908 ReadEEPROMBits(unit, 16, base);
1909 unit->LEWordOut(unit->card, PROREG_EEPROM, 0);
1910 BusyMicroDelay(1, base);
1912 return size;
1917 /****i* intelpro100.device/ReadEEPROM **************************************
1919 * NAME
1920 * ReadEEPROM -- Read an EEPROM location.
1922 * SYNOPSIS
1923 * value = ReadEEPROM(unit, index)
1925 * UWORD ReadEEPROM(struct DevUnit *, UWORD);
1927 * INPUTS
1928 * unit - A unit of this device.
1929 * index - Offset within EEPROM.
1931 * RESULT
1932 * value - Contents of specified EEPROM location.
1934 ****************************************************************************
1938 static UWORD ReadEEPROM(struct DevUnit *unit, UWORD index,
1939 struct DevBase *base)
1941 UWORD value;
1943 unit->LEWordOut(unit->card, PROREG_EEPROM, PROREG_EEPROMF_SELECT);
1944 WriteEEPROMBits(unit, 0x6, 3, base);
1945 WriteEEPROMBits(unit, index, unit->eeprom_addr_size, base);
1946 value = ReadEEPROMBits(unit, 16, base);
1947 unit->LEWordOut(unit->card, PROREG_EEPROM, 0);
1948 BusyMicroDelay(1, base);
1950 return value;
1955 /****i* intelpro100.device/ReadEEPROMBits **********************************
1957 * NAME
1958 * ReadEEPROMBits -- Read a stream of bits from the EEPROM.
1960 * SYNOPSIS
1961 * value = ReadEEPROMBits(unit, count)
1963 * ULONG ReadEEPROMBits(struct DevUnit *, UBYTE);
1965 * INPUTS
1966 * unit - A unit of this device.
1967 * count - Number of bits to be read.
1969 * RESULT
1970 * value - The bits read from the EEPROM, right-justified.
1972 ****************************************************************************
1976 static ULONG ReadEEPROMBits(struct DevUnit *unit, UBYTE count,
1977 struct DevBase *base)
1979 UBYTE i;
1980 ULONG value = 0;
1982 for(i = 0; i < count; i++)
1984 value <<= 1;
1985 if(ReadEEPROMBit(unit, base))
1986 value |= 0x1;
1989 return value;
1993 /****i* intelpro100.device/WriteEEPROMBits *********************************
1995 * NAME
1996 * WriteEEPROMBits -- Write a stream of bits to the EEPROM.
1998 * SYNOPSIS
1999 * WriteEEPROMBits(unit, value, count)
2001 * VOID WriteEEPROMBits(struct DevUnit *, ULONG, UBYTE);
2003 * INPUTS
2004 * unit - A unit of this device.
2005 * value - The bits to write to the EEPROM, right-justified.
2006 * count - Number of bits to be Write.
2008 * RESULT
2009 * None.
2011 ****************************************************************************
2015 static VOID WriteEEPROMBits(struct DevUnit *unit, ULONG value, UBYTE count,
2016 struct DevBase *base)
2018 ULONG mask;
2020 for(mask = 1 << (count - 1); mask != 0; mask >>= 1)
2021 WriteEEPROMBit(unit, (value & mask) != 0, base);
2023 return;
2028 /****i* intelpro100.device/ReadEEPROMBit ***********************************
2030 * NAME
2031 * ReadEEPROMBit -- Read a bit from the EEPROM.
2033 * SYNOPSIS
2034 * value = ReadEEPROMBit(unit)
2036 * BOOL ReadEEPROMBit(struct DevUnit *);
2038 * INPUTS
2039 * unit - A unit of this device.
2041 * RESULT
2042 * value - True for one, false for zero.
2044 ****************************************************************************
2048 static BOOL ReadEEPROMBit(struct DevUnit *unit, struct DevBase *base)
2050 BOOL is_one;
2052 unit->LEWordOut(unit->card, PROREG_EEPROM,
2053 PROREG_EEPROMF_SELECT | PROREG_EEPROMF_CLK);
2054 BusyMicroDelay(2, base);
2055 is_one =
2056 (unit->LEWordIn(unit->card, PROREG_EEPROM) & PROREG_EEPROMF_DATAIN)
2057 != 0;
2058 unit->LEWordOut(unit->card, PROREG_EEPROM, PROREG_EEPROMF_SELECT);
2059 BusyMicroDelay(2, base);
2061 return is_one;
2066 /****i* intelpro100.device/WriteEEPROMBit **********************************
2068 * NAME
2069 * WriteEEPROMBit -- Write a bit to the EEPROM.
2071 * SYNOPSIS
2072 * data_in = WriteEEPROMBit(unit, is_one)
2074 * BOOL WriteEEPROMBit(struct DevUnit *, BOOL);
2076 * INPUTS
2077 * unit - A unit of this device.
2078 * is_one - True if a set bit should be written.
2080 * RESULT
2081 * data_in - True if data-in bit is set.
2083 ****************************************************************************
2087 static BOOL WriteEEPROMBit(struct DevUnit *unit, BOOL is_one,
2088 struct DevBase *base)
2090 UWORD data_out;
2092 if(is_one)
2093 data_out = PROREG_EEPROMF_DATAOUT;
2094 else
2095 data_out = 0;
2097 unit->LEWordOut(unit->card, PROREG_EEPROM,
2098 PROREG_EEPROMF_SELECT | data_out);
2099 unit->LEWordOut(unit->card, PROREG_EEPROM,
2100 PROREG_EEPROMF_SELECT | PROREG_EEPROMF_CLK | data_out);
2101 BusyMicroDelay(2, base);
2102 unit->LEWordOut(unit->card, PROREG_EEPROM,
2103 PROREG_EEPROMF_SELECT | data_out);
2104 BusyMicroDelay(2, base);
2106 return
2107 (unit->LEWordIn(unit->card, PROREG_EEPROM) & PROREG_EEPROMF_DATAIN)
2108 != 0;
2113 /****i* intelpro100.device/ReadMII *****************************************
2115 * NAME
2116 * ReadMII -- Read a register in an MII PHY.
2118 * SYNOPSIS
2119 * value = ReadMII(unit, phy_no, reg_no)
2121 * UWORD ReadMII(struct DevUnit *, UWORD, UWORD);
2123 * INPUTS
2124 * unit - A unit of this device.
2125 * phy_no - Index of PHY to use.
2126 * reg_no - MII register to read.
2128 * RESULT
2129 * value - Value read from MII register.
2131 ****************************************************************************
2135 static UWORD ReadMII(struct DevUnit *unit, UWORD phy_no, UWORD reg_no,
2136 struct DevBase *base)
2138 ULONG value;
2140 unit->LELongOut(unit->card, PROREG_MIICONTROL,
2141 2 << PROREG_MIICONTROLB_CMD
2142 | phy_no << PROREG_MIICONTROLB_PHYNO
2143 | reg_no << PROREG_MIICONTROLB_REGNO);
2145 value = unit->LELongIn(unit->card, PROREG_MIICONTROL);
2146 while((value & PROREG_MIICONTROLF_READY) == 0);
2148 return value & PROREG_MIICONTROLF_DATA;
2153 /****i* intelpro100.device/WriteMII ****************************************
2155 * NAME
2156 * WriteMII -- Write to a register in an MII PHY.
2158 * SYNOPSIS
2159 * WriteMII(unit, phy_no, reg_no, value)
2161 * VOID WriteMII(struct DevUnit *, UWORD, UWORD, UWORD);
2163 * INPUTS
2164 * unit - A unit of this device.
2165 * phy_no - Index of PHY to use.
2166 * reg_no - MII register to write to.
2167 * value - Value to write to MII register.
2169 * RESULT
2170 * None.
2172 ****************************************************************************
2176 static VOID WriteMII(struct DevUnit *unit, UWORD phy_no, UWORD reg_no,
2177 UWORD value, struct DevBase *base)
2179 unit->LELongOut(unit->card, PROREG_MIICONTROL,
2180 1 << PROREG_MIICONTROLB_CMD
2181 | phy_no << PROREG_MIICONTROLB_PHYNO
2182 | reg_no << PROREG_MIICONTROLB_REGNO
2183 | value);
2184 while
2187 unit->LELongIn(unit->card, PROREG_MIICONTROL)
2188 & PROREG_MIICONTROLF_READY
2190 == 0
2193 return;
2198 /****i* intelpro100.device/BusyMicroDelay **********************************
2200 * NAME
2201 * BusyMilliDelay - Busy-wait for specified number of microseconds.
2203 * SYNOPSIS
2204 * BusyMilliDelay(micros)
2206 * VOID BusyMilliDelay(ULONG);
2208 ****************************************************************************
2212 #if 1
2213 static VOID BusyMicroDelay(ULONG micros, struct DevBase *base)
2215 struct timeval time, end_time;
2217 GetSysTime(&end_time);
2218 time.tv_secs = 0;
2219 time.tv_micro = micros;
2220 AddTime(&end_time, &time);
2222 while(CmpTime(&end_time, &time) < 0)
2223 GetSysTime(&time);
2225 return;
2229 #else
2230 static VOID BusyMicroDelay(ULONG micros, struct DevBase *base)
2232 struct EClockVal time, end_time;
2233 ULONG rate;
2235 rate = ReadEClock(&time);
2236 end_time.ev_hi = time.ev_hi;
2237 end_time.ev_lo = time.ev_lo + (micros * rate + 1) / 1000000;
2238 if(end_time.ev_lo < time.ev_lo)
2239 end_time.ev_hi++;
2241 while(time.ev_lo < end_time.ev_lo || time.ev_hi < end_time.ev_hi)
2242 ReadEClock(&time);
2244 return;
2246 #endif