五 linux 串口驱动

来源:互联网 发布:java mvc 编辑:程序博客网 时间:2024/05/18 09:07

一.串口结构体

1.串口驱动结构体

struct uart_driver {struct module*owner;//模块所有者const char*driver_name;//驱动名const char*dev_name;//设备名int major;//主设备号int minor;//次设备号int nr;//支持串口个数struct console*cons;//控制台设备struct uart_state*state;//串口状态struct tty_driver*tty_driver;//tty设备};

2.串口端口结构体

struct uart_port {spinlock_tlock;unsigned longiobase;//io端口基地址unsigned char __iomem*membase;//内存端口基地址unsigned int(*serial_in)(struct uart_port *, int);void(*serial_out)(struct uart_port *, int, int);void(*set_termios)(struct uart_port *,struct ktermios *new,struct ktermios *old);void(*pm)(struct uart_port *, unsigned int state,unsigned int old);unsigned intirq;//中断号unsigned longirqflags;//中断标志unsigned intuartclk;unsigned intfifosize;//fifo大小unsigned charx_char;unsigned charregshift;//寄存器偏移值unsigned chariotype;//io访问类型unsigned charunused1;unsigned intread_status_mask;unsigned intignore_status_mask;struct uart_state*state;//uart_state结构体struct uart_icounticount;//串口使用计数struct console*cons;//console控制台#if defined(CONFIG_SERIAL_CORE_CONSOLE) || defined(SUPPORT_SYSRQ)unsigned longsysrq;#endifupf_tflags;unsigned intmctrl;unsigned inttimeout;unsigned inttype;const struct uart_ops*ops;//串口操作函数集unsigned intcustom_divisor;unsigned intline;//端口号resource_size_tmapbase;struct device*dev;//设备文件unsigned charhub6;unsigned charsuspended;unsigned charirq_wake;unsigned charunused[2];void*private_data;};

3.操作函数集

struct uart_ops {unsigned int(*tx_empty)(struct uart_port *);//发送缓冲区为空void(*set_mctrl)(struct uart_port *, unsigned int mctrl);//设置串口modem控制模式unsigned int(*get_mctrl)(struct uart_port *);//获取串口modem控制模式void(*stop_tx)(struct uart_port *);//停止发送void(*start_tx)(struct uart_port *);//开始发送void(*send_xchar)(struct uart_port *, char ch);void(*stop_rx)(struct uart_port *);//停止接收void(*enable_ms)(struct uart_port *);//使能modem状态信息void(*break_ctl)(struct uart_port *, int ctl);int(*startup)(struct uart_port *);//打开串口void(*shutdown)(struct uart_port *);//关闭串口void(*flush_buffer)(struct uart_port *);void(*set_termios)(struct uart_port *, struct ktermios *new,struct ktermios *old);//设置串口参数void(*set_ldisc)(struct uart_port *, int new);void(*pm)(struct uart_port *, unsigned int state,unsigned int oldstate);int(*set_wake)(struct uart_port *, unsigned int state);const char *(*type)(struct uart_port *);void(*release_port)(struct uart_port *);//释放端口int(*request_port)(struct uart_port *);//请求端口void(*config_port)(struct uart_port *, int);//配置端口int(*verify_port)(struct uart_port *, struct serial_struct *);//校验端口int(*ioctl)(struct uart_port *, unsigned int, unsigned long);//控制#ifdef CONFIG_CONSOLE_POLLvoid(*poll_put_char)(struct uart_port *, unsigned char);int(*poll_get_char)(struct uart_port *);#endif};

4.uart_state

struct uart_state {struct tty_portport;intpm_state;struct circ_bufxmit;struct tasklet_structtlet;struct uart_port*uart_port;};

 

二.串口驱动的注册与注销

注册

int uart_register_driver(struct uart_driver *drv){struct tty_driver *normal;int i, retval;BUG_ON(drv->state);drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);//分配uart_state内存if (!drv->state)goto out;normal = alloc_tty_driver(drv->nr);//分配tty_driverif (!normal)goto out_kfree;drv->tty_driver = normal;//tty_driver和uart_driver捆绑normal->owner= drv->owner;//模块所有者normal->driver_name= drv->driver_name;//驱动名normal->name= drv->dev_name;//设备名normal->major= drv->major;//主设备号normal->minor_start= drv->minor;//次设备号normal->type= TTY_DRIVER_TYPE_SERIAL;//tty类型normal->subtype= SERIAL_TYPE_NORMAL;//tty子类型normal->init_termios= tty_std_termios;//termios结构体normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;//设置默认串口信息normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;//波特率normal->flags= TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;normal->driver_state    = drv;tty_set_operations(normal, &uart_ops);//设置tty操作函数集for (i = 0; i < drv->nr; i++) {//初始化uart_statestruct uart_state *state = drv->state + i;struct tty_port *port = &state->port;tty_port_init(port);//初始化tty端口port->ops = &uart_port_ops;//tty端口操作函数集port->close_delay     = 500;/* .5 seconds */port->closing_wait    = 30000;/* 30 seconds */tasklet_init(&state->tlet, uart_tasklet_action,(unsigned long)state);}retval = tty_register_driver(normal);//注册tty驱动if (retval >= 0)return retval;put_tty_driver(normal);//引用计数out_kfree:kfree(drv->state);out:return -ENOMEM;}

 注销

void uart_unregister_driver(struct uart_driver *drv){struct tty_driver *p = drv->tty_driver;tty_unregister_driver(p);//注销tty驱动put_tty_driver(p);//减少引用计数kfree(drv->state);drv->tty_driver = NULL;}

三.端口注册与注销

注册

int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport){struct uart_state *state;struct tty_port *port;int ret = 0;struct device *tty_dev;BUG_ON(in_interrupt());if (uport->line >= drv->nr)return -EINVAL;state = drv->state + uport->line;//获取uart_stateport = &state->port;//获取tty_portmutex_lock(&port_mutex);mutex_lock(&port->mutex);if (state->uart_port) {ret = -EINVAL;goto out;}state->uart_port = uport;//设置uart_state->uart_portstate->pm_state = -1;uport->cons = drv->cons;//设置uart_port->cons控制台uport->state = state;//设置uart_port->stateif (!(uart_console(uport) && (uport->cons->flags & CON_ENABLED))) {spin_lock_init(&uport->lock);lockdep_set_class(&uport->lock, &port_lock_key);}uart_configure_port(drv, state, uport);//配置端口tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev);//生成tty设备文件/dev/ttyXXXif (likely(!IS_ERR(tty_dev))) {device_init_wakeup(tty_dev, 1);device_set_wakeup_enable(tty_dev, 0);} elseprintk(KERN_ERR "Cannot register tty device on line %d\n",uport->line);uport->flags &= ~UPF_DEAD; out:mutex_unlock(&port->mutex);mutex_unlock(&port_mutex);return ret;}

uart_configure_port

static void uart_configure_port(struct uart_driver *drv, struct uart_state *state,struct uart_port *port){unsigned int flags;if (!port->iobase && !port->mapbase && !port->membase)return;flags = 0;if (port->flags & UPF_AUTO_IRQ)//设置可中断标志flags |= UART_CONFIG_IRQ;if (port->flags & UPF_BOOT_AUTOCONF) {//设置自动配置标志if (!(port->flags & UPF_FIXED_TYPE)) {port->type = PORT_UNKNOWN;flags |= UART_CONFIG_TYPE;}port->ops->config_port(port, flags);//调用uart_port的config_port方法}if (port->type != PORT_UNKNOWN) {unsigned long flags;uart_report_port(drv, port);uart_change_pm(state, 0);spin_lock_irqsave(&port->lock, flags);port->ops->set_mctrl(port, port->mctrl & TIOCM_DTR);//调用uart_port的set_mctrl方法spin_unlock_irqrestore(&port->lock, flags);if (port->cons && !(port->cons->flags & CON_ENABLED))//若console存在且设置了CON_ENABLED标志register_console(port->cons);//注册控制台设备if (!uart_console(port))uart_change_pm(state, 3);}}

 注销

int uart_remove_one_port(struct uart_driver *drv, struct uart_port *uport){struct uart_state *state = drv->state + uport->line;struct tty_port *port = &state->port;BUG_ON(in_interrupt());if (state->uart_port != uport)printk(KERN_ALERT "Removing wrong port: %p != %p\n",state->uart_port, uport);mutex_lock(&port_mutex);mutex_lock(&port->mutex);uport->flags |= UPF_DEAD;mutex_unlock(&port->mutex);tty_unregister_device(drv->tty_driver, uport->line);if (port->tty)tty_vhangup(port->tty);if (uport->type != PORT_UNKNOWN)uport->ops->release_port(uport);uport->type = PORT_UNKNOWN;tasklet_kill(&state->tlet);state->uart_port = NULL;mutex_unlock(&port_mutex);return 0;}

四.串口对应的tty_driver的操作函数集

1.tty的操作函数集uart_ops

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};

2.open方法

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);retval = -ENODEV;if (line >= tty->driver->num)goto fail;state = uart_get(drv, line);//获取uart_stateif (IS_ERR(state)) {retval = PTR_ERR(state);goto fail;}port = &state->port;//获取tty_porttty->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 (tty_hung_up_p(filp)) {retval = -EAGAIN;port->count--;mutex_unlock(&port->mutex);goto fail;}if (port->count == 1)uart_change_pm(state, 0);retval = uart_startup(tty, state, 0);//启动串口mutex_unlock(&port->mutex);if (retval == 0)retval = tty_port_block_til_ready(port, tty, filp);fail:return retval;}

uart_startup

static int uart_startup(struct tty_struct *tty, struct uart_state *state, int init_hw){struct uart_port *uport = state->uart_port;//获取uart_portstruct tty_port *port = &state->port;//获取tty_portunsigned long page;int retval = 0;if (port->flags & ASYNC_INITIALIZED)return 0;set_bit(TTY_IO_ERROR, &tty->flags);if (uport->type == PORT_UNKNOWN)return 0;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);//调用uart_port的startup方法if (retval == 0) {if (init_hw) {uart_change_speed(tty, state, NULL);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;}

3.写方法

static int uart_write(struct tty_struct *tty,const unsigned char *buf, int count){struct uart_state *state = tty->driver_data;//获取uart_statestruct uart_port *port;struct circ_buf *circ;unsigned long flags;int c, ret = 0;if (!state) {WARN_ON(1);return -EL3HLT;}port = state->uart_port;//获取uart_portcirc = &state->xmit;if (!circ->buf)return 0;spin_lock_irqsave(&port->lock, flags);while (1) {c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE);if (count < c)c = count;if (c <= 0)break;memcpy(circ->buf + circ->head, buf, c);circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1);buf += c;count -= c;ret += c;}spin_unlock_irqrestore(&port->lock, flags);uart_start(tty);//调用uart_start方法return ret;}

uart_start

static void uart_start(struct tty_struct *tty){struct uart_state *state = tty->driver_data;//获取tty_statestruct uart_port *port = state->uart_port;//获取uart_portunsigned long flags;spin_lock_irqsave(&port->lock, flags);__uart_start(tty);//调用__uart_start函数spin_unlock_irqrestore(&port->lock, flags);}

uart_start>>>__uart_start

static void __uart_start(struct tty_struct *tty){struct uart_state *state = tty->driver_data;//获取uart_statestruct uart_port *port = state->uart_port;//获取uart_portif (!uart_circ_empty(&state->xmit) && state->xmit.buf &&!tty->stopped && !tty->hw_stopped)port->ops->start_tx(port);//调用uart_port的start_tx方法}