ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/AmigaOS/ether_amiga.cpp
Revision: 1.13
Committed: 2008-01-01T09:40:31Z (16 years, 10 months ago) by gbeauche
Branch: MAIN
CVS Tags: HEAD
Changes since 1.12: +1 -1 lines
Log Message:
Happy New Year!

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * ether_amiga.cpp - Ethernet device driver, AmigaOS specific stuff
3     *
4 gbeauche 1.13 * Basilisk II (C) 1997-2008 Christian Bauer
5 cebix 1.1 *
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.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
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, MA 02111-1307 USA
19     */
20    
21     #include <exec/types.h>
22     #include <exec/memory.h>
23     #include <exec/errors.h>
24     #include <dos/dos.h>
25     #include <dos/dosextens.h>
26     #include <dos/dostags.h>
27     #include <devices/sana2.h>
28 jlachmann 1.12 #define __USE_SYSBASE
29 cebix 1.1 #include <proto/exec.h>
30     #include <proto/dos.h>
31 jlachmann 1.12 #include <inline/exec.h>
32     #include <inline/dos.h>
33     #include <clib/alib_protos.h>
34 cebix 1.1
35     #include "sysdeps.h"
36     #include "cpu_emulation.h"
37     #include "main.h"
38     #include "prefs.h"
39     #include "user_strings.h"
40     #include "macos_util.h"
41     #include "ether.h"
42     #include "ether_defs.h"
43    
44     #define DEBUG 0
45     #include "debug.h"
46    
47     #define MONITOR 0
48    
49    
50     // These messages are sent to the network process
51     const uint32 MSG_CLEANUP = 'clea'; // Remove all protocols
52     const uint32 MSG_ADD_MULTI = 'addm'; // Add multicast address
53     const uint32 MSG_DEL_MULTI = 'delm'; // Add multicast address
54     const uint32 MSG_ATTACH_PH = 'atph'; // Attach protocol handler
55     const uint32 MSG_DETACH_PH = 'deph'; // Attach protocol handler
56     const uint32 MSG_WRITE = 'writ'; // Write packet
57    
58     struct NetMessage : public Message {
59     NetMessage(uint32 what_, const struct MsgPort *reply_port)
60     {
61     what = what_;
62     mn_ReplyPort = (struct MsgPort *)reply_port;
63     mn_Length = sizeof(*this);
64     }
65     uint32 what;
66     uint32 pointer;
67     uint16 type;
68     int16 result;
69     };
70    
71    
72     // List of attached protocols
73     static const int NUM_READ_REQUESTS = 32; // Number of read requests that are sent to device in advance
74    
75     struct NetProtocol : public Node {
76     struct IOSana2Req read_io[NUM_READ_REQUESTS];
77     uint8 read_buf[NUM_READ_REQUESTS][1518]; // 14 bytes header, 1500 bytes data, 4 bytes CRC
78     uint16 type;
79     uint32 handler;
80     };
81    
82     static struct List prot_list;
83    
84    
85     // Global variables
86     static struct Process *net_proc = NULL; // Network device handler process
87     static bool proc_error; // Flag: process didn't initialize
88     static struct MsgPort *proc_port = NULL; // Message port of process, for communication with main task
89     static struct MsgPort *reply_port = NULL; // Reply port for communication with process
90     static struct MsgPort *read_port = NULL; // Reply port for read IORequests (set up and owned by network process)
91    
92     static bool write_done = false; // Flag: write request done
93    
94     extern struct Task *MainTask; // Pointer to main task (from main_amiga.cpp)
95    
96    
97     // Prototypes
98     static void net_func(void);
99    
100    
101     /*
102     * Send message to network process
103     */
104    
105     static int16 send_to_proc(uint32 what, uint32 pointer = 0, uint16 type = 0)
106     {
107     D(bug("sending %08lx to net_proc\n", what));
108     NetMessage msg(what, reply_port);
109     msg.pointer = pointer;
110     msg.type = type;
111     PutMsg(proc_port, &msg);
112     WaitPort(reply_port);
113     GetMsg(reply_port);
114     D(bug(" sent\n"));
115     return msg.result;
116     }
117    
118    
119     /*
120     * Initialization
121     */
122    
123 cebix 1.7 bool ether_init(void)
124 cebix 1.1 {
125     // Do nothing if no Ethernet device specified
126     if (PrefsFindString("ether") == NULL)
127 cebix 1.7 return false;
128 cebix 1.1
129     // Initialize protocol list
130     NewList(&prot_list);
131    
132     // Create message port
133     reply_port = CreateMsgPort();
134     if (reply_port == NULL)
135     goto open_error;
136     D(bug("signal mask %08lx\n", 1 << reply_port->mp_SigBit));
137    
138     // Start process
139     proc_error = false;
140     SetSignal(0, SIGF_SINGLE);
141     net_proc = CreateNewProcTags(
142 cebix 1.2 NP_Entry, (ULONG)net_func,
143     NP_Name, (ULONG)"Basilisk II Ethernet Task",
144 cebix 1.1 NP_Priority, 1,
145     TAG_END
146     );
147     if (net_proc == NULL)
148     goto open_error;
149    
150     // Wait for signal from process
151     Wait(SIGF_SINGLE);
152    
153     // Initialization error? Then bail out
154     if (proc_error)
155     goto open_error;
156    
157     // Everything OK
158 cebix 1.7 return true;
159 cebix 1.1
160     open_error:
161     net_proc = NULL;
162     if (reply_port) {
163     DeleteMsgPort(reply_port);
164     reply_port = NULL;
165     }
166 cebix 1.7 return false;
167 cebix 1.1 }
168    
169    
170     /*
171     * Deinitialization
172     */
173    
174 cebix 1.7 void ether_exit(void)
175 cebix 1.1 {
176     // Stop process
177     if (net_proc) {
178     SetSignal(0, SIGF_SINGLE);
179     Signal(&net_proc->pr_Task, SIGBREAKF_CTRL_C);
180     Wait(SIGF_SINGLE);
181     }
182    
183     // Delete reply port
184     if (reply_port) {
185     DeleteMsgPort(reply_port);
186     reply_port = NULL;
187     }
188     }
189    
190    
191     /*
192     * Reset
193     */
194    
195 cebix 1.8 void ether_reset(void)
196 cebix 1.1 {
197     // Remove all protocols
198 cebix 1.7 if (net_proc)
199 cebix 1.1 send_to_proc(MSG_CLEANUP);
200     }
201    
202    
203     /*
204     * Add multicast address
205     */
206    
207     int16 ether_add_multicast(uint32 pb)
208     {
209     return send_to_proc(MSG_ADD_MULTI, pb);
210     }
211    
212    
213     /*
214     * Delete multicast address
215     */
216    
217     int16 ether_del_multicast(uint32 pb)
218     {
219     return send_to_proc(MSG_DEL_MULTI, pb);
220     }
221    
222    
223     /*
224     * Attach protocol handler
225     */
226    
227     int16 ether_attach_ph(uint16 type, uint32 handler)
228     {
229     return send_to_proc(MSG_ATTACH_PH, handler, type);
230     }
231    
232    
233     /*
234     * Detach protocol handler
235     */
236    
237     int16 ether_detach_ph(uint16 type)
238     {
239     return send_to_proc(MSG_DETACH_PH, type);
240     }
241    
242    
243     /*
244     * Transmit raw ethernet packet
245     */
246    
247     int16 ether_write(uint32 wds)
248     {
249     send_to_proc(MSG_WRITE, wds);
250     return 1; // Command in progress
251     }
252    
253    
254     /*
255     * Remove protocol from protocol list
256     */
257    
258     static void remove_protocol(NetProtocol *p)
259     {
260     // Remove from list
261     Forbid();
262     Remove(p);
263     Permit();
264    
265     // Cancel read requests
266     for (int i=0; i<NUM_READ_REQUESTS; i++) {
267     AbortIO((struct IORequest *)(p->read_io + i));
268     WaitIO((struct IORequest *)(p->read_io + i));
269     }
270    
271     // Free protocol struct
272     FreeMem(p, sizeof(NetProtocol));
273     }
274    
275    
276     /*
277     * Remove all protocols
278     */
279    
280     static void remove_all_protocols(void)
281     {
282     NetProtocol *n = (NetProtocol *)prot_list.lh_Head, *next;
283     while ((next = (NetProtocol *)n->ln_Succ) != NULL) {
284     remove_protocol(n);
285     n = next;
286     }
287     }
288    
289    
290     /*
291     * Copy received network packet to Mac side
292     */
293    
294 cebix 1.2 static __saveds __regargs LONG copy_to_buff(uint8 *to /*a0*/, uint8 *from /*a1*/, uint32 packet_len /*d0*/)
295 cebix 1.1 {
296     D(bug("CopyToBuff to %08lx, from %08lx, size %08lx\n", to, from, packet_len));
297    
298     // It would be more efficient (and take up less memory) if we
299     // could invoke the packet handler from here. But we don't know
300     // in what context we run, so calling Execute68k() would not be
301     // a good idea, and even worse, we might run inside a hardware
302     // interrupt, so we can't even trigger a Basilisk interrupt from
303     // here and wait for its completion.
304     CopyMem(from, to, packet_len);
305     #if MONITOR
306     bug("Receiving Ethernet packet:\n");
307     for (int i=0; i<packet_len; i++) {
308     bug("%02lx ", from[i]);
309     }
310     bug("\n");
311     #endif
312     return 1;
313     }
314    
315    
316     /*
317     * Copy data from Mac WDS to outgoing network packet
318     */
319    
320 cebix 1.2 static __saveds __regargs LONG copy_from_buff(uint8 *to /*a0*/, char *wds /*a1*/, uint32 packet_len /*d0*/)
321 cebix 1.1 {
322     D(bug("CopyFromBuff to %08lx, wds %08lx, size %08lx\n", to, wds, packet_len));
323     #if MONITOR
324     bug("Sending Ethernet packet:\n");
325     #endif
326     for (;;) {
327 cebix 1.2 int len = ReadMacInt16((uint32)wds);
328 cebix 1.1 if (len == 0)
329     break;
330     #if MONITOR
331 cebix 1.2 uint8 *adr = Mac2HostAddr(ReadMacInt32((uint32)wds + 2));
332 cebix 1.1 for (int i=0; i<len; i++) {
333     bug("%02lx ", adr[i]);
334     }
335     #endif
336 cebix 1.2 CopyMem(Mac2HostAddr(ReadMacInt32((uint32)wds + 2)), to, len);
337 cebix 1.1 to += len;
338     wds += 6;
339     }
340     #if MONITOR
341     bug("\n");
342     #endif
343     return 1;
344     }
345    
346    
347     /*
348     * Process for communication with the Ethernet device
349     */
350    
351     static __saveds void net_func(void)
352     {
353 jlachmann 1.5 const char *str;
354     BYTE od_error;
355 cebix 1.1 struct MsgPort *write_port = NULL, *control_port = NULL;
356     struct IOSana2Req *write_io = NULL, *control_io = NULL;
357     bool opened = false;
358     ULONG read_mask = 0, write_mask = 0, proc_port_mask = 0;
359     struct Sana2DeviceQuery query_data = {sizeof(Sana2DeviceQuery)};
360     ULONG buffer_tags[] = {
361     S2_CopyToBuff, (uint32)copy_to_buff,
362     S2_CopyFromBuff, (uint32)copy_from_buff,
363     TAG_END
364     };
365    
366     // Default: error occured
367     proc_error = true;
368    
369     // Create message port for communication with main task
370     proc_port = CreateMsgPort();
371     if (proc_port == NULL)
372     goto quit;
373     proc_port_mask = 1 << proc_port->mp_SigBit;
374    
375     // Create message ports for device I/O
376     read_port = CreateMsgPort();
377     if (read_port == NULL)
378     goto quit;
379     read_mask = 1 << read_port->mp_SigBit;
380     write_port = CreateMsgPort();
381     if (write_port == NULL)
382     goto quit;
383     write_mask = 1 << write_port->mp_SigBit;
384     control_port = CreateMsgPort();
385     if (control_port == NULL)
386     goto quit;
387    
388     // Create control IORequest
389     control_io = (struct IOSana2Req *)CreateIORequest(control_port, sizeof(struct IOSana2Req));
390     if (control_io == NULL)
391     goto quit;
392     control_io->ios2_Req.io_Message.mn_Node.ln_Type = 0; // Avoid CheckIO() bug
393    
394     // Parse device name
395     char dev_name[256];
396     ULONG dev_unit;
397 jlachmann 1.5
398     str = PrefsFindString("ether");
399 cebix 1.10 if (str) {
400 jlachmann 1.5 const char *FirstSlash = strchr(str, '/');
401     const char *LastSlash = strrchr(str, '/');
402    
403 cebix 1.10 if (FirstSlash && FirstSlash && FirstSlash != LastSlash) {
404    
405 jlachmann 1.5 // Device name contains path, i.e. "Networks/xyzzy.device"
406     const char *lp = str;
407     char *dp = dev_name;
408    
409     while (lp != LastSlash)
410     *dp++ = *lp++;
411     *dp = '\0';
412    
413     if (strlen(dev_name) < 1)
414     goto quit;
415    
416 cebix 1.10 if (sscanf(LastSlash, "/%ld", &dev_unit) != 1)
417 jlachmann 1.5 goto quit;
418 cebix 1.10 } else {
419     if (sscanf(str, "%[^/]/%ld", dev_name, &dev_unit) != 2)
420 jlachmann 1.5 goto quit;
421     }
422 cebix 1.10 } else
423 cebix 1.1 goto quit;
424    
425     // Open device
426     control_io->ios2_BufferManagement = buffer_tags;
427 jlachmann 1.12 od_error = OpenDevice((UBYTE *) dev_name, dev_unit, (struct IORequest *)control_io, 0);
428 cebix 1.10 if (od_error != 0 || control_io->ios2_Req.io_Device == 0) {
429 jlachmann 1.5 printf("WARNING: OpenDevice(<%s>, unit=%d) returned error %d)\n", (UBYTE *)dev_name, dev_unit, od_error);
430 cebix 1.1 goto quit;
431 cebix 1.10 }
432 cebix 1.1 opened = true;
433    
434     // Is it Ethernet?
435     control_io->ios2_Req.io_Command = S2_DEVICEQUERY;
436     control_io->ios2_StatData = (void *)&query_data;
437     DoIO((struct IORequest *)control_io);
438     if (control_io->ios2_Req.io_Error)
439     goto quit;
440     if (query_data.HardwareType != S2WireType_Ethernet) {
441     WarningAlert(GetString(STR_NOT_ETHERNET_WARN));
442     goto quit;
443     }
444    
445     // Yes, create IORequest for writing
446     write_io = (struct IOSana2Req *)CreateIORequest(write_port, sizeof(struct IOSana2Req));
447     if (write_io == NULL)
448     goto quit;
449     memcpy(write_io, control_io, sizeof(struct IOSana2Req));
450     write_io->ios2_Req.io_Message.mn_Node.ln_Type = 0; // Avoid CheckIO() bug
451     write_io->ios2_Req.io_Message.mn_ReplyPort = write_port;
452    
453     // Configure Ethernet
454     control_io->ios2_Req.io_Command = S2_GETSTATIONADDRESS;
455     DoIO((struct IORequest *)control_io);
456     memcpy(ether_addr, control_io->ios2_DstAddr, 6);
457     memcpy(control_io->ios2_SrcAddr, control_io->ios2_DstAddr, 6);
458     control_io->ios2_Req.io_Command = S2_CONFIGINTERFACE;
459     DoIO((struct IORequest *)control_io);
460     D(bug("Ethernet address %08lx %08lx\n", *(uint32 *)ether_addr, *(uint16 *)(ether_addr + 4)));
461    
462     // Initialization went well, inform main task
463     proc_error = false;
464     Signal(MainTask, SIGF_SINGLE);
465    
466     // Main loop
467     for (;;) {
468    
469     // Wait for I/O and messages (CTRL_C is used for quitting the task)
470     ULONG sig = Wait(proc_port_mask | read_mask | write_mask | SIGBREAKF_CTRL_C);
471    
472     // Main task wants to quit us
473     if (sig & SIGBREAKF_CTRL_C)
474     break;
475    
476     // Main task sent a command to us
477     if (sig & proc_port_mask) {
478     struct NetMessage *msg;
479     while (msg = (NetMessage *)GetMsg(proc_port)) {
480     D(bug("net_proc received %08lx\n", msg->what));
481     switch (msg->what) {
482     case MSG_CLEANUP:
483     remove_all_protocols();
484     break;
485    
486     case MSG_ADD_MULTI:
487     control_io->ios2_Req.io_Command = S2_ADDMULTICASTADDRESS;
488 cebix 1.3 Mac2Host_memcpy(control_io->ios2_SrcAddr, msg->pointer + eMultiAddr, 6);
489 cebix 1.1 DoIO((struct IORequest *)control_io);
490     if (control_io->ios2_Req.io_Error == S2ERR_NOT_SUPPORTED) {
491     WarningAlert(GetString(STR_NO_MULTICAST_WARN));
492     msg->result = noErr;
493     } else if (control_io->ios2_Req.io_Error)
494     msg->result = eMultiErr;
495     else
496     msg->result = noErr;
497     break;
498    
499     case MSG_DEL_MULTI:
500     control_io->ios2_Req.io_Command = S2_DELMULTICASTADDRESS;
501 cebix 1.3 Mac2Host_memcpy(control_io->ios2_SrcAddr, msg->pointer + eMultiAddr, 6);
502 cebix 1.1 DoIO((struct IORequest *)control_io);
503     if (control_io->ios2_Req.io_Error)
504     msg->result = eMultiErr;
505     else
506     msg->result = noErr;
507     break;
508    
509     case MSG_ATTACH_PH: {
510     uint16 type = msg->type;
511     uint32 handler = msg->pointer;
512    
513     // Protocol of that type already installed?
514     NetProtocol *p = (NetProtocol *)prot_list.lh_Head, *next;
515     while ((next = (NetProtocol *)p->ln_Succ) != NULL) {
516     if (p->type == type) {
517     msg->result = lapProtErr;
518     goto reply;
519     }
520     p = next;
521     }
522    
523     // Allocate NetProtocol, set type and handler
524     p = (NetProtocol *)AllocMem(sizeof(NetProtocol), MEMF_PUBLIC);
525     if (p == NULL) {
526     msg->result = lapProtErr;
527     goto reply;
528     }
529     p->type = type;
530     p->handler = handler;
531    
532     // Set up and submit read requests
533     for (int i=0; i<NUM_READ_REQUESTS; i++) {
534     memcpy(p->read_io + i, control_io, sizeof(struct IOSana2Req));
535     p->read_io[i].ios2_Req.io_Message.mn_Node.ln_Name = (char *)p; // Hide pointer to NetProtocol in node name
536     p->read_io[i].ios2_Req.io_Message.mn_Node.ln_Type = 0; // Avoid CheckIO() bug
537     p->read_io[i].ios2_Req.io_Message.mn_ReplyPort = read_port;
538     p->read_io[i].ios2_Req.io_Command = CMD_READ;
539     p->read_io[i].ios2_PacketType = type;
540     p->read_io[i].ios2_Data = p->read_buf[i];
541     p->read_io[i].ios2_Req.io_Flags = SANA2IOF_RAW;
542     BeginIO((struct IORequest *)(p->read_io + i));
543     }
544    
545     // Add protocol to list
546     AddTail(&prot_list, p);
547    
548     // Everything OK
549     msg->result = noErr;
550     break;
551     }
552    
553     case MSG_DETACH_PH: {
554     uint16 type = msg->type;
555     msg->result = lapProtErr;
556     NetProtocol *p = (NetProtocol *)prot_list.lh_Head, *next;
557     while ((next = (NetProtocol *)p->ln_Succ) != NULL) {
558     if (p->type == type) {
559     remove_protocol(p);
560     msg->result = noErr;
561     break;
562     }
563     p = next;
564     }
565     break;
566     }
567    
568     case MSG_WRITE: {
569     // Get pointer to Write Data Structure
570     uint32 wds = msg->pointer;
571     write_io->ios2_Data = (void *)wds;
572    
573     // Calculate total packet length
574     long len = 0;
575     uint32 tmp = wds;
576     for (;;) {
577     int16 w = ReadMacInt16(tmp);
578     if (w == 0)
579     break;
580     len += w;
581     tmp += 6;
582     }
583     write_io->ios2_DataLength = len;
584    
585 cebix 1.9 // Get destination address
586 cebix 1.1 uint32 hdr = ReadMacInt32(wds + 2);
587 cebix 1.3 Mac2Host_memcpy(write_io->ios2_DstAddr, hdr, 6);
588 cebix 1.1
589     // Get packet type
590     uint32 type = ReadMacInt16(hdr + 12);
591     if (type <= 1500)
592     type = 0; // 802.3 packet
593     write_io->ios2_PacketType = type;
594    
595     // Multicast/broadcard packet?
596     if (write_io->ios2_DstAddr[0] & 1) {
597     if (*(uint32 *)(write_io->ios2_DstAddr) == 0xffffffff && *(uint16 *)(write_io->ios2_DstAddr + 4) == 0xffff)
598     write_io->ios2_Req.io_Command = S2_BROADCAST;
599     else
600     write_io->ios2_Req.io_Command = S2_MULTICAST;
601     } else
602     write_io->ios2_Req.io_Command = CMD_WRITE;
603    
604     // Send packet
605     write_done = false;
606     write_io->ios2_Req.io_Flags = SANA2IOF_RAW;
607     BeginIO((IORequest *)write_io);
608     break;
609     }
610     }
611     reply: D(bug(" net_proc replying\n"));
612     ReplyMsg(msg);
613     }
614     }
615    
616     // Packet received
617     if (sig & read_mask) {
618     D(bug(" packet received, triggering Ethernet interrupt\n"));
619     SetInterruptFlag(INTFLAG_ETHER);
620     TriggerInterrupt();
621     }
622    
623     // Packet write completed
624     if (sig & write_mask) {
625     GetMsg(write_port);
626     WriteMacInt32(ether_data + ed_Result, write_io->ios2_Req.io_Error ? excessCollsns : 0);
627     write_done = true;
628     D(bug(" packet write done, triggering Ethernet interrupt\n"));
629     SetInterruptFlag(INTFLAG_ETHER);
630     TriggerInterrupt();
631     }
632     }
633     quit:
634    
635     // Close everything
636     remove_all_protocols();
637     if (opened) {
638     if (CheckIO((struct IORequest *)write_io) == 0) {
639     AbortIO((struct IORequest *)write_io);
640     WaitIO((struct IORequest *)write_io);
641     }
642     CloseDevice((struct IORequest *)control_io);
643     }
644     if (write_io)
645     DeleteIORequest(write_io);
646     if (control_io)
647     DeleteIORequest(control_io);
648     if (control_port)
649     DeleteMsgPort(control_port);
650     if (write_port)
651     DeleteMsgPort(write_port);
652     if (read_port)
653     DeleteMsgPort(read_port);
654    
655     // Send signal to main task to confirm termination
656     Forbid();
657     Signal(MainTask, SIGF_SINGLE);
658     }
659    
660    
661     /*
662     * Ethernet interrupt - activate deferred tasks to call IODone or protocol handlers
663     */
664    
665     void EtherInterrupt(void)
666     {
667     D(bug("EtherIRQ\n"));
668    
669     // Packet write done, enqueue DT to call IODone
670     if (write_done) {
671 cebix 1.2 EnqueueMac(ether_data + ed_DeferredTask, 0xd92);
672 cebix 1.1 write_done = false;
673     }
674    
675     // Call protocol handler for received packets
676     IOSana2Req *io;
677     while (io = (struct IOSana2Req *)GetMsg(read_port)) {
678    
679     // Get pointer to NetProtocol (hidden in node name)
680     NetProtocol *p = (NetProtocol *)io->ios2_Req.io_Message.mn_Node.ln_Name;
681    
682     // No default handler
683     if (p->handler == 0)
684     continue;
685    
686     // Copy header to RHA
687 cebix 1.3 Host2Mac_memcpy(ether_data + ed_RHA, io->ios2_Data, 14);
688 cebix 1.1 D(bug(" header %08lx%04lx %08lx%04lx %04lx\n", ReadMacInt32(ether_data + ed_RHA), ReadMacInt16(ether_data + ed_RHA + 4), ReadMacInt32(ether_data + ed_RHA + 6), ReadMacInt16(ether_data + ed_RHA + 10), ReadMacInt16(ether_data + ed_RHA + 12)));
689    
690     // Call protocol handler
691     M68kRegisters r;
692     r.d[0] = *(uint16 *)((uint32)io->ios2_Data + 12); // Packet type
693     r.d[1] = io->ios2_DataLength - 18; // Remaining packet length (without header, for ReadPacket) (-18 because the CRC is also included)
694     r.a[0] = (uint32)io->ios2_Data + 14; // Pointer to packet (host address, for ReadPacket)
695     r.a[3] = ether_data + ed_RHA + 14; // Pointer behind header in RHA
696     r.a[4] = ether_data + ed_ReadPacket; // Pointer to ReadPacket/ReadRest routines
697     D(bug(" calling protocol handler %08lx, type %08lx, length %08lx, data %08lx, rha %08lx, read_packet %08lx\n", p->handler, r.d[0], r.d[1], r.a[0], r.a[3], r.a[4]));
698     Execute68k(p->handler, &r);
699    
700     // Resend IORequest
701     io->ios2_Req.io_Flags = SANA2IOF_RAW;
702     BeginIO((struct IORequest *)io);
703     }
704     D(bug(" EtherIRQ done\n"));
705     }