`
isiqi
  • 浏览: 16561610 次
  • 性别: Icon_minigender_1
  • 来自: 济南
社区版块
存档分类
最新评论

嵌入式Linux的串口驱动

阅读更多

CPU : s3c2410

PLAT : 由smdk2410修改来的一块板子。(资料依旧非常有限)

这次的项目,板子上面串口部分非常怪异。我们知道,samsung s3c2410这款芯片的UART控制器一共可以支持3个串行端口,如果不够用,还可以通过8250之类的芯片来扩展。而我手上的板子却不是这样实现的,它一共设计了7个端口,但是使用的方式比较特殊,port[1]和port[3]~port[6]这5个端口在任意时刻,只有一个有可能会被使用,考虑到这种特殊的使用方式,我们没有必要再承担一块8250芯片的成本,于是我们用一个映射到bank3(0x18000000)的寄存器来作为开关,实现虚拟的端口的切换,实际上port[3]~port[5]所用的硬件部分和port[1]是同一套,具体实现不再多言,这些对于写串口驱动来说貌似已经够用了。

下面开始修改源码(注意:红色部分是我添加或修改的 )

/linux-2.6.30.4/arch/arm/plat-s3c24xx/devs.c

添加UART设备和资源描述结构体。

#if 0 //modified by B.Zhou
static struct resource s3c2410_uart3_resource[] = {
[0] = {
.start = S3C2443_PA_UART3,
.end = S3C2443_PA_UART3 + 0x3fff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_S3CUART_RX3,
.end = IRQ_S3CUART_ERR3,
.flags = IORESOURCE_IRQ,
},
};
#else
static struct resource s3c2410_uart3_resource[] = {
[0] = {
.start = S3C2410_PA_UART1,
.end = S3C2410_PA_UART1 + 0x3fff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_S3CUART_RX1,
.end = IRQ_S3CUART_ERR1,
.flags = IORESOURCE_IRQ,
}
};

static struct resource s3c2410_uart4_resource[] = {
[0] = {
.start = S3C2410_PA_UART1,
.end = S3C2410_PA_UART1 + 0x3fff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_S3CUART_RX1,
.end = IRQ_S3CUART_ERR1,
.flags = IORESOURCE_IRQ,
}
};

static struct resource s3c2410_uart5_resource[] = {
[0] = {
.start = S3C2410_PA_UART1,
.end = S3C2410_PA_UART1 + 0x3fff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_S3CUART_RX1,
.end = IRQ_S3CUART_ERR1,
.flags = IORESOURCE_IRQ,
}
};

static struct resource s3c2410_uart6_resource[] = {
[0] = {
.start = S3C2410_PA_UART1,
.end = S3C2410_PA_UART1 + 0x3fff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_S3CUART_RX1,
.end = IRQ_S3CUART_ERR1,
.flags = IORESOURCE_IRQ,
}
};
#endif

#if 1 //added by B.Zhou
static struct platform_device s3c24xx_uart_device4 = {
.id = 4,
};

static struct platform_device s3c24xx_uart_device5 = {
.id = 5,
};

static struct platform_device s3c24xx_uart_device6 = {
.id = 6,
};
#endif

struct platform_device *s3c24xx_uart_src[7 ] = {
&s3c24xx_uart_device0,
&s3c24xx_uart_device1,
&s3c24xx_uart_device2,
&s3c24xx_uart_device3,
#if 1 //added by B.Zhou
&s3c24xx_uart_device4,
&s3c24xx_uart_device5,
&s3c24xx_uart_device6,
#endif
};

/linux-2.6.30.4/include/linux/autoconf.h

这个文件中的常量来自“make menuconfig”中的内核配置信息。

#define CONFIG_SERIAL_SAMSUNG_UARTS 7 //modified by B.Zhou
(注意,这个常量每次通过“make menuconfig”修改内核配置信息后,都会还原为3)

/linux-2.6.30.4/include/linux/serial_reg.h

在这里面添加bank3(0x18000000)寄存器相关的物理地址和虚拟地址的定义,具体如下:

#if 1 //added by B.Zhou for the driver of serial ports
#define pA_UART_Reg 0x18000000 //PA
#define vA_UART_Reg 0xe2000000 //VA
#define len_UART_Reg 0x00010000
#endif

/linux-2.6.30.4/arch/arm/mach-s3c2410/mach-smdk2410.c

在这里面要实现的是对于上面地址的映射。

先添加两个头文件:

#include <linux/serial_reg.h> // added by B.Zhou for the serial ports
#include <asm/memory.h> // added by B.Zhou for the __phys_to_pfn()

static struct map_desc smdk2410_iodesc[] __initdata = {
/* nothing here yet */
/* added by B.Zhou for the serial ports */
{vA_UART_Reg, __phys_to_pfn(pA_UART_Reg), len_UART_Reg, MT_DEVICE_NONSHARED},
};

linux-2.6.30.4/arch/arm/include/asm/io.h

添加静态变量,用于定义虚拟地址

volatile static unsigned long REG_SERIAL; // added by B.Zhou


/linux-2.6.30.4/drivers/serial/samsung.c

首先添加一个头文件,用于寄存器操作。

#include <asm/io.h> //added by B.Zhou for the "iowrite8()" and REG_SERIAL


我们在使用端口port[3]~port[5]之前需要通过0x18000000的寄存器来完成端口选择,完成使用后,还要还原状态。这个工作应该在端口启动和关闭时完成。那么我们就需要为port[3]~port[5],修改“static int s3c24xx_serial_startup(struct uart_port *port)”和“static int s3c24xx_serial_shutdown(struct uart_port *port)”两个函数。具体做法为添加以下两部分代码:

#if 1 //added by B.Zhou


static void s3c24xx_serial_shutdown_3(struct uart_port *port)
{
printk(KERN_INFO "\ncalling s3c24xx_serial_shutdown_3\n");
s3c24xx_serial_shutdown(port);
iowrite8(0x08,REG_SERIAL);
}

static void s3c24xx_serial_shutdown_4(struct uart_port *port)
{
printk(KERN_INFO "\ncalling s3c24xx_serial_shutdown_4\n");
s3c24xx_serial_shutdown(port);
iowrite8(0x08,REG_SERIAL);
}

static void s3c24xx_serial_shutdown_5(struct uart_port *port)
{
printk(KERN_INFO "\ncalling s3c24xx_serial_shutdown_5\n");
s3c24xx_serial_shutdown(port);
iowrite8(0x08,REG_SERIAL);
}

static void s3c24xx_serial_shutdown_6(struct uart_port *port)
{
printk(KERN_INFO "\ncalling s3c24xx_serial_shutdown_6\n");
s3c24xx_serial_shutdown(port);
iowrite8(0x08,REG_SERIAL);
}

#endif

static int s3c24xx_serial_startup(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
int ret;

dbg("s3c24xx_serial_startup: port(line:%d)=%p (%08lx,%p)\n",
port->line,port->mapbase, port->membase);
rx_enabled(port) = 1;
#if 0 //modified by B.Zhou
ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, 0,
s3c24xx_serial_portname(port), ourport);
#else
ret = request_irq(ourport->rx_irq, s3c24xx_serial_rx_chars, IRQF_SHARED,
s3c24xx_serial_portname(port), ourport);
#endif
if (ret != 0) {
printk(KERN_ERR "cannot get irq %d\n", ourport->rx_irq);
return ret;
}

ourport->rx_claimed = 1;

dbg("requesting tx irq...\n");

tx_enabled(port) = 1;
#if 0 //modified by B.Zhou
ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, 0,
s3c24xx_serial_portname(port), ourport);
#else
ret = request_irq(ourport->tx_irq, s3c24xx_serial_tx_chars, IRQF_SHARED,
s3c24xx_serial_portname(port), ourport);
#endif

if (ret) {
printk(KERN_ERR "cannot get irq %d\n", ourport->tx_irq);
goto err;
}

ourport->tx_claimed = 1;

dbg("s3c24xx_serial_startup ok\n");

/* the port reset code should have done the correct
* register setup for the port controls */

return ret;

err:
s3c24xx_serial_shutdown(port);
return ret;
}


#if 1 //added by B.Zhou

static int s3c24xx_serial_startup_3(struct uart_port *port)
{
printk(KERN_INFO "\ncall s3c24xx_serial_startup_3\n");
iowrite8(0x01,REG_SERIAL);
return s3c24xx_serial_startup(port);
}

static int s3c24xx_serial_startup_4(struct uart_port *port)
{
printk(KERN_INFO "\ncall s3c24xx_serial_startup_4\n");
iowrite8(0x02,REG_SERIAL);
return s3c24xx_serial_startup(port);
}

static int s3c24xx_serial_startup_5(struct uart_port *port)
{
printk(KERN_INFO "\ncall s3c24xx_serial_startup_5\n");
iowrite8(0x04,REG_SERIAL);
return s3c24xx_serial_startup(port);
}

static int s3c24xx_serial_startup_6(struct uart_port *port)
{
printk(KERN_INFO "\ncall s3c24xx_serial_startup_6\n");
iowrite8(0x08,REG_SERIAL);
return s3c24xx_serial_startup(port);
}
#endif


添加用于port[3]~port[6]的操作函数结构体,实际上只是修改了端口启动和关闭的函数,具体如下:

#if 1 //added by B.Zhou
static struct uart_ops s3c24xx_serial_ops3 = {
.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_3,
.shutdown = s3c24xx_serial_shutdown_3,
.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,
};

static struct uart_ops s3c24xx_serial_ops4 = {
.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_4,
.shutdown = s3c24xx_serial_shutdown_4,
.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,
};

static struct uart_ops s3c24xx_serial_ops5 = {
.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_5,
.shutdown = s3c24xx_serial_shutdown_5,
.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,
};

static struct uart_ops s3c24xx_serial_ops6 = {
.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_6,
.shutdown = s3c24xx_serial_shutdown_6,
.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,
};
#endif

在 “static struct s3c24xx_uart_port s3c24xx_serial_ports[CONFIG_SERIAL_SAMSUNG_UARTS]” 数组中添加port[3]~port[5]的端口描述结构体:

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_PORT,
.iobase = S3C2410_PA_UART0,
.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_PORT,
.iobase = S3C2410_PA_UART1,
.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_PORT,
.iobase = S3C2410_PA_UART2,
.irq = IRQ_S3CUART_RX2,
.uartclk = 0,
.fifosize = 16,
.ops = &s3c24xx_serial_ops,
.flags = UPF_BOOT_AUTOCONF,
.line = 2,
}
},
#endif
#if 1 //added by B.Zhou
#if CONFIG_SERIAL_SAMSUNG_UARTS > 3
[3] = {
.port = {
.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[3].port.lock),
.iotype = UPIO_PORT,
.iobase = S3C2410_PA_UART1 ,
.irq = IRQ_S3CUART_RX1 ,
.uartclk = 0,
.fifosize = 16,
.ops = &s3c24xx_serial_ops3,
.flags = UPF_BOOT_AUTOCONF,
.line = 3,
}
},

[4] = {
.port = {
.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[4].port.lock),
.iotype = UPIO_PORT,
.iobase = S3C2410_PA_UART1,
.irq = IRQ_S3CUART_RX1,
.uartclk = 0,
.fifosize = 16,
.ops = &s3c24xx_serial_ops4,
.flags = UPF_BOOT_AUTOCONF,
.line = 4,
}
},

[5] = {
.port = {
.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[5].port.lock),
.iotype = UPIO_PORT,
.iobase = S3C2410_PA_UART1,
.irq = IRQ_S3CUART_RX1,
.uartclk = 0,
.fifosize = 16,
.ops = &s3c24xx_serial_ops5,
.flags = UPF_BOOT_AUTOCONF,
.line = 5,
}
},

[6] = {
.port = {
.lock = __SPIN_LOCK_UNLOCKED(s3c24xx_serial_ports[6].port.lock),
.iotype = UPIO_PORT,
.iobase = S3C2410_PA_UART1,
.irq = IRQ_S3CUART_RX1,
.uartclk = 0,
.fifosize = 16,
.ops = &s3c24xx_serial_ops6,
.flags = UPF_BOOT_AUTOCONF,
.line = 6,
}
}
#endif

#endif
};

找到模块初始化函数,为“REG_SERIAL” 赋值,也可以直接添加上面提到的“serial_reg.h” 头文件。

static int __init s3c24xx_serial_modinit(void)
{
int ret;

#if 1 //added by B.Zhou
REG_SERIAL = 0xe2000000;

#endif
ret = uart_register_driver(&s3c24xx_uart_drv);
if (ret < 0) {
printk(KERN_ERR "failed to register UART driver\n");
return -1;
}
return 0;
}

找到端口初始化函数,做如下修改:

static int s3c24xx_serial_init_ports(struct s3c24xx_uart_info *info)
{
struct s3c24xx_uart_port *ptr = s3c24xx_serial_ports;
struct platform_device **platdev_ptr;
int i;

dbg("s3c24xx_serial_init_ports: initialising ports...\n");

platdev_ptr = s3c24xx_uart_devs;
#if 1 //modified by B.Zhou
for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++, ptr++) {
if(i < 3)
s3c24xx_serial_init_port(ptr, info, *(platdev_ptr+i));
else
s3c24xx_serial_init_port(ptr, info, *(platdev_ptr+1));
}
#else
for (i = 0; i < CONFIG_SERIAL_SAMSUNG_UARTS; i++, ptr++, platdev_ptr++) {
s3c24xx_serial_init_port(ptr, info, *platdev_ptr);
}
#endif

return 0;
}

下面修改控制台初始化函数中的工作频率:

static int __init
s3c24xx_serial_console_setup(struct console *co, char *options)
{
struct uart_port *port;
int baud = 115200; //modified by B.Zhou 9600
int bits = 8;
int parity = 'n';
int flow = 'n';

dbg("s3c24xx_serial_console_setup: co=%p (%d), %s\n",
co, co->index, options);

/* is this a valid port */

if (co->index == -1 || co->index >= CONFIG_SERIAL_SAMSUNG_UARTS)
co->index = 0;


port = &s3c24xx_serial_ports[co->index].port;

/* is the port configured? */

if (port->mapbase == 0x0) {
co->index = 0;
port = &s3c24xx_serial_ports[co->index].port;
}

cons_uart = port;

dbg("s3c24xx_serial_console_setup: port=%p (%d)\n", port, co->index);

/*
* Check whether an invalid uart number has been specified, and
* if so, search for the first available port that does have
* console support.
*/
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
s3c24xx_serial_get_options(port, &baud, &parity, &bits);

dbg("s3c24xx_serial_console_setup: baud %d\n", baud);

return uart_set_options(port, co, baud, parity, bits, flow);
}

/linux-2.6.30.4/arch/arm/plat-s3c/init.c

在这个文件中修改UART设备初始化函数:

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;
int uart_cur;

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;
}
#if 1 //added by B.Zhou
for(uart_cur = 3; uart_cur < 7; uart_cur++, cfgptr++) {
memcpy(cfgptr, cfg-2, sizeof(struct s3c2410_uartcfg));

platdev = s3c24xx_uart_src[uart_cur];

resp = res + cfgptr->hwport;

s3c24xx_uart_devs[uart_cur] = platdev;

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

platdev->dev.platform_data = cfgptr;

}
nr_uarts = 7;
#else
nr_uarts = no;
#endif
}

至此,这个板子上的串口已经可以工作了,启动后会看到在“/dev” 文件夹下,生成了7个串口设备文件,分别是"s3c2410_serial0~
s3c2410_serial6 "。 但是还有一个问题,就是串口的缺省状态,比如波特率默认为9600,而我们更希望它是115200。

/linux-2.6.30.4/drivers/serial/serial_core.c

找到UART驱动注册函数:

int uart_register_driver(struct uart_driver *drv)
{
struct tty_driver *normal = NULL;
int i, retval;

BUG_ON(drv->state);

/*
* Maybe we should be using a slab cache for this, especially if
* we have a large number of ports to handle.
*/
drv->state = kzalloc(sizeof(struct uart_state) * drv->nr, GFP_KERNEL);
retval = -ENOMEM;
if (!drv->state)
goto out;

normal = alloc_tty_driver(drv->nr);
if (!normal)
goto out;

drv->tty_driver = normal;

normal->owner = drv->owner;
normal->driver_name = drv->driver_name;
normal->name = drv->dev_name;
normal->major = drv->major;
normal->minor_start = drv->minor;
normal->type = TTY_DRIVER_TYPE_SERIAL;
normal->subtype = SERIAL_TYPE_NORMAL;
normal->init_termios = tty_std_termios;

#if 0 //modified by B.Zhou
normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 9600;
#else
normal->init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
normal->init_termios.c_lflag &= ~(ICANON | ISIG | ECHO | ECHOE);
normal->init_termios.c_oflag &= ~OPOST;
normal->init_termios.c_ispeed = normal->init_termios.c_ospeed = 115200;
#endif

normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
normal->driver_state = drv;
tty_set_operations(normal, &uart_ops);

/*
* Initialise the UART state(s).
*/
for (i = 0; i < drv->nr; i++) {
struct uart_state *state = drv->state + i;

state->close_delay = 500; /* .5 seconds */
state->closing_wait = 30000; /* 30 seconds */
mutex_init(&state->mutex);

tty_port_init(&state->info.port);
init_waitqueue_head(&state->info.delta_msr_wait);
tasklet_init(&state->info.tlet, uart_tasklet_action,
(unsigned long)state);
}

retval = tty_register_driver(normal);
out:
if (retval < 0) {
put_tty_driver(normal);
kfree(drv->state);
}
return retval;
}

终于,串口驱动全部完成了。

转至:http://blog.csdn.net/BZhouCHN/archive/2010/04/16/5494812.aspx

分享到:
评论

相关推荐

    一种嵌入式Linux串口驱动开发模式.pdf

    【嵌入式Linux串口驱动开发】在嵌入式设备应用中,串口通信是常见的数据传输方式。传统的做法是将串口数据的处理放在应用程序层进行,这可能导致数据实时性和重复利用率降低,增加应用程序的开发复杂度。针对这一...

    基于华邦W90P710的嵌入式Linux串口驱动的实现方法.pdf

    【嵌入式Linux串口驱动实现】 嵌入式Linux系统在工控产品中广泛应用,得益于其开源、稳定、高效的特点。在许多工控设备中,串口通信是连接外部设备并进行信息交换的常用手段。华邦W90P710是一款基于ARM7TDMI微处理...

    基于ARM9和嵌入式Linux的串口驱动开发.pdf

    总结来说,基于ARM9的嵌入式Linux串口驱动开发是一项重要的任务,它涉及到硬件接口的理解、Linux驱动模型的运用以及针对具体应用场景的优化。通过这样的驱动开发,可以实现嵌入式设备与其他设备的有效通信,是构建...

    嵌入式Linux设备驱动开发详解

    本书特色:本书系统地介绍了嵌入式Linux设备驱动开发的相关知识和实例,主要包括: ...串口驱动程序;网络设备驱动程序。 实例丰富、讲解细致、代码分析详尽,嵌入式Linux设备驱动开发的理想参考用书。

    嵌入式linux 串口 应用开发 代码

    总的来说,"嵌入式Linux 串口 应用开发 代码"这个项目涵盖了C语言编程、嵌入式系统、Linux内核驱动、ARM架构和串口通信等多个方面的知识,是学习和实践嵌入式Linux系统下设备驱动与通信协议的良好案例。通过深入理解...

    keyboard_嵌入式LINUX开发_嵌入式Linux串口_

    本文将详细解析标题“keyboard_嵌入式LINUX开发_嵌入式Linux串口_”所涉及的知识点,并以描述中的游戏快捷键修改程序为例,深入探讨如何实现主机与虚拟机之间的串口通信。 首先,我们要理解嵌入式Linux系统。嵌入式...

    嵌入式Linux设备驱动开发详解_实例代码

    嵌入式Linux设备驱动开发是将硬件功能与操作系统内核相结合的关键技术,它使得应用程序能够通过标准接口与硬件进行通信,而无需关心底层硬件的具体实现。在这个领域,开发者需要理解和掌握Linux内核的工作原理,以及...

    嵌入式Linux环境下的串口通信研究.pdf

    除非有特殊要求,否则不必另外开发串口驱动程序,只需调用系统提供的操作函数就可以访问和控制相应的串口。 在本系统的嵌入式Linux内核版本为2.4.18的系统中,串行端口1和端口2分别对应于设备文件“/dev/ttyS/0”...

    嵌入式Linux系统的研究及其在串口通信中的应用.pdf

    "嵌入式Linux系统的研究及其在串口通信中的应用" 嵌入式Linux系统是一种基于Linux操作系统的嵌入式系统,可以应用于各种领域,例如工业控制、医疗设备、家电等。该系统具有高可靠性、高可维护性和高可扩展性等特点...

    中嵌嵌入式LINUX 设备驱动开发课件

    在嵌入式Linux系统中,设备驱动开发是至关重要的一个环节,它连接着硬件与操作系统,使得硬件资源得以有效利用并提供服务。本课件"中嵌嵌入式LINUX 设备驱动开发"旨在深入讲解这一领域,帮助学习者掌握设备驱动的...

    嵌入式Linux设备驱动开发详解光盘实例代码.rar

    《嵌入式Linux设备驱动开发详解》是一本深入探讨嵌入式系统中Linux设备驱动程序设计与实现的专业书籍。光盘实例代码是该书的重要补充,提供了丰富的实践案例,帮助读者更好地理解和掌握理论知识。 在嵌入式系统中,...

    基于华邦W90P710的嵌入式Linux串口驱动的实现方法

    最后,为了正确实现和维护嵌入式Linux串口驱动,开发者需要熟悉ARM架构和Linux内核编程,了解如何操作硬件设备和如何编写与硬件交互的代码,以及具备对Linux内核机制和设备驱动框架的深入了解。

    嵌入式Linux驱动程序的开发.pdf

    "嵌入式 Linux 驱动程序的开发.pdf" 本文详细介绍了嵌入式 Linux 驱动程序的开发,包括驱动程序的结构、设备管理和文件系统的关系、设备驱动程序的加载方法及其优缺点等。通过实例代码的分析,得出了驱动程序模块的...

    嵌入式Linux的设备驱动程序设计及其交叉编译.pdf

    "嵌入式Linux设备驱动程序设计及其交叉编译" 嵌入式Linux设备驱动程序设计是指在嵌入式Linux系统中,为了使得外部设备能够正常工作,需要设计和实现相应的驱动程序。驱动程序是嵌入式Linux系统的重要组成部分,是...

    嵌入式linux下串口通信

    写嵌入式linux串口协议和驱动的最全的资源,大家可以参考

    嵌入式LINUX下驱动程序开发入门

    在嵌入式Linux系统中,驱动程序开发是构建硬件与操作系统之间桥梁的关键步骤。这篇文章将带你深入了解嵌入式Linux驱动程序开发的基础知识,让你能够入门并逐步掌握这一领域。 一、嵌入式Linux简介 嵌入式Linux是将...

    嵌入式Linux设备驱动开发详解+实例代码

    嵌入式Linux设备驱动开发是将硬件功能与操作系统内核相结合的关键技术,它使得应用程序能够通过标准接口与硬件交互。本资源提供了详细的嵌入式Linux设备驱动开发详解及实例代码,帮助开发者深入理解和实践这一领域。...

    第11章、嵌入式Linux设备驱动开发_linux_

    在嵌入式Linux系统中,设备驱动开发是至关重要的一个环节,它连接着硬件与操作系统,使得硬件资源得以有效利用并提供服务。本章节将深入探讨嵌入式Linux设备驱动开发的相关知识点,帮助读者理解其核心概念、设计原理...

Global site tag (gtag.js) - Google Analytics