qemu虚拟并口重定向
qemu可以使用参数 “-parallel dev” 将虚拟并口重定向至PC上的设备。比如重定向至一个打开的伪终端: -parallel /dev/pts/2
或者重定向至PC上的文件: -parallel file:/path/to/file
以下测试使用qemu运行并将并口重定向至文件 pptest.txt 。
使用/dev/port
linux内核提供 /dev/port 设备以供用户空间以常规文件读写方式直接访问IO端口。比如要读取地址为100的16位端口,只需seek到文件的100字节处并读取2字节数据,写端口数据亦然。
以并口为例,以下代码发送一串字符至地址为0x378的并口:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#define PORT_FILE "/dev/port"
#define PORT_ADDR 0x378
#define PORT_DATA (PORT_ADDR + 0)
#define PORT_STAT (PORT_ADDR + 1)
#define PORT_CTRL (PORT_ADDR + 2)
static int fd = -1;
static unsigned char io_read(unsigned int port)
{
unsigned char data;
lseek(fd, port, SEEK_SET);
read(fd, &data, 1);
return data;
}
static void io_write(unsigned int port, unsigned char data)
{
lseek(fd, port, SEEK_SET);
write(fd, &data, 1);
}
int main(void)
{
char msg[32] = "pptest: use /dev/port\r\n";
int i;
fd = open(PORT_FILE, O_RDWR);
if (fd < 0) {
fprintf(stderr, "open %s failed: %s\n", PORT_FILE, strerror(errno));
return -1;
}
fprintf(stdout, "opened %s\n", PORT_FILE);
fprintf(stdout, "status 0x%02x\n", io_read(PORT_STAT));
for (i = 0; i < strlen(msg); i++) {
io_write(PORT_DATA, (unsigned char)msg[i]);
io_write(PORT_CTRL, 0x0D); /* strobe */
io_write(PORT_CTRL, 0x0C);
}
fprintf(stdout, "send message done\n");
close(fd);
return 0;
}
生成测试程式 pptest_io :
gcc -static -o pptest_io pptest_io.c
在qemu中运行:
# ./pptest_io
opened /dev/port
status 0xd9
send message done
#
查看输出结果:
$ cat pptest.txt
pptest: use /dev/port
$
使用/dev/parport
linux内核还提供 /dev/parport 设备以简化用户空间并口编程,相关模块为:
| 配置 | 模块 | 说明 |
|---|---|---|
| CONFIG_PARPORT | parport.ko | 提供通用的基本接口 |
| CONFIG_PARPORT_PC | parport_pc.ko | 提供PC标准并口驱动 |
| CONFIG_PPDEV | ppdev.ko | 提供用户空间并口设备驱动,即/dev/parport |
/dev/parport 提供了一组 ioctl 接口以供用户配置并口或直接访问IO端口,也支持使用 read/write 函数收发数据。
以下代码分别使用 ioctl 和 write 的方式来发送字符串:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <asm/ioctl.h>
#include <linux/ppdev.h>
#define DEVICE "/dev/parport0"
int main(void)
{
char msg1[32] = "pptest: use /dev/parport0\r\n";
char msg2[32] = "pptest: call write\r\n";
unsigned char stat, ctrl, ctrl_s;
int fd, i;
/* open and claim port */
fd = open(DEVICE, O_RDWR);
if (fd < 0) {
fprintf(stderr, "open %s failed: %s\n", DEVICE, strerror(errno));
return -1;
}
fprintf(stdout, "%s opened\n", DEVICE);
if (ioctl(fd, PPCLAIM) < 0) {
fprintf(stderr, "PPCLAIM failed: %s\n", strerror(errno));
close(fd);
return -1;
}
fprintf(stdout, "port claimed\n");
/* read status and initial control */
ioctl(fd, PPRSTATUS, &stat);
ioctl(fd, PPRCONTROL, &ctrl);
fprintf(stdout, "status 0x%02x\n", stat);
fprintf(stdout, "control 0x%02x\n", ctrl);
ctrl = ctrl & ~0x01;
ctrl_s = ctrl | 0x01;
/* use 'ioctl' to send data */
for (i = 0; i < strlen(msg1); i++) {
ioctl(fd, PPWDATA, &msg1[i]);
ioctl(fd, PPWCONTROL, &ctrl_s); /* strobe */
ioctl(fd, PPWCONTROL, &ctrl);
}
fprintf(stdout, "send message 1 done\n");
/* use 'write' to send data */
if (write(fd, msg2, strlen(msg2)) != strlen(msg2))
fprintf(stderr, "failed to write: %s\n", strerror(errno));
else
fprintf(stdout, "send message 2 done\n");
ioctl(fd, PPRELEASE);
fprintf(stdout, "port released\n");
close(fd);
return 0;
}
生成测试程式 pptest_dev :
gcc -static -o pptest_dev pptest_dev.c
在qemu中运行:
# insmod /lib/modules/3.12.74/parport.ko
# insmod /lib/modules/3.12.74/parport_pc.ko
parport_pc 00:04: reported by Plug and Play ACPI
parport0: PC-style at 0x378, irq 7 [PCSPP,TRISTATE]
#
# insmod /lib/modules/3.12.74/ppdev.ko
ppdev: user-space parallel port driver
#
# ./pptest_dev
/dev/parport0 opened
port claimed
status 0xd8
control 0x0c
send message 1 done
send message 2 done
port released
#
查看输出结果:
$ cat pptest.txt
pptest: use /dev/parport0
pptest: call write
$
本文介绍了如何在Linux环境下进行用户空间的并口编程,通过QEMU虚拟并口的重定向实现与PC设备交互。详细讲解了使用`/dev/port`直接访问IO端口以及利用`/dev/parport`设备的ioctl和write接口进行数据传输的方法,并提供了相应的测试代码示例。
2045

被折叠的 条评论
为什么被折叠?



