1 用户态定义寄存器结构
以键盘keyscan
为例,定义一个IP寄存器描述头文件,IOCRREG
, IOCWREG
定义了两个ioctl命令,用来读写寄存器。struct msg
用来存放寄存器地址和值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #define keyscan_top_keyscan_config1 0x0 #define keyscan_top_keyscan_config2 0x4 #define keyscan_top_keyscan_config3 0x8 #define keyscan_top_keyscan_config4 0xc ...... #define keyscan_top_reg_fifo_count 0x20 #define keyscan_top_reg_fifo_count_OFFSET 0 #define keyscan_top_reg_fifo_count_MASK 0xf #define keyscan_top_reg_fifo_not_empty 0x20 #define keyscan_top_reg_fifo_not_empty_OFFSET 4 #define keyscan_top_reg_fifo_not_empty_MASK 0x10 struct msg { long unsigned int addr; unsigned int data; }; #define IOC_MAGIC 'k' #define IOCRREG _IOR(IOC_MAGIC, 1, struct msg) #define IOCWREG _IOW(IOC_MAGIC, 2, struct msg)
|
2 驱动代码
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
| static long keyscan_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct msg m; memset(&m, 0, sizeof(m)); void __iomem* base = dev->base; switch (cmd) { case IOCRREG: if (copy_from_user(&m, (struct msg __user *)arg, sizeof(m))) return -EFAULT; m.data = readl(base + m.addr); printk(KERN_DEBUG "base_addr:0x%lx, offset:0x%lx, read data: 0x%x \n", base, m.addr, m.data); if (copy_to_user((struct msg __user *)arg, &m, sizeof(m))) return -EFAULT; break; case IOCWREG: if (copy_from_user(&m, (struct msg __user *)arg, sizeof(m))) return -EFAULT; printk(KERN_DEBUG "base_addr:0x%lx, offset:0x%lx, write data: 0x%x \n", base, m.addr, m.data); writel(m.data, base + m.addr); break; default: return -EINVAL; } return 0; }
|
驱动先定义IP base addr
,然后透过ioctl
进行arg
参数接收,确定msg
中的addr
和data
, 接收cmd
调用writel, readl
进行读写。
3 用户态代码
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
| static inline void clrsetbits_32(long unsigned int addr, unsigned int clear, unsigned int set) { int ret; struct msg m; memset(&m, 0, sizeof(m)); m.addr = addr; ret = ioctl(fd, IOCRREG, &m); if (ret) { perror("ioctl: read error!"); return; } m.data = (m.data & (~clear)) | set; ret = ioctl(fd, IOCWREG, &m); if (ret) { perror("ioctl: write error"); return; } return; } static unsigned int read_reg(long unsigned int addr) { int ret; struct msg m; memset(&m, 0, sizeof(m)); m.addr = addr; ret = ioctl(fd, IOCRREG, &m); if (ret) { perror("ioctl: read reg error!"); return -1; } return m.data; }
|
首先实现基础读写函数进行寄存器读写,reg_read
函数传入addr
即可得到val
, clrsetbits_32
需要先读,在写入val.
1 2 3 4 5 6 7 8
| #define KEYSCAN_MASK(REG_NAME) keyscan_top_##REG_NAME##_MASK #define KEYSCAN_OFFSET(REG_NAME) keyscan_top_##REG_NAME##_OFFSET #define KEYSCAN_SET(REG_NAME, VAL) \ clrsetbits_32(keyscan_top_##REG_NAME, KEYSCAN_MASK(REG_NAME), \ (VAL) << KEYSCAN_OFFSET(REG_NAME)) #define KEYSCAN_GET(REG_NAME) \ ((read_reg(keyscan_top_##REG_NAME) & KEYSCAN_MASK(REG_NAME)) >> \ KEYSCAN_OFFSET(REG_NAME))
|
例如,当调用
1 2 3 4
| KEYSCAN_GET(reg_fifo_count);
read_reg(keycan_top_reg_fifo_count) & keycan_top_reg_fifo_count_MASK >> keycan_top_reg_fifo_count_OFFSET);
|
reg_fifo
表示IP的某一个寄存器:
①count
表示位域,因此对OFFSET
定义成位域在该寄存器的偏移量(count位域是bit[3:0]
)定义为0,因此MASK
定义为0xf
.
②同理not_empty
也是一个位域,bit[4]
,OFFSET
定义成4,MASK
定义成0x10
,来屏蔽除bit[4]
的其他bit.
KEYSCAN_GET(reg_fifo_count);
最终就获取到了reg_fifo
寄存器的count
位域的内容。
KEYSCAN_GET(reg_fifo_not_empty);
最终就获取到了reg_fifo
寄存器的not_empty
位域的内容
又例如,当调用
1 2 3 4 5
| KEYSCAN_SET(reg_enable, 1);
clrsetbits_32(keycan_top_reg_enable, keycan_top_reg_enable_MASK, 1 << keycan_top_reg_enable_OFFSET);
|
1 2 3 4 5 6 7 8 9
| #define keyscan_top_reg_row_mask 0x0 #define keyscan_top_reg_row_mask_OFFSET 0 #define keyscan_top_reg_row_mask_MASK 0xff #define keyscan_top_reg_col_mask 0x0 #define keyscan_top_reg_col_mask_OFFSET 8 #define keyscan_top_reg_col_mask_MASK 0xff00 #define keyscan_top_reg_enable 0x00 #define keyscan_top_reg_enable_OFFSET 16 #define keyscan_top_reg_enable_MASK 0x10000
|
可以看到offset
定义为16
,mask定义为0x10000
,用来屏蔽除bit[16]
的其他位。clrsetbits_32
会先读出该寄存器,然后对该位set1, mask掉其他位,再次写入该寄存器。