⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 common.c

📁 arm 平台下 linux gpio 的驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
		return -ERESTARTSYS;	error_led_status = driver_ops->readErrorLed();	if (error_led_status) {		buffer[0] = '1';	} else {		buffer[0] = '0';	}	buffer[1] = '\n';	buffer[2] = 0;	/* *start = buffer;*/	*eof=1;	up(&gpio_sema);	return 2;}static int procfile_led_write( __attribute__ ((unused)) struct file *file,                               const char *buf,                               unsigned long count,                               __attribute__ ((unused)) void *data){	int len;	char new_led_state[MAX_NUMBER_OF_PINS+1];	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_led_state, buf, len)) {		return -EFAULT;	}	if (new_led_state[0] == '1') {		driver_ops->writeErrorLed(1);	} else {		driver_ops->writeErrorLed(0);	}	up(&gpio_sema);	return len;}static int procfile_temperature_read(                               char *buffer,                               __attribute__ ((unused)) char **start,                               off_t offset,                               int buffer_length,                               int *eof,                               __attribute__ ((unused)) void *data){	int len;	if (driver_ops->readTemperature==NULL ||                               offset > 0 ||                               buffer_length<TEMPERATURE_BUFFER_SIZE)	{		return 0;	}	if (down_interruptible(&gpio_sema))		return -ERESTARTSYS;	len = driver_ops->readTemperature(buffer, buffer_length);	*eof=1;	up(&gpio_sema);	return len;}static int procfile_voltage_read(                               char *buffer,                               __attribute__ ((unused)) char **start,                               off_t offset,                               int buffer_length,                               int *eof,                               __attribute__ ((unused)) void *data){	int len;	if (driver_ops->readVoltage==NULL ||          offset > 0 ||          buffer_length<VOLTAGE_BUFFER_SIZE)	{		return 0;	}	if (down_interruptible(&gpio_sema))		return -ERESTARTSYS;	len = driver_ops->readVoltage(buffer, buffer_length);	*eof=1;	up(&gpio_sema);	return len;}//------------------------------------------------int net4xxx_gpio_ioctl(struct inode *inode, struct file *filp,                unsigned int cmd, unsigned long arg){	int err = 0;	int ret = 0;	int value=0;	/*	 * extract the type and number bitfields, and don't decode	 * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()	 */	if (_IOC_TYPE(cmd) != PP_IOCTL) return -ENOTTY;	/*	 * the direction is a bitmask, and VERIFY_WRITE catches R/W 	 * transfers. `Type' is user-oriented, while	 * access_ok is kernel-oriented, so the concept of "read" and	 * "write" is reversed	 */	if (_IOC_DIR(cmd) & _IOC_READ)		err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));	else if (_IOC_DIR(cmd) & _IOC_WRITE)		err =  !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));	if (err) return -EFAULT;	if (down_interruptible(&gpio_sema))		return -ERESTARTSYS;	switch(MINOR(inode->i_rdev)) {		case MINOR_BYTE:        // /dev/gpio0 controls the 8 gpio ports		case MINOR_FULL:        // /dev/gpio1 controls the 12 gpio ports			switch(cmd) {				case PPCLAIM:				case PPRELEASE:				case PPFCONTROL:					break;				case PPWDATA:					ret = __get_user(value, (unsigned char *)arg);					if (ret==0) {						driver_ops->write8Bit(value);					}					break;				case PPRDATA:					value = driver_ops->read8Bit();					ret = __put_user(value, (unsigned char *)arg);					break;				case PPDATADIR:					ret = __get_user(value, (unsigned char *)arg);					/* linux/ppdev.h define PPDATADIR as					"Data line direction: non-zero for input mode."					For gpios, the logic is reversed - bit=1 == output					This is _not_ "generic" at all, but very much hard-wired					towards being able to use an HD44780 LCD on the GPIO pins					(in 4-bit mode) and being able to do so using generic					ppdev instructions					So, GPIO4-GPIO7 will _always_ be set to output for this					call, only GPIO0-GPIO3 are changed*/					if (ret==0) {						if (value==0) {							driver_ops->set8BitDirection(0xFF);						} else {							driver_ops->set8BitDirection(0xF0);						}					} else {						printk(OUR_NAME ": ret=%x\n", ret);					}					break;				case GPIORDDIRECTION:					if (MINOR(inode->i_rdev)==MINOR_BYTE) {						value = driver_ops->get8BitDirection();					} else {						value = driver_ops->get16BitDirection();					}					ret = __put_user(value, (unsigned int *)arg);					break;				case GPIOWRDIRECTION:					ret = __get_user(value, (unsigned int *)arg);					if (ret==0) {						if (MINOR(inode->i_rdev)==MINOR_BYTE) {							driver_ops->set8BitDirection(value);						} else {							driver_ops->set16BitDirection(value);						}					}					break;				case GPIORDDATA:					if (MINOR(inode->i_rdev)==MINOR_BYTE) {						value = driver_ops->read8Bit();					} else {						value = driver_ops->read16Bit();					}					ret = __put_user(value, (unsigned int *)arg);					break;				case GPIOWRDATA:					ret = __get_user(value, (unsigned int *)arg);					if (ret==0) {						if (MINOR(inode->i_rdev)==MINOR_BYTE) {							driver_ops->write8Bit(value);						} else {							driver_ops->write16Bit(value);						}					}					break;				default:					return -ENOTTY;			}			break;		case MINOR_LED:        // /dev/gpio254 controls the error led			switch(cmd) {				case PPCLAIM:				case PPRELEASE:				case PPFCONTROL:				case PPDATADIR: /* Doesn't work the same way */					break;				case PPWDATA:					ret = __get_user(value, (unsigned char *)arg);					if (ret==0) {						driver_ops->writeErrorLed(value);					}					break;				case PPRDATA:					value = driver_ops->readErrorLed();					ret = __put_user(value, (unsigned char *)arg);					break;				default:					return -ENOTTY;			}			break;	}	up(&gpio_sema);	return ret;}static struct file_operations gpio_dispatch_fops = {	.owner   = THIS_MODULE,	.write   = net4xxx_gpio_write,	.read    = net4xxx_gpio_read,	.open    = net4xxx_gpio_open,	.release = net4xxx_gpio_release,	.ioctl   = net4xxx_gpio_ioctl,};int __init common_init(void){	static int result;	static struct proc_dir_entry *GPIO_Proc_File;	static struct proc_dir_entry *ErrorLED_Proc_File;	static struct proc_dir_entry *Settings_Proc_File;	static struct proc_dir_entry *Temperature_Proc_File;	static struct proc_dir_entry *Voltage_Proc_File;	init_map = 0;	result = net4801_init(&driver_ops);	if (result!=0) {		result = net4501_init(&driver_ops);		if (result!=0) {			return(result);		}	}	result = register_chrdev(gpio_major, OUR_NAME, &gpio_dispatch_fops);	if (result < 0) {		printk(KERN_WARNING OUR_NAME ": can't get major %d\n", gpio_major);		return result;	}	if (gpio_major == 0) gpio_major = result; /* dynamic */	GPIO_Proc_File = create_proc_entry(			GPIO_PROC_FILENAME,			S_IWUSR |S_IRUSR | S_IRGRP | S_IROTH, /*S_IFREG | S_IRUGO,*/			NULL);	if(GPIO_Proc_File == NULL) {		printk(KERN_ERR OUR_NAME ": Could not register " GPIO_PROC_FILENAME  ". Terminating\n");		common_cleanup();		return -ENOMEM;	} else {		GPIO_Proc_File->read_proc=procfile_gpio_read;		GPIO_Proc_File->write_proc=procfile_gpio_write;		init_map |= GPIO_PROC_FILE;	}	ErrorLED_Proc_File = create_proc_entry(			LED_PROC_FILENAME,			S_IWUSR |S_IRUSR | S_IRGRP | S_IROTH,			NULL);	if(ErrorLED_Proc_File == NULL) {		printk(KERN_ERR OUR_NAME ":Could not register " LED_PROC_FILENAME ". Terminating\n");		common_cleanup();		return -ENOMEM;	} else {		ErrorLED_Proc_File->read_proc=procfile_led_read;		ErrorLED_Proc_File->write_proc=procfile_led_write;		init_map |= LED_PROC_FILE;	}	Settings_Proc_File = create_proc_entry(			SETTINGS_PROC_FILENAME,			S_IWUSR |S_IRUSR | S_IRGRP | S_IROTH,			NULL);	if(Settings_Proc_File == NULL) {		printk(KERN_ERR OUR_NAME ": Could not register " SETTINGS_PROC_FILENAME ". Terminating\n");		common_cleanup();		return -ENOMEM;	} else {		Settings_Proc_File->read_proc=procfile_settings_read;		Settings_Proc_File->write_proc=procfile_settings_write;		init_map |= SETTINGS_PROC_FILE;	}	if (driver_ops->readTemperature!=NULL) {		Temperature_Proc_File = create_proc_entry(				TEMPERATURE_PROC_FILENAME,				S_IRUSR | S_IRGRP | S_IROTH,				NULL);		if(Temperature_Proc_File == NULL) {			printk(KERN_ERR OUR_NAME ": Could not register " TEMPERATURE_PROC_FILENAME ". Terminating\n");			common_cleanup();			return -ENOMEM;		} else {			Temperature_Proc_File->read_proc=procfile_temperature_read;			init_map |= TEMP_PROC_FILE;		}	}	if (driver_ops->readVoltage!=NULL) {		Voltage_Proc_File = create_proc_entry(				VOLTAGE_PROC_FILENAME,				S_IRUSR | S_IRGRP | S_IROTH,				NULL);		if(Voltage_Proc_File  == NULL) {			printk(KERN_ERR OUR_NAME ": Could not register " VOLTAGE_PROC_FILENAME ". Terminating\n");			common_cleanup();			return -ENOMEM;		} else {			Voltage_Proc_File->read_proc=procfile_voltage_read;			init_map |= VOLT_PROC_FILE;		}	}	sema_init(&gpio_sema, 1);	/* set gpio0-7 to output */	driver_ops->set8BitDirection(0xFF);	return(0);}void __exit common_cleanup(void){	if (init_map&VOLT_PROC_FILE)		remove_proc_entry(VOLTAGE_PROC_FILENAME, NULL);	if (init_map&TEMP_PROC_FILE)		remove_proc_entry(TEMPERATURE_PROC_FILENAME, NULL);	if (init_map&SETTINGS_PROC_FILE)		remove_proc_entry(SETTINGS_PROC_FILENAME, NULL);	if (init_map&LED_PROC_FILE)		remove_proc_entry(LED_PROC_FILENAME, NULL);	if (init_map&GPIO_PROC_FILE)		remove_proc_entry(GPIO_PROC_FILENAME, NULL);	unregister_chrdev(gpio_major, OUR_NAME);	driver_ops->cleanup();}//------------------------------------------------module_init(common_init);module_exit(common_cleanup);EXPORT_SYMBOL(__number_of_pins);MODULE_AUTHOR("Martin Hejl");MODULE_DESCRIPTION("Soekris net4xxx GPIO / Error LED driver");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -