參考資訊:
https://lore.kernel.org/patchwork/patch/171865/
雖然在Maemo系統下有USB Host功能可以使用,不過缺點則是UART(/dev/ttyS2)無法使用,而Native Debian系統下,則是UART(/dev/ttyO2)可以使用,但是USB Host無法使用,原因是驅動程式的問題,雖然司徒更喜愛Native Debian系統,畢竟可以直接使用Debian的套件,不過在Native Debian系統下,還是有很多不完善的地方,如:過於耗電(150mA, Idle)、USB Host無法使用、Camera無法使用、Display架構過於耗CPU資源,而最讓司徒頭痛就是耗電問題,因為150mA的耗電速度,大約是一小時10%(原廠電池),因此,這讓司徒又重新安裝回Maemo系統,加上司徒目前已經可以解決Root 256MB的容量限制,因此,司徒只要把Maemo的UART(/dev/ttyS2)問題解決後,基於Maemo系統的N900就可以成為一台真正好用的開發機器,而經過多次努力移植以及測試後,司徒發現其實只要修改一個小判斷就可以讓Maemo系統支援/dev/ttyS2,不需要重新移植OMAP UART驅動
司徒一開始使用Patch方式添加,發現只有兩個地方需要修改,分別是arch/arm/mach-omap2/serial.c、drivers/omap-serial.c,雖然有一些Redefine問題,不過手動修復後,TTY依然沒有被添加,於是司徒往回翻舊版Kernel,發現omap-serial.c是在Kernel 2.6.37新增,於是直接使用2.6.37 omap-serial.c,結果還是無法使用,後來發現omap-serial.c的probe()沒有被呼叫,於是查看arch/arm/mach-omap2/serial.c的添加是否有問題
void __init omap_serial_init(void)
{
int i;
const struct omap_uart_config *info;
char name[16];
/*
* Make sure the serial ports are muxed on at this point.
* You have to mux them off in device drivers later on
* if not needed.
*/
info = omap_get_config(OMAP_TAG_UART, struct omap_uart_config);
if (info == NULL)
return;
for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
struct plat_serial8250_port *p = serial_platform_data + i;
struct omap_uart_state *uart = &omap_uart[i];
if (!(info->enabled_uarts & (1 << i))) {
p->membase = NULL;
p->mapbase = 0;
continue;
}
info->enabled_uarts拿到的uart flag都是disabled,於是往回找omap_get_config()
const void *__omap_get_config(u16 tag, size_t len, int nr)
{
return get_config(tag, len, nr, NULL);
}
EXPORT_SYMBOL(__omap_get_config);
P.S. 位於arch/arm/plat-omap/common.c
往回找到get_config()
static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out)
{
struct omap_board_config_kernel *kinfo = NULL;
int i;
#ifdef CONFIG_OMAP_BOOT_TAG
struct omap_board_config_entry *info = NULL;
if (omap_bootloader_tag_len > 4)
info = (struct omap_board_config_entry *) omap_bootloader_tag;
while (info != NULL) {
u8 *next;
if (info->tag == tag) {
if (skip == 0)
break;
skip--;
}
if ((info->len & 0x03) != 0) {
/* We bail out to avoid an alignment fault */
printk(KERN_ERR "OMAP peripheral config: Length (%d) not word-aligned (tag %04x)\n",
info->len, info->tag);
return NULL;
}
next = (u8 *) info + sizeof(*info) + info->len;
if (next >= omap_bootloader_tag + omap_bootloader_tag_len)
info = NULL;
else
info = (struct omap_board_config_entry *) next;
}
if (info != NULL) {
/* Check the length as a lame attempt to check for
* binary inconsistency. */
if (len != NO_LENGTH_CHECK) {
/* Word-align len */
if (len & 0x03)
len = (len + 3) & ~0x03;
if (info->len != len) {
printk(KERN_ERR "OMAP peripheral config: Length mismatch with tag %x (want %d, got %d)\n",
tag, len, info->len);
return NULL;
}
}
if (len_out != NULL)
*len_out = info->len;
return info->data;
}
#endif
/* Try to find the config from the board-specific structures
* in the kernel. */
for (i = 0; i < omap_board_config_size; i++) {
if (omap_board_config[i].tag == tag) {
if (skip == 0) {
kinfo = &omap_board_config[i];
break;
} else {
skip--;
}
}
}
if (kinfo == NULL)
return NULL;
return kinfo->data;
}
接著看一下omap_board_config
static struct omap_uart_config rx51_uart_config = {
.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
};
P.S. 位於arch/arm/mach-omap2/board-rx51.c
從這個結構來看UART1、UART2、UART3應該都是被Enabled才是,怎會到omap_serial_init()就變成Disabled呢?於是埋了一些資訊Debug,這才發現CONFIG_OMAP_BOOT_TAG是被定義的,由UBoot傳入參數,這時司徒突然想起ITEM_OMAPTAG這個東西,原來是從那裡傳入,而列印後,發現UART確實被Disabled,於是司徒直接修改get_config(),只要是UART Tag(OMAP_TAG_UART)就直接讀取Kernel定義的Flag
static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out)
{
struct omap_board_config_kernel *kinfo = NULL;
int i;
#ifdef CONFIG_OMAP_BOOT_TAG
if(tag != OMAP_TAG_UART){
struct omap_board_config_entry *info = NULL;
if (omap_bootloader_tag_len > 4)
info = (struct omap_board_config_entry *) omap_bootloader_tag;
while (info != NULL) {
u8 *next;
if (info->tag == tag) {
if (skip == 0)
break;
skip--;
}
if ((info->len & 0x03) != 0) {
/* We bail out to avoid an alignment fault */
printk(KERN_ERR "OMAP peripheral config: Length (%d) not word-aligned (tag %04x)\n",
info->len, info->tag);
return NULL;
}
next = (u8 *) info + sizeof(*info) + info->len;
if (next >= omap_bootloader_tag + omap_bootloader_tag_len)
info = NULL;
else
info = (struct omap_board_config_entry *) next;
}
if (info != NULL) {
/* Check the length as a lame attempt to check for
* binary inconsistency. */
if (len != NO_LENGTH_CHECK) {
/* Word-align len */
if (len & 0x03)
len = (len + 3) & ~0x03;
if (info->len != len) {
printk(KERN_ERR "OMAP peripheral config: Length mismatch with tag %x (want %d, got %d)\n",
tag, len, info->len);
return NULL;
}
}
if (len_out != NULL)
*len_out = info->len;
return info->data;
}
}
#endif
/* Try to find the config from the board-specific structures
* in the kernel. */
for (i = 0; i < omap_board_config_size; i++) {
if (omap_board_config[i].tag == tag) {
if (skip == 0) {
kinfo = &omap_board_config[i];
break;
} else {
skip--;
}
}
}
if (kinfo == NULL)
return NULL;
return kinfo->data;
}
重新編譯zImage後,就可以使用/dev/ttyS2
$ dmesg | grep serial
[65435.071594] serial8250.0: ttyS0 at MMIO 0x4806a000 (irq = 72) is a ST16654
[65435.092071] serial8250.0: ttyS1 at MMIO 0x4806c000 (irq = 73) is a ST16654
[65435.112548] serial8250.0: ttyS2 at MMIO 0x49020000 (irq = 74) is a ST16654