📄 common.c
字号:
/* Soekris Netxxxx GPIO driver Common functions shared between the net4501 and net4801 driver (c) Copyright 2003-2004 Martin Hejl <martin@hejl.de> G&H Softwareentwicklung GmbH ********************************************************************** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ********************************************************************** * */#define GPIO_PROC_FILE 1#define LED_PROC_FILE 2#define SETTINGS_PROC_FILE 4#define TEMP_PROC_FILE 8#define VOLT_PROC_FILE 16#include "common.h"struct gpio_operations *driver_ops;static int gpio_major = GPIO_MAJOR;int __number_of_pins;static unsigned long init_map;struct semaphore gpio_sema;extern int net4501_init(struct gpio_operations **driver_ops);extern int net4801_init(struct gpio_operations **driver_ops);void __exit common_cleanup(void);int toString(unsigned long value, char* buffer, int number_of_bits) { static int i; /* convert it into a string */ for(i=number_of_bits;i>0;i--){ buffer[number_of_bits-i]=test_bit(i-1,&value)?'1':'0'; } buffer[number_of_bits] = '\n'; buffer[number_of_bits+1] = 0; return number_of_bits+1;}unsigned long fromString(char* buffer, int number_of_bits) { static int i; static unsigned long ret_val=0; ret_val = 0; /* Create WORD to write from the string */ for(i=0;i<number_of_bits;i++){ if (buffer[i] == 0) break; if (buffer[i] == '0' || buffer[i] == '1') { ret_val=ret_val<<1; } if (buffer[i] == '1') { ret_val |= 1; } } return(ret_val);}//------------------------------------------------static ssize_t net4xxx_gpio_write(struct file *file, const char *data, size_t count, loff_t *ppos){ unsigned m; size_t i; char port_status=0; ssize_t ret = 0; unsigned int value=0; unsigned int temp_value; m = MINOR(file->f_dentry->d_inode->i_rdev); if (ppos != &file->f_pos) return -ESPIPE; if (down_interruptible(&gpio_sema)) return -ERESTARTSYS; value = 0; for (i = 0; i < count; ++i) { port_status = 0; ret = __get_user(port_status, (char *)data); if (ret != 0) { //ret = -EFAULT; goto out; } switch(m) { case MINOR_BYTE: driver_ops->write8Bit(port_status); break; case MINOR_FULL: if ((i&1) == 0) { value = ((unsigned char)port_status); } else { temp_value = ((unsigned char)port_status); value |= ((temp_value<<8)&0xF00); driver_ops->write16Bit(value); } break; case MINOR_LED: driver_ops->writeErrorLed(port_status); break; default: ret=-EINVAL; goto out; } data++; *ppos = *ppos+1; } ret = count;out: up(&gpio_sema); return ret;}static ssize_t net4xxx_gpio_read(struct file *file, char *buf, size_t count, loff_t *ppos){ unsigned m = MINOR(file->f_dentry->d_inode->i_rdev); unsigned long value=0; size_t bytes_read=0; ssize_t ret = 0; char port_status; if (count == 0) return bytes_read; if (ppos != &file->f_pos) return -ESPIPE; if (down_interruptible(&gpio_sema)) return -ERESTARTSYS; switch(m) { case MINOR_BYTE: value = driver_ops->read8Bit(); port_status = (char)(value & 0xFF); if (copy_to_user(buf, &port_status, sizeof(char))) { ret = -EFAULT; goto out; } bytes_read++; buf++; *ppos = *ppos+1; ret = bytes_read; break; case MINOR_FULL: value = driver_ops->read16Bit(); port_status = (char)(value & 0xFF); if (copy_to_user(buf, &port_status, sizeof(char))) { ret = -EFAULT; goto out; } bytes_read++; buf++; *ppos = *ppos+1; if (count>1) { port_status = (char)((value>>8) & 0xF); if (copy_to_user(buf, &port_status, sizeof(char))) { ret = -EFAULT; goto out; } bytes_read++; buf++; *ppos = *ppos+1; } ret = bytes_read; break; case MINOR_LED: port_status = driver_ops->readErrorLed(); if (copy_to_user(buf, &port_status, sizeof(char))) { ret = -EFAULT; goto out; } bytes_read++; buf++; *ppos = *ppos+1; ret = bytes_read; break; default: ret = -EFAULT; goto out; }out: up(&gpio_sema); return ret;}static int net4xxx_gpio_open(struct inode *inode, struct file *file){ unsigned m = MINOR(inode->i_rdev); if (m!=MINOR_BYTE && m!=MINOR_FULL && m!=MINOR_LED ) return -EINVAL; return 0;}static int net4xxx_gpio_release(struct inode *inode, struct file *file){ return 0;}//------------------------------------------------// PROC filestatic int procfile_gpio_read( char *buffer, __attribute__ ((unused)) char **start, off_t offset, int buffer_length, int *eof, __attribute__ ((unused)) void *data){ int len; /* The number of bytes actually used */ unsigned int port_status=0; /* We give all of our information in one go, so if the * user asks us if we have more information the * answer should always be no. * * This is important because the standard read * function from the library would continue to issue * the read system call until the kernel replies * that it has no more information, or until its * buffer is filled. */ if (offset > 0 || buffer_length<__number_of_pins+2) { return 0; } len = buffer_length; if (len > __number_of_pins+1) { len = __number_of_pins+1; } if (down_interruptible(&gpio_sema)) return -ERESTARTSYS; /* Get the status of the gpio ports */ if (driver_ops->read16Bit == NULL) { port_status = driver_ops->read8Bit(); } else { port_status = driver_ops->read16Bit(); } len = toString(port_status,buffer,__number_of_pins); //*start = buffer; *eof = 1; /* Return the length */ up(&gpio_sema); return len;}static int procfile_gpio_write( __attribute__ ((unused)) struct file *file, const char *buf, unsigned long count, __attribute__ ((unused)) void *data){ int len; char new_gpio_state[MAX_NUMBER_OF_PINS+1]; unsigned int gpio_state; if (count==0) return 0; if(count > __number_of_pins) { len = __number_of_pins; } else { len = count; } if (down_interruptible(&gpio_sema)) return -ERESTARTSYS; if(copy_from_user(new_gpio_state, buf, len)) { up(&gpio_sema); return -EFAULT; } gpio_state = fromString(new_gpio_state,__number_of_pins); if (driver_ops->write16Bit==NULL) { driver_ops->write8Bit(gpio_state); } else { driver_ops->write16Bit(gpio_state); } up(&gpio_sema); return len;}static int procfile_settings_read( char *buffer, char **start, off_t offset, int buffer_length, int *eof, __attribute__ ((unused)) void *data){ int len; /* The number of bytes actually used */ unsigned int port_status=0; if (offset > 0 || buffer_length<__number_of_pins+2) return 0; if (down_interruptible(&gpio_sema)) return -ERESTARTSYS; if (driver_ops->set16BitDirection == NULL) { port_status = driver_ops->get8BitDirection(); } else { port_status = driver_ops->get16BitDirection(); } len = toString(port_status,buffer,__number_of_pins); // *start = buffer; *eof=1; up(&gpio_sema); return len;}static int procfile_settings_write( __attribute__ ((unused)) struct file *file, const char *buf, unsigned long count, __attribute__ ((unused)) void *data){ int len; int p1,p2; char ch; char new_gpio_state[MAX_NUMBER_OF_PINS+1]; unsigned int gpio_state; if (count==0) return 0; if (down_interruptible(&gpio_sema)) return -ERESTARTSYS; if(count > __number_of_pins) { len = __number_of_pins; } else { len = count; } if(copy_from_user(new_gpio_state, buf, len)) { up(&gpio_sema); return -EFAULT; } /* make sure our string only contains 1 and 0 */ p1=0; p2=0; while (p2<=len) { ch=new_gpio_state[p2]; if (ch == '0' || ch == '1' || ch == '\0') { new_gpio_state[p1] = ch; p1++; } if (ch==0) break; p2++; } new_gpio_state[p1] = 0; if (strlen(new_gpio_state)>0) { gpio_state = fromString(new_gpio_state,__number_of_pins); if (driver_ops->set16BitDirection==NULL) { driver_ops->set8BitDirection(gpio_state); } else { driver_ops->set16BitDirection(gpio_state); } } up(&gpio_sema); return len;}static int procfile_led_read( char *buffer, __attribute__ ((unused)) char **start, off_t offset, int len, int *eof, __attribute__ ((unused)) void *data){ unsigned int error_led_status; if (offset > 0 || len<3) { return 0; } if (down_interruptible(&gpio_sema))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -