问下关于put_user问题 - Linux/Unix

来源:百度文库 编辑:神马文学网 时间:2024/06/06 09:35:56
驱动:
/*
 * char-read.c
 *
 * Character driver with read operation
 *
 * Copyright (C) 2005 Farsight
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 *
 */


#include
#include
#include
#include
#include
#include

MODULE_LICENSE ("GPL");

int hello_major = 253;
int hello_minor = 0;
int number_of_devices = 1;
char data[50]="foobar not equal to barfoo";

struct cdev cdev;
dev_t dev = 0;


static int hello_open (struct inode *inode, struct file *file)
{
  printk (KERN_INFO "Hey! device opened\n");
  return 0;
}

static int hello_release (struct inode *inode, struct file *file)
{
  printk (KERN_INFO "Hmmm... device closed\n");
  return 0;
}
ssize_t hello_read (struct file *filp, char *buff, size_t count, loff_t *offp)
{
  ssize_t result = 0;
/*这里的buff仅是演示如把内核空间的变量传递给用户空间*/
  if (copy_to_user (buff, data, sizeof(data)-1))
  result = -EFAULT;
  else 
  printk (KERN_INFO "wrote %d bytes\n", count);
  return result;
}

ssize_t hello_write (struct file *filp, const char *buf, size_t count, loff_t *f_pos)
{
  ssize_t ret = 0;
  printk (KERN_INFO "Writing %d bytes\n", count);
  if (count>127) return -ENOMEM;
  if (count<0) return -EINVAL;
  if (copy_from_user (data, buf, count)) {
  ret = -EFAULT;
  }
  else {
  data[127]='\0';
  printk (KERN_INFO"Received: %s\n", data);
  ret = count;
  }
  return ret;
}


struct file_operations hello_fops = {
  .owner = THIS_MODULE,
  .open = hello_open,
  .release = hello_release,
  .read = hello_read,
  .write = hello_write
};

static void char_reg_setup_cdev (void)
{
  int error, devno = MKDEV (hello_major, hello_minor);
  cdev_init (&cdev, &hello_fops);
  cdev.owner = THIS_MODULE;
  cdev.ops = &hello_fops;
  error = cdev_add (&cdev, devno , 1);
  if (error)
  printk (KERN_NOTICE "Error %d adding char_reg_setup_cdev", error);

}

static int __init hello_2_init (void)
{
  int result;

  dev = MKDEV (hello_major, hello_minor);
  result = register_chrdev_region (dev, number_of_devices, "hello");

  if (result<0) {
  printk (KERN_WARNING "hello: can't get major number %d\n", hello_major);
  return result;
  }

  char_reg_setup_cdev ();
  printk (KERN_INFO "char device registered\n");
  return 0;
}

static void __exit hello_2_exit (void)
{
  dev_t devno = MKDEV (hello_major, hello_minor);
  
  cdev_del (&cdev);

  unregister_chrdev_region (devno, number_of_devices);

}

module_init (hello_2_init);
module_exit (hello_2_exit);

测试程序
/*
 * test.c
 *
 * Test application code for char-read.c
 *
 * Copyright (C) 2005 Farsight
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 *
 */

#include
#include
#include
#include

int main (void) 
{
int fd;
char buff[50];
fd = open ("/dev/hello",O_RDWR);
if (fd < 0) {
printf ("fd open failed\n");
exit(0);
}
printf ("\n/dev/hello opened, fd=%d\n",fd);
memset (buff, '\0', 50);
printf ("Read returns %d\n", read (fd, buff, sizeof(buff)));
buff[50]='0';
printf ("buff = %s\n", buff);
close (fd);
printf ("/dev/hello closed :)\n");
return 0;
}

Makefile:

#KERNELDIR 变量换成你的目标内核源码

KERNELDIR ?= /home/lht/kernel2.6/linux-2.6.14  
obj-m += char-read.o

all:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules


clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions