• 串口驱动程序的编写总结(二)


    功能实现:

         通过虚拟多个串口,实现用户层与驱动层数据的回环测试

    linux驱动有个特点:

        结构体定义都是在底层驱动程序所定义好的。

         通过container of()函数查找到被包含结构体的首地址。

        就比如结构体:

        底层  struct uart_8250_port canserial_ports[4];

               其结构体如下:

            

    struct uart_8250_port {
        struct uart_port    port;
        struct timer_list    timer;        /* "no irq" timer */
        struct list_head    list;        /* ports on this IRQ */
        unsigned short        capabilities;    /* port capabilities */
        unsigned short        bugs;        /* port bugs */
        bool            fifo_bug;    /* min RX trigger if enabled */
        unsigned int        tx_loadsz;    /* transmit fifo load size */
        unsigned char        acr;
        unsigned char        fcr;
        unsigned char        ier;
        unsigned char        lcr;
        unsigned char        mcr;
        unsigned char        mcr_mask;    /* mask of user bits */
        unsigned char        mcr_force;    /* mask of forced bits */
        unsigned char        cur_iotype;    /* Running I/O type */
        unsigned int        rpm_tx_active;
    
        /*
         * Some bits in registers are cleared on a read, so they must
         * be saved whenever the register is read but the bits will not
         * be immediately processed.
         */
    #define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
        unsigned char        lsr_saved_flags;
    #define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
        unsigned char        msr_saved_flags;
    
        struct uart_8250_dma    *dma;
        struct serial_rs485     rs485;
    
        /* 8250 specific callbacks */
        int            (*dl_read)(struct uart_8250_port *);
        void            (*dl_write)(struct uart_8250_port *, int);
        int            (*rs485_config)(struct uart_8250_port *,
                            struct serial_rs485 *rs485);
    };

         其结构体包含上层结构体struct uart_port。

         

    2、

    platform 虚拟总线的挂载方法:

       platform_device_alloc()、platform_device_add()、platform_driver_register()这三个函数

      两个结构体:

      

    struct platform_device *canserial_isa_devs、
      
    
    static struct platform_driver canserial_isa_driver = {
    .probe    = canserial_probe,
    .remove    = canserial_remove,
    .suspend    = canserial_suspend,
    .resume    = canserial_resume,
    .driver    = {
    .name    = "canserial8250",
    .owner    = THIS_MODULE,
    },
    };

    通过.name=“canserial8250”进行设备与驱动的匹配。

    通过 canserial_register_ports(&canserial_reg, &canserial_isa_devs->dev);函数将platform device 与 uart_driver 做挂钩。

    参看platform设备驱动的注册:http://blog.csdn.net/lidaqiang99/article/details/6602647

    通过 uart_register_driver(&canserial_reg); 将底层驱动注册上。

    serial_can_init()

        ->canserial_isa_init_ports()  串口初始化及绑定底层串口操作函数

       

    #include <linux/module.h>
    #include <linux/moduleparam.h>
    #include <linux/ioport.h>
    #include <linux/init.h>
    #include <linux/console.h>
    #include <linux/sysrq.h>
    #include <linux/delay.h>
    #include <linux/platform_device.h>
    #include <linux/tty.h>
    #include <linux/ratelimit.h>
    #include <linux/tty_flip.h>
    #include <linux/serial_core.h>
    #include <linux/serial.h>
    #include <linux/serial_8250.h>
    #include <linux/nmi.h>
    #include <linux/mutex.h>
    #include <linux/slab.h>
    #include <linux/uaccess.h>
    #include <linux/pm_runtime.h>
    
    #include <asm/io.h>
    
    #include <asm/serial.h>
    
    #include "mycan_drive.h"
    
    
    
    #define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
    #define PORT_8250 1
    
    #define S3C2410_LCON_PNONE      (0x0)
    #define S3C2410_LCON_PEVEN      (0x5 << 3)
    #define S3C2410_LCON_PODD      (0x4 << 3)
    #define UART_LCR_WLEN5  0x00    /* Wordlength: 5 bits */
    #define UART_LCR_WLEN6  0x01    /* Wordlength: 6 bits */
    #define UART_LCR_WLEN7  0x02    /* Wordlength: 7 bits */
    #define UART_LCR_WLEN8  0x03    /* Wordlength: 8 bits */
    #define UART_LCR_EPAR    0x10    /* Even parity select */
    #define UART_LCR_SPAR    0x20    /* Stick parity (?) */
    #define UART_LCR_STOP    0x04    /* Stop bits: 0=1 stop bit, 1= 2 stop bits */
    #define UART_LCR_PARITY    0x08    /* Parity Enable */
    
    
    #include <linux/netdevice.h>
    #include <linux/can.h>
    
    // {    X:jundasvnS1606_KernelV4	runksourcelinux-3.18includeuapilinuxcan.h
    
    static DEFINE_MUTEX(serial_mutex);
    /*
     * This "device" covers _all_ ISA 8250-compatible serial devices listed
     * in the table in include/asm/serial.h
     */
    static struct platform_device *canserial_isa_devs;
    
    static int cnt_flag = 0;
    
    // #ifndef SERIAL_PORT_DFNS
    // #define SERIAL_PORT_DFNS
    // #endif
    // static const struct old_serial_port old_serial_port[] = {
    //     SERIAL_PORT_DFNS /* defined in asm/serial.h */
    // };
    
    
    
    // static unsigned int nr_uarts = CONFIG_SERIAL_8250_RUNTIME_UARTS;
    // #define UART_NR    CONFIG_SERIAL_8250_NR_UARTS
    static unsigned int nr_uarts = 15;
    #define UART_NR    15
    
    static struct uart_driver canserial_reg;
    
    
    extern struct sja1000_priv m_ppriv;
    
    
    
    // can 发送数据格式
    struct can_frame cf;
    /*
     * Debugging.
     */
    #if 0
    #define DEBUG_AUTOCONF(fmt...)    printk(fmt)
    #else
    #define DEBUG_AUTOCONF(fmt...)    do { } while (0)
    #endif
    
    #if 0
    #define DEBUG_INTR(fmt...)    printk(fmt)
    #else
    #define DEBUG_INTR(fmt...)    do { } while (0)
    #endif
    
    
    #include <asm/serial.h>
    
    struct can_serial_port {
        unsigned char            rx_claimed;
        unsigned char            tx_claimed;
    
        // struct s3c24xx_uart_info    *info;
        // struct s3c24xx_uart_clksrc    *clksrc;
        struct clk            *clk;
        struct clk            *baudclk;
        struct uart_port        port;
    };
    
    
    // 参数: 串口地址、功能码、读写位、版本号
    uint32_t GetCanAddrMask(uint32_t PortComID,uint8_t ngnvlaue,uint8_t nrwstatus,uint8_t nrver)
    {
        uint32_t u32ID=0;
        uint8_t naddr=0,nstrport=0,nrw=0,ngn=0,data_group=0;
        if(PortComID<5){
            naddr=1;    
        }
        else if(PortComID<10){
            naddr=2;    
        }
        else if(PortComID<15){
            naddr=3;    
        }
        nstrport=PortComID%5;//子地址 端口号 0~4
        nrw=nrwstatus;//读写
        ngn=ngnvlaue;//功能码
        u32ID |=(nrver<<24);//版本号
        u32ID |=(data_group<<16); // 数据组
        u32ID |=(ngn<<8);//功能码
        u32ID |=(nrw<<7);// 读写位
        u32ID |=(nstrport<<4); //子地址
        u32ID |=naddr; //设备地址
    
        
        return u32ID;
    
    }
    
    
    
    //额外的函数
    static inline struct can_serial_port *to_ourport(struct uart_port *port)
    {
        return container_of(port, struct can_serial_port, port);
    }
    
    
    
    
     /**************************************************************/
    
    static void canserial_stop_tx(struct uart_port *port)
    {
        printk("canserial_stop_tx
    ");
    }
    
    static void canserial_start_tx(struct uart_port *port)
    {
    
        unsigned char ch;
    
        printk("canserial_start_tx line:%d
    ",port->line);
    
        //printk("the base_driver receive data  is %s
    ",port->state->xmit.buf);
    
        struct circ_buf *xmit = &port->state->xmit;
    
        // 进行数据的打包
        // 设备地址4bit、子地址(串口号地址)3、读写1、功能码8、数据组8、版本4
         
         /*
            参数: 串口地址、功能码、读写位、版本号
          */
        int m_can_id = GetCanAddrMask(port->line,0,0,1);
    
    
        // 在这里调用can驱动程序进行数据发送
         // cf.can_id = CAN_EFF_FLAG | 0x00000123; 
         cf.can_id = CAN_EFF_FLAG | m_can_id; 
         int tx_cnt_port=0;
          while(!uart_circ_empty(xmit))
         {
            ch= xmit->buf[xmit->tail];
            cf.data[tx_cnt_port] =  ch;
            tx_cnt_port++;
            xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
            port->icount.rx++;
         }
    
         cf.can_dlc = tx_cnt_port;
    
        mysja1000_start_xmit(&cf, &m_ppriv);
    
    
    
    
    
    
    
    
    
    
    
    
        uart_circ_clear(&port->state->xmit);
    
    }
    
    static void canserial_throttle(struct uart_port *port)
    {
        printk("canserial_throttle
    ");
        
    }
    
    static void canserial_unthrottle(struct uart_port *port)
    {
        printk("canserial_unthrottle
    ");
    }
    
    static void canserial_stop_rx(struct uart_port *port)
    {
        printk("canserial_stop_rx
    ");
        
    }
    
    static void canserial_enable_ms(struct uart_port *port)
    {
        printk("canserial_enable_ms
    ");
    
    }
    
    /*
     * canserial_rx_chars: processes according to the passed in LSR
     * value, and returns the remaining LSR bits not handled
     * by this Rx routine.
     */
    unsigned char
    canserial_rx_chars(struct uart_8250_port *up, unsigned char lsr)
    {
        printk("canserial_rx_chars
    ");
    
     //    spin_unlock(&port->lock);
        // tty_flip_buffer_push(&port->state->port);
        // spin_lock(&port->lock);
        return 0;
    }
    
    void canserial_tx_chars(struct uart_8250_port *up)
    {
        printk("canserial_tx_chars
    ");
        
    }
    
    static unsigned int canserial_tx_empty(struct uart_port *port)
    {
        printk("canserial_tx_empty
    ");
    
        return 0;
    }
    
    static unsigned int canserial_get_mctrl(struct uart_port *port)
    {
    
        printk("canserial_get_mctrl
    ");
    
        return 0;
    }
    
    static void canserial_set_mctrl(struct uart_port *port, unsigned int mctrl)
    {
    
        printk("canserial_set_mctrl
    ");
    
    }
    
    static void canserial_break_ctl(struct uart_port *port, int break_state)
    {
        printk("canserial_break_ctl
    ");
    
    }
    
    /*
     *    Wait for transmitter & holding register to empty
     */
    static void wait_for_xmitr(struct uart_8250_port *up, int bits)
    {
        printk("wait_for_xmitr
    ");
    
    }
    
    
    
    static int canserial_startup(struct uart_port *port)
    {
        printk("open first canserial_startup
    ");
    
     
       if(cnt_flag==0)
        {
            mytscan1_probe(&m_ppriv);
            mysja1000_set_bittiming(&m_ppriv);
            mysja1000_open(&m_ppriv);
        }
        
        cnt_flag++;
    
        // mysja1000_set_bittiming(&m_ppriv);
        return 0;
    }
    
    void canserial_do_shutdown(struct uart_port *port)
    {
        
    
        printk("canserial_do_shutdown
    ");
    }
    
    
    static void canserial_shutdown(struct uart_port *port)
    {
    
        cnt_flag--;
        if(cnt_flag == 0)
           mysja1000_close(&m_ppriv);
    
        printk("canserial_shutdown
    ");
    }
    
    static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud)
    {
        printk("serial8250_get_divisor
    ");
    }
    
    
    
    
    static void
    canserial_set_termios(struct uart_port *port, struct ktermios *termios,
                   struct ktermios *old)
    {
    
     //    struct net_device netdev;
     //    netdev.name = "can0";
     //    // netdev.ifindex = 
    
    
     
     //    struct can_frame can_data;
     //    can_data.can_id =  CAN_EFF_FLAG | 0x11;
     //    can_data.can_dlc = 1;
     //    can_data.data[0] = "Y";
    
    
     //    sk_buff_data.data = &can_data;
        // sja1000_start_xmit(&sk_buff_data,&netdev);
    
    
        printk("canserial_set_termios
    ");
        unsigned int baud, quot;
        unsigned char cval;
        unsigned int bitval;
    
       baud = uart_get_baud_rate(port, termios, old,0, 115200*8);
    
       
       // printk("termios->c_cflag :%d
    ",termios->c_cflag);
       // printk("termios->c_ispeed :%d
    ",termios->c_ispeed);
       // printk("termios->c_ospeed :%d
    ",termios->c_ospeed);
       // printk("termios->CBAUD :%d
    ",termios->c_cflag & CBAUD);
    
    
         switch (termios->c_cflag & CSIZE) {
        case CS5:
            cval = UART_LCR_WLEN5;
            break;
        case CS6:
            cval = UART_LCR_WLEN6;
            break;
        case CS7:
            cval = UART_LCR_WLEN7;
            break;
        default:
        case CS8:
            cval = UART_LCR_WLEN8;
            break;
        }
        // printk("serial8250_do_set_termios databit:%d
    ",cval);
    
    
        if (termios->c_cflag & CSTOPB)
            cval |= UART_LCR_STOP;
        
        // printk("serial8250_do_set_termios stopbit:%d
    ",cval);
    
    
        if (termios->c_cflag & PARENB) {
            cval |= UART_LCR_PARITY;
        }
        if (!(termios->c_cflag & PARODD))
            cval |= UART_LCR_EPAR;
    #ifdef CMSPAR
        if (termios->c_cflag & CMSPAR)
            cval |= UART_LCR_SPAR;
    #endif
    
        // printk("serial8250_do_set_termios chkbit:%d
    ",cval);
    
    
    
       // printk("port baud is %d
    ",baud);
    }
    
    static void
    canserial_set_ldisc(struct uart_port *port, int new)
    {
        printk("canserial_set_ldisc
    ");
    }
    
    
    void canserial_do_pm(struct uart_port *port, unsigned int state,
                  unsigned int oldstate)
    {    
        printk("canserial_do_pm
    ");
    }
    
    static void
    canserial_pm(struct uart_port *port, unsigned int state,
              unsigned int oldstate)
    {
    
        printk("canserial_pm
    ");
        // canserial_do_pm();
        // struct can_serial_port *ourport =  to_ourport(port);
         // pm_runtime_get_sync(port->dev);
    
         // printk("pm_runtime_get_sync after
    ");
    }
    
    static unsigned int canserial_port_size(struct uart_8250_port *pt)
    {
    
        printk("canserial_port_size
    ");
    
        
    }
    
    /*
     * Resource handling.
     */
    static int canserial_request_std_resource(struct uart_8250_port *up)
    {
        printk("canserial_request_std_resource
    ");
        return 0;
    }
    
    static void canserial_release_std_resource(struct uart_8250_port *up)
    {
        printk("canserial_release_std_resource
    ");
    }
    
    static int canserial_request_rsa_resource(struct uart_8250_port *up)
    { 
        printk("canserial_request_rsa_resource
    ");
        return 0;
    }
    
    static void canserial_release_rsa_resource(struct uart_8250_port *up)
    {
        printk("canserial_release_rsa_resource
    ");
    }
    
    static void canserial_release_port(struct uart_port *port)
    {
    
        printk("canserial_release_port
    ");
    
    
    }
    
    static int canserial_request_port(struct uart_port *port)
    {
        printk("canserial_request_port
    ");
        return 0;
    }
    
    static int fcr_get_rxtrig_bytes(struct uart_8250_port *up)
    {
        printk("fcr_get_rxtrig_bytes
    ");
        return 0;
    }
    
    static int bytes_to_fcr_rxtrig(struct uart_8250_port *up, unsigned char bytes)
    {
        printk("bytes_to_fcr_rxtrig
    ");
        return 0;
    }
    
    static int do_get_rxtrig(struct tty_port *port)
    {
        printk("do_get_rxtrig
    ");
        return 0;
    }
    
    static int do_canserial_get_rxtrig(struct tty_port *port)
    {
        printk("do_canserial_get_rxtrig
    ");
        return 0;
    }
    
    static ssize_t canserial_get_attr_rx_trig_bytes(struct device *dev,
        struct device_attribute *attr, char *buf)
    {
        
        printk("canserial_get_attr_rx_trig_bytes
    ");
        return 0;
        // return snprintf(buf, PAGE_SIZE, "%d
    ", rxtrig_bytes);
    }
    
    static int do_set_rxtrig(struct tty_port *port, unsigned char bytes)
    {
        printk("do_set_rxtrig
    ");
        return 0;
    }
    
    static int do_canserial_set_rxtrig(struct tty_port *port, unsigned char bytes)
    {
        printk("do_canserial_set_rxtrig
    ");
        return 0;
    }
    
    static ssize_t canserial_set_attr_rx_trig_bytes(struct device *dev,
        struct device_attribute *attr, const char *buf, size_t count)
    {
        printk("canserial_set_attr_rx_trig_bytes
    ");
        return 0;
    }
    
    
    
    
    static void register_dev_spec_attr_grp(struct uart_8250_port *up)
    {
        printk("register_dev_spec_attr_grp
    ");
    }
    
    static void canserial_config_port(struct uart_port *port, int flags)
    {
        printk("canserial_config_port
    ");
    
    }
    
    static int
    canserial_verify_port(struct uart_port *port, struct serial_struct *ser)
    {
        printk("canserial_verify_port
    ");
        return 0;
    }
    
    static int canserial_ioctl(struct uart_port *port, unsigned int cmd,
                   unsigned long arg)
    {
        // printk("canserial_ioctl cmd is %d
     ",cmd);
        // printk("canserial_ioctl
    ");
    
        // return 0;
    
    
        printk("canserial_ioctl cmd is %d
     ",cmd);
        
        struct uart_8250_port *up =
            container_of(port, struct uart_8250_port, port);
        int ret;
        struct serial_rs485 rs485_config;
    
        if (!up->rs485_config)
            return -ENOIOCTLCMD;
    
        switch (cmd) {
        case TIOCSRS485:
            if (copy_from_user(&rs485_config, (void __user *)arg,
                       sizeof(rs485_config)))
                return -EFAULT;
    
            ret = up->rs485_config(up, &rs485_config);
            if (ret)
                return ret;
    
            memcpy(&up->rs485, &rs485_config, sizeof(rs485_config));
    
            return 0;
        case TIOCGRS485:
            if (copy_to_user((void __user *)arg, &up->rs485,
                     sizeof(up->rs485)))
                return -EFAULT;
            return 0;
        default:
            break;
        }
    
        return -ENOIOCTLCMD;
    
    
    
    }
    
    static const char *
    canserial_type(struct uart_port *port)
    {
    
    }
    
    static struct uart_ops canserial_pops = {
        .tx_empty    = canserial_tx_empty,
        .set_mctrl    = canserial_set_mctrl,
        .get_mctrl    = canserial_get_mctrl,
        .stop_tx    = canserial_stop_tx,
        .start_tx    = canserial_start_tx,
        .throttle    = canserial_throttle,
        .unthrottle    = canserial_unthrottle,
        .stop_rx    = canserial_stop_rx,
        .enable_ms    = canserial_enable_ms,
        .break_ctl    = canserial_break_ctl,
        .startup    = canserial_startup,
        .shutdown    = canserial_shutdown,
        .set_termios    = canserial_set_termios,
        .set_ldisc    = canserial_set_ldisc,
        .pm        = canserial_pm,
        .type        = canserial_type,
        .release_port    = canserial_release_port,
        .request_port    = canserial_request_port,
        .config_port    = canserial_config_port,
        .verify_port    = canserial_verify_port,
        .ioctl        = canserial_ioctl,
    };
    
    struct uart_8250_port canserial_ports[UART_NR];
    
    /**
     * canserial_get_port - retrieve struct uart_8250_port
     * @line: serial line number
     *
     * This function retrieves struct uart_8250_port for the specific line.
     * This struct *must* *not* be used to perform a 8250 or serial core operation
     * which is not accessible otherwise. Its only purpose is to make the struct
     * accessible to the runtime-pm callbacks for context suspend/restore.
     * The lock assumption made here is none because runtime-pm suspend/resume
     * callbacks should not be invoked if there is any operation performed on the
     * port.
     */
    struct uart_8250_port *canserial_get_port(int line)
    {
        return &canserial_ports[line];
    }
    
    static void (*canserial_isa_config)(int port, struct uart_port *up,
        unsigned short *capabilities);
    
    void canserial_set_isa_configurator(
        void (*v)(int port, struct uart_port *up, unsigned short *capabilities))
    {
        canserial_isa_config = v;
    }
    //去除硬件信息
    static void __init canserial_isa_init_ports(void)
    {
        struct uart_8250_port *up;
        int i, irqflag = 0;
    
    
        if (nr_uarts > UART_NR)
            nr_uarts = UART_NR;
    
        for (i = 0; i < nr_uarts; i++) {
            struct uart_8250_port *up = &canserial_ports[i];
            struct uart_port *port = &up->port;
            port->line = i;
            port->ops = &canserial_pops;
        }
    
    
    
          for (i = 0, up = canserial_ports;i < nr_uarts;
             i++, up++) {
              printk("enter serial initialize
    ");
            struct uart_port *port = &up->port;
    
            // port->iobase   = old_serial_port[i].port;
            // port->irq      = 4;
            // port->irqflags = old_serial_port[i].irqflags;
            port->uartclk  = 1843200 ;
            port->flags    = STD_COM_FLAGS;
            port->type = PORT_8250_CIR;
            // port->hub6     = old_serial_port[i].hub6;
            // port->membase  = old_serial_port[i].iomem_base;
            // port->iotype   = old_serial_port[i].io_type;
            // port->regshift = old_serial_port[i].iomem_reg_shift;
            // set_io_from_upio(port);
            // port->irqflags |= irqflag;
            // if (serial8250_isa_config != NULL)
            //     serial8250_isa_config(i, &up->port, &up->capabilities);
    
        }
    
    
        
    }
    
    static void
    canserial_init_fixed_type_port(struct uart_8250_port *up, unsigned int type)
    {
        printk("canserial_init_fixed_type_port
    ");
    }
    
    static void __init
    canserial_register_ports(struct uart_driver *drv, struct device *dev)
    {
        int i;
        int ret;
        for (i = 0; i < nr_uarts; i++) {
            struct uart_8250_port *up = &canserial_ports[i];
    
            if (up->port.dev)
                continue;
    
            up->port.dev = dev;
    
            printk("uart add one port before
    ");
            ret = uart_add_one_port(drv, &up->port);
            printk("uart_add_one_port result %d
    ",ret);
        }
    }
    
    
    static struct uart_driver canserial_reg = {
        .owner            = THIS_MODULE,
        .driver_name        = "ttySAC",
        .dev_name        = "ttyS100",
        .major            = 5,
        .minor            = 64,
        .cons            = NULL,
    };
    
    
    /**
     *    canserial_suspend_port - suspend one serial port
     *    @line:  serial line number
     *
     *    Suspend one serial port.
     */
    void canserial_suspend_port(int line)
    {
        uart_suspend_port(&canserial_reg, &canserial_ports[line].port);
    }
    
    /**
     *    canserial_resume_port - resume one serial port
     *    @line:  serial line number
     *
     *    Resume one serial port.
     */
    void canserial_resume_port(int line)
    {
        printk("canserial_resume_port
    ");
    }
    
    /*
     * Register a set of serial devices attached to a platform device.  The
     * list is terminated with a zero flags entry, which means we expect
     * all entries to have at least UPF_BOOT_AUTOCONF set.
     */
    static int canserial_probe(struct platform_device *dev)
    {
        printk("Driver found device which my driver can handle!
    ");
    
        // struct uart_8250_port uart;
     //    for (int i = 0; i < 4; ++i)
     //    {
     //        uart.port.type = PORT_8250;
     //        ret = canserial_register_8250_port(&uart);
     //    }
    
        return 0;
    }
    
    /**
     *    canserial_register_8250_port - register a serial port
     *    @up: serial port template
     *
     *    Configure the serial port specified by the request. If the
     *    port exists and is in use, it is hung up and unregistered
     *    first.
     *
     *    The port is then probed and if necessary the IRQ is autodetected
     *    If this fails an error is returned.
     *
     *    On success the port is ready to use and the line number is returned.
     */
    int canserial_register_8250_port(struct uart_8250_port *up)
    {
        // struct uart_8250_port *uart;
        // int ret = -ENOSPC;
    
        // if (up->port.uartclk == 0)
        //     return -EINVAL;
    
        // mutex_lock(&serial_mutex);
    
        // // uart = serial8250_find_match_or_unused(&up->port);
        
    
        // mutex_unlock(&serial_mutex);
    
        // return ret;
    }
    
    
    void canserial_unregister_port(int line)
    {
        struct uart_8250_port *uart = &canserial_ports[line];
    
        mutex_lock(&serial_mutex);
        uart_remove_one_port(&canserial_reg, &uart->port);
        if (canserial_isa_devs) {
            // uart->port.flags &= ~UPF_BOOT_AUTOCONF;
            // uart->port.type = PORT_UNKNOWN;
            // uart->port.dev = &canserial_isa_devs->dev;
            // uart->capabilities = uart_config[uart->port.type].flags;
            uart_add_one_port(&canserial_reg, &uart->port);
        } else {
            uart->port.dev = NULL;
        }
        mutex_unlock(&serial_mutex);
    }
    
    
    
    /*
     * Remove serial ports registered against a platform device.
     */
    static int canserial_remove(struct platform_device *dev)
    {
        printk("Driver found device unpluged!
    ");
    
    
    
        int i;
        for (i = 0; i < nr_uarts; i++) {
            struct uart_8250_port *up = &canserial_ports[i];
    
            if (up->port.dev == &dev->dev)
                canserial_unregister_port(i);
        }
    
        return 0;
    }
    
    
    
    
    static int canserial_suspend(struct platform_device *dev, pm_message_t state)
    {
        return 0;
    }
    
    static int canserial_resume(struct platform_device *dev)
    {
    
        return 0;
    }
    
    static struct platform_driver canserial_isa_driver = {
        .probe        = canserial_probe,
        .remove        = canserial_remove,
        .suspend    = canserial_suspend,
        .resume        = canserial_resume,
        .driver        = {
            .name    = "canserial8250",
            .owner    = THIS_MODULE,
        },
    };
    
    
    
    /*
     * canserial_register_8250_port and canserial_unregister_port allows for
     * 16x50 serial ports to be configured at run-time, to support PCMCIA
     * modems and PCI multiport cards.
     */
    
    static struct uart_8250_port *canserial_find_match_or_unused(struct uart_port *port)
    {
        printk("canserial_find_match_or_unused
    ");
    }
    
    
    static int __init serial_can_init(void)
    {
        int ret;
    
        canserial_isa_init_ports();
    
        canserial_reg.nr = UART_NR;
        ret = uart_register_driver(&canserial_reg);
        printk("uart_register_driver
    ");
    
        printk("this ret:%d
    ",ret);
        if (ret)
            goto out;
    
        /*platform device *canserial_isa_devs */
        canserial_isa_devs = platform_device_alloc("canserial8250",-1);
        if (!canserial_isa_devs) {
            ret = -ENOMEM;
        }
        printk("platform_device_alloc success
    ");
        ret = platform_device_add(canserial_isa_devs);
        if (ret)
            goto put_dev;
    
        printk("platform_device_add success
    ");
        /*uart_driver canserial_reg*/
        canserial_register_ports(&canserial_reg, &canserial_isa_devs->dev);
    
        ret = platform_driver_register(&canserial_isa_driver);
        if (ret == 0)
            goto out;
    
    put_dev:
        platform_device_del(canserial_isa_devs);
        platform_device_put(canserial_isa_devs);
    unreg_uart_drv:
        uart_unregister_driver(&canserial_reg);
    
    out:
        return ret;
    }
    
    static void __exit serial_can_exit(void)
    {
        struct platform_device *isa_dev = canserial_isa_devs;
    
        /*
         * This tells canserial_unregister_port() not to re-register
         * the ports (thereby making canserial_isa_driver permanently
         * in use.)
         */
        canserial_isa_devs = NULL;
    
        platform_driver_unregister(&canserial_isa_driver);
        platform_device_unregister(isa_dev);
    
        // serial8250_pnp_exit();
    
        uart_unregister_driver(&canserial_reg);
    
    
    
    
    
    }
    
    module_init(serial_can_init);
    module_exit(serial_can_exit);
    
    
    MODULE_LICENSE("Dual BSD/GPL");
  • 相关阅读:
    php自动跳转中英文页面
    如何让一个层关闭之后,就算刷新页面了也不显示。除非关闭页面再次打开
    彻底杜绝warning: Cannot add header information headers already sent in......
    大三了
    X牛人關於編程語錄
    C++虚函数表解析
    epoll:Edge or Level Triggered
    LRU和LFU的区别
    会话、进程组与僵死进程
    Effective C++学习笔记:确定基类有虚析构函数
  • 原文地址:https://www.cnblogs.com/hzijone/p/5242407.html
Copyright © 2020-2023  润新知