Disabling auto-refresh of game list by default, as it is causing bugs sometimes
[open-ps2-loader.git] / modules / wip / lanman / smap.c
blob4e4e89dbbd53c2770129ec4fa0c025954f01579b
1 /*
2 Copyright (c) 2010 jimmikaelkael <jimmikaelkael@wanadoo.fr>
3 Copyright (c) 2003 Marcus R. Brown <mrbrown@0xd6.org>
4 Licenced under Academic Free License version 3.0
5 Review OpenPS2Loader README & LICENSE files for further details.
7 Code originally based on SMAP driver sources found in UDPTTY driver.
8 Optimized mips functions from Eugene Plotnikov.
9 */
11 #include <tamtypes.h>
12 #include <stdio.h>
13 #include <thbase.h>
14 #include <thsemap.h>
15 #include <intrman.h>
16 #include <dev9.h>
17 #include <speedregs.h>
18 #include <dev9regs.h>
19 #include <smapregs.h>
21 #include "smsutils.h"
22 #include "smap.h"
23 #include "ip.h"
24 #include "arp.h"
25 #include "tcp.h"
26 #include "inet.h"
28 #define SMAP_RX_BUFSIZE 16384
29 #define SMAP_RX_BASE 0x4000
30 #define SMAP_RX_MINSIZE 14 // Ethernet header size
31 #define SMAP_RX_MAXSIZE (6+6+2+1500+4)
32 #define SMAP_TX_MAXSIZE (6+6+2+1500)
34 #define SMAP_BD_NEXT(x) (x)=(x)<(SMAP_BD_MAX_ENTRY-1) ? (x)+1:0
36 // TX descriptor
37 typedef struct {
38 u16 txwp_start;
39 u16 txwp_end;
40 u8 txbdi_start;
41 u8 txbdi_end;
42 } smap_tx_stat_t;
44 static smap_tx_stat_t tx_stat;
46 // RX descriptor
47 typedef struct {
48 u8 rxbdi; // Index into current RX BD
49 u8 pad[3];
50 } smap_rx_stat_t;
52 static smap_rx_stat_t rx_stat;
54 static int smap_xmit_mutex = -1;
56 static u8 rcpt_buf[SMAP_RX_MAXSIZE] __attribute__((aligned(64)));
58 //-------------------------------------------------------------------------
59 void smap_CopyToFIFO(u16, u32 *, int);
60 __asm__(
61 ".set noreorder\n\t"
62 ".set nomacro\n\t"
63 ".set noat\n\t"
64 ".text\n\t"
65 "smap_CopyToFIFO:\n\t"
66 "srl $at, $a2, 4\n\t"
67 "lui $v1, 0xB000\n\t"
68 "sh $a0, 4100($v1)\n\t"
69 "beqz $at, 3f\n\t"
70 "andi $a2, $a2, 0xF\n\t"
71 "4:\n\t"
72 "lwr $t0, 0($a1)\n\t"
73 "lwl $t0, 3($a1)\n\t"
74 "lwr $t1, 4($a1)\n\t"
75 "lwl $t1, 7($a1)\n\t"
76 "lwr $t2, 8($a1)\n\t"
77 "lwl $t2, 11($a1)\n\t"
78 "lwr $t3, 12($a1)\n\t"
79 "lwl $t3, 15($a1)\n\t"
80 "addiu $at, $at, -1\n\t"
81 "sw $t0, 4352($v1)\n\t"
82 "sw $t1, 4352($v1)\n\t"
83 "sw $t2, 4352($v1)\n\t"
84 "addiu $a1, $a1, 16\n\t"
85 "bgtz $at, 4b\n\t"
86 "sw $t3, 4352($v1)\n\t"
87 "3:\n\t"
88 "beqz $a2, 1f\n\t"
89 "nop\n\t"
90 "2:\n\t"
91 "lwr $v0, 0($a1)\n\t"
92 "lwl $v0, 3($a1)\n\t"
93 "addiu $a2, $a2, -4\n\t"
94 "sw $v0, 4352($v1)\n\t"
95 "bnez $a2, 2b\n\t"
96 "addiu $a1, $a1, 4\n\t"
97 "1:\n\t"
98 "jr $ra\n\t"
99 "nop\n\t"
100 ".set at\n\t"
101 ".set macro\n\t"
102 ".set reorder\n\t"
105 //-------------------------------------------------------------------------
106 void smap_CopyFromFIFO(u16, u32 *, int);
107 __asm__(
108 ".set noreorder\n\t"
109 ".set nomacro\n\t"
110 ".set noat\n\t"
111 ".text\n\t"
112 "smap_CopyFromFIFO:\n\t"
113 "li $v0, -4\n\t"
114 "lui $a3, 0xB000\n\t"
115 "addiu $v1, $a2, 3\n\t"
116 "and $v1, $v1, $v0\n\t"
117 "srl $at, $v1, 5\n\t"
118 "sh $a0, 4148($a3)\n\t"
119 "beqz $at, 3f\n\t"
120 "andi $v1, $v1, 0x1F\n\t"
121 "4:\n\t"
122 "lw $t0, 4608($a3)\n\t"
123 "lw $t1, 4608($a3)\n\t"
124 "lw $t2, 4608($a3)\n\t"
125 "lw $t3, 4608($a3)\n\t"
126 "lw $t4, 4608($a3)\n\t"
127 "lw $t5, 4608($a3)\n\t"
128 "lw $t6, 4608($a3)\n\t"
129 "lw $t7, 4608($a3)\n\t"
130 "addiu $at, $at, -1\n\t"
131 "sw $t0, 0($a1)\n\t"
132 "sw $t1, 4($a1)\n\t"
133 "sw $t2, 8($a1)\n\t"
134 "sw $t3, 12($a1)\n\t"
135 "sw $t4, 16($a1)\n\t"
136 "sw $t5, 20($a1)\n\t"
137 "sw $t6, 24($a1)\n\t"
138 "sw $t7, 28($a1)\n\t"
139 "bgtz $at, 4b\n\t"
140 "addiu $a1, $a1, 32\n\t"
141 "3:\n\t"
142 "beqz $v1, 1f\n\t"
143 "nop\n\t"
144 "2:\n\t"
145 "lw $v0, 4608($a3)\n\t"
146 "addiu $v1, $v1, -4\n\t"
147 "sw $v0, 0($a1)\n\t"
148 "bnez $v1, 2b\n\t"
149 "addiu $a1, $a1, 4\n\t"
150 "1:\n\t"
151 "jr $ra\n\t"
152 "nop\n\t"
153 ".set at\n\t"
154 ".set macro\n\t"
155 ".set reorder\n\t"
158 //-------------------------------------------------------------------------
159 static int smap_phy_read(int reg, u16 *data)
161 USE_SMAP_EMAC3_REGS;
162 u32 i, val;
164 val = SMAP_E3_PHY_READ|(SMAP_DsPHYTER_ADDRESS << SMAP_E3_PHY_ADDR_BITSFT)|
165 (reg & SMAP_E3_PHY_REG_ADDR_MSK);
166 SMAP_EMAC3_SET(SMAP_R_EMAC3_STA_CTRL, val);
168 // Wait for the read operation to complete
169 for (i = 0; i < 100; i++) {
170 if (SMAP_EMAC3_GET(SMAP_R_EMAC3_STA_CTRL) & SMAP_E3_PHY_OP_COMP)
171 break;
172 DelayThread(1000);
174 if (i == 100 || !data)
175 return 1;
177 *data = SMAP_EMAC3_GET(SMAP_R_EMAC3_STA_CTRL) >> SMAP_E3_PHY_DATA_BITSFT;
178 return 0;
181 //-------------------------------------------------------------------------
182 static int smap_phy_write(int reg, u16 data)
184 USE_SMAP_EMAC3_REGS;
185 u32 i, val;
187 val = ((data & SMAP_E3_PHY_DATA_MSK) << SMAP_E3_PHY_DATA_BITSFT)|
188 SMAP_E3_PHY_WRITE|(SMAP_DsPHYTER_ADDRESS << SMAP_E3_PHY_ADDR_BITSFT)|
189 (reg & SMAP_E3_PHY_REG_ADDR_MSK);
190 SMAP_EMAC3_SET(SMAP_R_EMAC3_STA_CTRL, val);
192 // Wait for the write operation to complete
193 for (i = 0; i < 100; i++) {
194 if (SMAP_EMAC3_GET(SMAP_R_EMAC3_STA_CTRL) & SMAP_E3_PHY_OP_COMP)
195 break;
196 DelayThread(1000);
198 return (i == 100);
201 //-------------------------------------------------------------------------
202 static int smap_phy_init(void)
204 USE_SMAP_EMAC3_REGS;
205 u32 val;
206 int i;
207 u16 phydata, idr1, idr2;
209 // Reset the PHY
210 smap_phy_write(SMAP_DsPHYTER_BMCR, SMAP_PHY_BMCR_RST);
211 // Wait for it to come out of reset
212 for (i = 9; i; i--) {
213 smap_phy_read(SMAP_DsPHYTER_BMCR, &phydata);
214 if (!(phydata & SMAP_PHY_BMCR_RST))
215 break;
216 DelayThread(1000);
218 if (!i)
219 return 1;
221 // Confirm link status
222 i = 5000;
223 while (--i) {
224 smap_phy_read(SMAP_DsPHYTER_BMSR, &phydata);
225 if (phydata & SMAP_PHY_BMSR_LINK)
226 break;
227 DelayThread(1000);
230 smap_phy_write(SMAP_DsPHYTER_BMCR, SMAP_PHY_BMCR_100M|SMAP_PHY_BMCR_DUPM);
232 i = 2000;
233 while (--i)
234 DelayThread(1000);
236 // Force 100 Mbps full duplex mode
237 val = SMAP_EMAC3_GET(SMAP_R_EMAC3_MODE1);
238 val |= (SMAP_E3_FDX_ENABLE|SMAP_E3_FLOWCTRL_ENABLE|SMAP_E3_ALLOW_PF);
239 val &= ~SMAP_E3_MEDIA_MSK;
240 val |= SMAP_E3_MEDIA_100M;
241 SMAP_EMAC3_SET(SMAP_R_EMAC3_MODE1, val);
243 // DSP setup
244 smap_phy_read(SMAP_DsPHYTER_PHYIDR1, &idr1);
245 smap_phy_read(SMAP_DsPHYTER_PHYIDR2, &idr2);
247 if (idr1 == SMAP_PHY_IDR1_VAL &&
248 ((idr2 & SMAP_PHY_IDR2_MSK) == SMAP_PHY_IDR2_VAL)) {
249 smap_phy_read(SMAP_DsPHYTER_PHYSTS, &phydata);
250 if (phydata & SMAP_PHY_STS_10M)
251 smap_phy_write(0x1a, 0x104);
253 smap_phy_write(0x13, 0x0001);
254 smap_phy_write(0x19, 0x1898);
255 smap_phy_write(0x1f, 0x0000);
256 smap_phy_write(0x1d, 0x5040);
257 smap_phy_write(0x1e, 0x008c);
258 smap_phy_write(0x13, 0x0000);
261 return 0;
264 //-------------------------------------------------------------------------
265 int smap_xmit(void *buf, int size)
267 USE_SMAP_REGS;
268 USE_SMAP_EMAC3_REGS;
269 USE_SMAP_TX_BD;
270 int txlen, r = 0;
272 WaitSema(smap_xmit_mutex);
274 // Get total length of the packet
275 if (size > SMAP_TX_MAXSIZE) {
276 r = 1;
277 goto ssema;
280 txlen = (size + 3) & 0xfffc;
282 // Get free mem in TX
283 int txfree = ((tx_stat.txwp_start > tx_stat.txwp_end) ? \
284 (SMAP_TX_BUFSIZE + tx_stat.txwp_end - tx_stat.txwp_start) : \
285 (SMAP_TX_BUFSIZE - tx_stat.txwp_end + tx_stat.txwp_start));
286 if (txlen > txfree) {
287 r = 2;
288 goto ssema;
291 // Check EMAC is ready
292 if (SMAP_EMAC3_GET(SMAP_R_EMAC3_TxMODE0) & SMAP_E3_TX_GNP_0) {
293 r = 2;
294 goto ssema;
297 // Send from mem -> FIFO
298 smap_CopyToFIFO(tx_stat.txwp_end, buf, txlen);
300 // FIFO -> ethernet
301 tx_bd[tx_stat.txbdi_end].length = size;
302 tx_bd[tx_stat.txbdi_end].pointer = tx_stat.txwp_end + SMAP_TX_BASE;
303 SMAP_REG8(SMAP_R_TXFIFO_FRAME_INC) = 1;
304 tx_bd[tx_stat.txbdi_end].ctrl_stat = SMAP_BD_TX_READY | SMAP_BD_TX_GENFCS | SMAP_BD_TX_GENPAD;
306 SMAP_EMAC3_SET(SMAP_R_EMAC3_TxMODE0, SMAP_E3_TX_GNP_0);
308 // Update tx pointers
309 tx_stat.txwp_end = (tx_stat.txwp_end + txlen) % SMAP_TX_BUFSIZE;
310 SMAP_BD_NEXT(tx_stat.txbdi_end);
312 ssema:
313 SignalSema(smap_xmit_mutex);
315 return r;
318 //-------------------------------------------------------------------------
319 static int smap_tx_intr(int irq)
321 USE_SMAP_REGS;
322 USE_SMAP_TX_BD;
323 register int txbdi, stat;
324 register int ret = 1;
326 // Clear irq
327 SMAP_REG16(SMAP_R_INTR_CLR) = irq & SMAP_INTR_BITMSK;
329 while (tx_stat.txbdi_start != tx_stat.txbdi_end) {
331 txbdi = tx_stat.txbdi_start;
332 stat = tx_bd[txbdi].ctrl_stat;
334 if (stat & SMAP_BD_TX_ERROR)
335 ret = 0;
337 if (stat & SMAP_BD_TX_READY)
338 goto out;
340 tx_stat.txwp_start = (tx_stat.txwp_start + ((tx_bd[txbdi].length + 3) & 0xfffc)) % SMAP_TX_BUFSIZE;
341 SMAP_BD_NEXT(tx_stat.txbdi_start);
343 tx_bd[txbdi].ctrl_stat = 0;
344 tx_bd[txbdi].reserved = 0;
345 tx_bd[txbdi].length = 0;
348 tx_stat.txbdi_start = tx_stat.txbdi_end;
350 out:
351 return ret;
354 //-------------------------------------------------------------------------
355 static int smap_rx_intr(int irq)
357 USE_SMAP_REGS;
358 USE_SMAP_RX_BD;
359 u16 len;
360 register int rxbdi, stat;
361 register int ret = 1;
363 // Clear irq
364 irq &= SMAP_INTR_RXDNV | SMAP_INTR_RXEND;
365 SMAP_REG16(SMAP_R_INTR_CLR) = irq & SMAP_INTR_BITMSK;
367 while (1) {
369 rxbdi = rx_stat.rxbdi;
370 stat = rx_bd[rxbdi].ctrl_stat;
372 if (stat & SMAP_BD_RX_EMPTY)
373 break;
375 len = rx_bd[rxbdi].length;
377 // check for BD error and packet size
378 if ((stat & SMAP_BD_RX_ERROR) || ((len < SMAP_RX_MINSIZE) || (len > SMAP_RX_MAXSIZE)))
379 ret = 0;
380 else {
381 u16 rxrp = ((rx_bd[rxbdi].pointer - SMAP_RX_BASE) % SMAP_RX_BUFSIZE) & 0xfffc;
382 // FIFO -> memory
383 smap_CopyFromFIFO(rxrp, (u32 *)rcpt_buf, len);
385 eth_hdr_t *eth = (eth_hdr_t *)rcpt_buf;
386 if (eth->type == 0x0008) { // IP packet
388 ip_hdr_t *ip = (ip_hdr_t *)&rcpt_buf[14];
389 if ((ip->hlen == 0x45) && (inet_chksum(ip, 20) == 0)) { // Check IPv4 & IP checksum
390 if ((!(ip->flags & 0x3f)) && (ip->frag_offset == 0)) { // Drop IP fragments
391 if (ip->proto == 0x06) // Check it's TCP packet
392 tcp_input(rcpt_buf, len);
396 else if (eth->type == 0x0608) { // ARP packet
397 arp_input(rcpt_buf, len);
398 // ARP packet is then dropped
402 SMAP_REG8(SMAP_R_RXFIFO_FRAME_DEC) = 1;
403 rx_bd[rxbdi].ctrl_stat = SMAP_BD_RX_EMPTY;
404 SMAP_BD_NEXT(rx_stat.rxbdi);
407 return ret;
410 //-------------------------------------------------------------------------
411 static int smap_emac3_intr(int irq)
413 USE_SMAP_REGS;
414 USE_SMAP_EMAC3_REGS;
415 register u32 stat;
417 stat = SMAP_EMAC3_GET(SMAP_R_EMAC3_INTR_STAT);
419 SMAP_EMAC3_SET(SMAP_R_EMAC3_INTR_STAT, stat);
421 // clear irq
422 SMAP_REG16(SMAP_R_INTR_CLR) = SMAP_INTR_EMAC3;
423 SMAP_EMAC3_SET(SMAP_R_EMAC3_INTR_STAT, SMAP_E3_INTR_ALL);
425 return 1;
428 //-------------------------------------------------------------------------
429 static int smap_intr_handler(int state)
431 USE_SPD_REGS;
432 register int irq;
434 irq = SPD_REG16(SPD_R_INTR_STAT) & SMAP_INTR_BITMSK;
436 if (irq & (SMAP_INTR_TXDNV | SMAP_INTR_TXEND)) { // TX intr
437 smap_tx_intr(irq & (SMAP_INTR_TXDNV | SMAP_INTR_TXEND));
438 irq = SPD_REG16(SPD_R_INTR_STAT) & SMAP_INTR_BITMSK;
441 if (irq & (SMAP_INTR_RXDNV | SMAP_INTR_RXEND)) // RX intr
442 smap_rx_intr(irq & (SMAP_INTR_RXDNV | SMAP_INTR_RXEND));
443 else if (irq & SMAP_INTR_EMAC3) // EMAC3 intr
444 smap_emac3_intr(irq & SMAP_INTR_EMAC3);
446 return 1;
449 //-------------------------------------------------------------------------
450 int smap_init(u8 *eth_addr_src)
452 USE_SPD_REGS;
453 USE_DEV9_REGS;
454 USE_SMAP_REGS;
455 USE_SMAP_EMAC3_REGS;
456 USE_SMAP_TX_BD; USE_SMAP_RX_BD;
457 u16 MAC[4];
458 u16 MACcsum = 0;
459 u8 hwaddr[6];
460 u32 val;
461 register int i;
463 // Check out the SPEED chip revision
464 if (!(SPD_REG16(SPD_R_REV_3) & SPD_CAPS_SMAP) || SPD_REG16(SPD_R_REV_1) <= 16)
465 return 1;
467 dev9IntrDisable(SMAP_INTR_BITMSK);
468 EnableIntr(IOP_IRQ_DEV9);
469 CpuEnableIntr();
471 // PCMCIA Card removed flag
472 DEV9_REG(DEV9_R_1464) = 0x03;
474 // Get HW MAC address and check it
475 if ((dev9GetEEPROM(&MAC[0]) < 0) || (!MAC[0] && !MAC[1] && !MAC[2]))
476 return 1;
477 for (i=0; i<3; i++)
478 MACcsum += MAC[i];
479 if (MACcsum != MAC[3])
480 return 1;
481 mips_memcpy(eth_addr_src, &MAC[0], 6);
483 // Disable TX/RX
484 val = SMAP_EMAC3_GET(SMAP_R_EMAC3_MODE0);
485 val &= ~(SMAP_E3_TXMAC_ENABLE|SMAP_E3_RXMAC_ENABLE);
486 SMAP_EMAC3_SET(SMAP_R_EMAC3_MODE0, val);
488 // Disable all EMAC3 interrupts
489 SMAP_EMAC3_SET(SMAP_R_EMAC3_INTR_ENABLE, 0);
491 // Reset the transmit FIFO
492 SMAP_REG8(SMAP_R_TXFIFO_CTRL) = SMAP_TXFIFO_RESET;
493 for (i = 9; i; i--) {
494 if (!(SMAP_REG8(SMAP_R_TXFIFO_CTRL) & SMAP_TXFIFO_RESET))
495 break;
496 DelayThread(1000);
498 if (!i)
499 return 2;
501 // Reset the receive FIFO
502 SMAP_REG8(SMAP_R_RXFIFO_CTRL) = SMAP_RXFIFO_RESET;
503 for (i = 9; i; i--) {
504 if (!(SMAP_REG8(SMAP_R_RXFIFO_CTRL) & SMAP_RXFIFO_RESET))
505 break;
506 DelayThread(1000);
508 if (!i)
509 return 3;
511 // Perform soft reset of EMAC3
512 SMAP_EMAC3_SET(SMAP_R_EMAC3_MODE0, SMAP_E3_SOFT_RESET);
513 for (i = 9; i; i--) {
514 if (!(SMAP_EMAC3_GET(SMAP_R_EMAC3_MODE0) & SMAP_E3_SOFT_RESET))
515 break;
516 DelayThread(1000);
518 if (!i)
519 return 4;
521 SMAP_REG8(SMAP_R_BD_MODE) = 0;
523 // Initialize all RX and TX buffer descriptors
524 for (i = 0; i < SMAP_BD_MAX_ENTRY; i++, tx_bd++) {
525 tx_bd->ctrl_stat = 0;
526 tx_bd->reserved = 0;
527 tx_bd->length = 0;
528 tx_bd->pointer = 0;
530 for (i = 0; i < SMAP_BD_MAX_ENTRY; i++, rx_bd++) {
531 rx_bd->ctrl_stat = SMAP_BD_RX_EMPTY;
532 rx_bd->reserved = 0;
533 rx_bd->length = 0;
534 rx_bd->pointer = 0;
537 // Clear all irq
538 SMAP_REG16(SMAP_R_INTR_CLR) = SMAP_INTR_BITMSK;
540 // EMAC3 operating MODE
541 val = SMAP_E3_FDX_ENABLE|SMAP_E3_IGNORE_SQE|SMAP_E3_MEDIA_100M|
542 SMAP_E3_RXFIFO_2K|SMAP_E3_TXFIFO_1K|SMAP_E3_TXREQ0_SINGLE|SMAP_E3_TXREQ1_SINGLE;
543 SMAP_EMAC3_SET(SMAP_R_EMAC3_MODE1, val);
545 // TX fifo value for request priority. low = 7*8=56, urgent = 15*8=120.
546 val = (7 << SMAP_E3_TX_LOW_REQ_BITSFT) | (15 << SMAP_E3_TX_URG_REQ_BITSFT);
547 SMAP_EMAC3_SET(SMAP_R_EMAC3_TxMODE1, val);
549 // RX mode
550 val = SMAP_E3_RX_STRIP_PAD|SMAP_E3_RX_STRIP_FCS|SMAP_E3_RX_INDIVID_ADDR|SMAP_E3_RX_BCAST;
551 SMAP_EMAC3_SET(SMAP_R_EMAC3_RxMODE, val);
553 // Set HW MAC address
554 mips_memcpy(hwaddr, eth_addr_src, 6);
555 val = (u16)((hwaddr[0] << 8)|hwaddr[1]);
556 SMAP_EMAC3_SET(SMAP_R_EMAC3_ADDR_HI, val);
557 val = ((hwaddr[2] << 24)|(hwaddr[3] << 16)|(hwaddr[4] << 8)|hwaddr[5]);
558 SMAP_EMAC3_SET(SMAP_R_EMAC3_ADDR_LO, val);
560 // Inter-frame GAP
561 SMAP_EMAC3_SET(SMAP_R_EMAC3_INTER_FRAME_GAP, 4);
563 // TX threshold
564 val = 12 << SMAP_E3_TX_THRESHLD_BITSFT;
565 SMAP_EMAC3_SET(SMAP_R_EMAC3_TX_THRESHOLD, val);
567 // RX watermark, low = 16*8=128, hi = 128*8=1024
568 val = (16 << SMAP_E3_RX_LO_WATER_BITSFT) | (128 << SMAP_E3_RX_HI_WATER_BITSFT);
569 SMAP_EMAC3_SET(SMAP_R_EMAC3_RX_WATERMARK, val);
571 // Enable all EMAC3 interrupts
572 SMAP_EMAC3_SET(SMAP_R_EMAC3_INTR_ENABLE, SMAP_E3_INTR_ALL);
574 // Initialize the PHY
575 if ((i = smap_phy_init()) != 0)
576 return -i;
578 tx_stat.txwp_start = tx_stat.txwp_end = 0;
579 tx_stat.txbdi_start = tx_stat.txbdi_end = 0;
580 rx_stat.rxbdi = 0;
582 // Install the smap_intr_handler for all the SMAP interrupts
583 for (i=2; i<7; i++)
584 dev9RegisterIntrCb(i, smap_intr_handler);
586 // Enable TX/RX
587 SMAP_EMAC3_SET(SMAP_R_EMAC3_MODE0, SMAP_E3_TXMAC_ENABLE|SMAP_E3_RXMAC_ENABLE);
588 DelayThread(10000);
590 dev9IntrEnable(SMAP_INTR_BITMSK);
592 smap_xmit_mutex = CreateMutex(IOP_MUTEX_UNLOCKED);
594 return 0;