1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
|
#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, const unsigned char *in, unsigned char *out, int len)
{
volatile int x;
volatile int y; // specified as volatile to not make busy loops get optimized out
volatile int i;
volatile unsigned char TempData;
volatile 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;
#if 0
for(y=0;y<400;y++); /*Slight delay before first transmission*/
#endif
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);
}*/
|