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