added write functionality
This commit is contained in:
parent
ac91c5cb2b
commit
7fd5e0fffc
67
src/io.c
67
src/io.c
|
@ -5,6 +5,8 @@
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
#include "lcd.h"
|
#include "lcd.h"
|
||||||
|
|
||||||
|
static bool advance_ptr(const char* base, ssize_t size, char** ptr);
|
||||||
|
|
||||||
loff_t lcd_llseek(struct file* filp, loff_t where, int whence)
|
loff_t lcd_llseek(struct file* filp, loff_t where, int whence)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -17,7 +19,54 @@ ssize_t lcd_read(struct file* filp, char __user* buf, size_t count, loff_t* off)
|
||||||
|
|
||||||
ssize_t lcd_write(struct file* filp, const char __user* buf, size_t count, loff_t* off)
|
ssize_t lcd_write(struct file* filp, const char __user* buf, size_t count, loff_t* off)
|
||||||
{
|
{
|
||||||
return count;
|
struct lcd_dev* dev = (struct lcd_dev*)filp->private_data;
|
||||||
|
char* kern_buf = NULL;
|
||||||
|
char* cmd_start = NULL;
|
||||||
|
char* cmd_end = NULL;
|
||||||
|
ssize_t retval = 0;
|
||||||
|
|
||||||
|
if(down_interruptible(&dev->sem))
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
kern_buf = (char*)kmalloc(count, GFP_KERNEL);
|
||||||
|
if(kern_buf == NULL)
|
||||||
|
{
|
||||||
|
printk(KERN_ERR "%s: Failed to allocate buffer (%d bytes), aborting write.\n", THIS_MODULE->name, count);
|
||||||
|
retval = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(copy_from_user(kern_buf, buf, count))
|
||||||
|
{
|
||||||
|
printk(KERN_ERR "%s: Failed to copy data from user, aborting write.\n", THIS_MODULE->name);
|
||||||
|
retval = -EFAULT;
|
||||||
|
kfree(kern_buf);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_start = kern_buf;
|
||||||
|
cmd_end = kern_buf;
|
||||||
|
|
||||||
|
while(advance_ptr(kern_buf, count, &cmd_end))
|
||||||
|
{
|
||||||
|
*cmd_end = '\0';
|
||||||
|
|
||||||
|
if(strcmp(cmd_start, "0") == 0)
|
||||||
|
gpio_set_value(dev->gpio, 0);
|
||||||
|
else if(strcmp(cmd_start, "1") == 0)
|
||||||
|
gpio_set_value(dev->gpio, 1);
|
||||||
|
else
|
||||||
|
printk(KERN_WARNING "%s: Unrecognized command \"%s\"\n", THIS_MODULE->name, cmd_start);
|
||||||
|
|
||||||
|
cmd_start = cmd_end + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = count;
|
||||||
|
kfree(kern_buf);
|
||||||
|
|
||||||
|
out:
|
||||||
|
up(&dev->sem);
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
long lcd_ioctl(struct file* filp, unsigned int cmd, unsigned long arg)
|
long lcd_ioctl(struct file* filp, unsigned int cmd, unsigned long arg)
|
||||||
|
@ -31,9 +80,7 @@ int lcd_open(struct inode* inode, struct file* filp)
|
||||||
dev = container_of(inode->i_cdev, struct lcd_dev, dev);
|
dev = container_of(inode->i_cdev, struct lcd_dev, dev);
|
||||||
filp->private_data = (void*)dev;
|
filp->private_data = (void*)dev;
|
||||||
|
|
||||||
gpio_set_value(dev->gpio, 1);
|
printk(KERN_DEBUG "%s: Opened device\n", THIS_MODULE->name);
|
||||||
|
|
||||||
printk(KERN_INFO "%s: Opened device\n", THIS_MODULE->name);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,9 +88,17 @@ int lcd_release(struct inode* inode, struct file* filp)
|
||||||
{
|
{
|
||||||
struct lcd_dev* dev;
|
struct lcd_dev* dev;
|
||||||
dev = (struct lcd_dev*)filp->private_data;
|
dev = (struct lcd_dev*)filp->private_data;
|
||||||
gpio_set_value(dev->gpio, 0);
|
|
||||||
printk(KERN_INFO "%s: Released device\n", THIS_MODULE->name);
|
printk(KERN_DEBUG "%s: Released device\n", THIS_MODULE->name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool advance_ptr(const char* base, ssize_t size, char** ptr)
|
||||||
|
{
|
||||||
|
while(*ptr - base < size && **ptr != '\n')
|
||||||
|
(*ptr)++;
|
||||||
|
|
||||||
|
return *ptr - base < size;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -10,9 +10,11 @@ MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
int lcd_major = LCD_MAJOR;
|
int lcd_major = LCD_MAJOR;
|
||||||
int lcd_minor = LCD_MINOR;
|
int lcd_minor = LCD_MINOR;
|
||||||
|
int lcd_gpio = LCD_GPIO;
|
||||||
|
|
||||||
module_param(lcd_major, int, S_IRUGO);
|
module_param(lcd_major, int, S_IRUGO);
|
||||||
module_param(lcd_minor, int, S_IRUGO);
|
module_param(lcd_minor, int, S_IRUGO);
|
||||||
|
module_param(lcd_gpio, int, S_IRUGO);
|
||||||
|
|
||||||
static struct lcd_dev lcddev = { 0 };
|
static struct lcd_dev lcddev = { 0 };
|
||||||
static int __init lcd_init_cdev(void);
|
static int __init lcd_init_cdev(void);
|
||||||
|
@ -60,6 +62,8 @@ static int __init lcd_init_module(void)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sema_init(&lcddev.sem, 1);
|
||||||
|
|
||||||
result = lcd_init_cdev();
|
result = lcd_init_cdev();
|
||||||
if(result < 0)
|
if(result < 0)
|
||||||
return result;
|
return result;
|
||||||
|
@ -113,5 +117,5 @@ static int __init lcd_init_gpio(void)
|
||||||
|
|
||||||
static void __exit lcd_exit_gpio(void)
|
static void __exit lcd_exit_gpio(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
|
@ -7,13 +7,13 @@
|
||||||
#define LCD_MAJOR 0
|
#define LCD_MAJOR 0
|
||||||
#define LCD_MINOR 0
|
#define LCD_MINOR 0
|
||||||
|
|
||||||
extern int lcd_major;
|
#define LCD_GPIO 18
|
||||||
extern int lcd_minor;
|
|
||||||
|
|
||||||
struct lcd_dev
|
struct lcd_dev
|
||||||
{
|
{
|
||||||
dev_t devno;
|
dev_t devno;
|
||||||
struct cdev dev;
|
struct cdev dev;
|
||||||
|
struct semaphore sem;
|
||||||
int gpio;
|
int gpio;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue