/* Initialize UART driver */
int init_uart(char *dev, struct uart_t *u, int send_break)
{
 struct termios ti;
 int  fd, i;

 fd = open(dev, O_RDWR | O_NOCTTY);//打开串口设备,其中标志

//O_RDWR,可以对此设备进行读写操作;

//O_NOCTTY,我不是很理解?

//但是不要以控制 tty 的模式,因为我们并不希望在发送 Ctrl-C
 后结束此进程

 if (fd < 0) {
  perror(“Can’t open serial port”);
  return -1;
 }

 //drop fd’s data;
 tcflush(fd, TCIOFLUSH
);//清空数据线

 if (tcgetattr(fd, &ti) < 0) {
  perror(“Can’t get port settings”);
  return -1;
 }

 cfmakeraw(&ti);

cfmakeraw sets the terminal attributes as follows://此函数设置串口终端的以下这些属性,
termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
|INLCR|IGNCR|ICRNL|IXON);
termios_p->c_oflag &= ~OPOST;
termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
termios_p->c_cflag &= ~(CSIZE|PARENB) ;
termios_p->c_cflag |=CS8;

 ti.c_cflag |= CLOCAL;//本地连接,无调制解调器控制
 if (u->flags & FLOW_CTL)
  ti.c_cflag |= CRTSCTS
;//输出硬件流控(只能在具完整线路的缆线下工作,参

//考 Serial-HOWTO 第七节)
 else
  ti.c_cflag &= ~CRTSCTS;

 if (tcsetattr(fd, TCSANOW, &ti) < 0) {//启动新的串口设置
  perror(“Can’t set port settings”);
  return -1;
 }

 /* Set initial baudrate */
 if (set_speed(fd, &ti, u->init_speed) < 0) {/
/设置串口的传输速率bps, 也可以使

//用 cfsetispeed 和 cfsetospeed 来设置

  perror(“Can’t set initial baud rate”);
  return -1;
 }

 tcflush(fd, TCIOFLUSH);//清空数据线

 if (send_break)
  tcsendbreak(fd, 0);

//int tcsendbreak ( int fd, int duration );Sends a break for
//the given time.在串口线上发送0值,至少维持0.25秒。

//If duration is 0, it transmits zero-valued bits for at least 0.25 seconds, and

//not more than 0.5seconds.

 //where place register u’s init function;
 if (u->init && u->init(fd, u, &ti) < 0)

//所有bluez支持的蓝牙串口设备类型构成了一个uart结构数组,通过

//查找对应的uart类型,这个uart的init成员显示了它的init调用方法;

struct uart_t uart[] = {
 { “any”,      0×0000, 0×0000, HCI_UART_H4,   115200, 115200, FLOW_CTL, NULL },
 { “ericsson”, 0×0000, 0×0000, HCI_UART_H4,   57600,  115200, FLOW_CTL, ericsson },
 { “digi”,     0×0000, 0×0000, HCI_UART_H4,   9600,   115200, FLOW_CTL, digi },
 { “texas”,    0×0000, 0×0000, HCI_UART_H4,   115200, 115200, FLOW_CTL, texas},

 { “bcsp”,     0×0000, 0×0000, HCI_UART_BCSP, 115200, 115200, 0,        bcsp },//bcsp的init函数名为bcsp,定义在本文件中**;

  return -1;

 tcflush(fd, TCIOFLUSH);//清空数据线

 /* Set actual baudrate */
 if (set_speed(fd, &ti, u->speed) < 0) {
  perror(“Can’t set baud rate”);
  return -1;
 }

 /* Set TTY to N_HCI line discipline */
 i = N_HCI;
 if (ioctl(fd, TIOCSETD, &i) < 0) {//

TIOCSETD int *ldisc//改变到 i 行规,即hci行规
Change to the new line discipline pointed to by ldisc. The available line disciplines are listed in 

/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */

/* line disciplines */
#define N_TTY  0

……

#define N_HCI  15  /* Bluetooth HCI UART */

  perror(“Can’t set line discipline”);
  return -1;
 }

 if (ioctl(fd, HCIUARTSETPROTO, u->proto) < 0) {

//设置hci设备的proto操作函数集为hci_uart操作集;
  perror(“Can’t set device”);
  return -1;
 }

 return fd;
}


1条评论

  1. 前一阶段一直在看串口驱动程序,但是对于其工作流程一直有个疑问?请指教!

    对于串口驱动程序的执行流程大致是这样的:

    1)判断当前使用的UART是什么类型的?如果是16550A才可以使用FIFO,因为别的类型的UART要么不支持FIFO,要么在使用

    FIFO时有BUG.

    2)如果当前使用的UART是16550A那么就打开FIFO功能,并且初始化别的一些寄存器,包括打开中断使能位(UART_IER).但是

    对于不同版本的linux打开UART_IER的中断使能位各不相同,对于linux0.11它除了写中断外其它中断都开.而对于

    linux0.98版本,它把UART_IER中的所有中断都打开了!(大家可以参考一下0.98版本linux/kernel/serial.c L467

    outb_p(0×0f,UART_IER + port);)

    这两种初始化方式对于整个串口在发送数据时的流程会造成很大的差异!

    对于0.11版本而言,如果用户想要通过串口发送数据的话,那么它只要把UART_IER中的写中断打开,然后等待中断发生,在中

    断处理程序中把需要发送的数据发送出去!

    而对于0.98版本而言,如果用户想要通过口串口数据的话,那么它只要把数据放到FIFO中,一旦FIFO中的数据到达一定的量

    后就会触发中断(这个量是由初始化时向FCR寄存器写入的,好像最大是14),然后由中断处理程序再发送数据.

    我自己在写串口驱动程序的时候发现一旦UARE_IER中的写中断打开,系统立即会发生一个中断,从IIR中判断出发生这个中

    断是由THR产生的,也就是用户可以向串口写数据了!也即证明了linux0.11版本的机制是正确的!而0.98版本的机制好像不

    正确,不知我理解的对不对?

    (linux0.11版本和linux0.98版本可以在www.oldlinux.org下载)

发表评论

评论也有版权!