字符设备驱动之LED

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>

/* 次设备号:
 *   0  - 所有的灯
 *   1  - led1
 *   2  - led2
 *   3  - led3
 *   4  - led4
 */

static int major;

static struct class *led_class;

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)
{
 int minor = iminor(inode);

 if (minor > 4)
  return -EINVAL;
 
 /* 配置GPIO为输出引脚 */
 if (minor == 0)
 {
  *gpfcon &= ~0xff00;     /*设置gpf4,5,6,7为输出引脚*/
  *gpfcon |= 0x5500;
 }
 else
 {
  *gpfcon &= ~(0x3 << ((minor+3)*2)); /*否则单独设置某个引脚为输出功能*/
  *gpfcon |= (0x1 << ((minor+3)*2));;
 }

 return 0;
}

ssize_t led_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
 char ker_buf[1];
 int minor = iminor(file->f_path.dentry->d_inode);
 
 /* 根据buf传入的值点/灭灯 */
 /* buf[0] - 亮/灭 , 0 - 亮, 1 - 灭 */

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

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

 if (minor == 0)
 {
  if (ker_buf[0])
  {
   // 全灭
   *gpfdat |= (0xf<<4);
  }
  else
  {
   // 全亮
   *gpfdat &= ~(0xf<<4);
  }
 }
 else
 {
  if (ker_buf[0])
  {
   // 某个LED
   *gpfdat |= (0x1<<(minor + 3));
  }
  else
  {
   // 某个LED
   *gpfdat &= ~(0x1<<(minor + 3));
  }
 }
 
 return 1;
}

static int led_ioctl(struct inode *inode, struct file *file, unsigned int cmd,unsigned long arg)
{
 unsigned int minor = iminor(inode);
 if(minor>4)
  return -1;

 switch(cmd)
 {
  case 0: 
    if (minor == 0) {
     printk("leds right all\n");(用于调试,在串口上能够观察执行到了这步没有)
     // 全亮
     *gpfdat &= ~(0xf<<4);
    }
    // 某个LED 亮
    *gpfdat &= ~(0x1<<(minor + 3));
    break; 
  case 1:
    if (minor == 0) {
      // 全灭  
      *gpfdat |= (0xf<<4);       
    }
    // 某个LED 灭
    printk("led off \n");
    *gpfdat |= (0x1<<(minor + 3));
    break;
  default :
    break;
 } 
  
 return 0;
}

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

int led_init(void)
{
 int i;
 
 major = register_chrdev(0, "led", &led_fops);

 /* sysfs 自动创建设备节点 */
 led_class = class_create(THIS_MODULE, "led_class");
 class_device_create(led_class, NULL, MKDEV(major, 0), NULL, "leds"); // /dev/leds

 for (i = 1; i <= 4; i++)
  class_device_create(led_class, NULL, MKDEV(major, i), NULL, "led%d", i); // /dev/led1,2,3,4

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

void led_exit(void)
{
 int i;
 unregister_chrdev(major, "led");
 for (i = 0; i <= 4; i++)
  class_device_destroy(led_class, MKDEV(major, i));
  class_destroy(led_class);

 iounmap(gpfcon);
}

module_init(led_init);
module_exit(led_exit);

MODULE_LICENSE("GPL");

ioctl_test.c

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

/* led_test <dev> <on|off>
 * led_test /dev/leds on
 * led_test /dev/led1 on
 */
void print_usage(char *str)
{
 printf("Usage:\n");
 printf("%s </dev/leds | /dev/ledN 1,2,3,4> <on|off>\n", str);
}

int main(int argc, char **argv)
{
 int fd;
 char buf[2];
 int ret;
 int cmd;
 if(argc!=3&&argc!=2)
 {
  print_usage(argv[0]);
  return -1;
 }
 fd=open(argv[1],O_RDWR);
 if(fd<0)
 {
  printf("can't open %s\n", argv[1]);
  return -1;
 }
 if(strcmp(argv[2],"on")==0)
 {
 
  cmd=0;
 }
 else
 {
  cmd=1;
 }
  ret=ioctl(fd,cmd,NULL);
 if(ret <0)
  printf("error!\n");
 return 0;
}

write_test.c

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

/* led_test <dev> <on|off>
 * led_test /dev/leds on
 * led_test /dev/led1 on
 */
void print_usage(char *str)
{
 printf("Usage:\n");
 printf("%s </dev/leds | /dev/ledN 1,2,3,4> <on|off>\n", str);
}

int main(int argc, char **argv)
{
 int fd;
 char buf[1];
 int ret;

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

 fd = open(argv[1], O_RDWR);
 if (fd < 0)
 {
  printf("can't open %s\n",argv[1]);
  return -1;
 }

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

 ret = write(fd, buf, 1);
 if (ret != 1)
 {
  printf("error!\n");
  return -1;
 }
 
 return 0;
}

简单的Makefile

all:
    make -C /home/kernel/linux-2.6.22.6 M=`pwd` modules (前面是tab缩进哦)

clean:
    make -C /home/kernel/linux-2.6.22.6 M=`pwd` clean

obj-m += led_drv.o 

测试结果:

#insmod led.ko

#./ioctl
Usage:
./ioctl </dev/leds | /dev/ledN 1,2,3,4> <on|off>

#./ioctl /dev/leds on
leds right all

write测试也是没问题的。

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