sdk-core v2026.11.05
PS2 SDK - core tier (build-critical EE/IOP modules)
Loading...
Searching...
No Matches
iomanX.c
Go to the documentation of this file.
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
15
16#ifdef _IOP
17#include "irx_imports.h"
18#else
19#include <string.h>
20#include <types.h>
21#define index strchr
22#include <intrman.h>
23#include <stdio.h>
24#define Kprintf printf
25#endif
26#include <iomanX.h>
27
28#include <errno.h>
29#include <stdarg.h>
30
31#ifdef IOP
32#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
33IRX_ID("IOX/File_Manager", 1, 1);
34#else
35IRX_ID("IO/File_Manager", 2, 3);
36// Based on the module from SCE SDK 3.1.0.
37#endif
38#endif
39#ifdef _IOP
40#ifndef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
41extern struct irx_export_table _exp_ioman;
42#endif
43extern struct irx_export_table _exp_iomanx;
44#endif
45
46#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
47#define MAX_DEVICES 32
48#define MAX_FILES 128
49#else
50#define MAX_DEVICES 16
51#define MAX_FILES 32
52#endif
53
54void iomanX_StdioInit(int mode);
55static int open_tty_handles(const char *tty_name);
56static int xx_stat(int op, const char *name, iox_stat_t *stat, unsigned int statmask);
57static int xx_rename(int op, const char *oldname, const char *newname);
58static int xx_dir(int op, const char *name, int mode);
59static int _ioabort(const char *str1, const char *str2);
60static iomanX_iop_file_t *new_iob(void);
61static iomanX_iop_file_t *get_iob(int fd);
62static iomanX_iop_device_t *lookup_dev(const char *name, int show_unkdev_msg);
63static const char *parsefile(const char *path, iomanX_iop_device_t **p_device, int *p_unit);
64static void ShowDrv(void);
65static void register_tty(void);
66#ifdef _IOP
67static void register_dummytty(void);
68#endif
69
70#ifdef IOMANX_USE_DEVICE_LINKED_LIST
71struct ioman_dev_listentry
72{
73 struct ioman_dev_listentry *next;
74 iomanX_iop_device_t *device;
75};
76#endif
77
78static int showdrvflag = 1;
79
80IOMANX_RETURN_VALUE_IMPL(0);
81
82static iomanX_iop_device_ops_t dev_tty_dev_operations = {
83 IOMANX_RETURN_VALUE(0), // init
84 IOMANX_RETURN_VALUE(0), // deinit
85 IOMANX_RETURN_VALUE(0), // format
86 IOMANX_RETURN_VALUE(0), // open
87 IOMANX_RETURN_VALUE(0), // close
88 IOMANX_RETURN_VALUE(0), // read
89 IOMANX_RETURN_VALUE(0), // write
90 IOMANX_RETURN_VALUE(0), // lseek
91 IOMANX_RETURN_VALUE(0), // ioctl
92 IOMANX_RETURN_VALUE(0), // remove
93 IOMANX_RETURN_VALUE(0), // mkdir
94 IOMANX_RETURN_VALUE(0), // rmdir
95 IOMANX_RETURN_VALUE(0), // dopen
96 IOMANX_RETURN_VALUE(0), // dclose
97 IOMANX_RETURN_VALUE(0), // dread
98 IOMANX_RETURN_VALUE(0), // getstat
99 IOMANX_RETURN_VALUE(0), // chstat
100 IOMANX_RETURN_VALUE(0), // rename
101 IOMANX_RETURN_VALUE(0), // chdir
102 IOMANX_RETURN_VALUE(0), // sync
103 IOMANX_RETURN_VALUE(0), // mount
104 IOMANX_RETURN_VALUE(0), // umount
105 IOMANX_RETURN_VALUE_S64(0), // lseek64
106 IOMANX_RETURN_VALUE(0), // devctl
107 IOMANX_RETURN_VALUE(0), // symlink
108 IOMANX_RETURN_VALUE(0), // readlink
109 IOMANX_RETURN_VALUE(0), // ioctl2
110};
111static iomanX_iop_device_t dev_tty = {
112 "tty",
113 IOP_DT_CHAR,
114 1,
115 "CONSOLE",
116 &dev_tty_dev_operations,
117};
118#ifdef _IOP
119static iomanX_iop_device_t dev_dummytty = {
120 "dummytty",
121 IOP_DT_CHAR,
122 1,
123 "CONSOLE",
124 &dev_tty_dev_operations,
125};
126#endif
127static int adddeldrv_in_process;
128#ifdef IOMANX_USE_ERRNO
129static int errno_local;
130#endif
131#ifdef IOMANX_USE_DEVICE_LINKED_LIST
132static struct ioman_dev_listentry *device_entry_empty_list_head;
133static struct ioman_dev_listentry *device_entry_used_list_head;
134#endif
135#ifndef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
136static
137#endif
138 iomanX_iop_file_t file_table[MAX_FILES];
139#ifdef IOMANX_USE_DEVICE_LINKED_LIST
140static struct ioman_dev_listentry device_entry_list[MAX_DEVICES];
141#else
142static iomanX_iop_device_t *device_table[MAX_DEVICES];
143#endif
144
145#ifndef isnum
146#define isnum(c) ((c) >= '0' && (c) <= '9')
147#endif
148
149#ifndef EUNSUP
150#ifdef ENOTSUP
151#define EUNSUP ENOTSUP
152#else
153#define EUNSUP 48
154#endif
155#endif
156
157#define HANDLE_RESULT_CLEAR_INFO 1
158#define HANDLE_RESULT_CLEAR_INFO_ON_ERROR 2
159#define HANDLE_RESULT_RETURN_ZERO 4
160#define HANDLE_RESULT_RETURN_FD 8
161
162static inline void write_str_to_stdout(const char *in_str)
163{
164 iomanX_write(1, (void *)in_str, strlen(in_str));
165}
166
167static inline int set_errno(int in_errno)
168{
169#ifdef IOMANX_USE_ERRNO
170 errno_local = in_errno;
171#endif
172 return -in_errno;
173}
174
175static inline void handle_result_pre(int in_result, iomanX_iop_file_t *f, int op)
176{
177 if ( (op & HANDLE_RESULT_CLEAR_INFO) )
178 {
179 if ( f )
180 {
181 // Unofficial: don't clear mode
182 f->device = NULL;
183 }
184 }
185 if ( (op & HANDLE_RESULT_CLEAR_INFO_ON_ERROR) )
186 {
187 if ( f && (in_result < 0) )
188 {
189 f->device = NULL;
190 }
191 }
192}
193
194static inline int handle_result(int in_result, iomanX_iop_file_t *f, int op)
195{
196 handle_result_pre(in_result, f, op);
197 if ( in_result < 0 )
198 return set_errno(-in_result);
199 if ( (op & HANDLE_RESULT_RETURN_ZERO) )
200 return 0;
201 if ( (op & HANDLE_RESULT_RETURN_FD) )
202 return f - file_table;
203 return in_result;
204}
205
206static inline s64 handle_result64(s64 in_result, iomanX_iop_file_t *f, int op)
207{
208 handle_result_pre(in_result, f, op);
209 if ( in_result < 0 )
210 return set_errno(-(int)in_result);
211 if ( (op & HANDLE_RESULT_RETURN_ZERO) )
212 return 0;
213 if ( (op & HANDLE_RESULT_RETURN_FD) )
214 return f - file_table;
215 return in_result;
216}
217
218#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
219extern int hook_ioman(void);
220extern int unhook_ioman(void);
221#endif
222
223#ifndef IOMANX_ENTRYPOINT
224#ifdef _IOP
225#define IOMANX_ENTRYPOINT _start
226#else
227#define IOMANX_ENTRYPOINT iomanX_start
228#endif
229#endif
230
231#ifndef IOMANX_CLEANUP
232#define IOMANX_CLEANUP shutdown
233#endif
234
235int IOMANX_ENTRYPOINT(int ac, char **av)
236{
237#ifdef IOMANX_USE_DEVICE_LINKED_LIST
238 unsigned int i;
239#endif
240#ifdef _IOP
241 int ioman_already_registered;
242 int state;
243#endif
244
245 (void)ac;
246 (void)av;
247
248 adddeldrv_in_process = 0;
249#ifdef IOMANX_USE_DEVICE_LINKED_LIST
250 // Unofficial: memset instead of bzero
251 memset(device_entry_list, 0, sizeof(device_entry_list));
252 device_entry_used_list_head = NULL;
253 device_entry_empty_list_head = device_entry_list;
254 // Unofficial: link forwards instead of backwards
255 for ( i = 0; i < ((sizeof(device_entry_list) / sizeof(device_entry_list[0])) - 1); i += 1 )
256 device_entry_list[i].next = &device_entry_list[i + 1];
257#else
258 memset(device_table, 0, sizeof(device_table));
259#endif
260 // Unofficial: memset instead of bzero
261 memset(file_table, 0, sizeof(file_table));
262 iomanX_StdioInit(0);
263 // Unofficial: register libraries and hooks after initialization
264#ifdef _IOP
265 CpuSuspendIntr(&state);
266 if ( RegisterLibraryEntries(&_exp_iomanx) )
267 return MODULE_NO_RESIDENT_END;
268#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
269 ioman_already_registered = hook_ioman();
270#else
271 ioman_already_registered = RegisterLibraryEntries(&_exp_ioman);
272#endif
273 if ( ioman_already_registered )
274 return MODULE_NO_RESIDENT_END;
275#if 0
276 SetRebootTimeLibraryHandlingMode(&_exp_ioman, 2);
277#else
278 // Call termination before disabling interrupts
279 _exp_iomanx.mode &= ~6;
280 _exp_iomanx.mode |= 2;
281 CpuResumeIntr(state);
282#endif
283#endif
284 return MODULE_RESIDENT_END;
285}
286
287int IOMANX_CLEANUP(int arg)
288{
289#ifdef IOMANX_USE_DEVICE_LINKED_LIST
290 struct ioman_dev_listentry *i;
291#else
292 unsigned int i;
293#endif
294
295#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
296 unhook_ioman();
297#endif
298
299 if ( !arg )
300 {
301#ifdef IOMANX_USE_DEVICE_LINKED_LIST
302 for ( i = device_entry_used_list_head; i; i = i->next )
303 {
304 i->device->ops->deinit(i->device);
305 i->device = NULL;
306 }
307#else
308 for ( i = 0; i < (sizeof(device_table) / sizeof(device_table[0])); i += 1 )
309 {
310 if ( device_table[i] )
311 {
312 device_table[i]->ops->deinit(device_table[i]);
313 device_table[i] = NULL;
314 }
315 }
316#endif
317 }
318 return MODULE_RESIDENT_END;
319}
320
321#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
322iomanX_iop_device_t **iomanX_GetDeviceList(void)
323{
324 return device_table;
325}
326
327int mode2modex(int mode)
328{
329 int modex = 0;
330
331 if ( (mode & FIO_SO_IFLNK) != 0 )
332 modex |= FIO_S_IFLNK;
333 if ( (mode & FIO_SO_IFREG) != 0 )
334 modex |= FIO_S_IFREG;
335 if ( (mode & FIO_SO_IFDIR) != 0 )
336 modex |= FIO_S_IFDIR;
337
338 /* Convert the file access modes. */
339 if ( mode & FIO_SO_IROTH )
341 if ( mode & FIO_SO_IWOTH )
343 if ( mode & FIO_SO_IXOTH )
345
346 return modex;
347}
348
349int modex2mode(int modex)
350{
351 int mode = 0;
352
353 if ( (modex & FIO_S_IFLNK) != 0 )
354 mode |= FIO_SO_IFLNK;
355 if ( (modex & FIO_S_IFREG) != 0 )
356 mode |= FIO_SO_IFREG;
357 if ( (modex & FIO_S_IFDIR) != 0 )
358 mode |= FIO_SO_IFDIR;
359
360 /* Convert the file access modes. */
361 if ( modex & (FIO_S_IRUSR | FIO_S_IRGRP | FIO_S_IROTH) )
362 mode |= FIO_SO_IROTH;
363 if ( modex & (FIO_S_IWUSR | FIO_S_IWGRP | FIO_S_IWOTH) )
364 mode |= FIO_SO_IWOTH;
365 if ( modex & (FIO_S_IXUSR | FIO_S_IXGRP | FIO_S_IXOTH) )
366 mode |= FIO_SO_IXOTH;
367
368 return mode;
369}
370
371iomanX_iop_file_t *get_file(int fd)
372{
373 return get_iob(fd);
374}
375#endif
376
377void iomanX_StdioInit(int mode)
378{
379#ifdef _IOP
380 const int *BootMode;
381 iop_thread_info_t thinfo;
382#endif
383
384#ifdef _IOP
385 BootMode = QueryBootMode(3);
386 if ( BootMode && (BootMode[1] & 4) )
387 return;
388 ReferThreadStatus(TH_SELF, &thinfo);
389 ChangeThreadPriority(TH_SELF, 4);
390#endif
391#ifdef _IOP
392 switch ( mode )
393 {
394 case 0:
395 {
396 iomanX_close(0);
397 iomanX_close(1);
398 register_tty();
399 open_tty_handles("tty:");
400 break;
401 }
402 case 1:
403 {
404 iomanX_close(0);
405 iomanX_close(1);
406 register_dummytty();
407 open_tty_handles("dummytty:");
408 break;
409 }
410 default:
411 break;
412 }
413#else
414 iomanX_close(0);
415 iomanX_close(1);
416 register_tty();
417 open_tty_handles("tty:");
418#endif
419#ifdef _IOP
420 ChangeThreadPriority(TH_SELF, thinfo.currentPriority);
421#endif
422}
423
424static int open_tty_handles(const char *tty_name)
425{
426 if ( iomanX_open(tty_name, 3) != 0 || iomanX_open(tty_name, 2) != 1 )
427 return -1;
428 return 0;
429}
430
431int iomanX_open(const char *name, int flags, ...)
432{
434 const char *parsefile_res;
435 int mode;
436 va_list va;
437
438 va_start(va, flags);
439 mode = va_arg(va, int);
440 va_end(va);
441 f = new_iob();
442 if ( !f )
443 return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
444 parsefile_res = parsefile(name, &(f->device), &(f->unit));
445 if ( !parsefile_res )
446 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
447 f->mode = flags;
448 return handle_result(
449 f->device->ops->open(f, parsefile_res, flags, mode),
450 f,
451 HANDLE_RESULT_CLEAR_INFO_ON_ERROR | HANDLE_RESULT_RETURN_FD);
452}
453
454int iomanX_lseek(int fd, int offset, int mode)
455{
457
458 f = get_iob(fd);
459 if ( !f )
460 return handle_result(-EBADF, f, 0);
461 switch ( mode )
462 {
463 case FIO_SEEK_SET:
464 case FIO_SEEK_CUR:
465 case FIO_SEEK_END:
466 return handle_result(f->device->ops->lseek(f, offset, mode), f, 0);
467 default:
468 write_str_to_stdout("invalid lseek arg\r\n");
469 return handle_result(-EINVAL, f, 0);
470 }
471}
472
473s64 iomanX_lseek64(int fd, s64 offset, int whence)
474{
476
477 f = get_iob(fd);
478 if ( !f )
479 return handle_result(-EBADF, f, 0);
480 if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT )
481 return handle_result(-EUNSUP, f, 0);
482 switch ( whence )
483 {
484 case FIO_SEEK_SET:
485 case FIO_SEEK_CUR:
486 case FIO_SEEK_END:
487 return handle_result64(f->device->ops->lseek64(f, offset, whence), f, 0);
488 default:
489 write_str_to_stdout("invalid lseek arg\r\n");
490 return handle_result(-EINVAL, f, 0);
491 }
492}
493
494int iomanX_read(int fd, void *ptr, int size)
495{
497
498 f = get_iob(fd);
499 if ( !f || !(f->mode & FIO_O_RDONLY) )
500 return handle_result(-EBADF, f, 0);
501 return handle_result(f->device->ops->read(f, ptr, size), f, 0);
502}
503
504int iomanX_write(int fd, void *ptr, int size)
505{
507
508 f = get_iob(fd);
509 if ( !f || !(f->mode & FIO_O_WRONLY) )
510 return handle_result(-EBADF, f, 0);
511 return handle_result(f->device->ops->write(f, ptr, size), f, 0);
512}
513
514int iomanX_close(int fd)
515{
517
518 f = get_iob(fd);
519 if ( !f )
520 return handle_result(-EBADF, f, 0);
521 return handle_result(
522 (f->mode & FIO_O_DIROPEN) ? f->device->ops->dclose(f) : f->device->ops->close(f),
523 f,
524 HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_FD);
525}
526
527int iomanX_ioctl(int fd, int cmd, void *param)
528{
530
531 f = get_iob(fd);
532 if ( !f )
533 return handle_result(-EBADF, f, 0);
534 return handle_result(f->device->ops->ioctl(f, cmd, param), f, 0);
535}
536
537int iomanX_ioctl2(int fd, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen)
538{
540
541 f = get_iob(fd);
542 if ( !f )
543 return handle_result(-EBADF, f, 0);
544 // The filesystem must support these ops.
545 if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT )
546 return handle_result(-EUNSUP, f, 0);
547 return handle_result(f->device->ops->ioctl2(f, cmd, arg, arglen, buf, buflen), f, 0);
548}
549
550int iomanX_dopen(const char *path)
551{
553 const char *parsefile_res;
554
555 f = new_iob();
556 if ( !f )
557 return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
558 parsefile_res = parsefile(path, &(f->device), &(f->unit));
559 if ( !parsefile_res )
560 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
561 f->mode = FIO_O_DIROPEN;
562 return handle_result(
563 f->device->ops->dopen(f, parsefile_res), f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR | HANDLE_RESULT_RETURN_FD);
564}
565
566int iomanX_dread(int fd, iox_dirent_t *buf)
567{
569
570 f = get_iob(fd);
571 if ( !f || !(f->mode & FIO_O_DIROPEN) )
572 return handle_result(-EBADF, f, 0);
573#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
574 /* If this is a legacy device (such as mc:) then we need to convert the mode
575 variable of the stat structure to iomanX's extended format. */
576 if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT )
577 {
578 int res;
579 typedef int io_dread_t(iomanX_iop_file_t *, io_dirent_t *);
580 io_dirent_t io_dirent;
581 io_dread_t *io_dread;
582
583 io_dread = (io_dread_t *)f->device->ops->dread;
584 res = io_dread(f, &io_dirent);
585
586 buf->stat.mode = mode2modex(io_dirent.stat.mode);
587
588 buf->stat.attr = io_dirent.stat.attr;
589 buf->stat.size = io_dirent.stat.size;
590 memcpy(buf->stat.ctime, io_dirent.stat.ctime, sizeof(io_dirent.stat.ctime));
591 memcpy(buf->stat.atime, io_dirent.stat.atime, sizeof(io_dirent.stat.atime));
592 memcpy(buf->stat.mtime, io_dirent.stat.mtime, sizeof(io_dirent.stat.mtime));
593 buf->stat.hisize = io_dirent.stat.hisize;
594
595 strncpy(buf->name, io_dirent.name, sizeof(buf->name));
596 return handle_result(res, f, 0);
597 }
598#endif
599 return handle_result(f->device->ops->dread(f, buf), f, 0);
600}
601
602int iomanX_remove(const char *name)
603{
605 const char *parsefile_res;
606#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
607 iomanX_iop_file_t f_stk;
608#endif
609
610#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
611 f = &f_stk;
612#else
613 f = new_iob();
614 if ( !f )
615 return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
616#endif
617 parsefile_res = parsefile(name, &(f->device), &(f->unit));
618 if ( !parsefile_res )
619 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
620 return handle_result(
621 f->device->ops->remove(f, parsefile_res), f, HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
622}
623
624int iomanX_mkdir(const char *path, int mode)
625{
626 return xx_dir(4, path, mode);
627}
628
629int iomanX_rmdir(const char *path)
630{
631 return xx_dir(5, path, 0);
632}
633
634static int xx_stat(int op, const char *name, iox_stat_t *stat, unsigned int statmask)
635{
637 const char *parsefile_res;
638#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
639 iomanX_iop_file_t f_stk;
640#endif
641
642#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
643 f = &f_stk;
644#else
645 f = new_iob();
646 if ( !f )
647 return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
648#endif
649 parsefile_res = parsefile(name, &(f->device), &(f->unit));
650 if ( !parsefile_res )
651 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
652 switch ( op )
653 {
654 case 1:
655 {
656#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
657 /* If this is a legacy device (such as mc:) then we need to convert the mode
658 variable to iomanX's extended format. */
659 if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT )
660 {
661 iox_stat_t stat_tmp;
662
663 memcpy(&stat_tmp, stat, sizeof(stat_tmp));
664 stat_tmp.mode = modex2mode(stat->mode);
665 return handle_result(
666 f->device->ops->chstat(f, parsefile_res, &stat_tmp, statmask),
667 f,
668 HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
669 }
670#endif
671 return handle_result(
672 f->device->ops->chstat(f, parsefile_res, stat, statmask),
673 f,
674 HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
675 }
676 case 2:
677 {
678#ifdef IOMANX_ENABLE_LEGACY_IOMAN_HOOK
679 /* If this is a legacy device (such as mc:) then we need to convert the mode
680 variable to iomanX's extended format. */
681 if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT )
682 {
683 int res;
684
685 res = f->device->ops->getstat(f, parsefile_res, stat);
686 if ( res == 0 )
687 stat->mode = mode2modex(stat->mode);
688 return handle_result(res, f, HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
689 }
690#endif
691 return handle_result(
692 f->device->ops->getstat(f, parsefile_res, stat), f, HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
693 }
694 default:
695 // Unofficial: return negative instead of positive if op not found
696 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
697 }
698}
699
700int iomanX_getstat(const char *name, iox_stat_t *stat)
701{
702 return xx_stat(2, name, stat, 0);
703}
704
705int iomanX_chstat(const char *name, iox_stat_t *stat, unsigned int statmask)
706{
707 return xx_stat(1, name, stat, statmask);
708}
709
710int iomanX_format(const char *dev, const char *blockdev, void *arg, int arglen)
711{
713 const char *parsefile_res;
714#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
715 iomanX_iop_file_t f_stk;
716#endif
717
718#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
719 f = &f_stk;
720#else
721 f = new_iob();
722 if ( !f )
723 return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
724#endif
725 parsefile_res = parsefile(dev, &(f->device), &(f->unit));
726 if ( !parsefile_res )
727 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
728 return handle_result(
729 f->device->ops->format(f, parsefile_res, blockdev, arg, arglen),
730 f,
731 HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
732}
733
734static int xx_rename(int op, const char *oldname, const char *newname)
735{
737 const char *parsefile_res;
738 const char *parsefile_res_new;
739 iomanX_iop_device_t *device_new;
740 int unit_new;
741#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
742 iomanX_iop_file_t f_stk;
743#endif
744
745#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
746 f = &f_stk;
747#else
748 f = new_iob();
749 if ( !f )
750 return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
751#endif
752 parsefile_res = parsefile(oldname, &(f->device), &(f->unit));
753 if ( !parsefile_res )
754 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
755 // Unofficial: initialize variables and check if newname is not NULL
756 parsefile_res_new = newname;
757 device_new = f->device;
758 unit_new = f->unit;
759 if ( newname && index(newname, ':') )
760 parsefile_res_new = parsefile(newname, &device_new, &unit_new);
761 // Make sure the user isn't attempting to link across devices.
762 if ( !parsefile_res_new || (device_new != f->device) || (unit_new != f->unit) )
763 return handle_result(-EXDEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
764 // The filesystem must support these ops.
765 if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT )
766 return handle_result(-EUNSUP, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
767 switch ( op )
768 {
769 case 7:
770 return handle_result(
771 f->device->ops->rename(f, parsefile_res, parsefile_res_new),
772 f,
773 HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
774 case 8:
775 return handle_result(
776 f->device->ops->symlink(f, parsefile_res, parsefile_res_new),
777 f,
778 HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
779 default:
780 // Unofficial: return negative instead of positive if op not found
781 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
782 }
783}
784
785// cppcheck-suppress funcArgNamesDifferent
786int iomanX_rename(const char *oldname, const char *newname)
787{
788 return xx_rename(7, oldname, newname);
789}
790
791// cppcheck-suppress funcArgNamesDifferent
792int iomanX_symlink(const char *oldname, const char *newname)
793{
794 return xx_rename(8, oldname, newname);
795}
796
797int iomanX_chdir(const char *name)
798{
799 return xx_dir(0x103, name, 0);
800}
801
802/* Because mkdir, rmdir, chdir, and sync have similiar arguments (each starts
803 with a path followed by an optional integer), we use a common routine to
804 handle all of them. */
805static int xx_dir(int op, const char *name, int mode)
806{
808 const char *parsefile_res;
809#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
810 iomanX_iop_file_t f_stk;
811#endif
812
813#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
814 f = &f_stk;
815#else
816 f = new_iob();
817 if ( !f )
818 return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
819#endif
820 parsefile_res = parsefile(name, &(f->device), &(f->unit));
821 if ( !parsefile_res )
822 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
823 // The filesystem must support these ops.
824 if ( (op & 0x100) && ((f->device->type & 0xF0000000) != IOP_DT_FSEXT) )
825 return handle_result(-EUNSUP, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
826 switch ( op )
827 {
828 case 4:
829 return handle_result(
830 f->device->ops->mkdir(f, parsefile_res, mode), f, HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
831 case 5:
832 return handle_result(
833 f->device->ops->rmdir(f, parsefile_res), f, HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
834 case 0x103:
835 return handle_result(
836 f->device->ops->chdir(f, parsefile_res), f, HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
837 case 0x106:
838 return handle_result(
839 f->device->ops->sync(f, parsefile_res, mode), f, HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
840 default:
841 // Unofficial: return negative instead of positive if op not found
842 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
843 }
844}
845
846int iomanX_sync(const char *dev, int flag)
847{
848 return xx_dir(0x106, dev, flag);
849}
850
851int iomanX_mount(const char *fsname, const char *devname, int flag, void *arg, int arglen)
852{
854 const char *parsefile_res;
855#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
856 iomanX_iop_file_t f_stk;
857#endif
858
859#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
860 f = &f_stk;
861#else
862 f = new_iob();
863 if ( !f )
864 return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
865#endif
866 parsefile_res = parsefile(fsname, &(f->device), &(f->unit));
867 if ( !parsefile_res )
868 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
869 // The filesystem must support these ops.
870 if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT )
871 return handle_result(-EUNSUP, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
872 return handle_result(
873 f->device->ops->mount(f, parsefile_res, devname, flag, arg, arglen),
874 f,
875 HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
876}
877
878int iomanX_umount(const char *fsname)
879{
881 const char *parsefile_res;
882#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
883 iomanX_iop_file_t f_stk;
884#endif
885
886#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
887 f = &f_stk;
888#else
889 f = new_iob();
890 if ( !f )
891 return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
892#endif
893 parsefile_res = parsefile(fsname, &(f->device), &(f->unit));
894 if ( !parsefile_res )
895 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
896 // The filesystem must support these ops.
897 if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT )
898 return handle_result(-EUNSUP, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
899 return handle_result(
900 f->device->ops->umount(f, parsefile_res), f, HANDLE_RESULT_CLEAR_INFO | HANDLE_RESULT_RETURN_ZERO);
901}
902
903int iomanX_devctl(const char *name, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen)
904{
906 const char *parsefile_res;
907#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
908 iomanX_iop_file_t f_stk;
909#endif
910
911#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
912 f = &f_stk;
913#else
914 f = new_iob();
915 if ( !f )
916 return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
917#endif
918 parsefile_res = parsefile(name, &(f->device), &(f->unit));
919 if ( !parsefile_res )
920 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
921 // The filesystem must support these ops.
922 if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT )
923 return handle_result(-EUNSUP, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
924 return handle_result(
925 f->device->ops->devctl(f, parsefile_res, cmd, arg, arglen, buf, buflen), f, HANDLE_RESULT_CLEAR_INFO);
926}
927
928int iomanX_readlink(const char *path, char *buf, unsigned int buflen)
929{
931 const char *parsefile_res;
932#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
933 iomanX_iop_file_t f_stk;
934#endif
935
936#ifdef IOMAN_USE_FILE_STRUCT_TEMP_STACK
937 f = &f_stk;
938#else
939 f = new_iob();
940 if ( !f )
941 return handle_result(-EMFILE, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
942#endif
943 parsefile_res = parsefile(path, &(f->device), &(f->unit));
944 if ( !parsefile_res )
945 return handle_result(-ENODEV, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
946 // The filesystem must support these ops.
947 if ( (f->device->type & 0xF0000000) != IOP_DT_FSEXT )
948 return handle_result(-EUNSUP, f, HANDLE_RESULT_CLEAR_INFO_ON_ERROR);
949 return handle_result(f->device->ops->readlink(f, parsefile_res, buf, buflen), f, HANDLE_RESULT_CLEAR_INFO);
950}
951
952static int _ioabort(const char *str1, const char *str2)
953{
954 return Kprintf("ioabort exit:%s %s\n", str1, str2);
955}
956
957static iomanX_iop_file_t *new_iob(void)
958{
959 iomanX_iop_file_t *file_table_entry;
960 int state;
961 int fd;
962
963 fd = 0;
964 CpuSuspendIntr(&state);
965 file_table_entry = NULL;
966 while ( fd < (int)(sizeof(file_table) / sizeof(file_table[0])) )
967 {
968 if ( !file_table[fd].device )
969 {
970 file_table_entry = &file_table[fd];
971 break;
972 }
973 fd += 1;
974 }
975 // fill in "device" temporarily to mark the fd as allocated.
976 if ( file_table_entry )
977 file_table_entry->device = (iomanX_iop_device_t *)(uiptr)0xFFFFFFEC;
978 CpuResumeIntr(state);
979 if ( !file_table_entry )
980 _ioabort("out of file descriptors", "[too many open]");
981 return file_table_entry;
982}
983
984static iomanX_iop_file_t *get_iob(int fd)
985{
986 if ( (fd < 0) || (fd >= (int)(sizeof(file_table) / sizeof(file_table[0]))) || (!file_table[fd].device) )
987 return NULL;
988 return &file_table[fd];
989}
990
991static iomanX_iop_device_t *lookup_dev(const char *name, int show_unkdev_msg)
992{
993#ifdef IOMANX_USE_DEVICE_LINKED_LIST
994 struct ioman_dev_listentry *entry;
995#else
996 iomanX_iop_device_t *device;
997 unsigned int i;
998#endif
999 int state;
1000
1001 CpuSuspendIntr(&state);
1002#ifdef IOMANX_USE_DEVICE_LINKED_LIST
1003 entry = device_entry_used_list_head;
1004 while ( entry && strcmp(name, entry->device->name) )
1005 entry = entry->next;
1006 if ( !entry && show_unkdev_msg )
1007 {
1008 Kprintf("Unknown device '%s'\n", name);
1009 ShowDrv();
1010 }
1011#else
1012 device = NULL;
1013 for ( i = 0; i < (sizeof(device_table) / sizeof(device_table[0])); i += 1 )
1014 {
1015 if ( device_table[i] && !strcmp(name, device_table[i]->name) )
1016 {
1017 device = device_table[i];
1018 break;
1019 }
1020 }
1021 if ( !device && show_unkdev_msg )
1022 {
1023 Kprintf("Unknown device '%s'\n", name);
1024 ShowDrv();
1025 }
1026#endif
1027 CpuResumeIntr(state);
1028#ifdef IOMANX_USE_DEVICE_LINKED_LIST
1029 return entry ? entry->device : NULL;
1030#else
1031 return device;
1032#endif
1033}
1034
1035static const char *parsefile(const char *path, iomanX_iop_device_t **p_device, int *p_unit)
1036{
1037 const char *path_trimmed;
1038 char *colon_index;
1039 size_t devname_len;
1040 iomanX_iop_device_t *device;
1041 int unit;
1042 char canon[32];
1043
1044 path_trimmed = path;
1045 while ( *path_trimmed == ' ' )
1046 path_trimmed += 1;
1047 colon_index = index(path_trimmed, ':');
1048 // Unofficial: On error, return NULL instead of -1
1049 if ( !colon_index )
1050 {
1051 Kprintf("Unknown device '%s'\n", path_trimmed);
1052 return NULL;
1053 }
1054 devname_len = colon_index - path_trimmed;
1055 // Unofficial: bounds check
1056 if ( devname_len > (sizeof(canon) - 1) )
1057 return NULL;
1058 strncpy(canon, path_trimmed, devname_len);
1059 canon[devname_len] = 0;
1060 unit = 0;
1061 // Search backward for the unit number.
1062 while ( isnum(canon[devname_len - 1]) )
1063 devname_len -= 1;
1064 if ( isnum(canon[devname_len]) )
1065 unit = strtol(&canon[devname_len], 0, 10);
1066 canon[devname_len] = 0;
1067 // Find the actual device.
1068 device = lookup_dev(canon, 1);
1069 // Unofficial: On error, return NULL instead of -1
1070 if ( !device )
1071 return NULL;
1072 // Unofficial: set unit and device only after success
1073 *p_unit = unit;
1074 *p_device = device;
1075 // This is the name passed to the device op.
1076 return colon_index + 1;
1077}
1078
1079// Unofficial: unused "io request for unsupported operation" func removed
1080
1081int iomanX_AddDrv(iomanX_iop_device_t *device)
1082{
1083#ifdef IOMANX_USE_DEVICE_LINKED_LIST
1084 struct ioman_dev_listentry *entry;
1085 struct ioman_dev_listentry *old_head;
1086#else
1087 unsigned int i;
1088#endif
1089 int state;
1090
1091 CpuSuspendIntr(&state);
1092 if ( adddeldrv_in_process )
1093 {
1094 Kprintf("AddDrv()/DelDrv() recursive/mutithread call error !!");
1095 CpuResumeIntr(state);
1096 return -1;
1097 }
1098 // Unofficial: move list check out of interrupt disabled area
1099 adddeldrv_in_process = 1;
1100 CpuResumeIntr(state);
1101#ifdef IOMANX_USE_DEVICE_LINKED_LIST
1102 entry = device_entry_empty_list_head;
1103 // Unofficial: check if entry exists first
1104 if ( !entry || lookup_dev(device->name, 0) )
1105 {
1106 adddeldrv_in_process = 0;
1107 return -1;
1108 }
1109 entry->device = device;
1110 device_entry_empty_list_head = entry->next;
1111 if ( device->ops->init(device) < 0 )
1112 {
1113 old_head = device_entry_empty_list_head;
1114 entry->device = NULL;
1115 device_entry_empty_list_head = entry;
1116 entry->next = old_head;
1117 adddeldrv_in_process = 0;
1118 return -1;
1119 }
1120 old_head = device_entry_used_list_head;
1121 device_entry_used_list_head = entry;
1122 entry->next = old_head;
1123#else
1124 for ( i = 0; i < (sizeof(device_table) / sizeof(device_table[0])); i += 1 )
1125 {
1126 if ( !device_table[i] )
1127 break;
1128 }
1129
1130 if ( i >= (sizeof(device_table) / sizeof(device_table[0])) )
1131 {
1132 adddeldrv_in_process = 0;
1133 return -1;
1134 }
1135
1136 device_table[i] = device;
1137#ifdef _IOP
1138 FlushIcache();
1139#endif
1140 if ( device->ops->init(device) < 0 )
1141 {
1142 device_table[i] = NULL;
1143 adddeldrv_in_process = 0;
1144 return -1;
1145 }
1146#endif
1147 showdrvflag = 1;
1148 adddeldrv_in_process = 0;
1149 return 0;
1150}
1151
1152int iomanX_DelDrv(const char *name)
1153{
1154#ifdef IOMANX_USE_DEVICE_LINKED_LIST
1155 struct ioman_dev_listentry *entry;
1156 struct ioman_dev_listentry **p_next;
1157 struct ioman_dev_listentry *old_head;
1158#else
1159 unsigned int i;
1160#endif
1161 int state;
1162
1163 CpuSuspendIntr(&state);
1164 if ( adddeldrv_in_process )
1165 {
1166 Kprintf("AddDrv()/DelDrv() recursive/mutithread call error !!");
1167 CpuResumeIntr(state);
1168 return -1;
1169 }
1170 adddeldrv_in_process = 1;
1171 CpuResumeIntr(state);
1172#ifdef IOMANX_USE_DEVICE_LINKED_LIST
1173 entry = device_entry_used_list_head;
1174 p_next = &device_entry_used_list_head;
1175 while ( entry && strcmp(name, entry->device->name) )
1176 {
1177 p_next = &entry->next;
1178 entry = entry->next;
1179 }
1180 if ( !entry || entry->device->ops->deinit(entry->device) < 0 )
1181 {
1182 adddeldrv_in_process = 0;
1183 return -1;
1184 }
1185 old_head = device_entry_empty_list_head;
1186 entry->device = NULL;
1187 device_entry_empty_list_head = entry;
1188 *p_next = entry->next;
1189 entry->next = old_head;
1190 adddeldrv_in_process = 0;
1191 return 0;
1192#else
1193 for ( i = 0; i < (sizeof(device_table) / sizeof(device_table[0])); i += 1 )
1194 {
1195 if ( device_table[i] && !strcmp(name, device_table[i]->name) )
1196 {
1197 device_table[i]->ops->deinit(device_table[i]);
1198 device_table[i] = NULL;
1199 adddeldrv_in_process = 0;
1200 return 0;
1201 }
1202 }
1203
1204 adddeldrv_in_process = 0;
1205 return -1;
1206#endif
1207}
1208
1209unsigned int iomanX_GetDevType(int fd)
1210{
1212
1213 f = get_iob(fd);
1214 if ( !f )
1215 return handle_result(-EBADF, f, 0);
1216 return f->device->type;
1217}
1218
1219static void ShowDrv(void)
1220{
1221#ifdef IOMANX_USE_DEVICE_LINKED_LIST
1222 struct ioman_dev_listentry *i;
1223#else
1224 unsigned int i;
1225#endif
1226
1227 if ( !showdrvflag )
1228 return;
1229 Kprintf("Known devices are ");
1230#ifdef IOMANX_USE_DEVICE_LINKED_LIST
1231 for ( i = device_entry_used_list_head; i; i = i->next )
1232 Kprintf(" %s:(%s) ", i->device->name, i->device->desc);
1233#else
1234 for ( i = 0; i < (sizeof(device_table) / sizeof(device_table[0])); i += 1 )
1235 if ( device_table[i] != NULL && device_table[i]->name != NULL )
1236 Kprintf(" %s:(%s) ", device_table[i]->name, device_table[i]->desc);
1237#endif
1238 Kprintf("\n");
1239 showdrvflag = 0;
1240}
1241
1242static void register_tty(void)
1243{
1244 iomanX_DelDrv(dev_tty.name);
1245 iomanX_AddDrv(&dev_tty);
1246}
1247
1248#ifdef _IOP
1249static void register_dummytty(void)
1250{
1251 iomanX_DelDrv(dev_dummytty.name);
1252 iomanX_AddDrv(&dev_dummytty);
1253}
1254#endif
#define EINVAL
Definition errno.h:72
#define EUNSUP
Definition errno.h:126
#define EXDEV
Definition errno.h:64
#define EMFILE
Definition errno.h:76
#define ENODEV
Definition errno.h:66
#define EBADF
Definition errno.h:46
int CpuResumeIntr(int state)
Definition intrman.c:217
int CpuSuspendIntr(int *state)
Definition intrman.c:195
int iomanX_format(const char *dev, const char *blockdev, void *arg, int arglen)
Definition iomanX.c:710
struct _iomanX_iop_file iomanX_iop_file_t
#define IOP_DT_FSEXT
Definition iomanX.h:67
#define FIO_S_IXGRP
Definition iox_stat.h:72
#define FIO_SO_IFDIR
Definition iox_stat.h:129
#define FIO_SO_IFLNK
Definition iox_stat.h:125
#define FIO_S_IROTH
Definition iox_stat.h:77
#define FIO_SO_IXOTH
Definition iox_stat.h:136
#define FIO_S_IXUSR
Definition iox_stat.h:63
#define FIO_S_IRGRP
Definition iox_stat.h:68
#define FIO_S_IXOTH
Definition iox_stat.h:81
#define FIO_S_IWOTH
Definition iox_stat.h:79
#define FIO_S_IRUSR
Definition iox_stat.h:59
#define FIO_S_IWGRP
Definition iox_stat.h:70
#define FIO_SO_IWOTH
Definition iox_stat.h:134
#define FIO_S_IFLNK
Definition iox_stat.h:42
#define FIO_SO_IFREG
Definition iox_stat.h:127
#define FIO_S_IFDIR
Definition iox_stat.h:46
#define FIO_SO_IROTH
Definition iox_stat.h:132
#define FIO_S_IFREG
Definition iox_stat.h:44
#define FIO_S_IWUSR
Definition iox_stat.h:61
#define TH_SELF
Definition kernel.h:69
struct _iomanX_iop_device * device
Definition iomanX.h:77