Serial port drivers?
Theo Markettos (89) 919 posts |
I’ve been staring at code too long, and I’m confused how all the various serial port code fits together. The HAL, obviously, is specific to whatever serial chip is fitted to that machine. For example, the Tungsten (Iyonix) HAL (Sources/HAL/Tungsten/UART.s) dives straight in and assumes it knows where the serial port can be found and goes and pokes its registers. There’s also SerialDeviceDriver (Sources/HWSupport/Serial). This seems to come in two versions: 6551 (for Archimedes hardware) and 82C710 (for 16450/16550 compatible chips, as used in A5000, Risc PC, BeagleBoard and, using PCI detection, Iyonix). It seems to completely ignore the HAL. Then there’s Sources/HWSupport/DualSerial, which hasn’t been touched for years and seems to date from the NC projects. That also knows about serial port registers (of the 16550 variety, I assume). And then there’s other third-party drivers (like Thomas Milius’ FTDI driver) that just provide a DeviceFS object. If I want to write a primary serial port driver that doesn’t use a 16550 clone, do I have to write the code twice, once for the HAL and once for SerialDeviceDriver? Shouldn’t SerialDeviceDriver call the HAL rather than poking the registers itself? Presumably the HAL version is used for kernel debug etc and SerialDeviceDriver for talking to serial devices when the machine has booted. Does OS_SerialOp go through SDD? |
Theo Markettos (89) 919 posts |
I’ve just found yet another place where the serial port hardware is accessed: HAL_DebugRX/TX. I accept that that’s a special case, but that raises the question: if it isn’t used for HAL debug output, what does HAL_UART actually do? Jeffrey’s doc on hardware abstraction from 2009 states that it justs returns the 16550 UART address, but there seems to be a full driver in the Iyonix HAL, separate from DebugRX/TX. But then SerialDeviceDriver doesn’t use that driver. It’s confusing! |
Sprow (202) 1158 posts |
Remember that the Tungsten HAL will use its serial port to recover itself if the flash ROM image is corrupt, so will have more serial code than you might otherwise need. |
Jeffrey Lee (213) 6048 posts |
Although the main branch hasn’t been touched in years, there’s actually a HAL branch which is what gets used on the Iyonix. This uses the HAL_UART API, and (IIRC) creates multiple DeviceFS device instances, one per serial port.
I believe OS_SerialOp goes via SerialDeviceDriver. One of the things that’s still on my todo list is to sort out the BeagleBoard serial drivers. I’m still a little confused by everything, but I believe the (PCI-attached) 82C710 in the Iyonix provides both of the serial ports. One of these is then exposed via SerialDeviceDriver, and the other via the HAL_UART API (and therefore DualSerial). In an ideal world I’d just include DualSerial and let that deal with everything, but then that would leave OS_SerialOp doing nothing. So some extra logic is probably needed somewhere to make sure DualSerial is able to take care of OS_SerialOp & related functionality. It would also be nice if that logic was easily extensible to deal with other serial port drivers in the future (e.g. if RISC OS is ported to a system where the HAL UART API doesn’t make sense, or for a system without any serial ports fitted as default but people might want to use USB<→serial adapters, etc.). So something like a vector or service call where an OS_SerialOp handler can register itself with the kernel. |
Theo Markettos (89) 919 posts |
Thanks. I’ve done a bit more staring, and it’s starting to make sense. DualSerial (HAL branch) provides Devices:$.Serial1 and Devices:$.Serial2 using the HAL SerialDeviceDriver provides Devices:$.Serial using 16550 hardware (if built in 82C710 ‘NewHardware’ mode) or 6551 hardware (‘OldHardware’ mode). It mentions PCI – I haven’t worked out if that’s just a synonym for ‘NewHardware’. SerialDeviceSupport uses DeviceFS to implement OS_SerialOp and the appropriate OS_Byte calls. It’s hardcoded to Devices:$.Serial SerialMouse also uses DeviceFS and is hardcoded to Devices:$.Serial. However it throws all its good karma away by then calling OS_SerialOp to set some of the control lines (to power up the mouse, presumably) So I would suggest shooting SerialDeviceDriver and making everything run through DualSerial, which shouldn’t be too hard. Perhaps configuring the default ‘legacy’ port (for OS_SerialOp/*FX3) and ‘mouse’ port with system variables? |
Jeffrey Lee (213) 6048 posts |
I’ve just checked in a few serial related changes for the OMAP3 port – see here for details. But apart from bringing your attention to the changes, I’ll also make a quick comment about this:
Note that I didn’t actually write that doc – all I did was wikify the existing documentation that was in CVS. There are quite a few factual inaccuracies in the HAL docs, most of them inherited from the original docs :-( E.g. I’ve just spotted that the ‘mask’ parameter to HAL_UARTModemControl is ignored by the Iyonix UART driver, and anything derived from it (e.g. OMAP3 & OMAP4). The function always acts as if the mask is 3, i.e. unless ‘eor’ is -1 it just sets the two control lines to the indicated value. The DualSerial module acts as if the parameter works as documented, so it’s probably a bug in the HALs rather than a documentation error. DualSerial only ever uses the call to set both lines at once, so that’s probably why the bug hasn’t been noticed before. |
Jeffrey Lee (213) 6048 posts |
That Devices:$.Serial filename in the sources seems to be a red herring. The module issues a Service_SerialDevice service call, which SerialDeviceDriver responds to, returning the DeviceFS handle of the device. It shouldn’t be too hard to make DualSerial respond to the same service call, preferably with the HAL indicating which port to use as the default. Then later on decide on how to handle user configuration of ports. Using CMOS RAM would be nice, but is probably unfeasible, since there’d be no easy way of providing support for third-party serial device drivers that don’t name the DeviceFS entries Serial<n>. So I’m leaning towards using code system variables containing the DeviceFS filename. |
Dave Higton (281) 668 posts |
I’ve just been having a look at a couple of aspects of serial support for the BBxM. (I’m amazed at the complexity of support for just a collection of UARTs.) I see the OMAP labels them 1, 2 and 3, and the xM brings out one of them to a connector – not number 1, which would have been obvious; but number 3. And it’s a female connector, unlike all other computers that have serial ports. The Internal32 blockdriver numbers ports from 0 upwards in its API. Internal32, when booted, defines three macros: Serial1$Path(Macro) : devices#<FileSwitch$SpecialField>:$.Serial1. Serial2$Path(Macro) : devices#<FileSwitch$SpecialField>:$.Serial2. Serial3$Path(Macro) : devices#<FileSwitch$SpecialField>:$.Serial3. which is different from the Iyonix: Serial$Path(Macro) : devices#<FileSwitch$SpecialField>:$.Serial. Serial1$Path(Macro) : devices#<FileSwitch$SpecialField>:$.Serial1. One question is what mapping should be used. I’d expect the single built-in port to appear as the first port. Is that what’s planned? |