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,
24 #include <exec/types.h>
25 #include <exec/resident.h>
27 #include <exec/ports.h>
28 #include <exec/errors.h>
30 #include <devices/sana2.h>
31 #include <devices/sana2specialstats.h>
32 #include <devices/newstyle.h>
34 #include <utility/utility.h>
35 #include <utility/tagitem.h>
36 #include <utility/hooks.h>
38 #include <proto/exec.h>
39 #include <proto/dos.h>
40 #include <proto/battclock.h>
46 #include LC_LIBDEFS_FILE
48 #define KNOWN_EVENTS \
49 (S2EVENT_ERROR | S2EVENT_TX | S2EVENT_RX | S2EVENT_ONLINE \
50 | S2EVENT_OFFLINE | S2EVENT_BUFF | S2EVENT_HARDWARE | S2EVENT_SOFTWARE)
52 static BOOL
CmdInvalid(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
53 static BOOL
CmdRead(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
54 static BOOL
CmdWrite(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
55 static BOOL
CmdFlush(LIBBASETYPEPTR LIBBASE
, struct IORequest
*request
);
56 static BOOL
CmdS2DeviceQuery(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
57 static BOOL
CmdGetStationAddress(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
58 static BOOL
CmdConfigInterface(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
59 static BOOL
CmdBroadcast(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
60 static BOOL
CmdTrackType(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
61 static BOOL
CmdUntrackType(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
62 static BOOL
CmdGetTypeStats(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
63 static BOOL
CmdGetGlobalStats(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
64 static BOOL
CmdDeviceQuery(LIBBASETYPEPTR LIBBASE
, struct IOStdReq
*request
);
65 static BOOL
CmdOnEvent(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
66 static BOOL
CmdReadOrphan(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
67 static BOOL
CmdOnline(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
68 static BOOL
CmdOffline(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
69 static BOOL
CmdAddMulticastAddresses(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
70 static BOOL
CmdDelMulticastAddresses(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
72 static const UWORD supported_commands
[] =
80 S2_ADDMULTICASTADDRESS
,
81 S2_DELMULTICASTADDRESS
,
87 // S2_GETSPECIALSTATS,
94 S2_ADDMULTICASTADDRESSES
,
95 S2_DELMULTICASTADDRESSES
,
99 void handle_request(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
103 switch(request
->ios2_Req
.io_Command
)
106 complete
= CmdRead(LIBBASE
, request
);
111 complete
= CmdWrite(LIBBASE
, request
);
115 complete
= CmdFlush(LIBBASE
, (struct IORequest
*)request
);
119 complete
= CmdS2DeviceQuery(LIBBASE
, request
);
122 case S2_GETSTATIONADDRESS
:
123 complete
= CmdGetStationAddress(LIBBASE
, request
);
126 case S2_CONFIGINTERFACE
:
127 complete
= CmdConfigInterface(LIBBASE
, request
);
131 complete
= CmdBroadcast(LIBBASE
, request
);
135 complete
= CmdTrackType(LIBBASE
, request
);
139 complete
= CmdUntrackType(LIBBASE
, request
);
142 case S2_GETTYPESTATS
:
143 complete
= CmdGetTypeStats(LIBBASE
, request
);
146 case S2_GETGLOBALSTATS
:
147 complete
= CmdGetGlobalStats(LIBBASE
, request
);
151 complete
= CmdOnEvent(LIBBASE
, request
);
155 complete
= CmdReadOrphan(LIBBASE
, request
);
159 complete
= CmdOnline(LIBBASE
, request
);
163 complete
= CmdOffline(LIBBASE
, request
);
166 case S2_ADDMULTICASTADDRESS
:
167 case S2_ADDMULTICASTADDRESSES
:
168 complete
= CmdAddMulticastAddresses(LIBBASE
, request
);
171 case S2_DELMULTICASTADDRESS
:
172 case S2_DELMULTICASTADDRESSES
:
173 complete
= CmdDelMulticastAddresses(LIBBASE
, request
);
176 case NSCMD_DEVICEQUERY
:
177 complete
= CmdDeviceQuery(LIBBASE
, (struct IOStdReq
*)request
);
181 complete
= CmdInvalid(LIBBASE
, request
);
184 if(complete
&& (request
->ios2_Req
.io_Flags
& IOF_QUICK
) == 0)
186 ReplyMsg((APTR
)request
);
188 ReleaseSemaphore(&((struct RTL8169Unit
*)request
->ios2_Req
.io_Unit
)->rtl8169u_unit_lock
);
191 static BOOL
CmdInvalid(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
193 request
->ios2_Req
.io_Error
= IOERR_NOCMD
;
194 request
->ios2_WireError
= S2WERR_GENERIC_ERROR
;
199 static BOOL
CmdRead(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
201 struct RTL8169Unit
*unit
;
202 struct Opener
*opener
;
204 // ULONG wire_error = S2WERR_GENERIC_ERROR;
205 BOOL complete
= FALSE
;
207 unit
= (APTR
) request
->ios2_Req
.io_Unit
;
209 RTLD(bug("[%s] S2CmdRead()\n", unit
->rtl8169u_name
))
211 if((unit
->rtl8169u_flags
& IFF_UP
) != 0)
213 opener
= request
->ios2_BufferManagement
;
214 request
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
215 PutMsg(&opener
->read_port
, (struct Message
*) request
);
219 request
->ios2_Req
.io_Error
= S2ERR_OUTOFSERVICE
;
220 request
->ios2_WireError
= S2WERR_UNIT_OFFLINE
;
229 static BOOL
CmdWrite(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
231 struct RTL8169Unit
*unit
;
233 ULONG wire_error
= S2WERR_GENERIC_ERROR
;
234 BOOL complete
= FALSE
;
236 /* Check request is valid */
238 unit
= (APTR
) request
->ios2_Req
.io_Unit
;
240 RTLD(bug("[%s] S2CmdWrite()\n", unit
->rtl8169u_name
))
242 if((unit
->rtl8169u_flags
& IFF_UP
) == 0)
244 error
= S2ERR_OUTOFSERVICE
;
245 wire_error
= S2WERR_UNIT_OFFLINE
;
247 else if((request
->ios2_Req
.io_Command
== S2_MULTICAST
) &&
248 ((request
->ios2_DstAddr
[0] & 0x1) == 0))
250 error
= S2ERR_BAD_ADDRESS
;
251 wire_error
= S2WERR_BAD_MULTICAST
;
254 /* Queue request for sending */
258 request
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
259 PutMsg(unit
->rtl8169u_request_ports
[WRITE_QUEUE
], (APTR
)request
);
263 request
->ios2_Req
.io_Error
= error
;
264 request
->ios2_WireError
= wire_error
;
273 static BOOL
CmdFlush(LIBBASETYPEPTR LIBBASE
, struct IORequest
*request
)
275 FlushUnit(LIBBASE
, (APTR
)request
->io_Unit
, EVENT_QUEUE
, IOERR_ABORTED
);
279 static BOOL
CmdS2DeviceQuery(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
281 struct RTL8169Unit
*unit
= (APTR
)request
->ios2_Req
.io_Unit
;
282 // struct rtl8169_priv *np = unit->rtl8169u_priv;
283 struct Sana2DeviceQuery
*info
;
284 ULONG size_available
, size
;
286 RTLD(bug("[%s] S2CmdDeviceQuery()\n", unit
->rtl8169u_name
))
288 /* Copy device info */
290 info
= request
->ios2_StatData
;
291 size
= size_available
= info
->SizeAvailable
;
292 if(size
> sizeof(struct Sana2DeviceQuery
))
293 size
= sizeof(struct Sana2DeviceQuery
);
295 CopyMem(&unit
->rtl8169u_Sana2Info
, info
, size
);
297 info
->BPS
= unit
->rtl8169u_rtl_LinkSpeed
;
299 info
->HardwareType
= S2WireType_Ethernet
;
300 info
->SizeAvailable
= size_available
;
301 info
->SizeSupplied
= size
;
308 static BOOL
CmdGetStationAddress(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
310 struct RTL8169Unit
*unit
;
314 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
316 RTLD(bug("[%s] S2CmdGetStationAddress()\n", unit
->rtl8169u_name
))
318 CopyMem(unit
->rtl8169u_dev_addr
, request
->ios2_SrcAddr
, ETH_ADDRESSSIZE
);
319 CopyMem(unit
->rtl8169u_org_addr
, request
->ios2_DstAddr
, ETH_ADDRESSSIZE
);
326 static BOOL
CmdConfigInterface(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
328 struct RTL8169Unit
*unit
;
330 /* Configure adapter */
332 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
334 RTLD(bug("[%s] S2CmdConfigInterface()\n", unit
->rtl8169u_name
))
336 if((unit
->rtl8169u_flags
& IFF_CONFIGURED
) == 0)
338 CopyMem(request
->ios2_SrcAddr
, unit
->rtl8169u_dev_addr
, ETH_ADDRESSSIZE
);
339 unit
->set_mac_address(unit
);
340 unit
->rtl8169u_flags
|= IFF_CONFIGURED
;
344 request
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
345 request
->ios2_WireError
= S2WERR_IS_CONFIGURED
;
353 static BOOL
CmdBroadcast(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
355 /* Fill in the broadcast address as destination */
357 memset(request
->ios2_DstAddr
, 0xff, 6);
359 /* Queue the write as normal */
361 return CmdWrite(LIBBASE
, request
);
364 static BOOL
CmdTrackType(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
366 struct RTL8169Unit
*unit
;
367 struct Opener
*opener
;
368 ULONG packet_type
, wire_error
=0;
369 struct TypeTracker
*tracker
;
370 struct TypeStats
*initial_stats
;
373 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
375 RTLD(bug("[%s] S2CmdTrackType()\n", unit
->rtl8169u_name
))
377 packet_type
= request
->ios2_PacketType
;
379 /* Get global tracker */
381 tracker
= (struct TypeTracker
*)
382 FindTypeStats(LIBBASE
, unit
, &unit
->rtl8169u_type_trackers
, packet_type
);
386 tracker
->user_count
++;
390 tracker
= AllocMem(sizeof(struct TypeTracker
), MEMF_PUBLIC
| MEMF_CLEAR
);
393 tracker
->packet_type
= packet_type
;
394 tracker
->user_count
= 1;
397 AddTail((APTR
)&unit
->rtl8169u_type_trackers
, (APTR
)tracker
);
402 /* Store initial figures for this opener */
404 opener
= request
->ios2_BufferManagement
;
405 initial_stats
= FindTypeStats(LIBBASE
, unit
, &opener
->initial_stats
, packet_type
);
407 if(initial_stats
!= NULL
)
409 error
= S2ERR_BAD_STATE
;
410 wire_error
= S2WERR_ALREADY_TRACKED
;
415 initial_stats
= AllocMem(sizeof(struct TypeStats
), MEMF_PUBLIC
);
416 if(initial_stats
== NULL
)
418 error
= S2ERR_NO_RESOURCES
;
419 wire_error
= S2WERR_GENERIC_ERROR
;
425 CopyMem(tracker
, initial_stats
, sizeof(struct TypeStats
));
426 AddTail((APTR
)&opener
->initial_stats
, (APTR
)initial_stats
);
431 request
->ios2_Req
.io_Error
= error
;
432 request
->ios2_WireError
= wire_error
;
436 static BOOL
CmdUntrackType(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
438 struct RTL8169Unit
*unit
;
439 struct Opener
*opener
;
441 struct TypeTracker
*tracker
;
442 struct TypeStats
*initial_stats
;
444 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
446 RTLD(bug("[%s] S2CmdUntrackType()\n", unit
->rtl8169u_name
))
448 packet_type
= request
->ios2_PacketType
;
450 /* Get global tracker and initial figures */
452 tracker
= (struct TypeTracker
*)
453 FindTypeStats(LIBBASE
, unit
, &unit
->rtl8169u_type_trackers
, packet_type
);
454 opener
= request
->ios2_BufferManagement
;
455 initial_stats
= FindTypeStats(LIBBASE
, unit
, &opener
->initial_stats
, packet_type
);
457 /* Decrement tracker usage and free unused structures */
459 if(initial_stats
!= NULL
)
461 if((--tracker
->user_count
) == 0)
464 Remove((APTR
)tracker
);
466 FreeMem(tracker
, sizeof(struct TypeTracker
));
469 Remove((APTR
)initial_stats
);
470 FreeMem(initial_stats
, sizeof(struct TypeStats
));
474 request
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
475 request
->ios2_WireError
= S2WERR_NOT_TRACKED
;
483 static BOOL
CmdGetTypeStats(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
485 struct RTL8169Unit
*unit
;
486 struct Opener
*opener
;
488 struct TypeStats
*initial_stats
, *tracker
;
489 struct Sana2PacketTypeStats
*stats
;
491 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
493 RTLD(bug("[%s] S2CmdGetTypeStats()\n", unit
->rtl8169u_name
))
495 packet_type
= request
->ios2_PacketType
;
497 /* Get global tracker and initial figures */
499 tracker
= FindTypeStats(LIBBASE
, unit
, &unit
->rtl8169u_type_trackers
, packet_type
);
500 opener
= request
->ios2_BufferManagement
;
501 initial_stats
= FindTypeStats(LIBBASE
, unit
, &opener
->initial_stats
, packet_type
);
503 /* Copy and adjust figures */
504 if(initial_stats
!= NULL
)
506 stats
= request
->ios2_StatData
;
507 CopyMem(&tracker
->stats
, stats
, sizeof(struct Sana2PacketTypeStats
));
508 stats
->PacketsSent
-= initial_stats
->stats
.PacketsSent
;
509 stats
->PacketsReceived
-= initial_stats
->stats
.PacketsReceived
;
510 stats
->BytesSent
-= initial_stats
->stats
.BytesSent
;
511 stats
->BytesReceived
-= initial_stats
->stats
.BytesReceived
;
512 stats
->PacketsDropped
-= initial_stats
->stats
.PacketsDropped
;
516 request
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
517 request
->ios2_WireError
= S2WERR_NOT_TRACKED
;
525 static BOOL
CmdGetGlobalStats(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
527 struct RTL8169Unit
*unit
;
529 /* Update and copy stats */
531 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
533 RTLD(bug("[%s] S2CmdGetGlobalStats()\n", unit
->rtl8169u_name
))
535 CopyMem(&unit
->rtl8169u_stats
, request
->ios2_StatData
,
536 sizeof(struct Sana2DeviceStats
));
543 static BOOL
CmdDeviceQuery(LIBBASETYPEPTR LIBBASE
, struct IOStdReq
*request
)
545 struct NSDeviceQueryResult
*info
;
547 /* Set structure size twice */
549 info
= request
->io_Data
;
550 request
->io_Actual
= info
->SizeAvailable
=
551 offsetof(struct NSDeviceQueryResult
, SupportedCommands
) + sizeof(APTR
);
553 /* Report device details */
555 info
->DeviceType
= NSDEVTYPE_SANA2
;
556 info
->DeviceSubType
= 0;
558 info
->SupportedCommands
= (APTR
)supported_commands
;
565 static BOOL
CmdOnEvent(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
567 struct RTL8169Unit
*unit
;
568 ULONG events
, wanted_events
;
569 BOOL complete
= FALSE
;
571 /* Check if we understand the event types */
573 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
575 RTLD(bug("[%s] S2CmdOnEvent()\n", unit
->rtl8169u_name
))
577 wanted_events
= request
->ios2_WireError
;
578 if((wanted_events
& ~KNOWN_EVENTS
) != 0)
580 request
->ios2_Req
.io_Error
= S2ERR_NOT_SUPPORTED
;
581 events
= S2WERR_BAD_EVENT
;
585 if((unit
->rtl8169u_flags
& IFF_UP
) != 0)
587 events
= S2EVENT_ONLINE
;
591 events
= S2EVENT_OFFLINE
;
594 events
&= wanted_events
;
597 /* Reply request if a wanted event has already occurred */
601 request
->ios2_WireError
= events
;
606 request
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
607 PutMsg(unit
->rtl8169u_request_ports
[EVENT_QUEUE
], (APTR
)request
);
615 static BOOL
CmdReadOrphan(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
617 struct RTL8169Unit
*unit
;
620 BOOL complete
= FALSE
;
622 /* Check request is valid */
624 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
625 RTLD(bug("[%s] S2CmdReadOrphan()\n", unit
->rtl8169u_name
))
627 if((unit
->rtl8169u_flags
& IFF_UP
) == 0)
629 error
= S2ERR_OUTOFSERVICE
;
630 wire_error
= S2WERR_UNIT_OFFLINE
;
637 request
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
638 PutMsg(unit
->rtl8169u_request_ports
[ADOPT_QUEUE
], (struct Message
*) request
);
642 request
->ios2_Req
.io_Error
= error
;
643 request
->ios2_WireError
= wire_error
;
652 static BOOL
CmdOnline(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
654 struct RTL8169Unit
*unit
= (struct RTL8169Unit
*)request
->ios2_Req
.io_Unit
;
656 ULONG wire_error
= 0;
659 RTLD(bug("[%s] S2CmdOnline()\n", unit
->rtl8169u_name
))
661 /* Check request is valid */
662 if((unit
->rtl8169u_flags
& IFF_CONFIGURED
) == 0)
664 error
= S2ERR_BAD_STATE
;
665 wire_error
= S2WERR_NOT_CONFIGURED
;
668 /* Clear global and special stats and put adapter back online */
670 if((error
== 0) && ((unit
->rtl8169u_flags
& IFF_UP
) == 0))
672 unit
->rtl8169u_stats
.PacketsReceived
= 0;
673 unit
->rtl8169u_stats
.PacketsSent
= 0;
674 unit
->rtl8169u_stats
.BadData
= 0;
675 unit
->rtl8169u_stats
.Overruns
= 0;
676 unit
->rtl8169u_stats
.UnknownTypesReceived
= 0;
677 unit
->rtl8169u_stats
.Reconfigurations
= 0;
679 for(i
= 0; i
< STAT_COUNT
; i
++)
681 unit
->rtl8169u_special_stats
[i
] = 0;
684 if (unit
->start(unit
))
686 error
= S2ERR_OUTOFSERVICE
;
687 wire_error
= S2WERR_GENERIC_ERROR
;
693 request
->ios2_Req
.io_Error
= error
;
694 request
->ios2_WireError
= wire_error
;
698 static BOOL
CmdOffline(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
700 struct RTL8169Unit
*unit
;
702 /* Put adapter offline */
704 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
706 RTLD(bug("[%s] S2CmdOffline()\n", unit
->rtl8169u_name
))
708 if((unit
->rtl8169u_flags
& IFF_UP
) != 0)
717 static BOOL
CmdAddMulticastAddresses(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
719 struct RTL8169Unit
*unit
;
720 UBYTE
*lower_bound
, *upper_bound
;
722 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
724 RTLD(bug("[%s] S2CmdAddMulticastAddresses()\n", unit
->rtl8169u_name
))
726 lower_bound
= request
->ios2_SrcAddr
;
727 if(request
->ios2_Req
.io_Command
== S2_ADDMULTICASTADDRESS
)
728 upper_bound
= lower_bound
;
730 upper_bound
= request
->ios2_DstAddr
;
732 if(!AddMulticastRange(LIBBASE
, unit
, lower_bound
, upper_bound
))
734 request
->ios2_Req
.io_Error
= S2ERR_NO_RESOURCES
;
735 request
->ios2_WireError
= S2WERR_GENERIC_ERROR
;
743 static BOOL
CmdDelMulticastAddresses(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
745 struct RTL8169Unit
*unit
;
746 UBYTE
*lower_bound
, *upper_bound
;
748 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
750 RTLD(bug("[%s] S2CmdDelMulticastAddresses()\n", unit
->rtl8169u_name
))
752 lower_bound
= request
->ios2_SrcAddr
;
753 if(request
->ios2_Req
.io_Command
== S2_DELMULTICASTADDRESS
)
755 upper_bound
= lower_bound
;
759 upper_bound
= request
->ios2_DstAddr
;
762 if(!RemMulticastRange(LIBBASE
, unit
, lower_bound
, upper_bound
))
764 request
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
765 request
->ios2_WireError
= S2WERR_BAD_MULTICAST
;