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