串口的open操作(tty_open) .

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

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

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

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

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

  1. cdev_init(&driver->cdev, &tty_fops);  
cdev_init(&driver->cdev, &tty_fops);
因为根据注册的时候将s3c2410_serial0注册为一个字符设备,字符设备对应的驱动为tty_fops
  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. };  
static const struct file_operations tty_fops = {
	.llseek		= no_llseek,
	.read		= tty_read,
	.write		= tty_write,
	.poll		= tty_poll,
	.unlocked_ioctl	= tty_ioctl,
	.compat_ioctl	= tty_compat_ioctl,
	.open		= tty_open,
	.release		= tty_release,
	.fasync		= tty_fasync,
};

所以这里就调用的是tty_open函数。

下面具体分析tty_open

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

	nonseekable_open(inode, filp);

retry_open:
	noctty = filp->f_flags & O_NOCTTY;
	index  = -1;
	retval = 0;

	mutex_lock(&tty_mutex);
	tty_lock();

	if (device == MKDEV(TTYAUX_MAJOR, 0)) {
		tty = get_current_tty();
		if (!tty) {
			tty_unlock();
			mutex_unlock(&tty_mutex);
			return -ENXIO;
		}
		driver = tty_driver_kref_get(tty->driver);
		index = tty->index;
		filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
		/* noctty = 1; */
		/* FIXME: Should we take a driver reference ? */
		tty_kref_put(tty);
		goto got_driver;
	}
#ifdef CONFIG_VT
	if (device == MKDEV(TTY_MAJOR, 0)) {
		extern struct tty_driver *console_driver;
		driver = tty_driver_kref_get(console_driver);
		index = fg_console;
		noctty = 1;
		goto got_driver;
	}
#endif
	if (device == MKDEV(TTYAUX_MAJOR, 1)) {
		struct tty_driver *console_driver = console_device(&index);
		if (console_driver) {
			driver = tty_driver_kref_get(console_driver);
			if (driver) {
				/* Don't let /dev/console block */
				filp->f_flags |= O_NONBLOCK;
				noctty = 1;
				goto got_driver;
			}
		}
		tty_unlock();
		mutex_unlock(&tty_mutex);
		return -ENODEV;
	}

	driver = get_tty_driver(device, &index);
	if (!driver) {
		tty_unlock();
		mutex_unlock(&tty_mutex);
		return -ENODEV;
	}
got_driver:
	if (!tty) {
		/* check whether we're reopening an existing tty */
		tty = tty_driver_lookup_tty(driver, inode, index);

		if (IS_ERR(tty)) {
			tty_unlock();
			mutex_unlock(&tty_mutex);
			return PTR_ERR(tty);
		}
	}

	if (tty) {
		retval = tty_reopen(tty);
		if (retval)
			tty = ERR_PTR(retval);
	} else
		tty = tty_init_dev(driver, index, 0);

	mutex_unlock(&tty_mutex);
	tty_driver_kref_put(driver);
	if (IS_ERR(tty)) {
		tty_unlock();
		return PTR_ERR(tty);
	}

	retval = tty_add_file(tty, filp);
	if (retval) {
		tty_unlock();
		return retval;
	}

	check_tty_count(tty, "tty_open");
	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
	    tty->driver->subtype == PTY_TYPE_MASTER)
		noctty = 1;
#ifdef TTY_DEBUG_HANGUP
	printk(KERN_DEBUG "opening %s...", tty->name);
#endif
	if (!retval) {
		if (tty->ops->open)
			retval = tty->ops->open(tty, filp);
		else
			retval = -ENODEV;
	}
	filp->f_flags = saved_flags;

	if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) &&
						!capable(CAP_SYS_ADMIN))
		retval = -EBUSY;

	if (retval) {
#ifdef TTY_DEBUG_HANGUP
		printk(KERN_DEBUG "error %d in opening %s...", retval,
		       tty->name);
#endif
		tty_unlock(); /* need to call tty_release without BTM */
		tty_release(inode, filp);
		if (retval != -ERESTARTSYS)
			return retval;

		if (signal_pending(current))
			return retval;

		schedule();
		/*
		 * Need to reset f_op in case a hangup happened.
		 */
		tty_lock();
		if (filp->f_op == &hung_up_tty_fops)
			filp->f_op = &tty_fops;
		tty_unlock();
		goto retry_open;
	}
	tty_unlock();


	mutex_lock(&tty_mutex);
	tty_lock();
	spin_lock_irq(¤t->sighand->siglock);
	if (!noctty &&
	    current->signal->leader &&
	    !current->signal->tty &&
	    tty->session == NULL)
		__proc_set_tty(current, tty);
	spin_unlock_irq(&current->sighand->siglock);
	tty_unlock();
	mutex_unlock(&tty_mutex);
	return 0;
}
函数首先判断打开的设备是否是

5 0(/dev/tty)

5 1(/dev/console)

4 0(/dev/tty0)

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

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

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

	list_for_each_entry(p, &tty_drivers, tty_drivers) {
		dev_t base = MKDEV(p->major, p->minor_start);
		if (device < base || device >= base + p->num)
			continue;
		*index = device - base;
		return tty_driver_kref_get(p);
	}
	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

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

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

tty_init_dev()函数具体如下

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

	/* Check if pty master is being opened multiple times */
	if (driver->subtype == PTY_TYPE_MASTER &&
		(driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) {
		return ERR_PTR(-EIO);
	}

	/*
	 * First time open is complex, especially for PTY devices.
	 * This code guarantees that either everything succeeds and the
	 * TTY is ready for operation, or else the table slots are vacated
	 * and the allocated memory released.  (Except that the termios
	 * and locked termios may be retained.)
	 */

	if (!try_module_get(driver->owner))
		return ERR_PTR(-ENODEV);

	tty = alloc_tty_struct();
	if (!tty)
		goto fail_no_mem;
	initialize_tty_struct(tty, driver, idx);

	retval = tty_driver_install_tty(driver, tty);
	if (retval < 0) {
		free_tty_struct(tty);
		module_put(driver->owner);
		return ERR_PTR(retval);
	}

	/*
	 * Structures all installed ... call the ldisc open routines.
	 * If we fail here just call release_tty to clean up.  No need
	 * to decrement the use counts, as release_tty doesn't care.
	 */
	retval = tty_ldisc_setup(tty, tty->link);
	if (retval)
		goto release_mem_out;
	return tty;

fail_no_mem:
	module_put(driver->owner);
	return ERR_PTR(-ENOMEM);

	/* call the tty release_tty routine to clean out this slot */
release_mem_out:
	if (printk_ratelimit())
		printk(KERN_INFO "tty_init_dev: ldisc open failed, "
				 "clearing slot %d\n", idx);
	release_tty(tty, idx);
	return ERR_PTR(retval);
}

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

  1. initialize_tty_struct(tty, driver, idx);  
	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函数如下

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

	tty->driver = driver;
	tty->ops = driver->ops;
	tty->index = idx;
	tty_line_name(driver, idx, tty->name);
	tty->dev = tty_get_device(tty);
}
初始化中最重要的两步已标红,其中第一步和tty线路规程相关。之前分析过tty线路规程初始化部分的代码,

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

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

  1. void tty_ldisc_init(struct tty_struct *tty)  
  2. {  
  3.     struct tty_ldisc *ld = tty_ldisc_get(N_TTY);  
  4.     if (IS_ERR(ld))  
  5.         panic("n_tty: init_tty");  
  6.     tty_ldisc_assign(tty, ld);  
  7. }  
void tty_ldisc_init(struct tty_struct *tty)
{
	struct tty_ldisc *ld = tty_ldisc_get(N_TTY);
	if (IS_ERR(ld))
		panic("n_tty: init_tty");
	tty_ldisc_assign(tty, ld);
}
可见索引号是N_TTY,也就是tty_ldiscs[0]中的tty线路规程操纵方法集,tty_ldiscs[0]对应的具体操作集如下

  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. };    
    struct tty_ldisc_ops tty_ldisc_N_TTY = {  
        .magic           = TTY_LDISC_MAGIC,  
        .name            = "n_tty",  
        .open            = n_tty_open,  
        .close           = n_tty_close,  
        .flush_buffer    = n_tty_flush_buffer,  
        .chars_in_buffer = n_tty_chars_in_buffer,  
        .read            = n_tty_read,  
        .write           = n_tty_write,  
        .ioctl           = n_tty_ioctl,  
        .set_termios     = n_tty_set_termios,  
        .poll            = n_tty_poll,  
        .receive_buf     = n_tty_receive_buf,  
        .write_wakeup    = n_tty_write_wakeup  
    };  
在write过程中会调用其中的方法。tty_write->n_tty_write。

最后通过函数

  1. tty_ldisc_assign(tty, ld);  
tty_ldisc_assign(tty, ld);
将其填充到tty_struct中。

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

  1. tty->ops = driver->ops;  
	tty->ops = driver->ops;
也就是将tty_struct中的ops设置成tty_driver中的ops。后面write、read的操作调用的是tty_struct中的ops而非tty_driver

中的ops

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

  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. };  
static const struct tty_operations uart_ops = {
	.open		= uart_open,
	.close		= uart_close,
	.write		= uart_write,
	.put_char	= uart_put_char,
	.flush_chars	= uart_flush_chars,
	.write_room	= uart_write_room,
	.chars_in_buffer= uart_chars_in_buffer,
	.flush_buffer	= uart_flush_buffer,
	.ioctl		= uart_ioctl,
	.throttle	= uart_throttle,
	.unthrottle	= uart_unthrottle,
	.send_xchar	= uart_send_xchar,
	.set_termios	= uart_set_termios,
	.set_ldisc	= uart_set_ldisc,
	.stop		= uart_stop,
	.start		= uart_start,
	.hangup		= uart_hangup,
	.break_ctl	= uart_break_ctl,
	.wait_until_sent= uart_wait_until_sent,
#ifdef CONFIG_PROC_FS
	.proc_fops	= &uart_proc_fops,
#endif
	.tiocmget	= uart_tiocmget,
	.tiocmset	= uart_tiocmset,
	.get_icount	= uart_get_icount,
#ifdef CONFIG_CONSOLE_POLL
	.poll_init	= uart_poll_init,
	.poll_get_char	= uart_poll_get_char,
	.poll_put_char	= uart_poll_put_char,
#endif
};

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

调用函数

  1. retval = tty_driver_install_tty(driver, tty);  
retval = tty_driver_install_tty(driver, tty);
这个函数的主要作用就是将这个初始化好的

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

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

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

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

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

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

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

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

  1. retval = tty->ops->open(tty, filp);  
	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函数如下

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

	BUG_ON(!tty_locked());
	pr_debug("uart_open(%d) called\n", line);

	/*
	 * tty->driver->num won't change, so we won't fail here with
	 * tty->driver_data set to something non-NULL (and therefore
	 * we won't get caught by uart_close()).
	 */
	retval = -ENODEV;
	if (line >= tty->driver->num)
		goto fail;

	/*
	 * We take the semaphore inside uart_get to guarantee that we won't
	 * be re-entered while allocating the state structure, or while we
	 * request any IRQs that the driver may need.  This also has the nice
	 * side-effect that it delays the action of uart_hangup, so we can
	 * guarantee that state->port.tty will always contain something
	 * reasonable.
	 */
	state = uart_get(drv, line);
	if (IS_ERR(state)) {
		retval = PTR_ERR(state);
		goto fail;
	}
	port = &state->port;

	/*
	 * Once we set tty->driver_data here, we are guaranteed that
	 * uart_close() will decrement the driver module use count.
	 * Any failures from here onwards should not touch the count.
	 */
	tty->driver_data = state;
	state->uart_port->state = state;
	tty->low_latency = (state->uart_port->flags & UPF_LOW_LATENCY) ? 1 : 0;
	tty->alt_speed = 0;
	tty_port_tty_set(port, tty);

	/*
	 * If the port is in the middle of closing, bail out now.
	 */
	if (tty_hung_up_p(filp)) {
		retval = -EAGAIN;
		port->count--;
		mutex_unlock(&port->mutex);
		goto fail;
	}

	/*
	 * Make sure the device is in D0 state.
	 */
	if (port->count == 1)
		uart_change_pm(state, 0);

	/*
	 * Start up the serial port.
	 */
	retval = uart_startup(tty, state, 0);

	/*
	 * If we succeeded, wait until the port is ready.
	 */
	mutex_unlock(&port->mutex);
	if (retval == 0)
		retval = tty_port_block_til_ready(port, tty, filp);

fail:
	return retval;
}
函数通过

  1. state = uart_get(drv, line);  
	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函数来初始化串口硬件

  1.     retval = uart_startup(tty, state, 0);  
	    retval = uart_startup(tty, state, 0);
函数参数tty对应的就是tty_struct,state就是从tty_driver中找到的uart_state

具体的uart_startup函数如下

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

	if (port->flags & ASYNC_INITIALIZED)
		return 0;

	/*
	 * Set the TTY IO error marker - we will only clear this
	 * once we have successfully opened the port.  Also set
	 * up the tty->alt_speed kludge
	 */
	set_bit(TTY_IO_ERROR, &tty->flags);

	if (uport->type == PORT_UNKNOWN)
		return 0;

	/*
	 * Initialise and allocate the transmit and temporary
	 * buffer.
	 */
	if (!state->xmit.buf) {
		/* This is protected by the per port mutex */
		page = get_zeroed_page(GFP_KERNEL);
		if (!page)
			return -ENOMEM;

		state->xmit.buf = (unsigned char *) page;
		uart_circ_clear(&state->xmit);
	}

	retval = uport->ops->startup(uport);
	if (retval == 0) {
		if (init_hw) {
			/*
			 * Initialise the hardware port settings.
			 */
			uart_change_speed(tty, state, NULL);

			/*
			 * Setup the RTS and DTR signals once the
			 * port is open and ready to respond.
			 */
			if (tty->termios->c_cflag & CBAUD)
				uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
		}

		if (port->flags & ASYNC_CTS_FLOW) {
			spin_lock_irq(&uport->lock);
			if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS))
				tty->hw_stopped = 1;
			spin_unlock_irq(&uport->lock);
		}

		set_bit(ASYNCB_INITIALIZED, &port->flags);

		clear_bit(TTY_IO_ERROR, &tty->flags);
	}

	if (retval && capable(CAP_SYS_ADMIN))
		retval = 0;

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

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

  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. };  
static struct uart_ops s3c24xx_serial_ops = {
	.pm		= s3c24xx_serial_pm,
	.tx_empty	= s3c24xx_serial_tx_empty,
	.get_mctrl	= s3c24xx_serial_get_mctrl,
	.set_mctrl	= s3c24xx_serial_set_mctrl,
	.stop_tx	= s3c24xx_serial_stop_tx,
	.start_tx	= s3c24xx_serial_start_tx,
	.stop_rx	= s3c24xx_serial_stop_rx,
	.enable_ms	= s3c24xx_serial_enable_ms,
	.break_ctl	= s3c24xx_serial_break_ctl,
	.startup	= s3c24xx_serial_startup,
	.shutdown	= s3c24xx_serial_shutdown,
	.set_termios	= s3c24xx_serial_set_termios,
	.type		= s3c24xx_serial_type,
	.release_port	= s3c24xx_serial_release_port,
	.request_port	= s3c24xx_serial_request_port,
	.config_port	= s3c24xx_serial_config_port,
	.verify_port	= s3c24xx_serial_verify_port,
};
所以此处直接调用的是s3c24xx_serial_startup函数,此函数如下。

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

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

	rx_enabled(port) = 1;

	ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0,
			  s3c24xx_serial_portname(port), ourport);

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

	ourport->rx_claimed = 1;

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

	tx_enabled(port) = 1;

	ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0,
			  s3c24xx_serial_portname(port), ourport);

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

	ourport->tx_claimed = 1;

	dbg("s3c24xx_serial_startup ok\n");

	/* the port reset code should have done the correct
	 * register setup for the port controls */

	return ret;

 err:
	s3c24xx_serial_shutdown(port);
	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

====
http://blog.csdn.net/rockrockwu/article/details/7897283
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值