s3c6410的UART设备驱动(4)

本文详细解析了在Linux内核环境下UART驱动的注册与卸载过程,包括关键函数uart_register_driver和uart_unregister_driver的使用场景及实现原理,并介绍了三星S3C24XX和S3C6400系列处理器UART驱动的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上两篇说了在模块初始化是调用uart_register_driver和uart_add_one_port注册UART驱动并添加端口,在模块卸载时调用uart_unregister_driver和uart_remove_one_port以注销UART驱动并移除端口,主要讲述的是这些函数的具体代码,但没说这些函数在何处被调用,这一篇讲述这些函数的调用。

1、在Samsung.c (linux2.6.28\drivers\serial)文件中,有如下代码:

module_init(s3c24xx_serial_modinit);
module_exit(s3c24xx_serial_modexit);

看到这两个,应该知道了此模块调用的函数,和卸载时的函数。列出其源码:

/* module initialisation code */
static int __init s3c24xx_serial_modinit(void)
{
int ret;
ret = uart_register_driver(&s3c24xx_uart_drv);在上一篇中讲的有,可以去查看。

其中它的参数为

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,
};

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);
}

/**
 * uart_unregister_driver - remove a driver from the uart core layer
 * @drv: low level driver structure
 */
void uart_unregister_driver(struct uart_driver *drv)
{
struct tty_driver *p = drv->tty_driver;
tty_unregister_driver(p);
put_tty_driver(p);//减小引用数,为0是释放p
kfree(drv->state);
drv->tty_driver = NULL;
}

2、板级相关在S3c6400.c (linux2.6.28\drivers\serial)文件中有如下:

module_init(s3c6400_serial_init);
module_exit(s3c6400_serial_exit);

和上面一样列出其源码:

static int __init s3c6400_serial_init(void)
{
return s3c24xx_serial_init(&s3c6400_serial_drv, &s3c6400_uart_inf);
}

调用s3c24xx_serial_init函数,传入的参数为

static struct platform_driver s3c6400_serial_drv = {
.probe  = s3c6400_serial_probe,
.remove  = s3c24xx_serial_remove,
.driver  = {
.name = "s3c6400-uart",
.owner  = THIS_MODULE,
},
};

static struct s3c24xx_uart_info s3c6400_uart_inf = {
.name = "Samsung S3C6400 UART",
.type = PORT_S3C6400,
.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  = s3c6400_serial_getsource,
.set_clksrc  = s3c6400_serial_setsource,
.reset_port  = s3c6400_serial_resetport,
};这个结构体的原型在Samsung.h (linux2.6.28\drivers\serial)文件中,如下所示:

struct s3c24xx_uart_info {
char *name;
unsigned int  type;
unsigned int  fifosize;
unsigned long  rx_fifomask;
unsigned long  rx_fifoshift;
unsigned long  rx_fifofull;
unsigned long  tx_fifomask;
unsigned long  tx_fifoshift;
unsigned long  tx_fifofull;

/* clock source control */

int (*get_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk);
int (*set_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk);

/* uart controls */
int (*reset_port)(struct uart_port *, struct s3c2410_uartcfg *);
};

ints3c24xx_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);
}

platform_driver_register这个函数才是重点,因为uart是作为一种平台设备存在的。大家都知道,会调用其

static struct platform_driver s3c6400_serial_drv = {
.probe= s3c6400_serial_probe

结构体中的probe函数,源码如下:

static int s3c6400_serial_probe(struct platform_device *dev)
{
dbg("s3c6400_serial_probe: dev=%p\n", dev);
return s3c24xx_serial_probe(dev, &s3c6400_uart_inf);//该函数里调用uart_add_one_port
}

因为这个函数实在太长,所以放在下一篇中在说。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值