Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / workbench / devs / networks / nForce / handler.c
blob3e93f0cbefa25f9aff6e39652d45495befb87c2c
1 /*
2 * $Id$
3 */
5 /*
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,
19 MA 02111-1307, USA.
22 #define DEBUG 0
24 #include <exec/types.h>
25 #include <exec/resident.h>
26 #include <exec/io.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>
44 #include <stdlib.h>
46 #include "nforce.h"
47 #include "unit.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[] =
76 CMD_READ,
77 CMD_WRITE,
78 CMD_FLUSH,
79 S2_DEVICEQUERY,
80 S2_GETSTATIONADDRESS,
81 S2_CONFIGINTERFACE,
82 S2_ADDMULTICASTADDRESS,
83 S2_DELMULTICASTADDRESS,
84 S2_MULTICAST,
85 S2_BROADCAST,
86 S2_TRACKTYPE,
87 S2_UNTRACKTYPE,
88 S2_GETTYPESTATS,
89 // S2_GETSPECIALSTATS,
90 S2_GETGLOBALSTATS,
91 S2_ONEVENT,
92 S2_READORPHAN,
93 S2_ONLINE,
94 S2_OFFLINE,
95 NSCMD_DEVICEQUERY,
96 S2_ADDMULTICASTADDRESSES,
97 S2_DELMULTICASTADDRESSES,
101 void handle_request(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
103 BOOL complete;
105 switch(request->ios2_Req.io_Command)
107 case CMD_READ:
108 complete = CmdRead(LIBBASE, request);
109 break;
111 case CMD_WRITE:
112 case S2_MULTICAST:
113 complete = CmdWrite(LIBBASE, request);
114 break;
116 case CMD_FLUSH:
117 complete = CmdFlush(LIBBASE, (struct IORequest *)request);
118 break;
120 case S2_DEVICEQUERY:
121 complete = CmdS2DeviceQuery(LIBBASE, request);
122 break;
124 case S2_GETSTATIONADDRESS:
125 complete = CmdGetStationAddress(LIBBASE, request);
126 break;
128 case S2_CONFIGINTERFACE:
129 complete = CmdConfigInterface(LIBBASE, request);
130 break;
132 case S2_BROADCAST:
133 complete = CmdBroadcast(LIBBASE, request);
134 break;
136 case S2_TRACKTYPE:
137 complete = CmdTrackType(LIBBASE, request);
138 break;
140 case S2_UNTRACKTYPE:
141 complete = CmdUntrackType(LIBBASE, request);
142 break;
144 case S2_GETTYPESTATS:
145 complete = CmdGetTypeStats(LIBBASE, request);
146 break;
148 case S2_GETGLOBALSTATS:
149 complete = CmdGetGlobalStats(LIBBASE, request);
150 break;
152 case S2_ONEVENT:
153 complete = CmdOnEvent(LIBBASE, request);
154 break;
156 case S2_READORPHAN:
157 complete = CmdReadOrphan(LIBBASE, request);
158 break;
160 case S2_ONLINE:
161 complete = CmdOnline(LIBBASE, request);
162 break;
164 case S2_OFFLINE:
165 complete = CmdOffline(LIBBASE, request);
166 break;
168 case S2_ADDMULTICASTADDRESS:
169 case S2_ADDMULTICASTADDRESSES:
170 complete = CmdAddMulticastAddresses(LIBBASE, request);
171 break;
173 case S2_DELMULTICASTADDRESS:
174 case S2_DELMULTICASTADDRESSES:
175 complete = CmdDelMulticastAddresses(LIBBASE, request);
176 break;
178 case NSCMD_DEVICEQUERY:
179 complete = CmdDeviceQuery(LIBBASE, (struct IOStdReq *)request);
180 break;
182 default:
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;
197 return TRUE;
200 static BOOL CmdRead(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
202 struct NFUnit *unit;
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);
214 else
216 request->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
217 request->ios2_WireError = S2WERR_UNIT_OFFLINE;
218 complete = TRUE;
221 /* Return */
223 return complete;
226 static BOOL CmdWrite(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
228 struct NFUnit *unit;
229 BYTE error = 0;
230 ULONG wire_error;
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 */
250 if(error == 0) {
251 request->ios2_Req.io_Flags &= ~IOF_QUICK;
252 PutMsg(unit->request_ports[WRITE_QUEUE], (APTR)request);
254 else
256 request->ios2_Req.io_Error = error;
257 request->ios2_WireError = wire_error;
258 complete = TRUE;
261 /* Return */
263 return complete;
266 static BOOL CmdFlush(LIBBASETYPEPTR LIBBASE, struct IORequest *request)
268 FlushUnit(LIBBASE, (APTR)request->io_Unit, EVENT_QUEUE, IOERR_ABORTED);
269 return TRUE;
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;
292 else
293 info->BPS = 10000000;
295 info->SizeAvailable = size_available;
296 info->SizeSupplied = size;
298 /* Return */
300 return TRUE;
303 static BOOL CmdGetStationAddress(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
305 struct NFUnit *unit;
307 /* Copy addresses */
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);
313 /* Return */
315 return TRUE;
318 static BOOL CmdConfigInterface(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
320 struct NFUnit *unit;
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;
331 else
333 request->ios2_Req.io_Error = S2ERR_BAD_STATE;
334 request->ios2_WireError = S2WERR_IS_CONFIGURED;
337 /* Return */
339 return TRUE;
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)
356 struct NFUnit *unit;
357 struct Opener *opener;
358 ULONG packet_type, wire_error=0;
359 struct TypeTracker *tracker;
360 struct TypeStats *initial_stats;
361 BYTE error = 0;
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);
371 if(tracker != NULL)
372 tracker->user_count++;
373 else
375 tracker =
376 AllocMem(sizeof(struct TypeTracker), MEMF_PUBLIC|MEMF_CLEAR);
377 if(tracker != NULL)
379 tracker->packet_type = packet_type;
380 tracker->user_count = 1;
382 Disable();
383 AddTail((APTR)&unit->type_trackers, (APTR)tracker);
384 Enable();
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;
399 if(error == 0)
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;
409 if(error == 0)
411 CopyMem(tracker, initial_stats, sizeof(struct TypeStats));
412 AddTail((APTR)&opener->initial_stats, (APTR)initial_stats);
415 /* Return */
417 request->ios2_Req.io_Error = error;
418 request->ios2_WireError = wire_error;
419 return TRUE;
422 static BOOL CmdUntrackType(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
424 struct NFUnit *unit;
425 struct Opener *opener;
426 ULONG packet_type;
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)
446 Disable();
447 Remove((APTR)tracker);
448 Enable();
449 FreeMem(tracker, sizeof(struct TypeTracker));
452 Remove((APTR)initial_stats);
453 FreeMem(initial_stats, sizeof(struct TypeStats));
455 else
457 request->ios2_Req.io_Error = S2ERR_BAD_STATE;
458 request->ios2_WireError = S2WERR_NOT_TRACKED;
461 /* Return */
463 return TRUE;
466 static BOOL CmdGetTypeStats(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
468 struct NFUnit *unit;
469 struct Opener *opener;
470 ULONG packet_type;
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;
494 else
496 request->ios2_Req.io_Error = S2ERR_BAD_STATE;
497 request->ios2_WireError = S2WERR_NOT_TRACKED;
500 /* Return */
502 return TRUE;
505 static BOOL CmdGetGlobalStats(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
507 struct NFUnit *unit;
509 /* Update and copy stats */
511 unit = (APTR)request->ios2_Req.io_Unit;
512 CopyMem(&unit->stats, request->ios2_StatData,
513 sizeof(struct Sana2DeviceStats));
515 /* Return */
517 return TRUE;
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;
537 /* Return */
539 return TRUE;
542 static BOOL CmdOnEvent(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
544 struct NFUnit *unit;
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;
557 else
559 if((unit->flags & IFF_UP) != 0)
560 events = S2EVENT_ONLINE;
561 else
562 events = S2EVENT_OFFLINE;
564 events &= wanted_events;
567 /* Reply request if a wanted event has already occurred */
569 if(events != 0)
571 request->ios2_WireError = events;
572 complete = TRUE;
574 else
576 request->ios2_Req.io_Flags &= ~IOF_QUICK;
577 PutMsg(unit->request_ports[EVENT_QUEUE], (APTR)request);
580 /* Return */
582 return complete;
585 static BOOL CmdReadOrphan(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
587 struct NFUnit *unit;
588 BYTE error = 0;
589 ULONG wire_error;
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;
601 /* Queue request */
603 if(error == 0)
605 request->ios2_Req.io_Flags &= ~IOF_QUICK;
606 PutMsg(unit->request_ports[ADOPT_QUEUE], (struct Message *)request);
608 else
610 request->ios2_Req.io_Error = error;
611 request->ios2_WireError = wire_error;
612 complete = TRUE;
615 /* Return */
617 return complete;
620 static BOOL CmdOnline(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
622 struct NFUnit *unit = (struct NFUnit *)request->ios2_Req.io_Unit;
623 BYTE error = 0;
624 ULONG wire_error = 0;
625 UWORD i;
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;
654 /* Return */
656 request->ios2_Req.io_Error = error;
657 request->ios2_WireError = wire_error;
658 return TRUE;
661 static BOOL CmdOffline(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
663 struct NFUnit *unit;
665 /* Put adapter offline */
667 unit = (APTR)request->ios2_Req.io_Unit;
668 if((unit->flags & IFF_UP) != 0)
669 unit->stop(unit);
671 /* Return */
672 return TRUE;
675 static BOOL CmdAddMulticastAddresses(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
677 struct NFUnit *unit;
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;
685 else
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;
694 /* Return */
696 return TRUE;
699 static BOOL CmdDelMulticastAddresses(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
701 struct NFUnit *unit;
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;
709 else
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;
718 /* Return */
720 return TRUE;