參考資訊:
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