s3c6410的UART设备驱动(5)


s3c6410的UART设备驱动(1)的链接

s3c6410的UART设备驱动(2)的链接

s3c6410的UART设备驱动(3)的链接地址

s3c6410的UART设备驱动(4)的链接地址

上一篇中说到了这个函数,源码如下:

static int s3c6400_serial_probe(struct platform_device *dev)
{
 dbg("s3c6400_serial_probe: dev=%p\n", dev);
 return s3c24xx_serial_probe(dev, &s3c6400_uart_inf);
}

现在接着往下说:

int s3c24xx_serial_probe(struct platform_device *dev,
 struct s3c24xx_uart_info *info)
{
struct s3c24xx_uart_port *ourport;
int ret;

dbg("s3c24xx_serial_probe(%p, %p) %d\n", dev, info, probe_index);

ourport = &s3c24xx_serial_ports[probe_index];

         probe_index++;

如下,在Samsung.c (linux2.6.28\drivers\serial)文件中有如下定义:在struct s3c24xx_uart_port结构体重有struct uart_port结构体。

static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
[0] = {
.port = {
.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[0].port.lock),
.iotype = UPIO_MEM,
.irq = IRQ_S3CUART_RX0,
.uartclk = 0,
.fifosize = 16,
.ops = &s3c24xx_serial_ops,
.flags = UPF_BOOT_AUTOCONF,
.line = 0,
}
},
[1] = {
.port = {
.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[1].port.lock),
.iotype = UPIO_MEM,
.irq = IRQ_S3CUART_RX1,
.uartclk = 0,
.fifosize = 16,
.ops = &s3c24xx_serial_ops,
.flags = UPF_BOOT_AUTOCONF,
.line = 1,
}
},
#if CONFIG_SERIAL_SAMSUNG_UARTS > 2


[2] = {
.port = {
.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[2].port.lock),
.iotype = UPIO_MEM,
.irq = IRQ_S3CUART_RX2,
.uartclk = 0,
.fifosize = 16,
.ops = &s3c24xx_serial_ops,
.flags = UPF_BOOT_AUTOCONF,
.line = 2,
}
},
#endif
#if CONFIG_SERIAL_SAMSUNG_UARTS > 3
[3] = {
.port = {
.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock),
.iotype = UPIO_MEM,
.irq = IRQ_S3CUART_RX3,
.uartclk = 0,
.fifosize = 16,
.ops = &s3c24xx_serial_ops,
//---->modify by phantom
///#ifdef TE6410
#if 1
.flags = UPF_BOOT_AUTOCONF | UPF_CONS_FLOW,
#else
.flags = UPF_BOOT_AUTOCONF,
#endif
//<----
.line = 3,
}
}
#endif
};




dbg("%s: initialising port %p...\n", __func__, ourport);


ret = s3c24xx_serial_init_port(ourport, info, dev);
if (ret < 0)
goto probe_err;

/* s3c24xx_serial_init_port
 * initialise a single serial port from the platform device given
 */

此函数传入的参数中有个struct platform_device结构体,在那里定义的呢?

在Dev-uart.c (linux2.6.28\arch\arm\plat-s3c64xx)中有如下定义:

/* uart devices */
static struct platform_device s3c24xx_uart_device0 = {
.id = 0,
};
static struct platform_device s3c24xx_uart_device1 = {
.id = 1,
};
static struct platform_device s3c24xx_uart_device2 = {
.id = 2,
};
static struct platform_device s3c24xx_uart_device3 = {
.id = 3,
};
struct platform_device *s3c24xx_uart_src[4] = {
&s3c24xx_uart_device0,
&s3c24xx_uart_device1,
&s3c24xx_uart_device2,
&s3c24xx_uart_device3,
};
static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
    struct s3c24xx_uart_info *info,
    struct platform_device *platdev)
{
struct uart_port *port = &ourport->port;
struct s3c2410_uartcfg *cfg;
struct resource *res;
int ret;


dbg("s3c24xx_serial_init_port: port=%p, platdev=%p\n", port, platdev);


if (platdev == NULL)
return -ENODEV;


cfg = s3c24xx_dev_to_cfg(&platdev->dev);

        #define s3c24xx_dev_to_cfg(__dev) (struct s3c2410_uartcfg *)((__dev)->platform_data)

这里有关的一个结构体是:

/* configuration structure for per-machine configurations for the
 * serial port
 *
 * the pointer is setup by the machine specific initialisation from the
 * arch/arm/mach-s3c2410/ directory.
*/
struct s3c2410_uartcfg {
unsigned char    hwport;  /* hardware port number */
unsigned char    unused;
unsigned short   flags;
#if !defined(CONFIG_CPU_S3C6400) && !defined(CONFIG_CPU_S3C6410) && !defined(CONFIG_CPU_S5PC100) 
        upf_t              uart_flags;   /* default uart flags */
#else
        unsigned long   uart_flags;      /* default uart flags */
#endif

unsigned long    ucon;  /* value of ucon for port */
unsigned long    ulcon;  /* value of ulcon for port */
unsigned long    ufcon;  /* value of ufcon for port */

struct s3c24xx_uart_clksrc *clocks;
unsigned int     clocks_size;
};

这个结构体的实例在:Mach-smdk6410.c (linux2.6.28\arch\arm\mach-s3c6410)文件中,

static struct s3c2410_uartcfg smdk6410_uartcfgs[] __initdata = {
[0] = {
.hwport     = 0,
.flags     = 0,
.ucon     = S3C64XX_UCON_DEFAULT,
.ulcon     = S3C64XX_ULCON_DEFAULT,
.ufcon     = S3C64XX_UFCON_DEFAULT,
},
[1] = {
.hwport     = 1,
.flags     = 0,
.ucon     = S3C64XX_UCON_DEFAULT,
.ulcon     = S3C64XX_ULCON_DEFAULT,
.ufcon     = S3C64XX_UFCON_DEFAULT,
},
[2] = {
.hwport     = 2,
.flags     = 0,
.ucon     = S3C64XX_UCON_DEFAULT,
.ulcon     = S3C64XX_ULCON_DEFAULT,
.ufcon     = S3C64XX_UFCON_DEFAULT,
},
[3] = {
.hwport     = 3,
.flags     = 0,
.ucon     = S3C64XX_UCON_DEFAULT,
.ulcon     = S3C64XX_ULCON_DEFAULT,
.ufcon     = S3C64XX_UFCON_DEFAULT,
},
};


if (port->mapbase != 0)
return 0;


if (cfg->hwport > CONFIG_SERIAL_SAMSUNG_UARTS) {
.......
}


/* setup info for port */
port->dev = &platdev->dev;
ourport->info = info;



/* copy the info in from provided structure */
ourport->port.fifosize = info->fifosize;


dbg("s3c24xx_serial_init_port: %p (hw %d)...\n", port, cfg->hwport);

port->uartclk = 1;

if (cfg->uart_flags & UPF_CONS_FLOW) {
.......
}


/* sort our the physical and virtual addresses for each UART */
res = platform_get_resource(platdev, IORESOURCE_MEM, 0);
if (res == NULL) {
printk(KERN_ERR "failed to find memory resource for uart\n");
return -EINVAL;
}
大家应该都知道在struct platform_device结构体中有个struct resource* resource指针,可以存放相应的资源。但是在上面的static struct platform_device s3c24xx_uart_device2结构中并没有有关资源的赋值,那在那里赋的值呢?

static struct platform_device s3c24xx_uart_device2 = {
.id= 2,
};

struct platform_device {
const char * name;
int id;
struct device dev;
u32 num_resources;
struct resource* resource;
};

在Dev-uart.c (linux2.6.28\arch\arm\plat-s3c64xx)文件中有下面这两个结构,我们只列出了其中的一部分。

struct s3c24xx_uart_resources s3c64xx_uart_resources[] __initdata = {
[0] = {
.resources= s3c64xx_uart0_resource,
.nr_resources= ARRAY_SIZE(s3c64xx_uart0_resource),
}

static struct resource s3c64xx_uart0_resource[] = {
[0] = {
.start = S3C_PA_UART0,
.end = S3C_PA_UART0 + S3C_SZ_UART,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_S3CUART_RX0,
.end = IRQ_S3CUART_RX0,
.flags = IORESOURCE_IRQ,
}, 
[2] = {
.start = IRQ_S3CUART_TX0,
.end = IRQ_S3CUART_TX0,
.flags = IORESOURCE_IRQ,

},
[3] = {
.start = IRQ_S3CUART_ERR0,
.end = IRQ_S3CUART_ERR0,
.flags = IORESOURCE_IRQ,
}
};


那么这些结构怎样联系起来的呢?

在S3c6400-init.c (linux2.6.28\arch\arm\plat-s3c64xx)文件中有如下函数:

/* uart registration process */
void __init s3c6400_common_init_uarts(struct s3c2410_uartcfg *cfg, int no)
{
s3c24xx_init_uartdevs("s3c6400-uart", s3c64xx_uart_resources, cfg, no);
}

/* s3c24xx_init_uartdevs
 *
 * copy the specified platform data and configuration into our central
 * set of devices, before the data is thrown away after the init process.
 *
 * This also fills in the array passed to the serial driver for the
 * early initialisation of the console.
*/注:这个函数是在系统初始化是执行的。
void __init s3c24xx_init_uartdevs(char *name,
  struct s3c24xx_uart_resources *res,
  struct s3c2410_uartcfg *cfg, int no)
{
struct platform_device *platdev;
struct s3c2410_uartcfg *cfgptr = uart_cfgs;
struct s3c24xx_uart_resources *resp;
int uart;


//printk("iiiiiiiiiiiiiiiiiiii=%d\n",no);
memcpy(cfgptr, cfg, sizeof(struct s3c2410_uartcfg) * no);


for (uart = 0; uart < no; uart++, cfg++, cfgptr++) {
platdev = s3c24xx_uart_src[cfgptr->hwport];


resp = res + cfgptr->hwport;


s3c24xx_uart_devs[uart] = platdev;


platdev->name = name;
platdev->resource = resp->resources;
platdev->num_resources = resp->nr_resources;


platdev->dev.platform_data = cfgptr;

看到这些应该,明白了吧!
}


nr_uarts = no;
}此函数到此结束


dbg("resource %p (%lx..%lx)\n", res, res->start, res->end);


port->mapbase = res->start;
port->membase = S3C_VA_UART + res->start - (S3C_PA_UART & 0xfff00000);
ret = platform_get_irq(platdev, 0);这个应该不用说了。
if (ret < 0)
port->irq = 0;
else {
port->irq = ret;
ourport->rx_irq = ret;
ourport->tx_irq = ret + 1;
}


ret = platform_get_irq(platdev, 1);
if (ret > 0)
ourport->tx_irq = ret;


ourport->clk = clk_get(&platdev->dev, "uart");


dbg("port: map=%08x, mem=%08x, irq=%d (%d,%d), clock=%ld\n",
    port->mapbase, port->membase, port->irq,
    ourport->rx_irq, ourport->tx_irq, port->uartclk);


/* reset the fifos (and setup the uart) */
s3c24xx_serial_resetport(port, cfg);
return 0;
}s3c24xx_serial_init_port函数到这里就完了。下面接着分析s3c24xx_serial_probe函数:

dbg("%s: adding port\n", __func__);
uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);

这个函数应该很面熟,上一篇说过。
platform_set_drvdata(dev, &ourport->port);是个宏,展开后为:

#define platform_set_drvdata(_dev,data)dev_set_drvdata(&(_dev)->dev, (data))

static inline void dev_set_drvdata(struct device *dev, void *data)
{
dev->driver_data = data;
}

应该明白了吧。

ret = device_create_file(&dev->dev, &dev_attr_clock_source);与sysfs文件系统有关。
if (ret < 0)
printk(KERN_ERR "%s: failed to add clksrc attr.\n", __func__);

ret = s3c24xx_serial_cpufreq_register(ourport);
if (ret < 0)
dev_err(&dev->dev, "failed to add cpufreq notifier\n");

return 0;

 probe_err:
return ret;
}

好了,终于走完了这个函数的旅途,但以后的还很长啊!再接再厉!





  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Linux内核UART设备驱动注册流程如下: 1. 分配tty_driver结构体 在驱动初始化时,首先需要分配一个tty_driver结构体,该结构体描述了tty设备驱动属性信息,包括驱动名称、打开、关闭、读写等操作的回调函数指针等。 2. 注册tty_driver 调用tty_register_driver函数,将tty_driver结构体注册到内核中,该函数会将tty_driver结构体添加到tty_drivers链表中,同时会创建一个tty_class结构体和一个tty_class_dev结构体,并将其关联起来。 3. 创建tty设备节点 调用tty_register_device函数,该函数会根据tty_driver结构体中的信息创建tty设备节点,并将其添加到tty_drivers链表中。 4. 设置tty设备驱动回调函数 在tty_driver结构体中设置相应的驱动回调函数,例如open、close、read、write等操作的回调函数指针。 5. 注册tty设备驱动与硬件设备的关联 在驱动初始化时,需要将tty设备驱动与硬件设备进行关联,通常是通过platform_device_register函数将platform_device结构体注册到内核中,并调用platform_driver_register函数将platform_driver结构体注册到内核中。 6. 实现tty设备驱动回调函数 在驱动初始化时,需要实现相应的tty设备驱动回调函数,例如open、close、read、write等操作的回调函数。当用户调用相应的操作时,内核会自动调用相应的回调函数执行相应的操作。 7. 注销tty设备驱动驱动卸载时,需要调用tty_unregister_driver函数注销tty_driver结构体,并释放相关资源。同时也需要注销与硬件设备的关联关系。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值