在/dev/目录下创建字符设备节点
struct cdev * make_dev(struct cdevsw *devsw, 字符设备开关表
int unit,
uid_t uid,
gid_t gid,
int mode,
const char *fmt, ...)
删除字符设备
void destroy_dev(struct cdev *dev)
头文件:#include
DEV_MODULE是对DECLARE_MODULE的封装
#define DEV_MODULE(name, evh, arg) \
static moduledata_t name##_mod = { \
#name, \
evh, \
arg \
}; \
DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE)
定义IOCTL命令宏如下:
_IO(x,y) 定义一个不传输数据的ioctl命令 此方式data是没有用的
_IOR(x,y,z) 定义个读操作的ioctl命令 从设备向用户空间传递数据
_IOW(x,y,z) 定义个写操作的ioctl命令 从用户空间向设备传递数据
_IOWR(x,y,z) 顶一个读写操作的ioctl命令 设备和用户空间相互传递数据
x:一个8位的魔术 可以选择任何值,在整个驱动中保持一致
y:一个序号 将各个ioctl命令进行区分
z:传输的数据类型 _IO没有此参数
头文件: #include
内核代码如下:
#include
#include
#include
#include
#include
#include
#include
static d_open_t test_open;
static d_close_t test_close;
static d_read_t test_read;
static d_write_t test_write;
static d_ioctl_t test_ioctl;
//使用vmstat -m | grep testbuff 可以查看内存使用情况
//使用malloc分配内存采用M_TECDEV 自己定义的malloc_type
MALLOC_DECLARE(M_TECDEV);
MALLOC_DEFINE(M_TECDEV,"testbuff","test buff for chare dev");
//ioctl命令
#define TEST_CLEAR_BUFF _IO('Y',1)
#define TEST_SET_BUFF_SIZE _IOW('Y',2,int)
//字符设备开关
static struct cdevsw test_cdev={
.d_version = D_VERSION,//驱动程序支持的freebsd版本号 D_VERSION
.d_open = test_open,
.d_close = test_close,
.d_read = test_read,
.d_write = test_write,
.d_ioctl = test_ioctl,
.d_name = "tecdev"//驱动名字
};
static int countbuff;
static char *buff;
static struct cdev *dev;
static int test_ioctl(struct cdev *dev,
u_long cmd,
caddr_t data,
int fflag,
struct thread *td)
{
int error = 0;
switch(cmd)
{
case TEST_CLEAR_BUFF:
memset(buff,0,1024);
countbuff = 0;
case TEST_SET_BUFF_SIZE:
countbuff = *(int *)data;
default:
error = ENOTTY;
break;
}
return error;
}
static int test_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
{
uprintf("Open testdev\n");
return 0;
}
static int test_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
{
uprintf("close testcdev\n");
return 0;
}
static int test_read(struct cdev *dev, struct uio *uio, int ioflag)
{
int error = 0;
int count = 0;
count = MIN(countbuff,uio->uio_resid);
if(0 == count)
return 0;
error = uiomove(buff,count,uio);
if(error != 0)
{
uprintf("read error\n");
}
countbuff = 0;
return 0;
}
static int test_write(struct cdev *dev, struct uio *uio, int ioflag)
{
int error = 0;
error = copyin(uio->uio_iov->iov_base,buff,MIN(1024-1,uio->uio_iov->iov_len));
if(error != 0)
{
uprintf("copy from user error\n");
}
countbuff = MIN(1024-1,uio->uio_iov->iov_len);
return 0;
}
//模块事件处理程序
static int handleevent(module_t mod, int event, void *arg)
{
int error = 0;
switch(event)
{
case MOD_LOAD:
buff = malloc(1024,M_TECDEV,M_WAITOK);
dev = make_dev(&test_cdev,0,UID_ROOT,GID_WHEEL,0600,"testcdv");
break;
case MOD_UNLOAD:
destroy_dev(dev);
free(buff,M_TECDEV);
break;
default:
error = EOPNOTSUPP;
}
return error;
}
//DEV_MODULE是对DECLARE_MODULE的封装
DEV_MODULE(tecdev,handleevent,NULL);