make menuconfig:

1.Device Drivers ---> Character devices ---> Serial drivers ---> <*> Samsung Soc Serial support
obj-$(CONFIG_SERIAL_CORE) += serial_core.o 是串口核心
obj-$(CONFIG_SERIAL_SAMSUNG) += samsung.o 是串口具体实现
2.控制台终端
计算机显示器通常被称为控制台终端(console)。必须有一个(些)特殊文件与console相关联,比如虚拟终端tty1 tty2 串口ttySAC0 ttySAC1等。系统所发出的信息会发送到console对应的文件上。
如果不选此项,在启动kernel后就不输出了。
uboot里设置的 console=ttySAC0 ,决定了使用ttySAC0作控制台终端。
在samsung.c中实现console。
3. <*> Samsung S3C2440/S3C2442 Serial port support
普通串口 /dev/ttySAC*
obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o
比如
init.c
void __init s3c24xx_init_uartdevs(char *name,
struct s3c24xx_uart_resources *res,
struct s3c2410_uartcfg *cfg, int no)
{
struct platform_device *platdev;
struct s3c2410_uartcfg *cfgptr = uart_cfgs;
struct s3c24xx_uart_resources *resp;
int uart;
memcpy(cfgptr, cfg, sizeof(struct s3c2410_uartcfg) * no);
for (uart = 0; uart < no; uart++, cfg++, cfgptr++) {
platdev = s3c24xx_uart_src[cfgptr->hwport];
resp = res + cfgptr->hwport;
s3c24xx_uart_devs[uart] = platdev;
platdev->name = name;
platdev->resource = resp->resources;
platdev->num_resources = resp->nr_resources;
platdev->dev.platform_data = cfgptr;
}
nr_uarts = no;
}
2.串口的平台驱动在
arch/arm/mach-s3c2440/s3c2440.c和samsung.c
初始化:
s3c2440.c初始化时注册了平台驱动
samsung.c在初始化时就注册了串口驱动
看一下平台驱动的probe,可知是在probe函数里面添加串口
s3c2440.c
几个重要的结构体
在probe中(s3c24xx_serial_probe(),samsung.c)用uart_add_one_port()将uart_port加入uart_driver
每一uart_port对应一个uart_ops,主要工作就是实现这些函数指针。

1.Device Drivers ---> Character devices ---> Serial drivers ---> <*> Samsung Soc Serial support
obj-$(CONFIG_SERIAL_CORE) += serial_core.o 是串口核心
obj-$(CONFIG_SERIAL_SAMSUNG) += samsung.o 是串口具体实现
2.控制台终端
计算机显示器通常被称为控制台终端(console)。必须有一个(些)特殊文件与console相关联,比如虚拟终端tty1 tty2 串口ttySAC0 ttySAC1等。系统所发出的信息会发送到console对应的文件上。
如果不选此项,在启动kernel后就不输出了。
- Starting kernel ...
- Uncompressing Linux......................................................................................................................................
- ................... done, booting the kernel.
在samsung.c中实现console。
- /* s3c24xx_serial_initconsole
- *
- * initialise the console from one of the uart drivers
- */
- static struct console s3c24xx_serial_console = {
- .name = S3C24XX_SERIAL_NAME,
- .device = uart_console_device,
- .flags = CON_PRINTBUFFER,
- .index = -1,
- .write = s3c24xx_serial_console_write,
- .setup = s3c24xx_serial_console_setup
- };
- int s3c24xx_serial_initconsole(struct platform_driver *drv,
- struct s3c24xx_uart_info *info)
- {
- struct platform_device *dev = s3c24xx_uart_devs[0];
- dbg("s3c24xx_serial_initconsole\n");
- /* select driver based on the cpu */
- if (dev == NULL) {
- printk(KERN_ERR "s3c24xx: no devices for console init\n");
- return 0;
- }
- if (strcmp(dev->name, drv->driver.name) != 0)
- return 0;
- s3c24xx_serial_console.data = &s3c24xx_uart_drv;
- s3c24xx_serial_init_ports(info);
- register_console(&s3c24xx_serial_console);
- return 0;
- }
3. <*> Samsung S3C2440/S3C2442 Serial port support
普通串口 /dev/ttySAC*
obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o
- </pre><span style="font-family:SimSun;">1.串口的平台设备分散在mach-mini2440.c,arch/arm/plat-s3c/init.c等,在系统启动时注册。比如<span style="font-family:SimSun;">mach-mini2440.c</span></span><pre name="code" class="cpp">static struct s3c2410_uartcfg mini2440_uartcfgs[] __initdata = {
- [0] = {//串口0
- .hwport = 0,
- .flags = 0,
- .ucon = 0x3c5,
- .ulcon = 0x03,
- .ufcon = 0x51,
- },
- [1] = {//串口1
- .hwport = 1,
- .flags = 0,
- .ucon = 0x3c5,
- .ulcon = 0x03,
- .ufcon = 0x51,
- },
- [2] = {//串口2
- .hwport = 2,
- .flags = 0,
- .ucon = 0x3c5,
- .ulcon = 0x03,
- .ufcon = 0x51,
- }
- };
void __init s3c24xx_init_uartdevs(char *name,
struct s3c24xx_uart_resources *res,
struct s3c2410_uartcfg *cfg, int no)
{
struct platform_device *platdev;
struct s3c2410_uartcfg *cfgptr = uart_cfgs;
struct s3c24xx_uart_resources *resp;
int uart;
memcpy(cfgptr, cfg, sizeof(struct s3c2410_uartcfg) * no);
for (uart = 0; uart < no; uart++, cfg++, cfgptr++) {
platdev = s3c24xx_uart_src[cfgptr->hwport];
resp = res + cfgptr->hwport;
s3c24xx_uart_devs[uart] = platdev;
platdev->name = name;
platdev->resource = resp->resources;
platdev->num_resources = resp->nr_resources;
platdev->dev.platform_data = cfgptr;
}
nr_uarts = no;
}
2.串口的平台驱动在
arch/arm/mach-s3c2440/s3c2440.c和samsung.c
初始化:
s3c2440.c初始化时注册了平台驱动
- static int __init s3c2440_serial_init(void)
- {
- return s3c24xx_serial_init(&s3c2440_serial_driver, &s3c2440_uart_inf);//见下面
- }
- static void __exit s3c2440_serial_exit(void)
- {
- platform_driver_unregister(&s3c2440_serial_driver);
- }
- module_init(s3c2440_serial_init);
- module_exit(s3c2440_serial_exit);
- //samsung.c
- int s3c24xx_serial_init(struct platform_driver *drv,
- struct s3c24xx_uart_info *info)
- {
- dbg("s3c24xx_serial_init(%p,%p)\n", drv, info);
- #ifdef CONFIG_PM
- drv->suspend = s3c24xx_serial_suspend;
- drv->resume = s3c24xx_serial_resume;
- #endif
- return platform_driver_register(drv);
- }
samsung.c在初始化时就注册了串口驱动
- static int __init s3c24xx_serial_modinit(void)
- {
- int ret;
- ret = uart_register_driver(&s3c24xx_uart_drv);
- if (ret < 0) {
- printk(KERN_ERR "failed to register UART driver\n");
- return -1;
- }
- return 0;
- }
- static void __exit s3c24xx_serial_modexit(void)
- {
- uart_unregister_driver(&s3c24xx_uart_drv);
- }
- module_init(s3c24xx_serial_modinit);
- module_exit(s3c24xx_serial_modexit);
看一下平台驱动的probe,可知是在probe函数里面添加串口
s3c2440.c
- static struct s3c24xx_uart_info s3c2440_uart_inf = {
- .name = "Samsung S3C2440 UART",
- .type = PORT_S3C2440,
- .fifosize = 64,
- .rx_fifomask = S3C2440_UFSTAT_RXMASK,
- .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT,
- .rx_fifofull = S3C2440_UFSTAT_RXFULL,
- .tx_fifofull = S3C2440_UFSTAT_TXFULL,
- .tx_fifomask = S3C2440_UFSTAT_TXMASK,
- .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT,
- .get_clksrc = s3c2440_serial_getsource,
- .set_clksrc = s3c2440_serial_setsource,
- .reset_port = s3c2440_serial_resetport,
- };
- /* device management */
- static int s3c2440_serial_probe(struct platform_device *dev)
- {
- dbg("s3c2440_serial_probe: dev=%p\n", dev);
- return s3c24xx_serial_probe(dev, &s3c2440_uart_inf);//见下面
- }
- //samsung.c
- static int probe_index;
- int s3c24xx_serial_probe(struct platform_device *dev,
- struct s3c24xx_uart_info *info)
- {
- struct s3c24xx_uart_port *ourport;
- int ret;
- dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index);
- ourport = &s3c24xx_serial_ports[probe_index];
- probe_index++;
- dbg("%s: initialising port %p...\n", __func__, ourport);
- ret = s3c24xx_serial_init_port(ourport, info, dev);
- if (ret < 0)
- goto probe_err;
- dbg("%s: adding port\n", __func__);
- uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
- platform_set_drvdata(dev, &ourport->port);
- ret = device_create_file(&dev->dev, &dev_attr_clock_source);
- if (ret < 0)
- printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__);
- ret = s3c24xx_serial_cpufreq_register(ourport);
- if (ret < 0)
- dev_err(&dev->dev, "failed to add cpufreq notifier\n");
- return 0;
- probe_err:
- return ret;
- }
几个重要的结构体
- //uart_ops
- static struct uart_ops s3c24xx_serial_ops = {
- .pm = s3c24xx_serial_pm,
- .tx_empty = s3c24xx_serial_tx_empty,
- .get_mctrl = s3c24xx_serial_get_mctrl,
- .set_mctrl = s3c24xx_serial_set_mctrl,
- .stop_tx = s3c24xx_serial_stop_tx,
- .start_tx = s3c24xx_serial_start_tx,
- .stop_rx = s3c24xx_serial_stop_rx,
- .enable_ms = s3c24xx_serial_enable_ms,
- .break_ctl = s3c24xx_serial_break_ctl,
- .startup = s3c24xx_serial_startup,
- .shutdown = s3c24xx_serial_shutdown,
- .set_termios = s3c24xx_serial_set_termios,
- .type = s3c24xx_serial_type,
- .release_port = s3c24xx_serial_release_port,
- .request_port = s3c24xx_serial_request_port,
- .config_port = s3c24xx_serial_config_port,
- .verify_port = s3c24xx_serial_verify_port,
- };
- //uart_driver
- static struct uart_driver s3c24xx_uart_drv = {
- .owner = THIS_MODULE,
- .dev_name = "s3c2410_serial",
- .nr = CONFIG_SERIAL_SAMSUNG_UARTS,
- .cons = S3C24XX_SERIAL_CONSOLE,
- .driver_name = S3C24XX_SERIAL_NAME,
- .major = S3C24XX_SERIAL_MAJOR,
- .minor = S3C24XX_SERIAL_MINOR,
- };
- //s3c24xx_uart_port
- static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
- [0] = {
- .port = {
- .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
- .iotype = UPIO_MEM,
- .irq = IRQ_S3CUART_RX0,
- .uartclk = 0,
- .fifosize = 16,
- .ops = &s3c24xx_serial_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- }
- },
- [1] = {
- .port = {
- .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock),
- .iotype = UPIO_MEM,
- .irq = IRQ_S3CUART_RX1,
- .uartclk = 0,
- .fifosize = 16,
- .ops = &s3c24xx_serial_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 1,
- }
- },
- #if CONFIG_SERIAL_SAMSUNG_UARTS > 2
- [2] = {
- .port = {
- .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock),
- .iotype = UPIO_MEM,
- .irq = IRQ_S3CUART_RX2,
- .uartclk = 0,
- .fifosize = 16,
- .ops = &s3c24xx_serial_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 2,
- }
- },
- #endif
- #if CONFIG_SERIAL_SAMSUNG_UARTS > 3
- [3] = {
- .port = {
- .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock),
- .iotype = UPIO_MEM,
- .irq = IRQ_S3CUART_RX3,
- .uartclk = 0,
- .fifosize = 16,
- .ops = &s3c24xx_serial_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 3,
- }
- }
- #endif
- };
- //serial_core.h
- struct uart_port {
- spinlock_t lock; /* port lock */
- unsigned long iobase; /* in/out[bwl] */
- unsigned char __iomem *membase; /* read/write[bwl] */
- unsigned int (*serial_in)(struct uart_port *, int);
- void (*serial_out)(struct uart_port *, int, int);
- unsigned int irq; /* irq number */
- unsigned long irqflags; /* irq flags */
- unsigned int uartclk; /* base uart clock */
- unsigned int fifosize; /* tx fifo size */
- unsigned char x_char; /* xon/xoff char */
- unsigned char regshift; /* reg offset shift */
- unsigned char iotype; /* io access style */
- unsigned char unused1;
- #define UPIO_PORT (0)
- #define UPIO_HUB6 (1)
- #define UPIO_MEM (2)
- #define UPIO_MEM32 (3)
- #define UPIO_AU (4) /* Au1x00 type IO */
- #define UPIO_TSI (5) /* Tsi108/109 type IO */
- #define UPIO_DWAPB (6) /* DesignWare APB UART */
- #define UPIO_RM9000 (7) /* RM9000 type IO */
- unsigned int read_status_mask; /* driver specific */
- unsigned int ignore_status_mask; /* driver specific */
- struct uart_state *state; /* pointer to parent state */
- struct uart_icount icount; /* statistics */
- struct console *cons; /* struct console, if any */
- #if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ)
- unsigned long sysrq; /* sysrq timeout */
- #endif
- upf_t flags;
- #define UPF_FOURPORT ((__force upf_t) (1 << 1))
- #define UPF_SAK ((__force upf_t) (1 << 2))
- #define UPF_SPD_MASK ((__force upf_t) (0x1030))
- #define UPF_SPD_HI ((__force upf_t) (0x0010))
- #define UPF_SPD_VHI ((__force upf_t) (0x0020))
- #define UPF_SPD_CUST ((__force upf_t) (0x0030))
- #define UPF_SPD_SHI ((__force upf_t) (0x1000))
- #define UPF_SPD_WARP ((__force upf_t) (0x1010))
- #define UPF_SKIP_TEST ((__force upf_t) (1 << 6))
- #define UPF_AUTO_IRQ ((__force upf_t) (1 << 7))
- #define UPF_HARDPPS_CD ((__force upf_t) (1 << 11))
- #define UPF_LOW_LATENCY ((__force upf_t) (1 << 13))
- #define UPF_BUGGY_UART ((__force upf_t) (1 << 14))
- #define UPF_NO_TXEN_TEST ((__force upf_t) (1 << 15))
- #define UPF_MAGIC_MULTIPLIER ((__force upf_t) (1 << 16))
- #define UPF_CONS_FLOW ((__force upf_t) (1 << 23))
- #define UPF_SHARE_IRQ ((__force upf_t) (1 << 24))
- /* The exact UART type is known and should not be probed. */
- #define UPF_FIXED_TYPE ((__force upf_t) (1 << 27))
- #define UPF_BOOT_AUTOCONF ((__force upf_t) (1 << 28))
- #define UPF_FIXED_PORT ((__force upf_t) (1 << 29))
- #define UPF_DEAD ((__force upf_t) (1 << 30))
- #define UPF_IOREMAP ((__force upf_t) (1 << 31))
- #define UPF_CHANGE_MASK ((__force upf_t) (0x17fff))
- #define UPF_USR_MASK ((__force upf_t) (UPF_SPD_MASK|UPF_LOW_LATENCY))
- unsigned int mctrl; /* current modem ctrl settings */
- unsigned int timeout; /* character-based timeout */
- unsigned int type; /* port type */
- const struct uart_ops *ops;
- unsigned int custom_divisor;
- unsigned int line; /* port index */
- resource_size_t mapbase; /* for ioremap */
- struct device *dev; /* parent device */
- unsigned char hub6; /* this should be in the 8250 driver */
- unsigned char suspended;
- unsigned char unused[2];
- void *private_data; /* generic platform data pointer */
- };
在probe中(s3c24xx_serial_probe(),samsung.c)用uart_add_one_port()将uart_port加入uart_driver
每一uart_port对应一个uart_ops,主要工作就是实现这些函数指针。