6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston,
22 #include <exec/types.h>
23 #include <exec/resident.h>
25 #include <exec/ports.h>
26 #include <exec/errors.h>
28 #include <devices/sana2.h>
29 #include <devices/sana2specialstats.h>
30 #include <devices/newstyle.h>
32 #include <utility/utility.h>
33 #include <utility/tagitem.h>
34 #include <utility/hooks.h>
36 #include <proto/exec.h>
37 #include <proto/dos.h>
38 #include <proto/battclock.h>
42 #include "via-rhine.h"
44 #include LC_LIBDEFS_FILE
46 #define KNOWN_EVENTS \
47 (S2EVENT_ERROR | S2EVENT_TX | S2EVENT_RX | S2EVENT_ONLINE \
48 | S2EVENT_OFFLINE | S2EVENT_BUFF | S2EVENT_HARDWARE | S2EVENT_SOFTWARE)
50 static BOOL
CmdInvalid(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
51 static BOOL
CmdRead(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
52 static BOOL
CmdWrite(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
53 static BOOL
CmdFlush(LIBBASETYPEPTR LIBBASE
, struct IORequest
*request
);
54 static BOOL
CmdS2DeviceQuery(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
55 static BOOL
CmdGetStationAddress(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
56 static BOOL
CmdConfigInterface(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
57 static BOOL
CmdBroadcast(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
58 static BOOL
CmdTrackType(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
59 static BOOL
CmdUntrackType(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
60 static BOOL
CmdGetTypeStats(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
61 static BOOL
CmdGetGlobalStats(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
62 static BOOL
CmdDeviceQuery(LIBBASETYPEPTR LIBBASE
, struct IOStdReq
*request
);
63 static BOOL
CmdOnEvent(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
64 static BOOL
CmdReadOrphan(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
65 static BOOL
CmdOnline(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
66 static BOOL
CmdOffline(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
67 static BOOL
CmdAddMulticastAddresses(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
68 static BOOL
CmdDelMulticastAddresses(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
70 static const UWORD supported_commands
[] =
78 S2_ADDMULTICASTADDRESS
,
79 S2_DELMULTICASTADDRESS
,
85 // S2_GETSPECIALSTATS,
92 S2_ADDMULTICASTADDRESSES
,
93 S2_DELMULTICASTADDRESSES
,
97 void handle_request(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
101 switch(request
->ios2_Req
.io_Command
)
104 complete
= CmdRead(LIBBASE
, request
);
109 complete
= CmdWrite(LIBBASE
, request
);
113 complete
= CmdFlush(LIBBASE
, (struct IORequest
*)request
);
117 complete
= CmdS2DeviceQuery(LIBBASE
, request
);
120 case S2_GETSTATIONADDRESS
:
121 complete
= CmdGetStationAddress(LIBBASE
, request
);
124 case S2_CONFIGINTERFACE
:
125 complete
= CmdConfigInterface(LIBBASE
, request
);
129 complete
= CmdBroadcast(LIBBASE
, request
);
133 complete
= CmdTrackType(LIBBASE
, request
);
137 complete
= CmdUntrackType(LIBBASE
, request
);
140 case S2_GETTYPESTATS
:
141 complete
= CmdGetTypeStats(LIBBASE
, request
);
144 case S2_GETGLOBALSTATS
:
145 complete
= CmdGetGlobalStats(LIBBASE
, request
);
149 complete
= CmdOnEvent(LIBBASE
, request
);
153 complete
= CmdReadOrphan(LIBBASE
, request
);
157 complete
= CmdOnline(LIBBASE
, request
);
161 complete
= CmdOffline(LIBBASE
, request
);
164 case S2_ADDMULTICASTADDRESS
:
165 case S2_ADDMULTICASTADDRESSES
:
166 complete
= CmdAddMulticastAddresses(LIBBASE
, request
);
169 case S2_DELMULTICASTADDRESS
:
170 case S2_DELMULTICASTADDRESSES
:
171 complete
= CmdDelMulticastAddresses(LIBBASE
, request
);
174 case NSCMD_DEVICEQUERY
:
175 complete
= CmdDeviceQuery(LIBBASE
, (struct IOStdReq
*)request
);
179 complete
= CmdInvalid(LIBBASE
, request
);
182 if(complete
&& (request
->ios2_Req
.io_Flags
& IOF_QUICK
) == 0)
183 ReplyMsg((APTR
)request
);
185 ReleaseSemaphore(&((struct VIARHINEUnit
*)request
->ios2_Req
.io_Unit
)->rhineu_unit_lock
);
188 static BOOL
CmdInvalid(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
190 request
->ios2_Req
.io_Error
= IOERR_NOCMD
;
191 request
->ios2_WireError
= S2WERR_GENERIC_ERROR
;
196 static BOOL
CmdRead(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
198 struct VIARHINEUnit
*unit
;
199 struct Opener
*opener
;
200 BOOL complete
= FALSE
;
202 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
204 D(bug("%s: S2CmdRead()\n", unit
->rhineu_name
));
206 if((unit
->rhineu_flags
& IFF_UP
) != 0)
208 opener
= request
->ios2_BufferManagement
;
209 request
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
210 PutMsg(&opener
->read_port
, (struct Message
*)request
);
214 request
->ios2_Req
.io_Error
= S2ERR_OUTOFSERVICE
;
215 request
->ios2_WireError
= S2WERR_UNIT_OFFLINE
;
224 static BOOL
CmdWrite(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
226 struct VIARHINEUnit
*unit
;
228 ULONG wire_error
= S2WERR_GENERIC_ERROR
;
229 BOOL complete
= FALSE
;
231 /* Check request is valid */
233 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
235 D(bug("%s: S2CmdWrite()\n", unit
->rhineu_name
));
237 if((unit
->rhineu_flags
& IFF_UP
) == 0)
239 error
= S2ERR_OUTOFSERVICE
;
240 wire_error
= S2WERR_UNIT_OFFLINE
;
242 else if((request
->ios2_Req
.io_Command
== S2_MULTICAST
) &&
243 ((request
->ios2_DstAddr
[0] & 0x1) == 0))
245 error
= S2ERR_BAD_ADDRESS
;
246 wire_error
= S2WERR_BAD_MULTICAST
;
249 /* Queue request for sending */
252 request
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
253 PutMsg(unit
->rhineu_request_ports
[WRITE_QUEUE
], (APTR
)request
);
257 request
->ios2_Req
.io_Error
= error
;
258 request
->ios2_WireError
= wire_error
;
267 static BOOL
CmdFlush(LIBBASETYPEPTR LIBBASE
, struct IORequest
*request
)
269 FlushUnit(LIBBASE
, (APTR
)request
->io_Unit
, EVENT_QUEUE
, IOERR_ABORTED
);
273 static BOOL
CmdS2DeviceQuery(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
275 D(struct VIARHINEUnit
*unit
= (APTR
)request
->ios2_Req
.io_Unit
);
276 // struct fe_priv *np = unit->rhineu_fe_priv;
277 struct Sana2DeviceQuery
*info
;
278 ULONG size_available
, size
;
280 D(bug("%s: S2CmdDeviceQuery()\n", unit
->rhineu_name
));
282 /* Copy device info */
284 info
= request
->ios2_StatData
;
285 size
= size_available
= info
->SizeAvailable
;
286 if(size
> sizeof(struct Sana2DeviceQuery
))
287 size
= sizeof(struct Sana2DeviceQuery
);
289 CopyMem(&LIBBASE
->rhineb_Sana2Info
, info
, size
);
291 info
->BPS
= 100000000;
293 info
->HardwareType
= S2WireType_Ethernet
;
294 info
->SizeAvailable
= size_available
;
295 info
->SizeSupplied
= size
;
302 static BOOL
CmdGetStationAddress(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
304 struct VIARHINEUnit
*unit
;
308 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
310 D(bug("%s: S2CmdGetStationAddress()\n", unit
->rhineu_name
));
312 CopyMem(unit
->rhineu_dev_addr
, request
->ios2_SrcAddr
, ETH_ADDRESSSIZE
);
313 CopyMem(unit
->rhineu_org_addr
, request
->ios2_DstAddr
, ETH_ADDRESSSIZE
);
320 static BOOL
CmdConfigInterface(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
322 struct VIARHINEUnit
*unit
;
324 /* Configure adapter */
326 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
328 D(bug("%s: S2CmdConfigInterface()\n", unit
->rhineu_name
));
330 if((unit
->rhineu_flags
& IFF_CONFIGURED
) == 0)
332 CopyMem(request
->ios2_SrcAddr
, unit
->rhineu_dev_addr
, ETH_ADDRESSSIZE
);
333 unit
->set_mac_address(unit
);
334 unit
->rhineu_flags
|= IFF_CONFIGURED
;
338 request
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
339 request
->ios2_WireError
= S2WERR_IS_CONFIGURED
;
347 static BOOL
CmdBroadcast(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
351 /* Fill in the broadcast address as destination */
353 for(i
= 0; i
< ETH_ADDRESSSIZE
; i
++)
354 request
->ios2_DstAddr
[i
] = 0xff;
356 /* Queue the write as normal */
358 return CmdWrite(LIBBASE
, request
);
361 static BOOL
CmdTrackType(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
363 struct VIARHINEUnit
*unit
;
364 struct Opener
*opener
;
365 ULONG packet_type
, wire_error
=0;
366 struct TypeTracker
*tracker
;
367 struct TypeStats
*initial_stats
;
370 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
372 D(bug("%s: S2CmdTrackType()\n", unit
->rhineu_name
));
374 packet_type
= request
->ios2_PacketType
;
376 /* Get global tracker */
378 tracker
= (struct TypeTracker
*)
379 FindTypeStats(LIBBASE
, unit
, &unit
->rhineu_type_trackers
, packet_type
);
382 tracker
->user_count
++;
386 AllocMem(sizeof(struct TypeTracker
), MEMF_PUBLIC
|MEMF_CLEAR
);
389 tracker
->packet_type
= packet_type
;
390 tracker
->user_count
= 1;
393 AddTail((APTR
)&unit
->rhineu_type_trackers
, (APTR
)tracker
);
398 /* Store initial figures for this opener */
400 opener
= request
->ios2_BufferManagement
;
401 initial_stats
= FindTypeStats(LIBBASE
, unit
, &opener
->initial_stats
, packet_type
);
403 if(initial_stats
!= NULL
)
405 error
= S2ERR_BAD_STATE
;
406 wire_error
= S2WERR_ALREADY_TRACKED
;
411 initial_stats
= AllocMem(sizeof(struct TypeStats
), MEMF_PUBLIC
);
412 if(initial_stats
== NULL
)
414 error
= S2ERR_NO_RESOURCES
;
415 wire_error
= S2WERR_GENERIC_ERROR
;
421 CopyMem(tracker
, initial_stats
, sizeof(struct TypeStats
));
422 AddTail((APTR
)&opener
->initial_stats
, (APTR
)initial_stats
);
427 request
->ios2_Req
.io_Error
= error
;
428 request
->ios2_WireError
= wire_error
;
432 static BOOL
CmdUntrackType(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
434 struct VIARHINEUnit
*unit
;
435 struct Opener
*opener
;
437 struct TypeTracker
*tracker
;
438 struct TypeStats
*initial_stats
;
440 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
442 D(bug("%s: S2CmdUntrackType()\n", unit
->rhineu_name
));
444 packet_type
= request
->ios2_PacketType
;
446 /* Get global tracker and initial figures */
448 tracker
= (struct TypeTracker
*)
449 FindTypeStats(LIBBASE
, unit
, &unit
->rhineu_type_trackers
, packet_type
);
450 opener
= request
->ios2_BufferManagement
;
451 initial_stats
= FindTypeStats(LIBBASE
, unit
, &opener
->initial_stats
, packet_type
);
453 /* Decrement tracker usage and free unused structures */
455 if(initial_stats
!= NULL
)
457 if((--tracker
->user_count
) == 0)
460 Remove((APTR
)tracker
);
462 FreeMem(tracker
, sizeof(struct TypeTracker
));
465 Remove((APTR
)initial_stats
);
466 FreeMem(initial_stats
, sizeof(struct TypeStats
));
470 request
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
471 request
->ios2_WireError
= S2WERR_NOT_TRACKED
;
479 static BOOL
CmdGetTypeStats(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
481 struct VIARHINEUnit
*unit
;
482 struct Opener
*opener
;
484 struct TypeStats
*initial_stats
, *tracker
;
485 struct Sana2PacketTypeStats
*stats
;
487 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
489 D(bug("%s: S2CmdGetTypeStats()\n", unit
->rhineu_name
));
491 packet_type
= request
->ios2_PacketType
;
493 /* Get global tracker and initial figures */
495 tracker
= FindTypeStats(LIBBASE
, unit
, &unit
->rhineu_type_trackers
, packet_type
);
496 opener
= request
->ios2_BufferManagement
;
497 initial_stats
= FindTypeStats(LIBBASE
, unit
, &opener
->initial_stats
, packet_type
);
499 /* Copy and adjust figures */
500 if(initial_stats
!= NULL
)
502 stats
= request
->ios2_StatData
;
503 CopyMem(&tracker
->stats
, stats
, sizeof(struct Sana2PacketTypeStats
));
504 stats
->PacketsSent
-= initial_stats
->stats
.PacketsSent
;
505 stats
->PacketsReceived
-= initial_stats
->stats
.PacketsReceived
;
506 stats
->BytesSent
-= initial_stats
->stats
.BytesSent
;
507 stats
->BytesReceived
-= initial_stats
->stats
.BytesReceived
;
508 stats
->PacketsDropped
-= initial_stats
->stats
.PacketsDropped
;
512 request
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
513 request
->ios2_WireError
= S2WERR_NOT_TRACKED
;
521 static BOOL
CmdGetGlobalStats(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
523 struct VIARHINEUnit
*unit
;
525 /* Update and copy stats */
527 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
529 D(bug("%s: S2CmdGetGlobalStats()\n", unit
->rhineu_name
));
531 CopyMem(&unit
->rhineu_stats
, request
->ios2_StatData
,
532 sizeof(struct Sana2DeviceStats
));
539 static BOOL
CmdDeviceQuery(LIBBASETYPEPTR LIBBASE
, struct IOStdReq
*request
)
541 struct NSDeviceQueryResult
*info
;
543 /* Set structure size twice */
545 info
= request
->io_Data
;
546 request
->io_Actual
= info
->SizeAvailable
=
547 offsetof(struct NSDeviceQueryResult
, SupportedCommands
) + sizeof(APTR
);
549 /* Report device details */
551 info
->DeviceType
= NSDEVTYPE_SANA2
;
552 info
->DeviceSubType
= 0;
554 info
->SupportedCommands
= (APTR
)supported_commands
;
561 static BOOL
CmdOnEvent(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
563 struct VIARHINEUnit
*unit
;
564 ULONG events
, wanted_events
;
565 BOOL complete
= FALSE
;
567 /* Check if we understand the event types */
569 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
571 D(bug("%s: S2CmdOnEvent()\n", unit
->rhineu_name
));
573 wanted_events
= request
->ios2_WireError
;
574 if((wanted_events
& ~KNOWN_EVENTS
) != 0)
576 request
->ios2_Req
.io_Error
= S2ERR_NOT_SUPPORTED
;
577 events
= S2WERR_BAD_EVENT
;
581 if((unit
->rhineu_flags
& IFF_UP
) != 0)
582 events
= S2EVENT_ONLINE
;
584 events
= S2EVENT_OFFLINE
;
586 events
&= wanted_events
;
589 /* Reply request if a wanted event has already occurred */
593 request
->ios2_WireError
= events
;
598 request
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
599 PutMsg(unit
->rhineu_request_ports
[EVENT_QUEUE
], (APTR
)request
);
607 static BOOL
CmdReadOrphan(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
609 struct VIARHINEUnit
*unit
;
612 BOOL complete
= FALSE
;
614 /* Check request is valid */
616 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
617 D(bug("%s: S2CmdReadOrphan()\n", unit
->rhineu_name
));
619 if((unit
->rhineu_flags
& IFF_UP
) == 0)
621 error
= S2ERR_OUTOFSERVICE
;
622 wire_error
= S2WERR_UNIT_OFFLINE
;
629 request
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
630 PutMsg(unit
->rhineu_request_ports
[ADOPT_QUEUE
], (struct Message
*)request
);
634 request
->ios2_Req
.io_Error
= error
;
635 request
->ios2_WireError
= wire_error
;
644 static BOOL
CmdOnline(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
646 struct VIARHINEUnit
*unit
= (struct VIARHINEUnit
*)request
->ios2_Req
.io_Unit
;
648 ULONG wire_error
= 0;
651 D(bug("%s: S2CmdOnline()\n", unit
->rhineu_name
));
653 /* Check request is valid */
654 if((unit
->rhineu_flags
& IFF_CONFIGURED
) == 0)
656 error
= S2ERR_BAD_STATE
;
657 wire_error
= S2WERR_NOT_CONFIGURED
;
660 /* Clear global and special stats and put adapter back online */
662 if((error
== 0) && ((unit
->rhineu_flags
& IFF_UP
) == 0))
664 unit
->rhineu_stats
.PacketsReceived
= 0;
665 unit
->rhineu_stats
.PacketsSent
= 0;
666 unit
->rhineu_stats
.BadData
= 0;
667 unit
->rhineu_stats
.Overruns
= 0;
668 unit
->rhineu_stats
.UnknownTypesReceived
= 0;
669 unit
->rhineu_stats
.Reconfigurations
= 0;
671 for(i
= 0; i
< STAT_COUNT
; i
++)
672 unit
->rhineu_special_stats
[i
] = 0;
674 if (unit
->start(unit
))
676 error
= S2ERR_OUTOFSERVICE
;
677 wire_error
= S2WERR_GENERIC_ERROR
;
683 request
->ios2_Req
.io_Error
= error
;
684 request
->ios2_WireError
= wire_error
;
688 static BOOL
CmdOffline(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
690 struct VIARHINEUnit
*unit
;
692 /* Put adapter offline */
694 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
696 D(bug("%s: S2CmdOffline()\n", unit
->rhineu_name
));
698 if((unit
->rhineu_flags
& IFF_UP
) != 0)
705 static BOOL
CmdAddMulticastAddresses(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
707 struct VIARHINEUnit
*unit
;
708 UBYTE
*lower_bound
, *upper_bound
;
710 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
712 D(bug("%s: S2CmdAddMulticastAddresses()\n", unit
->rhineu_name
));
714 lower_bound
= request
->ios2_SrcAddr
;
715 if(request
->ios2_Req
.io_Command
== S2_ADDMULTICASTADDRESS
)
716 upper_bound
= lower_bound
;
718 upper_bound
= request
->ios2_DstAddr
;
720 if(!AddMulticastRange(LIBBASE
, unit
, lower_bound
, upper_bound
))
722 request
->ios2_Req
.io_Error
= S2ERR_NO_RESOURCES
;
723 request
->ios2_WireError
= S2WERR_GENERIC_ERROR
;
731 static BOOL
CmdDelMulticastAddresses(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
733 struct VIARHINEUnit
*unit
;
734 UBYTE
*lower_bound
, *upper_bound
;
736 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
738 D(bug("%s: S2CmdDelMulticastAddresses()\n", unit
->rhineu_name
));
740 lower_bound
= request
->ios2_SrcAddr
;
741 if(request
->ios2_Req
.io_Command
== S2_DELMULTICASTADDRESS
)
742 upper_bound
= lower_bound
;
744 upper_bound
= request
->ios2_DstAddr
;
746 if(!RemMulticastRange(LIBBASE
, unit
, lower_bound
, upper_bound
))
748 request
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
749 request
->ios2_WireError
= S2WERR_BAD_MULTICAST
;