一、往用戶空間傳遞數據
1.傳遞單個數據
put_user()可以向用戶空間傳遞單個數據。單個數據並不是指一個字節數據,對ARM而言, put_user一次性可傳遞一個char , short或者int型的數據,即1、2或者4字節。用put_user比用copy_to_user要快:
int put_user(x,p)
- x 為內核空間的數據,
- p 為用戶空間的指針。
- 傳遞成功,返回 0,否則返回-EFAULT。
put_user 一般在 ioctl 方法中使用,假如要往用戶空間傳遞一個 32 位的數據,可以這樣實現:
static int char_cdev_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
u32 dat,
switch(cmd)
{
case CHAR_CDEV_READ:
...其它操作
dat = 數據;
if (put_user(dat, (u32 *)arg) ) {
printk("put_user err\n");
return -EFAULT;
}
}
...其它操作
return ret;
}
__put_user 是沒有進行地址驗證的版本。
2.傳遞多個數據
copy_to_user()可以一次性向用戶空間傳遞一個數據塊,函數原型如下:
static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n);
- to 是內核空間緩沖區地址,
- from 是用戶空間地址,
- n 是數據字節數,
- 返回值是不能被復制的字節數,返回 0 表示全部復制成功。
copy_to_user()一般在 read 方法中使用。假如驅動要將從設備讀到的 count 個數據送往用戶空間,可以這樣實現:
static ssize_t char_cdev_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{
unsigned char data[256] = {0};
....從設備獲取數據
if (copy_to_user((void *)buf, data, count)) {
printk("copy_to_user err\n");
return -EFAULT;
}
return count;
}
__copy_to_user 是沒有進行地址驗證的版本。
二、從用戶空間獲取數據
1.獲取單個數據
調用get_user()可以從用戶空間獲取單個數據,單個數據並不是指一個字節數據,對ARM而言,get_user一次性可獲取一個char、short或者 int型的數據,即1、2或者4字節。用get_user比用get_from_user要快:
int get_user(x,p)
- x為內核空間的數據
- p為用戶空間的指針。
- 獲取成功,返回0,否則返回-EFAULT.
get_user()一般也用在ioctl方法中。假如驅動需要從用戶空間獲取一個32位數,然后寫到某個寄存器中,可以這樣實現:
static int char_cdev_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
u32 dat,
switch(cmd)
{
case CHAR_CDEV_WRITE:
if (get_user(dat, (u32 *)arg) ) {
printk("get_user err\n");
return -EFAULT;
}
CHAR_CDEV_REG = dat;
...其它操作
}
...其它操作
return ret;
}
__get_user 是沒有進行地址驗證的版本。
2.獲取多個數據
copy_from_user()可以一次性從用戶空間獲取一個數據塊。
函數原型如下:
static inline unsigned long _must_ check copy_from_user(void *to, const void_user*from, unsigned long n);
- to是內核空間緩沖區地址,
- from是用戶空間地址
- n是數據字節數
- 返回值是不能被復制的字節數,返回0表示全部復制成功。
copy_from_user()常用在 write方法中。如果驅動需要從用戶空間獲取count字節數據,用於操作設備,可以這樣實現:
static ssize_t char_cdev_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
unsigned char data[256];
if (copy_from_user(&data, buf, 256) ) {
printk("copy_from_user err\n");
return -EFAULT;
}
...
}
__copy_from_user 是沒有進行地址驗證的版本。