Android DHT11驱动

Android DHT11驱动


struct dht11_sensor_dev{
	struct cdev cdev;
	unsigned long pin;
	unsigned char value[5];
	unsigned char lock;
	unsigned int irq;
	struct timeval lasttv;
	int bitcount;
	int bytecount;
	int started;
	struct timer_list timer;
	void (*write_bit)(unsigned long pin, char bit);
	void (*delay)(short t);
};

static struct dht11_sensor_dev *dht11_dev;
struct class *dht11_class;
static int major = DEVICE_MAJOR;

static inline void usdelay(short t)
{
	return ndelay(t * 1000);
}

static inline void gpio_write_bit(unsigned long pin, char bit)
{
	gpio_set_value(pin, bit);
}
#if 0
static char gpio_read_bit(unsigned long pin)
{
	return gpio_get_value(pin) ? 1 : 0;
	//return gpio_get_value(pin);
}
static void gpio_write_bit_dir(unsigned long pin, char bit)
{
	if (bit)
		gpio_direction_input(pin);
	else
		gpio_direction_output(pin, 0);
}

static void gpio_write_bit_val(unsigned long pin, char bit)
{
	gpio_set_value(pin, bit);
}

static int dht11_get_temperature(struct dht11_sensor_dev *dev)
{
	return dev->value[0] * 1000 + dev->value[1];
}

static int dht11_get_humidity(struct dht11_sensor_dev *dev)
{
	return dev->value[2] * 1000 + dev->value[3];
}
#endif

static irqreturn_t dht11_interrupt(int irq, void *dev_id)
{
	struct dht11_sensor_dev *dev = (struct dht11_sensor_dev *)dev_id;
	struct timeval tv;
	long deltv = 0;
	int signal = 0, data = 0;

	signal = gpio_get_value(dev->pin);

	do_gettimeofday(&tv);	

	deltv = tv.tv_sec - dev->lasttv.tv_sec;
	data = (int)(deltv * 1000000 + (tv.tv_usec - dev->lasttv.tv_usec)); 
	dev->lasttv = tv;

	if(dev->bytecount == 5) return IRQ_HANDLED;
	if((signal == 1) & (data > 40)){
		dev->started = 1;
		return IRQ_HANDLED;
	}
	if((signal == 0) & (dev->started == 1)){
			if(data > 80)
				return IRQ_HANDLED;
			if(data < 30){
				dev->bitcount++;
				if(dev->bitcount == 8){
					dev->bitcount = 0;
					dev->bytecount++;
				}
				return IRQ_HANDLED;
			}
			if (data > 60)//55 
				dev->value[dev->bytecount] = dev->value[dev->bytecount] | (0x80 >> dev->bitcount);
			
			dev->bitcount++;
			if(dev->bitcount == 8){
				dev->bitcount = 0;
				dev->bytecount++;
			}
	
	}

	return IRQ_HANDLED;
}


static int setup_interrupts(void)
{
	int result;

	dht11_dev->irq = gpio_to_irq(dht11_dev->pin);
	result = request_irq(dht11_dev->irq, dht11_interrupt, 
			IRQ_TYPE_EDGE_BOTH, DEVICE_NAME, (void *)dht11_dev);

	switch (result) {
		case -EBUSY:
			printk(KERN_ERR "*%s(): IRQ %d is busy\n", __func__, dht11_dev->irq);
			return -EBUSY;
		case -EINVAL:
			printk(KERN_ERR "*%s(): Bad irq number or handler\n", __func__);
			return -EINVAL;
		default:
			//printk(KERN_INFO "*%s():Interrupt %04x obtained\n", __func__, dht11_dev->irq);
			break;
	}

	return 0;
}

static void clear_interrupts(void)
{
	free_irq(dht11_dev->irq, (void *)dht11_dev);

    if(gpio_request(dht11_dev->pin, DEVICE_NAME)){
		printk(KERN_INFO "[%s] gpio_request \n", __func__);
		return;
	}

	s3c_gpio_cfgpin(dht11_dev->pin, S3C_GPIO_OUTPUT);
	s3c_gpio_setpull(dht11_dev->pin, S3C_GPIO_PULL_NONE);
	//s5p_gpio_set_drvstr(dht11_dev->pin, S5P_GPIO_DRVSTR_LV2);
	gpio_set_value(dht11_dev->pin, 1);
	
	gpio_free(dht11_dev->pin);	
}

static int dht11_reset(struct dht11_sensor_dev *dev)
{
    if(gpio_request(dht11_dev->pin, DEVICE_NAME)){
		printk(KERN_INFO "[%s] gpio_request \n", __func__);
		return -1;
	}

	//s3c_gpio_cfgpin(dht11_dev->pin, S3C_GPIO_OUTPUT);
	s3c_gpio_cfgpin(dht11_dev->pin, S3C_GPIO_OUTPUT);
	s3c_gpio_setpull(dht11_dev->pin, S3C_GPIO_PULL_NONE);
	//s5p_gpio_set_drvstr(dht11_dev->pin, S5P_GPIO_DRVSTR_LV2);
	gpio_set_value(dht11_dev->pin, 1);
	
	dev->write_bit(dev->pin, 0);
	msleep(18);
	dev->write_bit(dev->pin, 1);
	s3c_gpio_cfgpin(dev->pin, S3C_GPIO_INPUT);
	dev->delay(20);

	gpio_free(dht11_dev->pin);	
	
	return 0;	
}

static int dht11_checksum(struct dht11_sensor_dev *dev)
{
	char tmp = 0;
	tmp = dev->value[0] + dev->value[1] + dev->value[2] + dev->value[3];
	
	if(tmp != dev->value[4]){
		//printk(KERN_INFO "[%s] %d %d\n", __func__, dev->value[4], tmp);
		return 0;
	}
	return 1;
}

static int dht11_sensor_open(struct inode *inode, struct file *filp)
{
	if(dht11_dev->lock)
		return -EBUSY;

	try_module_get(THIS_MODULE);
	dht11_dev->lock = 1;
	
	return 0;
}

static int dht11_sensor_release(struct inode *inode,struct file *filp)
{
	module_put(THIS_MODULE);
	dht11_dev->lock = 0;

	return 0;
}

static ssize_t dht11_sensor_read(
	struct file *filp,char __user *buf,size_t size,loff_t *f_pos)
{
	unsigned long length =(size>48)? 48:size;
	int result = 0;
	char msg[48];

	dht11_dev->started = 0;
	dht11_dev->bitcount = 0;
	dht11_dev->bytecount = 0;
	dht11_dev->value[0] = 0;
	dht11_dev->value[1] = 0;
	dht11_dev->value[2] = 0;
	dht11_dev->value[3] = 0;
	dht11_dev->value[4] = 0;

	if(!dht11_reset(dht11_dev)){
		do_gettimeofday(&dht11_dev->lasttv);
		setup_interrupts();
	}
	else{
		dprint("*%s(): reset fail \n", __func__);
		return -1;
	}

	msleep(20);
	clear_interrupts();

	//for(i = 0; i < 48; i++) dht11_dev->msg[i] = -1;
	sprintf(msg, "Humidity=%d.%d%%\nTemperature=%d.%dC\nResult=%d\n%c",\
			dht11_dev->value[0], dht11_dev->value[1], \
			dht11_dev->value[2], dht11_dev->value[3], \
			dht11_checksum(dht11_dev), '\0');
	
	length = strlen(msg);
	dprint(KERN_INFO "*%s(): length %lu\n", __func__, length);
#if 0
	while (length && *ptr) {
		put_user(*(ptr++), buf++);
		length--;
		result++;
	}
	put_user('\0', buf++);
	result++;
	*f_pos += result;
	return result;
#else
	result=copy_to_user(buf, msg + *f_pos, length);
	//*f_pos += length;
	*f_pos = 0;
	//if(result) return length - result;
	//else result = length;
	return length;
#endif
}
#if 0
static ssize_t dht11_sensor_write(struct file *filp,const char __user *buf,size_t size,loff_t *f_pos)
{

	return 0;
}
#endif
static struct file_operations dht11_sensor_fops={
	.owner = THIS_MODULE,
	.read = dht11_sensor_read,
	.open = dht11_sensor_open,
	.release = dht11_sensor_release,
};

static void dht11_sensor_setup_cdev(
	struct dht11_sensor_dev *dev,int minor,struct file_operations *fops)
{
	int err, devno = MKDEV(major, minor);
	cdev_init(&(dev->cdev), fops);
	dev->cdev.owner = THIS_MODULE;
	dev->cdev.ops = fops;
	err=cdev_add(&(dev->cdev), devno, 1);
	if(err){
		printk(KERN_NOTICE"erro %d adding %s %d\n",err,DEVICE_NAME,minor);
	}
}

int __init dht11_sensor_init(void){
	int result;
	dev_t devno=MKDEV(major,0);
	if(major){
		result = register_chrdev_region(devno, 1, DEVICE_NAME);
	}
	else{
		result = alloc_chrdev_region(&devno, 0, 1, DEVICE_NAME);
	}
	if(result < 0){
		printk(KERN_WARNING"%s: unable to get major %d\n",DEVICE_NAME,major);
		return result;
	}
	
	dht11_dev=kmalloc(sizeof(struct dht11_sensor_dev),GFP_KERNEL);
	if(!dht11_dev){
		result=-ENOMEM;
		goto fail_malloc;
	}

	dht11_class = class_create(THIS_MODULE, DEVICE_NAME);
	device_create(dht11_class, NULL, MKDEV(DEVICE_MAJOR, 0), NULL, DEVICE_NAME);

	dht11_sensor_setup_cdev(dht11_dev, 0, &dht11_sensor_fops);
	dht11_dev->pin = GPIO_DOUT;
	dht11_dev->delay = usdelay;
	dht11_dev->write_bit = gpio_write_bit;

        result = gpio_request(dht11_dev->pin, DEVICE_NAME);
	if(result){
		printk(KERN_INFO "[%s] gpio_request \n", __func__);
		goto fail_gpio;
	}

	//s3c_gpio_cfgpin(dht11_dev->pin, S3C_GPIO_OUTPUT);
	s3c_gpio_cfgpin(dht11_dev->pin, S3C_GPIO_OUTPUT);
	s3c_gpio_setpull(dht11_dev->pin, S3C_GPIO_PULL_NONE);
	//s5p_gpio_set_drvstr(dht11_dev->pin, S5P_GPIO_DRVSTR_LV2);
	gpio_set_value(dht11_dev->pin, 1);
	//gpio_direction_output(dht11_dev->pin, 1);
	
	gpio_free(dht11_dev->pin);	

	return 0;

fail_gpio:
	kfree(dht11_dev);
fail_malloc:
	unregister_chrdev_region(MKDEV(major,0),1);
	return result;
}

void  __exit dht11_sensor_exit(void)
{
	cdev_del(&dht11_dev->cdev);
	device_destroy(dht11_class, MKDEV(major, 0));
	class_destroy(dht11_class);
	
	//gpio_free(dht11_dev->pin);	
	kfree(dht11_dev);
	unregister_chrdev_region(MKDEV(major, 0), 1);
	//printk("%s device uninstalled OK!\n", DEVICE_NAME);
}

module_init(dht11_sensor_init);
module_exit(dht11_sensor_exit);

MODULE_AUTHOR("jvaemape");
MODULE_DESCRIPTION("S3C GPIO MQ2 Drive");
MODULE_LICENSE("Dual BSD/GPL");


你可能感兴趣的:(android,linux)