linux icon indicating copy to clipboard operation
linux copied to clipboard

Enable the DualShock 2 controller

Open frno7 opened this issue 6 years ago • 35 comments

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

  • [x] one DualShock 2 controller;
  • [x] two DualShock 2 controllers;
  • [x] regular polling, for example at 200 Hz;
  • [x] state change detection to avoid needless EE interrupts;
  • [ ] reduce polling to 10 Hz or so when controllers are idle for a long time;
  • [ ] define and implement a suitable IOP-EE SIO2 protocol;
  • [x] implement an input event Linux kernel device driver;
  • [ ] indicate whether controllers are attached or detached;
  • [x] handle errors, such as timeouts and failures of various kinds;
  • [ ] conclude whether SIO2 DMA makes sense for controllers;
  • [ ] motor (rumble) control;
  • [ ] switch between digital and analogue controls;
  • [ ] recognise 256 pressure levels for all buttons except for the analog mode, start, select, L3 and R3;
  • [ ] recognise controllers other than DualShock 2;
  • [ ] consider naming the module sio2controller, or suchlike, as that’d be more specific than gamepad;
  • [ ] multitap.

frno7 avatar Mar 17 '19 13:03 frno7

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.

frno7 avatar Jun 14 '20 17:06 frno7

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

AKuHAK avatar Jun 16 '20 08:06 AKuHAK

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

rickgaiser avatar Jun 16 '20 08:06 rickgaiser

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 avatar Jun 16 '20 14:06 frno7

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 avatar Jun 20 '20 17:06 frno7

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 avatar Jul 04 '20 14:07 frno7

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 avatar Jul 05 '20 13:07 frno7

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.

frno7 avatar Jul 06 '20 15:07 frno7

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.

sp193 avatar Jul 06 '20 15:07 sp193

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 avatar Jul 06 '20 15:07 frno7

@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.

frno7 avatar Jul 07 '20 17:07 frno7

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

AKuHAK avatar Jul 07 '20 19:07 AKuHAK

@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 avatar Jul 08 '20 12:07 frno7

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 avatar Jul 08 '20 16:07 frno7

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 avatar Dec 15 '20 18:12 frno7

The wiki now has a page on controllers.

frno7 avatar Dec 31 '21 09:12 frno7

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

  • and it asks for some likely absent file tool/version.c . No doubt I built a working cross-compiler.

Arch91 avatar Jan 21 '22 07:01 Arch91

@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.

frno7 avatar Jan 22 '22 06:01 frno7

@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"

Arch91 avatar Jan 22 '22 12:01 Arch91

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.

frno7 avatar Jan 22 '22 12:01 frno7

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?

Arch91 avatar Jan 22 '22 14:01 Arch91

@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?

frno7 avatar Jan 22 '22 14:01 frno7

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)?

Arch91 avatar Jan 22 '22 18:01 Arch91

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:

frno7 avatar Jan 22 '22 18:01 frno7

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

mirh avatar Jan 22 '22 19:01 mirh

@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.

frno7 avatar Jan 23 '22 06:01 frno7

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

mirh avatar Jan 23 '22 16:01 mirh

@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.

frno7 avatar Jan 23 '22 17:01 frno7

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

mirh avatar Feb 01 '22 14:02 mirh

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.

frno7 avatar Feb 01 '22 16:02 frno7