First thing you'll need is a working modeline. I created an ultra-wide 1920x240/60 modeline using this online calculator. Using a wide resolution like this leverages the natural blurriness of CRTs to hide fractional scaling artifacts on the horizontal axis, while the 240 vertical resolution allows perfect 1:1 scaling on the vertical axis. This provides a beautiful, "pixel-perfect" image for a large variety of games, including my favorites--Capcom's CPS-1/2.
This is the resulting modeline (negative sync options added by me):
Modeline "1920x240@60" 31.96 1920 1952 2072 2104 240 245 248 253 -HSync -VSyncI recommend testing your modeline out in a standard desktop environment using xrandr first, since it's pretty low-stakes. If something messes up, you just reboot and everything goes back to normal.
Once you've verified that your modeline works, you're ready to create your custom EDID. There are several good writeups about the process online, but I found this one most helpful. I won't rehash all the steps here, but you essentially just copy the appropriate files from the kernel tree and modify/rename one of the existing EDID source files (I used 1024x768.S) with the values from your modeline (I named mine 1920x240.S).
Here's the important part (i.e., license boilerplate removed for brevity; it's standard GPL2) from mine:
/* EDID */
#define VERSION 1
#define REVISION 3
/* Display */
#define CLOCK 31960 /* kHz */
#define XPIX 1920
#define YPIX 240
#define XY_RATIO XY_RATIO_4_3
#define XBLANK 184
#define YBLANK 13
#define XOFFSET 32
#define XPULSE 120
#define YOFFSET (63+5)
#define YPULSE (63+3)
#define DPI 72
#define VFREQ 60 /* Hz */
#define TIMING_NAME "Ultrawide"
#define ESTABLISHED_TIMING2_BITS 0x08 /* Bit 3 -> 1024x768 @60 Hz */
#define HSYNC_POL 0
#define VSYNC_POL 0
#define CRC 0xf7
#include "edid.S"
Next, compile your source files, which should leave you with 1920x240.bin and 1920x240.bin.ihex (the *.ihex one is unneeded, AFAICT). Open 1920x240.bin with the edid-decode utility (available from the standard Ubuntu repos) and it should tell you something about the checksum being wrong (assuming you're making your own; mine already has the corrected checksum). Reopen your custom *.S and replace the existing, incorrect checksum where it says "#define CRC [whatever]" with the value it says it should have and then re-compile. It shouldn't complain this time.
Here's my compiled 1920x240.bin EDID, which should work for any standard-res 15 khz arcade monitor.
Here's my compiled 1920x240.bin EDID, which should work for any standard-res 15 khz arcade monitor.
Once you have your shiny new EDID *.bin file, you'll need to create a new directory in /lib/firmware called 'edid,' which will require elevated privileges:
sudo mkdir /lib/firmware/edid
Then copy your *.bin file into it.
Next, you'll need to create a file named drm-kms-helper.conf, which contains only one line:
options drm_kms_helper edid_firmware=edid/1920x240.bin
and move it into your /etc/modprobe.d/ directory (again, needs elevated privs). Of course, you'll need to replace '1920x240.bin' with whatever you've named yours.
At this point, your custom EDID should be usable by your system, so a reboot will get you the desired resolution. If something goes wrong and you need to revert, just delete /etc/modprobe.d/drm-kms-helper.conf and it will put everything back the way it was.
If--like me--you'd like to go all the way and boot to a command line (instead of a standard GUI environment) that uses the new res, you'll want to edit your /etc/default/grub (needs elevated privs again) and replace the line:
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
with
GRUB_CMDLINE_LINUX_DEFAULT="text"
Then run 'sudo update-grub' to put it into effect. Now, on subsequent reboots, it won't try to load an X-Server and desktop environment and will instead go straight to console.
Finally, I don't plan on having a keyboard connected to my cabinet all the time (kinda kills the mood, y'know?), so I wanted it to login to my user account automatically. To do this, edit /etc/init/tty1.conf in a text editor and comment out the last line:
#exec /sbin/getty -8 38400 tty1
and add this below it instead:
exec /bin/login -f username < /dev/tty1 > /dev/tty1 2>&1
Replace 'username' with the name of the user account you want to login automatically. And, if you want to have it load a frontend--like RetroArch--as soon as it finishes logging in, you can add the launch command to the end of that user account's ~/.bashrc file.