/****************************************************************************** * FILE PURPOSE: Vlynq Linux Device Driver Source ****************************************************************************** * FILE NAME: vlynq_drv.c * * DESCRIPTION: Vlynq Linux Device Driver Source * * REVISION HISTORY: * * Date Description Author *----------------------------------------------------------------------------- * 17 July 2003 Initial Creation Anant Gole * 17 Dec 2003 Updates Sharath Kumar * * (C) Copyright 2003, Texas Instruments, Inc *******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #define TI_VLYNQ_VERSION "0.2" /* debug on ? */ #define VLYNQ_DEBUG /* Macro for debug and error printf's */ #ifdef VLYNQ_DEBUG #define DBGPRINT printk #else #define DBGPRINT(x) #endif #define ERRPRINT printk /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int vlynq_device_type0 = 0; int vlynq_device_type1 = 0; int vlynq_reset_bit_0 = 6; int vlynq_reset_bit_1 = 18; MODULE_PARM(vlynq_reset_bit_0, "i"); MODULE_PARM(vlynq_reset_bit_1, "i"); MODULE_PARM(vlynq_device_type0, "i"); MODULE_PARM(vlynq_device_type1, "i"); MODULE_PARM_DESC(vlynq_reset_bit_0, "VLYNQ No. 1 Reset GPIO Bit "); MODULE_PARM_DESC(vlynq_reset_bit_1, "VLYNQ No. 2 Reset GPIO Bit "); MODULE_PARM_DESC(vlynq_device_type0, "VLYNQ No. 1 Device Type (0=unused, 1=WLAN, 2=USB-HOST)"); MODULE_PARM_DESC(vlynq_device_type1, "VLYNQ No. 2 Device Type (0=unused, 1=WLAN, 2=USB-HOST)"); MODULE_LICENSE("(C) Copyright 2003, Texas Instruments, Inc\n(C) Copyright 2004, AVM"); /* include Vlynq HAL header file */ #include "vlynq_hal.h" /* Define the max vlynq ports this driver will support. Device name strings are statically added here */ #define MAX_VLYNQ_PORTS 2 /* Type define for VLYNQ private structure */ typedef struct vlynqPriv{ int irq; VLYNQ_DEV *vlynqDevice; }VLYNQ_PRIV; extern int vlynq_init_status[2]; /* Extern Global variable for vlynq devices used in initialization of the vlynq device * These variables need to be populated/initialized by the system as part of initialization * process. The vlynq enumerator can run at initialization and populate these globals */ VLYNQ_DEV vlynqDevice0; VLYNQ_DEV vlynqDevice1; /* Defining dummy macro AVALANCHE_HIGH_VLYNQ_INT to take * care of compilation in case of single vlynq device */ #ifndef AVALANCHE_HIGH_VLYNQ_INT #define AVALANCHE_HIGH_VLYNQ_INT 0 #endif /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ #if defined (CONFIG_MIPS_AVALANCHE_VLYNQ_MODULE) extern int vlynq_dev_init(unsigned int); extern void vlynq_set_function_pointers(void); extern void vlynq_clear_function_pointers(void); #endif /*--- #if defined (CONFIG_MIPS_AVALANCHE_VLYNQ_MODULE) ---*/ /* vlynq private object */ VLYNQ_PRIV vlynq_priv[CONFIG_MIPS_AVALANCHE_VLYNQ_PORTS] = { { LNXINTNUM(AVALANCHE_LOW_VLYNQ_INT), &vlynqDevice0 }, { LNXINTNUM(AVALANCHE_HIGH_VLYNQ_INT), &vlynqDevice1 }, }; static unsigned int avalanche_vlynq_ports = 0; /*****************************************************************************\ \*****************************************************************************/ static int vlynq_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) { return 0; } static struct file_operations vlynq_fops = { owner: THIS_MODULE, ioctl: vlynq_ioctl, }; /* Vlynq device object */ static struct miscdevice vlynq_dev [MAX_VLYNQ_PORTS] = { { MISC_DYNAMIC_MINOR , "vlynq0", &vlynq_fops }, { MISC_DYNAMIC_MINOR , "vlynq1", &vlynq_fops }, }; /*****************************************************************************\ \*****************************************************************************/ /* Proc read function */ static int vlynq_read_link_proc (char * buf, char ** start, off_t offset, int count, int * eof, void * unused) { int instance; int len = 0; len += sprintf( buf +len, "VLYNQ Devices in use/total: %d/%d\n", avalanche_vlynq_ports, CONFIG_MIPS_AVALANCHE_VLYNQ_PORTS ); for (instance = 0 ; instance < CONFIG_MIPS_AVALANCHE_VLYNQ_PORTS; instance++) { int link_state; char * link_msg[] = {" DOWN "," UP "}; if (vlynq_init_status[instance] == 0) link_state = 0; else if (vlynq_link_check (vlynq_priv[instance].vlynqDevice)) link_state = 1; else link_state = 0; len += sprintf (buf + len, "VLYNQ %d: Link state: %s\n", instance, link_msg[link_state]); } /* Print info about vlynq devices */ return len; } /* Proc function to display driver version */ static int vlynq_read_ver_proc (char * buf, char ** start, off_t offset, int count, int * eof, void * data) { int len = 0; len += sprintf (buf +len, "\nTI Linux VLYNQ Driver Version %s\n", TI_VLYNQ_VERSION); return len; } /*****************************************************************************\ \*****************************************************************************/ /* Wrapper for vlynq ISR */ static void lnx_vlynq_root_isr (int irq, void * arg, struct pt_regs * regs) { vlynq_root_isr(arg); } /*****************************************************************************\ \*****************************************************************************/ int vlynq_init_module (void) { int ret; int unit = 0; unsigned int mask = 0; int instance_count = CONFIG_MIPS_AVALANCHE_VLYNQ_PORTS; // volatile int * ptr; #if defined (CONFIG_MIPS_AVALANCHE_VLYNQ_MODULE) vlynq_set_function_pointers(); memset (&vlynqDevice0, 0, sizeof (VLYNQ_DEV)); /* <<<< */ memset (&vlynqDevice1, 0, sizeof (VLYNQ_DEV)); /* <<<< */ avalanche_vlynq_ports = 0; /* Safety first! */ if (vlynq_device_type0 != 0) { ++avalanche_vlynq_ports; mask |= 1; } if (vlynq_device_type1 != 0) { ++avalanche_vlynq_ports; mask |= 2; } printk ( KERN_INFO "vlynq_dev_init: %d/%d VLYNQs, mask 0x%04x\n", avalanche_vlynq_ports, CONFIG_MIPS_AVALANCHE_VLYNQ_PORTS, mask ); if (vlynq_dev_init(mask)) { printk (KERN_INFO "[vlynq_init_module] vlynq_dev_init failed\n"); vlynq_clear_function_pointers(); return -1; } #elif defined (CONFIG_MIPS_AVALANCHE_VLYNQ) avalanche_vlynq_ports = CONFIG_MIPS_AVALANCHE_VLYNQ_PORTS; #endif /* If num of configured vlynq ports > supported by driver return error */ if (instance_count > MAX_VLYNQ_PORTS) { ERRPRINT("ERROR: vlynq_init_module(): Max %d supported\n", MAX_VLYNQ_PORTS); return (-1); } /* register the misc device */ for (unit = 0; unit < CONFIG_MIPS_AVALANCHE_VLYNQ_PORTS; unit++) { /* was: avalanche_vlynq_ports */ if ((ret = misc_register (&vlynq_dev[unit])) < 0) { printk (KERN_ERR "VLYNQ%d: Could not register device!\n", unit); /* Try next one... */ continue; } else { DBGPRINT("VLYNQ%d: Misc device %s registered, minor #%d. (%d)\n", unit, vlynq_dev[unit].name, vlynq_dev[unit].minor, ret); } #if 0 DBGPRINT("Calling vlynq init\n"); /* Read the global variable for VLYNQ device structure and initialize vlynq driver */ ret = vlynq_init (vlynq_priv[unit].vlynqDevice, VLYNQ_INIT_PERFORM_ALL); #endif /**************************************************************\ \**************************************************************/ if (vlynq_init_status[unit] == 0) { printk(KERN_INFO "VLYNQ%d: Init failed!\n", unit); continue; } /* Check link before proceeding */ if (!vlynq_link_check (vlynq_priv[unit].vlynqDevice)) { printk (KERN_INFO "VLYNQ%d: Link check failed.\n", unit); } else { /* Install the vlynq local root ISR */ if (request_irq ( vlynq_priv[unit].irq, lnx_vlynq_root_isr, 0, vlynq_dev[unit].name, vlynq_priv[unit].vlynqDevice ) ) { printk (KERN_ERR "VLYNQ%d: Could not claim IRQ %d!\n", unit, vlynq_priv[unit].irq); /* What is to be returned here to signal failure? */ } else { printk (KERN_INFO "VLYNQ%d: Running on IRQ %d.\n", unit, vlynq_priv[unit].irq); } } /**************************************************************\ \**************************************************************/ } /* Creating proc entry for the devices */ create_proc_read_entry ("avalanche/vlynq_link", 0, NULL, vlynq_read_link_proc, NULL); create_proc_read_entry ("avalanche/vlynq_ver", 0, NULL, vlynq_read_ver_proc, NULL); return 0; } /* vlynq_init_module */ void vlynq_cleanup_module (void) { int unit = 0; #if defined (CONFIG_MIPS_AVALANCHE_VLYNQ_MODULE) vlynq_clear_function_pointers(); #endif /*--- #if defined (CONFIG_MIPS_AVALANCHE_VLYNQ_MODULE) ---*/ for (unit = 0; unit < avalanche_vlynq_ports; unit++) { DBGPRINT("vlynq_cleanup_module(): Unregistring misc device %s\n", vlynq_dev[unit].name); misc_deregister (&vlynq_dev[unit]); } remove_proc_entry ("avalanche/vlynq_link", NULL); remove_proc_entry("avalanche/vlynq_ver", NULL); } /* vlynq_cleanup_module */ /*****************************************************************************\ \*****************************************************************************/ module_init(vlynq_init_module); module_exit(vlynq_cleanup_module); EXPORT_SYMBOL(vlynq_interrupt_disable); EXPORT_SYMBOL(vlynq_interrupt_enable); EXPORT_SYMBOL(vlynq_interrupt_get_type); EXPORT_SYMBOL(vlynq_interrupt_set_type); EXPORT_SYMBOL(vlynq_interrupt_get_polarity); EXPORT_SYMBOL(vlynq_interrupt_set_polarity); EXPORT_SYMBOL(vlynq_interrupt_vector_map); EXPORT_SYMBOL(vlynq_interrupt_vector_cntl); EXPORT_SYMBOL(vlynq_interrupt_vector_set); EXPORT_SYMBOL(vlynq_uninstall_isr); EXPORT_SYMBOL(vlynq_install_isr); EXPORT_SYMBOL(vlynq_interrupt_get_count); EXPORT_SYMBOL(vlynq_root_isr); EXPORT_SYMBOL(vlynq_init);