一,移植环境
(红色粗字体字为修改后内容,蓝色粗体字为特别注意内容)
1.主机环境:Virtualbox 下ubuntu-10.10
2.编译编译环境:arm-linux-gcc v4.4.3
3.uboot : U-Boot 1.3.4(友坚提供)
4.linux内核版本:2.6.21.5
5.硬件平台:采用友坚UT2416CV02核心板开发的平台
6.参考:
linux内核支持S3C2416的UART3 (http://www.itkee.com/os/detail-1677.html )
修改linux内核支持S3C2416或S3C2443的UART3
linux内核版本为:2.6.21.5
1 2 3 步骤的修改都在/drivers/serial/s3c2410.c文件中。
1修改.#ifdef CONFIG_CPU_S3C2400
#define NR_PORTS (2)
#else
#define NR_PORTS (3)
#endif
为:
#ifdef CONFIG_CPU_S3C2400
#define NR_PORTS (2)
#else
#define (4) /*modify by zhuang*/
#endif
2.在static struct s3c24xx_uart_port s3c24xx_serial_ports[NR_PORTS]数组中添加:
#if NR_PORTS > 3
[3] = {
.port = {
.lock= SPIN_LOCK_UNLOCKED,
.iotype= UPIO_MEM,
.irq= IRQ_S3CUART_RX3,
.uartclk= 0,
.fifosize= 16,
.ops= &s3c24xx_serial_ops,
.flags= UPF_BOOT_AUTOCONF,
.line= 3,
} ,
#endif
3.结构体数组static struct uart_driver s3c24xx_uart_drv中的dev_name= "s3c2410_serial",
改为:
dev_name= "ttySAC",
修改.nr= 3,
为: .nr= NR_PORTS,
4.添加:在/includes/arm-arm/arch-s3c2410/irqs.h头文件中
/*UART3 for S3C2416 or S3C2443*/
#define IRQ_UART3 IRQ_S3C2443_UART3
#define IRQ_S3CUART_RX3 IRQ_S3C2443_RX3
#define IRQ_S3CUART_TX3 IRQ_S3C2443_TX3
#define IRQ_S3CUART_ERR3 IRQ_S3C2443_ERR3
5./arch/arm/mach-smdk2416中的static struct s3c2410_uartcfg smdk2416_uartcfgs[] __initdata数组中添加:
./* UART3 */
[3] = {
.hwport = 3,
.flags = 0,
.ucon = 0x3c5,
.ulcon = 0x03,
.ufcon = 0x51,
6.arch/arm/mach-s3c2416/irq.c中,
#define SUBMSK_UART3(0xf << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))修改为
#define SUBMSK_UART3(0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
7.arch/arm/mach-s3c2443/irq.c中,
#define SUBMSK_UART3(0xf << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))修改为
#define SUBMSK_UART3(0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
6和7步骤的修改如果是 2.6.38以上版本就不用修改,这个bug在2.6.38以后就被修复了。
这个bug在http://permalink.gmane.org/gmane.linux.kernel.samsung-soc/3530
发布了。
8 修改.arch/arm/mach-s3c2443/irq.c和.arch/arm/mach-s3c2416/irq.c的
static void s3c2443_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
s3c2443_irq_demux(IRQ_S3C2443_UART3, 3);
为:
static void s3c2443_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
s3c2443_irq_demux(IRQ_S3C2443_RX3, 3);
9.include/asm/arch/regs-serial.h中,修改
#if defined (CONFIG_CPU_S3C6400) || defined (CONFIG_CPU_S3C6410)
#define NR_PORTS (4)
#define UART_FIFO_SIZE64
#define UART_HAS_INTMSK
#define UART_C_CFLAG
#define UART_UMCON
#define UART_CLK115200
#else
#define NR_PORTS (3)
#endif
为:
#if defined (CONFIG_CPU_S3C6400) || defined (CONFIG_CPU_S3C6410)
#define NR_PORTS (4)
#define UART_FIFO_SIZE64
#define UART_HAS_INTMSK
#define UART_C_CFLAG
#define UART_UMCON
#define UART_CLK115200
#else
#define NR_PORTS (4)
#endif
修改后重新编译内核就可以使用UART3了。
S3C2416 User's Manual, Revision 1.10
二,添加UART3
S3C2416支持4个UART,但友坚给出的内核只支持3个UART(ttySAC0,ttySAC1,ttySAC2),而不支持UART3 及 ttySAC3。下面介绍在友坚给出的内核基础上实现UART3。
1.添加UART3的资源设置
<1>. 打开 kernel2416/arch/arm/plat-s3c24xx/devs.c ,定位到113行附近,更改如下:
[cpp] view plain copy print ?
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- static struct resource s3c2410_uart3_resource[] = {
- [0] = {
- .start = S3C2443_PA_UART3,
- .end = S3C2443_PA_UART3 + 0x3fff,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_S3CUART_RX3,
- .end = IRQ_S3CUART_ERR3,
- .flags = IORESOURCE_IRQ,
- }
- };
/* #if defined (CONFIG_CPU_S3C6400) || defined (CONFIG_CPU_S3C6410) static struct resource s3c_uart3_resource[] = { [0] = { .start = S3C2443_PA_UART3, .end = S3C2443_PA_UART3 + 0x3ff, .flags = IORESOURCE_MEM, }, [1] = { .start = IRQ_UART3, .end = IRQ_UART3, .flags = IORESOURCE_IRQ, } }; #endif ** change by bobee, 2012-03-8 */ static struct resource s3c2410_uart3_resource[] = { [0] = { .start = S3C2443_PA_UART3, .end = S3C2443_PA_UART3 + 0x3fff, .flags = IORESOURCE_MEM, }, [1] = { .start = IRQ_S3CUART_RX3, .end = IRQ_S3CUART_ERR3, .flags = IORESOURCE_IRQ, } };
<2>. 定位到157行附近,
#if defined (CONFIG_CPU_S3C6400) || defined (CONFIG_CPU_S3C6410) || defined (CONFIG_CPU_S3C2416)
[3] = {
.resources = s3c2410_uart3_resource,
.nr_resources = ARRAY_SIZE(s3c2410_uart3_resource),
},
#endif
<3>. 定位到179行附近,
#if defined (CONFIG_CPU_S3C6400) || defined (CONFIG_CPU_S3C6410) || defined (CONFIG_CPU_S3C2416)// add by bobee, 2011-03-08
static struct platform_device s3c24xx_uart_device3 = {
.id = 3,
};
#endif
<4>. 定位到189行附近,
#if defined (CONFIG_CPU_S3C6400) || defined (CONFIG_CPU_S3C6410) || defined (CONFIG_CPU_S3C2416) // add by bobee, 2011-03-08
&s3c24xx_uart_device3,
#endif
2.添加UART3的默认配置
打开kernel2416/arch/arm/mach-s3c2416/mach-smdk2416.c,定位到113行后,在结构体smdk2416_uartcfgs[] 中添加以下代码:
[cpp] view plain copy print ?
-
- [3] = {
- .hwport = 3,
- .flags = 0,
-
- .ucon = 0x3c5,
-
- .ulcon = 0x03,
- .ufcon = 0x51,
- .clocks = smdk2416_serial_clocks,
- .clocks_size = ARRAY_SIZE(smdk2416_serial_clocks),
- }
// add by bobee, 2012-03-08 [3] = { .hwport = 3, .flags = 0, /* Use PCLK */ .ucon = 0x3c5, //.ucon = 0xfc5, .ulcon = 0x03, .ufcon = 0x51, .clocks = smdk2416_serial_clocks, .clocks_size = ARRAY_SIZE(smdk2416_serial_clocks), }
3.更改s3c2416 的UART3 的中断相关函数
打开kernel2416/arch/arm/mach-s3c2416/irq.c,定位到181行后,更改如下:
[cpp] view plain copy print ?
- static void s3c2443_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
- {
-
- s3c2443_irq_demux(IRQ_S3C2443_RX3, 3);
- }
static void s3c2443_irq_demux_uart3(unsigned int irq, struct irq_desc *desc) { //s3c2443_irq_demux(IRQ_S3C2443_UART3, 3); s3c2443_irq_demux(IRQ_S3C2443_RX3, 3); // change by bobee, 2012-03-09 }
更改UART3的子串口中断掩码
//#define SUBMSK_UART3 (0xf << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
// change by bobee, 2012-03-09
#define SUBMSK_UART3 (0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
4.更改头文件regs-serial.h 中的相关定义
打开kernel2416/include/asm-arm/arch-s3c2410/irqs.h , 定位到153行后,添加如下定义
/* UART3 */
#define IRQ_S3C2443_RX3 S3C2410_IRQSUB(24)
#define IRQ_S3C2443_TX3 S3C2410_IRQSUB(25)
#define IRQ_S3C2443_ERR3 S3C2410_IRQSUB(26)
// add by bobee, 2012-03-08
#define IRQ_UART3 IRQ_S3C2443_UART3
#define IRQ_S3CUART_RX3 IRQ_S3C2443_RX3
#define IRQ_S3CUART_TX3 IRQ_S3C2443_TX3
#define IRQ_S3CUART_ERR3 IRQ_S3C2443_ERR3
更改串口数,定位到366行后,
#if defined (CONFIG_CPU_S3C6400) || defined (CONFIG_CPU_S3C6410)
#define NR_PORTS (4)
#define UART_FIFO_SIZE 64
#define UART_HAS_INTMSK
#define UART_C_CFLAG
#define UART_UMCON
#define UART_CLK 115200
#elif defined (CONFIG_CPU_S3C2416)
#define NR_PORTS (4) // change by bobee, 2012-03-08
#else
#define NR_PORTS (3)
#endif
5.修改串口驱动文件
打开/kernel2416/drivers/serial/s3c2410.c,
<1>. 定位到165行,更改串口个数
#ifdef CONFIG_CPU_S3C2400
#define NR_PORTS (2)
#else
#define NR_PORTS (4) // (3) // change by bobee, 2012-03-08
#endif
<2>. 定位到627行,在结构体 struct baud_calc 中添加如下变量
[cpp] view plain copy print ?
- struct baud_calc {
- struct s3c24xx_uart_clksrc *clksrc;
- unsigned int calc;
- unsigned int quot;
- unsigned int udivslot;
- struct clk *src;
- };
struct baud_calc { struct s3c24xx_uart_clksrc *clksrc; unsigned int calc; unsigned int quot; unsigned int udivslot; // add by bobee, 2012-03-07 struct clk *src; };
<3>. 添加 S3C2416 波特率 dividing slot register UDIVSLOTn 查询表:
(添加在上面struct baud_calc 结构体定义后)
// add by bobee, 2012-03-07
const unsigned int udivslot_table[16] = {0x0000, 0x0080, 0x0808, 0x0888, 0x2222, 0x4924, 0x4a52, 0x54aa,
0x5555, 0xd555, 0xd5d5, 0xddd5, 0xdddd, 0xdfdd, 0xdfdf, 0xffdf};
<4>. 定位到636行附近,更改波特率计算函数s3c24xx_serial_calcbaud,
更改如下:(更改后可以改善波特率 UBRDIVn设置值)
[cpp] view plain copy print ?
- static int s3c24xx_serial_calcbaud(struct baud_calc *calc,
- struct uart_port *port,
- struct s3c24xx_uart_clksrc *clksrc,
- unsigned int baud)
- {
- unsigned long rate;
-
- #if 1
- unsigned long tempdiv;
- unsigned int nslot, serial_result_1, serial_result_2;
-
-
- calc->src = clk_get(port->dev, clksrc->name);
- if (calc->src == NULL || IS_ERR(calc->src))
- return 0;
-
- baud/=100;
-
- rate = clk_get_rate(calc->src);
- rate /= clksrc->divisor;
-
- calc->clksrc = clksrc;
-
- tempdiv = (rate*10/(baud*16))-1000;
- serial_result_1 = ((tempdiv%1000)*16)/1000;
- serial_result_2 = (((tempdiv%1000)*16) - (serial_result_1*1000));
-
- if (serial_result_2 >=500)
- nslot = serial_result_1+1;
- else
- nslot = serial_result_1;
-
- calc->quot = tempdiv/1000;
- calc->calc = (rate / (calc->quot * 16));
- calc->udivslot = udivslot_table[nslot];
- printk(KERN_DEBUG "FOUND quot %d, calc %d, slot 0x%x, nslot %d\n",
- calc->quot, calc->calc ,
- calc->udivslot, nslot);
-
- #else
- calc->src = clk_get(port->dev, clksrc->name);
- if (calc->src == NULL || IS_ERR(calc->src))
- return 0;
-
- rate = clk_get_rate(calc->src);
- rate /= clksrc->divisor;
-
- calc->clksrc = clksrc;
- #if 0
-
- calc->quot = (rate + (8 * baud)) / (16 * baud);
- #else
-
- calc->quot = (rate) / (16 * baud);
- #endif
- calc->calc = (rate / (calc->quot * 16));
-
- calc->quot--;
-
- #endif
- return 1;
- }
static int s3c24xx_serial_calcbaud(struct baud_calc *calc, struct uart_port *port, struct s3c24xx_uart_clksrc *clksrc, unsigned int baud) { unsigned long rate; // change by bobee, 2012-06-07 #if 1 unsigned long tempdiv; unsigned int nslot, serial_result_1, serial_result_2; calc->src = clk_get(port->dev, clksrc->name); if (calc->src == NULL || IS_ERR(calc->src)) return 0; baud/=100; rate = clk_get_rate(calc->src); rate /= clksrc->divisor; calc->clksrc = clksrc; tempdiv = (rate*10/(baud*16))-1000; serial_result_1 = ((tempdiv%1000)*16)/1000; serial_result_2 = (((tempdiv%1000)*16) - (serial_result_1*1000)); if (serial_result_2 >=500) nslot = serial_result_1+1; else nslot = serial_result_1; calc->quot = tempdiv/1000; calc->calc = (rate / (calc->quot * 16)); calc->udivslot = udivslot_table[nslot]; printk(KERN_DEBUG "FOUND quot %d, calc %d, slot 0x%x, nslot %d\n", calc->quot, calc->calc , calc->udivslot, nslot); #else calc->src = clk_get(port->dev, clksrc->name); if (calc->src == NULL || IS_ERR(calc->src)) return 0; rate = clk_get_rate(calc->src); rate /= clksrc->divisor; calc->clksrc = clksrc; #if 0 /* Error to calculation of UART BAUD RATE DIVISOR */ calc->quot = (rate + (8 * baud)) / (16 * baud); #else /* Error correction */ calc->quot = (rate) / (16 * baud); #endif calc->calc = (rate / (calc->quot * 16)); calc->quot--; #endif return 1; }
<5>. 修改函数s3c24xx_serial_set_termios()
更改如下:(这里主要是 设置 寄存器UDIVSLOTn 的值,如果不设置此值,会导致波特率不准的问题)
[cpp] view plain copy print ?
- static void s3c24xx_serial_set_termios(struct uart_port *port,
- struct ktermios *termios,
- struct ktermios *old)
- {
- struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
- struct s3c24xx_uart_port *ourport = to_ourport(port);
- struct s3c24xx_uart_clksrc *clksrc = NULL;
- struct clk *clk = NULL;
- unsigned long flags;
- unsigned int baud, quot;
- unsigned int ulcon;
- unsigned int umcon;
- unsigned int udivslot = 0, div;
-
-
-
-
- termios->c_cflag &= ~(HUPCL | CMSPAR);
- termios->c_cflag |= CLOCAL;
-
-
-
-
-
- baud = uart_get_baud_rate(port, termios, old, 0, 115200*8);
-
- if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
- quot = port->custom_divisor;
- else
- quot = s3c24xx_serial_getclk(port, &clksrc, &clk, baud);
-
-
-
- if (ourport->clksrc != clksrc || ourport->baudclk != clk) {
- s3c24xx_serial_setsource(port, clksrc);
-
- if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) {
- clk_disable(ourport->baudclk);
- ourport->baudclk = NULL;
- }
-
- clk_enable(clk);
-
- ourport->clksrc = clksrc;
- ourport->baudclk = clk;
- }
-
- #if defined(CONFIG_CPU_S3C2416)
- div = clk_get_rate(clk) / baud;
- udivslot = udivslot_table[div & 15];
-
- #endif
- switch (termios->c_cflag & CSIZE) {
- case CS5:
- dbg("config: 5bits/char\n");
- ulcon = S3C2410_LCON_CS5;
- break;
- case CS6:
- dbg("config: 6bits/char\n");
- ulcon = S3C2410_LCON_CS6;
- break;
- case CS7:
- dbg("config: 7bits/char\n");
- ulcon = S3C2410_LCON_CS7;
- break;
- case CS8:
- default:
- dbg("config: 8bits/char\n");
- ulcon = S3C2410_LCON_CS8;
- break;
- }
-
-
- ulcon |= (cfg->ulcon & S3C2410_LCON_IRM);
-
- if (termios->c_cflag & CSTOPB)
- ulcon |= S3C2410_LCON_STOPB;
-
- umcon = (termios->c_cflag & CRTSCTS) ? S3C2410_UMCOM_AFC : 0;
-
- if (termios->c_cflag & PARENB) {
- if (termios->c_cflag & PARODD)
- ulcon |= S3C2410_LCON_PODD;
- else
- ulcon |= S3C2410_LCON_PEVEN;
- } else {
- ulcon |= S3C2410_LCON_PNONE;
- }
-
- spin_lock_irqsave(&port->lock, flags);
-
- dbg("setting ulcon to %08x, brddiv to %d\n", ulcon, quot);
-
- wr_regl(port, S3C2410_ULCON, ulcon);
- wr_regl(port, S3C2410_UBRDIV, quot);
- #if defined(CONFIG_CPU_S3C2416)
- wr_regl(port, S3C_UDIVSLOT, udivslot);
- #endif
- wr_regl(port, S3C2410_UMCON, umcon);
-
- dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n",
- rd_regl(port, S3C2410_ULCON),
- rd_regl(port, S3C2410_UCON),
- rd_regl(port, S3C2410_UFCON));
- #if defined(CONFIG_CPU_S3C2416)
- dbg("UDIVSLOT=0x%08x, UBRDIV=0x%08x\n",
- rd_regl(port, S3C2410_UBRDIV),
- rd_regl(port, S3C_UDIVSLOT));
- #endif
- dbg("baud=%d,clk=%ld \n", baud, clk_get_rate(clk));
-
-
-
-
-
- uart_update_timeout(port, termios->c_cflag, baud);
-
-
-
-
- port->read_status_mask = S3C2410_UERSTAT_OVERRUN;
- if (termios->c_iflag & INPCK)
- port->read_status_mask |= S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_PARITY;
-
-
-
-
- port->ignore_status_mask = 0;
- if (termios->c_iflag & IGNPAR)
- port->ignore_status_mask |= S3C2410_UERSTAT_OVERRUN;
- if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR)
- port->ignore_status_mask |= S3C2410_UERSTAT_FRAME;
-
-
-
-
- if ((termios->c_cflag & CREAD) == 0)
- port->ignore_status_mask |= RXSTAT_DUMMY_READ;
-
- spin_unlock_irqrestore(&port->lock, flags);
- }
static void s3c24xx_serial_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port); struct s3c24xx_uart_port *ourport = to_ourport(port); struct s3c24xx_uart_clksrc *clksrc = NULL; struct clk *clk = NULL; unsigned long flags; unsigned int baud, quot; unsigned int ulcon; unsigned int umcon; unsigned int udivslot = 0, div; // add by bobee, 2012-03-07 /* * We don't support modem control lines. */ termios->c_cflag &= ~(HUPCL | CMSPAR); termios->c_cflag |= CLOCAL; /* * Ask the core to calculate the divisor for us. */ baud = uart_get_baud_rate(port, termios, old, 0, 115200*8); if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) quot = port->custom_divisor; else quot = s3c24xx_serial_getclk(port, &clksrc, &clk, baud); /* check to see if we need to change clock source */ if (ourport->clksrc != clksrc || ourport->baudclk != clk) { s3c24xx_serial_setsource(port, clksrc); if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) { clk_disable(ourport->baudclk); ourport->baudclk = NULL; } clk_enable(clk); ourport->clksrc = clksrc; ourport->baudclk = clk; } // add by bobee, 2012-03-07 #if defined(CONFIG_CPU_S3C2416) div = clk_get_rate(clk) / baud; udivslot = udivslot_table[div & 15]; #endif switch (termios->c_cflag & CSIZE) { case CS5: dbg("config: 5bits/char\n"); ulcon = S3C2410_LCON_CS5; break; case CS6: dbg("config: 6bits/char\n"); ulcon = S3C2410_LCON_CS6; break; case CS7: dbg("config: 7bits/char\n"); ulcon = S3C2410_LCON_CS7; break; case CS8: default: dbg("config: 8bits/char\n"); ulcon = S3C2410_LCON_CS8; break; } /* preserve original lcon IR settings */ ulcon |= (cfg->ulcon & S3C2410_LCON_IRM); if (termios->c_cflag & CSTOPB) ulcon |= S3C2410_LCON_STOPB; umcon = (termios->c_cflag & CRTSCTS) ? S3C2410_UMCOM_AFC : 0; if (termios->c_cflag & PARENB) { if (termios->c_cflag & PARODD) ulcon |= S3C2410_LCON_PODD; else ulcon |= S3C2410_LCON_PEVEN; } else { ulcon |= S3C2410_LCON_PNONE; } spin_lock_irqsave(&port->lock, flags); dbg("setting ulcon to %08x, brddiv to %d\n", ulcon, quot); wr_regl(port, S3C2410_ULCON, ulcon); wr_regl(port, S3C2410_UBRDIV, quot); #if defined(CONFIG_CPU_S3C2416) wr_regl(port, S3C_UDIVSLOT, udivslot); // add by bobee, 2012-03-07 #endif wr_regl(port, S3C2410_UMCON, umcon); dbg("uart: ulcon = 0x%08x, ucon = 0x%08x, ufcon = 0x%08x\n", rd_regl(port, S3C2410_ULCON), rd_regl(port, S3C2410_UCON), rd_regl(port, S3C2410_UFCON)); #if defined(CONFIG_CPU_S3C2416) dbg("UDIVSLOT=0x%08x, UBRDIV=0x%08x\n", rd_regl(port, S3C2410_UBRDIV), rd_regl(port, S3C_UDIVSLOT)); #endif dbg("baud=%d,clk=%ld \n", baud, clk_get_rate(clk)); /* * Update the per-port timeout. */ uart_update_timeout(port, termios->c_cflag, baud); /* * Which character status flags are we interested in? */ port->read_status_mask = S3C2410_UERSTAT_OVERRUN; if (termios->c_iflag & INPCK) port->read_status_mask |= S3C2410_UERSTAT_FRAME | S3C2410_UERSTAT_PARITY; /* * Which character status flags should we ignore? */ port->ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) port->ignore_status_mask |= S3C2410_UERSTAT_OVERRUN; if (termios->c_iflag & IGNBRK && termios->c_iflag & IGNPAR) port->ignore_status_mask |= S3C2410_UERSTAT_FRAME; /* * Ignore all characters if CREAD is not set. */ if ((termios->c_cflag & CREAD) == 0) port->ignore_status_mask |= RXSTAT_DUMMY_READ; spin_unlock_irqrestore(&port->lock, flags); }
<6>. 修改结构体 s3c24xx_uart_drv
定位到1011行附近,修改如下:
[cpp] view plain copy print ?
- static struct uart_driver s3c24xx_uart_drv = {
- .owner = THIS_MODULE,
- .dev_name = "s3c2410_serial",
- .nr = NR_PORTS,
- .cons = S3C24XX_SERIAL_CONSOLE,
- .driver_name = S3C24XX_SERIAL_NAME,
- .major = S3C24XX_SERIAL_MAJOR,
- .minor = S3C24XX_SERIAL_MINOR,
- };
static struct uart_driver s3c24xx_uart_drv = { .owner = THIS_MODULE, .dev_name = "s3c2410_serial", .nr = NR_PORTS, //3, // change by bobee, 2012-03-07 .cons = S3C24XX_SERIAL_CONSOLE, .driver_name = S3C24XX_SERIAL_NAME, .major = S3C24XX_SERIAL_MAJOR, .minor = S3C24XX_SERIAL_MINOR, };
<7>. 在结构体 s3c24xx_serial_port[NR_PORT]中添加,uart3的设置
[cpp] view plain copy print ?
- #if defined (CONFIG_CPU_S3C2416) // add by bobee, 2011-03-07
- [3] = {
- .port = {
- .lock = SPIN_LOCK_UNLOCKED,
- .iotype = UPIO_MEM,
- .irq = IRQ_S3CUART_RX3,
- .uartclk = 0,
- .fifosize = 16,
- .ops = &s3c24xx_serial_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 3,
- }
- }
- #endif
#if defined (CONFIG_CPU_S3C2416) // add by bobee, 2011-03-07 [3] = { .port = { .lock = SPIN_LOCK_UNLOCKED, .iotype = UPIO_MEM, .irq = IRQ_S3CUART_RX3, .uartclk = 0, .fifosize = 16, .ops = &s3c24xx_serial_ops, .flags = UPF_BOOT_AUTOCONF, .line = 3, } } #endif
到此位置,已经成功添加串口 UART3,并修补了原来波特率不能设置9600 bug.