<pre name="code" class="cpp">/*** uart分析** 其实串口分析就两个重要的文件: S3c2440.c  Samsung.c** **//*1. 首先从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;
}/*参数是需要程序员自己定义 */
/** s3c2440.c **/static struct s3c24xx_uart_info s3c2440_uart_inf = {.name     = "Samsung S3C2440 UART",.type       = PORT_S3C2440,                //端口类型.fifosize = 64,                      //FIFO缓冲区大小.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,
};/*platform 驱动定义: s3c2440_serial_driver*/
static struct platform_driver s3c2440_serial_driver = {.probe      = s3c2440_serial_probe,                //匹配后设备调用.remove        = __devexit_p(s3c24xx_serial_remove),.driver       = {.name   = "s3c2440-uart",        //驱动的名字.owner   = THIS_MODULE,},
};/*分析uart_register_driver函数*/
/* 这个函数的主要作用是初始化tty_driver结构体。 其实tty_driver的主要成员都是通过传进来的参数drv赋值的* 其次是初始化uart_driver中的uart_state成员。* * uart_state是一个结构体包含了tty_port和uart_port。 而uart_port主要是和硬件相关。 其实每一个串口都对应一个uart_port结构* 这里只初始化了tty_port结构。而uart_port是在等设备匹配上后在设备的ops中的probe函数中初始化*/
int uart_register_driver(struct uart_driver *drv)
{/** Maybe we should be using a slab cache for this, especially if* we have a large number of ports to handle.*/drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);if (!drv->state)goto out;normal = alloc_tty_driver(drv->nr);if (!normal)goto out_kfree;drv->tty_driver = normal;normal->owner        = drv->owner;normal->driver_name = drv->driver_name;normal->name      = drv->dev_name;normal->major        = drv->major;normal->minor_start = drv->minor;normal->type        = TTY_DRIVER_TYPE_SERIAL;normal->subtype        = SERIAL_TYPE_NORMAL;normal->init_termios   = tty_std_termios;normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;normal->flags        = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;normal->driver_state    = drv;tty_set_operations(normal, &uart_ops);/** Initialise the UART state(s).*/for (i = 0; i < drv->nr; i++) {struct uart_state *state = drv->state + i;struct tty_port *port = &state->port;tty_port_init(port);port->ops = &uart_port_ops;port->close_delay     = 500;  /* .5 seconds */port->closing_wait    = 30000;  /* 30 seconds */tasklet_init(&state->tlet, uart_tasklet_action,(unsigned long)state);}retval = tty_register_driver(normal);
}/* 当设备与驱动匹配后,会调用此函数。**  probe函数一般就是做的硬件相关的初始化。*  *  其实uart_port的初始化也是通过s3c24xx_uart_port来初始化的。* */
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_port和uart_driver关联起来*/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;
}/** 端口初始化函数* */
static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,struct s3c24xx_uart_info *info,struct platform_device *platdev)
{struct uart_port *port = &ourport->port;struct s3c2410_uartcfg *cfg;struct resource *res;int ret;dbg("s3c24xx_serial_init_port: port=%p, platdev=%p\n", port, platdev);if (platdev == NULL)return -ENODEV;/*获取设备的资源,详细解析见下面*/cfg = s3c24xx_dev_to_cfg(&platdev->dev);if (port->mapbase != 0)return 0;/*判断是否大于总数4个*/if (cfg->hwport > CONFIG_SERIAL_SAMSUNG_UARTS) {printk(KERN_ERR "%s: port %d bigger than %d\n", __func__,cfg->hwport, CONFIG_SERIAL_SAMSUNG_UARTS);return -ERANGE;}port->dev = &platdev->dev;ourport->info    = info;/*初始化port的大小 = 64*/ourport->port.fifosize = info->fifosize;dbg("s3c24xx_serial_init_port: %p (hw %d)...\n", port, cfg->hwport);port->uartclk = 1;/*判断是否开启流控*/if (cfg->uart_flags & UPF_CONS_FLOW) {dbg("s3c24xx_serial_init_port: enabling flow control\n");port->flags |= UPF_CONS_FLOW;}/*获取uart资源*/res = platform_get_resource(platdev, IORESOURCE_MEM, 0);if (res == NULL) {printk(KERN_ERR "failed to find memory resource for uart\n");return -EINVAL;}dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);/*初始化基地址等*/port->mapbase = res->start;port->membase = S3C_VA_UART + (res->start & 0xfffff);ret = platform_get_irq(platdev, 0);if (ret < 0)port->irq = 0;else {port->irq = ret;ourport->rx_irq = ret;ourport->tx_irq = ret + 1;}ret = platform_get_irq(platdev, 1);if (ret > 0)ourport->tx_irq = ret;/*获取时钟*/ourport->clk  = clk_get(&platdev->dev, "uart");dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n",port->mapbase, port->membase, port->irq,ourport->rx_irq, ourport->tx_irq, port->uartclk);/* reset the fifos (and setup the uart) */s3c24xx_serial_resetport(port, cfg);return 0;
}#define s3c24xx_dev_to_cfg(__dev) (struct s3c2410_uartcfg *)((__dev)->platform_data)
/** cfg = s3c24xx_dev_to_cfg(&platdev->dev)* * 那么cfg到底是如何获得?** 搜索s3c2410_uartcfg得到:*/#define UCON S3C2410_UCON_DEFAULT | S3C2410_UCON_UCLK
#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODEstatic struct s3c2410_uartcfg smdk2440_uartcfgs[] __initdata = {[0] = {.hwport         = 0,.flags         = 0,.ucon      = 0x3c5,.ulcon         = 0x03,.ufcon      = 0x51,},[1] = {.hwport       = 1,.flags         = 0,.ucon      = 0x3c5,.ulcon         = 0x03,.ufcon      = 0x51,},[2] = {.hwport       = 2,.flags         = 0,.ucon      = 0x3c5,.ulcon         = 0x43,.ufcon      = 0x51,}};void __init s3c24xx_init_uarts(struct s3c2410_uartcfg *cfg, int no)
{if (cpu == NULL)return;if (cpu->init_uarts == NULL) {printk(KERN_ERR "s3c24xx_init_uarts: cpu has no uart init\n");} else(cpu->init_uarts)(cfg, no);
}/*初始化系统上的串口资源*/
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;/*从这里获取platform*/platdev->dev.platform_data = cfgptr;}nr_uarts = no;
}/*uart 所对应的资源 platform_get_resourced调用**/
/* Serial port registrations */static struct resource s3c2410_uart0_resource[] = {[0] = {.start = S3C2410_PA_UART0,.end   = S3C2410_PA_UART0 + 0x3fff,.flags = IORESOURCE_MEM,},[1] = {.start = IRQ_S3CUART_RX0,.end   = IRQ_S3CUART_ERR0,.flags = IORESOURCE_IRQ,}
};static struct resource s3c2410_uart1_resource[] = {[0] = {.start = S3C2410_PA_UART1,.end   = S3C2410_PA_UART1 + 0x3fff,.flags = IORESOURCE_MEM,},[1] = {.start = IRQ_S3CUART_RX1,.end   = IRQ_S3CUART_ERR1,.flags = IORESOURCE_IRQ,}
};static struct resource s3c2410_uart2_resource[] = {[0] = {.start = S3C2410_PA_UART2,.end   = S3C2410_PA_UART2 + 0x3fff,.flags = IORESOURCE_MEM,},[1] = {.start = IRQ_S3CUART_RX2,.end   = IRQ_S3CUART_ERR2,.flags = IORESOURCE_IRQ,}
};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,},
};struct s3c24xx_uart_resources s3c2410_uart_resources[] __initdata = {[0] = {.resources  = s3c2410_uart0_resource,.nr_resources = ARRAY_SIZE(s3c2410_uart0_resource),},[1] = {.resources  = s3c2410_uart1_resource,.nr_resources = ARRAY_SIZE(s3c2410_uart1_resource),},[2] = {.resources  = s3c2410_uart2_resource,.nr_resources = ARRAY_SIZE(s3c2410_uart2_resource),},[3] = {.resources  = s3c2410_uart3_resource,.nr_resources = ARRAY_SIZE(s3c2410_uart3_resource),},
};总结: 修改驱动需要设计的数据结构1. uart_driver:用于初始化tty_driver
2. s3c24xx_uart_port: 用于初始化uart_port
3. s3c24xx_serial_ops: 硬件的操作集
4. s3c24xx_uart_info: 用于初始化uart_port其实也就是:编写S3c2440.c这个串口文件。

Linux串口驱动分析初始化相关推荐

  1. linux串口驱动分析

    linux串口驱动分析 硬件资源及描写叙述 s3c2440A 通用异步接收器和发送器(UART)提供了三个独立的异步串行 I/O(SIO)port,每一个port都能够在中断模式或 DMA 模式下操作 ...

  2. linux串口驱动分析【转】

    转自:http://blog.csdn.net/hanmengaidudu/article/details/11946591 硬件资源及描述 s3c2440A 通用异步接收器和发送器(UART)提供了 ...

  3. linux串口发送数据程序,linux串口驱动分析——发送数据

    一.应用程序中write函数到底层驱动历程 和前文提到的一样,首先先注册串口,使用uart_register_driver函数,依次分别为tty_register_driver,cdev_init函数 ...

  4. LINUX串口驱动分析——发送数据

    https://www.cnblogs.com/51qianrushi/p/4324845.html

  5. GPS NMEA 0183 4.10协议/GPS Linux串口驱动

      NMEA 0183是美国国家海洋电子协会(National Marine Electronics Association)为海用电子设备制定的标准格式.现在已经成为GPS导航设备统一的RTCM(R ...

  6. Linux UART驱动分析及测试

    1.Linux TTY驱动程序框架 Linux TTY驱动程序代码位于/drivers/tty下面.TTY的层次接口包括TTY应用层.TTY文件层.TTY线路规程层.TTY驱动层.TTY设备驱动层.T ...

  7. Linux串口驱动(2) - 线路规程

    1. 注册tty的ldisc ldisc全称 line discipline(线路规程),因为历史原因,tty属于一类设备,而串口设备只是其中一种,所以该模块负责将用户操作桥接到不同的tty驱动.从代 ...

  8. Linux串口驱动(3) - open详解

    1. 用户空间open的操作实现 串口设备是被注册为字符设备的,在注册过程中填充了struct file_operations tty_fops结构体,该结构体中的成员open.read.write等 ...

  9. wince串口驱动分析(转)

    wince串口驱动分析 串行通讯接口主要是指UART(通用串行)和IRDA两种.通常的串行连接电气连接上有3wire和9wire两种.3wire的接线方式下定义了发送.接收和地三根连接.其用途就如名称 ...

  10. Linux spi驱动分析(四)----SPI设备驱动(W25Q32BV)

    一.W25Q32BV芯片简介 W25X是一系列SPI接口Flash芯片的简称,它采用SPI接口和CPU通信,本文使用的W25Q32BV容量为32M,具体特性如下: 1.1.基本特性 该芯片最大支持10 ...

最新文章

  1. 面向对象 - 继承性
  2. 【STM32】FreeRTOS 移植到 STM32F103
  3. Xcode6.3 怎样使用Leaks查看内存泄露
  4. openstack vlan配置_为OpenStack和K8s集群提供无缝虚拟网络
  5. mysql查看执行计划_MySql中如何使用 explain 查询 SQL 的执行计划
  6. openssl java aes_请问如何使用AES对使用OpenSSL命令加密的Java文件进行解密?
  7. 算法复习第五章贪心法
  8. 20169210 2016-2017-2《网络攻防实践》第五周作业
  9. 第3次作业:阅读《构建之法》1-5章
  10. 最好用的十六进制编辑器010 Editor
  11. linux下文本去重
  12. 重装服务器系统鼠标键盘用不了,win7重装系统后鼠标键盘不能用怎么办
  13. Windows下Perl环境安装和使用
  14. Python运算(四)random模块secrets模块
  15. Drone 自定义 UI
  16. 视频压缩【亲测可用】
  17. 蓝牙4.0BLE中协议栈详解
  18. 【专业知识问答】问:什么叫突然短路?为什么突然短路时会产生很大短路电流?
  19. 【号外20191127】微软刚刚更新了snipping tool
  20. 细菌觅食算法(Bacterial Foraging Optimization)

热门文章

  1. 在Linux环境下安装MYSQL
  2. vue项目下,webpack.js/package.json配置
  3. 静态修饰词static以及图解分析
  4. 解决windows下的mysql匿名登陆无法使用mysql数据库的问题
  5. SQL 2005 带自增列 带外键约束 数据导入导出
  6. 深度学习基础系列(六)| 权重初始化的选择
  7. 关于虚拟机virtualbox使用无线卡上网的设置
  8. 轻松搞定RabbitMQ(四)——发布/订阅
  9. R6300V2 从 DD-WRT 回刷恢复 官方原厂固件   DD-WRT to R6300V2
  10. 环境配置就是安装软件,修改软件的配置文件,安装软件就是文件的复制,与新增--linux下一切皆文件...