PS2SDK
PS2 Homebrew Libraries
dvrdv.c
1 /*
2 # _____ ___ ____ ___ ____
3 # ____| | ____| | | |____|
4 # | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5 #-----------------------------------------------------------------------
6 # Copyright 2021-2021, ps2dev - http://www.ps2dev.org
7 # Licenced under Academic Free License version 2.0
8 # Review ps2sdk README & LICENSE files for further details.
9 */
10 
11 #include <stdbool.h>
12 #include "iomanX.h"
13 #include "loadcore.h"
14 #include "pvrdrv.h"
15 #include "stdio.h"
16 #include "thbase.h"
17 #include "thsemap.h"
18 #include "speedregs.h"
19 #include "errno.h"
20 
21 #define MODNAME "DVRDV"
22 #ifdef DEBUG
23 #define DPRINTF(x...) printf(MODNAME ": " x)
24 #else
25 #define DPRINTF(x...)
26 #endif
27 
28 extern int module_start(int argc, char *argv[], void *startaddr, ModuleInfo_t *mi);
29 extern int module_stop(int argc, char *argv[], void *startaddr, ModuleInfo_t *mi);
30 extern int dvrdv_df_init(iomanX_iop_device_t *dev);
31 extern int dvrdv_df_exit(iomanX_iop_device_t *dev);
32 extern int dvrdv_df_ioctl(iomanX_iop_file_t *f, int cmd, void *param);
33 extern int dvrdv_df_devctl(iomanX_iop_file_t *a1, const char *name, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen);
34 extern int dvrdv_df_ioctl2(iomanX_iop_file_t *f, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen);
35 extern int dvrioctl2_dv_dubb_start(iomanX_iop_file_t *a1, const char *name, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen);
36 extern int dvrioctl2_dv_dubb_stop(iomanX_iop_file_t *a1, const char *name, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen);
37 extern int dvrioctl2_dv_dubb_rec_start(iomanX_iop_file_t *a1, const char *name, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen);
38 extern int dvrioctl2_dv_dubb_rec_stop(iomanX_iop_file_t *a1, const char *name, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen);
39 extern int dvrioctl2_get_dvcam_info(iomanX_iop_file_t *a1, const char *name, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen);
40 extern int dvrioctl2_get_dvcam_name(iomanX_iop_file_t *a1, const char *name, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen);
41 
42 struct DevctlCmdTbl_t
43 {
44  u16 cmd;
45  int (*fn)(iomanX_iop_file_t *f, const char *name, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen);
46 } DevctlCmdTbl[6] =
47  {
48  {0x5601, &dvrioctl2_dv_dubb_start},
49  {0x5602, &dvrioctl2_dv_dubb_stop},
50  {0x5603, &dvrioctl2_dv_dubb_rec_start},
51  {0x5604, &dvrioctl2_dv_dubb_rec_stop},
52  {0x5607, &dvrioctl2_get_dvcam_info},
53  {0x5608, &dvrioctl2_get_dvcam_name},
54 };
55 
56 IOMANX_RETURN_VALUE_IMPL(EUNSUP);
57 
58 static iomanX_iop_device_ops_t DvrFuncTbl =
59  {
60  &dvrdv_df_init, // init
61  &dvrdv_df_exit, // deinit
62  IOMANX_RETURN_VALUE(EUNSUP), // format
63  IOMANX_RETURN_VALUE(EUNSUP), // open
64  IOMANX_RETURN_VALUE(EUNSUP), // close
65  IOMANX_RETURN_VALUE(EUNSUP), // read
66  IOMANX_RETURN_VALUE(EUNSUP), // write
67  IOMANX_RETURN_VALUE(EUNSUP), // lseek
68  &dvrdv_df_ioctl, // ioctl
69  IOMANX_RETURN_VALUE(EUNSUP), // remove
70  IOMANX_RETURN_VALUE(EUNSUP), // mkdir
71  IOMANX_RETURN_VALUE(EUNSUP), // rmdir
72  IOMANX_RETURN_VALUE(EUNSUP), // dopen
73  IOMANX_RETURN_VALUE(EUNSUP), // dclose
74  IOMANX_RETURN_VALUE(EUNSUP), // dread
75  IOMANX_RETURN_VALUE(EUNSUP), // getstat
76  IOMANX_RETURN_VALUE(EUNSUP), // chstat
77  IOMANX_RETURN_VALUE(EUNSUP), // rename
78  IOMANX_RETURN_VALUE(EUNSUP), // chdir
79  IOMANX_RETURN_VALUE(EUNSUP), // sync
80  IOMANX_RETURN_VALUE(EUNSUP), // mount
81  IOMANX_RETURN_VALUE(EUNSUP), // umount
82  IOMANX_RETURN_VALUE_S64(EUNSUP), // lseek64
83  &dvrdv_df_devctl, // devctl
84  IOMANX_RETURN_VALUE(EUNSUP), // symlink
85  IOMANX_RETURN_VALUE(EUNSUP), // readlink
86  &dvrdv_df_ioctl2, // ioctl2
87  };
88 static iomanX_iop_device_t DVR = {
89  .name = "dvr_dv",
90  .desc = "Digital Video Recorder DVR task",
91  .type = (IOP_DT_FS | IOP_DT_FSEXT),
92  .ops = &DvrFuncTbl,
93 };
94 s32 sema_id;
95 
96 // Based off of DESR / PSX DVR system software version 2.11.
97 IRX_ID(MODNAME, 1, 0);
98 
99 int _start(int argc, char *argv[], void *startaddr, ModuleInfo_t *mi)
100 {
101  if (argc >= 0)
102  return module_start(argc, argv, startaddr, mi);
103  else
104  return module_stop(argc, argv, startaddr, mi);
105 }
106 
107 int module_start(int argc, char *argv[], void *startaddr, ModuleInfo_t *mi)
108 {
109  int i;
110 
111  (void)argc;
112  (void)argv;
113  (void)startaddr;
114 
115  for (i = 0; i < 30000; ++i) {
116  if (((*((vu32 *)0xB0004230)) & 4) != 0)
117  break;
118  DelayThread(1000);
119  }
120  if (i == 30000) {
121  DPRINTF("DVR task of DVRP is not running...\n");
122  return MODULE_NO_RESIDENT_END;
123  } else {
124  if (iomanX_AddDrv(&DVR) != 0)
125  return MODULE_NO_RESIDENT_END;
126  }
127 #if 0
128  return MODULE_REMOVABLE_END;
129 #else
130  if (mi && ((mi->newflags & 2) != 0))
131  mi->newflags |= 0x10;
132  return MODULE_RESIDENT_END;
133 #endif
134 }
135 
136 int module_stop(int argc, char *argv[], void *startaddr, ModuleInfo_t *mi)
137 {
138  (void)argc;
139  (void)argv;
140  (void)startaddr;
141  (void)mi;
142 
143  if (iomanX_DelDrv(DVR.name) != 0)
144  return MODULE_REMOVABLE_END;
145  return MODULE_NO_RESIDENT_END;
146 }
147 
148 int dvrdv_df_init(iomanX_iop_device_t *dev)
149 {
150  int v1;
151  iop_sema_t v3;
152 
153  (void)dev;
154 
155  v3.attr = 0;
156  v3.initial = 1;
157  v3.max = 1;
158  v3.option = 0;
159  v1 = CreateSema(&v3);
160  if (v1 < 0)
161  return -1;
162  sema_id = v1;
163  return 0;
164 }
165 
166 int dvrdv_df_exit(iomanX_iop_device_t *dev)
167 {
168  (void)dev;
169 
170  if (DeleteSema(sema_id) != 0)
171  return -1;
172  return 0;
173 }
174 
175 int dvrdv_df_ioctl(iomanX_iop_file_t *f, int cmd, void *param)
176 {
177  (void)f;
178  (void)cmd;
179  (void)param;
180 
181  WaitSema(sema_id);
182  SignalSema(sema_id);
183  return -EINVAL;
184 }
185 
186 int dvrdv_df_devctl(
187  iomanX_iop_file_t *a1,
188  const char *name,
189  int cmd,
190  void *arg,
191  unsigned int arglen,
192  void *buf,
193  unsigned int buflen)
194 {
195  int v10;
196  unsigned int v11;
197  unsigned int v12;
198 
199  v10 = 0;
200  v11 = 0;
201  WaitSema(sema_id);
202  v12 = 0;
203  while (DevctlCmdTbl[v12].cmd != cmd) {
204  v12 = ++v11;
205  if (v11 >= sizeof(DevctlCmdTbl) / sizeof(DevctlCmdTbl[0]))
206  goto LABEL_5;
207  }
208  v10 = DevctlCmdTbl[v12].fn(a1, name, cmd, arg, arglen, buf, buflen);
209 LABEL_5:
210  if (v11 == sizeof(DevctlCmdTbl) / sizeof(DevctlCmdTbl[0]))
211  v10 = -EINVAL;
212  SignalSema(sema_id);
213  return v10;
214 }
215 
216 int dvrdv_df_ioctl2(
218  int cmd,
219  void *arg,
220  unsigned int arglen,
221  void *buf,
222  unsigned int buflen)
223 {
224 
225  (void)f;
226  (void)cmd;
227  (void)arg;
228  (void)arglen;
229  (void)buf;
230  (void)buflen;
231 
232  WaitSema(sema_id);
233  SignalSema(sema_id);
234  return -EINVAL;
235 }
236 
237 int dvrioctl2_dv_dubb_start(
238  iomanX_iop_file_t *a1,
239  const char *name,
240  int cmd,
241  void *arg,
242  unsigned int arglen,
243  void *buf,
244  unsigned int buflen)
245 {
246  int cmdack_err;
247  drvdrv_exec_cmd_ack cmdack;
248 
249  (void)a1;
250  (void)name;
251  (void)cmd;
252  (void)arg;
253  (void)arglen;
254  (void)buf;
255  (void)buflen;
256 
257  DPRINTF("------------------------------ dv dubb start!!!\n");
258  cmdack.command = 0x4101;
259  cmdack.input_word_count = 0;
260  cmdack_err = DvrdrvExecCmdAck(&cmdack);
261  if (cmdack_err) {
262  DPRINTF("dvrioctl2_dv_dubb_start -> Handshake error!,%d\n", cmdack_err);
263  return -EIO;
264  } else {
265  if (cmdack.ack_status_ack) {
266  DPRINTF("dvrioctl2_dv_dubb_start -> Status error!,%04X\n", cmdack.ack_status_ack);
267  return -EADV;
268  }
269  }
270  return 0;
271 }
272 
273 int dvrioctl2_dv_dubb_stop(
274  iomanX_iop_file_t *a1,
275  const char *name,
276  int cmd,
277  void *arg,
278  unsigned int arglen,
279  void *buf,
280  unsigned int buflen)
281 {
282  int cmdack_err;
283  drvdrv_exec_cmd_ack cmdack;
284 
285  (void)a1;
286  (void)name;
287  (void)cmd;
288  (void)arg;
289  (void)arglen;
290  (void)buf;
291  (void)buflen;
292 
293  DPRINTF("------------------------------ dv dubb stop!!!\n");
294  cmdack.command = 0x4102;
295  cmdack.input_word_count = 0;
296  cmdack_err = DvrdrvExecCmdAck(&cmdack);
297  if (cmdack_err) {
298  DPRINTF("dvrioctl2_dv_dubb_stop -> Handshake error!,%d\n", cmdack_err);
299  return -EIO;
300  } else {
301  if (cmdack.ack_status_ack) {
302  DPRINTF("dvrioctl2_dv_dubb_stop -> Status error!,%04X\n", cmdack.ack_status_ack);
303  return -EADV;
304  }
305  }
306  return 0;
307 }
308 
309 int dvrioctl2_dv_dubb_rec_start(
310  iomanX_iop_file_t *a1,
311  const char *name,
312  int cmd,
313  void *arg,
314  unsigned int arglen,
315  void *buf,
316  unsigned int buflen)
317 {
318  int v8;
319  u16 *v9;
320  u16 *v10;
321  int cmdack_err;
322  drvdrv_exec_cmd_ack cmdack;
323 
324  (void)a1;
325  (void)name;
326  (void)cmd;
327  (void)arglen;
328  (void)buf;
329  (void)buflen;
330 
331  cmdack.command = 0x4103;
332  DPRINTF("------------------------------ dv dubb rec start!!!\n");
333  v8 = 4;
334  v9 = (u16 *)((u8 *)arg + 8);
335  v10 = &cmdack.input_word[4];
336  do {
337  *v10 = *v9;
338  v9 += 1;
339  v8 += 1;
340  v10 += 1;
341  } while (v8 < 7);
342  cmdack.input_word[0] = *((u16 *)arg + 1);
343  cmdack.input_word[1] = *(u16 *)arg;
344  cmdack.input_word[2] = *((u16 *)arg + 3);
345  cmdack.input_word[3] = *((u16 *)arg + 2);
346  cmdack.input_word_count = 7;
347  cmdack_err = DvrdrvExecCmdAck(&cmdack);
348  if (cmdack_err) {
349  DPRINTF("dvrioctl2_dv_dubb_rec_start -> Handshake error!,%d\n", cmdack_err);
350  return -EIO;
351  } else {
352  if (cmdack.ack_status_ack) {
353  DPRINTF("dvrioctl2_dv_dubb_rec_start -> Status error!,%04X\n", cmdack.ack_status_ack);
354  return -EADV;
355  }
356  }
357  return 0;
358 }
359 
360 int dvrioctl2_dv_dubb_rec_stop(
361  iomanX_iop_file_t *a1,
362  const char *name,
363  int cmd,
364  void *arg,
365  unsigned int arglen,
366  void *buf,
367  unsigned int buflen)
368 {
369  int cmdack_err;
370  drvdrv_exec_cmd_ack cmdack;
371 
372  (void)a1;
373  (void)name;
374  (void)cmd;
375  (void)arg;
376  (void)arglen;
377  (void)buf;
378  (void)buflen;
379 
380  DPRINTF("------------------------------ dv dubb rec stop!!!\n");
381  cmdack.command = 0x4104;
382  cmdack.input_word_count = 0;
383  cmdack.timeout = 5000000;
384  cmdack_err = DvrdrvExecCmdAckComp(&cmdack);
385  if (cmdack_err) {
386  DPRINTF("phase %d\n", cmdack.phase);
387  DPRINTF("dvrioctl2_dv_dubb_rec_stop -> Handshake error!,%d\n", cmdack_err);
388  return -EIO;
389  } else {
390  if (cmdack.ack_status_ack) {
391  DPRINTF("phase %d\n", cmdack.phase);
392  DPRINTF("dvrioctl2_dv_dubb_rec_stop -> Status error!,%04X\n", cmdack.ack_status_ack);
393  return -EADV;
394  }
395  }
396  return 0;
397 }
398 
399 int dvrioctl2_get_dvcam_info(
400  iomanX_iop_file_t *a1,
401  const char *name,
402  int cmd,
403  void *arg,
404  unsigned int arglen,
405  void *buf,
406  unsigned int buflen)
407 {
408  int cmdack_err;
409  drvdrv_exec_cmd_ack cmdack;
410 
411  (void)a1;
412  (void)name;
413  (void)cmd;
414  (void)arg;
415  (void)arglen;
416  (void)buflen;
417 
418  cmdack.command = 0x4107;
419  cmdack.input_word_count = 0;
420  cmdack_err = DvrdrvExecCmdAck(&cmdack);
421  if (cmdack_err) {
422  DPRINTF("phase %d\n", cmdack.phase);
423  DPRINTF("dvrioctl2_get_dvcam_info -> Handshake error!,%d\n", cmdack_err);
424  return -EIO;
425  } else {
426  if (cmdack.ack_status_ack) {
427  DPRINTF("dvrioctl2_get_dvcam_info -> Status error!,%04X\n", cmdack.ack_status_ack);
428  return -EADV;
429  } else {
430  u16 *v11;
431  int cpy_cnt;
432  v11 = &cmdack.output_word[0];
433  cpy_cnt = 0;
434  do {
435  cpy_cnt += 1;
436  *(u16 *)buf = *v11;
437  buf = (char *)buf + 2;
438  v11 += 1;
439  } while (cpy_cnt < 4);
440  return 0;
441  }
442  }
443 }
444 
445 int dvrioctl2_get_dvcam_name(
446  iomanX_iop_file_t *a1,
447  const char *name,
448  int cmd,
449  void *arg,
450  unsigned int arglen,
451  void *buf,
452  unsigned int buflen)
453 {
454  drvdrv_exec_cmd_ack cmdack;
455 
456  (void)name;
457  (void)arg;
458  (void)arglen;
459 
460  DPRINTF("dvrioctl2_get_dvcam_name(io=%p, cmd=%d buf=%p, nbyte=%u)\n", a1, cmd, buf, buflen);
461  cmdack.command = 0x4108;
462  cmdack.input_word[0] = 0;
463  cmdack.input_word[1] = 0;
464  cmdack.input_word[2] = (buflen & 0xFFFF0000) >> 16;
465  cmdack.input_word[3] = buflen;
466  cmdack.input_word_count = 4;
467  cmdack.output_buffer = buf;
468  cmdack.timeout = 5000000;
469  if (DvrdrvExecCmdAckDmaRecvComp(&cmdack)) {
470  DPRINTF("dvrioctl2_get_dvcam_name : IO error (phase %d)\n", cmdack.phase);
471  return -EIO;
472  } else {
473  if (cmdack.comp_status) {
474  DPRINTF("dvrioctl2_get_dvcam_name : Complete parameter error (phase %d), %04X\n", cmdack.phase, cmdack.comp_status);
475  return -EIO;
476  }
477  }
478  return 0;
479 }
iomanX.h
_ModuleInfo::newflags
u16 newflags
Definition: loadcore.h:36
speedregs.h
IOP_DT_FSEXT
#define IOP_DT_FSEXT
Definition: iomanX.h:66
EUNSUP
#define EUNSUP
Definition: errno.h:117
thbase.h
iop_sema_t
Definition: thsemap.h:38
_iomanX_iop_file
Definition: iomanX.h:70
EADV
#define EADV
Definition: errno.h:151
EIO
#define EIO
Definition: errno.h:29
loadcore.h
pvrdrv.h
_iomanX_iop_device_ops
Definition: iomanX.h:95
thsemap.h
_iomanX_iop_device
Definition: iomanX.h:81
stdio.h
EINVAL
#define EINVAL
Definition: errno.h:63
DevctlCmdTbl_t
Definition: xesdrv.c:198
_ModuleInfo
Definition: loadcore.h:31
errno.h