/****************************************************************************** * FILE PURPOSE: - LED driver module Source ****************************************************************************** * FILE NAME: led_drv.c * * DESCRIPTION: Linux LED character driver implementation * * REVISION HISTORY: * 27 Aug 2003 Initial Creation Sharath Kumar * * 16 Dec 2003 Updates for 5.7 Sharath Kumar * * 07 Jan 2004 Wrapper for DSL Sharath Kumar * * (C) Copyright 2002, Texas Instruments, Inc *******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "led_hal.h" #include "led_platform.h" /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ MODULE_LICENSE("\n(C) Copyright 2003, Texas Instruments, Inc\n(C) Copyright 2004, 2005, AVM"); /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #if 0 #define DEB_ERR(args...) printk(KERN_ERR args) #define DEB_WARN(args...) printk(KERN_WARNING args) #define DEB_INFO(args...) printk(KERN_INFO args) #define DEB_TRACE(args...) printk(KERN_INFO args) #else #define DEB_ERR(args...) printk(KERN_ERR args) #define DEB_WARN(args...) #define DEB_INFO(args...) #define DEB_TRACE(args...) #endif extern void hardware_error_init(void); /*------------------------------------------------------------------------------------------*\ * FIXME Diesen Bereich unbedingt ansehen, ob er noch gueltig ist! FIXME * \*------------------------------------------------------------------------------------------*/ #define AVALANCHE_GPIO_OFF_MAP {0xF34FFFC0} #define AVALANCHE_GPIO_PIN_COUNT 32 /* FIXME hier evtl. 40 ? */ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #define TI_LED_VERSION "1.0" #define GPIO_MAP_LEN ((MAX_GPIO_PIN_NUM/32) + 1) static int gpio_off_state[GPIO_MAP_LEN] = AVALANCHE_GPIO_OFF_MAP; static struct proc_dir_entry *led_dir; struct _avm_led { struct char_device_struct *device_region; dev_t device; struct cdev *cdev; } avm_led; static int led_ioctl( struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg ) { int ret = 0; // char name[80]; DEB_TRACE("[led_ioctl]: cmd = %u\n", cmd); switch ( cmd ) { case LED_CONFIG: { LED_CONFIG_T led_cfg; if (copy_from_user((char *)&led_cfg, (char *)arg, sizeof(led_cfg))) { ret = -EFAULT; break; } DEB_TRACE("[led_ioctl/LED_CONFIG]: led_cfg: name=%s instance=%u state=%u gpio_num=%u param1=%u param2=%u\n", led_cfg.name, led_cfg.instance, led_cfg.state, /*--- unsigned int gpio[MAX_GPIOS_PER_STATE]; ---*/ /*--- unsigned int mode[MAX_GPIOS_PER_STATE]; ---*/ led_cfg.gpio_num, led_cfg.param1, led_cfg.param2); ret = avalanche_led_config_set(&led_cfg); } break; case LED_CONFIG_DONE: DEB_TRACE("[led_ioctl/LED_CONFIG_DONE]: \n"); avalanche_led_late_actions(); ret = 0; break; case LED_GET_HANDLE: { LED_MODULE_T led_mod; int handle; if (copy_from_user((char *)&led_mod, (char *)arg, sizeof(led_mod))) { ret = -EFAULT; break; } DEB_TRACE("[led_ioctl/LED_GET_HANDLE]: led_mod: name=%s instance=%u\n", led_mod.name, led_mod.instance); handle = (int)avalanche_led_register(led_mod.name, led_mod.instance); if (copy_to_user((char *)(&(((LED_MODULE_T *)arg)->handle)), (char *)(&handle), sizeof(int))) { ret = -EFAULT; break; } DEB_TRACE("[led_ioctl/LED_GET_HANDLE]: led_mod: handle=0x%x\n", handle); if(handle) ret = 0; else ret = -1; } break; case LED_ACTION: { LED_STATE_T led_state; if (copy_from_user((char *)&led_state, (char *)arg, sizeof(led_state))) { ret = -EFAULT; break; } DEB_TRACE("[led_ioctl/LED_ACTION]: led_state: handle=0x%x state=%u\n", led_state.handle, led_state.state_id); avalanche_led_action((void *)led_state.handle, led_state.state_id); } break; case LED_RELEASE_HANDLE: DEB_TRACE("[led_ioctl/LED_RELEASE_HANDLE]: handle=0x%x\n", arg); ret = avalanche_led_unregister((void *)arg); break; default: ret = -EINVAL; } return ret; } static int led_open( struct inode * inode, struct file * file ) { return 0; } static int led_close( struct inode * inode, struct file * file ) { return 0; } struct file_operations led_fops = { ioctl: led_ioctl, open: led_open, release: led_close }; /* Proc function to display driver version */ static int led_ver_info(char *buf, char **start, off_t offset, int count, int *eof, void *data) { // int instance; int len=0; len += sprintf(buf +len,"TI Linux LED Driver Version %s\n", TI_LED_VERSION); return len; } /* proc interface /proc/led/led_cfg */ int led_cfg_info(char* buf, char **start, off_t offset, int count, int *eof, void *data) { int mod_count = 0; int i; int len=0; int limit = count - 80; char *msg[NUM_LED_MODES] = { "LED OFF", "LED_ON", "LED_ONESHOT_OFF", "LED_ONESHOT_ON", "LED_FLASH", "LED_BLINK_CODE0", "LED_BLINK_CODE1", "LED_BLINK_CODE2" }; for(mod_count = 0;mod_count 1) { if(len <= limit) len += sprintf(buf + len, " number of gpios: %u\n", led_cfg.gpio_num); } for(i = 0 ; i < led_cfg.gpio_num ; i++) { if(len <= limit) len+= sprintf(buf+len, " mode: %s\n", msg[led_cfg.mode[0] % NUM_LED_MODES]); if(len <= limit) len+= sprintf(buf+len, " gpio: %d\n",led_cfg.gpio[0]); } if(len <= limit) { char *text = "param1"; switch(led_cfg.mode[0]) { case LED_ONESHOT_OFF: text = "off-time [ms]"; break; case LED_ONESHOT_ON: case LED_FLASH: case LED_BLINK_CODE0: case LED_BLINK_CODE1: case LED_BLINK_CODE2: text = "on-time [ms]"; break; } len+= sprintf(buf+len, " %s: %d\n", text, led_cfg.param1); } if(len <= limit) { char *text = "param2"; switch(led_cfg.mode[0]) { case LED_FLASH: text = "off-time [ms]"; break; case LED_BLINK_CODE0: case LED_BLINK_CODE1: case LED_BLINK_CODE2: text = "blink code"; break; } len+= sprintf(buf+len, " %s: %d\n", text, led_cfg.param2); } } } } } return len; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int led_init(void) { int reason; /* register LED device */ DEB_INFO("[avm_led] alloc_chrdev_region()\n"); avm_led.device = MKDEV(AVM_LED_MAJOR, 0); reason = register_chrdev_region(avm_led.device, 1, "led"); if(reason) { DEB_ERR("[avm_led] register_chrdev_region failed: reason %d!\n", reason); return -ERESTARTSYS; } avm_led.cdev = cdev_alloc(); if (!avm_led.cdev) { unregister_chrdev_region(avm_led.device, 1); DEB_ERR("[avm_led] cdev_alloc failed!\n"); return -ERESTARTSYS; } avm_led.cdev->owner = led_fops.owner; avm_led.cdev->ops = &led_fops; kobject_set_name(&(avm_led.cdev->kobj), "led"); if (cdev_add(avm_led.cdev, avm_led.device, 1)) { kobject_put(&avm_led.cdev->kobj); unregister_chrdev_region(avm_led.device, 1); printk("[avm_led] cdev_add failed!\n"); return -ERESTARTSYS; } avalanche_led_hal_init(gpio_off_state,AVALANCHE_GPIO_PIN_COUNT); /* create proc entry */ #ifdef CONFIG_PROC_FS led_dir = proc_mkdir("led", NULL); if (led_dir) { create_proc_read_entry("led_cfg", 0666, led_dir, led_cfg_info, NULL); create_proc_read_entry("led_ver", 0, led_dir, led_ver_info, NULL); } #endif hardware_error_init(); return 0; } void led_exit(void) { avalanche_led_hal_exit(); if(avm_led.cdev) { cdev_del(avm_led.cdev); /* Delete char device */ unregister_chrdev_region(avm_led.device, 1); } return; }