您的位置:首页 > 其它

s3c6410的UART设备驱动(5)

2012-05-17 22:52 316 查看

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;

}

好了,终于走完了这个函数的旅途,但以后的还很长啊!再接再厉!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: