Will use message queues for IPC between the kernel and user-space helper

master
Stefan Krulj 14 years ago
parent 4c5e1b78d2
commit ee18e4dfa5
  1. 4
      Makefile.helper
  2. 140
      ftdi_daemon.c
  3. 12
      ftdi_daemon.h
  4. 11
      usb_gpio.c
  5. 4
      usb_gpio.h

@ -1,8 +1,8 @@
OBJS = ftdi_daemon.o OBJS = ftdi_daemon.o
CC=gcc DEFINES := -DDEBUG
CFLAGS = CFLAGS = $(DEFINES)
LDFLAGS = -lftdi LDFLAGS = -lftdi
usbgpiod: $(OBJS) usbgpiod: $(OBJS)

@ -10,8 +10,6 @@ volatile uint8_t main_loop=1;
static int vendor=0x0403, device=0x6001; static int vendor=0x0403, device=0x6001;
static int is_output(unsigned offset){ static int is_output(unsigned offset){
return !!((USB_GPIO_DDR)&(1<<offset)); return !!((USB_GPIO_DDR)&(1<<offset));
} }
@ -20,88 +18,158 @@ static int is_high(unsigned offset){
return !!((USB_GPIO_PORT)&(1<<offset)); return !!((USB_GPIO_PORT)&(1<<offset));
} }
/*!
This will update the data direction according to the current
USB_GPIO_DDR value
*/
static int update_mode(void){ static int update_mode(void){
if( ftdi_set_bitmode(&ftdic, USB_GPIO_DDR, BITMODE_BITBANG)<0 ){ if( ftdi_set_bitmode(&ftdic, USB_GPIO_DDR, BITMODE_BITBANG)<0 ){
printf("%s: Can't enter FTDIs bitbang mode (%04x:%04x)!\n",MOD_NAME,vendor,device); printf("%s: Can't enter FTDIs bitbang mode (%04x:%04x)!\n",MOD_NAME,vendor,device);
printf("%s: %s\n",MOD_NAME,ftdi_get_error_string(&ftdic)); LOG("%s: %s\n",MOD_NAME,ftdi_get_error_string(&ftdic));
return -EIO; return -EIO;
} }
return 0; return 0;
} }
/*!
If in output this will allways return 0
in input it will return the logic level of the pin
*/
static int get_value(unsigned offset){ static int get_value(unsigned offset){
DEBUG_OUT("%s: GET_VALUE of pin%d ",MOD_NAME,offset); DEBUG_OUT("%s: GET_VALUE of pin%d\n",MOD_NAME,offset);
if( !is_output(offset) ){ if( !is_output(offset) ){
while( ftdic.readbuffer_remaining > 0 ){ if( ftdi_read_pins(&ftdic,&USB_GPIO_PIN) < 0){
if( ftdi_read_data(&ftdic,&USB_GPIO_PIN,1) < 0){ LOG("%s: Unable to read pin%d \n",MOD_NAME,offset);
printf("%s: Unable to read pin%d \n",MOD_NAME,offset);
}
} }
return !!((USB_GPIO_PIN) & (1<<offset)); return !!((USB_GPIO_PIN) & (1<<offset));
} }
return 0; return 0;
} }
/*!
If in input this will turn on/off the pullup
in output it will simply turn on/off the logic level of the pin
*/
static void set_value(unsigned offset, int value){ static void set_value(unsigned offset, int value){
DEBUG_OUT("%s: SET_VALUE of pin%d to %d",MOD_NAME,offset,value); DEBUG_OUT("%s: SET_VALUE of pin%d to %d\n",MOD_NAME,offset,value);
if( !is_output(offset) ){ if(value){
if(value && !is_high(offset)){ USB_GPIO_PORT |= (1<<offset);
if( ftdi_write_data(&ftdic,&USB_GPIO_PORT,1) < 0){ }else{
printf("%s: Unable to set pin%d to value %d\n",MOD_NAME,offset,value); USB_GPIO_PORT &= ~(1<<offset);
} }
}else if(!value && is_high(offset)){ if( ftdi_write_data(&ftdic,&USB_GPIO_PORT,1) < 0){
if( ftdi_write_data(&ftdic,&USB_GPIO_PORT,1) < 0){ LOG("%s: Unable to set pin%d to value %d\n",MOD_NAME,offset,value);
printf("%s: Unable to set pin%d to value %d\n",MOD_NAME,offset,value);
}
}
} }
} }
/*!
This will set the pin as input.
Warning: if the pin is HIGH at the moment you put the pin to input
the pull-up of that pin will be enabled
*/
static int set_in(unsigned offset){ static int set_in(unsigned offset){
DEBUG_OUT("%s: SET_INPUT of pin%d ",MOD_NAME,offset); DEBUG_OUT("%s: SET_INPUT of pin%d\n",MOD_NAME,offset);
USB_GPIO_DDR &= ~(1<<offset); USB_GPIO_DDR &= ~(1<<offset);
return update_mode(); return update_mode();
} }
/*
This will set the pin as output and drive its logic level according
to value.
*/
static int set_out(unsigned offset, int value){ static int set_out(unsigned offset, int value){
DEBUG_OUT("%s: SET_OUTPUT of pin%d to %d",MOD_NAME,offset,value); DEBUG_OUT("%s: SET_OUTPUT of pin%d to %d\n",MOD_NAME,offset,value);
USB_GPIO_DDR |= (1<<offset); USB_GPIO_DDR |= (1<<offset);
set_value(offset,value);
return update_mode(); return update_mode();
} }
static int ftdi_chip_init(){ static int ftdi_chip_init(){
// Init FTDI lib // Init FTDI lib
DEBUG_OUT("INIT libftdi\n");
if( ftdi_init(&ftdic)<0 ){ if( ftdi_init(&ftdic)<0 ){
printf("%s: Can't initialize FTDI-lib!\n",MOD_NAME); LOG("%s: Can't initialize FTDI-lib!\n",MOD_NAME);
return ENOMEM; return ENOMEM;
} }
// Open device // Open device
DEBUG_OUT("Opening device (%04x:%04x) \n",vendor,device);
if(ftdi_usb_open(&ftdic, vendor, device)<0) { if(ftdi_usb_open(&ftdic, vendor, device)<0) {
printf("%s: Can't open FTDI chip (%04x:%04x)!\n",MOD_NAME,vendor,device); printf("%s: Can't open FTDI chip (%04x:%04x)!\n",MOD_NAME,vendor,device);
printf("%s: %s\n",MOD_NAME,ftdi_get_error_string(&ftdic)); LOG("%s: %s\n",MOD_NAME,ftdi_get_error_string(&ftdic));
return ENXIO; return ENXIO;
} }
// Put device into bitbang modes
if( ftdi_set_bitmode(&ftdic, 0x00, BITMODE_BITBANG)<0 ){
printf("%s: Can't enter FTDIs bitbang mode (%04x:%04x)!\n",MOD_NAME,vendor,device);
printf("%s: %s\n",MOD_NAME,ftdi_get_error_string(&ftdic));
return EIO;
}
//All pins input //All pins input
USB_GPIO_DDR = 0x00; USB_GPIO_DDR = 0x00;
//No port set //No port set
USB_GPIO_PORT = 0x00; USB_GPIO_PORT = 0x00;
// Put device into bitbang mode
DEBUG_OUT("Putting device (%04x:%04x) into bitbang mode\n",vendor,device);
if( ftdi_set_bitmode(&ftdic, 0x00, BITMODE_BITBANG)<0 ){
printf("%s: Can't enter FTDIs bitbang mode (%04x:%04x)!\n",MOD_NAME,vendor,device);
LOG("%s: %s\n",MOD_NAME,ftdi_get_error_string(&ftdic));
return EIO;
}
// Set all pins low
if( ftdi_write_data(&ftdic,&USB_GPIO_PORT,1) < 0){
LOG("%s: Unable to set pins to low\n",MOD_NAME);
return EIO;
}
return 0; return 0;
} }
static void ftdi_chip_exit(){ static void ftdi_chip_exit(){
if( ftdi_disable_bitbang(&ftdic)<0 ){ if( ftdi_disable_bitbang(&ftdic)<0 ){
printf("%s: Can't reset FTDI (%04x:%04x)!\n",MOD_NAME,vendor,device); LOG("%s: Can't reset FTDI (%04x:%04x)!\n",MOD_NAME,vendor,device);
}
if( ftdi_usb_close(&ftdic) < 0){
LOG("%s: Unable to close FTDI-Device!\n",MOD_NAME);
LOG("%s: %s\n",MOD_NAME,ftdi_get_error_string(&ftdic));
} }
ftdi_deinit(&ftdic);
}
enum cmd_states {CMD_PORT_NUM, CMD_CMD};
static int cmd_fsm(char c){
static int state = CMD_PORT_NUM;
static char pin = 0;
int ret;
switch(state){
case CMD_PORT_NUM:
pin=c;
state=CMD_CMD;
break;
case CMD_CMD:
state = CMD_PORT_NUM;
// Pin commands
switch(c){
case CMD_IN:
return set_in((unsigned)pin);
case CMD_OUTH:
return set_out((unsigned)pin,1);
case CMD_OUTL:
return set_out((unsigned)pin,0);
case CMD_H:
set_value((unsigned)pin,1);
return 0;
case CMD_L:
set_value((unsigned)pin,0);
return 0;
case CMD_READ:
ret = get_value((unsigned)pin);
DEBUG_OUT("Value of %d is %d\n", pin,ret);
fputc((char)ret,stdout);
return 0;
}
}
return 0;
} }
int main(void){ int main(void){
@ -111,7 +179,13 @@ int main(void){
} }
for(;main_loop;){ for(;main_loop;){
//Sleep mostly //kernel will write commands to the stdin
ret = fgetc(stdin);
if( ret!=EOF ){
cmd_fsm(ret);
}else{
//main_loop=0;
}
} }
ftdi_chip_exit(); ftdi_chip_exit();

@ -1,19 +1,27 @@
#ifndef _FTDL_DAEMON_H #ifndef _FTDL_DAEMON_H
#define _FTDL_DAEMON_H #define _FTDL_DAEMON_H
#include <sys/msg.h>
#include <ftdi.h> #include <ftdi.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <errno.h> #include <errno.h>
#define MOD_NAME "usb_gpio" #include "common.h"
#ifdef DEBUG #ifdef DEBUG
#define DEBUG_OUT(FMT,...) printk(FMT, ## __VA_ARGS__) #define DEBUG_OUT(FMT,...) printf(FMT, ## __VA_ARGS__)
#else #else
#define DEBUG_OUT(FMT,...) {} #define DEBUG_OUT(FMT,...) {}
#endif #endif
#ifdef DEBUG
#define LOG(FMT,...) printf(FMT, ## __VA_ARGS__)
#else
#define DEBUG_OUT(FMT,...) {} //FIXME: add a log-file
#endif
#define PIN_TX 0 #define PIN_TX 0
#define PIX_RX 1 #define PIX_RX 1
#define PIN_RTS 2 #define PIN_RTS 2

@ -1,6 +1,7 @@
#include "usb_gpio.h" #include "usb_gpio.h"
static struct gpio_chip ft232_chip; static struct gpio_chip ft232_chip;
static struct subprocess_info *sub_info;
#include "gpio_callbacks.c" #include "gpio_callbacks.c"
@ -14,7 +15,7 @@ static void usb_gpio_exit(void) {
static int usb_gpio_init(void) { static int usb_gpio_init(void) {
int ret; int ret;
// Prepare user space handler call // Prepare user space handler call
char *argv[] = { "/usr/bin/logger", "help!", NULL }; char *argv[] = { "/usr/bin/usb_gpio_ftdi_helper", NULL };
static char *envp[] = { static char *envp[] = {
"HOME=/", "HOME=/",
"TERM=linux", "TERM=linux",
@ -45,7 +46,13 @@ static int usb_gpio_init(void) {
} }
//Call the user space handler //Call the user space handler
return call_usermodehelper( argv[0], argv, envp, UMH_WAIT_PROC ); sub_info = call_usermodehelper_setup( argv[0], argv, envp, GFP_ATOMIC );
if (sub_info == NULL){
return -ENOMEM;
}
// the helper will run in the background until the module decides to kill it
return call_usermodehelper_exec( sub_info, UMH_NO_WAIT );
} }
module_init(usb_gpio_init); module_init(usb_gpio_init);

@ -9,12 +9,12 @@
#include <linux/slab.h> /* kmalloc() */ #include <linux/slab.h> /* kmalloc() */
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/kmod.h> #include <linux/kmod.h>
#include <linux/msg.h>
#include "usb_gpio_util.h" #include "usb_gpio_util.h"
#include "common.h"
#define NUM_OF_GPIO 8 #define NUM_OF_GPIO 8
#define MOD_NAME "usb_gpio"
#ifndef CONFIG_GENERIC_GPIO #ifndef CONFIG_GENERIC_GPIO
#error This module needs generic gpio support (CONFIG_GENERIC_GPIO) #error This module needs generic gpio support (CONFIG_GENERIC_GPIO)

Loading…
Cancel
Save