字符设备驱动简单例子

  

/*
 *  linux/drivers/char/timer_cpu_rate.c
 *
 *  Copyright (C) 2012 
 *
 *  Created by ryan, 03/17/12, for  cpu rating
 */
#include <linux/module.h>
#include <linux/init.h>
#include <asm/page.h>
#include <linux/cdev.h>
#include <linux/fs.h>  
#include <linux/errno.h>
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/jiffies.h>


static const int rate_delta_in_ticks = HZ;
static struct timer_list rate_timer;
typedef struct
{
    unsigned long cur;
    unsigned long count;
    unsigned int flag;
    unsigned int result;
   /*
 * extra info
 */
 int      start_record;
 int   cpu;
}pmedia_cpu_rate;
#define NUM_MEDIA 32
#define CPU_MONITOR 0
#define DEVNAME "timer_rate"
#define MAGIC_IOCTL_NUM 'R'
#define MAX_IOCTL_SERNR 50
#define IOCTL_SETADDR    _IOWR(MAGIC_IOCTL_NUM, 0,pmedia_cpu_rate)
pmedia_cpu_rate* user_cpu_calc_rate[NUM_MEDIA];
unsigned int mask_cpu_rate = 0;
static long ioctl_notify_calc_rate(void* args)
{
 int cpu = -1;
 int start_record_calc = 0;
 //\\pmedia_cpu_rate* tmp_user_calc_rate = (pmedia_cpu_rate*)(__va(args));
 pmedia_cpu_rate* tmp_user_calc_rate = (pmedia_cpu_rate*)(args);
 if(tmp_user_calc_rate!=NULL){
  start_record_calc = tmp_user_calc_rate->start_record;
 cpu   = tmp_user_calc_rate->cpu;
 /*
  * begin to calc in array?
  */
 if(start_record_calc==1){
  if(user_cpu_calc_rate[cpu] == NULL){
     /*
   * update kernel calc array
   */
   user_cpu_calc_rate[cpu] = tmp_user_calc_rate;
  }
  /*
   * calc op on this cpu will be opened
   */
  mask_cpu_rate|=(1UL<<cpu);
 }else{
     /*
      * otherwise close
      */
  mask_cpu_rate&=~(1UL<<cpu);
 } 
 }
 return 0;
}

static void calc_cpu_media_rate(pmedia_cpu_rate *p)
{
    p->cur += p->flag;

    if(++p->count >= 4096)
    {
        unsigned long result = p->cur;
        /* result = p->cur * 100 /4096 */
        result = (result << 3) + (result << 1);
        result = (result << 3) + (result << 1);
        result >>= 12;
        p->result = result;
        p->cur   = 0;
        p->count = 0;
    }
}

void timer_monitor_handler(void* data)
{
 int i = 0;
 for(;i<NUM_MEDIA;++i){
  if((1UL<<i)&mask_cpu_rate)
   calc_cpu_media_rate(user_cpu_calc_rate[i]);
 }
 mod_timer(&rate_timer, jiffies + rate_delta_in_ticks);
 
}
struct cdev timer_rate_dev;
static int major_devid = 0;
int chr_timer_rate_open(struct inode *inode, struct file *filp)
{
 return 0;
}
static int chr_timer_rate_ioctl(struct inode *inodep,struct file *filep,
 unsigned int cmd, unsigned long arg){
 
 if (_IOC_TYPE(cmd) != MAGIC_IOCTL_NUM)   
        return -EINVAL;   
    if (_IOC_NR(cmd) > MAX_IOCTL_SERNR)   
        return -EINVAL;   
 
    switch (cmd) 
    { 
      case IOCTL_SETADDR: 
          ioctl_notify_calc_rate((void*)arg);
          break; 
      default: 
          return -EINVAL; 
    } 
    return 0;   
}
static struct file_operations timer_rate_fops =
{
.open = chr_timer_rate_open,
.ioctl = chr_timer_rate_ioctl
};
static void chr_timer_rate_setup(void)
{
 int err,devno = MKDEV(major_devid,0);
 cdev_init(&timer_rate_dev,&timer_rate_fops);
 timer_rate_dev.owner = THIS_MODULE;
 err = cdev_add(&timer_rate_dev,devno,1);
 if(err)
  printk("Erro %d adding timer_rate\n",err);
}

static int timer_rate_init(void)
{
 int result = 0;
 dev_t devno = MKDEV(major_devid,0);
 if(major_devid){
  result = register_chrdev_region(devno,1,DEVNAME);
 }else{
  result = alloc_chrdev_region(&devno,0,1,DEVNAME);
  major_devid = MAJOR(devno);
 }
 if(result < 0 )
  return result;
 chr_timer_rate_setup();
 init_timer(&rate_timer);
 rate_timer.expires  = jiffies + 1;
 rate_timer.data     = (unsigned long)&rate_timer;
 rate_timer.function = (void *)&timer_monitor_handler;
 add_timer_on(&rate_timer,CPU_MONITOR);
 return 0;
}

static void __exit timer_rate_exit(void)
{
 cdev_del(&timer_rate_dev);   
 unregister_chrdev_region(MKDEV(major_devid,0), 1);
}

module_init(timer_rate_init);
module_exit(timer_rate_exit);
MODULE_LICENSE("GPL");

 

 

 

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/syscall.h>
#include <sys/prctl.h>
#define __USE_GNU
#include <sched.h>
#include <pthread.h>

#define LOOP_TIME 10
typedef struct
{
    unsigned long cur;
    unsigned long count;
    unsigned int flag;
    unsigned int result;
   /*
 * extra info
 */
 int      start_record;
 int   cpu;
}pmedia_cpu_rate;
#define CPU_NUM 32
pmedia_cpu_rate p_test[CPU_NUM];

#define MAX_LOOP 1000000
void mdelay(int delay)
{
 int i = 0;
 for(;i<((MAX_LOOP)*delay);++i)
  ;
}

#define DEVFILENAME "/dev/timer_rate"
#define MAGIC_IOCTL_NUM 'R'
#define IOCTL_SETADDR    _IOWR(MAGIC_IOCTL_NUM, 0,pmedia_cpu_rate)

void start_pmedia_test(int cpu)
{
 p_test[cpu].start_record = 1;
 p_test[cpu].cpu = 0;
}

void stop_pmedia_test(int cpu)
{
 p_test[cpu].start_record = 0;
 p_test[cpu].cpu = 0;
}

void print_result(int cpu)
{
 printf("cpu%d rate:%d%%\n",p_test[cpu].result);
}

void* MediaThread(void* data)
{
 cpu_set_t cpuset;
    CPU_ZERO(&cpuset);
    CPU_SET(0, &cpuset);
    sched_setaffinity((long)syscall(SYS_gettid),sizeof(cpu_set_t),&cpuset);
 while(1)
 {
  
   mdelay(10);
   sleep(1);
 }
 return NULL;
}


int main(int argc,char* argv[])
{
 int fd = -1,result=-1;
 int i  = 0;
 int result;
 pthread_t media; 
 pthread_create(&media, NULL, &MediaThread, NULL);
 pthread_join(media, (void *)&result);
 
 fd = open(DEVFILENAME, O_RDWR);
 if(fd==-1)
 {
   perror("open device error!\n");
   return -1;
 }
 start_pmedia_test(0);
 result=ioctl(fd, IOCTL_SETADDR,p_test[0]);
  if(result<0)
 {
   printf("%d",result);
   perror("ioctol error\n");
   return -1;
 }
 for(i=0;i<LOOP_TIME;++i){
  print_result(0);
  sleep(1);
 }
 stop_pmedia_test(0);
 return 0;
}

 


 

你可能感兴趣的:(字符设备驱动简单例子)