PS2SDK
PS2 Homebrew Libraries
devfs.c
Go to the documentation of this file.
1 /*
2 # _____ ___ ____ ___ ____
3 # ____| | ____| | | |____|
4 # | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5 #-----------------------------------------------------------------------
6 # Copyright 2001-2004, 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 #include "types.h"
17 #include "defs.h"
18 #include "irx.h"
19 #include "loadcore.h"
20 #include "thbase.h"
21 #include "thevent.h"
22 #include "thsemap.h"
23 #include "intrman.h"
24 #include "stdio.h"
25 #include "sysclib.h"
26 #include <errno.h>
27 #include "devfs.h"
28 #include "sysmem.h"
29 #include "stdio.h"
30 
31 #ifdef USE_IOMAN
32 #include "ioman.h"
33 #else
34 #include "iomanX.h"
35 #endif
36 
37 #define MODNAME "devfs"
38 IRX_ID(MODNAME, 1, 1);
39 
40 #define M_PRINTF(format, args...) printf(MODNAME ": " format, ## args)
41 
42 #define BANNER "DEVFS %s\n"
43 #define VERSION "v0.1"
44 #define MAX_OPENFILES 32
45 #define MAX_OPEN_DIRFILES 16
46 
47 extern struct irx_export_table _exp_devfs;
48 
49 typedef struct
50 
51 {
52  void *data;
53  s32 valid;
54  u32 mode;
55  u32 open_refcount;
56  devfs_loc_t extent;
57  struct _ioman_data *open_files[MAX_OPENFILES];
58 } subdev_t;
59 
60 typedef struct _devfs_device
61 {
63  struct _devfs_device *forw, *back;
64  HDEV hDev;
65  devfs_node_t node;
66  subdev_t subdevs[DEVFS_MAX_SUBDEVS];
67  u32 subdev_count;
68  u32 open_refcount;
70 
71 typedef struct _ioman_data
72 {
73  HDEV hDev;
76  int subdev;
77  u32 mode;
78  devfs_loc_t loc;
79 } ioman_data_t;
80 
83 HDEV dev_count;
84 
85 typedef struct _directory_file
86 
87 {
91  u32 devno;
93  u32 opened;
95 
96 directory_file_t open_dirfiles[MAX_OPEN_DIRFILES];
97 
103 const char *devfs_subdev_to_str(int subdev)
104 
105 {
106  static char name[4]; /* Supports up to 999 subdevices */
107  int loop;
108 
109  if((subdev > 999) || (subdev < 0))
110  {
111  name[0] = 0;
112  }
113  else
114  {
115  loop = 0;
116  name[loop++] = ((subdev / 100) % 10) + '0';
117  name[loop++] = ((subdev / 10) % 10) + '0';
118  name[loop++] = (subdev % 10) + '0';
119  name[loop++] = 0;
120  }
121 
122  loop = 0;
123  if(name[0] == '0') loop = 1;
124  if((name[0] == '0') && (name[1] == '0')) loop = 2;
125 
126  return &name[loop];
127 }
128 
137 int devfs_fill_dirent(iox_dirent_t *dirent, int devno)
138 
139 {
140  devfs_device_t *dev_scan;
141  int curr_no = 0;
142  u32 subdev_loop;
143 
144  dev_scan = root_device;
145 
146  while(dev_scan != NULL)
147  {
148  if((curr_no + dev_scan->subdev_count) > (u32)devno)
149  {
150  for(subdev_loop = 0; subdev_loop < DEVFS_MAX_SUBDEVS; subdev_loop++)
151  {
152  if(dev_scan->subdevs[subdev_loop].valid)
153  {
154  if(curr_no == devno)
155  {
156  break;
157  }
158  curr_no++;
159  }
160  }
161 
162  if(subdev_loop < DEVFS_MAX_SUBDEVS)
163  {
164  memset(dirent, 0, sizeof(iox_dirent_t));
165  dirent->stat.size = dev_scan->subdevs[subdev_loop].extent.loc32[0];
166  dirent->stat.hisize = dev_scan->subdevs[subdev_loop].extent.loc32[1];
167  dirent->stat.mode = FIO_S_IFREG;
168  if(dev_scan->subdevs[subdev_loop].mode & DEVFS_MODE_R)
169  {
170  dirent->stat.mode |= FIO_S_IRUSR;
171  }
172  if(dev_scan->subdevs[subdev_loop].mode & DEVFS_MODE_W)
173  {
174  dirent->stat.mode |= FIO_S_IWUSR;
175  }
176  dirent->name[0] = 0;
177  strcpy(dirent->name, dev_scan->node.name);
178  strcat(dirent->name, devfs_subdev_to_str(subdev_loop));
179 
180  return strlen(dirent->name);
181  }
182  }
183 
184  curr_no += dev_scan->subdev_count;
185 
186  dev_scan = dev_scan->forw;
187  }
188 
189  return 0;
190 }
191 
199 
200 {
201  devfs_device_t *dev;
202 
203  if((node == NULL) || (node->name == NULL))
204  {
205  return NULL;
206  }
207 
208  dev = AllocSysMemory(ALLOC_FIRST, sizeof(devfs_device_t), NULL);
209  if(dev == NULL)
210  {
211  printf("create_device: Alloc Failed\n");
212  return NULL;
213  }
214 
215  memset(dev, 0, sizeof(devfs_device_t));
216  memcpy(&dev->node, node, sizeof(devfs_node_t));
217  if(dev->node.name != NULL)
218  {
219  dev->node.name = AllocSysMemory(ALLOC_FIRST, strlen(node->name) + 1, NULL);
220  if(dev->node.name == NULL)
221  {
222  FreeSysMemory(dev);
223  return NULL;
224  }
225  memcpy(dev->node.name, node->name, strlen(node->name) + 1);
226  }
227 
228  if(dev->node.desc != NULL)
229  {
230  dev->node.desc = AllocSysMemory(ALLOC_FIRST, strlen(node->desc) + 1, NULL);
231  if(dev->node.name == NULL)
232  {
233  FreeSysMemory(dev->node.name);
234  FreeSysMemory(dev);
235  return NULL;
236  }
237  memcpy(dev->node.desc, node->desc, strlen(node->desc) + 1);
238  }
239 
240  return dev;
241 }
242 
249 
250 {
251  if(dev != NULL)
252  {
253  if(dev->node.name)
254  {
255  FreeSysMemory(dev->node.name);
256  }
257 
258  if(dev->node.desc)
259  {
260  FreeSysMemory(dev->node.desc);
261  }
262 
263  FreeSysMemory(dev);
264  }
265 
266  return 0;
267 }
268 
277 
278 {
279  devfs_device_t *dev_scan;
280 
281  if(name == NULL)
282  {
283  return NULL;
284  }
285 
286  dev_scan = root_device;
287 
288  while(dev_scan != NULL)
289  {
290  /* Ensure name is at least less than or equal to the one we want to find */
291  if(strlen(dev_scan->node.name) <= strlen(name))
292  {
293  if(strncmp(dev_scan->node.name, name, strlen(dev_scan->node.name)) == 0)
294  {
295  return dev_scan;
296  }
297  }
298  dev_scan = dev_scan->forw;
299  }
300 
301  return NULL;
302 }
303 
310 
311 {
312  devfs_device_t *dev_scan;
313 
314  dev_scan = root_device;
315 
316  while(dev_scan != NULL)
317  {
318  if(dev_scan->hDev == hDev)
319  {
320  return dev_scan;
321  }
322  dev_scan = dev_scan->forw;
323  }
324 
325  return NULL;
326 }
327 
334 #ifdef USE_IOMAN
335 int devfs_open(iop_file_t *file, const char *name, int mode)
336 #else
337 int devfs_open(iop_file_t *file, const char *name, int mode, int unused)
338 #endif
339 {
340  devfs_device_t *dev;
341  int fn_offset = 0;
342 
343  (void)unused;
344 
345  //printf("devfs_open file=%p name=%s mode=%d\n", file, name, mode);
346  if(name == NULL)
347  {
348  M_PRINTF("open: Name is NULL\n");
349  return -EPERM;
350  }
351 
352  if((name[0] == '\\') || (name[0] == '/'))
353  {
354  fn_offset = 1;
355  }
356 
357  dev = devfs_find_devicename(name + fn_offset);
358 
359  if(dev != NULL)
360  {
361  int loop;
362  char *endp;
363  int subdev;
364  int name_len;
365 
366  name_len = strlen(dev->node.name);
367 
368  if((unsigned int)name_len == strlen(name)) /* If this is has not got a subnumber */
369  {
370  M_PRINTF("open: No subdevice number in filename %s\n", name);
371  return -EPERM;
372  }
373 
374  subdev = strtoul(&name[name_len + fn_offset], &endp, 10);
375  if(((subdev == 0) && (name[name_len + fn_offset] != '0'))
376  || (subdev >= DEVFS_MAX_SUBDEVS))
377  /* Invalid number */
378  {
379  M_PRINTF("open: Invalid subdev number %d\n", subdev);
380  return -EPERM;
381  }
382 
383  if(*endp)
384  /* Extra charactes after filename */
385  {
386  M_PRINTF("open: Invalid filename\n");
387  return -EPERM;
388  }
389 
390  if(!dev->subdevs[subdev].valid)
391  /* No subdev */
392  {
393  M_PRINTF("open: No subdev registered\n");
394  return -EPERM;
395  }
396 
397  if((dev->subdevs[subdev].mode & DEVFS_MODE_EX)
398  && (dev->subdevs[subdev].open_refcount > 0))
399  /* Already opened in exclusive mode */
400  {
401  M_PRINTF("open: Exclusive subdevice already opened\n");
402  return -EPERM;
403  }
404 
405  if(dev->subdevs[subdev].open_refcount == MAX_OPENFILES)
406  {
407  M_PRINTF("open: Reached open file limit for sub device\n");
408  }
409 
410  /* Tried to open read but not allowed */
411  if(((mode & O_RDONLY) || ((mode & O_RDWR) == O_RDWR))
412  && !(dev->subdevs[subdev].mode & DEVFS_MODE_R))
413  {
414  M_PRINTF("open: Read mode requested but not permitted\n");
415  return -EPERM;
416  }
417 
418  if(((mode & O_WRONLY) || ((mode & O_RDWR) == O_RDWR))
419  && !(dev->subdevs[subdev].mode & DEVFS_MODE_W))
420  {
421  M_PRINTF("open: Write mode requested but not permitted\n");
422  return -EPERM;
423  }
424 
425  file->privdata = AllocSysMemory(ALLOC_FIRST, sizeof(ioman_data_t), NULL);
426  if(file->privdata == NULL)
427  {
428  M_PRINTF("open: Allocation failure\n");
429  return -EPERM;
430  }
431 
432  ((ioman_data_t *) file->privdata)->hDev = dev->hDev;
433  ((ioman_data_t *) file->privdata)->subdev = subdev;
434  ((ioman_data_t *) file->privdata)->loc.loc64 = 0;
435  ((ioman_data_t *) file->privdata)->dev = dev;
436  ((ioman_data_t *) file->privdata)->mode = mode;
437 
438  dev->subdevs[subdev].open_refcount++;
439  loop = 0;
440  while((loop < MAX_OPENFILES) && (dev->subdevs[subdev].open_files[loop]))
441  {
442  loop++;
443  }
444  if(loop == MAX_OPENFILES)
445  {
446  FreeSysMemory(file->privdata);
447  M_PRINTF("open: Inconsistency between number of open files and available slot\n");
448  return -EPERM;
449  }
450 
451  dev->subdevs[subdev].open_files[loop] = file->privdata;
452  dev->open_refcount++;
453  M_PRINTF("open: Opened device %s subdev %d\n", dev->node.name, subdev);
454  }
455  else
456  {
457  M_PRINTF("open: Couldn't find the device\n");
458  return -EPERM;
459  }
460 
461  return 0;
462 }
463 
470 
471 {
472  ioman_data_t *data = (ioman_data_t *) file->privdata;
473 
474  if((data) && (data->hDev != INVALID_HDEV)) /* Invalid HDEV is a dir listing */
475  {
476  devfs_device_t *dev;
477  dev = data->dev;
478 
479  if(dev != NULL)
480  {
481  int loop;
482 
483  if(dev->subdevs[data->subdev].open_refcount > 0)
484  {
485  dev->subdevs[data->subdev].open_refcount--;
486  }
487  if(dev->open_refcount > 0)
488  {
489  dev->open_refcount--;
490  }
491 
492  loop = 0;
493  while((loop < MAX_OPENFILES)
494  && (dev->subdevs[data->subdev].open_files[loop] != data))
495  {
496  loop++;
497  }
498 
499  if(loop != MAX_OPENFILES)
500  {
501  dev->subdevs[data->subdev].open_files[loop] = NULL;
502  }
503  else
504  {
505  M_PRINTF("close: Could not find opened file\n");
506  }
507 
508  M_PRINTF("close: Closing device %s subdev %d\n", dev->node.name, data->subdev);
509  FreeSysMemory(data);
510  }
511  else
512  {
513  FreeSysMemory(data);
514  file->privdata = NULL;
515  return -EPERM;
516  }
517  }
518  else
519  {
520  return -EPERM;
521  }
522 
523  return 0;
524 }
525 
532 int devfs_ioctl(iop_file_t *file, int cmd, void *args)
533 
534 {
535  devfs_device_t *dev;
536  ioman_data_t *data = (ioman_data_t *) file->privdata;
537 
538  if(cmd == DEVFS_IOCTL_GETDESC)
539  {
540  return -EPERM; /* ioctl cannot support this call */
541  }
542 
543  data = file->privdata;
544  if((data) && (data->hDev != INVALID_HDEV))
545  {
546  dev = data->dev;
547  if(dev == NULL) /* Device has been closed from under us */
548  {
549  /* Delete data to try and prevent a memory leak */
550  FreeSysMemory(data);
551  file->privdata = NULL;
552  return -EPERM;
553  }
554 
555  if(dev->node.ioctl != NULL)
556  {
557  devfs_info_t dev_info;
558 
559  dev_info.data = dev->subdevs[data->subdev].data;
560  dev_info.subdev = data->subdev;
561  dev_info.mode = data->mode;
562  dev_info.loc = data->loc;
563  return dev->node.ioctl(&dev_info, DEVFS_IOCTL_TYPE_1, cmd, args, 0, NULL, 0);
564  }
565 
566  }
567 
568  return -EPERM;
569 }
570 
580 int devfs_ioctl2(iop_file_t *file, int cmd, void *args, unsigned int arglen, void *buf, unsigned int buflen)
581 
582 {
583  devfs_device_t *dev;
584  ioman_data_t *data = (ioman_data_t *) file->privdata;
585 
586  data = file->privdata;
587  if((data) && (data->hDev != INVALID_HDEV))
588  {
589  dev = data->dev;
590  if(dev == NULL) /* Device has been closed from under us */
591  {
592  /* Delete data to try and prevent a memory leak */
593  FreeSysMemory(data);
594  file->privdata = NULL;
595  return -EPERM;
596  }
597 
598  if((cmd == DEVFS_IOCTL_GETDESC) && (buf) && (buflen >= DEVFS_MAX_DESC_LENGTH))
599  {
600  if(dev->node.desc)
601  {
602  strncpy(buf, dev->node.desc, buflen-1);
603  *(((u8 *)buf + buflen)) = 0;
604  return strlen(buf);
605  }
606 
607  return 0;
608  }
609 
610  if(dev->node.ioctl != NULL)
611  {
612  devfs_info_t dev_info;
613 
614  dev_info.data = dev->subdevs[data->subdev].data;
615  dev_info.subdev = data->subdev;
616  dev_info.mode = data->mode;
617  dev_info.loc = data->loc;
618  return dev->node.ioctl(&dev_info, DEVFS_IOCTL_TYPE_2, cmd, args, arglen, buf, buflen);
619  }
620 
621  }
622 
623  return -EPERM;
624 }
625 
632 int devfs_read(iop_file_t *file, void *buf, int len)
633 
634 {
635  devfs_device_t *dev;
636  ioman_data_t *data = (ioman_data_t *) file->privdata;
637 
638  //printf("devfs_read file=%p buf=%p len=%d\n", file, buf, len);
639 
640  data = file->privdata;
641  if((data) && (data->hDev != INVALID_HDEV))
642  {
643  dev = data->dev;
644  if(dev == NULL) /* Device has been closed from under us */
645  {
646  /* Delete data to try and prevent a memory leak */
647  FreeSysMemory(data);
648  file->privdata = NULL;
649  return -EPERM;
650  }
651 
652  if((dev->node.read != NULL)
653  && (dev->subdevs[data->subdev].mode & DEVFS_MODE_R))
654  {
655  devfs_info_t dev_info;
656  int bytes_read;
657 
658  dev_info.data = dev->subdevs[data->subdev].data;
659  dev_info.subdev = data->subdev;
660  dev_info.mode = data->mode;
661  dev_info.loc = data->loc;
662  bytes_read = dev->node.read(&dev_info, buf, len);
663  if(bytes_read > 0)
664  {
665  data->loc.loc64 += (u64) bytes_read;
666  }
667  return bytes_read;
668  }
669  }
670 
671  return -EPERM;
672 }
673 
680 int devfs_write(iop_file_t *file, void *buf, int len)
681 
682 {
683  devfs_device_t *dev;
684  ioman_data_t *data = (ioman_data_t *) file->privdata;
685 
686  //printf("devfs_write file=%p buf=%p len=%d\n", file, buf, len);
687  data = file->privdata;
688  if((data) && (data->hDev != INVALID_HDEV))
689  {
690  dev = data->dev;
691  if(dev == NULL) /* Device has been closed from under us */
692  {
693  /* Delete data to try and prevent a memory leak */
694  FreeSysMemory(data);
695  file->privdata = NULL;
696  return -EPERM;
697  }
698 
699  if((dev->node.write != NULL)
700  && (dev->subdevs[data->subdev].mode & DEVFS_MODE_W))
701  {
702  devfs_info_t dev_info;
703  int bytes_written;
704 
705  dev_info.data = dev->subdevs[data->subdev].data;
706  dev_info.subdev = data->subdev;
707  dev_info.mode = data->mode;
708  dev_info.loc = data->loc;
709  bytes_written = dev->node.write(&dev_info, buf, len);
710  if(bytes_written > 0)
711  {
712  data->loc.loc64 += (u64) bytes_written;
713  }
714  return bytes_written;
715  }
716  }
717 
718  return -EPERM;
719 }
720 
727 int devfs_lseek(iop_file_t *file, long loc, int whence)
728 {
729  devfs_device_t *dev;
730  ioman_data_t *data = (ioman_data_t *) file->privdata;
731 
732  //printf("devfs_lseek file=%p loc=%ld whence=%d\n", file, loc, whence);
733  data = file->privdata;
734  if((data) && (data->hDev != INVALID_HDEV))
735  {
736  dev = data->dev;
737  if(dev == NULL) /* Device has been closed from under us */
738  {
739  /* Delete data to try and prevent a memory leak */
740  FreeSysMemory(data);
741  file->privdata = NULL;
742  return -EPERM;
743  }
744 
745  switch(whence)
746  {
747  case SEEK_SET: if(loc > 0)
748  data->loc.loc64 = (u64) loc;
749  break;
750  case SEEK_CUR: if(loc > 0)
751  data->loc.loc64 += (u64) loc;
752  else if((u64)((s64) -loc) < data->loc.loc64)
753  data->loc.loc64 += (s64) loc;
754  break;
755  case SEEK_END: if((loc > 0)
756  && (dev->subdevs[data->subdev].extent.loc64 >= (u64) loc))
757  data->loc.loc64 = dev->subdevs[data->subdev].extent.loc64 - (u64) loc;
758  break;
759  default: return -EPERM;
760  }
761  }
762  else
763  {
764  return -EPERM;
765  }
766 
767  return data->loc.loc32[0];
768 }
769 
775 int devfs_lseek64(iop_file_t *file, long long loc, int whence)
776 {
777  devfs_device_t *dev;
778  ioman_data_t *data = (ioman_data_t *) file->privdata;
779 
780  //printf("devfs_lseek64 file=%p loc= whence=%d\n", file, whence);
781  data = file->privdata;
782  if((data) && (data->hDev != INVALID_HDEV))
783  {
784  dev = data->dev;
785  if(dev == NULL) /* Device has been closed from under us */
786  {
787  /* Delete data to try and prevent a memory leak */
788  FreeSysMemory(data);
789  file->privdata = NULL;
790  return -EPERM;
791  }
792 
793  switch(whence)
794  {
795  case SEEK_SET: if(loc > 0)
796  data->loc.loc64 = (u64) loc;
797  break;
798  case SEEK_CUR: if(loc > 0)
799  data->loc.loc64 += (u64) loc;
800  else if((u64)((s64) -loc) < data->loc.loc64)
801  data->loc.loc64 += (s64) loc;
802  break;
803  case SEEK_END: if((loc > 0) && (dev->subdevs[data->subdev].extent.loc64 >= (u64) loc))
804  data->loc.loc64 = dev->subdevs[data->subdev].extent.loc64 - (u64) loc;
805  break;
806  default: return -EPERM;
807  }
808 
809  }
810  else
811  {
812  return -EPERM;
813  }
814 
815  return data->loc.loc32[0];
816 }
817 
823 int devfs_dopen(iop_file_t *file, const char *name)
824 {
825  int dir_loop;
826 
827  if((name == NULL) || ((name[0] != '\\') && (name[0] != '/')))
828  {
829  M_PRINTF("dopen: Not a valid directory name\n");
830  return -EPERM;
831  }
832 
833  //M_PRINTF("dopen: file=%p name=%s\n", file, name);
834  for(dir_loop = 0; dir_loop < MAX_OPEN_DIRFILES; dir_loop++)
835  {
836  if(!open_dirfiles[dir_loop].opened)
837  {
838  open_dirfiles[dir_loop].devno = 0;
839  open_dirfiles[dir_loop].hDev = INVALID_HDEV;
840  file->privdata = &open_dirfiles[dir_loop];
841  return 0;
842  }
843  }
844 
845  return -EPERM;
846 }
847 
853 {
854  directory_file_t *dir;
855 
856  //M_PRINTF("dclose: file=%p\n", file);
857  dir = (directory_file_t *) file->privdata;
858 
859  if((dir) && (dir->hDev == INVALID_HDEV))
860  {
861  dir->opened = 0;
862  file->privdata = NULL;
863  }
864 
865  return 0;
866 }
867 
868 #ifdef USE_IOMAN
869 int devfs_dread(iop_file_t *file, fio_dirent_t *buf)
870 #else
871 int devfs_dread(iop_file_t *file, iox_dirent_t *buf)
872 #endif
873 {
874  directory_file_t *dir;
875  int ret = 0;
876 
877  //M_PRINTF("dread: file=%p buf=%p\n", file, buf);
878  dir = (directory_file_t *) file->privdata;
879  if((dir) && (dir->hDev == INVALID_HDEV) && (buf))
880  {
881  ret = devfs_fill_dirent(buf, dir->devno);
882  if(ret)
883  {
884  dir->devno++;
885  }
886  }
887 
888  return ret;
889 }
890 
897 #ifdef USE_IOMAN
898 int devfs_getstat(iop_file_t *file, const char *name, fio_stat_t *stat)
899 #else
900 int devfs_getstat(iop_file_t *file, const char *name, iox_stat_t *stat)
901 #endif
902 {
903  devfs_device_t *dev;
904  int fn_offset = 0;
905 
906  (void)file;
907 
908  if(name == NULL)
909  {
910  return -EPERM;
911  }
912 
913  if((name[0] == '\\') || (name[0] == '/'))
914  {
915  fn_offset = 1;
916  }
917 
918  if(stat == NULL)
919  {
920  return -EPERM;
921  }
922 
923  dev = devfs_find_devicename(name + fn_offset);
924 
925  if(dev != NULL)
926  {
927  char *endp;
928  int subdev;
929  int name_len;
930 
931  name_len = strlen(dev->node.name);
932 
933  if((unsigned int)name_len == strlen(name)) /* If this is has not got a subnumber */
934  {
935  M_PRINTF("getstat: No subdevice number in filename %s\n", name);
936  return -EPERM;
937  }
938 
939  subdev = strtoul(&name[name_len + fn_offset], &endp, 10);
940  if(((subdev == 0) && (name[name_len + fn_offset] != '0'))
941  || (subdev >= DEVFS_MAX_SUBDEVS))
942  /* Invalid number */
943  {
944  M_PRINTF("getstat: Invalid subdev number %d\n", subdev);
945  return -EPERM;
946  }
947 
948  if(*endp)
949  /* Extra charactes after filename */
950  {
951  M_PRINTF("getstat: Invalid filename\n");
952  return -EPERM;
953  }
954 
955  if(!dev->subdevs[subdev].valid)
956  {
957  M_PRINTF("getstat: No subdev registered\n");
958  return -EPERM;
959  }
960 
961 #ifdef USE_IOMAN
962  memset(stat, 0, sizeof(fio_stat_t));
963 #else
964  memset(stat, 0, sizeof(iox_stat_t));
965 #endif
966  stat->size = dev->subdevs[subdev].extent.loc32[0];
967  stat->hisize = dev->subdevs[subdev].extent.loc32[1];
968  stat->mode = FIO_S_IFREG;
969  if(dev->subdevs[subdev].mode & DEVFS_MODE_R)
970  {
971  stat->mode |= FIO_S_IRUSR;
972  }
973  if(dev->subdevs[subdev].mode & DEVFS_MODE_W)
974  {
975  stat->mode |= FIO_S_IWUSR;
976  }
977  }
978 
979  return 0;
980 }
981 
982 IOMANX_RETURN_VALUE_IMPL(0);
983 IOMANX_RETURN_VALUE_IMPL(EPERM);
984 
985 static iop_device_ops_t devfs_ops = {
986  IOMANX_RETURN_VALUE(0), // init
987  IOMANX_RETURN_VALUE(0), // deinit
988  IOMANX_RETURN_VALUE(EPERM), // format
989  &devfs_open, // open
990  &devfs_close, // close
991  &devfs_read, // read
992  IOMANX_RETURN_VALUE(EPERM), // write
993  IOMANX_RETURN_VALUE(EPERM), // lseek
994  &devfs_ioctl, // ioctl
995  IOMANX_RETURN_VALUE(EPERM), // remove
996  IOMANX_RETURN_VALUE(EPERM), // mkdir
997  IOMANX_RETURN_VALUE(EPERM), // rmdir
998  &devfs_dopen, // dopen
999  &devfs_dclose, // dclose
1000  &devfs_dread, // dread
1001  &devfs_getstat, // getstat
1002  IOMANX_RETURN_VALUE(EPERM), // chstat
1003  IOMANX_RETURN_VALUE(EPERM), // rename
1004  IOMANX_RETURN_VALUE(EPERM), // chdir
1005  IOMANX_RETURN_VALUE(EPERM), // sync
1006  IOMANX_RETURN_VALUE(EPERM), // mount
1007  IOMANX_RETURN_VALUE(EPERM), // umount
1008  IOMANX_RETURN_VALUE_S64(EPERM), // lseek64
1009  IOMANX_RETURN_VALUE(EPERM), // devctl
1010  IOMANX_RETURN_VALUE(EPERM), // symlink
1011  IOMANX_RETURN_VALUE(EPERM), // readlink
1012  &devfs_ioctl2, // ioctl2
1013 };
1014 
1015 static iop_device_t devfs_device = {
1016  "devfs",
1017  IOP_DT_FS | IOP_DT_FSEXT,
1018  0x100,
1019  "PS2 Device FS Driver",
1020  &devfs_ops,
1021 };
1022 
1026 int init_devfs(void)
1027 
1028 {
1029  root_device = NULL;
1030  dev_count = 0;
1031 
1032  memset(open_dirfiles, 0, sizeof(directory_file_t) * MAX_OPEN_DIRFILES);
1033 
1034  DelDrv(devfs_device.name);
1035 
1036  return AddDrv(&devfs_device);
1037 }
1038 
1044 int _start(int argc, char *argv[])
1045 {
1046  int res = MODULE_NO_RESIDENT_END;
1047  int err;
1048 
1049  (void)argc;
1050  (void)argv;
1051 
1052  printf(BANNER, VERSION);
1053 
1054  if ((err = RegisterLibraryEntries(&_exp_devfs)) != 0) {
1055  M_PRINTF("Library is already registered, exiting.\n");
1056  printf("err=%d\n", err);
1057  }
1058  else
1059  {
1060  res = init_devfs() ? MODULE_NO_RESIDENT_END : MODULE_RESIDENT_END;
1061  }
1062 
1063  M_PRINTF("devfs_device_t size=%d\n", (int)(sizeof(devfs_device_t)));
1064  M_PRINTF("Driver loaded.\n");
1065 
1066  return res;
1067 }
1068 
1073 int devfs_check_devname(const char *name)
1074 /* Valid device name uses alphabetic characters only */
1075 
1076 {
1077  int str_loop;
1078 
1079  if((name == NULL) || (name[0] == 0))
1080  {
1081  return 0;
1082  }
1083 
1084  if(strlen(name) > DEVFS_MAX_DEVNAME_LENGTH)
1085  {
1086  return 0;
1087  }
1088 
1089  str_loop = 0;
1090 
1091  while(name[str_loop])
1092  {
1093  char ch;
1094 
1095  ch = name[str_loop];
1096  if(((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')))
1097  {
1098  str_loop++;
1099  }
1100  else
1101  {
1102  return 0;
1103  }
1104  }
1105 
1106  return 1;
1107 }
1108 
1110 
1111 {
1112  devfs_device_t *dev = NULL;
1113  devfs_device_t *dev_scan;
1114 
1115  //printf("AddDevice node=%p\n", node);
1116  if(node == NULL)
1117  {
1118  M_PRINTF("AddDevice: node == NULL\n");
1119  return INVALID_HDEV;
1120  }
1121 
1122  if(!devfs_check_devname(node->name))
1123  {
1124  M_PRINTF("AddDevice: node name invalid\n");
1125  return INVALID_HDEV;
1126  }
1127 
1128  if(devfs_find_devicename(node->name))
1129  {
1130  M_PRINTF("AddDevice: cannot add new device. Already exists\n");
1131  return INVALID_HDEV;
1132  }
1133 
1134  dev = devfs_create_device(node);
1135  if(dev == NULL)
1136  {
1137  M_PRINTF("AddDevice: failed to allocate device structure\n");
1138  return INVALID_HDEV;
1139  }
1140  if(root_device == NULL)
1141  {
1142  root_device = dev;
1143  }
1144  else
1145  {
1146  dev_scan = root_device;
1147  while(dev_scan->forw) /* Scan the device linked list */
1148  {
1149  dev_scan = dev_scan->forw;
1150  }
1151  dev_scan->forw = dev;
1152  dev->back = dev_scan;
1153  }
1154 
1155  dev->hDev = dev_count++;
1156  if(dev_count == INVALID_HDEV) dev_count++;
1157  M_PRINTF("AddDevice: Registered device (%s)\n", node->name);
1158 
1159  return dev->hDev;
1160 }
1161 
1163 
1164 {
1165  devfs_device_t *dev;
1166  int ret = -1;
1167  devfs_device_t *forw, *back;
1168 
1169  //printf("DelDevice hDev=%d\n", hDev);
1170  dev = devfs_find_deviceid(hDev);
1171  if(dev)
1172  {
1173  int subdev_loop;
1174  int openfile_loop;
1175 
1176  forw = dev->forw;
1177  back = dev->back;
1178 
1179  /* Delete the device even if open files */
1180  for(subdev_loop = 0; subdev_loop < DEVFS_MAX_SUBDEVS; subdev_loop++)
1181  {
1182  for(openfile_loop = 0; openfile_loop < MAX_OPENFILES; openfile_loop++)
1183  {
1184  if(dev->subdevs[subdev_loop].open_files[openfile_loop])
1185  {
1186  dev->subdevs[subdev_loop].open_files[openfile_loop]->dev = NULL;
1187  /* Set the device reference to NULL */
1188  }
1189  }
1190  }
1191  devfs_delete_device(dev);
1192 
1193  if(back)
1194  {
1195  back->forw = forw;
1196  }
1197  else
1198  {
1199  root_device = NULL;
1200  }
1201 
1202  if(forw)
1203  {
1204  forw->back = back;
1205  }
1206 
1207  ret = 0;
1208  }
1209 
1210  return ret;
1211 }
1212 
1213 int DevFSAddSubDevice(HDEV hDev, u32 subdev_no, s32 mode, devfs_loc_t extent, void *data)
1214 
1215 {
1216  devfs_device_t *dev;
1217 
1218  //M_PRINTF("AddSubDevice hDev=%d subdev_no=%d data=%p\n", hDev, subdev_no, data);
1219  dev = devfs_find_deviceid(hDev);
1220  if(dev != NULL)
1221  {
1222  if(subdev_no >= DEVFS_MAX_SUBDEVS)
1223  {
1224  M_PRINTF("AddSubDevice: Sub device number too big\n");
1225  return -1;
1226  }
1227 
1228  if(dev->subdevs[subdev_no].valid)
1229  {
1230  M_PRINTF("AddSubDevice: Sub device already created\n");
1231  return -1;
1232  }
1233 
1234  dev->subdevs[subdev_no].data = data;
1235  dev->subdevs[subdev_no].valid = 1;
1236  dev->subdevs[subdev_no].mode = mode;
1237  dev->subdevs[subdev_no].open_refcount = 0;
1238  dev->subdevs[subdev_no].extent = extent;
1239  memset(dev->subdevs[subdev_no].open_files, 0, sizeof(ioman_data_t *) * MAX_OPENFILES);
1240  dev->subdev_count++;
1241  }
1242  else
1243  {
1244  M_PRINTF("AddSubDevice: Couldn't find device ID\n");
1245  return -1;
1246  }
1247 
1248  return 0;
1249 }
1250 
1251 int DevFSDelSubDevice(HDEV hDev, u32 subdev_no)
1252 
1253 {
1254  devfs_device_t *dev;
1255 
1256  //printf("DelSubDevice hDev=%d subdev_no=%d\n", hDev, subdev_no);
1257  dev = devfs_find_deviceid(hDev);
1258  if(dev != NULL)
1259  {
1260  int openfile_loop;
1261 
1262  if(subdev_no >= DEVFS_MAX_SUBDEVS)
1263  {
1264  M_PRINTF("DelSubDevice: Sub device number too big\n");
1265  return -1;
1266  }
1267 
1268  if(!dev->subdevs[subdev_no].valid)
1269  {
1270  M_PRINTF("DelSubDevice: Sub device not created\n");
1271  return -1;
1272  }
1273 
1274  dev->subdevs[subdev_no].data = NULL;
1275  dev->subdevs[subdev_no].valid = 0;
1276  dev->subdevs[subdev_no].mode = 0;
1277  dev->subdevs[subdev_no].open_refcount = 0;
1278  dev->subdevs[subdev_no].extent.loc64= 0;
1279  for(openfile_loop = 0; openfile_loop < MAX_OPENFILES; openfile_loop++)
1280  {
1281  if(dev->subdevs[subdev_no].open_files[openfile_loop])
1282  {
1283  dev->subdevs[subdev_no].open_files[openfile_loop]->dev = NULL;
1284  dev->subdevs[subdev_no].open_files[openfile_loop] = NULL;
1285  }
1286  }
1287  dev->subdev_count--;
1288  }
1289 
1290  return 0;
1291 }
DEVFS_MODE_EX
@ DEVFS_MODE_EX
Definition: devfs.h:38
_ioman_data
Definition: devfs.c:71
iomanX.h
devfs_getstat
int devfs_getstat(iop_file_t *file, const char *name, iox_stat_t *stat)
Definition: devfs.c:900
_devfs_device::forw
struct _devfs_device * forw
Definition: devfs.c:63
devfs_lseek
int devfs_lseek(iop_file_t *file, long loc, int whence)
Definition: devfs.c:727
iox_stat_t
Definition: iox_stat.h:92
_directory_file::hDev
HDEV hDev
Definition: devfs.c:89
devfs_info_t::mode
u32 mode
Definition: devfs.h:89
HDEV
s32 HDEV
Definition: devfs.h:26
IOP_DT_FSEXT
#define IOP_DT_FSEXT
Definition: iomanX.h:66
thbase.h
_iop_file::privdata
void * privdata
Definition: ioman.h:61
sysclib.h
devfs_find_deviceid
devfs_device_t * devfs_find_deviceid(HDEV hDev)
Definition: devfs.c:309
FIO_S_IWUSR
#define FIO_S_IWUSR
Definition: iox_stat.h:60
EPERM
#define EPERM
Definition: errno.h:21
devfs_create_device
devfs_device_t * devfs_create_device(const devfs_node_t *node)
Definition: devfs.c:198
devfs_check_devname
int devfs_check_devname(const char *name)
Definition: devfs.c:1073
FIO_S_IFREG
#define FIO_S_IFREG
Definition: iox_stat.h:43
devfs_info_t::loc
devfs_loc_t loc
Definition: devfs.h:91
DEVFS_IOCTL_TYPE_2
#define DEVFS_IOCTL_TYPE_2
Definition: devfs.h:63
devfs_loc_t::loc32
u32 loc32[2]
Definition: devfs.h:73
devfs_info_t::data
void * data
Definition: devfs.h:83
loadcore.h
DEVFS_MODE_R
@ DEVFS_MODE_R
Definition: devfs.h:42
_start
int _start(int argc, char *argv[])
Definition: devfs.c:1044
devfs_subdev_to_str
const char * devfs_subdev_to_str(int subdev)
Definition: devfs.c:103
devfs_dclose
int devfs_dclose(iop_file_t *file)
Definition: devfs.c:852
devfs_node_t::ioctl
ioctl_handler ioctl
Definition: devfs.h:118
init_devfs
int init_devfs(void)
Definition: devfs.c:1026
devfs_loc_t::loc64
u64 loc64
Definition: devfs.h:75
irx.h
devfs_lseek64
int devfs_lseek64(iop_file_t *file, long long loc, int whence)
Definition: devfs.c:775
_ioman_data::dev
devfs_device_t * dev
Definition: devfs.c:75
devfs_node_t::read
read_handler read
Definition: devfs.h:114
thsemap.h
DevFSAddSubDevice
int DevFSAddSubDevice(HDEV hDev, u32 subdev_no, s32 mode, devfs_loc_t extent, void *data)
Definition: devfs.c:1213
devfs_info_t
Definition: devfs.h:79
_directory_file::opened
u32 opened
Definition: devfs.c:93
irx_export_table
Definition: irx.h:90
DevFSDelSubDevice
int DevFSDelSubDevice(HDEV hDev, u32 subdev_no)
Definition: devfs.c:1251
DEVFS_MODE_W
@ DEVFS_MODE_W
Definition: devfs.h:40
DEVFS_MAX_DEVNAME_LENGTH
#define DEVFS_MAX_DEVNAME_LENGTH
Definition: devfs.h:30
_iop_file
Definition: ioman.h:53
subdev_t
Definition: devfs.c:49
devfs_delete_device
int devfs_delete_device(devfs_device_t *dev)
Definition: devfs.c:248
stdio.h
devfs_node_t::desc
char * desc
Definition: devfs.h:108
devfs_loc_t
Definition: devfs.h:69
devfs_open
int devfs_open(iop_file_t *file, const char *name, int mode, int unused)
Definition: devfs.c:337
DevFSAddDevice
HDEV DevFSAddDevice(const devfs_node_t *node)
Definition: devfs.c:1109
ioman.h
DEVFS_MAX_DESC_LENGTH
#define DEVFS_MAX_DESC_LENGTH
Definition: devfs.h:32
FIO_S_IRUSR
#define FIO_S_IRUSR
Definition: iox_stat.h:58
DEVFS_MAX_SUBDEVS
#define DEVFS_MAX_SUBDEVS
Definition: devfs.h:28
iox_dirent_t
Definition: iox_stat.h:111
_iop_device_ops
Definition: ioman.h:79
devfs_read
int devfs_read(iop_file_t *file, void *buf, int len)
Definition: devfs.c:632
devfs_info_t::subdev
s32 subdev
Definition: devfs.h:85
devfs.h
_directory_file
Definition: devfs.c:85
sysmem.h
devfs_close
int devfs_close(iop_file_t *file)
Definition: devfs.c:469
DEVFS_IOCTL_TYPE_1
#define DEVFS_IOCTL_TYPE_1
Definition: devfs.h:61
devfs_write
int devfs_write(iop_file_t *file, void *buf, int len)
Definition: devfs.c:680
devfs_node_t::name
char * name
Definition: devfs.h:106
root_device
devfs_device_t * root_device
Definition: devfs.c:82
devfs_dopen
int devfs_dopen(iop_file_t *file, const char *name)
Definition: devfs.c:823
devfs_node_t
Definition: devfs.h:103
defs.h
_iop_device
Definition: ioman.h:64
intrman.h
devfs_fill_dirent
int devfs_fill_dirent(iox_dirent_t *dirent, int devno)
Definition: devfs.c:137
_devfs_device
Definition: devfs.c:60
devfs_ioctl2
int devfs_ioctl2(iop_file_t *file, int cmd, void *args, unsigned int arglen, void *buf, unsigned int buflen)
Definition: devfs.c:580
INVALID_HDEV
#define INVALID_HDEV
Definition: devfs.h:152
DevFSDelDevice
int DevFSDelDevice(HDEV hDev)
Definition: devfs.c:1162
thevent.h
devfs_node_t::write
write_handler write
Definition: devfs.h:116
DEVFS_IOCTL_GETDESC
#define DEVFS_IOCTL_GETDESC
Definition: devfs.h:66
errno.h
_directory_file::devno
u32 devno
Definition: devfs.c:91
devfs_ioctl
int devfs_ioctl(iop_file_t *file, int cmd, void *args)
Definition: devfs.c:532
devfs_find_devicename
devfs_device_t * devfs_find_devicename(const char *name)
Definition: devfs.c:276