字元裝置驅動之LED

來源:互聯網
上載者:User

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測試也是沒問題的。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.