linux serial framework (2) - serial 8250 driver

  • http://www.wowotech.net/tty_framework/435.html
  • https://www.codeleading.com/article/13543009429/

1.UART 框架图
在这里插入图片描述
串口驱动相关数据结构:

struct uart_driver;		//串口驱动结构
struct uart_port;		//端口结构,串口驱动只有一个,端口却有多个,一个端口对应一个实际的串口
struct uart_ops;		//函数操作集
struct uart_state;		//状态结构
struct uart_info;		//串口信息结构

2.8250/16550 chip

  • drivers/tty/serial/8250/8250_of.c
  • drivers/tty/serial/8250/8250_core.c
  • drivers/tty/serial/8250/8250_port.c

代码分析:

  • serial8250_init()—>uart_register_driver(&serial8250_reg)

  • serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev)

  • serial8250_probe(struct platform_device *dev)

2.1.串口驱动初始化
在这里插入图片描述

  初始化函数为serial8250_init(),代码如下:

  drivers/tty/serial/8250/8250_core.c:
  1142 static int __init serial8250_init(void)
  1143 {
    
    
  1144     int ret;
  1149     serial8250_isa_init_ports();
  1150
  1154 #ifdef CONFIG_SPARC
  1155     ret = sunserial_register_minors(&serial8250_reg, UART_NR);
  1156 #else
  1157     serial8250_reg.nr = UART_NR;
  1158     ret = uart_register_driver(&serial8250_reg);
  1159 #endif
  1163     ret = serial8250_pnp_init();
  1167     serial8250_isa_devs = platform_device_alloc("serial8250",
  1168                             PLAT8250_DEV_LEGACY);
  1174     ret = platform_device_add(serial8250_isa_devs);
  1178     serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev);
  1180     ret = platform_driver_register(&serial8250_isa_driver);
  1181    }

  uart_register_driver(&serial8250_reg); 函数将参数serial8250_reg注册进了tty层。具体代码如下所示:

 2486 int uart_register_driver(struct uart_driver *drv)                                                                                                                                                           
  2487 {
    
    
  2488     struct tty_driver *normal;
  2489     int i, retval;

  2497     drv->state = kcalloc(drv->nr, sizeof(struct uart_state), GFP_KERNEL);
  2500 
  2501     normal = alloc_tty_driver(drv->nr);
  2504 
  2505     drv->tty_driver = normal;
  2506 
  2507     normal->driver_name = drv->driver_name;
  2508     normal->name        = drv->dev_name;
  2509     normal->major       = drv->major;
  2510     normal->minor_start = drv->minor;
  2511     normal->type        = TTY_DRIVER_TYPE_SERIAL;
  2512     normal->subtype     = SERIAL_TYPE_NORMAL;
  2513     normal->init_termios    = tty_std_termios;
  2514     normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
  2515     normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
  2516     normal->flags       = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
  2517     normal->driver_state    = drv;
  2518     tty_set_operations(normal, &uart_ops);
  2523     for (i = 0; i < drv->nr; i++) {
    
    
  2524         struct uart_state *state = drv->state + i;
  2525         struct tty_port *port = &state->port;
  2526 
  2527         tty_port_init(port);
  2528         port->ops = &uart_port_ops;
  2529     }
  2530 
  2531     retval = tty_register_driver(normal);
  2534 
  2535     for (i = 0; i < drv->nr; i++)
  2536         tty_port_destroy(&drv->state[i].port);
  2537     put_tty_driver(normal);
  2540 out:
  2541     return -ENOMEM;
  2542 }

  从上面代码可以看出,uart_driver中很多数据结构其实就是tty_driver中的,将数据转换为tty_driver之后,tty_register_driver注册tty_driver。然后初始化uart_driver->state的存储空间。这里有两个地方我们需要特别关注:

第一个需要关注的地方:

normal->driver_state = drv;

  将参数的ops关系都赋给了serial_core层。也就是说在后面serial_core会根据uart_ops关系找到8250.c中所对应的操作,而参数中的ops是在哪被赋值的呢?这个一定是会在8250.c,定位到了8250.c中的serial8250_ops结构体,初始化如下:

drivers/tty/serial/8250/8250_port.c:
static struct uart_ops serial8250_pops = {
    
      
    .tx_empty   = serial8250_tx_empty,  
    .set_mctrl  = serial8250_set_mctrl,  
    .get_mctrl  = serial8250_get_mctrl,  
    .stop_tx    = serial8250_stop_tx,  
    .start_tx   = serial8250_start_tx,  
    .stop_rx    = serial8250_stop_rx,  
    .enable_ms  = serial8250_enable_ms,  
    .break_ctl  = serial8250_break_ctl,  
    .startup    = serial8250_startup,  
    .shutdown   = serial8250_shutdown,  
    .set_termios    = serial8250_set_termios,  //串口clk,波特率,数据位等参数设置 
    .pm     = serial8250_pm,  
    .type       = serial8250_type,  
    .release_port   = serial8250_release_port,  
    .request_port   = serial8250_request_port,  
    .config_port    = serial8250_config_port,  
    .verify_port    = serial8250_verify_port,  
#ifdef CONFIG_CONSOLE_POLL  
    .poll_get_char = serial8250_get_poll_char,  
    .poll_put_char = serial8250_put_poll_char,  
#endif  
}; 


同理:
static struct uart_ops <strong>s3c24xx_serial_ops </strong>={
    
    
      .pm         =s3c24xx_serial_pm,   //电源管理函数
      .tx_empty       = s3c24xx_serial_tx_empty, //检车发送FIFO缓冲区是否空
      .get_mctrl       = s3c24xx_serial_get_mctrl, //是否串口流控
      .set_mctrl       = s3c24xx_serial_set_mctrl, //是否设置串口流控cts
       .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,   //发送break信号
       .startup    =s3c24xx_serial_startup,   //串口发送/接收,以及中断申请初始配置函数
      .shutdown       = s3c24xx_serial_shutdown,  //关闭串口
      .set_termios    = s3c24xx_serial_set_termios,//串口clk,波特率,数据位等参数设置
      .type             = s3c24xx_serial_type,  // CPU类型关于串口
       .release_port   =s3c24xx_serial_release_port,  //释放串口
       .request_port   =s3c24xx_serial_request_port, //申请串口
      .config_port    = s3c24xx_serial_config_port,  //串口的一些配置信息info
      .verify_port    = s3c24xx_serial_verify_port,  //串口检测
      .wake_peer    = s3c24xx_serial_wake_peer,
};

  这样一来只要将serial8250_ops结构体成员的值赋给uart_dirver就可以了,那么这个过程在哪呢?就是在uart_add_one_port()函数中,这个函数是从serial8250_init->serial8250_register_ports()->uart_add_one_port()逐步调用过来的,这一步就将port和uart_driver联系起来了。serial8250_pops 定义硬件操作实现:

  • tx_empty: serial8250_tx_empty
    读取并判断LSR的第THRE、TEMT位是否为1

  • set_mctrl: serial8250_set_mctrl
    将位设置(RTS、DTR、OUT1、OUT2、LOOP)写入MCR

  • get_mctrl: serial8250_get_mctrl
    读取MSR, 即Modem Interface的当前状态

  • stop_tx: serial8250_stop_tx
    禁用IER的THRI/ETBEI位

  • start_tx: serial8250_start_tx
    启用IER的THRI/ETBEI位; 当LSR的THRE位为1, 通过操作THR将circ_buf的数据搬运至UART

  • stop_rx: serial8250_stop_rx
    禁用IER的RLSI/ELSI和RDI/ERBFI位

  • enable_ms: serial8250_enable_ms
    启用IER的MSI/EDSSI

  • break_ctl: serial8250_break_ctl
    启动或者禁用LCR的SBC/SetBreak位

  • startup: serial8250_startup

    • 设置FCR清空FIFO缓冲区, 清空中断寄存器(LSR、RX、IIR、MSR), 初始化相关寄存器
    • 调用uart_8250_ops::setup_irq(univ8250_setup_irq)
    • 设置MCR寄存器
    • 为TX/RX请求DMA通道
  • set_termios: serial8250_set_termios
    设置相关寄存器(…)

  • set_ldisc: serial8250_set_ldisc
    如果没有设置了Modem状态, 则禁用IER的MSI位

  • type: serial8250_type
    获取硬件名称

  • release_port: serial8250_release_port
    释放端口占用物理资源, 如Memory, I/O

  • request_port: serial8250_request_port
    请求物理资源

  • config_port: serial8250_config_port
    按照传入参数配置端口

  • verify_port: serial8250_verify_port
    校验端口配置是否有效

第二个需要关注的地方:

tty_set_operations(normal, &uart_ops);

  将tty_driver的操作集统一设为了uart_ops,这样就使得从用户空间下来的操作可以找到正确的serial_core的操作函数,这样就保证了调用关系的通畅。uart_ops是在serial_core.c中的:

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  
    .read_proc  = uart_read_proc,  
#endif  
    .tiocmget   = uart_tiocmget,  
    .tiocmset   = uart_tiocmset,  
#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.2.注册uart_driver

  对应uart_driver的结构为serial8250_reg,定义如下:

   703 static struct uart_driver serial8250_reg = {
    
                                                                                                                                                                    
   704     .owner          = THIS_MODULE,
   705     .driver_name        = "serial",
   706     .dev_name       = "ttyS",
   707     .major          = TTY_MAJOR,
   708     .minor          = 64,
   709     .cons           = SERIAL8250_CONSOLE,
   710 };

  从上面可以看出,串口对应的设备节点为/dev/ttyS0 ~ /dev/ttyS0(UART_NR),设备节点号为(4 64)起始的UART_NR个节点。

2.3.初始化并注册platform_device

  龙芯3a4000 CPU有两个串口驱动,设备定义如下:

   arch/mips/loongson64/common/serial.c:
   54 static struct platform_device uart8250_device = {
    
    
   55     .name = "serial8250",
   56     .id = PLAT8250_DEV_PLATFORM,
   57 };

注册设备:

platform_device_register(&uart8250_device);

  另外添加设备serial8250_isa_devs:

serial8250_isa_devs = platform_device_alloc("serial8250", PAT8250_DEV_LEGACY);
platform_device_add(serial8250_isa_devs);

  serial8250_isa_devs->name为serial8250,这个参数是在匹配platform_device和platform_driver使用的。

2.4.为uart-driver添加port

相关代码如下:

serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev)
   569 static void __init
   570 serial8250_register_ports(struct uart_driver *drv, struct device *dev)                                                                                                                                      
   571 {
    
    
   572     int i;
   573     
   574     for (i = 0; i < nr_uarts; i++) {
    
    
   575         struct uart_8250_port *up = &serial8250_ports[i];
   576     
   577         if (up->port.type == PORT_8250_CIR)
   578             continue;
   579 
   580         if (up->port.dev)
   581             continue;
   582 
   583         up->port.dev = dev;
   584 
   585         serial8250_apply_quirks(up);
   586         uart_add_one_port(drv, &up->port);
   587     }
   588 }

  初始化port,然后将挂添加到uart-driver中。生成的deivce节点,在sysfs中是位于platform_deivce对应目录的下面。

  serial8250_isa_init_ports()代码如下所示:

   503 static void __init serial8250_isa_init_ports(void)
   504 {
    
    
   505     struct uart_8250_port *up;
   506     static int first = 1;
   507     int i, irqflag = 0;
   518 
   519     for (i = 0; i < nr_uarts; i++) {
    
    
   520         struct uart_8250_port *up = &serial8250_ports[i];
   521         struct uart_port *port = &up->port;
   522 
   523         port->line = i;
   524         serial8250_init_port(up);  //port->ops = &serial8250_pops;
   525         if (!base_ops)
   526             base_ops = port->ops;
   527         port->ops = &univ8250_port_ops;
   528 
   529         timer_setup(&up->timer, serial8250_timeout, 0);
   530 
   531         up->ops = &univ8250_driver_ops;
   532 
   533         /*
   534          * ALPHA_KLUDGE_MCR needs to be killed.
   535          */
   536         up->mcr_mask = ~ALPHA_KLUDGE_MCR;
   537         up->mcr_force = ALPHA_KLUDGE_MCR;
   538     }
   539 
   540     /* chain base port ops to support Remote Supervisor Adapter */
   541     univ8250_port_ops = *base_ops;                                                                                                                                                                          
   542     univ8250_rsa_support(&univ8250_port_ops);
   543 
   547     for (i = 0, up = serial8250_ports;
   548          i < ARRAY_SIZE(old_serial_port) && i < nr_uarts;
   549          i++, up++) {
    
    
   550         struct uart_port *port = &up->port;
   551 
   552         port->iobase   = old_serial_port[i].port;
   553         port->irq      = irq_canonicalize(old_serial_port[i].irq);
   554         port->irqflags = 0;
   555         port->uartclk  = old_serial_port[i].baud_base * 16;
   556         port->flags    = old_serial_port[i].flags;
   557         port->hub6     = 0;
   558         port->membase  = old_serial_port[i].iomem_base;
   559         port->iotype   = old_serial_port[i].io_type;
   560         port->regshift = old_serial_port[i].iomem_reg_shift;
   561         serial8250_set_defaults(up);
   562 
   563         port->irqflags |= irqflag;
   564         if (serial8250_isa_config != NULL)
   565             serial8250_isa_config(i, &up->port, &up->capabilities);
   566     }
   567 }

  两个for循环内的操作:

  • 第一个for循环功能是初始化定时器功能函数up->timer.function = serial8250_timeout; 初始化serial8250 port的操作函数 port->ops = &serial8250_pops; 这个接口serial8250_pops内有关于port操作函数挂载。
  • 第二个for循环功能是初始化默认port硬件参数old_serial_port[i].port。

2.5.注册platform_driver

相关代码如下:

platform_driver_register(&serial8250_isa_driver);
serial8250_isa_driver定义如下:
   900 static struct platform_driver serial8250_isa_driver = {
    
                                                                                                                                                         
   901     .probe      = serial8250_probe,
   902     .remove     = serial8250_remove,
   903     .suspend    = serial8250_suspend,
   904     .resume     = serial8250_resume,
   905     .driver     = {
    
    
   906         .name   = "serial8250",
   907     },
   908 }; 

  这个platform的name为” serial8250”,刚好跟前面注册的platform_device相匹配,会调用platform_driver-> probe,在这里对应的接口为: serial8250_probe(),代码如下:

   811 static int serial8250_probe(struct platform_device *dev)
   812 {
    
    
   813     struct plat_serial8250_port *p = dev_get_platdata(&dev->dev);
   814     struct uart_8250_port uart;                                                                                                                                                                             
   815     int ret, i, irqflag = 0;
   816 
   817     memset(&uart, 0, sizeof(uart));
   818 
   819     if (share_irqs)
   820         irqflag = IRQF_SHARED;
   821 
   822     for (i = 0; p && p->flags != 0; p++, i++) {
    
    
   823         uart.port.iobase    = p->iobase;
   824         uart.port.membase   = p->membase;
   825         uart.port.irq       = p->irq;
   826         uart.port.irqflags  = p->irqflags;
   827         uart.port.uartclk   = p->uartclk;
   828         uart.port.regshift  = p->regshift;
   829         uart.port.iotype    = p->iotype;
   830         uart.port.flags     = p->flags;
   831         uart.port.mapbase   = p->mapbase;
   832         uart.port.hub6      = p->hub6;
   833         uart.port.private_data  = p->private_data;
   834         uart.port.type      = p->type;
   835         uart.port.serial_in = p->serial_in;
   836         uart.port.serial_out    = p->serial_out;
   837         uart.port.handle_irq    = p->handle_irq;
   838         uart.port.handle_break  = p->handle_break;
   839         uart.port.set_termios   = p->set_termios;
   840         uart.port.set_ldisc = p->set_ldisc;
   841         uart.port.get_mctrl = p->get_mctrl;
   842         uart.port.pm        = p->pm;
   843         uart.port.dev       = &dev->dev;
   844         uart.port.irqflags  |= irqflag;
   845         ret = serial8250_register_8250_port(&uart);
   853     return 0;
   854 }

注册调用流程:

  serial8250_register_8250_port->uart_add_one_port

  /* 将 uart_port 注册到 uart_driver */
  2755 int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)                                                                                                                                     
  2756 {
    
    
  2757     struct uart_state *state;
  2758     struct tty_port *port;
  2759     int ret = 0;
  2760     struct device *tty_dev;
  2761     int num_groups;                                                                                                                        
  2804     ...
  
		/* 实际调用 port->ops->config_port(port, flags) 稍后再看 */
  2805     uart_configure_port(drv, state, uport);
  2807     port->console = uart_console(uport);
  2827     tty_dev = tty_port_register_device_attr_serdev(port, drv->tty_driver,
  2828             uport->line, uport->dev, port, uport->tty_groups);
  2835 
  2845     return ret;
  • uart_configure_port
    • port->ops->config_port(port, flags); //serial8250_config_port

3.Changing serial ports configuration

  • To get current configuration
# stty -F /dev/ttyS0 -a
speed 57600 baud; rows 0; columns 0; line = 0;
intr = <undef>; quit = <undef>; erase = <undef>; kill = <undef>; eof = <undef>; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = <undef>; stop = <undef>; susp = <undef>; rprnt = <undef>; werase = <undef>;
lnext = <undef>; discard = <undef>; min = 1; time = 1;
-parenb -parodd cs8 -hupcl -cstopb cread clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany -imaxbel -iutf8
-opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
-isig -icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt -echoctl -echoke -flusho -extproc
  • To only get actual speed:
# stty -F /dev/ttyS0  speed
115200
  • To change baudrate to 115200 :
# stty -F /dev/ttyS0 ispeed 115200 ospeed 115200 cs8

3.1.Sending/Receiving data

  • Sending data to it:

echo “HELLO” > /dev/ttyS3

代码调用流程:
uart_open
  ->tty_port_open
    ->int retval = port->ops->activate(port, tty);//uart_port_activate
      ->uart_startup
        ->retval = uport->ops->startup(uport); //serial8250_startup
          ->serial8250_startup
            ->serial8250_do_startup
              ->retval = up->ops->setup_irq(up);
                -->univ8250_setup_irq
                  ->serial_link_irq_chain // ret = request_irq(up->port.irq, serial8250_interrupt, irq_flags, up->port.name, i);
                    ->serial8250_interrupt
                      ->port->handle_irq(port)
                        ->serial8250_handle_irq
                          ->serial8250_rx_chars
                          ->serial8250_tx_chars

  • To receive data (ASCII in that case):

cat /dev/ttyS3

3.2.Statistics

# cat /proc/tty/driver/serial 
serinfo:1.0 driver revision:
0: uart:ST16650 mmio:0x1FE001E0 irq:88 tx:211 rx:0 RTS|CTS|DTR|DSR|CD|RI
1: uart:ST16650 mmio:0x1FE001E8 irq:58 tx:0 rx:0 CTS|DSR|CD|RI
2: uart:Loongson 16550 mmio:0x10080000 irq:24 tx:211 rx:0 RTS|DTR|CD|RI
3: uart:unknown port:00000000 irq:0
4: uart:unknown port:00000000 irq:0
5: uart:unknown port:00000000 irq:0
6: uart:unknown port:00000000 irq:0
7: uart:unknown port:00000000 irq:0
8: uart:unknown port:00000000 irq:0
9: uart:unknown port:00000000 irq:0
10: uart:unknown port:00000000 irq:0
11: uart:unknown port:00000000 irq:0
12: uart:unknown port:00000000 irq:0
13: uart:unknown port:00000000 irq:0
14: uart:unknown port:00000000 irq:0
15: uart:unknown port:00000000 irq:0

3.3. ttyS0 节点信息

#/sys/class/tty/ttyS0$ ls -l
总用量 0
-r--r----- 1 root root 16384 1112 14:08 close_delay
-r--r----- 1 root root 16384 1112 14:08 closing_wait
-r--r----- 1 root root 16384 1112 14:08 custom_divisor
-r--r--r-- 1 root root 16384 1112 14:08 dev
lrwxrwxrwx 1 root root     0 1112 13:47 device -> ../../../serial8250.0
-r--r----- 1 root root 16384 1112 14:08 flags
-r--r----- 1 root root 16384 1112 14:08 iomem_base
-r--r----- 1 root root 16384 1112 14:08 iomem_reg_shift
-r--r----- 1 root root 16384 1112 14:08 io_type
-r--r----- 1 root root 16384 1112 14:08 irq
-r--r----- 1 root root 16384 1112 14:08 line
-r--r----- 1 root root 16384 1112 14:08 port
drwxr-xr-x 2 root root     0 1112 14:08 power
lrwxrwxrwx 1 root root     0 1112 13:47 subsystem -> ../../../../../class/tty
-r--r----- 1 root root 16384 1112 14:08 type
-r--r----- 1 root root 16384 1112 14:08 uartclk
-rw-r--r-- 1 root root 16384 1112 13:47 uevent
-r--r----- 1 root root 16384 1112 14:08 xmit_fifo_size
uos@uos-PC:/sys/class/tty/ttyS0$ cat uartclk 

3.4.设置波特率

  将串口1(/dev/ttyS0)设置成115200波特率,8位数据模式。

# stty -F /dev/ttyS0 ispeed 115200 ospeed 115200 cs8
# stty -F /dev/ttyS0 -a         //查看设置信息

stty应用程序调用流程:

tty_ioctl->tty_mode_ioctl->set_termios->uart_set_termios

3.5.Use the setserial command to check and use serial ports

  The setserial is a program designed to set and/or report the configuration information associated with a serial port. This information includes what I/O port and IRQ a particular serial port is using, and whether or not the break key should be interpreted as the Secure Attention Key, and so on.

Using setserial to list serial ports and devices
Now we installed required package. Open the termial and then type the following setserial command:
$ setserial -g /dev/ttyS[0123]

If you get an error/warning that reads as “Permission denied,” try running the command as the root user. For example, I am running it using the sudo command/su command:
$ sudo setserial -g /dev/ttyS[0123]

The setserial with -g option help to find out what physical serial ports your Linux box has.

refer to

  • https://tldp.org/HOWTO/Serial-HOWTO.html
  • http://www.wowotech.net/tty_framework/435.html
  • https://www.geek-share.com/detail/2677828880.html
  • https://developer.aliyun.com/article/375411
  • https://www.cnblogs.com/hzl6255/p/9560138.html
  • http://www.armadeus.org/wiki/index.php?title=Serial_ports_usage_on_Linux

猜你喜欢

转载自blog.csdn.net/weixin_41028621/article/details/109364125
今日推荐