serial driver 1
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后就不输出了。
在samsung.c中实现console。
3.<*> Samsung S3C2440/S3C2442 Serial port support
普通串口 /dev/ttySAC*
obj-$(CONFIG_SERIAL_S3C2440) += s3c2440.o
1.串口的平台设备分散在mach-mini2440.c,arch/arm/plat-s3c/init.c等,在系统启动时注册.比如mach-mini2440.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.uboot里设置的 console=ttySAC0 ,决定了使用ttySAC0作控制台终端。
在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
1.串口的平台设备分散在mach-mini2440.c,arch/arm/plat-s3c/init.c等,在系统启动时注册.比如mach-mini2440.c
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,
    }
};比如init.cvoid __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,主要工作就是实现这些函数指针。
                    
                
                
            
        
浙公网安备 33010602011771号