4 * Created on: May 18, 2009
9 #include <aros/debug.h>
10 #include <aros/libcall.h>
11 #include <aros/asmcall.h>
12 #include <aros/symbolsets.h>
14 #include <exec/memory.h>
15 #include <exec/errors.h>
17 #include <devices/newstyle.h>
18 #include <devices/sana2.h>
19 #include <devices/sana2specialstats.h>
21 #include <proto/openfirmware.h>
22 #include <proto/exec.h>
23 #include <proto/dos.h>
29 #define KNOWN_EVENTS \
30 (S2EVENT_ERROR | S2EVENT_TX | S2EVENT_RX | S2EVENT_ONLINE \
31 | S2EVENT_OFFLINE | S2EVENT_BUFF | S2EVENT_HARDWARE | S2EVENT_SOFTWARE)
33 static BOOL
CmdInvalid(struct FECBase
*FECBase
, struct IOSana2Req
*request
);
34 static BOOL
CmdRead(struct FECBase
*FECBase
, struct IOSana2Req
*request
);
35 static BOOL
CmdWrite(struct FECBase
*FECBase
, struct IOSana2Req
*request
);
36 static BOOL
CmdFlush(struct FECBase
*FECBase
, struct IORequest
*request
);
37 static BOOL
CmdS2DeviceQuery(struct FECBase
*FECBase
, struct IOSana2Req
*request
);
38 static BOOL
CmdGetStationAddress(struct FECBase
*FECBase
, struct IOSana2Req
*request
);
39 static BOOL
CmdConfigInterface(struct FECBase
*FECBase
, struct IOSana2Req
*request
);
40 static BOOL
CmdBroadcast(struct FECBase
*FECBase
, struct IOSana2Req
*request
);
41 static BOOL
CmdTrackType(struct FECBase
*FECBase
, struct IOSana2Req
*request
);
42 static BOOL
CmdUntrackType(struct FECBase
*FECBase
, struct IOSana2Req
*request
);
43 static BOOL
CmdGetTypeStats(struct FECBase
*FECBase
, struct IOSana2Req
*request
);
44 static BOOL
CmdGetGlobalStats(struct FECBase
*FECBase
, struct IOSana2Req
*request
);
45 static BOOL
CmdDeviceQuery(struct FECBase
*FECBase
, struct IOStdReq
*request
);
46 static BOOL
CmdOnEvent(struct FECBase
*FECBase
, struct IOSana2Req
*request
);
47 static BOOL
CmdReadOrphan(struct FECBase
*FECBase
, struct IOSana2Req
*request
);
48 static BOOL
CmdOnline(struct FECBase
*FECBase
, struct IOSana2Req
*request
);
49 static BOOL
CmdOffline(struct FECBase
*FECBase
, struct IOSana2Req
*request
);
50 static BOOL
CmdAddMulticastAddresses(struct FECBase
*FECBase
, struct IOSana2Req
*request
);
51 static BOOL
CmdDelMulticastAddresses(struct FECBase
*FECBase
, struct IOSana2Req
*request
);
53 static const uint16_t supported_commands
[] =
61 S2_ADDMULTICASTADDRESS
,
62 S2_DELMULTICASTADDRESS
,
68 // S2_GETSPECIALSTATS,
75 S2_ADDMULTICASTADDRESSES
,
76 S2_DELMULTICASTADDRESSES
,
80 void handle_request(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
82 D(bug("[FEC] handle_request\n"));
86 switch(request
->ios2_Req
.io_Command
)
89 complete
= CmdRead(FECBase
, request
);
94 complete
= CmdWrite(FECBase
, request
);
98 complete
= CmdFlush(FECBase
, (struct IORequest
*)request
);
102 complete
= CmdS2DeviceQuery(FECBase
, request
);
105 case S2_GETSTATIONADDRESS
:
106 complete
= CmdGetStationAddress(FECBase
, request
);
109 case S2_CONFIGINTERFACE
:
110 complete
= CmdConfigInterface(FECBase
, request
);
114 complete
= CmdBroadcast(FECBase
, request
);
118 complete
= CmdTrackType(FECBase
, request
);
122 complete
= CmdUntrackType(FECBase
, request
);
125 case S2_GETTYPESTATS
:
126 complete
= CmdGetTypeStats(FECBase
, request
);
129 case S2_GETGLOBALSTATS
:
130 complete
= CmdGetGlobalStats(FECBase
, request
);
134 complete
= CmdOnEvent(FECBase
, request
);
138 complete
= CmdReadOrphan(FECBase
, request
);
142 complete
= CmdOnline(FECBase
, request
);
146 complete
= CmdOffline(FECBase
, request
);
149 case S2_ADDMULTICASTADDRESS
:
150 case S2_ADDMULTICASTADDRESSES
:
151 complete
= CmdAddMulticastAddresses(FECBase
, request
);
154 case S2_DELMULTICASTADDRESS
:
155 case S2_DELMULTICASTADDRESSES
:
156 complete
= CmdDelMulticastAddresses(FECBase
, request
);
159 case NSCMD_DEVICEQUERY
:
160 complete
= CmdDeviceQuery(FECBase
, (struct IOStdReq
*)request
);
164 complete
= CmdInvalid(FECBase
, request
);
167 if(complete
&& (request
->ios2_Req
.io_Flags
& IOF_QUICK
) == 0)
168 ReplyMsg((APTR
)request
);
170 ReleaseSemaphore(&((struct FECUnit
*)request
->ios2_Req
.io_Unit
)->feu_Lock
);
174 static BOOL
CmdInvalid(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
176 request
->ios2_Req
.io_Error
= IOERR_NOCMD
;
177 request
->ios2_WireError
= S2WERR_GENERIC_ERROR
;
182 static BOOL
CmdRead(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
184 struct FECUnit
*unit
;
185 struct Opener
*opener
;
186 BOOL complete
= FALSE
;
188 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
190 D(bug("[FEC] S2CmdRead()\n"));
192 if((unit
->feu_Flags
& IFF_UP
) != 0)
194 opener
= request
->ios2_BufferManagement
;
195 request
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
196 PutMsg(&opener
->read_port
, (struct Message
*)request
);
200 request
->ios2_Req
.io_Error
= S2ERR_OUTOFSERVICE
;
201 request
->ios2_WireError
= S2WERR_UNIT_OFFLINE
;
210 static BOOL
CmdWrite(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
212 struct FECUnit
*unit
;
214 ULONG wire_error
= S2WERR_GENERIC_ERROR
;
215 BOOL complete
= FALSE
;
217 /* Check request is valid */
219 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
221 D(bug("[FEC] S2CmdWrite()\n"));
223 if((unit
->feu_Flags
& IFF_UP
) == 0)
225 error
= S2ERR_OUTOFSERVICE
;
226 wire_error
= S2WERR_UNIT_OFFLINE
;
228 else if((request
->ios2_Req
.io_Command
== S2_MULTICAST
) &&
229 ((request
->ios2_DstAddr
[0] & 0x1) == 0))
231 error
= S2ERR_BAD_ADDRESS
;
232 wire_error
= S2WERR_BAD_MULTICAST
;
235 /* Queue request for sending */
238 request
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
239 PutMsg(unit
->feu_RequestPorts
[WRITE_QUEUE
], (APTR
)request
);
243 request
->ios2_Req
.io_Error
= error
;
244 request
->ios2_WireError
= wire_error
;
252 static BOOL
CmdFlush(struct FECBase
*FECBase
, struct IORequest
*request
)
254 #warning TODO: Implement CmdFlush!!!!!!!!!
255 // FlushUnit(LIBBASE, (APTR)request->io_Unit, EVENT_QUEUE, IOERR_ABORTED);
259 static BOOL
CmdS2DeviceQuery(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
261 struct FECUnit
*unit
= (APTR
)request
->ios2_Req
.io_Unit
;
262 //struct fe_priv *np = unit->pcnu_fe_priv;
263 struct Sana2DeviceQuery
*info
;
264 ULONG size_available
, size
;
266 D(bug("[FEC] S2CmdDeviceQuery()\n"));
268 /* Copy device info */
270 info
= request
->ios2_StatData
;
271 size
= size_available
= info
->SizeAvailable
;
272 if(size
> sizeof(struct Sana2DeviceQuery
))
273 size
= sizeof(struct Sana2DeviceQuery
);
275 CopyMem(&FECBase
->feb_Sana2Info
, info
, size
);
277 info
->BPS
= unit
->feu_speed
* 1000000;
279 info
->HardwareType
= S2WireType_Ethernet
;
280 info
->SizeAvailable
= size_available
;
281 info
->SizeSupplied
= size
;
288 static BOOL
CmdGetStationAddress(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
290 struct FECUnit
*unit
;
294 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
296 D(bug("[FEC] S2CmdGetStationAddress()\n"));
298 CopyMem(unit
->feu_DevAddr
, request
->ios2_SrcAddr
, ETH_ADDRESSSIZE
);
299 CopyMem(unit
->feu_OrgAddr
, request
->ios2_DstAddr
, ETH_ADDRESSSIZE
);
306 static BOOL
CmdConfigInterface(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
308 struct FECUnit
*unit
;
310 /* Configure adapter */
312 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
314 D(bug("[FEC] S2CmdConfigInterface()\n"));
316 if((unit
->feu_Flags
& IFF_CONFIGURED
) == 0)
318 CopyMem(request
->ios2_SrcAddr
, unit
->feu_DevAddr
, ETH_ADDRESSSIZE
);
319 unit
->set_mac_address(unit
);
320 unit
->feu_Flags
|= IFF_CONFIGURED
;
324 request
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
325 request
->ios2_WireError
= S2WERR_IS_CONFIGURED
;
333 static BOOL
CmdBroadcast(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
337 /* Fill in the broadcast address as destination */
339 for(i
= 0; i
< ETH_ADDRESSSIZE
; i
++)
340 request
->ios2_DstAddr
[i
] = 0xff;
342 /* Queue the write as normal */
344 return CmdWrite(FECBase
, request
);
347 static BOOL
CmdTrackType(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
349 struct FECUnit
*unit
;
350 struct Opener
*opener
;
351 ULONG packet_type
, wire_error
=0;
352 struct TypeTracker
*tracker
;
353 struct TypeStats
*initial_stats
;
356 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
358 D(bug("[FEC] S2CmdTrackType(%d)\n", request
->ios2_PacketType
));
360 packet_type
= request
->ios2_PacketType
;
362 /* Get global tracker */
363 tracker
= (struct TypeTracker
*)
364 FindTypeStats(FECBase
, unit
, &unit
->feu_TypeTrackers
, packet_type
);
367 tracker
->user_count
++;
371 AllocMem(sizeof(struct TypeTracker
), MEMF_PUBLIC
|MEMF_CLEAR
);
374 tracker
->packet_type
= packet_type
;
375 tracker
->user_count
= 1;
378 AddTail((APTR
)&unit
->feu_TypeTrackers
, (APTR
)tracker
);
383 /* Store initial figures for this opener */
385 opener
= request
->ios2_BufferManagement
;
386 initial_stats
= FindTypeStats(FECBase
, unit
, &opener
->initial_stats
, packet_type
);
387 if(initial_stats
!= NULL
)
389 error
= S2ERR_BAD_STATE
;
390 wire_error
= S2WERR_ALREADY_TRACKED
;
395 initial_stats
= AllocMem(sizeof(struct TypeStats
), MEMF_PUBLIC
);
396 if(initial_stats
== NULL
)
398 error
= S2ERR_NO_RESOURCES
;
399 wire_error
= S2WERR_GENERIC_ERROR
;
405 CopyMem(tracker
, initial_stats
, sizeof(struct TypeStats
));
406 AddTail((APTR
)&opener
->initial_stats
, (APTR
)initial_stats
);
411 request
->ios2_Req
.io_Error
= error
;
412 request
->ios2_WireError
= wire_error
;
416 static BOOL
CmdUntrackType(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
418 struct FECUnit
*unit
;
419 struct Opener
*opener
;
421 struct TypeTracker
*tracker
;
422 struct TypeStats
*initial_stats
;
424 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
426 D(bug("[FEC] S2CmdUntrackType()\n"));
428 packet_type
= request
->ios2_PacketType
;
430 /* Get global tracker and initial figures */
432 tracker
= (struct TypeTracker
*)
433 FindTypeStats(FECBase
, unit
, &unit
->feu_TypeTrackers
, packet_type
);
434 opener
= request
->ios2_BufferManagement
;
435 initial_stats
= FindTypeStats(FECBase
, unit
, &opener
->initial_stats
, packet_type
);
437 /* Decrement tracker usage and free unused structures */
439 if(initial_stats
!= NULL
)
441 if((--tracker
->user_count
) == 0)
444 Remove((APTR
)tracker
);
446 FreeMem(tracker
, sizeof(struct TypeTracker
));
449 Remove((APTR
)initial_stats
);
450 FreeMem(initial_stats
, sizeof(struct TypeStats
));
454 request
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
455 request
->ios2_WireError
= S2WERR_NOT_TRACKED
;
463 static BOOL
CmdGetTypeStats(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
465 struct FECUnit
*unit
;
466 struct Opener
*opener
;
468 struct TypeStats
*initial_stats
, *tracker
;
469 struct Sana2PacketTypeStats
*stats
;
471 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
473 D(bug("[FEC] S2CmdGetTypeStats()\n"));
475 packet_type
= request
->ios2_PacketType
;
477 /* Get global tracker and initial figures */
479 tracker
= FindTypeStats(FECBase
, unit
, &unit
->feu_TypeTrackers
, packet_type
);
480 opener
= request
->ios2_BufferManagement
;
481 initial_stats
= FindTypeStats(FECBase
, unit
, &opener
->initial_stats
, packet_type
);
483 /* Copy and adjust figures */
484 if(initial_stats
!= NULL
)
486 stats
= request
->ios2_StatData
;
487 CopyMem(&tracker
->stats
, stats
, sizeof(struct Sana2PacketTypeStats
));
488 stats
->PacketsSent
-= initial_stats
->stats
.PacketsSent
;
489 stats
->PacketsReceived
-= initial_stats
->stats
.PacketsReceived
;
490 stats
->BytesSent
-= initial_stats
->stats
.BytesSent
;
491 stats
->BytesReceived
-= initial_stats
->stats
.BytesReceived
;
492 stats
->PacketsDropped
-= initial_stats
->stats
.PacketsDropped
;
496 request
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
497 request
->ios2_WireError
= S2WERR_NOT_TRACKED
;
505 static BOOL
CmdGetGlobalStats(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
507 struct FECUnit
*unit
;
509 /* Update and copy stats */
511 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
513 D(bug("[FEC] S2CmdGetGlobalStats()\n"));
515 CopyMem(&unit
->feu_Stats
, request
->ios2_StatData
,
516 sizeof(struct Sana2DeviceStats
));
523 static BOOL
CmdDeviceQuery(struct FECBase
*FECBase
, struct IOStdReq
*request
)
525 struct NSDeviceQueryResult
*info
;
527 /* Set structure size twice */
529 info
= request
->io_Data
;
530 request
->io_Actual
= info
->SizeAvailable
=
531 offsetof(struct NSDeviceQueryResult
, SupportedCommands
) + sizeof(APTR
);
533 /* Report device details */
535 info
->DeviceType
= NSDEVTYPE_SANA2
;
536 info
->DeviceSubType
= 0;
538 info
->SupportedCommands
= (APTR
)supported_commands
;
545 static BOOL
CmdOnEvent(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
547 struct FECUnit
*unit
;
548 ULONG events
, wanted_events
;
549 BOOL complete
= FALSE
;
551 /* Check if we understand the event types */
553 unit
= (struct FECUnit
*)request
->ios2_Req
.io_Unit
;
555 D(bug("[FEC] S2CmdOnEvent()\n"));
557 wanted_events
= request
->ios2_WireError
;
558 if((wanted_events
& ~KNOWN_EVENTS
) != 0)
560 request
->ios2_Req
.io_Error
= S2ERR_NOT_SUPPORTED
;
561 events
= S2WERR_BAD_EVENT
;
565 if((unit
->feu_Flags
& IFF_UP
) != 0)
566 events
= S2EVENT_ONLINE
;
568 events
= S2EVENT_OFFLINE
;
570 events
&= wanted_events
;
573 /* Reply request if a wanted event has already occurred */
576 request
->ios2_WireError
= events
;
581 request
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
582 PutMsg(unit
->feu_RequestPorts
[EVENT_QUEUE
], (APTR
)request
);
590 static BOOL
CmdReadOrphan(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
592 struct FECUnit
*unit
;
595 BOOL complete
= FALSE
;
597 /* Check request is valid */
599 unit
= (struct FECUnit
*)request
->ios2_Req
.io_Unit
;
601 D(bug("[FEC] S2CmdReadOrphan()\n"));
603 if((unit
->feu_Flags
& IFF_UP
) == 0)
605 error
= S2ERR_OUTOFSERVICE
;
606 wire_error
= S2WERR_UNIT_OFFLINE
;
613 request
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
614 PutMsg(unit
->feu_RequestPorts
[ADOPT_QUEUE
], (struct Message
*)request
);
618 request
->ios2_Req
.io_Error
= error
;
619 request
->ios2_WireError
= wire_error
;
628 static BOOL
CmdOnline(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
630 struct FECUnit
*unit
= (struct FECUnit
*)request
->ios2_Req
.io_Unit
;
632 ULONG wire_error
= 0;
635 D(bug("[FEC] S2CmdOnline()\n"));
637 /* Check request is valid */
638 if((unit
->feu_Flags
& IFF_CONFIGURED
) == 0)
640 error
= S2ERR_BAD_STATE
;
641 wire_error
= S2WERR_NOT_CONFIGURED
;
644 /* Clear global and special stats and put adapter back online */
646 if((error
== 0) && ((unit
->feu_Flags
& IFF_UP
) == 0))
648 unit
->feu_Stats
.PacketsReceived
= 0;
649 unit
->feu_Stats
.PacketsSent
= 0;
650 unit
->feu_Stats
.BadData
= 0;
651 unit
->feu_Stats
.Overruns
= 0;
652 unit
->feu_Stats
.UnknownTypesReceived
= 0;
653 unit
->feu_Stats
.Reconfigurations
= 0;
655 for(i
= 0; i
< STAT_COUNT
; i
++)
656 unit
->feu_SpecialStats
[i
] = 0;
658 if (unit
->start(unit
)) {
659 error
= S2ERR_OUTOFSERVICE
;
660 wire_error
= S2WERR_GENERIC_ERROR
;
665 request
->ios2_Req
.io_Error
= error
;
666 request
->ios2_WireError
= wire_error
;
670 static BOOL
CmdOffline(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
672 struct FECUnit
*unit
;
674 /* Put adapter offline */
676 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
678 D(bug("[FEC] S2CmdOffline()\n"));
680 if((unit
->feu_Flags
& IFF_UP
) != 0)
687 static BOOL
CmdAddMulticastAddresses(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
689 struct FECUnit
*unit
;
690 UBYTE
*lower_bound
, *upper_bound
;
692 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
694 D(bug("[FEC] S2CmdAddMulticastAddresses()\n"));
696 lower_bound
= request
->ios2_SrcAddr
;
697 if(request
->ios2_Req
.io_Command
== S2_ADDMULTICASTADDRESS
)
698 upper_bound
= lower_bound
;
700 upper_bound
= request
->ios2_DstAddr
;
702 if(!AddMulticastRange(FECBase
, unit
, lower_bound
, upper_bound
))
704 request
->ios2_Req
.io_Error
= S2ERR_NO_RESOURCES
;
705 request
->ios2_WireError
= S2WERR_GENERIC_ERROR
;
713 static BOOL
CmdDelMulticastAddresses(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
715 struct FECUnit
*unit
;
716 UBYTE
*lower_bound
, *upper_bound
;
718 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
720 D(bug("[FEC] S2CmdDelMulticastAddresses()\n"));
722 lower_bound
= request
->ios2_SrcAddr
;
723 if(request
->ios2_Req
.io_Command
== S2_DELMULTICASTADDRESS
)
724 upper_bound
= lower_bound
;
726 upper_bound
= request
->ios2_DstAddr
;
728 if(!RemMulticastRange(FECBase
, unit
, lower_bound
, upper_bound
))
730 request
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
731 request
->ios2_WireError
= S2WERR_BAD_MULTICAST
;