Android DHT 11駆動
Android DHT 11駆動 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
", __func__, dht11_dev->irq);
return -EBUSY;
case -EINVAL:
printk(KERN_ERR "*%s(): Bad irq number or handler
", __func__);
return -EINVAL;
default:
//printk(KERN_INFO "*%s():Interrupt %04x obtained
", __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
", __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
", __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
", __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
", __func__);
return -1;
}
msleep(20);
clear_interrupts();
//for(i = 0; i < 48; i++) dht11_dev->msg[i] = -1;
sprintf(msg, "Humidity=%d.%d%%
Temperature=%d.%dC
Result=%d
%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
", __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
",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
",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
", __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!
", 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");
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
", __func__, dht11_dev->irq);
return -EBUSY;
case -EINVAL:
printk(KERN_ERR "*%s(): Bad irq number or handler
", __func__);
return -EINVAL;
default:
//printk(KERN_INFO "*%s():Interrupt %04x obtained
", __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
", __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
", __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
", __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
", __func__);
return -1;
}
msleep(20);
clear_interrupts();
//for(i = 0; i < 48; i++) dht11_dev->msg[i] = -1;
sprintf(msg, "Humidity=%d.%d%%
Temperature=%d.%dC
Result=%d
%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
", __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
",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
",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
", __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!
", 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");