Revision as of 09:53, 9 November 2004

While early printk is rather useful, you still need to get the real serial
driver working.

Assuming you have a standard serial port, there are two ways to add serial
support: static defines and run-time setup.

With static defines, you modify the 'include/asm-mips/serial.h' file. Looking
through the code, it is not difficult to figure out how to add support for your
board's serial port(s).

As more boards are supported by Linux/MIPS, the 'serial.h' file gets crowded.
One potential solution is to do run-time serial setup. Sometimes run-time
serial setup is necessary if any of the parameters can only be detected at the
run-time where settings are read from a non-volatile memory device or an option
is passed on the kernel command line.

There are two elements to consider for doing run-time serial setup:

Reserve the 'rs_table[]' size, see the 'drivers/char/serial.c' file. Unfortunately there is not a clean way to accomplish this yet. A temporary workaround is to define CONFIG_SERIAL_MANY_PORTS in 'arch/mips/config-shared.in' for your board. This configuration reserves up to 64 serial port entries for your board!

Contents

Serial parameters

Most of the parameter settings are rather obvious. Here is a list of some less
obvious ones:

line

Only used for run-time serial configuration. It is the index into the 'rs_table[] array'.

io_type

io_type determines how your serial registers are accessed. Two common types are SERIAL_IO_PORT and SERIAL_IO_MEM. A SERIAL_IO_PORT type driver uses the inb/outb macros to access registers whose base address is at port. In other words, if you specify SERIAL_IO_PORT as the io_type, you should also specify the port parameter.

For SERIAL_IO_MEM, the driver uses readb/writeb macros to access regsiters whose address is at iomem_base plus a shifted offset. The number of digits shifted is specified by iomem_reg_shift. For example, all the serial registers are placed at 4-byte boundary, then you have an iomem_reg_shift
of 2.

Generally SERIAL_IO_PORT is for serial ports on an ISA bus and SERIAL_IO_MEM is for memory-mapped serial ports. There are also SERIAL_IO_HUB6 and SERIAL_IO_GSC. The HUB6 was a multi-port serial card produced by Bell Technologies. The GSC is a special bus found on PA-RISC systems. These options will not be used on any MIPS boards.

Non-standard serial ports

If you have a non-standard serial port, you will have to write your own serial driver.

Some people derive their code from the standard serial driver. Unfortunately this is a very daunting task. The 'drivers/char/serial.c' file has over 6000 lines of code!

The generic serial way

Fortunately, there is an alternative [THANKS: Fillod Stephane]. There is a generic serial driver, 'drivers/char/generic_serial.c'. This file provides a set of serial routines that are hardware independent. Then your task is to provide only the routines that are hardware dependent such as the interrupt handler routine and low-level I/O functions. There are plenty of examples. Just look inside the 'drivers/char/Makefile' and look for drivers that link with 'generic_serial.o' file.

[HELP: Would appreciate if you can share your experience of writing proprietary serial driver code or using the 'generic_serial.c' file.]

The drivers/serial way

There is an other, even simpler alternative to the generic serial way described above. It consists in using the drivers/serial/serial_core.c infrastructure, which allows to write a very simple serial driver.

Writing the kernel console driver

First of all, the kernel needs a very simple serial driver that only allows to output characters. It should not use interrupts nor DMA to be as simple as possible. It is used to display all kernel messages printed with printk().

Let's say our strange chipset is named //foo// in the rest of the article. Start by creating the file drivers/serial/foo-console.c. You should at least include the following files :

- static void foo_console_write(struct console *co, const char *s, unsigned count), which should write the count characters from the string s to the serial port. For example, it can simply loop on each character of the string and call an internal function which aims at writing a single character to the serial port.
- static __init int mv64340_console_setup(struct console *co, char *options), which should initialize the serial port hardware according to the given options. If your serial hardware is already initialized by the Firmware, then you don't need to do anything in this function.