summaryrefslogtreecommitdiff
path: root/libpsx/src/pad.c
diff options
context:
space:
mode:
authorXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
committerXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
commit7c24e9a9b02b04dcaf9507acb94091ea70a2c02d (patch)
treec28d0748652ad4b4222309e46e6cfc82c0906220 /libpsx/src/pad.c
parenta2b7b6bb1cc2f4a3258b7b2dbc92399d151f864d (diff)
downloadpsxsdk-7c24e9a9b02b04dcaf9507acb94091ea70a2c02d.tar.gz
Imported pristine psxsdk-20190410 from official repo
Diffstat (limited to 'libpsx/src/pad.c')
-rw-r--r--libpsx/src/pad.c163
1 files changed, 163 insertions, 0 deletions
diff --git a/libpsx/src/pad.c b/libpsx/src/pad.c
new file mode 100644
index 0000000..ea3e20e
--- /dev/null
+++ b/libpsx/src/pad.c
@@ -0,0 +1,163 @@
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <psx.h>
+
+/*
+ * Flags taken from PCSX
+ */
+
+// Status Flags
+#define TX_RDY 0x0001
+#define RX_RDY 0x0002
+#define TX_EMPTY 0x0004
+#define PARITY_ERR 0x0008
+#define RX_OVERRUN 0x0010
+#define FRAMING_ERR 0x0020
+#define SYNC_DETECT 0x0040
+#define DSR 0x0080
+#define CTS 0x0100
+#define IRQ 0x0200
+
+// Control Flags
+#define TX_PERM 0x0001
+#define DTR 0x0002
+#define RX_PERM 0x0004
+#define BREAK 0x0008
+#define RESET_ERR 0x0010
+#define RTS 0x0020
+#define PADSIO_RESET 0x0040
+
+/*
+ from BlackBag/Nagra PSX
+
+ 0x1f801040 - unsigned char data;
+ 0x1f801044 - unsigned short status;
+ 0x1f80104a - unsigned short cntl;
+ 0x1f80104e - unsigned short baud;
+*/
+
+#define PADSIO_DATA(x) *((volatile unsigned char*)(0x1f801040 + (x<<4)))
+#define PADSIO_STATUS(x) *((volatile unsigned short*)(0x1f801044 + (x<<4)))
+#define PADSIO_MODE(x) *((volatile unsigned short*)(0x1f801048 + (x<<4)))
+#define PADSIO_CTRL(x) *((volatile unsigned short*)(0x1f80104a + (x<<4)))
+#define PADSIO_BAUD(x) *((volatile unsigned short*)(0x1f80104e + (x<<4)))
+
+unsigned char readpad_vibrations[4][2];
+int querypad_rxrdy = 1;
+
+void QueryPAD(int pad_n, unsigned char *in, unsigned char *out, int len)
+{
+ int x;
+ volatile int y; // specified as volatile to not make busy loops get optimized out
+ int i;
+ unsigned char TempData;
+ int EmuFlag = 0;
+
+ PADSIO_MODE(0) = 0xD;
+ PADSIO_BAUD(0) = 0x88;
+
+ if(pad_n == 1) PADSIO_CTRL(0) = 0x3003; else PADSIO_CTRL(0) = 0x1003;
+
+ /*Get the initial command (usually 0x01 or 0x81)*/
+ TempData = *in;
+
+ for(y=0;y<400;y++); /*Slight delay before first transmission*/
+
+ for(x = 0; x < len; x++)
+ {
+ /*Must use timeouts or else program hangs on emulators*/
+ if(!EmuFlag)
+ {
+ for(y=0;y<1000;y++)
+ {
+ /*Wait for TX ready*/
+ if(PADSIO_STATUS(0) & 4)break;
+ }
+ }
+
+ PADSIO_DATA(0) = *in;
+ in++;
+
+ if(!EmuFlag)
+ {
+ /*Check ACK only for Memory Cards*/
+ if(TempData == 0x81 || x == 0)
+ {
+ for(y=0;y<2000;y++)
+ {
+ /*Check for ACK signal*/
+ if(PADSIO_STATUS(0) & 128)break;
+ }
+ }
+
+ for(i=0;i<100;i++)
+ {
+ /*Read RX status flag, required for Xebra*/
+ if(PADSIO_STATUS(0) & 2)break;
+ }
+ }
+
+ *out = PADSIO_DATA(0);
+
+ /*This is emulator, valid data was received without ACK, ePSXe and PCSX*/
+ if(x == 0 && y > 1900 && *out != 0xFF)EmuFlag = 1;
+
+ out++;
+ }
+
+ PADSIO_CTRL(0) = 0;
+}
+
+void pad_read_raw(int pad_n, unsigned char *arr)
+{
+ // arr must be at least 16 bytes long...
+
+ unsigned char pad_cmd[PAD_READ_RAW_SIZE] = {1,0x42,0,0,0};
+
+ pad_cmd[3] = readpad_vibrations[pad_n][0];
+ pad_cmd[4] = readpad_vibrations[pad_n][1];
+
+ QueryPAD(pad_n, pad_cmd, arr, sizeof(pad_cmd));
+}
+
+void pad_escape_mode(int pad_n, int enable)
+{
+ unsigned char pad_cmd[] = {1,0x43,0,enable?1:0,0};
+
+ QueryPAD(pad_n, pad_cmd, NULL, sizeof(pad_cmd));
+}
+
+void pad_enable_vibration(int pad_n)
+{
+ unsigned char pad_cmd[] = {1, 0x4d, 0, 0, 1, 0xff, 0xff, 0xff, 0xff};
+
+ pad_escape_mode(pad_n, 1); // Enter escape / configuration mode
+ QueryPAD(pad_n, pad_cmd, NULL, sizeof(pad_cmd));
+ pad_escape_mode(pad_n, 0); // Exit escape / configuration mode
+}
+
+void pad_set_vibration(int pad_n, unsigned char small, unsigned char big)
+{
+ if(pad_n >= 0 && pad_n <= 3)
+ {
+ readpad_vibrations[pad_n][0] = small;
+ readpad_vibrations[pad_n][1] = big;
+ }
+}
+
+/*
+ // Sony pads make this interface unpractical!
+void pad_set_analog(int pad_n, int lock)
+{
+ unsigned char pad_cmd[9] =
+ {1, 0x44, 0, 1, lock?3:0, 0, 0, 0, 0};
+ unsigned char pad_cmd2[9] =
+ {1, 0x4f, 0, 0xff, 0xff, 3, 0, 0, 0};
+
+ pad_escape_mode(pad_n, 1);
+ QueryPAD(pad_n, pad_cmd, NULL, sizeof(pad_cmd));
+ QueryPAD(pad_n, pad_cmd2, NULL, sizeof(pad_cmd));
+ pad_escape_mode(pad_n, 0);
+}*/
+