I am trying to make a Linux Kernel driver in the Raspberry pi 3 that turns on a led when a button in a joystick es pressed(Sets GPIO as an Output and then sets it on) and also reads the status of that GPIO port.
My driver for turning on the leds is:
#include<linux/init.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/cdev.h>
#include<linux/slab.h>
#include<asm/uaccess.h>
#include<asm/io.h>
#define ioaddress_SIE_BASE 0x3F200000
#define ioaddress_SIZE 0x38
#define address_LED_on 0x1C
#define address_LED_off 0x28
#define address_LED_estado 0x34
MODULE_LICENSE("Dual BSD/GPL");
static char *nombre="4led";
static unsigned int PrimerMenor=0;
static unsigned int cuenta=1;
static dev_t led_dev_numero;
char *buffer;
int on_off=0;
int leido=0;
static void __iomem *ioaddress_SIE;
struct led_dev *led_dev_puntero;
struct led_dev {
struct cdev led_cdev;
};
int led_open (struct inode *puntero_inode, struct file *puntero_file)
{
struct led_dev *led_dev_puntero;
printk (KERN_INFO "led_SIE: se ha abierto el dispositivo \n" );
led_dev_puntero=container_of(puntero_inode->i_cdev, struct led_dev, led_cdev);
puntero_file->private_data=led_dev_puntero;
return 0;
}
int led_release (struct inode *puntero_inode , struct file *puntero_file)
{
printk (KERN_INFO "led_SIE: se ha liberado el dispositivo \n" );
return 0;
}
static ssize_t led_read (struct file *puntero_file , char *buffer_user, size_t tamano, loff_t *puntero_offset)
{
unsigned int estado;
unsigned long prueba;
printk (KERN_INFO "led_SIE: leyendo el dispositivo \n" );
iowrite32(0x00000000, ioaddress_SIE);
estado=ioread32(ioaddress_SIE + address_LED_estado);
printk("led_SIE: GPIOs 9 to 0 --> 0x%X \n", estado);
*buffer=(char ) (estado >> leido );
prueba=copy_to_user(buffer_user, buffer, 1);
printk("led_SIE: GPIOs 9 to 0 --> 0x%X \n", *buffer);
if(leido>23){
leido=0;}
else
leido=leido+8;
return 1;
}
static ssize_t led_write (struct file *puntero_file , const char *buffer_user, size_t tamano, loff_t *puntero_offset)
{
unsigned long prueba;
/*printk(KERN_INFO "led_SIE: escribiendo en el dispositivo \n");
if(buffer_user[0]!='1'){
if(buffer_user[0]!='0'){
printk(KERN_INFO "led_SIE: Ha ingresado una orden incorrecta! \n");
printk(KERN_INFO "led_SIE: Las ordenes son: 1 para encender, 0 para apagar \n");
return tamano;
}
}*/
prueba=copy_from_user(buffer, buffer_user, tamano);
printk(KERN_INFO "led_SIE: SE escribió %c en el dispositivo \n", buffer);
/*ibuffer_user=(int)buffer_user;*/
/*printk(ibuffer_user);
int ibuffer = (int) buffer;*/
/*if(buffer_user=='1'){
printk(KERN_INFO "Lee maldita sea \n");
}*/
switch(buffer[0]){
case '1':
if(on_off==1){
printk(KERN_INFO "led_SIE: El led ya se encuentra encendido \n");
return tamano;
}
on_off=1;
iowrite32(0x00009240, ioaddress_SIE);
iowrite32(0x00000004, ioaddress_SIE + address_LED_on);
iowrite32(0x00000038, ioaddress_SIE + address_LED_off);
break;
case '2':
if(on_off==2){
printk(KERN_INFO "led_SIE: El led ya se encuentra encendido \n");
return tamano;
}
on_off=2;
iowrite32(0x00009240, ioaddress_SIE);
iowrite32(0x00000008, ioaddress_SIE + address_LED_on);
iowrite32(0x00000034, ioaddress_SIE + address_LED_off);
break;
case '3':
if(on_off==3){
printk(KERN_INFO "led_SIE: El led ya se encuentra encendido \n");
return tamano;
}
on_off=3;
iowrite32(0x00009240, ioaddress_SIE);
iowrite32(0x00000010, ioaddress_SIE + address_LED_on);
iowrite32(0x0000002C, ioaddress_SIE + address_LED_off);
break;
case '4':
if(on_off==4){
printk(KERN_INFO "led_SIE: El led ya se encuentra encendido \n");
return tamano;
}
on_off=4;
iowrite32(0x00009240, ioaddress_SIE);
iowrite32(0x00000020, ioaddress_SIE + address_LED_on);
iowrite32(0x0000001C, ioaddress_SIE + address_LED_off);
break;
case '0':
if(on_off==0){
printk(KERN_INFO "led_SIE: El led ya se encuentra apagado \n");
return tamano;
}
on_off=0;
iowrite32(0x00009240, ioaddress_SIE);
iowrite32(0x0000003C, ioaddress_SIE + address_LED_off);
break;
default:
return tamano;
}
return tamano;
}
struct file_operations led_fops = {
.owner = THIS_MODULE,
.read = led_read,
.write = led_write,
.open = led_open,
.release = led_release
};
static int hello_init(void)
{
int resultado, error;
printk(KERN_ALERT "Hola, mundo\n");
resultado=alloc_chrdev_region(&led_dev_numero, PrimerMenor, cuenta, nombre);
if (resultado ==0)
printk(KERN_INFO "Se reservaron los siguientes numeros \n Mayor: %d\n Menor: %d\n", MAJOR(led_dev_numero), MINOR(led_dev_numero));
else
printk(KERN_INFO "Hubo un error y los numeros no se reservaron. Error: %d\n", resultado);
led_dev_puntero = kmalloc (sizeof(struct led_dev), GFP_ATOMIC);
buffer=kmalloc(8,GFP_ATOMIC);//GFP_KERNEL---Difícil
cdev_init(&led_dev_puntero->led_cdev, &led_fops);
led_dev_puntero->led_cdev.owner=THIS_MODULE;
led_dev_puntero->led_cdev.ops=&led_fops;
error=cdev_add(&led_dev_puntero->led_cdev, led_dev_numero, cuenta);
if(error)
printk (KERN_INFO "error $d al anadir led_dev");
ioaddress_SIE=ioremap(ioaddress_SIE_BASE, ioaddress_SIZE);
printk(KERN_ALERT "ioadress_SIE_BASE fue mapeado a: %p \n", ioaddress_SIE);
return 0;
}
module_init(hello_init);
static void hello_exit(void)
{
printk(KERN_ALERT "Adios, mundo cruel\n");
unregister_chrdev_region(led_dev_numero,cuenta);
cdev_del(&led_dev_puntero->led_cdev);
kfree(led_dev_puntero);
kfree(buffer);
if(on_off==1){
iowrite32(0xFFFFFFFF, ioaddress_SIE + address_LED_off);
}
iounmap(ioaddress_SIE);
}
module_exit(hello_exit);
And the application that interacts with the driver and the joystick is:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
struct js_event {
unsigned int time; /* event timestamp in milliseconds */
short value; /* value */
unsigned char type; /* event type */
unsigned char number; /* axis/button number */
};
#define JS_EVENT_BUTTON 0x01 /* button pressed/released */
#define JS_EVENT_AXIS 0x02 /* joystick moved */
#define JS_EVENT_INIT 0x80 /* initial state of device */
int main(int argc, char **argv)
{ //Acceso al driver Xdriv
int fd = open ("/dev/input/js0", O_RDONLY);
FILE *archivo;
int tamano;
int a;int b;
/*Acceso al driver 4_leds
system("sudo chmod 777 /dev/4leds");
archivo=fopen("/dev/4leds" ,"w");
if (archivo==NULL){fputs("No existe el archivo" ,stderr); exit(1);}
*/
if( fd < 0 )
printf( "cannot open dev\n" );
else
printf( "opened success...:)\n" );
struct js_event e;
while( 1 ) //event loop
{
read( fd, &e, sizeof(e) );
//printf( "%d %d %d %d\n", e.time, e.value, e.type, e.number );
if( e.type == JS_EVENT_BUTTON || e.type == JS_EVENT_AXIS )
{
if( e.type == JS_EVENT_BUTTON ){
printf( "button#%d value:%d\n", (int) e.number, e.value );
switch((int) e.number) {
case 0 ://Btn A, Motor 1---Atrás
if ((int) e.value == 1){
printf("Hola esto es 0\n Btn A, Motor 1---Atrás");
char escribe[1] = "1";
//Acceso al driver 4_leds
system("sudo chmod 777 /dev/4leds");
archivo=fopen("/dev/4leds" ,"w");
if (archivo==NULL){fputs("No existe el archivo" ,stderr); exit(1);}
//
fwrite(escribe ,sizeof(char) ,tamano , archivo);//Escribe 1 en driver
fclose(archivo);
sleep(3);
printf("Este es escribe :%c ",*escribe);}
else{
printf("Hola esto es 0 pero no presionado\n");
}
break;
case 1 ://Btn B, Motor 1---Adelante
if ((int) e.value == 1){
printf("Hola esto es 1\n Btn B, Motor 1---Adelante");
char escribe[1] = "2";
//Acceso al driver 4_leds
system("sudo chmod 777 /dev/4leds");
archivo=fopen("/dev/4leds" ,"w");
if (archivo==NULL){fputs("No existe el archivo" ,stderr); exit(1);}
//
fwrite(escribe ,sizeof(char) ,tamano , archivo);//Escribe 2 en driver
fclose(archivo);
sleep(3);
printf("Este es escribe :%c \n",*escribe);}
else{
printf("Hola esto es 1 pero no presionado\n");
}
break;
case 2 ://Btn X, Motor 2---Abajo
if ((int) e.value == 1){
printf("Hola esto es 2 \n Btn X, Motor 2---Abajo");
char escribe[1] = "3";
//Acceso al driver 4_leds
system("sudo chmod 777 /dev/4leds");
archivo=fopen("/dev/4leds" ,"w");
if (archivo==NULL){fputs("No existe el archivo" ,stderr); exit(1);}
//
fwrite(escribe ,sizeof(char) ,tamano , archivo);//Escribe 3 en driver
fclose(archivo);
sleep(3);
printf("Este es escribe :%c \n",*escribe);}
else{
printf("Hola esto es 2 pero no presionado\n");
}
break;
case 3 ://Btn Y, Motor 2---Arriba
if ((int) e.value == 1){
printf("Hola esto es 3 \n Btn Y, Motor 2---Arriba");
char escribe[1] = "4";
//Acceso al driver 4_leds
system("sudo chmod 777 /dev/4leds");
archivo=fopen("/dev/4leds" ,"w");
if (archivo==NULL){fputs("No existe el archivo" ,stderr); exit(1);}
//
fwrite(escribe ,sizeof(char) ,tamano , archivo);//Escribe 4 en driver
fclose(archivo);
sleep(3);
printf("Este es escribe :%c \n",*escribe);}
else{
printf("Hola esto es 3 pero no presionado\n");
}
break;
case 7 ://Detener
if ((int) e.value == 1){
printf("Hola esto es Start/Stop \n");
char escribe[1] = "0";
//Acceso al driver 4_leds
system("sudo chmod 777 /dev/4leds");
archivo=fopen("/dev/4leds" ,"w");
if (archivo==NULL){fputs("No existe el archivo" ,stderr); exit(1);}
//
fwrite(escribe ,sizeof(char) ,tamano , archivo);//Escribe 0 en driver
fclose(archivo);
sleep(3);
printf("Este es escribe :%c \n",*escribe);}
else{
printf("Hola esto es 7 pero no presionado\n");
}
break;
default : /* Optional */
printf("Hola esto es default también sirve como stop\n");
char escribe[1] = "0";
//Acceso al driver 4_leds
system("sudo chmod 777 /dev/4leds");
archivo=fopen("/dev/4leds" ,"w");
if (archivo==NULL){fputs("No existe el archivo" ,stderr); exit(1);}
//
fwrite(escribe ,sizeof(char) ,tamano , archivo);//Escribe 0 en driver
fclose(archivo);
sleep(3);
printf("Este es escribe :%c \n",*escribe);
}
printf("El último presionado fue: %X \n",(char) e.number);}
else{
printf( "axis#%d value:%d \n", (int) e.number, e.value );}
}
else
{
printf( "Init Events\n" );
}
}
return 0;
}
I am getting segmentation fault so I think it may be a problem with the memory allocation in the buffer of the copy_from_user...but I don't now how to solve it.
I've tried opening the file before the while and then writing on it in every switch case, also opening the file and writing on it in the switch case...and so on.
The driver works fine with another application that is not event.
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int main(int argc, char **argv){
FILE *archivo;
char escribe[1];
char lee[1];
int tamano, i;
int registro=0;
int registro2=0;
tamano=1;
printf("introduzca el numero que quiere escribir: ");
scanf("%c" ,escribe);
printf("%c ",*escribe);
system("sudo chmod 777 /dev/4leds");
archivo=fopen("/dev/4leds" ,"w");
if (archivo==NULL){fputs("No existe el archivo" ,stderr); exit(1);}
fwrite(escribe ,sizeof(char) ,tamano , archivo);
printf("El valor escrito fue: %c \n" , *escribe);
fclose(archivo);
sleep(3);
/*archivo=fopen("/dev/4leds", "r");
if (archivo==NULL){fputs("No existe el archivo" ,stderr); exit(1);}
for (i=0;i<4;i++)
{
registro=registro << 8;
fread(lee ,tamano*sizeof(char),1,archivo);
registro=registro | *lee;
}
registro2=registro2 | (registro << 24 & 0xFF000000);
registro2=registro2 | (registro << 8 & 0x00FF0000);
registro2=registro2 | (registro >> 8 & 0x0000FF00);
registro2=registro2 | (registro >> 24 & 0x000000FF);
printf("El valor leido es: 0x%X \n" , registro2);
fclose(archivo);*/
return 0;
}
Thanks for your help and advices. Sorry for the commented code but I am testing all parts of the driver.
tamano
or number of elements is declared but never defined in main()
.
fwrite(escribe ,sizeof(char) ,tamano , archivo);
User contributions licensed under CC BY-SA 3.0