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