设备配置例程清单 12. 1) devswadd 内核服务:1
| int devswadd (dev_t devno, struct devsw *dswptr)
|
这在设备交换表中为 devno 指定的设备增加了一个由 dswptr 指向的设备条目。它通常由设备驱动程序的 ddconfig() 例程调用。
清单 13. 2) devswdel() 内核服务:1
| int devswdel(dev_t devno)
|
这在设备交换表中删除一个设备条目。它由 ddconfig() 例程调用,以终止设备驱动程序。
uio 结构的组件和意义uio 结构包含一个内存缓冲,用于在实现驱动程序例程时在用户和内核空间之间的数据交换。uio 结构描述虚拟内存中不连续的缓冲。ureadc、uwritec、uiomove 和 uphysio 内核服务全都执行进入或离开 uio 结构所描述的数据缓冲的数据传输。uio 结构是在 /usr/include/sys/uio.h 文件中定义的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| struct uio {
/* ptr to array of iovec structs describing user buffer for data transfer */
struct iovec *uio_iov;
/* ptr to array of xmem structs containing cross memory descriptors for iovec array.*/
struct xmem *uio_xmem;
/* #iovec elements remaining to be processed*/
int32long64_t uio_iovcnt;
/* #iovec elements already processed */
int32long64_t uio_iovdcnt;
#ifdef _LONG_LONG
/* byte offset in file/dev to read/write */
offset_t uio_offset;
#else /* _LONG_LONG */
#ifdef __64BIT__
/* off_t offset for ANSI-C mode */
off_t uio_offset;
#else
/* ANSI-C does not support long long */
int uio_rsvd;
/* off_t offset for ANSI-C mode */
off_t uio_offset;
#endif /* __64BIT__ */
#endif /* _LONG_LONG */
/* Byte count for data transfer */
int32long64_t uio_resid;
/* Type of buffer being described by uio structure. Data pointed by
buffer can either be in user or kernel or cross-memory region. */
short uio_segflg;
/* copy of file modes from open file structure */
long uio_fmode;
};
|
设备驱动程序示例sample_driver.c1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
| #include <stdio.h>
#include <syslog.h>
#include <sys/types.h> /* for dev_t and other types */
#include <sys/errno.h> /* for errno declarations */
#include <sys/sysconfig.h> /* for sysconfig() */
#include <sys/device.h> /* for devsw */
#include <sys/uio.h> /* for uiomove */
#include <sys/sysmacros.h>
struct dr_data
{
char buffer[1024];
}dr_data[5];
int dr_open(dev_t devno, ulong devflag, chan_t chan, int ext)
{
bsdlog(LOG_KERN|LOG_DEBUG,"Inside dr_open\n");
return 0;
}
int dr_close (dev_t devno, chan_t chan)
{
bsdlog(LOG_KERN|LOG_DEBUG,"Inside dr_close \n");
return 0;
}
int dr_read (dev_t devno, struct uio *uiop, chan_t chan, int ext)
{
uint min;
int rc;
min = minor_num(devno);
rc = uiomove(dr_data[min].buffer, 1024, UIO_READ, uiop);
bsdlog(LOG_KERN | LOG_DEBUG, "Inside dr_read min:
%d, buffer: %s \n", min, dr_data[min].buffer);
return rc;
}
int dr_write (dev_t devno, struct uio *uiop, chan_t chan, int ext)
{
uint min;
int rc;
min = minor_num(devno);
rc = uiomove(dr_data[min].buffer, 1024, UIO_WRITE, uiop);
bsdlog(LOG_KERN | LOG_DEBUG,"Inside dr_write min:
%d, buffer: %s \n", min, dr_data[min].buffer);
return rc;
}
int driverdd_config (dev_t devno, int cmd, struct uio *uiop)
{
struct devsw dswp;
int rc = 0;
switch (cmd)
{
case CFG_INIT:
dswp.d_open = dr_open;
dswp.d_close = dr_close;
dswp.d_read = dr_read;
dswp.d_write = dr_write;
dswp.d_ioctl = nodev;
dswp.d_strategy = nodev;
dswp.d_ttys = NULL;
dswp.d_select = nodev;
dswp.d_config = driverdd_config;
dswp.d_print = nodev;
dswp.d_dump = nodev;
dswp.d_mpx = nodev;
dswp.d_revoke = nodev;
dswp.d_dsdptr = NULL;
dswp.d_selptr = NULL;
dswp.d_opts = DEV_MPSAFE|DEV_64BIT;
if((rc = devswadd(devno, &dswp)) != 0)
{
rc = major_num(devno);
printf("Error in devswadd: %d\n", rc);
return rc;
}
break;
case CFG_TERM:
if((rc = devswdel(devno)) != 0)
{
printf("Error in devswdel: %d\n", rc);
return rc;
}
break;
default:
printf("Invalid command \n");
return EINVAL;
}
return 0;
}
|
给定设备驱动程序的配置应用程序示例Config_mgr.c1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
| #include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/sysmacros.h>
#include <sys/sysconfig.h>
#include <sys/device.h>
#include <sys/mode.h>
#include <odmi.h>
#include <cf.h>
#include <sys/cfgodm.h>
#include <sys/cfgdb.h>
int main()
{
struct cfg_load ext_load; /* to load kernel extension */
struct cfg_dd ddcfg; /* to invoke driver config() */
char c, str[80];
int rc;
int major, minor = 0;
dev_t devno;
rc = odm_initialize();
printf("\n Enter choice, (l)oad, (u)nload \n");
while((c = getchar()) < 'a' && c > 'z');
switch(c) {
case 'l':
ext_load.path = "sample_driver";
ext_load.libpath = NULL;
ext_load.kmid = 0;
if(sysconfig(SYS_KLOAD,
&ext_load, sizeof(struct cfg_load))) {
printf("Error in loading extension\n");
exit (1);
}
else
printf("Extension Successfully loaded, kmid is %d\n", ext_load.kmid);
major = genmajor("sample_driver");
printf("Major number: %d\n", major);
devno = makedev64(major, minor);
ddcfg.kmid = ext_load.kmid;
ddcfg.devno = devno;
ddcfg.cmd = CFG_INIT;
ddcfg.ddsptr = NULL;
ddcfg.ddslen = 0;
if (rc = sysconfig(SYS_CFGDD,
&ddcfg, sizeof(ddcfg))) {
printf("Error in configuring device %d %d\n", rc, errno);
exit (1);
}
for(minor = 0; minor <=2; minor++) {
devno = makedev64(major, minor);
sprintf(str, "/dev/drvdd%d", minor);
if (mknod(str, 0666 | _S_IFCHR, devno) == -1){
printf("Error while creating device %s\n", str);
exit (1);
}
}
break;
case 'u':
ext_load.path = " sample_driver";
ext_load.libpath = NULL;
ext_load.kmid = 0;
if(sysconfig(SYS_QUERYLOAD, &ext_load,
sizeof(struct cfg_load)))
printf("Error while querying\n");
if(sysconfig(SYS_KULOAD, &ext_load,
sizeof(struct cfg_load)))
printf("Error in unloading extension\n");
else
printf("Extension Successfully unloaded\n");
break;
default:
printf("Incorrect option\n");
break;
}
return 0;
}
|
利用已实现设备驱动程序的应用程序的示例application.c1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| #include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
int fd0, fd1;
char rbuf[1024];
fd0 = open("/dev/drvdd0", O_RDWR);
if(fd0 < 0){
printf("Error in opening /dev/drvdd0\n");
return -1;
}
fd1 = open("/dev/drvdd1", O_RDWR);
if(fd1 < 0){
printf("Error in opening /dev/drvdd1\n");
return -1;
}
write(fd0, "Hello", 5);
write(fd1, "World", 5);
read(fd0, rbuf, 5);
printf("Read from /dev/drvdd0 : %s\n",rbuf);
read(fd1, rbuf, 5);
printf("Read from /dev/drvdd1 : %s\n",rbuf);
return 0;
}
|
Makefile1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| all: sample_driver config_mgr application
config_mgr: config_mgr.c
cc -q64 -o config_mgr -g config_mgr.c -lodm -lcfg
application: application.c
cc -o application application.c
K_LIBS= -bI:/usr/lib/kernex.exp -lsys -lcsys
sample_driver: sample_driver.c
cc -q64 -o sample_driver64.o -c sample_driver.c -D_KERNEL -D_64BIT_KERNEL
ld -b64 -o sample_driver sample_driver64.o -e driverdd_config $(K_LIBS)
clean:
rm -f *.o sample_driver sample_driver32
sample_driver64 config_mgr application 2> /dev/null
|
样例驱动程序的编译和测试以 root 权限登录到 AIX 6.1 或更高版本的系统。将上述文件复制到开发目录,并在 shell 命令提示符下运行 make 命令。
此操作构建必要的驱动程序、配置实用程序和一个应用程序,该应用程序又会调用驱动程序 API。然后在命令提示符下运行 ./config_mgr 实用程序,并检查驱动程序是否已被成功加载。如果没有抛出错误,您可以继续执行 ./application,它将测试驱动程序 API。 |