Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1817460
  • 博文数量: 272
  • 博客积分: 1272
  • 博客等级: 少尉
  • 技术积分: 1866
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-09 15:51
文章分类

全部博文(272)

文章存档

2016年(16)

2015年(28)

2014年(97)

2013年(59)

2012年(25)

2011年(47)

分类: LINUX

2013-11-13 14:40:47

根据前面的操作,串口作为字符驱动也已经注册到系统了,/dev目录下也有设备文件节点了。

那接下来uart的操作是如何进行的呢?

操作硬件之前都是要先open设备,先来分析下这里的open函数具体做了那些工作(做了大量工作 ,真的!)。

应用层通过open系统调用open(“/dev/s3c2410_serial0”,)一层一层调用到会调用到tty_open。

因为串口在linux下是作为tty设备的,结合前面的注册过程可以分析这里首先调用的就是tty_open这个函数。

[cpp]
  1. cdev_init(&driver->cdev, &tty_fops); 


因为根据注册的时候将s3c2410_serial0注册为一个字符设备,字符设备对应的驱动为tty_fops
[cpp]
  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_open

[cpp]
  1. static int tty_open(struct inode *inode, struct file *filp) 
  2.     struct tty_struct *tty = NULL; 
  3.     int noctty, retval; 
  4.     struct tty_driver *driver; 
  5.     int index; 
  6.     dev_t device = inode->i_rdev; 
  7.     unsigned saved_flags = filp->f_flags; 
  8.  
  9.     nonseekable_open(inode, filp); 
  10.  
  11. retry_open: 
  12.     noctty = filp->f_flags & O_NOCTTY; 
  13.     index  = -1; 
  14.     retval = 0; 
  15.  
  16.     mutex_lock(&tty_mutex); 
  17.     tty_lock(); 
  18.  
  19.     if (device == MKDEV(TTYAUX_MAJOR, 0)) { 
  20.         tty = get_current_tty(); 
  21.         if (!tty) { 
  22.             tty_unlock(); 
  23.             mutex_unlock(&tty_mutex); 
  24.             return -ENXIO; 
  25.         } 
  26.         driver = tty_driver_kref_get(tty->driver); 
  27.         index = tty->index; 
  28.         filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */ 
  29.         /* noctty = 1; */ 
  30.         /* FIXME: Should we take a driver reference ? */ 
  31.         tty_kref_put(tty); 
  32.         goto got_driver; 
  33.     } 
  34. #ifdef CONFIG_VT 
  35.     if (device == MKDEV(TTY_MAJOR, 0)) { 
  36.         extern struct tty_driver *console_driver; 
  37.         driver = tty_driver_kref_get(console_driver); 
  38.         index = fg_console; 
  39.         noctty = 1; 
  40.         goto got_driver; 
  41.     } 
  42. #endif 
  43.     if (device == MKDEV(TTYAUX_MAJOR, 1)) { 
  44.         struct tty_driver *console_driver = console_device(&index); 
  45.         if (console_driver) { 
  46.             driver = tty_driver_kref_get(console_driver); 
  47.             if (driver) { 
  48.                 /* Don't let /dev/console block */ 
  49.                 filp->f_flags |= O_NONBLOCK; 
  50.                 noctty = 1; 
  51.                 goto got_driver; 
  52.             } 
  53.         } 
  54.         tty_unlock(); 
  55.         mutex_unlock(&tty_mutex); 
  56.         return -ENODEV; 
  57.     } 
  58.  
  59. "color: rgb(255, 0, 0);">   driver = get_tty_driver(device, &index); 
  60.     if (!driver) { 
  61.         tty_unlock(); 
  62.         mutex_unlock(&tty_mutex); 
  63.         return -ENODEV; 
  64.     } 
  65. got_driver: 
  66.     if (!tty) { 
  67.         /* check whether we're reopening an existing tty */ 
  68.         tty = tty_driver_lookup_tty(driver, inode, index); 
  69.  
  70.         if (IS_ERR(tty)) { 
  71.             tty_unlock(); 
  72.             mutex_unlock(&tty_mutex); 
  73.             return PTR_ERR(tty); 
  74.         } 
  75.     } 
  76.  
  77.     if (tty) { 
  78.         retval = tty_reopen(tty); 
  79.         if (retval) 
  80.             tty = ERR_PTR(retval); 
  81.     } else 
  82.     "color: rgb(255, 0, 0);">   tty = tty_init_dev(driver, index, 0); 
  83.  
  84.     mutex_unlock(&tty_mutex); 
  85.     tty_driver_kref_put(driver); 
  86.     if (IS_ERR(tty)) { 
  87.         tty_unlock(); 
  88.         return PTR_ERR(tty); 
  89.     } 
  90.  
  91.     retval = tty_add_file(tty, filp); 
  92.     if (retval) { 
  93.         tty_unlock(); 
  94.         return retval; 
  95.     } 
  96.  
  97.     check_tty_count(tty, "tty_open"); 
  98.     if (tty->driver->type == TTY_DRIVER_TYPE_PTY && 
  99.         tty->driver->subtype == PTY_TYPE_MASTER) 
  100.         noctty = 1; 
  101. #ifdef TTY_DEBUG_HANGUP 
  102.     printk(KERN_DEBUG "opening %s...", tty->name); 
  103. #endif 
  104.     if (!retval) { 
  105.         if (tty->ops->open) 
  106.             "color: rgb(255, 0, 0);">retval = tty->ops->open(tty, filp); 
  107.         else 
  108.             retval = -ENODEV; 
  109.     } 
  110.     filp->f_flags = saved_flags; 
  111.  
  112.     if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && 
  113.                         !capable(CAP_SYS_ADMIN)) 
  114.         retval = -EBUSY; 
  115.  
  116.     if (retval) { 
  117. #ifdef TTY_DEBUG_HANGUP 
  118.         printk(KERN_DEBUG "error %d in opening %s...", retval, 
  119.                tty->name); 
  120. #endif 
  121.         tty_unlock(); /* need to call tty_release without BTM */ 
  122.         tty_release(inode, filp); 
  123.         if (retval != -ERESTARTSYS) 
  124.             return retval; 
  125.  
  126.         if (signal_pending(current)) 
  127.             return retval; 
  128.  
  129.         schedule(); 
  130.         /*
  131.          * Need to reset f_op in case a hangup happened.
  132.          */ 
  133.         tty_lock(); 
  134.         if (filp->f_op == &hung_up_tty_fops) 
  135.             filp->f_op = &tty_fops; 
  136.         tty_unlock(); 
  137.         goto retry_open; 
  138.     } 
  139.     tty_unlock(); 
  140.  
  141.  
  142.     mutex_lock(&tty_mutex); 
  143.     tty_lock(); 
  144.     spin_lock_irq(¤t->sighand->siglock); 
  145.     if (!noctty && 
  146.         current->signal->leader && 
  147.         !current->signal->tty && 
  148.         tty->session == NULL) 
  149.         __proc_set_tty(current, tty); 
  150.     spin_unlock_irq(¤t->sighand->siglock); 
  151.     tty_unlock(); 
  152.     mutex_unlock(&tty_mutex); 
  153.     return 0; 


函数首先判断打开的设备是否是

5 0(/dev/tty)

5 1(/dev/console)

4 0(/dev/tty0)

此处打开的是/dev/s3c2410_serial0设备号为204 64

所以前面的判断全部失败,直接执行标红的那条语句

[cpp]
  1. driver = get_tty_driver(device, &index); 


get_tty_driver函数如下:
[cpp]
  1. static struct tty_driver *get_tty_driver(dev_t device, int *index) 
  2.     struct tty_driver *p; 
  3.  
  4.     list_for_each_entry(p, &tty_drivers, tty_drivers) { 
  5.         dev_t base = MKDEV(p->major, p->minor_start); 
  6.         if (device < base || device >= base + p->num) 
  7.             continue
  8.         *index = device - base; 
  9.         return tty_driver_kref_get(p); 
  10.     } 
  11.     return NULL; 


可见,此函数的作用就是通过设备号来找到设备对应的tty_driver,并且将索引号码保存在index中

因为一个tty_driver对应的是所有此种类型的tty设备,比如所有的串口设备,所以需要通过这个索引号

index来判断打开的是具体哪个设备。并且每个具体的设备对应着一个用来描述自己的tty_struct。

而系统后面的操作全部和这个tty_struct相关。

然后接着open函数会判断是否有tty_struct,假如不存在则创建并初始化一个tty_struct。

tty_struct是tty结构体中最重要的一个数据结构,内核通过tty-struct这个结构体来描述一个具体的tty设备在内核中

的活动状况的,后面对设备的write、read中都需要使用到这个tty_struct,并且严重依赖这个结构体。

由于此处是不存在tty_struct,所以直接调用函数初始化tty_struct

[cpp]
  1. tty = tty_init_dev(driver, index, 0); 



参数driver为tty_driver,是前面通过get_tty_driver获得的,index此处为0,也是通过前面get_tty_driver获得的。

tty_init_dev()函数具体如下

[cpp]
  1. struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx, 
  2.                                 int first_ok) 
  3.     struct tty_struct *tty; 
  4.     int retval; 
  5.  
  6.     /* Check if pty master is being opened multiple times */ 
  7.     if (driver->subtype == PTY_TYPE_MASTER && 
  8.         (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) { 
  9.         return ERR_PTR(-EIO); 
  10.     } 
  11.  
  12.     /*
  13.      * First time open is complex, especially for PTY devices.
  14.      * This code guarantees that either everything succeeds and the
  15.      * TTY is ready for operation, or else the table slots are vacated
  16.      * and the allocated memory released.  (Except that the termios
  17.      * and locked termios may be retained.)
  18.      */ 
  19.  
  20.     if (!try_module_get(driver->owner)) 
  21.         return ERR_PTR(-ENODEV); 
  22.  
  23.     tty = alloc_tty_struct(); 
  24.     if (!tty) 
  25.         goto fail_no_mem; 
  26.     "color: rgb(255, 0, 0);">initialize_tty_struct(tty, driver, idx); 
  27.  
  28.     retval = tty_driver_install_tty(driver, tty); 
  29.     if (retval < 0) { 
  30.         free_tty_struct(tty); 
  31.         module_put(driver->owner); 
  32.         return ERR_PTR(retval); 
  33.     } 
  34.  
  35.     /*
  36.      * Structures all installed ... call the ldisc open routines.
  37.      * If we fail here just call release_tty to clean up.  No need
  38.      * to decrement the use counts, as release_tty doesn't care.
  39.      */ 
  40.     retval = tty_ldisc_setup(tty, tty->link); 
  41.     if (retval) 
  42.         goto release_mem_out; 
  43.     return tty; 
  44.  
  45. fail_no_mem: 
  46.     module_put(driver->owner); 
  47.     return ERR_PTR(-ENOMEM); 
  48.  
  49.     /* call the tty release_tty routine to clean out this slot */ 
  50. release_mem_out: 
  51.     if (printk_ratelimit()) 
  52.         printk(KERN_INFO "tty_init_dev: ldisc open failed, " 
  53.                  "clearing slot %d\n", idx); 
  54.     release_tty(tty, idx); 
  55.     return ERR_PTR(retval); 


这个函数首先是给tty_struct分配好内存,然后将其初始化,初始化的工作在函数


[cpp]
  1. initialize_tty_struct(tty, driver, idx); 


中完成。参数tty为待初始化的tty_struct,driver为前面通过get_tty_driver获得的tty_driver,index为具体的索引号,同样是通过get_tty_driver获得的,此处index值为0。


初始化的tty_struct部分信息来自于tty_driver,所以将tty_driver传递进此函数。

具体的initialize_tty_struct函数如下


[cpp]
  1. void initialize_tty_struct(struct tty_struct *tty, 
  2.         struct tty_driver *driver, int idx) 
  3.     memset(tty, 0, sizeof(struct tty_struct)); 
  4.     kref_init(&tty->kref); 
  5.     tty->magic = TTY_MAGIC; 
  6.     "color: rgb(255, 0, 0);">tty_ldisc_init(tty); 
  7.     tty->session = NULL; 
  8.     tty->pgrp = NULL; 
  9.     tty->overrun_time = jiffies; 
  10.     tty->buf.head = tty->buf.tail = NULL; 
  11.     tty_buffer_init(tty); 
  12.     mutex_init(&tty->termios_mutex); 
  13.     mutex_init(&tty->ldisc_mutex); 
  14.     init_waitqueue_head(&tty->write_wait); 
  15.     init_waitqueue_head(&tty->read_wait); 
  16.     INIT_WORK(&tty->hangup_work, do_tty_hangup); 
  17.     mutex_init(&tty->atomic_read_lock); 
  18.     mutex_init(&tty->atomic_write_lock); 
  19.     mutex_init(&tty->output_lock); 
  20.     mutex_init(&tty->echo_lock); 
  21.     spin_lock_init(&tty->read_lock); 
  22.     spin_lock_init(&tty->ctrl_lock); 
  23.     INIT_LIST_HEAD(&tty->tty_files); 
  24.     INIT_WORK(&tty->SAK_work, do_SAK_work); 
  25.  
  26.     tty->driver = driver; 
  27.     "color: rgb(255, 0, 0);">tty->ops = driver->ops; 
  28.     "color: rgb(255, 0, 0);">tty->index = idx; 
  29.     tty_line_name(driver, idx, tty->name); 
  30.     tty->dev = tty_get_device(tty); 


初始化中最重要的两步已标红,其中第一步和tty线路规程相关。之前分析过tty线路规程初始化部分的代码,


而这里的初始化就是根据数组的索引号,从前面初始化好的tty线路规程操作方法数组中获取对应的操作方法,然后将其填充到

tty_struct中对应的域中。具体如下


[cpp]
  1. void tty_ldisc_init(struct tty_struct *tty) 
  2.     struct tty_ldisc *ld = tty_ldisc_get(N_TTY); 
  3.     if (IS_ERR(ld)) 
  4.         panic("n_tty: init_tty"); 
  5.     tty_ldisc_assign(tty, ld); 


可见索引号是N_TTY,也就是tty_ldiscs[0]中的tty线路规程操纵方法集,tty_ldiscs[0]对应的具体操作集如下



[cpp]
  1. struct tty_ldisc_ops tty_ldisc_N_TTY = {   
  2.     .magic           = TTY_LDISC_MAGIC,   
  3.     .name            = "n_tty",   
  4.     .open            = n_tty_open,   
  5.     .close           = n_tty_close,   
  6.     .flush_buffer    = n_tty_flush_buffer,   
  7.     .chars_in_buffer = n_tty_chars_in_buffer,   
  8.     .read            = n_tty_read,   
  9.     .write           = n_tty_write,   
  10.     .ioctl           = n_tty_ioctl,   
  11.     .set_termios     = n_tty_set_termios,   
  12.     .poll            = n_tty_poll,   
  13.     .receive_buf     = n_tty_receive_buf,   
  14.     .write_wakeup    = n_tty_write_wakeup   
  15. };   


在write过程中会调用其中的方法。tty_write->n_tty_write。


最后通过函数

[cpp]
  1. tty_ldisc_assign(tty, ld); 


将其填充到tty_struct中。


在这个tty_struct的初始化函数还需要注意的是


[cpp]
  1. tty->ops = driver->ops; 


也就是将tty_struct中的ops设置成tty_driver中的ops。后面write、read的操作调用的是tty_struct中的ops而非tty_driver


中的ops

此处的tty_driver的ops在uart_register_driver中被设置成如下


[cpp]
  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.     .get_icount = uart_get_icount, 
  27. #ifdef CONFIG_CONSOLE_POLL 
  28.     .poll_init  = uart_poll_init, 
  29.     .poll_get_char  = uart_poll_get_char, 
  30.     .poll_put_char  = uart_poll_put_char, 
  31. #endif 
  32. }; 



接着函数返回到tty_init_dev函数中继续往下执行。


调用函数


[cpp]
  1. retval = tty_driver_install_tty(driver, tty); 


这个函数的主要作用就是将这个初始化好的


tty_struct存放到tty_driver的tty_structs[]数组中,存放的位置依据tty-struct->index

这样可以tty_driver中每个设备都可以根据index找到对应的tty_struct了。

最后再次返回tty_init_dev函数中执行


[cpp]
  1. retval = tty_ldisc_setup(tty, tty->link); 



这个函数会调用tty线路规程中的open方法n_tty_open函数


n_tty_open中主要完成buff缓冲区大小设置的工作,具体不展开了(其实我也没仔细分析)。

最后这个tty_struct的初始化函数彻底执行完毕,退到tty_open函数中继续执行后续代码。

在tty_open中会被执行到的代码是


[cpp]
  1. retval = tty->ops->open(tty, filp); 



这里就是tty-struct中的ops,在tty_struct初始化的时候被赋值成tty_driver的ops,所以这里调用到的就是


uart_open函数。uart_open函数的重要作用是找到之前初始化的时候保存在tty_driver中的uart_state,因为这里面还有uart_port的重要信息。

找到这个uart_state后将其赋值给tty_struct。具体的uart_open函数如下


[cpp]
  1. static int uart_open(struct tty_struct *tty, struct file *filp) 
  2.     struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state; 
  3.     struct uart_state *state; 
  4.     struct tty_port *port; 
  5.     int retval, line = tty->index; 
  6.  
  7.     BUG_ON(!tty_locked()); 
  8.     pr_debug("uart_open(%d) called\n", line); 
  9.  
  10.     /*
  11.      * tty->driver->num won't change, so we won't fail here with
  12.      * tty->driver_data set to something non-NULL (and therefore
  13.      * we won't get caught by uart_close()).
  14.      */ 
  15.     retval = -ENODEV; 
  16.     if (line >= tty->driver->num) 
  17.         goto fail; 
  18.  
  19.     /*
  20.      * We take the semaphore inside uart_get to guarantee that we won't
  21.      * be re-entered while allocating the state structure, or while we
  22.      * request any IRQs that the driver may need.  This also has the nice
  23.      * side-effect that it delays the action of uart_hangup, so we can
  24.      * guarantee that state->port.tty will always contain something
  25.      * reasonable.
  26.      */ 
  27.     "color: rgb(255, 0, 0);">state = uart_get(drv, line); 
  28.     if (IS_ERR(state)) { 
  29.         retval = PTR_ERR(state); 
  30.         goto fail; 
  31.     } 
  32.     port = &state->port; 
  33.  
  34.     /*
  35.      * Once we set tty->driver_data here, we are guaranteed that
  36.      * uart_close() will decrement the driver module use count.
  37.      * Any failures from here onwards should not touch the count.
  38.      */ 
  39.     "color: rgb(255, 0, 0);">tty->driver_data = state; 
  40.     state->uart_port->state = state; 
  41.     tty->low_latency = (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0; 
  42.     tty->alt_speed = 0; 
  43.     tty_port_tty_set(port, tty); 
  44.  
  45.     /*
  46.      * If the port is in the middle of closing, bail out now.
  47.      */ 
  48.     if (tty_hung_up_p(filp)) { 
  49.         retval = -EAGAIN; 
  50.         port->count--; 
  51.         mutex_unlock(&port->mutex); 
  52.         goto fail; 
  53.     } 
  54.  
  55.     /*
  56.      * Make sure the device is in D0 state.
  57.      */ 
  58.     if (port->count == 1) 
  59.         uart_change_pm(state, 0); 
  60.  
  61.     /*
  62.      * Start up the serial port.
  63.      */ 
  64.     "color: rgb(255, 0, 0);">retval = uart_startup(tty, state, 0); 
  65.  
  66.     /*
  67.      * If we succeeded, wait until the port is ready.
  68.      */ 
  69.     mutex_unlock(&port->mutex); 
  70.     if (retval == 0) 
  71.         retval = tty_port_block_til_ready(port, tty, filp); 
  72.  
  73. fail: 
  74.     return retval; 


函数通过



[cpp]
  1. state = uart_get(drv, line); 



来找到保存在tty_driver中的uart_state。


最后将其值赋值给tty_struct。此处特别注意一下,这个uart_state会被放到tty_struct的driver_data中的!因为后面的write、read都是从driver_data中找到这个uar_state的!

最后函数条用uart_startup函数来初始化串口硬件


[cpp]
  1.     retval = uart_startup(tty, state, 0); 


函数参数tty对应的就是tty_struct,state就是从tty_driver中找到的uart_state


具体的uart_startup函数如下


[cpp]
  1. static int uart_startup(struct tty_struct *tty, struct uart_state *state, int init_hw) 
  2.     struct uart_port *uport = state->uart_port; 
  3.     struct tty_port *port = &state->port; 
  4.     unsigned long page; 
  5.     int retval = 0; 
  6.  
  7.     if (port->flags & ASYNC_INITIALIZED) 
  8.         return 0; 
  9.  
  10.     /*
  11.      * Set the TTY IO error marker - we will only clear this
  12.      * once we have successfully opened the port.  Also set
  13.      * up the tty->alt_speed kludge
  14.      */ 
  15.     set_bit(TTY_IO_ERROR, &tty->flags); 
  16.  
  17.     if (uport->type == PORT_UNKNOWN) 
  18.         return 0; 
  19.  
  20.     /*
  21.      * Initialise and allocate the transmit and temporary
  22.      * buffer.
  23.      */ 
  24.     if (!state->xmit.buf) { 
  25.         /* This is protected by the per port mutex */ 
  26.         page = get_zeroed_page(GFP_KERNEL); 
  27.         if (!page) 
  28.             return -ENOMEM; 
  29.  
  30.         state->xmit.buf = (unsigned char *) page; 
  31.         uart_circ_clear(&state->xmit); 
  32.     } 
  33.  
  34.     "color: rgb(255, 0, 0);">retval = uport->ops->startup(uport); 
  35.     if (retval == 0) { 
  36.         if (init_hw) { 
  37.             /*
  38.              * Initialise the hardware port settings.
  39.              */ 
  40.             uart_change_speed(tty, state, NULL); 
  41.  
  42.             /*
  43.              * Setup the RTS and DTR signals once the
  44.              * port is open and ready to respond.
  45.              */ 
  46.             if (tty->termios->c_cflag & CBAUD) 
  47.                 uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR); 
  48.         } 
  49.  
  50.         if (port->flags & ASYNC_CTS_FLOW) { 
  51.             spin_lock_irq(&uport->lock); 
  52.             if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) 
  53.                 tty->hw_stopped = 1; 
  54.             spin_unlock_irq(&uport->lock); 
  55.         } 
  56.  
  57.         set_bit(ASYNCB_INITIALIZED, &port->flags); 
  58.  
  59.         clear_bit(TTY_IO_ERROR, &tty->flags); 
  60.     } 
  61.  
  62.     if (retval && capable(CAP_SYS_ADMIN)) 
  63.         retval = 0; 
  64.  
  65.     return retval; 


此函数的作用就是初始化s3c2440的uart,其中最重要的是调用了s3c2440的硬件操作函数集中的startup方法,


即uart_port的ops,此ops在初始化的时候被初始化为


[cpp]
  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. }; 


所以此处直接调用的是s3c24xx_serial_startup函数,此函数如下。



[cpp]
  1. static int s3c24xx_serial_startup(struct uart_port *port) 
  2.     struct s3c24xx_uart_port *ourport = to_ourport(port); 
  3.     int ret; 
  4.  
  5.     dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n"
  6.         port->mapbase, port->membase); 
  7.  
  8.     rx_enabled(port) = 1; 
  9.  
  10. "color: rgb(255, 0, 0);">   ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0, 
  11.               s3c24xx_serial_portname(port), ourport); 
  12.  
  13.     if (ret != 0) { 
  14.         printk(KERN_ERR "cannot get irq %d\n", ourport->rx_irq); 
  15.         return ret; 
  16.     } 
  17.  
  18.     ourport->rx_claimed = 1; 
  19.  
  20.     dbg("requesting tx irq...\n"); 
  21.  
  22.     tx_enabled(port) = 1; 
  23.  
  24. "color: rgb(255, 0, 0);">   ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0, 
  25.               s3c24xx_serial_portname(port), ourport); 
  26.  
  27.     if (ret) { 
  28.         printk(KERN_ERR "cannot get irq %d\n", ourport->tx_irq); 
  29.         goto err; 
  30.     } 
  31.  
  32.     ourport->tx_claimed = 1; 
  33.  
  34.     dbg("s3c24xx_serial_startup ok\n"); 
  35.  
  36.     /* the port reset code should have done the correct
  37.      * register setup for the port controls */ 
  38.  
  39.     return ret; 
  40.  
  41. err: 
  42.     s3c24xx_serial_shutdown(port); 
  43.     return ret; 



其作用还是初始化,主要初始化的是s3c24xx的uart的中断。


设置uart的发送中断,接收中断处理函数。

至此,通过open函数后s3c24xx的uart硬件部分也初始化好了,接着可以通过write、read函数收发数据了。

总结下

open的主要作用是 在内核通过创建并初始化一个tty_struct来描述具体对应的一个硬件设备,比如这里就是用一个tty_struct来描述s3c24xx上的uart0的,然后找到uart_port

中ops的startup方法初始化uart的硬件。

具体的tty_struct初始化过程中最重要的几步如下

1.初始化tty-struct的ops,就是将tty_driver中的ops赋值给tty_struct

2.初始化tty线路规程操作集

3.初始化tty_struct中的uart_state,uart_state中包含uart_port信息,这一步通过步骤1中ops中的open方法来完成。

4.根据步骤3中找到的uart_state,找到里面的uart_port的ops中的startup方法来初始化uart硬件。

open的流程大致如下:

open

--tty_open

    |

    --get_tty_driver

    --tty_init_dev

    --tty->ops->open(uart_open)

        |

        --uart_startup

            |

            --uport->ops->startup(s3c24xx_serial_startup())

                |

                --request_irq(rx_irq)

                --request_irq(tx_irq)

中断处理函数如下:

s3c24xx_serial_rx_chars

s3c24xx_serial_tx_chars

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