Here's an idea: don't add interrupt handlers when they've already been
[AROS.git] / workbench / devs / networks / nForce / handler.c
blob267d0a0d182c62b506c16b96e4f80f86bde598ce
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 <string.h>
26 #include <exec/types.h>
27 #include <exec/resident.h>
28 #include <exec/io.h>
29 #include <exec/ports.h>
30 #include <exec/errors.h>
32 #include <aros/debug.h>
34 #include <devices/sana2.h>
35 #include <devices/sana2specialstats.h>
36 #include <devices/newstyle.h>
38 #include <utility/utility.h>
39 #include <utility/tagitem.h>
40 #include <utility/hooks.h>
42 #include <proto/exec.h>
43 #include <proto/dos.h>
44 #include <proto/battclock.h>
46 #include <stdlib.h>
48 #include "nforce.h"
49 #include "unit.h"
50 #include LC_LIBDEFS_FILE
52 #define KNOWN_EVENTS \
53 (S2EVENT_ERROR | S2EVENT_TX | S2EVENT_RX | S2EVENT_ONLINE \
54 | S2EVENT_OFFLINE | S2EVENT_BUFF | S2EVENT_HARDWARE | S2EVENT_SOFTWARE)
56 static BOOL CmdInvalid(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request);
57 static BOOL CmdRead(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request);
58 static BOOL CmdWrite(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request);
59 static BOOL CmdFlush(LIBBASETYPEPTR LIBBASE, struct IORequest *request);
60 static BOOL CmdS2DeviceQuery(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request);
61 static BOOL CmdGetStationAddress(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request);
62 static BOOL CmdConfigInterface(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request);
63 static BOOL CmdBroadcast(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request);
64 static BOOL CmdTrackType(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request);
65 static BOOL CmdUntrackType(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request);
66 static BOOL CmdGetTypeStats(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request);
67 static BOOL CmdGetGlobalStats(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request);
68 static BOOL CmdDeviceQuery(LIBBASETYPEPTR LIBBASE, struct IOStdReq *request);
69 static BOOL CmdOnEvent(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request);
70 static BOOL CmdReadOrphan(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request);
71 static BOOL CmdOnline(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request);
72 static BOOL CmdOffline(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request);
73 static BOOL CmdAddMulticastAddresses(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request);
74 static BOOL CmdDelMulticastAddresses(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request);
76 static const UWORD supported_commands[] =
78 CMD_READ,
79 CMD_WRITE,
80 CMD_FLUSH,
81 S2_DEVICEQUERY,
82 S2_GETSTATIONADDRESS,
83 S2_CONFIGINTERFACE,
84 S2_ADDMULTICASTADDRESS,
85 S2_DELMULTICASTADDRESS,
86 S2_MULTICAST,
87 S2_BROADCAST,
88 S2_TRACKTYPE,
89 S2_UNTRACKTYPE,
90 S2_GETTYPESTATS,
91 // S2_GETSPECIALSTATS,
92 S2_GETGLOBALSTATS,
93 S2_ONEVENT,
94 S2_READORPHAN,
95 S2_ONLINE,
96 S2_OFFLINE,
97 NSCMD_DEVICEQUERY,
98 S2_ADDMULTICASTADDRESSES,
99 S2_DELMULTICASTADDRESSES,
103 void handle_request(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
105 BOOL complete;
107 switch(request->ios2_Req.io_Command)
109 case CMD_READ:
110 complete = CmdRead(LIBBASE, request);
111 break;
113 case CMD_WRITE:
114 case S2_MULTICAST:
115 complete = CmdWrite(LIBBASE, request);
116 break;
118 case CMD_FLUSH:
119 complete = CmdFlush(LIBBASE, (struct IORequest *)request);
120 break;
122 case S2_DEVICEQUERY:
123 complete = CmdS2DeviceQuery(LIBBASE, request);
124 break;
126 case S2_GETSTATIONADDRESS:
127 complete = CmdGetStationAddress(LIBBASE, request);
128 break;
130 case S2_CONFIGINTERFACE:
131 complete = CmdConfigInterface(LIBBASE, request);
132 break;
134 case S2_BROADCAST:
135 complete = CmdBroadcast(LIBBASE, request);
136 break;
138 case S2_TRACKTYPE:
139 complete = CmdTrackType(LIBBASE, request);
140 break;
142 case S2_UNTRACKTYPE:
143 complete = CmdUntrackType(LIBBASE, request);
144 break;
146 case S2_GETTYPESTATS:
147 complete = CmdGetTypeStats(LIBBASE, request);
148 break;
150 case S2_GETGLOBALSTATS:
151 complete = CmdGetGlobalStats(LIBBASE, request);
152 break;
154 case S2_ONEVENT:
155 complete = CmdOnEvent(LIBBASE, request);
156 break;
158 case S2_READORPHAN:
159 complete = CmdReadOrphan(LIBBASE, request);
160 break;
162 case S2_ONLINE:
163 complete = CmdOnline(LIBBASE, request);
164 break;
166 case S2_OFFLINE:
167 complete = CmdOffline(LIBBASE, request);
168 break;
170 case S2_ADDMULTICASTADDRESS:
171 case S2_ADDMULTICASTADDRESSES:
172 complete = CmdAddMulticastAddresses(LIBBASE, request);
173 break;
175 case S2_DELMULTICASTADDRESS:
176 case S2_DELMULTICASTADDRESSES:
177 complete = CmdDelMulticastAddresses(LIBBASE, request);
178 break;
180 case NSCMD_DEVICEQUERY:
181 complete = CmdDeviceQuery(LIBBASE, (struct IOStdReq *)request);
182 break;
184 default:
185 complete = CmdInvalid(LIBBASE, request);
188 if(complete && (request->ios2_Req.io_Flags & IOF_QUICK) == 0)
189 ReplyMsg((APTR)request);
191 ReleaseSemaphore(&((struct NFUnit *)request->ios2_Req.io_Unit)->unit_lock);
194 static BOOL CmdInvalid(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
196 request->ios2_Req.io_Error = IOERR_NOCMD;
197 request->ios2_WireError = S2WERR_GENERIC_ERROR;
199 return TRUE;
202 static BOOL CmdRead(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
204 struct NFUnit *unit;
205 struct Opener *opener;
206 BOOL complete = FALSE;
208 unit = (APTR)request->ios2_Req.io_Unit;
210 if((unit->flags & IFF_UP) != 0)
212 opener = request->ios2_BufferManagement;
213 request->ios2_Req.io_Flags &= ~IOF_QUICK;
214 PutMsg(&opener->read_port, (struct Message *)request);
216 else
218 request->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
219 request->ios2_WireError = S2WERR_UNIT_OFFLINE;
220 complete = TRUE;
223 /* Return */
225 return complete;
228 static BOOL CmdWrite(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
230 struct NFUnit *unit;
231 BYTE error = 0;
232 ULONG wire_error;
233 BOOL complete = FALSE;
235 /* Check request is valid */
237 unit = (APTR)request->ios2_Req.io_Unit;
238 if((unit->flags & IFF_UP) == 0)
240 error = S2ERR_OUTOFSERVICE;
241 wire_error = S2WERR_UNIT_OFFLINE;
243 else if((request->ios2_Req.io_Command == S2_MULTICAST) &&
244 ((request->ios2_DstAddr[0] & 0x1) == 0))
246 error = S2ERR_BAD_ADDRESS;
247 wire_error = S2WERR_BAD_MULTICAST;
250 /* Queue request for sending */
252 if(error == 0) {
253 request->ios2_Req.io_Flags &= ~IOF_QUICK;
254 PutMsg(unit->request_ports[WRITE_QUEUE], (APTR)request);
256 else
258 request->ios2_Req.io_Error = error;
259 request->ios2_WireError = wire_error;
260 complete = TRUE;
263 /* Return */
265 return complete;
268 static BOOL CmdFlush(LIBBASETYPEPTR LIBBASE, struct IORequest *request)
270 FlushUnit(LIBBASE, (APTR)request->io_Unit, EVENT_QUEUE, IOERR_ABORTED);
271 return TRUE;
274 static BOOL CmdS2DeviceQuery(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
276 struct NFUnit *unit = (APTR)request->ios2_Req.io_Unit;
277 struct fe_priv *np = unit->nu_fe_priv;
278 struct Sana2DeviceQuery *info;
279 ULONG size_available, size;
281 /* Copy device info */
283 info = request->ios2_StatData;
284 size = size_available = info->SizeAvailable;
285 if(size > sizeof(struct Sana2DeviceQuery))
286 size = sizeof(struct Sana2DeviceQuery);
288 CopyMem(&LIBBASE->nf_Sana2Info, info, size);
290 if ((np->linkspeed & NVREG_LINKSPEED_MASK) == NVREG_LINKSPEED_100)
291 info->BPS = 100000000;
292 else if ((np->linkspeed & NVREG_LINKSPEED_MASK) == NVREG_LINKSPEED_1000)
293 info->BPS = 1000000000;
294 else
295 info->BPS = 10000000;
297 info->SizeAvailable = size_available;
298 info->SizeSupplied = size;
300 /* Return */
302 return TRUE;
305 static BOOL CmdGetStationAddress(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
307 struct NFUnit *unit;
309 /* Copy addresses */
311 unit = (APTR)request->ios2_Req.io_Unit;
312 CopyMem(unit->dev_addr, request->ios2_SrcAddr, ETH_ADDRESSSIZE);
313 CopyMem(unit->org_addr, request->ios2_DstAddr, ETH_ADDRESSSIZE);
315 /* Return */
317 return TRUE;
320 static BOOL CmdConfigInterface(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
322 struct NFUnit *unit;
324 /* Configure adapter */
326 unit = (APTR)request->ios2_Req.io_Unit;
327 if((unit->flags & IFF_CONFIGURED) == 0)
329 CopyMem(request->ios2_SrcAddr, unit->dev_addr, ETH_ADDRESSSIZE);
330 unit->set_mac_address(unit);
331 unit->flags |= IFF_CONFIGURED;
333 else
335 request->ios2_Req.io_Error = S2ERR_BAD_STATE;
336 request->ios2_WireError = S2WERR_IS_CONFIGURED;
339 /* Return */
341 return TRUE;
344 static BOOL CmdBroadcast(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
346 /* Fill in the broadcast address as destination */
348 memset(request->ios2_DstAddr, 0xff, 6);
350 /* Queue the write as normal */
352 return CmdWrite(LIBBASE, request);
355 static BOOL CmdTrackType(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
357 struct NFUnit *unit;
358 struct Opener *opener;
359 ULONG packet_type, wire_error=0;
360 struct TypeTracker *tracker;
361 struct TypeStats *initial_stats;
362 BYTE error = 0;
364 unit = (APTR)request->ios2_Req.io_Unit;
365 packet_type = request->ios2_PacketType;
367 /* Get global tracker */
369 tracker = (struct TypeTracker *)
370 FindTypeStats(LIBBASE, unit, &unit->type_trackers, packet_type);
372 if(tracker != NULL)
373 tracker->user_count++;
374 else
376 tracker =
377 AllocMem(sizeof(struct TypeTracker), MEMF_PUBLIC|MEMF_CLEAR);
378 if(tracker != NULL)
380 tracker->packet_type = packet_type;
381 tracker->user_count = 1;
383 Disable();
384 AddTail((APTR)&unit->type_trackers, (APTR)tracker);
385 Enable();
389 /* Store initial figures for this opener */
391 opener = request->ios2_BufferManagement;
392 initial_stats = FindTypeStats(LIBBASE, unit, &opener->initial_stats, packet_type);
394 if(initial_stats != NULL)
396 error = S2ERR_BAD_STATE;
397 wire_error = S2WERR_ALREADY_TRACKED;
400 if(error == 0)
402 initial_stats = AllocMem(sizeof(struct TypeStats), MEMF_PUBLIC);
403 if(initial_stats == NULL)
405 error = S2ERR_NO_RESOURCES;
406 wire_error = S2WERR_GENERIC_ERROR;
410 if(error == 0)
412 CopyMem(tracker, initial_stats, sizeof(struct TypeStats));
413 AddTail((APTR)&opener->initial_stats, (APTR)initial_stats);
416 /* Return */
418 request->ios2_Req.io_Error = error;
419 request->ios2_WireError = wire_error;
420 return TRUE;
423 static BOOL CmdUntrackType(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
425 struct NFUnit *unit;
426 struct Opener *opener;
427 ULONG packet_type;
428 struct TypeTracker *tracker;
429 struct TypeStats *initial_stats;
431 unit = (APTR)request->ios2_Req.io_Unit;
432 packet_type = request->ios2_PacketType;
434 /* Get global tracker and initial figures */
436 tracker = (struct TypeTracker *)
437 FindTypeStats(LIBBASE, unit, &unit->type_trackers, packet_type);
438 opener = request->ios2_BufferManagement;
439 initial_stats = FindTypeStats(LIBBASE, unit, &opener->initial_stats, packet_type);
441 /* Decrement tracker usage and free unused structures */
443 if(initial_stats != NULL)
445 if((--tracker->user_count) == 0)
447 Disable();
448 Remove((APTR)tracker);
449 Enable();
450 FreeMem(tracker, sizeof(struct TypeTracker));
453 Remove((APTR)initial_stats);
454 FreeMem(initial_stats, sizeof(struct TypeStats));
456 else
458 request->ios2_Req.io_Error = S2ERR_BAD_STATE;
459 request->ios2_WireError = S2WERR_NOT_TRACKED;
462 /* Return */
464 return TRUE;
467 static BOOL CmdGetTypeStats(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
469 struct NFUnit *unit;
470 struct Opener *opener;
471 ULONG packet_type;
472 struct TypeStats *initial_stats, *tracker;
473 struct Sana2PacketTypeStats *stats;
475 unit = (APTR)request->ios2_Req.io_Unit;
476 packet_type = request->ios2_PacketType;
478 /* Get global tracker and initial figures */
480 tracker = FindTypeStats(LIBBASE, unit, &unit->type_trackers, packet_type);
481 opener = request->ios2_BufferManagement;
482 initial_stats = FindTypeStats(LIBBASE, unit, &opener->initial_stats, packet_type);
484 /* Copy and adjust figures */
485 if(initial_stats != NULL)
487 stats = request->ios2_StatData;
488 CopyMem(&tracker->stats, stats, sizeof(struct Sana2PacketTypeStats));
489 stats->PacketsSent -= initial_stats->stats.PacketsSent;
490 stats->PacketsReceived -= initial_stats->stats.PacketsReceived;
491 stats->BytesSent -= initial_stats->stats.BytesSent;
492 stats->BytesReceived -= initial_stats->stats.BytesReceived;
493 stats->PacketsDropped -= initial_stats->stats.PacketsDropped;
495 else
497 request->ios2_Req.io_Error = S2ERR_BAD_STATE;
498 request->ios2_WireError = S2WERR_NOT_TRACKED;
501 /* Return */
503 return TRUE;
506 static BOOL CmdGetGlobalStats(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
508 struct NFUnit *unit;
510 /* Update and copy stats */
512 unit = (APTR)request->ios2_Req.io_Unit;
513 CopyMem(&unit->stats, request->ios2_StatData,
514 sizeof(struct Sana2DeviceStats));
516 /* Return */
518 return TRUE;
521 static BOOL CmdDeviceQuery(LIBBASETYPEPTR LIBBASE, 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;
538 /* Return */
540 return TRUE;
543 static BOOL CmdOnEvent(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
545 struct NFUnit *unit;
546 ULONG events, wanted_events;
547 BOOL complete = FALSE;
549 /* Check if we understand the event types */
551 unit = (APTR)request->ios2_Req.io_Unit;
552 wanted_events = request->ios2_WireError;
553 if((wanted_events & ~KNOWN_EVENTS) != 0)
555 request->ios2_Req.io_Error = S2ERR_NOT_SUPPORTED;
556 events = S2WERR_BAD_EVENT;
558 else
560 if((unit->flags & IFF_UP) != 0)
561 events = S2EVENT_ONLINE;
562 else
563 events = S2EVENT_OFFLINE;
565 events &= wanted_events;
568 /* Reply request if a wanted event has already occurred */
570 if(events != 0)
572 request->ios2_WireError = events;
573 complete = TRUE;
575 else
577 request->ios2_Req.io_Flags &= ~IOF_QUICK;
578 PutMsg(unit->request_ports[EVENT_QUEUE], (APTR)request);
581 /* Return */
583 return complete;
586 static BOOL CmdReadOrphan(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
588 struct NFUnit *unit;
589 BYTE error = 0;
590 ULONG wire_error;
591 BOOL complete = FALSE;
593 /* Check request is valid */
595 unit = (APTR)request->ios2_Req.io_Unit;
596 if((unit->flags & IFF_UP) == 0)
598 error = S2ERR_OUTOFSERVICE;
599 wire_error = S2WERR_UNIT_OFFLINE;
602 /* Queue request */
604 if(error == 0)
606 request->ios2_Req.io_Flags &= ~IOF_QUICK;
607 PutMsg(unit->request_ports[ADOPT_QUEUE], (struct Message *)request);
609 else
611 request->ios2_Req.io_Error = error;
612 request->ios2_WireError = wire_error;
613 complete = TRUE;
616 /* Return */
618 return complete;
621 static BOOL CmdOnline(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
623 struct NFUnit *unit = (struct NFUnit *)request->ios2_Req.io_Unit;
624 BYTE error = 0;
625 ULONG wire_error = 0;
626 UWORD i;
628 /* Check request is valid */
629 if((unit->flags & IFF_CONFIGURED) == 0)
631 error = S2ERR_BAD_STATE;
632 wire_error = S2WERR_NOT_CONFIGURED;
635 /* Clear global and special stats and put adapter back online */
637 if((error == 0) && ((unit->flags & IFF_UP) == 0))
639 unit->stats.PacketsReceived = 0;
640 unit->stats.PacketsSent = 0;
641 unit->stats.BadData = 0;
642 unit->stats.Overruns = 0;
643 unit->stats.UnknownTypesReceived = 0;
644 unit->stats.Reconfigurations = 0;
646 for(i = 0; i < STAT_COUNT; i++)
647 unit->special_stats[i] = 0;
649 if (unit->start(unit))
651 error = S2ERR_OUTOFSERVICE;
652 wire_error = S2WERR_GENERIC_ERROR;
656 /* Return */
658 request->ios2_Req.io_Error = error;
659 request->ios2_WireError = wire_error;
660 return TRUE;
663 static BOOL CmdOffline(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
665 struct NFUnit *unit;
667 /* Put adapter offline */
669 unit = (APTR)request->ios2_Req.io_Unit;
670 if((unit->flags & IFF_UP) != 0)
671 unit->stop(unit);
673 /* Return */
674 return TRUE;
677 static BOOL CmdAddMulticastAddresses(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
679 struct NFUnit *unit;
680 UBYTE *lower_bound, *upper_bound;
682 unit = (APTR)request->ios2_Req.io_Unit;
684 lower_bound = request->ios2_SrcAddr;
685 if(request->ios2_Req.io_Command == S2_ADDMULTICASTADDRESS)
686 upper_bound = lower_bound;
687 else
688 upper_bound = request->ios2_DstAddr;
690 if(!AddMulticastRange(LIBBASE, unit, lower_bound, upper_bound))
692 request->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
693 request->ios2_WireError = S2WERR_GENERIC_ERROR;
696 /* Return */
698 return TRUE;
701 static BOOL CmdDelMulticastAddresses(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *request)
703 struct NFUnit *unit;
704 UBYTE *lower_bound, *upper_bound;
706 unit = (APTR)request->ios2_Req.io_Unit;
708 lower_bound = request->ios2_SrcAddr;
709 if(request->ios2_Req.io_Command == S2_DELMULTICASTADDRESS)
710 upper_bound = lower_bound;
711 else
712 upper_bound = request->ios2_DstAddr;
714 if(!RemMulticastRange(LIBBASE, unit, lower_bound, upper_bound))
716 request->ios2_Req.io_Error = S2ERR_BAD_STATE;
717 request->ios2_WireError = S2WERR_BAD_MULTICAST;
720 /* Return */
722 return TRUE;