ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/AmigaOS/ether_amiga.cpp
Revision: 1.10
Committed: 2001-07-15T02:34:23Z (23 years, 4 months ago) by cebix
Branch: MAIN
Changes since 1.9: +9 -16 lines
Log Message:
fixed indentation

File Contents

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