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 <aros/debug.h>
32 #include <devices/sana2.h>
33 #include <devices/sana2specialstats.h>
34 #include <devices/newstyle.h>
36 #include <utility/utility.h>
37 #include <utility/tagitem.h>
38 #include <utility/hooks.h>
40 #include <proto/exec.h>
41 #include <proto/dos.h>
42 #include <proto/battclock.h>
48 #include LC_LIBDEFS_FILE
50 #define KNOWN_EVENTS \
51 (S2EVENT_ERROR | S2EVENT_TX | S2EVENT_RX | S2EVENT_ONLINE \
52 | S2EVENT_OFFLINE | S2EVENT_BUFF | S2EVENT_HARDWARE | S2EVENT_SOFTWARE)
54 static BOOL
CmdInvalid(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
55 static BOOL
CmdRead(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
56 static BOOL
CmdWrite(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
57 static BOOL
CmdFlush(LIBBASETYPEPTR LIBBASE
, struct IORequest
*request
);
58 static BOOL
CmdS2DeviceQuery(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
59 static BOOL
CmdGetStationAddress(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
60 static BOOL
CmdConfigInterface(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
61 static BOOL
CmdBroadcast(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
62 static BOOL
CmdTrackType(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
63 static BOOL
CmdUntrackType(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
64 static BOOL
CmdGetTypeStats(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
65 static BOOL
CmdGetGlobalStats(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
66 static BOOL
CmdDeviceQuery(LIBBASETYPEPTR LIBBASE
, struct IOStdReq
*request
);
67 static BOOL
CmdOnEvent(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
68 static BOOL
CmdReadOrphan(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
69 static BOOL
CmdOnline(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
70 static BOOL
CmdOffline(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
71 static BOOL
CmdAddMulticastAddresses(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
72 static BOOL
CmdDelMulticastAddresses(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
);
74 static const UWORD supported_commands
[] =
82 S2_ADDMULTICASTADDRESS
,
83 S2_DELMULTICASTADDRESS
,
89 // S2_GETSPECIALSTATS,
96 S2_ADDMULTICASTADDRESSES
,
97 S2_DELMULTICASTADDRESSES
,
101 void handle_request(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
105 switch(request
->ios2_Req
.io_Command
)
108 complete
= CmdRead(LIBBASE
, request
);
113 complete
= CmdWrite(LIBBASE
, request
);
117 complete
= CmdFlush(LIBBASE
, (struct IORequest
*)request
);
121 complete
= CmdS2DeviceQuery(LIBBASE
, request
);
124 case S2_GETSTATIONADDRESS
:
125 complete
= CmdGetStationAddress(LIBBASE
, request
);
128 case S2_CONFIGINTERFACE
:
129 complete
= CmdConfigInterface(LIBBASE
, request
);
133 complete
= CmdBroadcast(LIBBASE
, request
);
137 complete
= CmdTrackType(LIBBASE
, request
);
141 complete
= CmdUntrackType(LIBBASE
, request
);
144 case S2_GETTYPESTATS
:
145 complete
= CmdGetTypeStats(LIBBASE
, request
);
148 case S2_GETGLOBALSTATS
:
149 complete
= CmdGetGlobalStats(LIBBASE
, request
);
153 complete
= CmdOnEvent(LIBBASE
, request
);
157 complete
= CmdReadOrphan(LIBBASE
, request
);
161 complete
= CmdOnline(LIBBASE
, request
);
165 complete
= CmdOffline(LIBBASE
, request
);
168 case S2_ADDMULTICASTADDRESS
:
169 case S2_ADDMULTICASTADDRESSES
:
170 complete
= CmdAddMulticastAddresses(LIBBASE
, request
);
173 case S2_DELMULTICASTADDRESS
:
174 case S2_DELMULTICASTADDRESSES
:
175 complete
= CmdDelMulticastAddresses(LIBBASE
, request
);
178 case NSCMD_DEVICEQUERY
:
179 complete
= CmdDeviceQuery(LIBBASE
, (struct IOStdReq
*)request
);
183 complete
= CmdInvalid(LIBBASE
, request
);
186 if(complete
&& (request
->ios2_Req
.io_Flags
& IOF_QUICK
) == 0)
187 ReplyMsg((APTR
)request
);
189 ReleaseSemaphore(&((struct NFUnit
*)request
->ios2_Req
.io_Unit
)->unit_lock
);
192 static BOOL
CmdInvalid(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
194 request
->ios2_Req
.io_Error
= IOERR_NOCMD
;
195 request
->ios2_WireError
= S2WERR_GENERIC_ERROR
;
200 static BOOL
CmdRead(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
203 struct Opener
*opener
;
204 BOOL complete
= FALSE
;
206 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
208 if((unit
->flags
& IFF_UP
) != 0)
210 opener
= request
->ios2_BufferManagement
;
211 request
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
212 PutMsg(&opener
->read_port
, (struct Message
*)request
);
216 request
->ios2_Req
.io_Error
= S2ERR_OUTOFSERVICE
;
217 request
->ios2_WireError
= S2WERR_UNIT_OFFLINE
;
226 static BOOL
CmdWrite(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
231 BOOL complete
= FALSE
;
233 /* Check request is valid */
235 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
236 if((unit
->flags
& IFF_UP
) == 0)
238 error
= S2ERR_OUTOFSERVICE
;
239 wire_error
= S2WERR_UNIT_OFFLINE
;
241 else if((request
->ios2_Req
.io_Command
== S2_MULTICAST
) &&
242 ((request
->ios2_DstAddr
[0] & 0x1) == 0))
244 error
= S2ERR_BAD_ADDRESS
;
245 wire_error
= S2WERR_BAD_MULTICAST
;
248 /* Queue request for sending */
251 request
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
252 PutMsg(unit
->request_ports
[WRITE_QUEUE
], (APTR
)request
);
256 request
->ios2_Req
.io_Error
= error
;
257 request
->ios2_WireError
= wire_error
;
266 static BOOL
CmdFlush(LIBBASETYPEPTR LIBBASE
, struct IORequest
*request
)
268 FlushUnit(LIBBASE
, (APTR
)request
->io_Unit
, EVENT_QUEUE
, IOERR_ABORTED
);
272 static BOOL
CmdS2DeviceQuery(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
274 struct NFUnit
*unit
= (APTR
)request
->ios2_Req
.io_Unit
;
275 struct fe_priv
*np
= unit
->nu_fe_priv
;
276 struct Sana2DeviceQuery
*info
;
277 ULONG size_available
, size
;
279 /* Copy device info */
281 info
= request
->ios2_StatData
;
282 size
= size_available
= info
->SizeAvailable
;
283 if(size
> sizeof(struct Sana2DeviceQuery
))
284 size
= sizeof(struct Sana2DeviceQuery
);
286 CopyMem(&LIBBASE
->nf_Sana2Info
, info
, size
);
288 if ((np
->linkspeed
& NVREG_LINKSPEED_MASK
) == NVREG_LINKSPEED_100
)
289 info
->BPS
= 100000000;
290 else if ((np
->linkspeed
& NVREG_LINKSPEED_MASK
) == NVREG_LINKSPEED_1000
)
291 info
->BPS
= 1000000000;
293 info
->BPS
= 10000000;
295 info
->SizeAvailable
= size_available
;
296 info
->SizeSupplied
= size
;
303 static BOOL
CmdGetStationAddress(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
309 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
310 CopyMem(unit
->dev_addr
, request
->ios2_SrcAddr
, ETH_ADDRESSSIZE
);
311 CopyMem(unit
->org_addr
, request
->ios2_DstAddr
, ETH_ADDRESSSIZE
);
318 static BOOL
CmdConfigInterface(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
322 /* Configure adapter */
324 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
325 if((unit
->flags
& IFF_CONFIGURED
) == 0)
327 CopyMem(request
->ios2_SrcAddr
, unit
->dev_addr
, ETH_ADDRESSSIZE
);
328 unit
->set_mac_address(unit
);
329 unit
->flags
|= IFF_CONFIGURED
;
333 request
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
334 request
->ios2_WireError
= S2WERR_IS_CONFIGURED
;
342 static BOOL
CmdBroadcast(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
344 /* Fill in the broadcast address as destination */
346 *((ULONG
*)request
->ios2_DstAddr
) = 0xffffffff;
347 *((UWORD
*)(request
->ios2_DstAddr
+ 4)) = 0xffff;
349 /* Queue the write as normal */
351 return CmdWrite(LIBBASE
, request
);
354 static BOOL
CmdTrackType(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
357 struct Opener
*opener
;
358 ULONG packet_type
, wire_error
=0;
359 struct TypeTracker
*tracker
;
360 struct TypeStats
*initial_stats
;
363 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
364 packet_type
= request
->ios2_PacketType
;
366 /* Get global tracker */
368 tracker
= (struct TypeTracker
*)
369 FindTypeStats(LIBBASE
, unit
, &unit
->type_trackers
, packet_type
);
372 tracker
->user_count
++;
376 AllocMem(sizeof(struct TypeTracker
), MEMF_PUBLIC
|MEMF_CLEAR
);
379 tracker
->packet_type
= packet_type
;
380 tracker
->user_count
= 1;
383 AddTail((APTR
)&unit
->type_trackers
, (APTR
)tracker
);
388 /* Store initial figures for this opener */
390 opener
= request
->ios2_BufferManagement
;
391 initial_stats
= FindTypeStats(LIBBASE
, unit
, &opener
->initial_stats
, packet_type
);
393 if(initial_stats
!= NULL
)
395 error
= S2ERR_BAD_STATE
;
396 wire_error
= S2WERR_ALREADY_TRACKED
;
401 initial_stats
= AllocMem(sizeof(struct TypeStats
), MEMF_PUBLIC
);
402 if(initial_stats
== NULL
)
404 error
= S2ERR_NO_RESOURCES
;
405 wire_error
= S2WERR_GENERIC_ERROR
;
411 CopyMem(tracker
, initial_stats
, sizeof(struct TypeStats
));
412 AddTail((APTR
)&opener
->initial_stats
, (APTR
)initial_stats
);
417 request
->ios2_Req
.io_Error
= error
;
418 request
->ios2_WireError
= wire_error
;
422 static BOOL
CmdUntrackType(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
425 struct Opener
*opener
;
427 struct TypeTracker
*tracker
;
428 struct TypeStats
*initial_stats
;
430 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
431 packet_type
= request
->ios2_PacketType
;
433 /* Get global tracker and initial figures */
435 tracker
= (struct TypeTracker
*)
436 FindTypeStats(LIBBASE
, unit
, &unit
->type_trackers
, packet_type
);
437 opener
= request
->ios2_BufferManagement
;
438 initial_stats
= FindTypeStats(LIBBASE
, unit
, &opener
->initial_stats
, packet_type
);
440 /* Decrement tracker usage and free unused structures */
442 if(initial_stats
!= NULL
)
444 if((--tracker
->user_count
) == 0)
447 Remove((APTR
)tracker
);
449 FreeMem(tracker
, sizeof(struct TypeTracker
));
452 Remove((APTR
)initial_stats
);
453 FreeMem(initial_stats
, sizeof(struct TypeStats
));
457 request
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
458 request
->ios2_WireError
= S2WERR_NOT_TRACKED
;
466 static BOOL
CmdGetTypeStats(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
469 struct Opener
*opener
;
471 struct TypeStats
*initial_stats
, *tracker
;
472 struct Sana2PacketTypeStats
*stats
;
474 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
475 packet_type
= request
->ios2_PacketType
;
477 /* Get global tracker and initial figures */
479 tracker
= FindTypeStats(LIBBASE
, unit
, &unit
->type_trackers
, packet_type
);
480 opener
= request
->ios2_BufferManagement
;
481 initial_stats
= FindTypeStats(LIBBASE
, 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(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
509 /* Update and copy stats */
511 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
512 CopyMem(&unit
->stats
, request
->ios2_StatData
,
513 sizeof(struct Sana2DeviceStats
));
520 static BOOL
CmdDeviceQuery(LIBBASETYPEPTR LIBBASE
, struct IOStdReq
*request
)
522 struct NSDeviceQueryResult
*info
;
524 /* Set structure size twice */
526 info
= request
->io_Data
;
527 request
->io_Actual
= info
->SizeAvailable
=
528 offsetof(struct NSDeviceQueryResult
, SupportedCommands
) + sizeof(APTR
);
530 /* Report device details */
532 info
->DeviceType
= NSDEVTYPE_SANA2
;
533 info
->DeviceSubType
= 0;
535 info
->SupportedCommands
= (APTR
)supported_commands
;
542 static BOOL
CmdOnEvent(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
545 ULONG events
, wanted_events
;
546 BOOL complete
= FALSE
;
548 /* Check if we understand the event types */
550 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
551 wanted_events
= request
->ios2_WireError
;
552 if((wanted_events
& ~KNOWN_EVENTS
) != 0)
554 request
->ios2_Req
.io_Error
= S2ERR_NOT_SUPPORTED
;
555 events
= S2WERR_BAD_EVENT
;
559 if((unit
->flags
& IFF_UP
) != 0)
560 events
= S2EVENT_ONLINE
;
562 events
= S2EVENT_OFFLINE
;
564 events
&= wanted_events
;
567 /* Reply request if a wanted event has already occurred */
571 request
->ios2_WireError
= events
;
576 request
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
577 PutMsg(unit
->request_ports
[EVENT_QUEUE
], (APTR
)request
);
585 static BOOL
CmdReadOrphan(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
590 BOOL complete
= FALSE
;
592 /* Check request is valid */
594 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
595 if((unit
->flags
& IFF_UP
) == 0)
597 error
= S2ERR_OUTOFSERVICE
;
598 wire_error
= S2WERR_UNIT_OFFLINE
;
605 request
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
606 PutMsg(unit
->request_ports
[ADOPT_QUEUE
], (struct Message
*)request
);
610 request
->ios2_Req
.io_Error
= error
;
611 request
->ios2_WireError
= wire_error
;
620 static BOOL
CmdOnline(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
622 struct NFUnit
*unit
= (struct NFUnit
*)request
->ios2_Req
.io_Unit
;
624 ULONG wire_error
= 0;
627 /* Check request is valid */
628 if((unit
->flags
& IFF_CONFIGURED
) == 0)
630 error
= S2ERR_BAD_STATE
;
631 wire_error
= S2WERR_NOT_CONFIGURED
;
634 /* Clear global and special stats and put adapter back online */
636 if((error
== 0) && ((unit
->flags
& IFF_UP
) == 0))
638 unit
->stats
.PacketsReceived
= 0;
639 unit
->stats
.PacketsSent
= 0;
640 unit
->stats
.BadData
= 0;
641 unit
->stats
.Overruns
= 0;
642 unit
->stats
.UnknownTypesReceived
= 0;
643 unit
->stats
.Reconfigurations
= 0;
645 for(i
= 0; i
< STAT_COUNT
; i
++)
646 unit
->special_stats
[i
] = 0;
648 if (unit
->start(unit
)) {
649 error
= S2ERR_OUTOFSERVICE
;
650 wire_error
= S2WERR_GENERIC_ERROR
;
656 request
->ios2_Req
.io_Error
= error
;
657 request
->ios2_WireError
= wire_error
;
661 static BOOL
CmdOffline(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
665 /* Put adapter offline */
667 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
668 if((unit
->flags
& IFF_UP
) != 0)
675 static BOOL
CmdAddMulticastAddresses(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
678 UBYTE
*lower_bound
, *upper_bound
;
680 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
682 lower_bound
= request
->ios2_SrcAddr
;
683 if(request
->ios2_Req
.io_Command
== S2_ADDMULTICASTADDRESS
)
684 upper_bound
= lower_bound
;
686 upper_bound
= request
->ios2_DstAddr
;
688 if(!AddMulticastRange(LIBBASE
, unit
, lower_bound
, upper_bound
))
690 request
->ios2_Req
.io_Error
= S2ERR_NO_RESOURCES
;
691 request
->ios2_WireError
= S2WERR_GENERIC_ERROR
;
699 static BOOL
CmdDelMulticastAddresses(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*request
)
702 UBYTE
*lower_bound
, *upper_bound
;
704 unit
= (APTR
)request
->ios2_Req
.io_Unit
;
706 lower_bound
= request
->ios2_SrcAddr
;
707 if(request
->ios2_Req
.io_Command
== S2_DELMULTICASTADDRESS
)
708 upper_bound
= lower_bound
;
710 upper_bound
= request
->ios2_DstAddr
;
712 if(!RemMulticastRange(LIBBASE
, unit
, lower_bound
, upper_bound
))
714 request
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
715 request
->ios2_WireError
= S2WERR_BAD_MULTICAST
;