linux UART驱动 二

module_init(s3c2440_serial_init);

static int __init s3c2440_serial_init(void)
{
	return s3c24xx_serial_init(&s3c2440_serial_driver, &s3c2440_uart_inf);
}

int s3c24xx_serial_init(struct platform_driver *drv,
			struct s3c24xx_uart_info *info)
{
	dbg("s3c24xx_serial_init(%p,%p)\n", drv, info);

#ifdef CONFIG_PM
	drv->suspend = s3c24xx_serial_suspend;
	drv->resume = s3c24xx_serial_resume;
#endif

	return platform_driver_register(drv);
}

static struct platform_driver s3c2440_serial_driver = {
	.probe		= s3c2440_serial_probe,
	.remove		= __devexit_p(s3c24xx_serial_remove),
	.driver		= {
		.name	= "s3c2440-uart",
		.owner	= THIS_MODULE,
	},
};

当注册驱动程序的时候,会调用 probe 函数,即 s3c2440_serial_probe 函数。

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

参数 dev 是前面我们注册的设备,以uart0为例,它的结构如下:

static struct platform_device s3c24xx_uart_device0 = {
	.id				= 0,
	.name			= "s3c2440-uart",
	.resource 		= s3c2410_uart0_resource,
	.num_resources 	= ARRAY_SIZE(s3c2410_uart0_resource),
	.dev			= {
						.platform_data = uart_cfgs,
					  }
};

static struct resource s3c2410_uart0_resource[] = {
	[0] = {
		.start = S3C2410_PA_UART0,
		.end   = S3C2410_PA_UART0 + 0x3fff,
		.flags = IORESOURCE_MEM,
	},
	[1] = {
		.start = IRQ_S3CUART_RX0,
		.end   = IRQ_S3CUART_ERR0,
		.flags = IORESOURCE_IRQ,
	}
};

static struct s3c2410_uartcfg uart_cfgs[CONFIG_SERIAL_SAMSUNG_UARTS]  = {
	[0] = {
		.hwport	     = 0,
		.flags	     = 0,
		.ucon	     = UCON,
		.ulcon	     = ULCON,
		.ufcon	     = UFCON,
	},
	[1] = {
		.hwport	     = 1,
		.flags	     = 0,
		.ucon	     = UCON,
		.ulcon	     = ULCON,
		.ufcon	     = UFCON,
	},
	[2] = {
		.hwport	     = 2,
		.flags	     = 0,
		.ucon	     = UCON,
		.ulcon	     = ULCON,
		.ufcon	     = UFCON,
	},
};

参数 s3c2440_uart_inf 是一个全局变量,下面是它的定义:

static struct s3c24xx_uart_info s3c2440_uart_inf = {
	.name		= "Samsung S3C2440 UART",
	.type		= PORT_S3C2440,
	.fifosize	= 64,
	.rx_fifomask	= S3C2440_UFSTAT_RXMASK,
	.rx_fifoshift	= S3C2440_UFSTAT_RXSHIFT,
	.rx_fifofull	= S3C2440_UFSTAT_RXFULL,
	.tx_fifofull	= S3C2440_UFSTAT_TXFULL,
	.tx_fifomask	= S3C2440_UFSTAT_TXMASK,
	.tx_fifoshift	= S3C2440_UFSTAT_TXSHIFT,
	.get_clksrc	= s3c2440_serial_getsource,
	.set_clksrc	= s3c2440_serial_setsource,
	.reset_port	= s3c2440_serial_resetport,
};


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

//描述A
	ourport = &s3c24xx_serial_ports[probe_index];
	probe_index++;

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

//描述B
	ret = s3c24xx_serial_init_port(ourport, info, dev);
	if (ret < 0)
		goto probe_err;

	dbg("%s: adding port\n", __func__);
//描述C
	uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
	platform_set_drvdata(dev, &ourport->port);

	ret = device_create_file(&dev->dev, &dev_attr_clock_source);
	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;
}

描述A:
变量 s3c24xx_serial_ports 是一个全局变量,以uart0为例, 变量 probe_index 也是一个全局变量,从0开始

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

所以局部变量 ourport 的值为:

{
	.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,
	}
}

static struct uart_ops s3c24xx_serial_ops = {
	.pm		= s3c24xx_serial_pm,
	.tx_empty	= s3c24xx_serial_tx_empty,
	.get_mctrl	= s3c24xx_serial_get_mctrl,
	.set_mctrl	= s3c24xx_serial_set_mctrl,
	.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,
	.startup	= s3c24xx_serial_startup,
	.shutdown	= s3c24xx_serial_shutdown,
	.set_termios	= s3c24xx_serial_set_termios,
	.type		= s3c24xx_serial_type,
	.release_port	= s3c24xx_serial_release_port,
	.request_port	= s3c24xx_serial_request_port,
	.config_port	= s3c24xx_serial_config_port,
	.verify_port	= s3c24xx_serial_verify_port,
};

描述B:

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;
/*
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,
}
*/
	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);

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

	if (cfg->hwport > CONFIG_SERIAL_SAMSUNG_UARTS) {
		printk(KERN_ERR "%s: port %d bigger than %d\n", __func__,
		       cfg->hwport, CONFIG_SERIAL_SAMSUNG_UARTS);
		return -ERANGE;
	}

	/* 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) {
		dbg("s3c24xx_serial_init_port: enabling flow control\n");
		port->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;
	}

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

可以看出,这个函数的主要目的就是:
用之前注册的设备platdev【struct platform_device】的值初始化struct uart_port结构的port的其它成员变量,如:
uartclk /* base uart clock */
membase /* read/write[bwl] */
irq     /* irq number */
mapbase /* for ioremap */
其实这里的uart_port就相当于我们实际上的一个uart接口,当读写uart接口的时候,就是在调用uart_port中的成员。
简单梳理一下,当我们自己写uart驱动的时候:
1> 先定义一个设备,比如这里的 s3c24xx_uart_device0

	static struct platform_device s3c24xx_uart_device0 = {
		.id				= 0,
		.name			= "s3c2440-uart",
		.resource 		= s3c2410_uart0_resource,
		.num_resources 	= ARRAY_SIZE(s3c2410_uart0_resource),
		.dev			= {
							.platform_data = uart_cfgs,
						  }
	};

	static struct resource s3c2410_uart0_resource[] = {
		[0] = {
			.start = S3C2410_PA_UART0,
			.end   = S3C2410_PA_UART0 + 0x3fff,
			.flags = IORESOURCE_MEM,
		},
		[1] = {
			.start = IRQ_S3CUART_RX0,
			.end   = IRQ_S3CUART_ERR0,
			.flags = IORESOURCE_IRQ,
		}
	};
在这里定义了两种资源类型,MEM和IRQ。上面的函数就是通过获取该资源从而配置port变量。
该变量需要通过 platform_add_devices 函数添加该设备。


2> 再定义一个struct uart_port类型的变量,这里定义的是struct s3c24xx_uart_port型的变量,
其实是对struct uart_port的封装,因为struct s3c24xx_uart_port结构是包含了struct uart_port的

	static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS] = {
		[0] = {
			//这里的port即 struct uart_port 类型
			.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,
			}
		}
	}

在probe函数中用第1步中定义的设备结构体初始化该uart_port结构体。在probe函数下一步操作中,会将
该uart_port加入到 uart_driver 中。

描述C:

uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);

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;
	port = &state->port;

	mutex_lock(&port_mutex);
	mutex_lock(&port->mutex);
	if (state->uart_port) {
		ret = -EINVAL;
		goto out;
	}

//描述1
	state->uart_port = uport;
	state->pm_state = -1;

	uport->cons = drv->cons;
	uport->state = state;

	/*
	 * If this port is a console, then the spinlock is already
	 * initialised.
	 */
	if (!(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);

	/*
	 * Register the port whether it's detected or not.  This allows
	 * setserial to be used to alter this ports parameters.
	 */
	tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev);
	if (likely(!IS_ERR(tty_dev))) {
		device_init_wakeup(tty_dev, 1);
		device_set_wakeup_enable(tty_dev, 0);
	} else
		printk(KERN_ERR "Cannot register tty device on line %d\n",
		       uport->line);

	/*
	 * Ensure UPF_DEAD is not set.
	 */
	uport->flags &= ~UPF_DEAD;

 out:
	mutex_unlock(&port->mutex);
	mutex_unlock(&port_mutex);

	return ret;
}
说明:
参数 s3c24xx_uart_drv 是一个全局变量,它的定义如下:
static struct uart_driver s3c24xx_uart_drv = {
	.owner		= THIS_MODULE,
	.dev_name	= "s3c2410_serial",
	.nr		= CONFIG_SERIAL_SAMSUNG_UARTS,
	.cons		= S3C24XX_SERIAL_CONSOLE,
	.driver_name	= S3C24XX_SERIAL_NAME,
	.major		= S3C24XX_SERIAL_MAJOR,
	.minor		= S3C24XX_SERIAL_MINOR,
};
s3c24xx_uart_drv 变量中的另外两个重要的成员
	struct uart_state	*state;
	struct tty_driver	*tty_driver;

在 uart_register_driver 函数中初始化,前面已经分析过。


描述1:
将前面初始化后的 uart_port 挂载到 uart_driver 中


接着前面的描述,当我们自己写uart驱动的时候:
3> 需要定义一个 struct uart_driver 结构的变量,如这里的:

	static struct uart_driver s3c24xx_uart_drv = {
		.owner		= THIS_MODULE,
		.dev_name	= "s3c2410_serial",
		.nr		= CONFIG_SERIAL_SAMSUNG_UARTS,
		.cons		= S3C24XX_SERIAL_CONSOLE,
		.driver_name	= S3C24XX_SERIAL_NAME,
		.major		= S3C24XX_SERIAL_MAJOR,
		.minor		= S3C24XX_SERIAL_MINOR,
	};
该变量中的最后两个成员必须初始化为空,并通过 uart_register_driver 函数配置该变量。


最后用一张图来说明它们之间的关系




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值