frno7 / linux

Linux 2.2, 2.6, 3.x, 4.x and 5.x kernels for the PlayStation 2.
Other
84 stars 5 forks source link

Enable the DualShock 2 controller #22

Open frno7 opened 5 years ago

frno7 commented 5 years ago

Implement a device driver for the DualShock 2 controller. See also #11. Plan:

frno7 commented 4 years ago

Is anyone aware of complete and detailed hardware documentation of the IOP SIO2? Including interrupts and use of DMA? With good naming conventions for all register bits?

A selection of incomplete references is ps2tek and PS2SDK.

Nocash PSX-SPX describes related registers for the PS1, but SIO2 is apparently specific for the PS2.

AKuHAK commented 4 years ago

You can check this header file . More info discussed here . Maybe @rickgaiser can give more info on it.

rickgaiser commented 4 years ago

I was actually watching this issue hoping to get more information. The information in the header file is created by wisi.

frno7 commented 4 years ago

Thanks @AKuHAK & @rickgaiser! My plan is to begin to use SIO2 with DMA for the DualShock controller, and then make the SIO2 part more general for #21. I expect reading and writing memory cards to be more complex.

To improve performance, the plan is also to have the IOP notify the EE about gamepads only when there are actual state changes, such as someone pressing a button. This could significantly lower controller latency too, and means not asserting gamepad interrupts regularly, such as every video frame or similar.

frno7 commented 4 years ago

I have gathered the relevant SIO2 references I could find, especially via notes by Wisi, and defined sio2.h with the best address and bit field identifiers I could come up with. @AKuHAK and @rickgaiser, do you have any comments on those?

Note: All of these files are technically in the iopmod repo, and not in this Linux repo, so maybe we ought to move the IOP part of this discussion to that repo?

I have also made a provisional gamepad.c IOP module with a simple loop printing SIO2 register values to the Linux kernel log, and it looks reasonable to me:

iop: gamepad: PORT0_CTRL0 c0c0050f
iop: gamepad: PORT0_CTRL1  1060014
iop: gamepad: PORT1_CTRL0 c0c0050f
iop: gamepad: PORT1_CTRL1  1060014
iop: gamepad: PORT2_CTRL0 c0c0050f
iop: gamepad: PORT2_CTRL1  1060014
iop: gamepad: PORT3_CTRL0 c0c0050f
iop: gamepad: PORT3_CTRL1  1060014
iop: gamepad:          TX        0
iop: gamepad:          RX ffffffff
iop: gamepad:        CTRL      3b0
iop: gamepad:    CMD_STAT    15000
iop: gamepad:   PORT_STAT        f
iop: gamepad:   FIFO_STAT  8000000
iop: gamepad:     FIFO_TX        0
iop: gamepad:     FIFO_RX        0
iop: gamepad:    IRQ_STAT        0

Unfortunately, trying to register the SIO2 IRQ fails with

iop: gamepad_init: request_irq for IRQ_IOP_SIO2 failed with -16

where -16 means errno EBUSY. I suppose that is to be expected, given that

# cat /sys/firmware/iop/*/name | grep -i sio
sio2man

indicates that the IOP module SIO2MAN is loaded, which collides with the SIO2 handling I’m about to implement. So SIO2MAN must be unloaded, or not loaded to begin with. I suspect that it comes via rom0:OSDCNF in

https://github.com/frno7/linux/blob/1a3ad68953e0f4f29cb866b629cd74b59cc9283b/drivers/ps2/sif.c#L49

which is the topic of #28, and more specifically the issue of implementing Mr Brown’s SBV LoadModuleBuffer patch linked in https://github.com/frno7/linux/issues/28#issuecomment-530912627. @AKuHAK, what are your thoughts?

frno7 commented 4 years ago

With issue #28 just about finished, simple operations on the SIO2 hardware registers appear to complete as expected. The controller polling command 0x01 0x42 0x00 returns the anticipated 0xff 0x41 0x5a 0xff 0xff, with the SIO2 interrupt asserted and SIO2 FIFO registers updated accordingly. With printk in the IRQ handler in the SIO2 IRX module:

iop: sio2: PORT0_CTRL0 ff600a0a
iop: sio2: PORT0_CTRL1    20014
iop: sio2: PORT1_CTRL0 ffc00505
iop: sio2: PORT1_CTRL1    2000a
iop: sio2: PORT2_CTRL0        0
iop: sio2: PORT2_CTRL1        0
iop: sio2: PORT3_CTRL0        0
iop: sio2: PORT3_CTRL1        0
iop: sio2:        CTRL      390
iop: sio2:    CMD_STAT     1100
iop: sio2:   PORT_STAT        f
iop: sio2:   FIFO_STAT    50000
iop: sio2:     FIFO_TX    50005
iop: sio2:     FIFO_RX        5
iop: sio2:    IRQ_STAT        1
iop: sio2:   tx buffer 01 42 00 00 00 00 00 00 ...
iop: sio2:   rx buffer ff 41 5a ff ff 00 00 00 ...

I’ve added a list of remains-to-be-done boxes as an implementation plan in the description of this issue.

frno7 commented 4 years ago

Curiously, PS2SDK has notes in timrman.h that PADMAN reserves two timers for its task, but I suppose it shares them with others using VBLANK and HBLANK. HBLANK usually runs rather often, though, at 10+ kHz and seems best to avoid.

I’m considering polling controllers with SetAlarm in THBASE at about 200 Hz instead, in combination with a SIO2 IRQ handler. Any controller latency ought to be imperceptible at that rate. With a 250 kHz SIO2 baud rate that would be a maximum of 156 bytes per poll, or twice the amount at 500 kHz. I assume the worst case is 8 simultaneous controllers via multitap. Perhaps it would be best with an adaptable polling rate, so that one or two controllers are optimal at 200 Hz and won’t suffer any latency for the unusual worst case of having 8 controllers.

Then eventually controllers and memory cards (issue #21) must multiplex over the SIO2 with minimum latency for the controllers and maximum bandwidth for the memory cards.

frno7 commented 4 years ago

Thanks, @sp193! I’m moving the discussion to this issue, since issue #28 will close and applications of timers are more relevant here.

By documentation, it may only be executed from a thread. The newer SDKs have GetSystemTimeLow(), which Sony documented as a faster version that can also be invoked from interrupt handlers.

Would you know if someone has written reasonably complete and publicly available documentation for these and other functions? PS2SDK contains a lot of function declarations but I’m unable to find any reference manual or suchlike.

The USec2SysClock() and SysClock2USec() functions use these values to convert ticks to/from microseconds.

These will be useful, thanks! The plan is to write a state machine for the SIO2 and the controllers described in this issue. Timers will then be used, so that attached controllers are polled for instance every 5 ms whereas unattached ports are polled much less frequently at every 100 ms or so (to discover whether a controller is being attached). If more than 4 controllers are attached, polling could be reduced to 10 ms or perhaps 20 ms, to save SIO2 bandwidth. I expected timers to be crucial to multiplex the SIO2 fairly and efficiently.

sp193 commented 4 years ago

Since it is a Sony console, only Sony has the most complete documentation. Other information can be derived from disassembling their modules.

The official PADMAN transfers data every frame to the EE. Games read the pad state from a buffer on the EE, so the SIO2 bus does not see more activity from the game checking on the pad state at an increased rate.

frno7 commented 4 years ago

Since it is a Sony console, only Sony has the most complete documentation. Other information can be derived from disassembling their modules.

Right, so to use PS2SDK without Sony’s documentation one have to disassemble the modules and study the machine code. I assumed that was the case, but now I know, thanks!

The official PADMAN transfers data every frame to the EE. Games read the pad state from a buffer on the EE, so the SIO2 bus does not see more activity from the game checking on the pad state at an increased rate.

I believe that we can obtain subframe controller latency in the Linux kernel, as it won’t use PADMAN. With adaptable timers and controller state change detection on the IOP side, this should be more efficient too, especially for the EE.

frno7 commented 3 years ago

@sp193, I’m considering writing up a reference manual for the IOP BIOS, starting with the subset used by the Linux kernel modules so far. The format would be RST. Perhaps this text could be shared with PS2SDK? Although different naming conventions are used, the semantics remain exactly the same.

AKuHAK commented 3 years ago

Ps2sdk lacks documentation, thats true. BTW Doxygen generates documentation from ps2sdk with each commit. https://ps2dev.github.io/ps2sdk/

frno7 commented 3 years ago

@AKuHAK, I’ve added issue #4 to Document IOP BIOS API used by modules. Hopefully we can choose a common reference documentation licence that is compatible with both PS2SDK and Linux, to effortlessly share that kind of text.

frno7 commented 3 years ago

So far so good, with 5 out of 13 items done, as listed in the description! The SIO2 seems to behave as one could expect, when directly operating hardware registers (not using the official Sony SIO2MAN or PADMAN modules). The code certainly needs cleaning, but the controller fundamentals are there now.

frno7 commented 3 years ago

Now 6 out of 13 are done, with a proper input event Linux kernel device driver in drivers/ps2/gamepad.c. The corresponding IOP module is module/gamepad.c, which is a SIO2 hardware driver not using Sony firmware.

Documentation remains to be written. And feature extensions, and cleanups. The standard evtest tool in Linux can now test gamepad input events, as applications would observe them. After the keyboard devices (not shown here), the two gamepad ports are listed, and I selected 4 for event4 since a controller happened to be connected to port 2:

/dev/input/event3:  PlayStation 2 gamepad 1
/dev/input/event4:  PlayStation 2 gamepad 2
Select the device event number [0-4]: 4

Various input device information is printed (bus, vendor and version ought to be filled in with something useful):

Input driver version is 1.0.1
Input device ID: bus 0x0 vendor 0x0 product 0x0 version 0x0
Input device name: "PlayStation 2 gamepad 2"

A list of the possible key code events is given, where BTN_SOUTH corresponds cross, BTN_EAST to circle, and so on:

Supported events:
  Event type 0 (EV_SYN)
  Event type 1 (EV_KEY)
    Event code 304 (BTN_SOUTH)
    Event code 305 (BTN_EAST)
    Event code 307 (BTN_NORTH)
    Event code 308 (BTN_WEST)
    Event code 310 (BTN_TL)
    Event code 311 (BTN_TR)
    Event code 312 (BTN_TL2)
    Event code 313 (BTN_TR2)
    Event code 314 (BTN_SELECT)
    Event code 315 (BTN_START)
    Event code 544 (BTN_DPAD_UP)
    Event code 545 (BTN_DPAD_DOWN)
    Event code 546 (BTN_DPAD_LEFT)
    Event code 547 (BTN_DPAD_RIGHT)
Properties:

Then evtest waits for input and pressing and releasing for example the cross, circle and START buttons prints the following:

Testing ... (interrupt to exit)
Event: time 1608053409.675738, type 1 (EV_KEY), code 304 (BTN_SOUTH), value 1
Event: time 1608053409.675738, -------------- SYN_REPORT ------------
Event: time 1608053409.899124, type 1 (EV_KEY), code 304 (BTN_SOUTH), value 0
Event: time 1608053409.899124, -------------- SYN_REPORT ------------
Event: time 1608053412.613564, type 1 (EV_KEY), code 305 (BTN_EAST), value 1
Event: time 1608053412.613564, -------------- SYN_REPORT ------------
Event: time 1608053412.738838, type 1 (EV_KEY), code 305 (BTN_EAST), value 0
Event: time 1608053412.738838, -------------- SYN_REPORT ------------
Event: time 1608053427.549995, type 1 (EV_KEY), code 315 (BTN_START), value 1
Event: time 1608053427.549995, -------------- SYN_REPORT ------------
Event: time 1608053427.735774, type 1 (EV_KEY), code 315 (BTN_START), value 0
Event: time 1608053427.735774, -------------- SYN_REPORT ------------

So two-player games with digital controllers are now possible.

I’m quite happy with how this driver turned out, so far. Especially that it is both event driven (not bothering the EE with nonevents), and has significantly lower latency (preliminary at about 5 ms), compared with the standard firmware.

frno7 commented 2 years ago

The wiki now has a page on controllers.

Arch91 commented 2 years ago

Currently can not build iopmod branch "gamepad". I typed make CROSS_COMPILE=mipsr5900el-unknown-linux-gnu-

frno7 commented 2 years ago

@Arch91, maybe you’ve got a dangling dependency if you’ve switched branches. Have you tried make clean or git clean -fdx before compiling? Strictly speaking this would be an issue for the iopmod repo, but let’s hope it’ll be resolved with a simple cleaning. :smile:

I should probably announce as well that the gamepad.ko kernel module probably will be renamed to controller.ko in the near future, since a gamepad is special kind of controller. Likewise with controller.irx for gamepad.irx. The code will also be merged with the main branch.

Arch91 commented 2 years ago

@frno7, I manually downloaded the source of the iopmod-gamepad branch as a zip-archive file and unpacked it at the same level where is the folder with the iopmod main branch. Should I download it by some git command instead? I tried make clean and git clean -fdx. After the last one I got the same "fatal" notice as if I am trying to build: "not a git repository (or any of the parent directories): .git"

frno7 commented 2 years ago

Ah, yes, iopmod is meant to be compiled in a proper Git repo. One should do something like git clone https://github.com/frno7/iopmod.git, and then cd iopmod followed by git checkout -b gamepad origin/gamepad. The file tool/version.c is generated using Git and its tags. Hence, if the code isn’t in a Git repo, this won’t work.

The code could be made to be compilable without a Git repo too, of course, but I haven’t done that yet.

The generated version.c is used for the --version tool option.

Arch91 commented 2 years ago

Alright, gamepad.irx is compiled. To test the gamepad driver I compiled «joypadlib-0.14», there is a «main» gamepad test program. However, to compile that, I had to copy the old headers like pad.h (and etc. — ee.h, gs.h, ...) to cross-compiler’s_directory/include/linux/ps2/ . Also I sured that there are ps2pad00 and ps2pad10 device nodes in /dev/ directory. modprobe gamepad goes well. And when I launch that "main" test program, nothing happens. Analog button is not working. After the "main" program is launched, the gamepad's led was originally enlighten, and with the current gamepad driver nothing of that is happening. @frno7, are you trying to make a usual linux gamepad controller driver? Will be the old original PS2Linux device access supported for such programs/libs like joypadlib? If not, will be that result linux gamepad driver support the buttons pressure detection and the vibration functions?

frno7 commented 2 years ago

@Arch91, could you try the evtest tool as explained on the controller wiki page? It should be very easy to compile, and it’s the best starting point. I believe /dev/input/event# is the modern input device interface for Linux 5.x kernels, and I believe it supports all items listed including motor (rumble) control which would be advertised as FF_RUMBLE when implemented. Modern Linux games use this for most if not all architectures.

Have you taken a look at the official Linux gamepad specification?

Arch91 commented 2 years ago

I took a look at the linux gamepad specification, and I see no the detector of how hardly the button is pressed. That's unique for all of the DS>=2 gamepads. Well... I didn't see a worth implementation for that function... only L2/R2 in the race games... Anyway, I do not see how that unique feature is achievable through the standard linux gamepad functions. Tested evtest. It detected PS2 gamepad1 (connected to the right gamepad slot) in /dev/input/event4 and gamepad2 (to the left gamepad slot) in /dev/input/event5 - are these slots/detection correct? - not vice versa? Working buttons are the arrows, x,o,^,[], L1/2, R1/2. DS1 is also working, same buttons acceptable. I see that in the places where that unique pressing function will be needed, it will has to be implemented manually in the source code of that program. Even I could implement the functions of the old joypadlib to PicoDrive-SDL making it working with the gamepads and with their vibration units :D So this birthed that question - is there a chance that there will be two drivers - your new one and an ps2linux'es old renewed one (with pad.h, /dev/ps2pad00\/10)?

frno7 commented 2 years ago

Thanks, @Arch91! I’ve added a new item about pressure sensitivity

  • [ ] recognise 256 pressure levels for all buttons except for the analog mode, start, select, L3 and R3;

to the plan. It remains to be investigated how to do that properly though...

Tested evtest. It detected PS2 gamepad1 (connected to the right gamepad slot) in /dev/input/event4 and gamepad2 (to the left gamepad slot) in /dev/input/event5 - are these slots/detection correct? - not vice versa?

I believe that /dev/input/event# devices are dynamically assigned, and therefore have arbitrary numbers starting at 0. First come, first served, I’d guess. The event device description text should tell which controller port it really is, though.

Working buttons are the arrows, x,o,^,[], L1/2, R1/2. DS1 is also working, same buttons acceptable.

Hooray!

I see that in the places where that unique pressing function will be needed, it will has to be implemented manually in the source code of that program. Even I could implement the functions of the old joypadlib to PicoDrive-SDL making it working with the gamepads and with their vibration units :D So this birthed that question - is there a chance that there will be two drivers - your new one and an ps2linux'es old renewed one (with pad.h, /dev/ps2pad00/10)?

Someone could certainly do it, but my focus is on completing the modern /dev/input/event# controller thing. :smile:

mirh commented 2 years ago

https://bugzilla.kernel.org/show_bug.cgi?id=195643

frno7 commented 2 years ago

@mirh, have you heard anything since its last message on 27 July 2018?

It’s very unfortunate that firms “deprecate” Linux kernel features of hardware they believe are no longer used. The fbdev replacement DRM, for example, is a poor match for the Graphics Synthesizer because it doesn’t work like recent graphics cards, having no EDID etc.

mirh commented 2 years ago

Not really, but you can chime in. I guess it's awful when it's just a random noob passing by with handwaved ideas (to this day I'm still not sure evdev is really the system you'd want and need to tinker with), and not somebody that could actually contribute with some code pitch. Supposedly you should be able to do it with hidapi, but putting aside I have never really checked, I don't know, it still seems a bit too low level than it should.

As for fbdev, it's not that bad either. https://lwn.net/Articles/881827/ https://www.phoronix.com/scan.php?page=news_item&px=Linux-FBDEV-2022-Maintainer

frno7 commented 2 years ago

@mirh, my impression is that evdev is the most appropriate controller interface for most applications such as games that needn’t deal with much hardware specifics. For example, everything that broadly looks like a gamepad would work. Presumably hundreds of different makes and models. Sure, USB and Bluetooth devices, possibly via some hidapi library, could be made to work without too much effort in special cases, especially for a limited set of controllers such as the DualShock series and third-party USB adapters for DualShock 2, etc. Emulators would be as good as they could possibly get, given the hardware.

That said, the DualShock 2 is a native device on actual PlayStation 2 hardware, so it’s neither USB nor Bluetooth and hidapi therefore doesn’t apply. The only reasonable alternative I could think of is the special ps2pad device used with Linux 2.x, as suggested by @Arch91, which would require special support with games and libraries such as the SDL. Of course, one could support both evdev and ps2pad devices.

Curiously, netevent is a tool whereby actual PlayStation 2 hardware with DualShock 2 devices attached can share its controllers with another machine, such as PC. No need for silly DualShock 2 USB adapters. :smile:

I heard about a new fbdev maintainer, but I assume that the fbdev ban still stands, because fbdev seems to be destined for removal regardless. Once fbdev is disposed, perhaps someone will step up and fix the most pressing problems with the DRM.

mirh commented 2 years ago

Right, this is about having (and controlling at the source) a driver, not just whatever plain user api. https://web.archive.org/web/20031229164058/http://playstation2-linux.com/projects/joypadlib https://github.com/rickgaiser/linux-2.4.17-ps2/blob/master/drivers/ps2/pad.c Idk really how much of those design decisions could still apply neatly in 2022 then, though I feel like whatever the answer should come to encompass neatly the DS3 too (since its feature set is a strict superset).

Maybe @jonnygrant and @nedelman have still some idea :) p.s. a multitap driver did exist in the past

frno7 commented 2 years ago

Right, this is about having (and controlling at the source) a driver, not just whatever plain user api. https://web.archive.org/web/20031229164058/http://playstation2-linux.com/projects/joypadlib https://github.com/rickgaiser/linux-2.4.17-ps2/blob/master/drivers/ps2/pad.c p.s. a multitap driver did exist in the past

@mirh, I’m quite sure they used a Sony gamepad IRX module, and possibly the BIOS. Neither are usable with the controller driver implemented here, since it operates directly on the hardware registers for maximum flexibility, efficiency and performance. I’ve found the following resources usable:

https://problemkaputt.de/psx-spx.htm https://store.curiousinventor.com/guides/PS2

And helpful notes by Wisi, as mentioned in https://github.com/frno7/linux/issues/22#issuecomment-647026775. Quite a few hardware registers in sio2.h remain to be understood, named, and documented, though.

Arch91 commented 2 years ago

@frno7, I noticed some gamepad related changes made 5 days ago) Share that's new!)

frno7 commented 2 years ago

@Arch91, oh? Well, the DualShock was recently mentioned in discussion #75 if you should care to dip into real console games...

frno7 commented 1 year ago

The Dual Shock gamepad module commit https://github.com/frno7/iopmod/commit/3c9d92e61e75b77f0df3dd7efcb151c62d56103f is now on the iopmod main branch. Load it into the kernel with modprobe gamepad. evtest is perhaps the simplest tool to test it, as mentioned in https://github.com/frno7/linux/issues/22#issuecomment-745493264.

Arch91 commented 1 year ago

@frno7, so you decided to make the .irx module for the DS®2 gamepads instead of the kernel's module.o... Will you reveal the stormy clouds of your idea why did you do that?)

frno7 commented 1 year ago

@frno7, so you decided to make the .irx module for the DS®2 gamepads instead of the kernel's module.o... Will you reveal the stormy clouds of your idea why did you do that?)

There’s a lib/firmware/ps2/gamepad.irx for the IOP and its SIO2 hardware, and a lib/modules/*/kernel/drivers/ps2/gamepad.ko for the Linux kernel. The latter loads the former automatically. Both are needed for Dual Shock gamepads to function.