PS2SDK
PS2 Homebrew Libraries
Loading...
Searching...
No Matches
spduart.c
1/*
2# _____ ___ ____ ___ ____
3# ____| | ____| | | |____|
4# | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5#-----------------------------------------------------------------------
6# Copyright ps2dev - http://www.ps2dev.org
7# Licenced under Academic Free License version 2.0
8# Review ps2sdk README & LICENSE files for further details.
9*/
10
11#include <ctype.h>
12#include <irx_imports.h>
13#include <speedregs.h>
14
15#define MODNAME "INET_SPEED_UART_driver"
16
17// Based off of the module from SDK 3.1.0
18IRX_ID(MODNAME, 0x2, 0x1A);
19
20extern struct irx_export_table _exp_spduart;
21
22// 16550 compatible UART interface.
23// Reference: https://www.freebsd.org/doc/en_US.ISO8859-1/articles/serial-uart/index.html
24typedef struct uart16550_regs_
25{
27 u8 pad01;
29 u8 pad03;
30 u8 r_lcr;
31 u8 pad05;
32 u8 r_mcr;
33 u8 pad07;
34 u8 r_lsr;
35 u8 pad09;
36 u8 r_msr;
37 u8 pad0B;
38 u8 r_scr;
39 u8 pad0D;
40 u8 pad0E;
41 u8 pad0F;
42 u8 r_cr1;
43 u8 pad11;
44 u8 r_cr2;
45 u8 pad13;
47
49{
50 int m_offset1;
51 int m_offset2;
52 int m_cur_xfer_len;
53 void *m_ptr;
55
56typedef struct spduart_internals_
57{
58 int spduart_thread;
59 int spduart_ef;
60 uart16550_regs_t *dev9_uart_reg_area;
61 int spduart_thpri_;
62 int spduart_thstack_;
63 int spduart_overrun_error_count;
64 int spduart_parity_error_count;
65 int spduart_framing_error_count;
66 int spduart_break_interrupt_count;
67 int spduart_buffer_overflow_count;
68 int spduart_rx_count;
69 int spduart_tx_count;
70 char spduart_fcr_cached;
71 char spduart_msr_cached;
72 char spduart_signal_pin;
73 char spduart_mcr_cached;
74 int spduart_baud_;
75 int spduart_trig_;
76 iop_sys_clock_t spduart_clock_1e4;
77 iop_sys_clock_t spduart_clock_1e6;
78 int spduart_alarm_1e4_flag;
79 int spduart_alarm_1e6_flag;
80 int spduart_start_flag;
81 int spduart_stop_flag;
82 int shutdown_flag;
83 int spduart_data_set_ready_flag;
84 int spduart_nogci_;
85 char spduart_gci_[2];
86 // cppcheck-suppress unusedStructMember
87 char unused6a;
88 // cppcheck-suppress unusedStructMember
89 char unused6b;
90 spduart_buffer_struct_t recv_buf_struct;
91 spduart_buffer_struct_t send_buf_struct;
92 sceModemOps_t spduart_modem_ops;
93 char spduart_dial_[1024];
94 char buf1data[1024];
95 char buf2data[1024];
97
98// The modem used in SCPH-10281 network adapter is Conexant SMARTSCM/56 CX88168-11
99// Datasheet: https://archive.org/download/ps2_modem_ref/DSA-140092.pdf
100// AT command reference: https://archive.org/download/ps2_modem_ref/IML56_modem_AT_commands.pdf
101
102// The following is formatted in Motorola s37 format (aka S-Record, SRECORD, S-Rec, SREC)
103static const char *modem_firmware_s37[54] = {
104 "S3100000A000B20269A9008DBC044C0EE101\r",
105 "S31500009DA560606060606060606B606B606060606092\r",
106 "S31500009DB56B60606B60606060606060606060606082\r",
107 "S31500009DC56060606060606B606B60606B6060606067\r",
108 "S31500009DD5606060606060606B6B6060606B60606B4C\r",
109 "S31500009DE560606B606060606060606060606B606052\r",
110 "S31500009EB000000600000000004E0003000000000045\r",
111 "S31500009EC09300002A000000000000000000000000CF\r",
112 "S31500009ED00000000000006E006100006E000000003F\r",
113 "S31500009EE0000000000000004B7100000074000098A4\r",
114 "S31500009EF000009B000000000000000000005E000063\r",
115 "S30600009F00005A\r",
116 "S31500009F019A284C5F86A9608DA79DADA102D019A99B\r",
117 "S31500009F11048DEC02A973CD0D01B0038D0D01A9418C\r",
118 "S31500009F21CD110190038D110160C2016001FF4C1931\r",
119 "S31500009F31AD6487D014D2105D01A9328D1D87A900A9\r",
120 "S31500009F418D1E8748C2105D0168604CC686A9603FB8\r",
121 "S31500009F516B02A96B8DE49DA96B8DA79D604C008159\r",
122 "S31500009F61A21820445A0DEB02A2184CF5584C6986EA\r",
123 "S31500009F714C449EAE59048A2902F0168A29FD8D5950\r",
124 "S31500009F8104A9528D1C06A9807B09208D1806A9A05B\r",
125 "S31200009F917B60D2083906604CEF864C548682\r",
126 "S31500009DF9AD4B878540AD4C878541A541C900D00447\r",
127 "S31500009E09A540C996B033AD43878540AD44878541A2\r",
128 "S31500009E1938A540E98C8540A541E9008541A540ED75\r",
129 "S31500009E2952878540A541ED53878541B26444207820\r",
130 "S30F00009E3969A5408D439E4C708660BB\r",
131 "S31500009E447F4C04D21060016087FFAD9602C971F0A1\r",
132 "S31500009E542C206067A540E9588540A541E902854163\r",
133 "S31500009E64900BAD588789018D58874C4575AD960280\r",
134 "S31500009E74C971F009ADA89E8DA79E4CAE77ADA89E7C\r",
135 "S31500009E8438EDA79E9004C902B00160A900854085FB\r",
136 "S31500009E9441A5408D5887A5418D598707FF20DD7759\r",
137 "S30800009EA44C1361F5\r",
138 "S31500008654A950CD0286B0038D028660E2750102043C\r",
139 "S3150000866497FF27FF60A203A9004C9BE4AD478785CB\r",
140 "S3150000867440AD48878541B26444207869AD439E8500\r",
141 "S3150000868442208B69A541C907D004A540C9089012A8\r",
142 "S31500008694A9758D3F87A9778D4087B200AEB248B1E0\r",
143 "S315000086A4B759601FFF1BAFFF09A7FFC2027501B2CE\r",
144 "S315000086B414FEE25D01100AC6FED00617FFD202754B\r",
145 "S315000086C40160AD5702C93CD021BF6B1EB20747B249\r",
146 "S315000086D45046B20A45B2B9442096E3B20747B250AF\r",
147 "S315000086E446B20B45B2B9442096E360E21106100681\r",
148 "S30C000086F47F5C032095026084\r",
149 "S3150000810020A786E25D0110374F63342073E7AD96F2\r",
150 "S3150000811002C971D00FF24E01100AAD0404C960B055\r",
151 "S31500008120034CF960AD3F87C9B1F00FAD4D87C9006B\r",
152 "S31500008130F00DE2600110094C7E9EA9008D4D87600E\r",
153 "S3150000814020F99DADEC02C903D0F5AD3F87C9DBD060\r",
154 "S31500008150EEE25E0101E920C466A5406D45878540D3\r",
155 "S31500008160A5416D46878541B26444207869A5408D56\r",
156 "S31500008170A89E38E92890C8A54038E93290060FFF36\r",
157 "S30C00008180BE4C719E4C4C9EA3\r"};
158
159static spduart_internals_t spduart_internals;
160
161#define sceInetPrintf(...) printf(__VA_ARGS__)
162
163static int module_start(int ac, char *av[], void *startaddr, ModuleInfo_t *mi);
164static int module_stop(int ac, char *av[], void *startaddr, ModuleInfo_t *mi);
165
166int _start(int argc, char *argv[], void *startaddr, ModuleInfo_t *mi)
167{
168 if ( argc >= 0 )
169 return module_start(argc, argv, startaddr, mi);
170 else
171 return module_stop(argc, argv, startaddr, mi);
172}
173
174static void spduart_dump_msr(u8 msr)
175{
176 sceInetPrintf(
177 "spduart: MSR=%02x (DCTS=%d DDSR=%d TERI=%d DDCD=%d\n",
178 msr,
179 msr & 1,
180 (msr >> 1) & 1,
181 (msr >> 2) & 1,
182 (msr >> 3) & 1);
183 sceInetPrintf(
184 "spduart: CTS=%d DSR=%d RI=%d DCD=%d)\n", (msr >> 4) & 1, (msr >> 5) & 1, (msr >> 6) & 1, msr >> 7);
185}
186
187static unsigned int alarm_cb_1e4(struct spduart_internals_ *priv)
188{
189 priv->spduart_modem_ops.rcv_len = priv->recv_buf_struct.m_cur_xfer_len;
190 iSetEventFlag(priv->spduart_modem_ops.evfid, 0x100u);
191 return 0;
192}
193
194static u32 alarm_cb_1e6(struct spduart_internals_ *priv)
195{
196 iSetEventFlag(priv->spduart_ef, 4u);
197 return priv->spduart_clock_1e6.lo;
198}
199
200static int spduart_send(struct spduart_internals_ *priv)
201{
202 int m_cur_xfer_len;
203 int v4;
204 u8 v7;
205 int state;
206
207 CpuSuspendIntr(&state);
208 priv->spduart_fcr_cached &= ~2;
209 m_cur_xfer_len = priv->send_buf_struct.m_cur_xfer_len;
210 v4 = 0;
211 if ( m_cur_xfer_len > 0 )
212 {
213 if ( m_cur_xfer_len > 16 )
214 m_cur_xfer_len = 16;
215 if ( (priv->spduart_msr_cached & 0x10) != 0 )
216 {
217 if ( (spduart_internals.dev9_uart_reg_area->r_msr & 0x20) != 0 )
218 {
219 int v6;
220
221 v6 = m_cur_xfer_len - 1;
222 do
223 {
224 v7 = *((u8 *)priv->send_buf_struct.m_ptr + (priv->send_buf_struct.m_offset2 & 0x3FF));
225 ++priv->send_buf_struct.m_offset2;
226 priv->send_buf_struct.m_cur_xfer_len -= 1;
227 --v6;
228 spduart_internals.dev9_uart_reg_area->r_wrthr_rdrbr = v7;
229 ++v4;
230 } while ( v6 > 0 );
231 if ( priv->send_buf_struct.m_cur_xfer_len > 0 )
232 {
233 priv->spduart_fcr_cached |= 2;
234 }
235 }
236 else
237 {
238 priv->spduart_fcr_cached |= 2;
239 }
240 priv->spduart_tx_count += v4;
241 }
242 }
243 spduart_internals.dev9_uart_reg_area->r_wrfcr_rdiir = priv->spduart_fcr_cached;
244 CpuResumeIntr(state);
245 return v4;
246}
247
248static int spduart_dev9_intr_cb(int flag)
249{
250 int v1;
251 u32 v2;
252 u8 r_msr;
253 int m_offset1;
254 char r_scr;
255 u32 v18;
256
257 (void)flag;
258
259 v1 = 0;
260 v2 = 0;
261 while ( 1 )
262 {
263 switch ( spduart_internals.dev9_uart_reg_area->r_lcr & 0xF )
264 {
265 case 0:
266 r_scr = spduart_internals.dev9_uart_reg_area->r_scr;
267 if ( spduart_internals.spduart_start_flag )
268 {
269 spduart_internals.spduart_msr_cached = spduart_internals.dev9_uart_reg_area->r_scr;
270 continue;
271 }
272 if ( (spduart_internals.dev9_uart_reg_area->r_scr & 1) != 0 )
273 {
274 if ( (spduart_internals.dev9_uart_reg_area->r_scr & 0x10) != 0 )
275 {
276 v2 |= 4u;
277 }
278 }
279 if ( r_scr & 2 )
280 {
281 if ( (spduart_internals.dev9_uart_reg_area->r_scr & 0x20) == 0 )
282 {
283 spduart_internals.shutdown_flag = 1;
284 iSetEventFlag(spduart_internals.spduart_modem_ops.evfid, 2);
285 }
286 else
287 {
288 if ( !spduart_internals.spduart_data_set_ready_flag )
289 {
290 v2 |= 4u;
291 spduart_internals.spduart_data_set_ready_flag = 1;
292 iSetEventFlag(spduart_internals.spduart_modem_ops.evfid, 513);
293 }
294 }
295 }
296 if ( r_scr & 4 )
297 {
298 iSetEventFlag(spduart_internals.spduart_modem_ops.evfid, 0x40u);
299 }
300 if ( (r_scr & 8) && ((spduart_internals.spduart_msr_cached ^ (u8)r_scr) & 0x80) != 0 )
301 {
302 v18 = 32;
303 if ( (r_scr & 0x80) != 0 )
304 v18 = 16;
305 iSetEventFlag(spduart_internals.spduart_modem_ops.evfid, v18);
306 }
307 spduart_internals.spduart_msr_cached = r_scr;
308 break;
309 case 1:
310 if ( v1 > 0 )
311 {
312 v2 |= 8u;
313 spduart_internals.spduart_rx_count += v1;
314 if ( spduart_internals.recv_buf_struct.m_cur_xfer_len < 257 )
315 {
316 if ( (spduart_internals.spduart_signal_pin & 2) == 0 )
317 {
318 spduart_internals.spduart_signal_pin |= 2u;
319 spduart_internals.dev9_uart_reg_area->r_lsr = spduart_internals.spduart_signal_pin;
320 }
321 }
322 if ( spduart_internals.recv_buf_struct.m_cur_xfer_len >= 768 )
323 {
324 if ( (spduart_internals.spduart_signal_pin & 2) != 0 )
325 {
326 spduart_internals.spduart_signal_pin &= ~2u;
327 spduart_internals.dev9_uart_reg_area->r_lsr = spduart_internals.spduart_signal_pin;
328 }
329 }
330 }
331 if ( v2 )
332 iSetEventFlag(spduart_internals.spduart_ef, v2);
333 return 0;
334 case 2:
335 spduart_internals.spduart_fcr_cached &= ~2u;
336 spduart_internals.dev9_uart_reg_area->r_wrfcr_rdiir = spduart_internals.spduart_fcr_cached;
337 v2 |= 4u;
338 continue;
339 case 4:
340 case 0xC:
341 while ( (spduart_internals.dev9_uart_reg_area->r_msr & 1) != 0 && !spduart_internals.spduart_start_flag )
342 {
343 if ( spduart_internals.recv_buf_struct.m_cur_xfer_len >= 1024 )
344 {
345 ++spduart_internals.spduart_buffer_overflow_count;
346 }
347 else
348 {
349 ++v1;
350 m_offset1 = spduart_internals.recv_buf_struct.m_offset1;
351 *((u8 *)spduart_internals.recv_buf_struct.m_ptr + (spduart_internals.recv_buf_struct.m_offset1 & 0x3FF)) =
352 spduart_internals.dev9_uart_reg_area->r_wrthr_rdrbr;
353 spduart_internals.recv_buf_struct.m_offset1 = m_offset1 + 1;
354 ++spduart_internals.recv_buf_struct.m_cur_xfer_len;
355 }
356 }
357 continue;
358 case 6:
359 r_msr = spduart_internals.dev9_uart_reg_area->r_msr;
360 if ( r_msr & 2 )
361 {
362 ++spduart_internals.spduart_overrun_error_count;
363 }
364 if ( r_msr & 4 )
365 {
366 ++spduart_internals.spduart_parity_error_count;
367 }
368 if ( r_msr & 8 )
369 {
370 ++spduart_internals.spduart_framing_error_count;
371 }
372 if ( r_msr & 0x10 )
373 {
374 ++spduart_internals.spduart_break_interrupt_count;
375 }
376 continue;
377 default:
378 continue;
379 }
380 }
381}
382
383static int spduart_set_baud(int baud)
384{
385 switch ( baud )
386 {
387 case 115200:
388 return 1;
389 case 57600:
390 return 2;
391 case 38400:
392 return 3;
393 case 28800:
394 return 4;
395 case 19200:
396 return 6;
397 case 9600:
398 return 12;
399 default:
400 return 0;
401 }
402}
403
404static void spduart_do_init_dev9(struct spduart_internals_ *priv)
405{
406 int v2;
407
408 spduart_internals.dev9_uart_reg_area->r_cr1 = 27;
409 spduart_internals.dev9_uart_reg_area->r_cr2 = 4;
410 DelayThread(10000);
411 spduart_internals.dev9_uart_reg_area->r_wrfcr_rdiir = 0;
412 priv->spduart_mcr_cached = -125;
413 spduart_internals.dev9_uart_reg_area->r_mcr = priv->spduart_mcr_cached;
414 v2 = spduart_set_baud(priv->spduart_baud_);
415 spduart_internals.dev9_uart_reg_area->r_wrthr_rdrbr = v2;
416 spduart_internals.dev9_uart_reg_area->r_wrfcr_rdiir = (v2 >> 8) & 0xFF;
417 priv->spduart_mcr_cached = 3;
418 spduart_internals.dev9_uart_reg_area->r_mcr = priv->spduart_mcr_cached;
419 priv->spduart_signal_pin = 3;
420 spduart_internals.dev9_uart_reg_area->r_lsr = priv->spduart_signal_pin;
421 switch ( priv->spduart_trig_ )
422 {
423 case 1:
424 {
425 spduart_internals.dev9_uart_reg_area->r_lcr = 1;
426 break;
427 }
428 case 4:
429 {
430 spduart_internals.dev9_uart_reg_area->r_lcr = 65;
431 break;
432 }
433 case 8:
434 default:
435 {
436 spduart_internals.dev9_uart_reg_area->r_lcr = -127;
437 break;
438 }
439 case 14:
440 {
441 spduart_internals.dev9_uart_reg_area->r_lcr = -63;
442 break;
443 }
444 }
445}
446
447static void spduart_deinit()
448{
449 spduart_internals.dev9_uart_reg_area->r_cr2 = -124;
450}
451
452static void fail_sleep(const char *fmt)
453{
454 sceInetPrintf(fmt);
455 while ( 1 )
456 SleepThread();
457}
458
459static void sleep_on_shutdown(const struct spduart_internals_ *priv)
460{
461 if ( priv->shutdown_flag )
462 {
463 fail_sleep("spduart: plug-out\n");
464 }
465}
466
467static int spduart_send_now(struct spduart_internals_ *priv, const char *in_buf, char *expected_buf)
468{
469 char *v6;
470 int v7;
471 char r_scr;
472 int v11;
473 char v12;
474 int v13;
475 int v14;
476
477 v6 = expected_buf;
478 v7 = 0;
479 while ( 1 )
480 {
481 int v8;
482 int v9;
483
484 v8 = 0;
485 v9 = 0;
486 sleep_on_shutdown(priv);
487 if ( *in_buf )
488 {
489 r_scr = spduart_internals.dev9_uart_reg_area->r_scr;
490 priv->spduart_msr_cached = r_scr;
491 if ( (r_scr & 0x10) != 0 && (spduart_internals.dev9_uart_reg_area->r_msr & 0x20) != 0 )
492 {
493 v11 = 15;
494 do
495 {
496 v12 = *in_buf;
497 v13 = v11;
498 if ( !v12 )
499 break;
500 ++in_buf;
501 ++v9;
502 --v11;
503 spduart_internals.dev9_uart_reg_area->r_wrthr_rdrbr = v12;
504 } while ( v13 > 0 );
505 }
506 }
507 if ( (spduart_internals.dev9_uart_reg_area->r_msr & 1) != 0 )
508 {
509 v8 = 1;
510 v14 = *v6;
511 if ( *v6 )
512 {
513 ++v6;
514 if ( v14 != spduart_internals.dev9_uart_reg_area->r_wrthr_rdrbr )
515 v6 = expected_buf;
516 }
517 }
518 if ( !*in_buf )
519 {
520 if ( !*v6 )
521 break;
522 }
523 if ( !v9 && !v8 )
524 {
525 if ( v7 >= 300 )
526 return -1;
527 v7 += 1;
528 DelayThread(10000);
529 }
530 }
531 return 0;
532}
533
534static void spduart_init_hw(struct spduart_internals_ *priv)
535{
536 int i;
537 int v5;
538 char *buf1data;
539
540 while ( 1 )
541 {
542 int v7;
543 int v10;
544 const char *v11;
545
546 while ( 1 )
547 {
548 while ( 1 )
549 {
550 do
551 {
552 spduart_deinit();
553 DelayThread(200000);
554 sleep_on_shutdown(priv);
555 spduart_do_init_dev9(priv);
556 for ( i = 0; i < 300; ++i )
557 {
558 sleep_on_shutdown(priv);
559 DelayThread(10000);
560 }
561 while ( 1 )
562 {
563 sleep_on_shutdown(priv);
564 priv->spduart_msr_cached = spduart_internals.dev9_uart_reg_area->r_scr;
565 if ( (priv->spduart_msr_cached & 0x20) != 0 )
566 break;
567 DelayThread(100000);
568 }
569 } while ( spduart_send_now(priv, "AT\r", "OK") < 0 && spduart_send_now(priv, "AT\r", "OK") < 0 );
570 if ( spduart_send_now(priv, "ATI3\r", "P2109-V90") < 0 )
571 break;
572 sceInetPrintf("spduart: P2109-V90 detected\n");
573 spduart_send_now(priv, "AT**\r", "Download initiated ..");
574 sceInetPrintf("spduart: downloading (9A-40)\n");
575 v5 = 0;
576 i = 0;
577 while ( modem_firmware_s37[i] )
578 {
579 v5 = spduart_send_now(priv, modem_firmware_s37[i], ".");
580 if ( v5 < 0 )
581 {
582 sceInetPrintf("spduart: failed to download (1)\n");
583 break;
584 }
585 i += 1;
586 }
587 if ( v5 >= 0 && spduart_send_now(priv, "S70500000000FA\r", "OK") >= 0 )
588 {
589 sceInetPrintf("spduart: download completed\n");
590 break;
591 }
592 sceInetPrintf("spduart: failed to download (2)\n");
593 }
594 if ( priv->spduart_nogci_ )
595 return;
596 if ( !priv->spduart_gci_[0] )
597 break;
598 sprintf(priv->buf2data, "AT+GCI=%c%c\r", priv->spduart_gci_[0], priv->spduart_gci_[1]);
599 sceInetPrintf("spduart: sending \"%S\"\n", priv->buf2data);
600 if ( spduart_send_now(priv, priv->buf2data, "OK") >= 0 )
601 return;
602 sceInetPrintf("spduart: failed to set GCI (1)\n");
603 }
604 if ( !priv->spduart_dial_[0] )
605 {
606 fail_sleep("spduart: no dial_cnf\n");
607 }
608 sceInetPrintf("spduart: scanning GCI setting in \"%s\"\n", priv->spduart_dial_);
609 v7 = open(priv->spduart_dial_, 1);
610 if ( v7 < 0 )
611 {
612 fail_sleep("spduart: can't open\n");
613 }
614 buf1data = priv->buf1data;
615 v10 = read(v7, buf1data, 1024);
616 if ( v10 < 0 )
617 {
618 fail_sleep("spduart: read error\n");
619 }
620 close(v7);
621 if ( (unsigned int)v10 >= 0x400 )
622 {
623 fail_sleep("spduart: file too big\n");
624 }
625 v11 = &buf1data[v10];
626 while ( 1 )
627 {
628 if ( buf1data >= v11 )
629 {
630 fail_sleep("spduart: no GCI setting\n");
631 }
632 while ( buf1data < v11 )
633 {
634 if ( (isspace(*buf1data)) == 0 )
635 break;
636 buf1data += 1;
637 }
638 if ( *buf1data != '#' )
639 {
640 while ( buf1data < v11 && *buf1data != '+' )
641 {
642 buf1data += 1;
643 }
644 if ( (*buf1data == '+') && (strncmp("+GCI=", buf1data, 5) == 0) )
645 {
646 buf1data += 5;
647 if ( ((isxdigit(buf1data[0])) != 0) && ((isxdigit(buf1data[1])) != 0) )
648 {
649 break;
650 }
651 }
652 }
653 while ( buf1data < v11 && *buf1data != '\n' )
654 {
655 buf1data += 1;
656 }
657 if ( *buf1data == '\n' )
658 buf1data += 1;
659 }
660 sprintf(priv->buf2data, "AT+GCI=%c%c\r", (u8)*buf1data, (u8)buf1data[1]);
661 sceInetPrintf("spduart: sending \"%S\"\n", priv->buf2data);
662 if ( spduart_send_now(priv, priv->buf2data, "OK") < 0 )
663 {
664 sceInetPrintf("spduart: failed to set GCI (2)\n");
665 continue;
666 }
667 break;
668 }
669}
670
671static void spduart_thread_proc(void *arg)
672{
673 struct spduart_internals_ *priv = arg;
674 int i;
675 int m_cur_xfer_len;
676 int v10;
677 u32 v12;
678
679 spduart_init_hw(priv);
680 priv->spduart_fcr_cached = 13;
681 spduart_internals.dev9_uart_reg_area->r_wrfcr_rdiir = priv->spduart_fcr_cached;
682 while ( !WaitEventFlag(priv->spduart_ef, 0xFu, 17, &v12) )
683 {
684 if ( (v12 & 2) != 0 && !priv->spduart_start_flag )
685 {
686 SpdIntrDisable(4096);
687 if ( priv->spduart_alarm_1e4_flag )
688 {
689 CancelAlarm((unsigned int (*)(void *))alarm_cb_1e4, priv);
690 priv->spduart_alarm_1e4_flag = 0;
691 }
692 if ( priv->spduart_alarm_1e6_flag )
693 {
694 CancelAlarm((unsigned int (*)(void *))alarm_cb_1e6, priv);
695 priv->spduart_alarm_1e6_flag = 0;
696 }
697 priv->spduart_signal_pin = 0;
698 spduart_internals.dev9_uart_reg_area->r_lsr = 0;
699 spduart_internals.dev9_uart_reg_area->r_lcr = -121;
700 priv->recv_buf_struct.m_cur_xfer_len = 0;
701 priv->recv_buf_struct.m_offset1 = 0;
702 priv->recv_buf_struct.m_offset2 = 0;
703 priv->send_buf_struct.m_cur_xfer_len = 0;
704 priv->send_buf_struct.m_offset1 = 0;
705 priv->send_buf_struct.m_offset2 = 0;
706 // cppcheck-suppress redundantAssignment
707 spduart_internals.dev9_uart_reg_area->r_lcr = -127;
708 priv->spduart_start_flag = 1;
709 priv->spduart_stop_flag = 0;
710 if ( !priv->shutdown_flag )
711 {
712 priv->spduart_mcr_cached = 67;
713 spduart_internals.dev9_uart_reg_area->r_mcr = priv->spduart_mcr_cached;
714 for ( i = 0; i < 20; i += 1 )
715 {
716 if ( priv->shutdown_flag )
717 break;
718 if ( (priv->spduart_msr_cached & 0x80) == 0 )
719 {
720 priv->spduart_mcr_cached = 3;
721 spduart_internals.dev9_uart_reg_area->r_mcr = 3;
722 for ( i = 0; i < 300; i += 1 )
723 {
724 if ( priv->shutdown_flag )
725 break;
726 DelayThread(10000);
727 }
728 break;
729 }
730 DelayThread(100000);
731 }
732 }
733 }
734 if ( !priv->spduart_start_flag )
735 {
736 if ( (v12 & 4) != 0 )
737 {
738 if ( priv->spduart_data_set_ready_flag )
739 {
740 if ( spduart_send(priv) > 0 )
741 {
742 m_cur_xfer_len = priv->send_buf_struct.m_cur_xfer_len;
743 if ( m_cur_xfer_len >= 257 )
744 {
745 priv->spduart_modem_ops.snd_len = 1024 - m_cur_xfer_len;
746 SetEventFlag(priv->spduart_modem_ops.evfid, 0x200u);
747 }
748 }
749 }
750 }
751 if ( (v12 & 8) != 0 )
752 {
753 if ( priv->spduart_alarm_1e4_flag )
754 {
755 CancelAlarm((unsigned int (*)(void *))alarm_cb_1e4, priv);
756 priv->spduart_alarm_1e4_flag = 0;
757 }
758 v10 = priv->recv_buf_struct.m_cur_xfer_len;
759 if ( v10 >= 257 )
760 {
761 priv->spduart_modem_ops.rcv_len = v10;
762 SetEventFlag(priv->spduart_modem_ops.evfid, 0x100u);
763 }
764 else
765 {
766 SetAlarm(&priv->spduart_clock_1e4, (unsigned int (*)(void *))alarm_cb_1e4, priv);
767 priv->spduart_alarm_1e4_flag = 1;
768 }
769 }
770 }
771 else if ( (v12 & 1) != 0 )
772 {
773 priv->shutdown_flag = 0;
774 priv->spduart_data_set_ready_flag = 0;
775 priv->spduart_modem_ops.snd_len = 1024;
776 priv->spduart_signal_pin = 3;
777 spduart_internals.dev9_uart_reg_area->r_lsr = 3;
778 priv->spduart_msr_cached = spduart_internals.dev9_uart_reg_area->r_scr;
779 spduart_dump_msr(priv->spduart_msr_cached);
780 if ( (priv->spduart_msr_cached & 0x20) != 0 )
781 {
782 SetEventFlag(priv->spduart_modem_ops.evfid, 0x201u);
783 priv->spduart_data_set_ready_flag = 1;
784 }
785 if ( (priv->spduart_msr_cached & 0x80) != 0 )
786 {
787 SetEventFlag(priv->spduart_modem_ops.evfid, 0x10u);
788 }
789 priv->spduart_start_flag = 0;
790 SetAlarm(&priv->spduart_clock_1e6, (unsigned int (*)(void *))alarm_cb_1e6, priv);
791 priv->spduart_alarm_1e6_flag = 1;
792 SpdIntrEnable(4096);
793 }
794 }
795}
796
797static int spduart_op_start(struct spduart_internals_ *priv, int flags)
798{
799 (void)flags;
800
801 priv->spduart_stop_flag = 0;
802 SetEventFlag(priv->spduart_ef, 1u);
803 return 0;
804}
805
806static int spduart_op_stop(struct spduart_internals_ *priv, int flags)
807{
808 (void)flags;
809
810 priv->spduart_stop_flag = 1;
811 SetEventFlag(priv->spduart_ef, 2u);
812 return 0;
813}
814
815static size_t spduart_op_recv(struct spduart_internals_ *priv, void *ptr, int len)
816{
817 int m_cur_xfer_len;
818 size_t v7;
819 int v8;
820 size_t v9;
821 int state;
822
823 m_cur_xfer_len = len;
824 v7 = 0;
825 if ( priv->recv_buf_struct.m_cur_xfer_len < len )
826 m_cur_xfer_len = priv->recv_buf_struct.m_cur_xfer_len;
827 v8 = priv->recv_buf_struct.m_offset2 & 0x3FF;
828 v9 = 1024 - v8;
829 if ( m_cur_xfer_len < 1024 - v8 )
830 v9 = m_cur_xfer_len;
831 if ( v9 > 0 )
832 {
833 size_t v10;
834
835 v7 = v9;
836 bcopy((char *)priv->recv_buf_struct.m_ptr + v8, ptr, v9);
837 v10 = m_cur_xfer_len - v9;
838 if ( v10 > 0 )
839 {
840 bcopy(priv->recv_buf_struct.m_ptr, (char *)ptr + v9, v10);
841 v7 += v10;
842 }
843 CpuSuspendIntr(&state);
844 priv->recv_buf_struct.m_cur_xfer_len -= v7;
845 priv->recv_buf_struct.m_offset2 += v7;
846 priv->spduart_modem_ops.rcv_len = priv->recv_buf_struct.m_cur_xfer_len;
847 if ( priv->recv_buf_struct.m_cur_xfer_len < 257 )
848 {
849 if ( (priv->spduart_signal_pin & 2) == 0 )
850 {
851 priv->spduart_signal_pin |= 2;
852 spduart_internals.dev9_uart_reg_area->r_lsr = priv->spduart_signal_pin;
853 }
854 }
855 CpuResumeIntr(state);
856 }
857 return v7;
858}
859
860static int spduart_op_send(struct spduart_internals_ *priv, void *ptr, int len)
861{
862 int v4;
863 int v7;
864 int v8;
865 size_t v9;
866 int state;
867
868 v4 = len;
869 v7 = 0;
870 if ( 1024 - priv->send_buf_struct.m_cur_xfer_len < len )
871 v4 = 1024 - priv->send_buf_struct.m_cur_xfer_len;
872 v8 = priv->send_buf_struct.m_offset1 & 0x3FF;
873 v9 = 1024 - v8;
874 if ( (unsigned int)v4 < v9 )
875 v9 = v4;
876 if ( v9 > 0 )
877 {
878 size_t v10;
879
880 v7 = v9;
881 bcopy(ptr, (char *)priv->send_buf_struct.m_ptr + v8, v9);
882 v10 = v4 - v9;
883 if ( v10 > 0 )
884 {
885 bcopy((char *)ptr + v9, priv->send_buf_struct.m_ptr, v10);
886 v7 += v10;
887 }
888 CpuSuspendIntr(&state);
889 priv->send_buf_struct.m_cur_xfer_len += v7;
890 priv->send_buf_struct.m_offset1 += v7;
891 priv->spduart_modem_ops.snd_len = 1024 - priv->send_buf_struct.m_cur_xfer_len;
892 CpuResumeIntr(state);
893 }
894 if ( v7 > 0 )
895 SetEventFlag(priv->spduart_ef, 4u);
896 return v7;
897}
898
899static int spduart_op_control(struct spduart_internals_ *priv, int code, void *ptr, int len)
900{
901 int v22;
902 int state;
903 int priority;
904 unsigned int v25;
905 int v26;
906
907 switch ( code )
908 {
909 case 0xC0000110:
910 case 0xC0000111:
911 case 0xC0000200:
912 break;
913 default:
914 {
915 if ( len != 4 )
916 return -512;
917 }
918 }
919 switch ( code )
920 {
921 case 0xC0000000:
922 {
923 bcopy(&priv->spduart_thpri_, ptr, 4);
924 return 0;
925 }
926 case 0xC0000100:
927 {
928 v22 = 1;
929 bcopy(&v22, ptr, 4);
930 return 0;
931 }
932 case 0xC0000110:
933 {
934 CpuSuspendIntr(&state);
935 priv->recv_buf_struct.m_offset1 = 0;
936 priv->recv_buf_struct.m_offset2 = 0;
937 priv->recv_buf_struct.m_cur_xfer_len = 0;
938 priv->spduart_modem_ops.rcv_len = 0;
939 CpuResumeIntr(state);
940 return 0;
941 }
942 case 0xC0000111:
943 {
944 CpuSuspendIntr(&state);
945 priv->send_buf_struct.m_offset1 = 0;
946 priv->send_buf_struct.m_offset2 = 0;
947 priv->send_buf_struct.m_cur_xfer_len = 0;
948 priv->spduart_modem_ops.snd_len = 1024;
949 CpuResumeIntr(state);
950 return 0;
951 }
952 case 0xC0000200:
953 {
954 int v13;
955
956 v13 = strlen(priv->spduart_dial_) + 1;
957 if ( len < v13 )
958 {
959 return -512;
960 }
961 bcopy(priv->spduart_dial_, ptr, v13);
962 return 0;
963 }
964 case 0xC0010000:
965 {
966 bcopy(&priv->spduart_rx_count, ptr, 4);
967 return 0;
968 }
969 case 0xC0010001:
970 {
971 bcopy(&priv->spduart_tx_count, ptr, 4);
972 return 0;
973 }
974 case 0xC0010002:
975 {
976 bcopy(&priv->spduart_overrun_error_count, ptr, 4);
977 return 0;
978 }
979 case 0xC0010003:
980 {
981 bcopy(&priv->spduart_parity_error_count, ptr, 4);
982 return 0;
983 }
984 case 0xC0010004:
985 {
986 bcopy(&priv->spduart_framing_error_count, ptr, 4);
987 return 0;
988 }
989 case 0xC0010005:
990 {
991 bcopy(&priv->spduart_buffer_overflow_count, ptr, 4);
992 return 0;
993 }
994 case 0xC0020000:
995 {
996 v25 = ((priv->spduart_mcr_cached & 3) << 28) | ((priv->spduart_mcr_cached & 0x18) << 27) | priv->spduart_baud_
997 | 0x2000000;
998 if ( (priv->spduart_mcr_cached & 4) != 0 )
999 v25 |= 0xC000000;
1000 else
1001 v25 |= 0x4000000;
1002 bcopy((int *)&v25, ptr, 4);
1003 return 0;
1004 }
1005 case 0xC0030000:
1006 {
1007 v26 = (16 * (priv->spduart_signal_pin & 3)) | ((u8)priv->spduart_msr_cached >> 4);
1008 bcopy(&v26, ptr, 4);
1009 return 0;
1010 }
1011 case 0xC1000000:
1012 {
1013 int v6;
1014
1015 bcopy(ptr, &priority, 4);
1016 v6 = 0;
1017 if ( priv->spduart_thread > 0 )
1018 {
1019 v6 = ChangeThreadPriority(priv->spduart_thread, priority);
1020 if ( !v6 )
1021 priv->spduart_thpri_ = priority;
1022 }
1023 if ( priv->spduart_thread <= 0 || v6 == -413 )
1024 {
1025 if ( (unsigned int)(priority - 9) < 0x73 )
1026 priv->spduart_thpri_ = priority;
1027 }
1028 return v6;
1029 }
1030 case 0xC1020000:
1031 {
1032 int v17;
1033 unsigned int v18;
1034
1035 bcopy(ptr, &v25, 4);
1036 v17 = spduart_set_baud(v25 & 0x3FFFFF);
1037 if ( !v17 )
1038 {
1039 return -512;
1040 }
1041 if ( ((v25 >> 26) & 1) == 0 || (v25 & 0x1800000) != 0 )
1042 return -512;
1043 v18 = v25 >> 30;
1044 if ( v18 == 1 || (v25 & 0x2000000) == 0 )
1045 {
1046 return -512;
1047 }
1048 priv->spduart_mcr_cached =
1049 v18 | ((int)((v25 >> 26) & 3) >> 1) | ((v25 >> 28) & 3) | (priv->spduart_mcr_cached & 0x40) | 0x80;
1050 spduart_internals.dev9_uart_reg_area->r_mcr = priv->spduart_mcr_cached;
1051 spduart_internals.dev9_uart_reg_area->r_wrthr_rdrbr = v17;
1052 spduart_internals.dev9_uart_reg_area->r_wrfcr_rdiir = (v17 >> 8) & 0xFF;
1053 priv->spduart_mcr_cached &= ~0x80;
1054 // cppcheck-suppress redundantAssignment
1055 spduart_internals.dev9_uart_reg_area->r_mcr = priv->spduart_mcr_cached;
1056 return 0;
1057 }
1058 case 0xC1030000:
1059 {
1060 bcopy(ptr, &v26, 4);
1061 if ( (v26 & 0xFFFFFFCF) != 0 )
1062 {
1063 return -512;
1064 }
1065 priv->spduart_signal_pin &= ~3;
1066 priv->spduart_signal_pin |= ((unsigned int)v26 >> 4);
1067 spduart_internals.dev9_uart_reg_area->r_lsr = priv->spduart_signal_pin;
1068 return 0;
1069 }
1070 default:
1071 return -513;
1072 }
1073}
1074
1075static void shutdown_cb(void)
1076{
1077 spduart_internals.shutdown_flag = 1;
1078}
1079
1080static int print_version(void)
1081{
1082 printf("SPDUART (%s)%s\n", "Version 2.26.0", "");
1083 return MODULE_NO_RESIDENT_END;
1084}
1085
1086static int print_usage(void)
1087{
1088 printf("Usage: spduart [-probe] [-nogci] [baud=<baud>] [trig=<trig>] [gci=<gci>] [thpri=<prio>] [thstack=<stack>] "
1089 "[dial=<dial>]\n");
1090 return MODULE_NO_RESIDENT_END;
1091}
1092
1093// cppcheck-suppress unusedFunction
1094void spduart_2_deinit(int a1)
1095{
1096 USE_SPD_REGS;
1097
1098 if ( !a1 && (SPD_REG16(SPD_R_REV_3) & 8) != 0 )
1099 spduart_internals.dev9_uart_reg_area->r_cr2 = -124;
1100}
1101
1102// cppcheck-suppress constParameter
1103static int module_start(int ac, char *av[], void *startaddr, ModuleInfo_t *mi)
1104{
1105 int v2;
1106 int v3;
1107 int v5;
1108 char *v7;
1109 int v11;
1110 int v14;
1111 int v16;
1112 iop_event_t v17;
1113 iop_thread_t v18;
1114 USE_SPD_REGS;
1115
1116 (void)startaddr;
1117
1118 v2 = 0;
1119 v3 = 0;
1120 spduart_internals.spduart_thpri_ = 40;
1121 spduart_internals.spduart_thstack_ = 0x2000;
1122 spduart_internals.spduart_dial_[0] = 0;
1123 spduart_internals.spduart_baud_ = 115200;
1124 spduart_internals.spduart_trig_ = 8;
1125 for ( v5 = 1; v5 < ac; v5 += 1 )
1126 {
1127 if ( !strcmp("-help", av[v5]) )
1128 {
1129 return print_usage();
1130 }
1131 else if ( !strcmp("-version", av[v5]) )
1132 {
1133 return print_version();
1134 }
1135 else if ( !strcmp("-probe", av[v5]) )
1136 {
1137 v3 = 1;
1138 continue;
1139 }
1140 else if ( !strcmp("-nogci", av[v5]) )
1141 {
1142 spduart_internals.spduart_nogci_ = 1;
1143 continue;
1144 }
1145 else if ( !strncmp("dial=", av[v5], 5) )
1146 {
1147 strcpy(spduart_internals.spduart_dial_, av[v5] + 5);
1148 continue;
1149 }
1150 else if ( !strncmp("gci=", av[v5], 4) )
1151 {
1152 v7 = (char *)(av[v5] + 4);
1153 if ( (isxdigit(*v7)) == 0 || (isxdigit(v7[1])) == 0 )
1154 return print_usage();
1155 spduart_internals.spduart_gci_[0] = v7[0];
1156 spduart_internals.spduart_gci_[1] = v7[1];
1157 continue;
1158 }
1159 else if ( !strncmp("thpri=", av[v5], 6) )
1160 {
1161 v7 = (char *)(av[v5] + 6);
1162 if ( (isdigit(*v7)) == 0 )
1163 return print_usage();
1164 v11 = strtol(v7, 0, 10);
1165 if ( (unsigned int)(v11 - 9) >= 0x73 )
1166 return print_usage();
1167 spduart_internals.spduart_thpri_ = v11;
1168 }
1169 else if ( !strncmp("thstack=", av[v5], 8) )
1170 {
1171 v7 = (char *)(av[v5] + 8);
1172 if ( (isdigit(*v7)) == 0 )
1173 return print_usage();
1174 spduart_internals.spduart_thstack_ = strtol(v7, 0, 10);
1175 while ( *v7 )
1176 {
1177 if ( (isdigit(*v7)) == 0 )
1178 break;
1179 ++v7;
1180 }
1181 if ( !strcmp(v7, "KB") )
1182 {
1183 spduart_internals.spduart_thstack_ <<= 10;
1184 continue;
1185 }
1186 }
1187 else if ( !strncmp("baud=", av[v5], 5) )
1188 {
1189 v7 = (char *)(av[v5] + 5);
1190 if ( (isdigit(*v7)) == 0 )
1191 return print_usage();
1192 spduart_internals.spduart_baud_ = strtol(v7, 0, 10);
1193 if ( !spduart_set_baud(spduart_internals.spduart_baud_) )
1194 return print_usage();
1195 }
1196 else if ( !strncmp("trig=", av[v5], 5) )
1197 {
1198 v7 = (char *)(av[v5] + 5);
1199 if ( (isdigit(*v7)) == 0 )
1200 return print_usage();
1201 v11 = strtol(v7, 0, 10);
1202 switch ( v11 )
1203 {
1204 case 1:
1205 case 4:
1206 case 8:
1207 case 14:
1208 {
1209 spduart_internals.spduart_trig_ = v11;
1210 break;
1211 }
1212 default:
1213 {
1214 return print_usage();
1215 }
1216 }
1217 }
1218 else
1219 {
1220 return print_usage();
1221 }
1222 while ( *v7 )
1223 {
1224 if ( (isdigit(*v7)) == 0 )
1225 break;
1226 ++v7;
1227 }
1228 if ( *v7 )
1229 return print_usage();
1230 }
1231 if ( (SPD_REG16(SPD_R_REV_3) & 8) == 0 )
1232 {
1233 sceInetPrintf("spduart: SPEED-UART not found\n");
1234 return 1;
1235 }
1236 sceInetPrintf("spduart: SPEED-UART detected\n");
1237 if ( v3 )
1238 {
1239 return 5;
1240 }
1241 if ( RegisterLibraryEntries(&_exp_spduart) )
1242 {
1243 sceInetPrintf("spduart: module already loaded\n");
1244 }
1245 else
1246 {
1247 v14 = 0;
1248 sceInetPrintf(
1249 "spduart: thpri=%d baud=%d trig=%d\n",
1250 spduart_internals.spduart_thpri_,
1251 spduart_internals.spduart_baud_,
1252 spduart_internals.spduart_trig_);
1253 spduart_internals.dev9_uart_reg_area = (uart16550_regs_t *)0xB0000080;
1254 spduart_internals.recv_buf_struct.m_ptr = spduart_internals.buf1data;
1255 spduart_internals.send_buf_struct.m_ptr = spduart_internals.buf2data;
1256 spduart_internals.spduart_start_flag = 1;
1257 spduart_internals.spduart_stop_flag = 0;
1258 spduart_do_init_dev9(&spduart_internals);
1259 for ( v14 = 0; v14 < 30; v14 += 1 )
1260 {
1261 spduart_internals.spduart_msr_cached = spduart_internals.dev9_uart_reg_area->r_scr;
1262 if ( (spduart_internals.spduart_msr_cached & 0x20) != 0 )
1263 {
1264 sceInetPrintf("spduart: Modem module detected\n");
1265 Dev9RegisterPowerOffHandler(1, shutdown_cb);
1266 memset(&v17, 0, sizeof(v17));
1267 spduart_internals.spduart_ef = CreateEventFlag(&v17);
1268 if ( spduart_internals.spduart_ef > 0 )
1269 {
1270 v18.attr = 0x2000000;
1271 v18.thread = spduart_thread_proc;
1272 v18.option = 0;
1273 v18.priority = spduart_internals.spduart_thpri_;
1274 v18.stacksize = spduart_internals.spduart_thstack_;
1275 v16 = CreateThread(&v18);
1276 if ( v16 > 0 )
1277 {
1278 spduart_internals.spduart_thread = v16;
1279 if ( !StartThread(v16, &spduart_internals) )
1280 {
1281 SpdIntrDisable(4096);
1282 SpdRegisterIntrHandler(12, (dev9_intr_cb_t)spduart_dev9_intr_cb);
1283 USec2SysClock(10000u, &spduart_internals.spduart_clock_1e4);
1284 USec2SysClock(1000000u, &spduart_internals.spduart_clock_1e6);
1285 bzero(&spduart_internals.spduart_modem_ops, 108);
1286 spduart_internals.spduart_modem_ops.module_name = "spduart";
1287 spduart_internals.spduart_modem_ops.vendor_name = "SCE";
1288 spduart_internals.spduart_modem_ops.device_name = "Modem (Network Adaptor)";
1289 spduart_internals.spduart_modem_ops.bus_type = 5;
1290 spduart_internals.spduart_modem_ops.start = (int (*)(void *, int))spduart_op_start;
1291 spduart_internals.spduart_modem_ops.stop = (int (*)(void *, int))spduart_op_stop;
1292 spduart_internals.spduart_modem_ops.recv = (int (*)(void *, void *, int))spduart_op_recv;
1293 spduart_internals.spduart_modem_ops.send = (int (*)(void *, void *, int))spduart_op_send;
1294 spduart_internals.spduart_modem_ops.prot_ver = 0;
1295 spduart_internals.spduart_modem_ops.impl_ver = 0;
1296 spduart_internals.spduart_modem_ops.priv = &spduart_internals;
1297 spduart_internals.spduart_modem_ops.control = (int (*)(void *, int, void *, int))spduart_op_control;
1298 if ( sceModemRegisterDevice(&spduart_internals.spduart_modem_ops) >= 0 )
1299 {
1300#if 0
1301 return MODULE_REMOVABLE_END;
1302#else
1303 if ( mi && ((mi->newflags & 2) != 0) )
1304 mi->newflags |= 0x10;
1305 return MODULE_RESIDENT_END;
1306#endif
1307 }
1308 v2 += 1;
1309 TerminateThread(spduart_internals.spduart_thread);
1310 }
1311 v2 += 1;
1312 DeleteThread(spduart_internals.spduart_thread);
1313 }
1314 v2 += 1;
1315 DeleteEventFlag(spduart_internals.spduart_ef);
1316 }
1317 }
1318 DelayThread(100000);
1319 }
1320 sceInetPrintf("spduart: Modem module NOT detected\n");
1321 spduart_deinit();
1322 ReleaseLibraryEntries(&_exp_spduart);
1323 }
1324 sceInetPrintf("spduart: not resident end (fail%d)\n", v2);
1325 return MODULE_NO_RESIDENT_END;
1326}
1327
1328static int module_stop(int ac, char *av[], void *startaddr, ModuleInfo_t *mi)
1329{
1330 (void)ac;
1331 (void)av;
1332 (void)startaddr;
1333 (void)mi;
1334
1335 if ( !spduart_internals.spduart_start_flag && !spduart_internals.spduart_stop_flag )
1336 {
1337 sceInetPrintf("spduart: can't unload (busy)\n");
1338 return MODULE_REMOVABLE_END;
1339 }
1340 sceModemUnregisterDevice(&spduart_internals.spduart_modem_ops);
1341 TerminateThread(spduart_internals.spduart_thread);
1342 DeleteThread(spduart_internals.spduart_thread);
1343 DeleteEventFlag(spduart_internals.spduart_ef);
1344 if ( spduart_internals.spduart_alarm_1e4_flag )
1345 CancelAlarm((unsigned int (*)(void *))alarm_cb_1e4, &spduart_internals);
1346 if ( spduart_internals.spduart_alarm_1e6_flag )
1347 CancelAlarm((unsigned int (*)(void *))alarm_cb_1e6, &spduart_internals);
1348 Dev9RegisterPowerOffHandler(1, 0);
1349 ReleaseLibraryEntries(&_exp_spduart);
1350 SpdIntrDisable(4096);
1351 spduart_deinit();
1352 return MODULE_NO_RESIDENT_END;
1353}
int CpuResumeIntr(int state)
Definition intrman.c:227
int CpuSuspendIntr(int *state)
Definition intrman.c:205
u16 newflags
Definition loadcore.h:36