📄 common.c
字号:
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 + -