驱动代码:
#include <linux/module.h> #include <linux/fs.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/gpio.h> #include <plat/gpio-cfg.h> #define DEVICE_NAME "TEM0" #define TEM_SHOW_CODE 0x01 //static struct cdev cdev; struct class *tem_class; //static dev_t devno; //static int major = 243;//可以用int alloc_chrdev_region(dev_t *dev,unsigned baseminor, //unsigned count,const char *name);向系统动态申请未被占用的设备号。 struct tem_dev_t { struct cdev cdev; }tem_dev; /** * * s3c_gpio_cfgpin() - Change the GPIO function of a pin. * * @pin pin The pin number to configure. * * @to to The configuration for the pin's function. * * * * Configure which function is actually connected to the external * * pin, such as an gpio input, output or some form of special function * * connected to an internal peripheral block. * * * * The @to parameter can be one of the generic S3C_GPIO_INPUT, S3C_GPIO_OUTPUT * * or S3C_GPIO_SFN() to indicate one of the possible values that the helper * * will then generate the correct bit mask and shift for the configuration. * * * * If a bank of GPIOs all needs to be set to special-function 2, then * * the following code will work: * * * * for (gpio = start; gpio < end; gpio++) * * s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(2)); * * * * The @to parameter can also be a specific value already shifted to the * * correct position in the control register, although these are discouraged * * in newer kernels and are only being kept for compatibility. * */ unsigned int gpio=0; void tem_reset(void) { s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(1));//当x=0时是输入功能,x=1时是输出功能 gpio_set_value(gpio, 1); udelay(100);//延迟0.1ms gpio_set_value(gpio, 0); udelay(600); gpio_set_value(gpio, 1); udelay(100); s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(0)); } void tem_wbyte(unsigned char data) { int i; s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(1)); for (i = 0; i < 8; ++i) { gpio_set_value(gpio, 0); udelay(1); if (data & 0x01) { gpio_set_value(gpio, 1); } udelay(60); gpio_set_value(gpio, 1); udelay(15); data >>= 1; } gpio_set_value(gpio, 1); } unsigned char tem_rbyte(void) { int i; unsigned char ret = 0; for (i = 0; i < 8; ++i) { s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(1)); gpio_set_value(gpio, 0); udelay(1); gpio_set_value(gpio, 1); s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(0)); ret >>= 1; if (gpio_get_value(gpio)) { ret |= 0x80; } udelay(60); } s3c_gpio_cfgpin(gpio, S3C_GPIO_SFN(1)); return ret; } static ssize_t tem_read(struct file *filp, char *buf, size_t len, loff_t *offset) { unsigned char low, high; tem_reset(); udelay(420); tem_wbyte(0xcc); tem_wbyte(0x44); mdelay(750); tem_reset(); udelay(400); tem_wbyte(0xcc); tem_wbyte(0xbe); low = tem_rbyte(); high = tem_rbyte(); *buf = low / 16 + high * 16; *(buf + 1) = (low & 0x0f) * 10 / 16 + (high & 0x0f) * 100 / 16 % 10; return 0; } /******************************************************************* * *ioctl 还不准确,需要改进 * by mhb * **********************************************************************/ int tem_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg) { printk("in the ioctl!!\n");//debug switch(cmd) { case TEM_SHOW_CODE: { int i; unsigned char fc,sn[6],crc; tem_reset(); udelay(400); tem_wbyte(0x33); fc = tem_rbyte; for (i = 0; i < 5; i++) { /* code */ sn[i]=tem_rbyte; } crc=tem_rbyte; printk("familycode=%x\n",fc); printk("serialnumber=%x%x%x%x%x%x\n",sn[5],sn[4],sn[3],sn[2],sn[1],sn[0]); printk("crc=%x\n",crc); break; } default: { return - ENOTTY; } } } static struct file_operations tem_fops = { .owner = THIS_MODULE, .read = tem_read, .ioctl =tem_ioctl, }; static int __init tem_init(void) { int result; int major; int minor; cdev_init(&tem_dev.cdev,&tem_fops);/*init cdev*/ tem_dev.cdev.owner=THIS_MODULE; // devno = MKDEV(major, 0); // result = register_chrdev_region(devno, 1, DEVICE_NAME); result = alloc_chrdev_region(&tem_dev.cdev.dev,0,1,DEVICE_NAME); major=MAJOR(tem_dev.cdev.dev); minor=MINOR(tem_dev.cdev.dev); if(major) { printk("majior=%d\n",major); printk("minor=%d\n",minor); }else printk("can not get device num!!\n"); if (result) { printk("register failed\n"); return result; } #ifdef CONFIG_OK210_BOARD_V2 gpio=S5PV210_MP04(3); #else gpio=S5PV210_GPH3(1); #endif // cdev_init(&cdev, &tem_fops); // cdev.owner = THIS_MODULE; // cdev.ops = &tem_fops; result = cdev_add(&tem_dev.cdev, tem_dev.cdev.dev, 1); if (result) { printk("cdev add failed\n"); goto fail1; } tem_class = class_create(THIS_MODULE, "tmp_class");/*在sys目录下创建tmp_class这个类,/sys/class/~*/ if (IS_ERR(tem_class)) { printk("class create failed\n"); goto fail2; } device_create(tem_class, NULL, tem_dev.cdev.dev, DEVICE_NAME, DEVICE_NAME);/*自动创建设备/dev/TEM0*/ return 0; fail2: cdev_del(&tem_dev.cdev); fail1: unregister_chrdev_region(tem_dev.cdev.dev, 1); return result; } static void __exit tem_exit(void) { device_destroy(tem_class, tem_dev.cdev.dev); class_destroy(tem_class); cdev_del(&tem_dev.cdev); unregister_chrdev_region(tem_dev.cdev.dev, 1); } module_init(tem_init); module_exit(tem_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("mhb");
测试代码:
#include "stdio.h" #include "sys/types.h" #include "sys/ioctl.h" #include "stdlib.h" #include "termios.h" #include "sys/stat.h" #include "fcntl.h" #include "sys/time.h" #define TEM_SHOW 0x01 main() { int fd; #if 1 unsigned char buf[2]; #else unsigned int tmp; #endif float result; if ((fd=open("/dev/TEM0",O_RDWR | O_NDELAY | O_NOCTTY)) < 0) { printf("Open Device DS18B20 failed.\r\n"); exit(1); } else { printf("Open Device DS18B20 successed.\r\n"); while(1) { // read(fd, buf, sizeof(buf)); // result = tmp * 1000; // result = *(int *)buf; read(fd, buf, sizeof(buf)); #if 0 printf("%d\n", buf[0]); printf("%d\n", buf[1]); result = (float)buf[0]; result /= 16; result += ((float)buf[1] * 16); #endif #if 0 // printf("%f .C\r\n", result); sleep(1); #else printf("%d.%d C\r\n", buf[0], buf[1]); sleep(1); ioctl(fd,TEM_SHOW,0); #endif } close(fd); } }