当前位置:首页 > 嵌入式培训 > 嵌入式学习 > 讲师博文 > Linux下编写zlg7290驱动(4)

Linux下编写zlg7290驱动(4) 时间:2018-09-25      来源:未知

3. LED数码管驱动编写

在第二节驱动的基础上我们加入LED数码管驱动,这里我们简单点直接构建一个简单的字符设备驱动即可。

3.1. 字符设备注册

static int register_led(void)

{

int ret;

dev_t devno = MKDEV(led_major, led_minor);

ret = register_chrdev_region(devno, 1, "led");

if (ret < 0) {

printk("Failed: register_chrdev_region\n");

return -1;

}

cdev_init(&zlg7290->cdev, &zlg7290_led_fops);

zlg7290->cdev.owner = THIS_MODULE;

ret = cdev_add(&zlg7290->cdev, devno, 1);

if (ret < 0) {

unregister_chrdev_region(devno, 1);

printk("Failed: cdev_add\n");

return -1;

}

return 0;

}

static int unregister_led(void)

{

dev_t devno = MKDEV(led_major, led_minor);

cdev_del(&zlg7290->cdev);

unregister_chrdev_region(devno, 1);

return 0;

}

3.2. 用户接口实现

static int zlg7290_open(struct inode *inode, struct file *file)

{

return 0;

}

static int zlg7290_release(struct inode *inode, struct file *file)

{

return 0;

}

static long zlg7290_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {

unsigned char buf[8] = {0};

ssize_t len = 0;

unsigned char val[2] = {0};

unsigned char reg[8] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17};

int i = 0;

switch (cmd) {

case SET_VAL:

if (copy_from_user(buf, (void *)arg, 8))

return -EFAULT;

for(i = 0; i < 8; i++) {

val[0] = reg[i];

switch(buf[i]) {

case '0': val[1] = 0xfc; break;

case '1': val[1] = 0x0c; break;

case '2': val[1] = 0xda; break;

case '3': val[1] = 0xf2; break;

case '4': val[1] = 0x66; break;

case '5': val[1] = 0xb6; break;

case '6': val[1] = 0xbe; break;

case '7': val[1] = 0xe0; break;

case '8': val[1] = 0xfe; break;

case '9': val[1] = 0xf6; break;

case 'a':

case 'A': val[1] = 0xee; break;

case 'b':

case 'B': val[1] = 0x3e; break;

case 'c':

case 'C': val[1] = 0x9c; break;

case 'd':

case 'D': val[1] = 0x7a; break;

case 'e':

case 'E': val[1] = 0x9e; break;

case 'f':

case 'F': val[1] = 0x8e; break;

case ' ': val[1] = 0x00; break;

default:

val[1] = 0x00; break;

}

msleep(10);

zlg7290_hw_write(zlg7290, 2, &len, val);

}

break;

}

return 0;

}

static struct file_operations zlg7290_led_fops = {

.owner = THIS_MODULE,

.open = zlg7290_open,

.release = zlg7290_release,

.unlocked_ioctl = zlg7290_ioctl,

};

3.3. 测试程序

#include

#include

#include

#include

#include

#include

#include

#define SET_VAL _IO('Z', 0)

int main(int argc, const char *argv[])

{

time_t t;

struct tm *tm;

char buf[8] = "8765 321";

int fd = open("/dev/zlg7290", O_RDWR);

if (fd < 0) {

perror("open");

exit(1);

}

while(1) {

time(&t);

tm = localtime(&t);

sprintf(buf, "%02d %02d %02d", tm->tm_hour, tm->tm_min, tm->tm_sec);

printf("%s\n", buf);

ioctl(fd, SET_VAL, buf);

sleep(1);

}

return 0;

}

当执行应用程序后8个数码管会见识当前系统时间如下:

10 01 01

4. 完整驱动

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define ZLG7290_NAME "zlg7290"

#define SET_VAL _IO('Z', 0)

unsigned int led_major = 800;

unsigned int led_minor = 0;

/*zlg7290 device struct*/

struct zlg7290

{

struct i2c_client *client;

struct work_struct work;

struct input_dev *key;

struct cdev cdev;

};

struct zlg7290 *zlg7290;

unsigned int key_value[65] = {

0,

1, 2, 3, 4, 5, 6, 7, 8,

9, 10, 11, 12, 13, 14, 15, 16,

17, 18, 19, 20, 21, 22, 23, 24,

25, 26, 27, 28, 29, 30, 31, 32,

33, 34, 35, 36, 37, 38, 39, 40,

41, 42, 43, 44, 45, 46, 47, 48,

49, 50, 51, 52, 53, 54, 55, 56,

57, 58, 59, 60, 61, 62, 63, 64,

};

/*****************Character device File operations application interface part

* begin********/

static int zlg7290_hw_write(struct zlg7290 *ctr_zlg7290,

int len, size_t *retlen, char *buf)

{

struct i2c_client *client = ctr_zlg7290->client;

int ret;

struct i2c_msg msg[] = {

{ client->addr, 0, len, buf}, /*the buf contains register address*/

};

ret =i2c_transfer(client->adapter, msg, 1);

if (ret < 0)

{

printk("ret=%d,addr=%x\n",ret,client->addr);

dev_err(&client->dev, "i2c read error/n");

return -EIO;

}

*retlen = len;

return 0;

}

static int zlg7290_hw_read(struct zlg7290 *ctr_zlg7290 ,

int len, size_t *retlen, char *buf)

{

struct i2c_client *client = ctr_zlg7290->client;

int ret;

struct i2c_msg msg[] = {

{ client->addr, 0, len, buf}, /*the buf contains register address*/

{ client->addr, I2C_M_RD, len, buf },/*the buf contains register value*/

};

ret =i2c_transfer(client->adapter, msg, 2);

if (ret < 0)

{

printk("ret=%d,addr=%x\n",ret,client->addr);

dev_err(&client->dev, "i2c read error/n");

return -EIO;

}

*retlen = len;

return 0;

}

static int zlg7290_open(struct inode *inode, struct file *file)

{

return 0;

}

static int zlg7290_release(struct inode *inode, struct file *file)

{

return 0;

}

static void zlg7290_work(struct work_struct *work)

{

struct zlg7290 *ctr_zlg7290 = container_of(work, struct zlg7290, work);

unsigned char val = 0;

size_t len;

unsigned char status = 0;

zlg7290_hw_read(ctr_zlg7290, 1, &len, &status);

if(status & 0x1) {

val = 1;

zlg7290_hw_read(ctr_zlg7290, 1, &len, &val);

if (val == 0) {

val = 3;

zlg7290_hw_read(ctr_zlg7290, 1, &len, &val);

if (val == 0 || val == 0xFF)

goto out;

}

//printk("key_val = %02x\n", val);

if (val > 56) {

switch (val) {

case 0xFE: val = 57; break;

case 0xFD: val = 58; break;

case 0xFB: val = 59; break;

case 0xF7: val = 60; break;

case 0xEF: val = 61; break;

case 0xDF: val = 62; break;

case 0xBF: val = 63; break;

case 0x7F: val = 64; break;

}

}

//printk("key_val = %02x\n", val);

input_report_key(ctr_zlg7290->key, key_value[val], 1);

input_report_key(ctr_zlg7290->key, key_value[val], 0);

input_sync(ctr_zlg7290->key);

}

out:

return;

//printk("jiffies = %ld\n", jiffies);

//schedule_delayed_work(&zlg7290->work, HZ / 5);

}

static long zlg7290_ioctl(struct file *file,

unsigned int cmd, unsigned long arg) {

unsigned char buf[8] = {0};

ssize_t len = 0;

unsigned char val[2] = {0};

unsigned char reg[8] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17};

int i = 0;

switch (cmd) {

case SET_VAL:

if (copy_from_user(buf, (void *)arg, 8))

return -EFAULT;

for(i = 0; i < 8; i++) {

val[0] = reg[i];

switch(buf[i]) {

case '0': val[1] = 0xfc; break;

case '1': val[1] = 0x0c; break;

case '2': val[1] = 0xda; break;

case '3': val[1] = 0xf2; break;

case '4': val[1] = 0x66; break;

case '5': val[1] = 0xb6; break;

case '6': val[1] = 0xbe; break;

case '7': val[1] = 0xe0; break;

case '8': val[1] = 0xfe; break;

case '9': val[1] = 0xf6; break;

case 'a':

case 'A': val[1] = 0xee; break;

case 'b':

case 'B': val[1] = 0x3e; break;

case 'c':

case 'C': val[1] = 0x9c; break;

case 'd':

case 'D': val[1] = 0x7a; break;

case 'e':

case 'E': val[1] = 0x9e; break;

case 'f':

case 'F': val[1] = 0x8e; break;

case ' ': val[1] = 0x00; break;

default:

val[1] = 0x00; break;

}

msleep(10);

zlg7290_hw_write(zlg7290, 2, &len, val);

}

break;

}

return 0;

}

static struct file_operations zlg7290_led_fops = {

.owner = THIS_MODULE,

.open = zlg7290_open,

.release = zlg7290_release,

.unlocked_ioctl = zlg7290_ioctl,

};

static int register_led(void)

{

int ret;

dev_t devno = MKDEV(led_major, led_minor);

ret = register_chrdev_region(devno, 1, "led");

if (ret < 0) {

printk("Failed: register_chrdev_region\n");

return -1;

}

cdev_init(&zlg7290->cdev, &zlg7290_led_fops);

zlg7290->cdev.owner = THIS_MODULE;

ret = cdev_add(&zlg7290->cdev, devno, 1);

if (ret < 0) {

unregister_chrdev_region(devno, 1);

printk("Failed: cdev_add\n");

return -1;

}

return 0;

}

static int unregister_led(void)

{

dev_t devno = MKDEV(led_major, led_minor);

cdev_del(&zlg7290->cdev);

unregister_chrdev_region(devno, 1);

return 0;

}

irqreturn_t zlg7290_interrupt(int irq, void *devid)

{

printk("irq = %d\n", irq);

schedule_work(&zlg7290->work);

return IRQ_HANDLED;

}

static int zlg7290_probe(struct i2c_client *client, const struct i2c_device_id *id)

{

struct input_dev *key_dev;

int ret = 0;

int i = 0;

int err = -EINVAL;

if (!(zlg7290 = kzalloc(sizeof(struct zlg7290), GFP_KERNEL)))

return -ENOMEM;

printk("irq = %d\n", client->irq);

zlg7290->key = input_allocate_device();

if (zlg7290->key == NULL) {

kfree(zlg7290);

return -ENOMEM;

}

key_dev = zlg7290->key;

key_dev->name = "zlg7290";

key_dev->id.bustype = BUS_HOST;

key_dev->id.vendor = 0x0001;

key_dev->id.product = 0x0001;

key_dev->id.version = 0x0001;

key_dev->evbit[0] = BIT_MASK(EV_KEY);

for(i = 1; i <= 64; i++) {

key_dev->keybit[BIT_WORD(key_value[i])] |= BIT_MASK(key_value[i]);

}

ret = input_register_device(key_dev);

if (ret < 0) {

printk("Failed to register input device\n");

goto err1;

}

printk("zlg7290 probe\n");

if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {

err = -ENODEV;

return err;

}

zlg7290->client = client;

i2c_set_clientdata(client, zlg7290);

INIT_WORK(&zlg7290->work, zlg7290_work);

// schedule_delayed_work(&zlg7290->work, HZ / 5);

ret = request_irq(client->irq, zlg7290_interrupt,

IRQF_DISABLED|IRQF_TRIGGER_FALLING, "zlg7290", NULL);

if (ret < 0) {

goto err1;

}

ret = register_led();

if (ret < 0)

goto err1;

return 0;

err1:

input_free_device(key_dev);

kfree(zlg7290);

return ret;

}

static int zlg7290_remove(struct i2c_client *client)

{

unregister_led();

free_irq(client->irq, NULL);

i2c_set_clientdata(client, NULL);

input_unregister_device(zlg7290->key);

input_free_device(zlg7290->key);

kfree(zlg7290);

return 0;

}

static const struct i2c_device_id zlg7290_id[] = {

{ZLG7290_NAME, 0 },

{ }

};

MODULE_DEVICE_TABLE(i2c, zlg7290_id);

static struct i2c_driver zlg7290_driver= {

.probe = zlg7290_probe,

.remove = zlg7290_remove,

.id_table = zlg7290_id,

.driver = {

.name = ZLG7290_NAME,

.owner = THIS_MODULE,

},

};

static int __init zlg7290_init(void)

{

return i2c_add_driver(&zlg7290_driver);

}

static void __exit zlg7290_exit(void)

{

i2c_del_driver(&zlg7290_driver);

}

MODULE_AUTHOR("farsight");

MODULE_DESCRIPTION("zlg7290 driver");

MODULE_LICENSE("GPL");

module_init(zlg7290_init);

module_exit(zlg7290_exit);

 
 

上一篇:基于3.14内核usb摄像头驱动的移植

下一篇:putty 自动远程登录linux

热点文章推荐
华清学员就业榜单
高薪学员经验分享
热点新闻推荐
前台专线:010-82525158 企业培训洽谈专线:010-82525379 院校合作洽谈专线:010-82525379 Copyright © 2004-2022 北京华清远见科技集团有限公司 版权所有 ,京ICP备16055225号-5京公海网安备11010802025203号

回到顶部