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
)
335 /* Fill in the broadcast address as destination */
337 *((ULONG
*)request
->ios2_DstAddr
) = 0xffffffff;
338 *((UWORD
*)(request
->ios2_DstAddr
+ 4)) = 0xffff;
340 /* Queue the write as normal */
342 return CmdWrite(FECBase
, request
);
345 static BOOL
CmdTrackType(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
347 struct FECUnit
*unit
;
348 struct Opener
*opener
;
349 ULONG packet_type
, wire_error
=0;
350 struct TypeTracker
*tracker
;
351 struct TypeStats
*initial_stats
;
354 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
356 D(bug("[FEC] S2CmdTrackType(%d)\n", request
->ios2_PacketType
));
358 packet_type
= request
->ios2_PacketType
;
360 /* Get global tracker */
361 tracker
= (struct TypeTracker
*)
362 FindTypeStats(FECBase
, unit
, &unit
->feu_TypeTrackers
, packet_type
);
365 tracker
->user_count
++;
369 AllocMem(sizeof(struct TypeTracker
), MEMF_PUBLIC
|MEMF_CLEAR
);
372 tracker
->packet_type
= packet_type
;
373 tracker
->user_count
= 1;
376 AddTail((APTR
)&unit
->feu_TypeTrackers
, (APTR
)tracker
);
381 /* Store initial figures for this opener */
383 opener
= request
->ios2_BufferManagement
;
384 initial_stats
= FindTypeStats(FECBase
, unit
, &opener
->initial_stats
, packet_type
);
385 if(initial_stats
!= NULL
)
387 error
= S2ERR_BAD_STATE
;
388 wire_error
= S2WERR_ALREADY_TRACKED
;
393 initial_stats
= AllocMem(sizeof(struct TypeStats
), MEMF_PUBLIC
);
394 if(initial_stats
== NULL
)
396 error
= S2ERR_NO_RESOURCES
;
397 wire_error
= S2WERR_GENERIC_ERROR
;
403 CopyMem(tracker
, initial_stats
, sizeof(struct TypeStats
));
404 AddTail((APTR
)&opener
->initial_stats
, (APTR
)initial_stats
);
409 request
->ios2_Req
.io_Error
= error
;
410 request
->ios2_WireError
= wire_error
;
414 static BOOL
CmdUntrackType(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
416 struct FECUnit
*unit
;
417 struct Opener
*opener
;
419 struct TypeTracker
*tracker
;
420 struct TypeStats
*initial_stats
;
422 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
424 D(bug("[FEC] S2CmdUntrackType()\n"));
426 packet_type
= request
->ios2_PacketType
;
428 /* Get global tracker and initial figures */
430 tracker
= (struct TypeTracker
*)
431 FindTypeStats(FECBase
, unit
, &unit
->feu_TypeTrackers
, packet_type
);
432 opener
= request
->ios2_BufferManagement
;
433 initial_stats
= FindTypeStats(FECBase
, unit
, &opener
->initial_stats
, packet_type
);
435 /* Decrement tracker usage and free unused structures */
437 if(initial_stats
!= NULL
)
439 if((--tracker
->user_count
) == 0)
442 Remove((APTR
)tracker
);
444 FreeMem(tracker
, sizeof(struct TypeTracker
));
447 Remove((APTR
)initial_stats
);
448 FreeMem(initial_stats
, sizeof(struct TypeStats
));
452 request
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
453 request
->ios2_WireError
= S2WERR_NOT_TRACKED
;
461 static BOOL
CmdGetTypeStats(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
463 struct FECUnit
*unit
;
464 struct Opener
*opener
;
466 struct TypeStats
*initial_stats
, *tracker
;
467 struct Sana2PacketTypeStats
*stats
;
469 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
471 D(bug("[FEC] S2CmdGetTypeStats()\n"));
473 packet_type
= request
->ios2_PacketType
;
475 /* Get global tracker and initial figures */
477 tracker
= FindTypeStats(FECBase
, unit
, &unit
->feu_TypeTrackers
, packet_type
);
478 opener
= request
->ios2_BufferManagement
;
479 initial_stats
= FindTypeStats(FECBase
, unit
, &opener
->initial_stats
, packet_type
);
481 /* Copy and adjust figures */
482 if(initial_stats
!= NULL
)
484 stats
= request
->ios2_StatData
;
485 CopyMem(&tracker
->stats
, stats
, sizeof(struct Sana2PacketTypeStats
));
486 stats
->PacketsSent
-= initial_stats
->stats
.PacketsSent
;
487 stats
->PacketsReceived
-= initial_stats
->stats
.PacketsReceived
;
488 stats
->BytesSent
-= initial_stats
->stats
.BytesSent
;
489 stats
->BytesReceived
-= initial_stats
->stats
.BytesReceived
;
490 stats
->PacketsDropped
-= initial_stats
->stats
.PacketsDropped
;
494 request
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
495 request
->ios2_WireError
= S2WERR_NOT_TRACKED
;
503 static BOOL
CmdGetGlobalStats(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
505 struct FECUnit
*unit
;
507 /* Update and copy stats */
509 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
511 D(bug("[FEC] S2CmdGetGlobalStats()\n"));
513 CopyMem(&unit
->feu_Stats
, request
->ios2_StatData
,
514 sizeof(struct Sana2DeviceStats
));
521 static BOOL
CmdDeviceQuery(struct FECBase
*FECBase
, struct IOStdReq
*request
)
523 struct NSDeviceQueryResult
*info
;
525 /* Set structure size twice */
527 info
= request
->io_Data
;
528 request
->io_Actual
= info
->SizeAvailable
=
529 offsetof(struct NSDeviceQueryResult
, SupportedCommands
) + sizeof(APTR
);
531 /* Report device details */
533 info
->DeviceType
= NSDEVTYPE_SANA2
;
534 info
->DeviceSubType
= 0;
536 info
->SupportedCommands
= (APTR
)supported_commands
;
543 static BOOL
CmdOnEvent(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
545 struct FECUnit
*unit
;
546 ULONG events
, wanted_events
;
547 BOOL complete
= FALSE
;
549 /* Check if we understand the event types */
551 unit
= (struct FECUnit
*)request
->ios2_Req
.io_Unit
;
553 D(bug("[FEC] S2CmdOnEvent()\n"));
555 wanted_events
= request
->ios2_WireError
;
556 if((wanted_events
& ~KNOWN_EVENTS
) != 0)
558 request
->ios2_Req
.io_Error
= S2ERR_NOT_SUPPORTED
;
559 events
= S2WERR_BAD_EVENT
;
563 if((unit
->feu_Flags
& IFF_UP
) != 0)
564 events
= S2EVENT_ONLINE
;
566 events
= S2EVENT_OFFLINE
;
568 events
&= wanted_events
;
571 /* Reply request if a wanted event has already occurred */
574 request
->ios2_WireError
= events
;
579 request
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
580 PutMsg(unit
->feu_RequestPorts
[EVENT_QUEUE
], (APTR
)request
);
588 static BOOL
CmdReadOrphan(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
590 struct FECUnit
*unit
;
593 BOOL complete
= FALSE
;
595 /* Check request is valid */
597 unit
= (struct FECUnit
*)request
->ios2_Req
.io_Unit
;
599 D(bug("[FEC] S2CmdReadOrphan()\n"));
601 if((unit
->feu_Flags
& IFF_UP
) == 0)
603 error
= S2ERR_OUTOFSERVICE
;
604 wire_error
= S2WERR_UNIT_OFFLINE
;
611 request
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
612 PutMsg(unit
->feu_RequestPorts
[ADOPT_QUEUE
], (struct Message
*)request
);
616 request
->ios2_Req
.io_Error
= error
;
617 request
->ios2_WireError
= wire_error
;
626 static BOOL
CmdOnline(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
628 struct FECUnit
*unit
= (struct FECUnit
*)request
->ios2_Req
.io_Unit
;
630 ULONG wire_error
= 0;
633 D(bug("[FEC] S2CmdOnline()\n"));
635 /* Check request is valid */
636 if((unit
->feu_Flags
& IFF_CONFIGURED
) == 0)
638 error
= S2ERR_BAD_STATE
;
639 wire_error
= S2WERR_NOT_CONFIGURED
;
642 /* Clear global and special stats and put adapter back online */
644 if((error
== 0) && ((unit
->feu_Flags
& IFF_UP
) == 0))
646 unit
->feu_Stats
.PacketsReceived
= 0;
647 unit
->feu_Stats
.PacketsSent
= 0;
648 unit
->feu_Stats
.BadData
= 0;
649 unit
->feu_Stats
.Overruns
= 0;
650 unit
->feu_Stats
.UnknownTypesReceived
= 0;
651 unit
->feu_Stats
.Reconfigurations
= 0;
653 for(i
= 0; i
< STAT_COUNT
; i
++)
654 unit
->feu_SpecialStats
[i
] = 0;
656 if (unit
->start(unit
)) {
657 error
= S2ERR_OUTOFSERVICE
;
658 wire_error
= S2WERR_GENERIC_ERROR
;
663 request
->ios2_Req
.io_Error
= error
;
664 request
->ios2_WireError
= wire_error
;
668 static BOOL
CmdOffline(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
670 struct FECUnit
*unit
;
672 /* Put adapter offline */
674 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
676 D(bug("[FEC] S2CmdOffline()\n"));
678 if((unit
->feu_Flags
& IFF_UP
) != 0)
685 static BOOL
CmdAddMulticastAddresses(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
687 struct FECUnit
*unit
;
688 UBYTE
*lower_bound
, *upper_bound
;
690 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
692 D(bug("[FEC] S2CmdAddMulticastAddresses()\n"));
694 lower_bound
= request
->ios2_SrcAddr
;
695 if(request
->ios2_Req
.io_Command
== S2_ADDMULTICASTADDRESS
)
696 upper_bound
= lower_bound
;
698 upper_bound
= request
->ios2_DstAddr
;
700 if(!AddMulticastRange(FECBase
, unit
, lower_bound
, upper_bound
))
702 request
->ios2_Req
.io_Error
= S2ERR_NO_RESOURCES
;
703 request
->ios2_WireError
= S2WERR_GENERIC_ERROR
;
711 static BOOL
CmdDelMulticastAddresses(struct FECBase
*FECBase
, struct IOSana2Req
*request
)
713 struct FECUnit
*unit
;
714 UBYTE
*lower_bound
, *upper_bound
;
716 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
718 D(bug("[FEC] S2CmdDelMulticastAddresses()\n"));
720 lower_bound
= request
->ios2_SrcAddr
;
721 if(request
->ios2_Req
.io_Command
== S2_DELMULTICASTADDRESS
)
722 upper_bound
= lower_bound
;
724 upper_bound
= request
->ios2_DstAddr
;
726 if(!RemMulticastRange(FECBase
, unit
, lower_bound
, upper_bound
))
728 request
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
729 request
->ios2_WireError
= S2WERR_BAD_MULTICAST
;