Chinaunix首页 | 论坛 | 博客
  • 博客访问: 498899
  • 博文数量: 223
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2145
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-01 10:23
个人简介

该坚持的时候坚持,该妥协的时候妥协,该放弃的时候放弃

文章分类

全部博文(223)

文章存档

2017年(56)

2016年(118)

2015年(3)

2014年(46)

我的朋友

分类: 嵌入式

2016-11-16 21:54:30

一、串口驱动程序结构
用户程序通过调用open /dev/... 来实现对串口的打开,其中要通过tty子系统对串口驱动xx_operations的open操作。
samsun.c>>moudle_init(s3c24xx_serial_modinit);>>uart_register_driver(&s3c24xx_uart_drv);
  1. int uart_register_driver(struct uart_driver *drv)
  2. {
  3.     .....

  4.     retval = tty_register_driver(normal);
  5.  out:
  6.     if (retval < 0) {
  7.         put_tty_driver(normal);
  8.         kfree(drv->state);
  9.     }
  10.     return retval;
  11. }
tty_register_driver(normal);
  1. /*
  2.  * Called by a tty driver to register itself.
  3.  */
  4. int tty_register_driver(struct tty_driver *driver)
  5. {
  6.     int error;
  7.     int i;
  8.     dev_t dev;
  9.     void **p = NULL;

  10.     if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
  11.         p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
  12.         if (!p)
  13.             return -ENOMEM;
  14.     }

  15.     if (!driver->major) {
  16.         error = alloc_chrdev_region(&dev, driver->minor_start,
  17.                         driver->num, driver->name);
  18.         if (!error) {
  19.             driver->major = MAJOR(dev);
  20.             driver->minor_start = MINOR(dev);
  21.         }
  22.     } else {
  23.         dev = MKDEV(driver->major, driver->minor_start);
  24.         error = register_chrdev_region(dev, driver->num, driver->name);
  25.     }
  26.     if (error < 0) {
  27.         kfree(p);
  28.         return error;
  29.     }

  30.     if (p) {
  31.         driver->ttys = (struct tty_struct **)p;
  32.         driver->termios = (struct ktermios **)(p + driver->num);
  33.     } else {
  34.         driver->ttys = NULL;
  35.         driver->termios = NULL;
  36.     }

  37.     cdev_init(&driver->cdev, &tty_fops);                                   //这里的注册其实就是注册字符设备
  38.     driver->cdev.owner = driver->owner;
  39.     error = cdev_add(&driver->cdev, dev, driver->num);
  40.     if (error) {
  41.         unregister_chrdev_region(dev, driver->num);
  42.         driver->ttys = NULL;
  43.         driver->termios = NULL;
  44.         kfree(p);
  45.         return error;
  46.     }

  47.     mutex_lock(&tty_mutex);
  48.     list_add(&driver->tty_drivers, &tty_drivers);
  49.     mutex_unlock(&tty_mutex);

  50.     if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) {
  51.         for (i = 0; i < driver->num; i++)
  52.          tty_register_device(driver, i, NULL);
  53.     }
  54.     proc_tty_register_driver(driver);
  55.     driver->flags |= TTY_DRIVER_INSTALLED;
  56.     return 0;
  57. }
第一个入口已找到,tty_fops->tty_open:
  1. static const struct file_operations tty_fops = {
  2.     .llseek        = no_llseek,
  3.     .read        = tty_read,
  4.     .write        = tty_write,
  5.     .poll        = tty_poll,
  6.     .unlocked_ioctl    = tty_ioctl,
  7.     .compat_ioctl    = tty_compat_ioctl,
  8.     .open        = tty_open,
  9.     .release    = tty_release,
  10.     .fasync        = tty_fasync,
  11. };
在tty_open中调用了tty->ops的open:
  1. static int __tty_open(struct inode *inode, struct file *filp)
  2. {
  3.     ......

  4.     if (!retval) {
  5.         if (tty->ops->open)                           //这里调用tty->ops->open
  6.             retval = tty->ops->open(tty, filp);
  7.         else
  8.             retval = -ENODEV;
  9.     }
  10.     filp->f_flags = saved_flags;

  11.     .......
  12. }
tty->ops的tty_operations类型的,uart_ops->uart_open:
  1. static const struct tty_operations uart_ops = {
  2.     .open        = uart_open,                            
  3.     .close        = uart_close,
  4.     .write        = uart_write,
  5.     .put_char    = uart_put_char,
  6.     .flush_chars    = uart_flush_chars,
  7.     .write_room    = uart_write_room,
  8.     .chars_in_buffer= uart_chars_in_buffer,
  9.     .flush_buffer    = uart_flush_buffer,
  10.     .ioctl        = uart_ioctl,
  11.     .throttle    = uart_throttle,
  12.     .unthrottle    = uart_unthrottle,
  13.     .send_xchar    = uart_send_xchar,
  14.     .set_termios    = uart_set_termios,
  15.     .set_ldisc    = uart_set_ldisc,
  16.     .stop        = uart_stop,
  17.     .start        = uart_start,
  18.     .hangup        = uart_hangup,
  19.     .break_ctl    = uart_break_ctl,
  20.     .wait_until_sent= uart_wait_until_sent,
  21. #ifdef CONFIG_PROC_FS
  22.     .proc_fops    = &uart_proc_fops,
  23. #endif
  24.     .tiocmget    = uart_tiocmget,
  25.     .tiocmset    = uart_tiocmset,
  26. #ifdef CONFIG_CONSOLE_POLL
  27.     .poll_init    = uart_poll_init,
  28.     .poll_get_char    = uart_poll_get_char,
  29.     .poll_put_char    = uart_poll_put_char,
  30. #endif
  31. };
继续看uart_open:
  1. static int uart_open(struct tty_struct *tty, struct file *filp)
  2. {
  3.     .......
  4.     /*
  5.      * Start up the serial port.
  6.      */
  7.     retval = uart_startup(state, 0);      //这里调用了uart_startup;

  8.     ........
  9. }
然后是uart_startup:
  1. static int uart_startup(struct uart_state *state, int init_hw)
  2. {
  3.     struct uart_info *info = &state->info;
  4.     struct uart_port *port = state->port;
  5.     
  6.     ........

  7.     retval = port->ops->startup(port);       //这里的port是uart_oprt,里面又有一个ops集合,这个集合需要由串口驱动来实现这里是uart_oprt。找到了startup函数
  8.     
  9.     ........

  10. }
然后继续回到samsung.c中来看uart_ops,通过uart_ops->startup到了s3c24xx_serial_startup,:
  1. static struct uart_ops s3c24xx_serial_ops = {
  2.     .pm        = s3c24xx_serial_pm,
  3.     .tx_empty    = s3c24xx_serial_tx_empty,
  4.     .get_mctrl    = s3c24xx_serial_get_mctrl,
  5.     .set_mctrl    = s3c24xx_serial_set_mctrl,
  6.     .stop_tx    = s3c24xx_serial_stop_tx,
  7.     .start_tx    = s3c24xx_serial_start_tx,
  8.     .stop_rx    = s3c24xx_serial_stop_rx,
  9.     .enable_ms    = s3c24xx_serial_enable_ms,
  10.     .break_ctl    = s3c24xx_serial_break_ctl,
  11.     .startup    = s3c24xx_serial_startup,
  12.     .shutdown    = s3c24xx_serial_shutdown,
  13.     .set_termios    = s3c24xx_serial_set_termios,
  14.     .type        = s3c24xx_serial_type,
  15.     .release_port    = s3c24xx_serial_release_port,
  16.     .request_port    = s3c24xx_serial_request_port,
  17.     .config_port    = s3c24xx_serial_config_port,
  18.     .verify_port    = s3c24xx_serial_verify_port,
  19. };

  1. static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {              //这里是各个串口
  2.     [0] = {
  3.         .port = {
  4.             .lock        = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
  5.             .iotype        = UPIO_MEM,
  6.             .irq        = IRQ_S3CUART_RX0,
  7.             .uartclk    = 0,
  8.             .fifosize    = 16,
  9.             .ops        = &s3c24xx_serial_ops,
  10.             .flags        = UPF_BOOT_AUTOCONF,
  11.             .line        = 0,
  12.         }
  13.     },
  14.     [1] = {
  15.         .port = {
  16.             .lock        = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock),
  17.             .iotype        = UPIO_MEM,
  18.             .irq        = IRQ_S3CUART_RX1,
  19.             .uartclk    = 0,
  20.             .fifosize    = 16,
  21.             .ops        = &s3c24xx_serial_ops,
  22.             .flags        = UPF_BOOT_AUTOCONF,
  23.             .line        = 1,
  24.         }
  25.     },
  26. #if CONFIG_SERIAL_SAMSUNG_UARTS > 2

  27.     [2] = {
  28.         .port = {
  29.             .lock        = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock),
  30.             .iotype        = UPIO_MEM,
  31.             .irq        = IRQ_S3CUART_RX2,
  32.             .uartclk    = 0,
  33.             .fifosize    = 16,
  34.             .ops        = &s3c24xx_serial_ops,
  35.             .flags        = UPF_BOOT_AUTOCONF,
  36.             .line        = 2,
  37.         }
  38.     },
  39. #endif
  40. #if CONFIG_SERIAL_SAMSUNG_UARTS > 3
  41.     [3] = {
  42.         .port = {
  43.             .lock        = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock),
  44.             .iotype        = UPIO_MEM,
  45.             .irq        = IRQ_S3CUART_RX3,
  46.             .uartclk    = 0,
  47.             .fifosize    = 16,
  48.             .ops        = &s3c24xx_serial_ops,
  49.             .flags        = UPF_BOOT_AUTOCONF,
  50.             .line        = 3,
  51.         }
  52.     }
  53. #endif
  54. };
到这里总结一下:tty_operations结构中有open的函数指针,这个对应的open函数是uart_open;这个uart_open调用了uart_ops中的startup函数。
而这个uart_ops是串口对应的函数,从而实现的设备驱动。

二、 串口驱动中的重要数据结构
个人感觉重要的数据结构就是tty_operations和uart_ops,当然和应用层的先是file_operaions。

三、初始化分析
  1. static int s3c24xx_serial_startup(struct uart_port *port)
  2. {
  3.     struct s3c24xx_uart_port *ourport = to_ourport(port);
  4.     int ret;

  5.     dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n",
  6.      port->mapbase, port->membase);

  7.     rx_enabled(port) = 1;                                                         //使能串口接收功能

  8.     ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0,
  9.              s3c24xx_serial_portname(port), ourport);                             //注册数据接收中断

  10.     if (ret != 0) {
  11.         printk(KERN_ERR "cannot get irq %d\n", ourport->rx_irq);
  12.         return ret;
  13.     }

  14.     ourport->rx_claimed = 1;

  15.     dbg("requesting tx irq...\n");

  16.     tx_enabled(port) = 1;                                                          //使能发送功能

  17.     ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0,
  18.              s3c24xx_serial_portname(port), ourport);                              //注册数据发送中断

  19.     if (ret) {
  20.         printk(KERN_ERR "cannot get irq %d\n", ourport->tx_irq);
  21.         goto err;
  22.     }

  23.     ourport->tx_claimed = 1;

  24.     dbg("s3c24xx_serial_startup ok\n");

  25.     /* the port reset code should have done the correct
  26.      * register setup for the port controls */
  27.     if (port->line == 2) {
  28.      s3c2410_gpio_cfgpin(S3C2410_GPH6, S3C2410_GPH6_TXD2);
  29.      s3c2410_gpio_pullup(S3C2410_GPH6, 1);
  30.      s3c2410_gpio_cfgpin(S3C2410_GPH7, S3C2410_GPH7_RXD2);
  31.      s3c2410_gpio_pullup(S3C2410_GPH7, 1);
  32.     }

  33.     return ret;

  34.  err:
  35.     s3c24xx_serial_shutdown(port);
  36.     return ret;
  37. }


阅读(609) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~