2 This program is free software; you can redistribute it and/or modify
3 it under the terms of the GNU General Public License as published by
4 the Free Software Foundation; either version 2 of the License, or
5 (at your option) any later version.
7 This program is distributed in the hope that it will be useful, but
8 WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 General Public License for more details.
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 59 Temple Place - Suite 330, Boston,
19 #include <aros/debug.h>
21 #include <exec/types.h>
22 #include <exec/resident.h>
24 #include <exec/ports.h>
25 #include <exec/errors.h>
27 #include <devices/sana2.h>
28 #include <devices/sana2specialstats.h>
29 #include <devices/newstyle.h>
31 #include <utility/utility.h>
32 #include <utility/tagitem.h>
33 #include <utility/hooks.h>
35 #include <proto/exec.h>
36 #include <proto/dos.h>
37 #include <proto/battclock.h>
42 #include LC_LIBDEFS_FILE
44 #define KNOWN_EVENTS \
45 (S2EVENT_ERROR | S2EVENT_TX | S2EVENT_RX | S2EVENT_ONLINE \
46 | S2EVENT_OFFLINE | S2EVENT_BUFF | S2EVENT_HARDWARE | S2EVENT_SOFTWARE)
48 static BOOL
CmdInvalid(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
49 static BOOL
CmdRead(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
50 static BOOL
CmdWrite(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
51 static BOOL
CmdFlush(LIBBASETYPEPTR LIBBASE
, struct IORequest
*request
);
52 static BOOL
CmdS2DeviceQuery(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
53 static BOOL
CmdGetStationAddress(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
54 static BOOL
CmdConfigInterface(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
55 static BOOL
CmdBroadcast(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
56 static BOOL
CmdTrackType(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
57 static BOOL
CmdUntrackType(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
58 static BOOL
CmdGetTypeStats(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
59 static BOOL
CmdGetGlobalStats(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
60 static BOOL
CmdDeviceQuery(LIBBASETYPEPTR LIBBASE
, struct IOStdReq
*request
);
61 static BOOL
CmdOnEvent(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
62 static BOOL
CmdReadOrphan(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
63 static BOOL
CmdOnline(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
64 static BOOL
CmdOffline(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
65 static BOOL
CmdAddMulticastAddresses(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
66 static BOOL
CmdDelMulticastAddresses(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
68 static const UWORD supported_commands
[] =
76 S2_ADDMULTICASTADDRESS
,
77 S2_DELMULTICASTADDRESS
,
83 // S2_GETSPECIALSTATS,
90 S2_ADDMULTICASTADDRESSES
,
91 S2_DELMULTICASTADDRESSES
,
95 void handle_request(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
99 switch(request
->ios2_Req
.io_Command
)
102 complete
= CmdRead(LIBBASE
, request
);
107 complete
= CmdWrite(LIBBASE
, request
);
111 complete
= CmdFlush(LIBBASE
, (struct IORequest
*)request
);
115 complete
= CmdS2DeviceQuery(LIBBASE
, request
);
118 case S2_GETSTATIONADDRESS
:
119 complete
= CmdGetStationAddress(LIBBASE
, request
);
122 case S2_CONFIGINTERFACE
:
123 complete
= CmdConfigInterface(LIBBASE
, request
);
127 complete
= CmdBroadcast(LIBBASE
, request
);
131 complete
= CmdTrackType(LIBBASE
, request
);
135 complete
= CmdUntrackType(LIBBASE
, request
);
138 case S2_GETTYPESTATS
:
139 complete
= CmdGetTypeStats(LIBBASE
, request
);
142 case S2_GETGLOBALSTATS
:
143 complete
= CmdGetGlobalStats(LIBBASE
, request
);
147 complete
= CmdOnEvent(LIBBASE
, request
);
151 complete
= CmdReadOrphan(LIBBASE
, request
);
155 complete
= CmdOnline(LIBBASE
, request
);
159 complete
= CmdOffline(LIBBASE
, request
);
162 case S2_ADDMULTICASTADDRESS
:
163 case S2_ADDMULTICASTADDRESSES
:
164 complete
= CmdAddMulticastAddresses(LIBBASE
, request
);
167 case S2_DELMULTICASTADDRESS
:
168 case S2_DELMULTICASTADDRESSES
:
169 complete
= CmdDelMulticastAddresses(LIBBASE
, request
);
172 case NSCMD_DEVICEQUERY
:
173 complete
= CmdDeviceQuery(LIBBASE
, (struct IOStdReq
*)request
);
177 complete
= CmdInvalid(LIBBASE
, request
);
180 if(complete
&& (request
->ios2_Req
.io_Flags
& IOF_QUICK
) == 0)
181 ReplyMsg((APTR
)request
);
183 ReleaseSemaphore(&((struct EMACUnit
*)request
->ios2_Req
.io_Unit
)->eu_Lock
);
186 static BOOL
CmdInvalid(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
188 request
->ios2_Req
.io_Error
= IOERR_NOCMD
;
189 request
->ios2_WireError
= S2WERR_GENERIC_ERROR
;
194 static BOOL
CmdRead(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
196 struct EMACUnit
*unit
;
197 struct Opener
*opener
;
198 BOOL complete
= FALSE
;
200 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
202 D(bug("[EMAC%d] S2CmdRead()\n", unit
->eu_UnitNum
));
204 if((unit
->eu_Flags
& IFF_UP
) != 0)
206 opener
= request
->ios2_BufferManagement
;
207 request
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
208 PutMsg(&opener
->read_port
, (struct Message
*)request
);
212 request
->ios2_Req
.io_Error
= S2ERR_OUTOFSERVICE
;
213 request
->ios2_WireError
= S2WERR_UNIT_OFFLINE
;
222 static BOOL
CmdWrite(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
224 struct EMACUnit
*unit
;
226 ULONG wire_error
= S2WERR_GENERIC_ERROR
;
227 BOOL complete
= FALSE
;
229 /* Check request is valid */
231 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
233 D(bug("[EMAC%d] S2CmdWrite()\n", unit
->eu_UnitNum
));
235 if((unit
->eu_Flags
& IFF_UP
) == 0)
237 error
= S2ERR_OUTOFSERVICE
;
238 wire_error
= S2WERR_UNIT_OFFLINE
;
240 else if((request
->ios2_Req
.io_Command
== S2_MULTICAST
) &&
241 ((request
->ios2_DstAddr
[0] & 0x1) == 0))
243 error
= S2ERR_BAD_ADDRESS
;
244 wire_error
= S2WERR_BAD_MULTICAST
;
247 /* Queue request for sending */
250 request
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
251 PutMsg(unit
->eu_RequestPorts
[WRITE_QUEUE
], (APTR
)request
);
255 request
->ios2_Req
.io_Error
= error
;
256 request
->ios2_WireError
= wire_error
;
265 static BOOL
CmdFlush(LIBBASETYPEPTR LIBBASE
, struct IORequest
*request
)
267 // TODO: Implement CmdFlush!!!!!!!!!
268 // FlushUnit(LIBBASE, (APTR)request->io_Unit, EVENT_QUEUE, IOERR_ABORTED);
272 static BOOL
CmdS2DeviceQuery(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
274 struct EMACUnit
*unit
= (APTR
)request
->ios2_Req
.io_Unit
;
275 //struct fe_priv *np = unit->pcnu_fe_priv;
276 struct Sana2DeviceQuery
*info
;
277 ULONG size_available
, size
;
279 D(bug("[EMAC%d] S2CmdDeviceQuery()\n", unit
->eu_UnitNum
));
281 /* Copy device info */
283 info
= request
->ios2_StatData
;
284 size
= size_available
= info
->SizeAvailable
;
285 if(size
> sizeof(struct Sana2DeviceQuery
))
286 size
= sizeof(struct Sana2DeviceQuery
);
288 CopyMem(&LIBBASE
->emb_Sana2Info
, info
, size
);
290 info
->BPS
= 100000000;
292 info
->HardwareType
= S2WireType_Ethernet
;
293 info
->SizeAvailable
= size_available
;
294 info
->SizeSupplied
= size
;
301 static BOOL
CmdGetStationAddress(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
303 struct EMACUnit
*unit
;
307 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
309 D(bug("[EMAC%d] S2CmdGetStationAddress()\n", unit
->eu_UnitNum
));
311 CopyMem(unit
->eu_DevAddr
, request
->ios2_SrcAddr
, ETH_ADDRESSSIZE
);
312 CopyMem(unit
->eu_OrgAddr
, request
->ios2_DstAddr
, ETH_ADDRESSSIZE
);
319 static BOOL
CmdConfigInterface(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
321 struct EMACUnit
*unit
;
323 /* Configure adapter */
325 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
327 D(bug("[EMAC%d] S2CmdConfigInterface()\n", unit
->eu_UnitNum
));
329 if((unit
->eu_Flags
& IFF_CONFIGURED
) == 0)
331 CopyMem(request
->ios2_SrcAddr
, unit
->eu_DevAddr
, ETH_ADDRESSSIZE
);
332 unit
->set_mac_address(unit
);
333 unit
->eu_Flags
|= IFF_CONFIGURED
;
337 request
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
338 request
->ios2_WireError
= S2WERR_IS_CONFIGURED
;
346 static BOOL
CmdBroadcast(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
348 /* Fill in the broadcast address as destination */
350 *((ULONG
*)request
->ios2_DstAddr
) = 0xffffffff;
351 *((UWORD
*)(request
->ios2_DstAddr
+ 4)) = 0xffff;
353 /* Queue the write as normal */
355 return CmdWrite(LIBBASE
, request
);
358 static BOOL
CmdTrackType(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
360 struct EMACUnit
*unit
;
361 struct Opener
*opener
;
362 ULONG packet_type
, wire_error
=0;
363 struct TypeTracker
*tracker
;
364 struct TypeStats
*initial_stats
;
367 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
369 D(bug("[EMAC%d] S2CmdTrackType(%d)\n", unit
->eu_UnitNum
, request
->ios2_PacketType
));
371 packet_type
= request
->ios2_PacketType
;
373 /* Get global tracker */
374 tracker
= (struct TypeTracker
*)
375 FindTypeStats(LIBBASE
, unit
, &unit
->eu_TypeTrackers
, packet_type
);
378 tracker
->user_count
++;
382 AllocMem(sizeof(struct TypeTracker
), MEMF_PUBLIC
|MEMF_CLEAR
);
385 tracker
->packet_type
= packet_type
;
386 tracker
->user_count
= 1;
389 AddTail((APTR
)&unit
->eu_TypeTrackers
, (APTR
)tracker
);
394 /* Store initial figures for this opener */
396 opener
= request
->ios2_BufferManagement
;
397 initial_stats
= FindTypeStats(LIBBASE
, unit
, &opener
->initial_stats
, packet_type
);
398 if(initial_stats
!= NULL
)
400 error
= S2ERR_BAD_STATE
;
401 wire_error
= S2WERR_ALREADY_TRACKED
;
406 initial_stats
= AllocMem(sizeof(struct TypeStats
), MEMF_PUBLIC
);
407 if(initial_stats
== NULL
)
409 error
= S2ERR_NO_RESOURCES
;
410 wire_error
= S2WERR_GENERIC_ERROR
;
416 CopyMem(tracker
, initial_stats
, sizeof(struct TypeStats
));
417 AddTail((APTR
)&opener
->initial_stats
, (APTR
)initial_stats
);
422 request
->ios2_Req
.io_Error
= error
;
423 request
->ios2_WireError
= wire_error
;
427 static BOOL
CmdUntrackType(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
429 struct EMACUnit
*unit
;
430 struct Opener
*opener
;
432 struct TypeTracker
*tracker
;
433 struct TypeStats
*initial_stats
;
435 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
437 D(bug("[EMAC%d] S2CmdUntrackType()\n", unit
->eu_UnitNum
));
439 packet_type
= request
->ios2_PacketType
;
441 /* Get global tracker and initial figures */
443 tracker
= (struct TypeTracker
*)
444 FindTypeStats(LIBBASE
, unit
, &unit
->eu_TypeTrackers
, packet_type
);
445 opener
= request
->ios2_BufferManagement
;
446 initial_stats
= FindTypeStats(LIBBASE
, unit
, &opener
->initial_stats
, packet_type
);
448 /* Decrement tracker usage and free unused structures */
450 if(initial_stats
!= NULL
)
452 if((--tracker
->user_count
) == 0)
455 Remove((APTR
)tracker
);
457 FreeMem(tracker
, sizeof(struct TypeTracker
));
460 Remove((APTR
)initial_stats
);
461 FreeMem(initial_stats
, sizeof(struct TypeStats
));
465 request
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
466 request
->ios2_WireError
= S2WERR_NOT_TRACKED
;
474 static BOOL
CmdGetTypeStats(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
476 struct EMACUnit
*unit
;
477 struct Opener
*opener
;
479 struct TypeStats
*initial_stats
, *tracker
;
480 struct Sana2PacketTypeStats
*stats
;
482 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
484 D(bug("[EMAC%d] S2CmdGetTypeStats()\n", unit
->eu_UnitNum
));
486 packet_type
= request
->ios2_PacketType
;
488 /* Get global tracker and initial figures */
490 tracker
= FindTypeStats(LIBBASE
, unit
, &unit
->eu_TypeTrackers
, packet_type
);
491 opener
= request
->ios2_BufferManagement
;
492 initial_stats
= FindTypeStats(LIBBASE
, unit
, &opener
->initial_stats
, packet_type
);
494 /* Copy and adjust figures */
495 if(initial_stats
!= NULL
)
497 stats
= request
->ios2_StatData
;
498 CopyMem(&tracker
->stats
, stats
, sizeof(struct Sana2PacketTypeStats
));
499 stats
->PacketsSent
-= initial_stats
->stats
.PacketsSent
;
500 stats
->PacketsReceived
-= initial_stats
->stats
.PacketsReceived
;
501 stats
->BytesSent
-= initial_stats
->stats
.BytesSent
;
502 stats
->BytesReceived
-= initial_stats
->stats
.BytesReceived
;
503 stats
->PacketsDropped
-= initial_stats
->stats
.PacketsDropped
;
507 request
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
508 request
->ios2_WireError
= S2WERR_NOT_TRACKED
;
516 static BOOL
CmdGetGlobalStats(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
518 struct EMACUnit
*unit
;
520 /* Update and copy stats */
522 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
524 D(bug("[EMAC%d] S2CmdGetGlobalStats()\n", unit
->eu_UnitNum
));
526 CopyMem(&unit
->eu_Stats
, request
->ios2_StatData
,
527 sizeof(struct Sana2DeviceStats
));
534 static BOOL
CmdDeviceQuery(LIBBASETYPEPTR LIBBASE
, struct IOStdReq
*request
)
536 struct NSDeviceQueryResult
*info
;
538 /* Set structure size twice */
540 info
= request
->io_Data
;
541 request
->io_Actual
= info
->SizeAvailable
=
542 offsetof(struct NSDeviceQueryResult
, SupportedCommands
) + sizeof(APTR
);
544 /* Report device details */
546 info
->DeviceType
= NSDEVTYPE_SANA2
;
547 info
->DeviceSubType
= 0;
549 info
->SupportedCommands
= (APTR
)supported_commands
;
557 static BOOL
CmdOnEvent(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
559 struct EMACUnit
*unit
;
560 ULONG events
, wanted_events
;
561 BOOL complete
= FALSE
;
563 /* Check if we understand the event types */
565 unit
= (struct EMACUnit
*)request
->ios2_Req
.io_Unit
;
567 D(bug("[EMAC%d] S2CmdOnEvent()\n", unit
->eu_UnitNum
));
569 wanted_events
= request
->ios2_WireError
;
570 if((wanted_events
& ~KNOWN_EVENTS
) != 0)
572 request
->ios2_Req
.io_Error
= S2ERR_NOT_SUPPORTED
;
573 events
= S2WERR_BAD_EVENT
;
577 if((unit
->eu_Flags
& IFF_UP
) != 0)
578 events
= S2EVENT_ONLINE
;
580 events
= S2EVENT_OFFLINE
;
582 events
&= wanted_events
;
585 /* Reply request if a wanted event has already occurred */
589 request
->ios2_WireError
= events
;
594 request
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
595 PutMsg(unit
->eu_RequestPorts
[EVENT_QUEUE
], (APTR
)request
);
603 static BOOL
CmdReadOrphan(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
605 struct EMACUnit
*unit
;
608 BOOL complete
= FALSE
;
610 /* Check request is valid */
612 unit
= (struct EMACUnit
*)request
->ios2_Req
.io_Unit
;
614 D(bug("[EMAC%d] S2CmdReadOrphan()\n", unit
->eu_UnitNum
));
616 if((unit
->eu_Flags
& IFF_UP
) == 0)
618 error
= S2ERR_OUTOFSERVICE
;
619 wire_error
= S2WERR_UNIT_OFFLINE
;
626 request
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
627 PutMsg(unit
->eu_RequestPorts
[ADOPT_QUEUE
], (struct Message
*)request
);
631 request
->ios2_Req
.io_Error
= error
;
632 request
->ios2_WireError
= wire_error
;
641 static BOOL
CmdOnline(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
643 struct EMACUnit
*unit
= (struct EMACUnit
*)request
->ios2_Req
.io_Unit
;
645 ULONG wire_error
= 0;
648 D(bug("[EMAC%d] S2CmdOnline()\n", unit
->eu_UnitNum
));
650 /* Check request is valid */
651 if((unit
->eu_Flags
& IFF_CONFIGURED
) == 0)
653 error
= S2ERR_BAD_STATE
;
654 wire_error
= S2WERR_NOT_CONFIGURED
;
657 /* Clear global and special stats and put adapter back online */
659 if((error
== 0) && ((unit
->eu_Flags
& IFF_UP
) == 0))
661 unit
->eu_Stats
.PacketsReceived
= 0;
662 unit
->eu_Stats
.PacketsSent
= 0;
663 unit
->eu_Stats
.BadData
= 0;
664 unit
->eu_Stats
.Overruns
= 0;
665 unit
->eu_Stats
.UnknownTypesReceived
= 0;
666 unit
->eu_Stats
.Reconfigurations
= 0;
668 for(i
= 0; i
< STAT_COUNT
; i
++)
669 unit
->eu_SpecialStats
[i
] = 0;
671 if (unit
->start(unit
)) {
672 error
= S2ERR_OUTOFSERVICE
;
673 wire_error
= S2WERR_GENERIC_ERROR
;
679 request
->ios2_Req
.io_Error
= error
;
680 request
->ios2_WireError
= wire_error
;
684 static BOOL
CmdOffline(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
686 struct EMACUnit
*unit
;
688 /* Put adapter offline */
690 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
692 D(bug("[EMAC%d] S2CmdOffline()\n", unit
->eu_UnitNum
));
694 if((unit
->eu_Flags
& IFF_UP
) != 0)
701 static BOOL
CmdAddMulticastAddresses(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
703 struct EMACUnit
*unit
;
704 UBYTE
*lower_bound
, *upper_bound
;
706 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
708 D(bug("[EMAC%d] S2CmdAddMulticastAddresses()\n", unit
->eu_UnitNum
));
710 lower_bound
= request
->ios2_SrcAddr
;
711 if(request
->ios2_Req
.io_Command
== S2_ADDMULTICASTADDRESS
)
712 upper_bound
= lower_bound
;
714 upper_bound
= request
->ios2_DstAddr
;
716 if(!AddMulticastRange(LIBBASE
, unit
, lower_bound
, upper_bound
))
718 request
->ios2_Req
.io_Error
= S2ERR_NO_RESOURCES
;
719 request
->ios2_WireError
= S2WERR_GENERIC_ERROR
;
728 static BOOL
CmdDelMulticastAddresses(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
730 struct EMACUnit
*unit
;
731 UBYTE
*lower_bound
, *upper_bound
;
733 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
735 D(bug("[EMAC%d] S2CmdDelMulticastAddresses()\n", unit
->eu_UnitNum
));
737 lower_bound
= request
->ios2_SrcAddr
;
738 if(request
->ios2_Req
.io_Command
== S2_DELMULTICASTADDRESS
)
739 upper_bound
= lower_bound
;
741 upper_bound
= request
->ios2_DstAddr
;
743 if(!RemMulticastRange(LIBBASE
, unit
, lower_bound
, upper_bound
))
745 request
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
746 request
->ios2_WireError
= S2WERR_BAD_MULTICAST
;