ImageVerifierCode 换一换
格式:DOCX , 页数:43 ,大小:30.54KB ,
资源ID:15210273      下载积分:5 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bingdoc.com/d-15210273.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(linux设备驱动之8250串口驱动.docx)为本站会员(b****1)主动上传,冰点文库仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰点文库(发送邮件至service@bingdoc.com或直接QQ联系客服),我们立即给予删除!

linux设备驱动之8250串口驱动.docx

1、linux设备驱动之8250串口驱动linux设备驱动之8250串口驱动一:前言 前一段时间自己实践了一下8250芯片串口驱动的编写。今天就在此基础上分析一下linux kernel自带的串口驱动。毕竟只有对比专业的驱动代码才能更好的进步,同以往一样,基于linix kernel2.6.25.相应驱动代码位于:linux-2.6.25/drivers/serial/8250.c。 二:8250串口驱动初始化 相应的初始化函数为serial8250_init().代码如下: static int _init serial8250_init(void) int ret, i; if (nr_uar

2、ts UART_NR) nr_uarts = UART_NR; printk(KERN_INFO Serial: 8250/16550 driver $Revision: 1.90 $ %d ports, IRQ sharing %sabledn, nr_uarts, share_irqs ? en : dis); for (i = 0; i dev); ret = platform_driver_register(&serial8250_isa_driver); if (ret = 0) goto out; platform_device_del(serial8250_isa_devs);

3、put_dev: platform_device_put(serial8250_isa_devs); unreg_uart_drv: uart_unregister_driver(&serial8250_reg); out: return ret; 这段代码涉及到的知识要求,如platform ,uart等我们在之前都已经做过详细的分析。这里不再重复。在代码中UART_NR:表示串口的个数。这个参数在编译内核的时候可以自己配置,默认为32。 我们按照代码中的流程一步一步进行研究。 1:注册uart_driver. 对应uart-driver的结构为serial8250_reg.定义如下: st

4、atic struct uart_driver serial8250_reg = .owner = THIS_MODULE, .driver_name = serial, .dev_name = ttyS, .major = TTY_MAJOR, .minor = 64, .nr = UART_NR, .cons = SERIAL8250_CONSOLE, ; TTY_MAJOR定义如下: #define TTY_MAJOR 4 从上面可以看出。串口对应的设备节点为/dev/ ttyS0 /dev/ ttyS0(UART_NR).设备节点号为(4。64)起始的UART_NR个节点. 2:初始化

5、并注册platform_device 相关代码如下: serial8250_isa_devs = platform_device_alloc(serial8250, PAT8250_DEV_LEGACY); platform_device_add(serial8250_isa_devs); 可以看出。serial8250_isa_devs.-name为serial8250。这个参数是在匹配platform_device和platform_driver使用的. 3:为uart-driver添加port. 相关代码如下: serial8250_register_ports(&serial8250_

6、reg, &serial8250_isa_devs-dev) 跟进这个函数看一下: static void _init serial8250_register_ports(struct uart_driver *drv, struct device *dev) int i; serial8250_isa_init_ports(); for (i = 0; i port.dev = dev; uart_add_one_port(drv, &up-port); 在这里函数里,初始化了port.然后将挂添加到uart-driver中。我们还注意到。生成的deivce节点,在sysfs中是位于plat

7、form_deivce对应目录的下面. serial8250_isa_init_ports()代码如下所示: static void _init serial8250_isa_init_ports(void) struct uart_8250_port *up; static int first = 1; int i; if (!first) return; first = 0; for (i = 0; i port.line = i; spin_lock_init(&up-port.lock); init_timer(&up-timer); up-timer.function = seria

8、l8250_timeout; /* * ALPHA_KLUDGE_MCR needs to be killed. */ up-mcr_mask = ALPHA_KLUDGE_MCR; up-mcr_force = ALPHA_KLUDGE_MCR; up-port.ops = &serial8250_pops; for (i = 0, up = serial8250_ports; i ARRAY_SIZE(old_serial_port) & i port.iobase = old_serial_porti.port; up-port.irq = irq_canonicalize(old_se

9、rial_porti.irq); up-port.uartclk = old_serial_porti.baud_base * 16; up-port.flags = old_serial_porti.flags; up-port.hub6 = old_serial_porti.hub6; up-port.membase = old_serial_porti.iomem_base; up-port.iotype = old_serial_porti.io_type; up-port.regshift = old_serial_porti.iomem_reg_shift; if (share_i

10、rqs) up-port.flags |= UPF_SHARE_IRQ; 在这里,我们关注一下注要成员的初始化。Uart_port的各项操作位于serial8250_pops中.iobase irq等成员是从old_serial_por这个结构中得来的,这个结构如下所示: static const struct old_serial_port old_serial_port = SERIAL_PORT_DFNS /* defined in asm/serial.h */ #define SERIAL_PORT_DFNS /* UART CLK PORT IRQ FLAGS */ 0, BASE

11、_BAUD, 0x3F8, 4, STD_COM_FLAGS , /* ttyS0 */ 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS , /* ttyS1 */ 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS , /* ttyS2 */ 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS , /* ttyS3 */ 从上面看到。前两项对应了com1 com2的各项参数。如寄存器首始地址,Irq号等。后面两项不太清楚。 在上面的代码中,我们看到了uart_port各项成员的初始化。在后面很多操作中需要用到这个成

12、员。我们等分析相关部份的时候,再到这个地方来看相关成员的值。 4:注册platform_driver 相关代码如下: platform_driver_register(&serial8250_isa_driver); serial8250_isa_driver定义如下: static struct platform_driver serial8250_isa_driver = .probe = serial8250_probe, .remove = _devexit_p(serial8250_remove), .suspend = serial8250_suspend, .resume = s

13、erial8250_resume, .driver = .name = serial8250, .owner = THIS_MODULE, , 为了以后把分析集中到具体的驱动部份.我们先把这个platform_driver引会的事件讲述完. 经过前面有关platform的分析我们知道.这个platform的name为” serial8250”.刚好跟前面注册的platform_device相匹配.会调用platform_driver- probe.在这里,对应的接口为: serial8250_probe().代码如下: static int _devinit serial8250_probe(

14、struct platform_device *dev) struct plat_serial8250_port *p = dev-dev.platform_data; struct uart_port port; int ret, i; memset(&port, 0, sizeof(struct uart_port); for (i = 0; p & p-flags != 0; p+, i+) port.iobase = p-iobase; port.membase = p-membase; port.irq = p-irq; port.uartclk = p-uartclk; port.

15、regshift = p-regshift; port.iotype = p-iotype; port.flags = p-flags; port.mapbase = p-mapbase; port.hub6 = p-hub6; port.private_data = p-private_data; port.dev = &dev-dev; if (share_irqs) port.flags |= UPF_SHARE_IRQ; ret = serial8250_register_port(&port); if (ret dev, unable to register port at inde

16、x %d (IO%lx MEM%llx IRQ%d): %dn, i, p-iobase, (unsigned long long)p-mapbase, p-irq, ret); return 0; 从上述代码可以看出.会将dev-dev.platform_data所代表的port添加到uart_driver中.这个dev-dev.platform_data究竟代表什么.我们在看到的时候再来研究它. 现在,我们把精力集中到uart_port的操作上. 三:config_port过程 在初始化uart_port的过程中,在以下代码片段: serial8250_isa_init_ports(voi

17、d) for (i = 0, up = serial8250_ports; i ARRAY_SIZE(old_serial_port) & i port.iobase = old_serial_porti.port; up-port.irq = irq_canonicalize(old_serial_porti.irq); up-port.uartclk = old_serial_porti.baud_base * 16; up-port.flags = old_serial_porti.flags; up-port.hub6 = old_serial_porti.hub6; up-port.

18、membase = old_serial_porti.iomem_base; up-port.iotype = old_serial_porti.io_type; up-port.regshift = old_serial_porti.iomem_reg_shift; if (share_irqs) up-port.flags |= UPF_SHARE_IRQ; 而old_serial_port又定义如下: static const struct old_serial_port old_serial_port = SERIAL_PORT_DFNS /* defined in asm/seria

19、l.h */ ; #define SERIAL_PORT_DFNS /* UART CLK PORT IRQ FLAGS */ 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS , /* ttyS0 */ 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS , /* ttyS1 */ 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS , /* ttyS2 */ 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS , /* ttyS3 */ 由此可见.port-flags被定义成了STD_COM

20、_FLAGS,定义如下: #ifdef CONFIG_SERIAL_DETECT_IRQ #define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ) #define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_AUTO_IRQ) #else #define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) #define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF #en

21、dif 从这里看到,不管是否自己探测IRQ,都会定义ASYNC_BOOT_AUTOCONF.这样,在uart_add_one_port()的时候.就会进入到port-config_port来配置端口.在8250中,对应的接口为: serial8250_config_port().代码如下: static void serial8250_config_port(struct uart_port *port, int flags) struct uart_8250_port *up = (struct uart_8250_port *)port; int probeflags = PROBE_AN

22、Y; int ret; /* * Find the region that we can probe for. This in turn * tells us whether we can probe for the type of port. */ ret = serial8250_request_std_resource(up); if (ret 0) return; ret = serial8250_request_rsa_resource(up); if (ret port.type != PORT_UNKNOWN & flags & UART_CONFIG_IRQ) autoconf

23、ig_irq(up); if (up-port.type != PORT_RSA & probeflags & PROBE_RSA) serial8250_release_rsa_resource(up); if (up-port.type = PORT_UNKNOWN) serial8250_release_std_resource(up); serial8250_request_std_resource和serial8250_request_rsa_resource都是分配操作的端口.回顾在前面的分析中.port的相关参数会从old_serial_port中取得.而old_serial_p

24、ort中又没有定义port-iotype和port- regshift.也就是说对应这两项全为0.而 #define UPIO_PORT (0) 即表示是要操作I/O端口. 自己阅读这两个函数代表.会发现在serial8250_request_rsa_resource()中是会返回失败的. 另外,在uart_add_one_port()在进行端口匹配时,会先置flags为UART_CONFIG_TYPE. 这样,在本次操作中, if (flags & UART_CONFIG_TYPE)是会满足的.相应的就会进入autoconfig(). 代码如下,这段代码比较长,分段分析如下: static

25、void autoconfig(struct uart_8250_port *up, unsigned int probeflags) unsigned char status1, scratch, scratch2, scratch3; unsigned char save_lcr, save_mcr; unsigned long flags; if (!up-port.iobase & !up-port.mapbase & !up-port.membase) return; DEBUG_AUTOCONF(ttyS%d: autoconf (0x%04x, 0x%p): , up-port.

26、line, up-port.iobase, up-port.membase); /* * We really do need global IRQs disabled here - were going to * be frobbing the chips IRQ enable register to see if it exists. */ spin_lock_irqsave(&up-port.lock, flags); up-capabilities = 0; up-bugs = 0; if (!(up-port.flags & UPF_BUGGY_UART) /* * Do a simp

27、le existence test first; if we fail this, * theres no point trying anything else. * * 0x80 is used as a nonsense port to prevent against * false positives due to ISA bus float. The * assumption is that 0x80 is a non-existent port; * which should be safe since include/asm/io.h also * makes this assumption. * * Note: this is safe as long as MCR bit 4 is clear * and the device is in PC

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2