[Armadeus-commitlog] SF.net SVN: armadeus: [767] trunk/target/linux/modules/led
Brought to you by:
sszy
|
From: <Fa...@us...> - 2008-03-07 18:07:14
|
Revision: 767
http://armadeus.svn.sourceforge.net/armadeus/?rev=767&view=rev
Author: FabM
Date: 2008-03-07 10:07:11 -0800 (Fri, 07 Mar 2008)
Log Message:
-----------
[target]Driver led upgraded with sysfs at /sys/fpgaled/
Modified Paths:
--------------
trunk/target/linux/modules/led/Makefile
trunk/target/linux/modules/led/README
trunk/target/linux/modules/led/led.c
trunk/target/linux/modules/led/led.h
Added Paths:
-----------
trunk/target/linux/modules/led/testled.c
Modified: trunk/target/linux/modules/led/Makefile
===================================================================
--- trunk/target/linux/modules/led/Makefile 2008-03-04 09:11:14 UTC (rev 766)
+++ trunk/target/linux/modules/led/Makefile 2008-03-07 18:07:11 UTC (rev 767)
@@ -24,6 +24,11 @@
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
cp led.ko /tftpboot/
+test:
+ ~/armadeus/buildroot/build_arm/staging_dir/bin/arm-linux-gcc testled.c -o testled
+ chmod 755 testled
+ cp testled /tftpboot/
+
clean:
rm -f *.*o \
rm -f Module.symvers
Modified: trunk/target/linux/modules/led/README
===================================================================
--- trunk/target/linux/modules/led/README 2008-03-04 09:11:14 UTC (rev 766)
+++ trunk/target/linux/modules/led/README 2008-03-07 18:07:11 UTC (rev 767)
@@ -4,13 +4,23 @@
To use it configure fpga with bus_led then insert led.ko with insmod :
>insmod led.ko
-watch dmesg :
+Watch dmesg :
LED: MAJOR: 253 MINOR: 0
-Led module insered
+Led module inserted
-then make a character file with wright major and minor number :
+Then make a character file with wright major and minor number :
>mknod led c 253 0
-Then led can be switched on/off writing a character in nod file,
+Then led can be switched on/off writing a character in node file,
only LSB will switch led, 1 will switch off led and 0 will
witch on. To read value, just read the file.
+
+To test read/write testled.c can be used, to compile :
+make test
+then launch the binary :
+>./testled led
+
+Sysfs is created at /sys/fpgaled/status, to print the led status:
+>cat /sys/fpgaled/status
+To switch the status :
+>echo 1 > /sys/fpgaled/status
Modified: trunk/target/linux/modules/led/led.c
===================================================================
--- trunk/target/linux/modules/led/led.c 2008-03-04 09:11:14 UTC (rev 766)
+++ trunk/target/linux/modules/led/led.c 2008-03-07 18:07:11 UTC (rev 767)
@@ -1,17 +1,109 @@
-/* Driver for bus_led IP
+/* Driver for bus_led fpga IP
* Fabien Marteau <fab...@ar...>
* 4 march 2008
*/
#include "led.h"
+/* *********************************
+ * Sysfs operations
+ * *********************************/
+
+static void kobj_release(struct kobject *kobj){
+ PDEBUG("led kobject released\n");
+}
+
+static int init_sysinterface(struct led_dev *ldev){
+ int ret = 0;
+
+ /* initializing kobject to 0 */
+ memset(&ldev->kobj,0,sizeof(struct kobject));
+ /* set kobject name */
+ if(unlikely(ret = kobject_set_name(&ldev->kobj,"fpgaled")))
+ goto out;
+ /* register */
+ if(unlikely(ret=kobject_register(&ldev->kobj)))
+ goto out;
+ /* register the kobj_type */
+ ldev->kobj.ktype = &kobjtype;
+ /* add status attribute */
+ if(unlikely(ret=sysfs_create_file(&ldev->kobj,&led_status_attr)));
+
+out:
+ return ret;
+}
+
+static ssize_t led_show_status(struct kobject *kobj,struct attribute *attr,char *buf){
+ ssize_t ret_size = 0;
+ struct led_dev *dev;
+ void * virt_addr;
+ u16 data;
+
+ dev = container_of(kobj,struct led_dev,kobj);
+
+ if(down_interruptible(&dev->sem)) /* take mutex */
+ return -ERESTARTSYS;
+
+ virt_addr = ioremap(IMX_CS1_PHYS,1);/* translate hardware address to virtual */
+ if(virt_addr==NULL){
+ printk(KERN_WARNING "ioremap error\n");
+ return -EFAULT;
+ }
+ data = ioread16(virt_addr);/* read the led value */
+ PDEBUG( "show : value read : %x\n",data);
+
+ iounmap(virt_addr);
+
+ if(data&0x0001)ret_size = (ssize_t)sprintf(buf,"1\n");
+ else ret_size = (ssize_t)sprintf(buf,"0\n");
+
+ up(&dev->sem);
+ return ret_size;
+}
+
+static ssize_t led_store_status(struct kobject *kobj,struct attribute *attr,
+ const char *buff, size_t size){
+ struct led_dev *ldev = container_of(kobj,struct led_dev,kobj);
+ void * virt_addr;
+ ssize_t retval=0;
+ u16 data;
+
+ if(buff[0]=='1')
+ data=0x0001;
+ else if(buff[0]=='0')
+ data=0x0000;
+ else
+ return size;
+
+ if(down_interruptible(&ldev->sem))
+ return -ERESTARTSYS;
+
+ virt_addr = ioremap(IMX_CS1_PHYS,1);/* translate hardware address to virtual */
+ if(virt_addr==NULL){
+ printk(KERN_WARNING "write : ioremap error\n");
+ retval = -EFAULT;
+ goto out;
+ }
+ iowrite16(data,virt_addr);/* write the led value */
+ iounmap(virt_addr);
+ PDEBUG( "write : Value wrote : %x\n",data);
+
+ up(&ldev->sem);
+ return size ;
+out:
+ return retval;
+}
+
+/***********************************
+ * characters file /dev operations
+ * *********************************/
ssize_t led_read(struct file *fildes, char __user *buff, size_t count, loff_t *offp){
struct led_dev *ldev = fildes->private_data;
void * virt_addr;
u16 data=0;
ssize_t retval = 0;
- PDEBUG( "offset %d, count %d\n",(int)*offp,(int)count);
+ PDEBUG( "read : offset %d, count %d\n",(int)*offp,(int)count);
if(down_interruptible(&ldev->sem)) /* take mutex */
return -ERESTARTSYS;
if(*offp >= 1){ /* offset must be 0 or 1 */
@@ -25,16 +117,17 @@
printk(KERN_WARNING "ioremap error\n");
return -EFAULT;
}
- PDEBUG("Virtual fpga adress : %lx\n",(long int)virt_addr);
- PDEBUG("Real fpga adress : %lx\n",(long int)IMX_CS1_PHYS);
+ PDEBUG("read : Virtual fpga adress : %lx\n",(long int)virt_addr);
+ PDEBUG("read : Real fpga adress : %lx\n",(long int)IMX_CS1_PHYS);
// rmb();
data = ioread16(virt_addr);/* read the led value */
- PDEBUG( "Value read : %x\n",data);
+ PDEBUG( "read : value read : %x\n",data);
iounmap(virt_addr);
/* return data for user */
if(copy_to_user(buff,&data,2)){
+ printk(KERN_WARNING "read : copy to user data error\n");
retval = -EFAULT;
goto out;
}
@@ -44,18 +137,18 @@
out:
up(&ldev->sem); /* free mutex */
- PDEBUG("Return value %d\n",(int)retval);
+ PDEBUG("read : Return value %d\n",(int)retval);
return retval;
}
ssize_t led_write(struct file *fildes, const char __user *buff,size_t count, loff_t *offp){
struct led_dev *ldev = fildes->private_data;
void * virt_addr;
- u16 data;
- ssize_t retval = -ENOMEM;
+ u16 data=0;
+ ssize_t retval = 0;
- PDEBUG("offset %d, count %d\n",(int)*offp,(int)count);
+ PDEBUG("write : offset %d, count %d\n",(int)*offp,(int)count);
if(down_interruptible(&ldev->sem))
return -ERESTARTSYS;
if(*offp != 0){ /* offset must be 0 */
@@ -66,41 +159,46 @@
virt_addr = ioremap(IMX_CS1_PHYS,1);/* translate hardware address to virtual */
if(virt_addr==NULL){
- printk(KERN_WARNING "ioremap error\n");
- return -EFAULT;
+ printk(KERN_WARNING "write : ioremap error\n");
+ retval = -EFAULT;
+ goto out;
}
- PDEBUG("Virtual fpga adress : %lx\n",(long int)virt_addr);
- PDEBUG( "Real fpga adress : %lx\n",(long int)IMX_CS1_PHYS);
+ PDEBUG("write : Virtual fpga adress : %lx\n",(long int)virt_addr);
+ PDEBUG("write : Real fpga adress : %lx\n",(long int)IMX_CS1_PHYS);
// rmb();
- if(copy_from_user(&data,buff,2)){
+ if(copy_from_user(&data,buff,1)){
+ printk(KERN_WARNING "write : copy from user error\n");
retval = -EFAULT;
goto out;
}
- PDEBUG( "user buff value %d\n",(int)data);
- data = data;
- iowrite16(data,virt_addr);/* read the led value */
+ PDEBUG( "write : user buff value %d\n",(int)data);
+ iowrite16(data,virt_addr);/* write the led value */
iounmap(virt_addr);
- PDEBUG( "Value wrote : %x\n",data);
-
-
+ PDEBUG( "write : Value wrote : %x\n",data);
+ retval = 1;
out:
up(&ldev->sem);
return retval;
}
int led_open(struct inode *inode, struct file *filp){
-
/* Allocate and fill any data structure to be put in filp->private_data */
filp->private_data = container_of(inode->i_cdev,struct led_dev, cdev);
PDEBUG( "Led opened\n");
return 0;
}
+/* ******************************
+ * Init and release functions
+ * ******************************/
int led_release(struct inode *inode, struct file *filp){
PDEBUG( "Led released\n");
return 0;
}
+/**********************************
+ * Module management
+ **********************************/
static int __init led_init(void){
int result; /* error return */
@@ -111,6 +209,7 @@
mem = NULL;
/* Allocate a private structure and reference it as driver's data */
+ PDEBUG("Allocate a private structure and reference it as driver s data\n");
sdev = (struct led_dev *)kmalloc(sizeof(struct led_dev),GFP_KERNEL);
if(sdev == NULL){
printk(KERN_WARNING "LED: unable to allocate private structure\n");
@@ -118,9 +217,11 @@
}
/* initiate mutex for accessing led */
+ PDEBUG("initiate mutex for accessing led\n");
init_MUTEX(&sdev->sem);
/* Get the major and minor device numbers */
+ PDEBUG("Get the major and minor device numbers");
if(led_major){
devno = MKDEV(led_major,led_minor);
result = register_chrdev_region(devno, N_DEV,"led");
@@ -134,27 +235,43 @@
}
/* Init the cdev structure */
+ PDEBUG("Init the cdev structure\n");
cdev_init(&sdev->cdev,&led_fops);
sdev->cdev.owner = THIS_MODULE;
/* Add the device to the kernel, connecting cdev to major/minor number */
+ PDEBUG(" Add the device to the kernel, connecting cdev to major/minor number \n");
result = cdev_add(&sdev->cdev,devno,1);
if(result < 0)printk(KERN_WARNING "LED: can't add cdev\n");
-
/* Requested I/O memory */
+ PDEBUG(" Requested I/O memory \n");
mem = request_mem_region(LED_BASE_ADDR,LED_LENGTH,"led");
if(mem == NULL)
printk(KERN_ERR "LED: Error memory allocation\n");
+ /* initialyzing sysfs */
+ PDEBUG(" initialyzing sysfs");
+ if(unlikely(result = init_sysinterface(sdev)))
+ goto error;
-
printk(KERN_INFO "Led module insered\n");
return 0;
+
+error:
+ printk(KERN_ERR "%s: not inserted\n",DRIVER_NAME);
+ free_all();
+ return result;
}
static void __exit led_exit(void){
+ free_all();
+}
+static void free_all(void){
+ /* unregister kobj */
+ kobject_unregister(&sdev->kobj);
+
/* delete the cdev structure */
cdev_del(&sdev->cdev);
Modified: trunk/target/linux/modules/led/led.h
===================================================================
--- trunk/target/linux/modules/led/led.h 2008-03-04 09:11:14 UTC (rev 766)
+++ trunk/target/linux/modules/led/led.h 2008-03-07 18:07:11 UTC (rev 767)
@@ -19,6 +19,8 @@
/* linux device model */
#include <linux/kobject.h>
#include <linux/sysfs.h>
+#include <linux/sysdev.h>
+#include <linux/device.h>
/* for file operations */
#include <linux/fs.h>
@@ -55,15 +57,20 @@
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Fabien Marteau - ARMadeus Systems");
+MODULE_AUTHOR("Fabien Marteau <fab...@ar...> - ARMadeus Systems");
MODULE_DESCRIPTION("Led device driver");
/* cdev struct */
struct led_dev{
struct cdev cdev; /* Char device structure */
struct semaphore sem; /* Mutex */
+ struct kobject kobj;
};
+static void kobj_release(struct kobject *);
+
+#define DRIVER_NAME "led"
+
/* major and minor number */
#define N_DEV 1
static dev_t devno; /* to store Major and minor numbers */
@@ -74,12 +81,13 @@
#define LED_LENGTH 1
struct resource *mem; /* pointer to fpga led */
+
+/* to read write led register */
ssize_t led_read(struct file *fildes, char __user *buff,
size_t count, loff_t *offp);
ssize_t led_write(struct file *fildes, const char __user *
buff,size_t count, loff_t *offp);
-
int led_open(struct inode *inode, struct file *filp);
int led_release(struct inode *, struct file *filp);
@@ -93,3 +101,25 @@
};
+/* Sysfs operation */
+static struct attribute led_status_attr = {
+ .name = "status",
+ .owner = THIS_MODULE,
+ .mode = 0666,
+};
+static int init_sysinterface(struct led_dev *pdev);
+static ssize_t led_show_status(struct kobject *kobj,struct attribute *attr,char *buf);
+static ssize_t led_store_status(struct kobject *kobj,struct attribute *attr, const char *buff, size_t size);
+
+static struct sysfs_ops led_status_fs_ops = {
+ .show = led_show_status,
+ .store = led_store_status,
+};
+
+struct kobj_type kobjtype = {
+ .release = kobj_release,
+ .sysfs_ops = &led_status_fs_ops,
+};
+
+
+static void free_all(void);
Added: trunk/target/linux/modules/led/testled.c
===================================================================
--- trunk/target/linux/modules/led/testled.c (rev 0)
+++ trunk/target/linux/modules/led/testled.c 2008-03-07 18:07:11 UTC (rev 767)
@@ -0,0 +1,72 @@
+/* a little program to test led driver
+ * Fabien Marteau <fab...@ar...>
+ * 7 march 2008
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+/* file management */
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <signal.h>
+
+/* sleep */
+#include <unistd.h>
+
+int fled;
+
+void quit(int pouet){
+ close(fled);
+ exit(0);
+}
+
+int main(int argc, char *argv[])
+{
+ unsigned short i,j;
+
+ /* quit when Ctrl-C pressed */
+ signal(SIGINT, quit);
+
+ j=0;
+
+ printf( "Testing led driver\n" );
+
+ if(argc < 2){
+ perror("invalide arguments number\ntestled <led_filename>\n");
+ exit(EXIT_FAILURE);
+ }
+
+ fled=open(argv[1],O_RDWR);
+ if(fled<0){
+ perror("can't open file\n");
+ exit(EXIT_FAILURE);
+ }
+
+ while(1){
+ i = (i==0)?1:0;
+ printf("Write %d,",i);
+ fflush(stdout);
+ /* write i in led register */
+ if(write(fled, &i, 1)<0){
+ perror("write error\n");
+ exit(EXIT_FAILURE);
+ }
+ if(read(fled,&j,1)<0){
+ perror("read error\n");
+ exit(EXIT_FAILURE);
+ }
+ printf("Read %d\n",j);
+
+ if(lseek(fled,0,SEEK_SET)<0){
+ perror("lseek error\n");
+ exit(EXIT_FAILURE);
+ }
+
+ sleep(1);/* wait one second */
+ }
+
+ close(fled);
+ exit(0);
+}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|