字符设备驱动之LED-混杂设备驱动(misc)

misc_led.c

#include <linux/fs.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/miscdevice.h>

static volatile unsigned long * gpfcon; // = (volatile unsigned long *)0x56000050;
static volatile unsigned long * gpfdat; // = (volatile unsigned long *)0x56000054;

int led_open(struct inode *inode, struct file *file)
{
 /* 配置GPIO为输出引脚 */
 *gpfcon &= ~0xff00;
 *gpfcon |= 0x5500;

 return 0;
}

ssize_t led_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
 char ker_buf[2];
 
 /* 根据buf传入的值点/灭灯 */
 /* buf[0] - 哪个灯, 0 - 第1个灯 */
 /* buf[1] - 亮/灭 , 0 - 亮, 1 - 灭 */

 if (size != 2)
 {
  return -EINVAL;
 }

 copy_from_user(ker_buf, buf, 2);
 
 if (ker_buf[0] < 0 || ker_buf[0] > 3)
  return -EINVAL;

 if ((ker_buf[1] != 0) && (ker_buf[1] != 1))
  return -EINVAL;

 if (ker_buf[1])
 {
  // 灭灯
  *gpfdat |= (1<<(ker_buf[0] + 4));
 }
 else
 {
  *gpfdat &= ~(1<<(ker_buf[0] + 4));
 }
 
 return 2;
}

/* buf[0] - led1,0亮, 1灭 */
/* buf[1] - led2,0亮, 1灭 */
/* buf[2] - led3,0亮, 1灭 */
/* buf[3] - led4,0亮, 1灭 */
ssize_t led_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
{
 char ker_buf[4];
 unsigned long val;

 if (size != 4)
  return -EINVAL;

 val = *gpfdat;
 
 ker_buf[0] = (val & (1<<4)) ? 1 : 0;
 ker_buf[1] = (val & (1<<5)) ? 1 : 0;
 ker_buf[2] = (val & (1<<6)) ? 1 : 0;
 ker_buf[3] = (val & (1<<7)) ? 1 : 0;

 copy_to_user(buf, ker_buf, 4);
 return 4;
}

static const struct file_operations led_fops = {
 .owner = THIS_MODULE,
 .write = led_write,
 .read   = led_read,
 .open = led_open
};

static struct miscdevice led_misc = {
 .minor  = 140,
 .name  = "led",
 .fops  = &led_fops, 
};

int led_init(void)
{
 misc_register(&led_misc);

 gpfcon = ioremap(0x56000050, 8); /* 得到虚拟地址 */
 gpfdat = gpfcon + 1;
 
 return 0;
}

void led_exit(void)
{
 misc_deregister(&led_misc);
 iounmap(gpfcon);
}

module_init(led_init);
module_exit(led_exit);

MODULE_LICENSE("GPL");

test.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>


/* led_test <which> <on|off>
*  led_test r
 */

void print_usage(char *str)
{
 printf("Usage:\n");
 printf("%s r : read status\n", str);
 printf("%s <which> <on|off>\n", str);
 printf("which = 0,1,2,3\n");
}
 
int main(int argc, char **argv)
{
 int fd;
 char buf[4];
 int ret;
 int i;

 if (argc != 3 && argc != 2)
 {
  print_usage(argv[0]);
  return -1;
 }

 fd = open("/dev/led", O_RDWR);
 if (fd < 0)
 {
  printf("can't open /dev/led\n");
  return -1;
 }

 if (argc == 3)
 {

  buf[0] = strtoul(argv[1], NULL, 0);

  if (strcmp(argv[2], "on") == 0)
  {
   buf[1] = 0;
  }
  else
  {
   buf[1] = 1;
  }

  ret = write(fd, buf, 2);
  if (ret != 2)
  {
   printf("error!\n");
   return -1;
  }
 }
 else
 {
  if (strcmp(argv[1], "r") == 0)
  {
   ret = read(fd, buf, 4);
   for (i = 0; i < 4; i++)
   {
    printf("led%d %s\n", i+1, buf[i] ? "off" : "on");
   }
  }
 }
 
 return 0;

你可能感兴趣的:(struct,user,Module,File,null)