/************************************************************************** * File Name : pcmace.c * * Project: Ace BU6555xM2-300 PCMCIA interface driver for Linux 2.2.16-22 * * * Copyright (C) 2004 by ILC Data Device Corp. * All Rights Reserved. * * * Comments: * Make within the Linux Card Services package * usr/src/linux/pcmcia-cs-x.y.z/clients * Ignore warining for .modinfo (not implemented) * See readme.txt * * Revision History * Date Name Version Description *-------------------------------------------------------------------------- * 18-Apr-2001 Gary Davies 1.0 Original * 04-Mar-2002 Mark Findlater 1.1 Added support for multiple cards * Added kernel support for Kernel version 2.4.X * Removed Register address and replace with #defines * * 15-Oct-2002 Ray Little 1.2 Fixed Interrupt problems. * 26-Jun-2003 KWH 1.3 Merged driver with ACE library. * 07-Dec-2004 ESK 1.4 Replaced deprectaed functions with macros. * 07-Dec-2010 GLS 2.0 Ported to 2.6.18 kernels * (and deleted all old stuff) * * ***************************************************************************/ #include #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) #error unsupported kernel version! #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pcmace.h" // Driver declarations ----------------------------------------------- /* List of known cards to bind*/ char m_cszArrKnownCards[ACE53_MAX_NUM_KNOWN_CARDS][20]; /* Holds the MAJOR number of the ace53 driver */ __s32 m_dwMajorNumber = 0; __s32 m_dwMinorNumber = 0; /* Holds the total number of 65549 cards in the system */ __u8 m_bNumberOfCards = 0; /* The card list. */ ACE53_CARD m_aCards[ACE53_MAX_NUM_CARDS]; /* Card device ID's used by ISR to determine which card issued an interrupt. */ __u8 m_Dev_id[ACE53_MAX_NUM_CARDS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }; /* String used as a reference for interrupt usage (/proc/interrupts). * THIS STRING BEING DECLARED AND INITIALIZED CANNOT BE LOCATED IN THE 'ioctl' * METHOD BECAUSE IT WOULD NEED A 'memset' SYMBOL TO BE AVAILABLE, BUT I DON'T * THINK ONE EXISTS AT THE KERNEL LEVEL. IT WOULD COMPILE, BUT GIVES AN ERROR * WHEN THE MODULE IS LOADED. */ // sDevName gets updated by the ioctl function so don't use it to reference the module name in other functions, use MODULE_NAME __s8 m_sDevName[DEV_NAME_LEN] = { MODULE_NAME }; /* Wait queues used for blocking. */ wait_queue_head_t m_apWaitQue[ACE53_MAX_NUM_CARDS]; int m_apWaitFlag = 0; // End of Driver declarations ---------------------------------------- /* All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If you do not define PCMCIA_DEBUG at all, all the debug code will be left out. If you compile with PCMCIA_DEBUG=0, the debug code will be present but disabled -- but it can then be enabled for specific modules at load time with a 'pc_debug=#' option to insmod. */ //#define PCMCIA_DEBUG 0 //#define PCMCIA_KERN_DEBUG KERN_DEBUG #define PCMCIA_DEBUG 100 #define PCMCIA_KERN_DEBUG KERN_ALERT #ifdef PCMCIA_DEBUG static int pc_debug = PCMCIA_DEBUG; #define DEBUG(n, args...) if (pc_debug>(n)) printk(PCMCIA_KERN_DEBUG args) #else #define DEBUG(n, args...) #endif /* The event() function is this driver's Card Services event handler. It will be called by Card Services when an appropriate card status event is received. The config() and release() entry points are used to configure or release a socket, in response to card insertion and ejection events. They are invoked from the bu65553x event handler. */ static void pcmace_cs_config(struct pcmcia_device *plink); static void pcmace_cs_release(struct pcmcia_device *plink); /* The attach() and detach() entry points are used to create and destroy "instances" of the driver, where each instance represents everything needed to manage one actual PCMCIA card. */ static int pcmace_cs_attach(struct pcmcia_device *); static void pcmace_cs_detach(struct pcmcia_device *); static int pcmace_cs_suspend(struct pcmcia_device *); static int pcmace_cs_resume(struct pcmcia_device *); static void PrintServinfo(struct pcmcia_device *dev); static void dumpStruct(void); /* You'll also need to prototype all the functions that will actually be used to talk to your device. See 'memory_cs' for a good example of a fully self-sufficient driver; the other drivers rely more or less on other parts of the kernel. */ /* The dev_info variable is the "key" that is used to match up this device driver with appropriate cards, through the card configuration database. */ /*static dev_info_t dev_info = "pcmace";*/ /* A linked list of "instances" of the bu6555x device. Each actual PCMCIA card corresponds to one device instance, and is described by one struct pcmcia_device structure (defined in ds.h). You may not want to use a linked list for this -- for example, the bu65553x card driver uses an array of struct pcmcia_device pointers, where minor device numbers are used to derive the corresponding array index. */ /*static struct pcmcia_device *dev_list = NULL;*/ /* A struct pcmcia_device structure has fields for most things that are needed to keep track of a socket, but there will usually be some device specific information that also needs to be kept track of. The 'priv' pointer in a struct pcmcia_device structure can be used to point to a device-specific private data structure, like this. To simplify the data structure handling, we actually include the struct pcmcia_device structure in the device's private data structure. A driver needs to provide a dev_node_t structure for each device on a card. In some cases, there is only one device per card (for example, ethernet cards, modems). In other cases, there may be many actual or logical devices (SCSI adapters, memory cards with multiple partitions). The dev_node_t structures need to be kept in a linked list starting at the 'dev' field of a struct pcmcia_device structure. We allocate them in the card's private data structure, because they generally shouldn't be allocated dynamically. In this case, we also provide a flag to indicate if a device is "stopped" due to a power management event, or card ejection. The device IO routines can use a flag like this to throttle IO to a card that is not ready to accept it. The bus_operations pointer is used on platforms for which we need to use special socket-specific versions of normal IO primitives (inb, outb, readb, writeb, etc) for card IO. */ typedef struct local_info_t { struct pcmcia_device *link; /*dev_node_t node;*/ int stop; struct bus_operations *bus; } local_info_t; #define __NOTREQUESTED__ 0 #define __REQUESTED__ 1 // Structures used to request card resources; IO ports, IRQ, memory typedef struct { win_req_t req; memreq_t map; window_handle_t winhandle; char cArrWindowRequest; int* pnDirectPhysicalAddr; unsigned long ulWindowSize; int* pnDirectKernelAddr; } Card_Win_t; typedef struct { char cIORequest; char cIRQRequest; int nNumWindows; Card_Win_t WinArr[ACE53_MAX_NUM_WINDOWS]; } Card_IO_t; static Card_IO_t m_CardIO[ACE53_MAX_NUM_CARDS]; /*---------------------------START OF CHAR DRIVER FUNCTIONS----------------------------*/ /******************************************************************* * Function: pcmace_fops_open * * * * Description: Handles opening of a single channel (device) * * * * Parameters: inode - used to get the Minor Number * * flip - Not Used * *******************************************************************/ static int pcmace_fops_open(struct inode *inode, struct file *filp) { __u8 bCardNum = MINOR(inode->i_rdev); /* Card number in system (0 - 3) */ DEBUG(10, "%s: entering fops_open\n", MODULE_NAME); dumpStruct(); /* Check that minor number corresponds to a card in the system. */ if (bCardNum >= m_bNumberOfCards) return STATUS_ACE53_DEVICE_NOT_EXIST; /* Check that this device is not already opened. */ if(m_aCards[bCardNum].Channel.bOpen) return STATUS_ACE53_CARD_ALREADY_OPEN; /* Check if REGISTER window in User Space was properly closed */ if( (m_aCards[bCardNum].Channel.dwMemWndUsrAddr) || (m_aCards[bCardNum].Channel.dwRegWndUsrAddr) ) return STATUS_ACE53_CARD_IMPROPERLY_CLOSED; /* Set Card Number */ m_aCards[bCardNum].Channel.bCardNum = bCardNum; /* Set Channel Number */ m_aCards[bCardNum].Channel.bChanNum = 0; /* Check if the other channel is closed */ /* Kernel Memory should be null */ if( (m_aCards[bCardNum].dwRegWndKrnAddr) || (m_aCards[bCardNum].dwMemWndKrnAddr) ) return STATUS_ACE53_CARD_IMPROPERLY_CLOSED; DEBUG(80, "%s: fops_open: 0x%x 0x%x\n", MODULE_NAME, m_aCards[bCardNum].dwRegWndPcmciaAddr, ACE53_CHAN_REG_LENGTH); /* Map the Register window to kernel space. */ /* GLS */ request_mem_region(m_aCards[bCardNum].dwRegWndPcmciaAddr, ACE53_CHAN_REG_LENGTH, MODULE_NAME); if(!(m_aCards[bCardNum].dwRegWndKrnAddr = (__u64)ioremap(m_aCards[bCardNum].dwRegWndPcmciaAddr,ACE53_CHAN_REG_LENGTH))) return STATUS_ACE53_PCMCIACFG_REMAP_FAIL; request_mem_region(m_aCards[bCardNum].dwRegWndKrnAddr, ACE53_CHAN_REG_LENGTH, MODULE_NAME); DEBUG(80, "%s: fops_open: reading from card registers through kernel:\n" " 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", MODULE_NAME, *((unsigned char *)(m_aCards[bCardNum].dwRegWndKrnAddr)), *(((unsigned char *)(m_aCards[bCardNum].dwRegWndKrnAddr))+ 1), *(((unsigned char *)(m_aCards[bCardNum].dwRegWndKrnAddr))+ 2), *(((unsigned char *)(m_aCards[bCardNum].dwRegWndKrnAddr))+ 3), *(((unsigned char *)(m_aCards[bCardNum].dwRegWndKrnAddr))+ 4), *(((unsigned char *)(m_aCards[bCardNum].dwRegWndKrnAddr))+ 5)); DEBUG(80, "%s: fops_open: before card reset\n", MODULE_NAME); *(((unsigned char *)(m_aCards[bCardNum].dwRegWndKrnAddr))+ 7) = 1; DEBUG(80, "%s: fops_open: after card reset\n", MODULE_NAME); DEBUG(80, "%s: fops_open: 0x%02x\n", MODULE_NAME, *(((unsigned char *)(m_aCards[bCardNum].dwRegWndKrnAddr))+ 14)); *(((unsigned char *)(m_aCards[bCardNum].dwRegWndKrnAddr))+ 14) = 15; DEBUG(80, "%s: fops_open: 0x%02x\n", MODULE_NAME, *(((unsigned char *)(m_aCards[bCardNum].dwRegWndKrnAddr))+ 14)); /* GLS */ /* Map the Memory window to kernel space. */ request_mem_region(m_aCards[bCardNum].dwMemWndPcmciaAddr, ACE53_CHAN_MEM_LENGTH, MODULE_NAME); if(!(m_aCards[bCardNum].dwMemWndKrnAddr = (__u64)ioremap(m_aCards[bCardNum].dwMemWndPcmciaAddr,ACE53_CHAN_MEM_LENGTH))) return STATUS_ACE53_PCMCIACFG_REMAP_FAIL; request_mem_region(m_aCards[bCardNum].dwMemWndKrnAddr, ACE53_CHAN_MEM_LENGTH, MODULE_NAME); DEBUG(80, "%s: fops_open: reading from card data through kernel:\n" " 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", MODULE_NAME, *((unsigned char *)(m_aCards[bCardNum].dwMemWndKrnAddr)), *(((unsigned char *)(m_aCards[bCardNum].dwMemWndKrnAddr))+ 1), *(((unsigned char *)(m_aCards[bCardNum].dwMemWndKrnAddr))+ 2), *(((unsigned char *)(m_aCards[bCardNum].dwMemWndKrnAddr))+ 3), *(((unsigned char *)(m_aCards[bCardNum].dwMemWndKrnAddr))+ 4), *(((unsigned char *)(m_aCards[bCardNum].dwMemWndKrnAddr))+ 5)); DEBUG(80, "%s: fops_open: 0x%02x\n", MODULE_NAME, *(((unsigned char *)(m_aCards[bCardNum].dwMemWndKrnAddr))+ 1)); *(((unsigned char *)(m_aCards[bCardNum].dwMemWndKrnAddr))+ 1) = 255; DEBUG(80, "%s: fops_open: 0x%02x\n", MODULE_NAME, *(((unsigned char *)(m_aCards[bCardNum].dwMemWndKrnAddr))+ 1)); /* Set Number of Channels */ m_aCards[bCardNum].bNumChnls = (U8)ACE53_NUM_CHANS_PER_CARD; /* Add initialise for wait_queue */ init_waitqueue_head(&m_apWaitQue[bCardNum]); /* Reset BC Auto Flip Stack */ m_aCards[bCardNum].Channel.bAutoFlipStk = 0; /* define device as open */ m_aCards[bCardNum].Channel.bOpen = 1; /* define Card Device Number */ m_aCards[bCardNum].bPciDevNum = bCardNum; //jmf added to allow multiple cards m_aCards[bCardNum].bMajor = MAJOR(inode->i_rdev); m_aCards[bCardNum].bMinor = bCardNum; dumpStruct(); return STATUS_ACE53_SUCCESS; } /* ISR for legacy ACE devices. */ static irqreturn_t pcmace_isr(int irq, void* dev_id, struct pt_regs *regs) { __u8 *bpChanNum = dev_id; /* Pointer to interrupted device */ __u8 bSystemNum = (__u8)(*bpChanNum); /* Enumerated System Number */ __u8 bCardNum = (__u8)(bSystemNum); /* Card number in system (0 - 3) */ __u8 bChanNum = 0; /* Channel number on card (0, 1) */ /* __u8 bIntFlag = 0x11; */ /* This device's INT flag */ __u8 bCurArea = 0x00; /* Current Stack Area (A/B) */ __u8 bBCEof = 0x00; /* BC End-of-Frame Interrupt */ /* __u16 wConfigReg = 0x1111; */ /* 65549 0800 Configuration Space */ __u16 wIntStatReg = 0x0000; /* Ace Interrupt Status Register */ __u16 wCfgReg1 = 0x0000; /* Ace Configuration Register #1 */ __u64 dwChanOffset = 0x0000000000000000; /* Holds the channel's Reg base addr */ DEBUG(10, "%s: entering legacy ACE isr pcmace_isr\n", MODULE_NAME); DEBUG(10, "%s: pcmace_isr: bChanNum %u\n", MODULE_NAME, bChanNum); DEBUG(10, "%s: pcmace_isr: bCardNum %u\n", MODULE_NAME, bCardNum); /* Get Channel Offset */ dwChanOffset = (__u64)(m_aCards[bCardNum].dwRegWndKrnAddr + (bChanNum*0x0080)); /* reg space = 0x80 */ DEBUG(10, "%s: pcmace_isr: 01\n", MODULE_NAME); DEBUG(10, "%s: pcmace_isr: dwChanOffset 0x%llX\n", MODULE_NAME, dwChanOffset); DEBUG(10, "%s: pcmace_isr: dwChanOffset 0x%llX\n", MODULE_NAME, dwChanOffset + 0x000C); /* Get INTERRUPT_STATUS_REG */ m_aCards[bCardNum].Channel.dwIntStatus = (__u32)readw((void*)(dwChanOffset + 0x000C)); DEBUG(10, "%s: pcmace_isr: 02\n", MODULE_NAME); /* Wake up the blocked driver level ISR thread */ wake_up_interruptible(&m_apWaitQue[bCardNum]); m_apWaitFlag = 1; DEBUG(10, "%s: pcmace_isr: 03\n", MODULE_NAME); /* Make sure Interrupt Status Reg is valid */ if (m_aCards[bCardNum].Channel.dwIntStatus) { DEBUG(10, "%s: pcmace_isr: 04\n", MODULE_NAME); /* Check for BC EOF Interrupt */ bBCEof = ((wIntStatReg >> 3) & 0x1); DEBUG(10, "%s: legacy ACE isr: 05\n", MODULE_NAME); /* Flip BC Stacks if EOF Int and its enabled */ if ((m_aCards[bCardNum].Channel.bAutoFlipStk) && (bBCEof)) { DEBUG(10, "%s: legacy ACE isr: 06\n", MODULE_NAME); /* Get CONFIG_REG_1 */ wCfgReg1 = readw((void*)(dwChanOffset + 0x0002)); DEBUG(10, "%s: legacy ACE isr: 07\n", MODULE_NAME); /* Get Current BC Stack Area */ bCurArea = ((wCfgReg1 >> 13) & 0x1); DEBUG(10, "%s: legacy ACE isr: 08\n", MODULE_NAME); if (bCurArea) /* A */ { DEBUG(10, "%s: legacy ACE isr: 09\n", MODULE_NAME); writew(wCfgReg1&0xDFFF,(void*)(dwChanOffset + 0x0002)); DEBUG(10, "%s: legacy ACE isr: 10\n", MODULE_NAME); } else /* B */ { DEBUG(10, "%s: legacy ACE isr: 11\n", MODULE_NAME); writew(wCfgReg1|0x2000,(void*)(dwChanOffset + 0x0002)); DEBUG(10, "%s: legacy ACE isr: 12\n", MODULE_NAME); } DEBUG(10, "%s: legacy ACE isr: 13\n", MODULE_NAME); } DEBUG(10, "%s: legacy ACE isr: 14\n", MODULE_NAME); } /* Clear Interrupt */ DEBUG(10, "%s: legacy ACE isr: 15\n", MODULE_NAME); writew(0x0004,(void*)(dwChanOffset + 0x0006)); DEBUG(10, "%s: legacy ACE isr: 16\n", MODULE_NAME); return 0; } /* ISR for Enhanced Mini-ACE devices. */ static irqreturn_t pcmemace_isr(int irq, void* dev_id, struct pt_regs *regs) { __u8 *pbCardNum; /* Indicates which card issued the interrupt. */ __u64 dwChanOffset; /* Holds the channel's Reg base addr */ __u32 dwIntStatus; /* Holds the channel's Reg base addr */ DEBUG(10, "%s: entering Enhanced Mini-ACE isr\n", MODULE_NAME); pbCardNum = dev_id; /* Get Channel Offset */ dwChanOffset = (__u32)(m_aCards[*pbCardNum].dwRegWndKrnAddr + 0x0080); /* reg space = 0x80 */ /* NULL out status variable and get INTERRUPT_STATUS_REG's */ dwIntStatus = 0; dwIntStatus = readw((void*)(dwChanOffset + 0x0003C)) << 16; dwIntStatus |= readw((void*)(dwChanOffset + 0x000C)); /* If there is no status, we didn't generate the interrupt. */ if( !dwIntStatus ) return 0; /* Not us, return to OS */ /* Assign the read status to the card structure so the IOCTL can return it to user space. */ m_aCards[*pbCardNum].Channel.dwIntStatus = dwIntStatus; /* Wake up the blocked driver level ISR thread */ wake_up_interruptible(&m_apWaitQue[*pbCardNum]); m_apWaitFlag = 1; /* Clear Interrupt */ if( !(readw((void*)(dwChanOffset + 0x0004)) & 0x0010) ) writew(0x0004,(void*)(dwChanOffset + 0x0006)); return 0; } /******************************************************************* * Function: pcmace_fops_ioctl * * * * Description: Handles all ioctl calls to device driver * * * * Parameters: inode - used to get Minor number * * flip - Not Used * * wCmd - ioctl command requested * * dwParam - ioctl return data variable * *******************************************************************/ static int pcmace_fops_ioctl(struct inode *inode, struct file *flip, unsigned int wCmd, unsigned long dwParam) { int nResult = STATUS_ACE53_SUCCESS; /* return value */ __u8 bCardNum = MINOR(inode->i_rdev); /* Card number in system (0 - 3) */ __u8 *bpCardNum = &m_Dev_id[bCardNum]; /*jmf used to register interrupts seperatley for each card */ __u32 dwFlags = 0x00000000; /* temp variables for cli() */ irqreturn_t (*pfIsr)(int, void*, struct pt_regs*) = NULL; /* DEBUG(10, "%s: entering fops_ioctl: cmd %u\n", MODULE_NAME, wCmd); DEBUG(80, "%s: GET_VERSION=%ld\n", MODULE_NAME, IOCTL_ACE53_GET_VERSION); DEBUG(80, "%s: GET_CARD_INFO=%ld\n", MODULE_NAME, IOCTL_ACE53_GET_CARD_INFO); DEBUG(80, "%s: GET_CHANNEL_INFO=%ld\n", MODULE_NAME, IOCTL_ACE53_GET_CHANNEL_INFO); DEBUG(80, "%s: BLOCK_IN_DRIVER=%ld\n", MODULE_NAME, IOCTL_ACE53_BLOCK_IN_DRIVER); DEBUG(80, "%s: BC_AUTO_FLIPSTK=%ld\n", MODULE_NAME, IOCTL_ACE53_BC_AUTO_FLIPSTK); DEBUG(80, "%s: INSTALL_IRQ=%d\n", MODULE_NAME, IOCTL_ACE53_INSTALL_IRQ); DEBUG(80, "%s: UNINSTALL_IRQ=%d\n", MODULE_NAME, IOCTL_ACE53_UNINSTALL_IRQ); dumpStruct(); */ /* Process the command. */ switch(wCmd) { /* Get Driver Version */ case IOCTL_ACE53_GET_VERSION: DEBUG(10, "%s: fops_ioctl: GET_VERSION\n", MODULE_NAME); *(__u32 *)dwParam = ACE53_VERSION; break; /* BC Auto Flip Stack */ case IOCTL_ACE53_BC_AUTO_FLIPSTK: DEBUG(10, "%s: fops_ioctl: BC_AUTO_FLIPSTK\n", MODULE_NAME); m_aCards[bCardNum].Channel.bAutoFlipStk = *(__u32 *)dwParam; break; /* Get specific card's information */ case IOCTL_ACE53_GET_CARD_INFO: DEBUG(10, "%s: fops_ioctl: GET_CARD_INFO\n", MODULE_NAME); ((pACE53_CARD)dwParam)->plink = m_aCards[bCardNum].plink; ((pACE53_CARD)dwParam)->bPciBusNum = m_aCards[bCardNum].bPciBusNum; ((pACE53_CARD)dwParam)->bPciDevNum = m_aCards[bCardNum].bPciDevNum; ((pACE53_CARD)dwParam)->bPciFcnNum = m_aCards[bCardNum].bPciFcnNum; ((pACE53_CARD)dwParam)->bMajor = MAJOR(inode->i_rdev); ((pACE53_CARD)dwParam)->bMinor = MINOR(inode->i_rdev); ((pACE53_CARD)dwParam)->wDeviceID = m_aCards[bCardNum].wDeviceID; ((pACE53_CARD)dwParam)->dwCardID = m_aCards[bCardNum].dwCardID; ((pACE53_CARD)dwParam)->dwChanMemLen = m_aCards[bCardNum].dwChanMemLen; ((pACE53_CARD)dwParam)->wIrq = m_aCards[bCardNum].wIrq; ((pACE53_CARD)dwParam)->bNumChnls = m_aCards[bCardNum].bNumChnls; ((pACE53_CARD)dwParam)->dwMemWndPcmciaAddr = m_aCards[bCardNum].dwMemWndPcmciaAddr; ((pACE53_CARD)dwParam)->dwRegWndPcmciaAddr = m_aCards[bCardNum].dwRegWndPcmciaAddr; ((pACE53_CARD)dwParam)->dwRegWndKrnAddr = m_aCards[bCardNum].dwRegWndKrnAddr; ((pACE53_CARD)dwParam)->Channel = m_aCards[bCardNum].Channel; break; /* Get Specific channel's information */ case IOCTL_ACE53_GET_CHANNEL_INFO: DEBUG(10, "%s: fops_ioctl: GET_CHANNEL_INFO\n", MODULE_NAME); ((pACE_CHANNEL)dwParam)->bCardNum = m_aCards[bCardNum].Channel.bCardNum; ((pACE_CHANNEL)dwParam)->bChanNum = m_aCards[bCardNum].Channel.bChanNum; ((pACE_CHANNEL)dwParam)->dwMemWndUsrAddr = m_aCards[bCardNum].Channel.dwMemWndUsrAddr; ((pACE_CHANNEL)dwParam)->dwRegWndUsrAddr = m_aCards[bCardNum].Channel.dwRegWndUsrAddr; ((pACE_CHANNEL)dwParam)->wIrq = m_aCards[bCardNum].wIrq; ((pACE_CHANNEL)dwParam)->bBlocked = m_aCards[bCardNum].Channel.bBlocked; ((pACE_CHANNEL)dwParam)->bMmapWinNum = m_aCards[bCardNum].Channel.bMmapWinNum; ((pACE_CHANNEL)dwParam)->bIsrEnabled = m_aCards[bCardNum].Channel.bIsrEnabled; ((pACE_CHANNEL)dwParam)->bOpen = m_aCards[bCardNum].Channel.bOpen; break; /* Block Driver (Sleep Thread) */ case IOCTL_ACE53_BLOCK_IN_DRIVER: DEBUG(10, "%s: fops_ioctl: BLOCK_IN_DRIVER\n", MODULE_NAME); DEBUG(80, "%s: fops_ioctl: param1 0x%lX\n", MODULE_NAME, dwParam); save_flags(dwFlags); /* Save processor state */ cli(); /* Disable interrupts */ /* If interrupts are disabled.. */ if( !m_aCards[bCardNum].Channel.bIsrEnabled ) { restore_flags(dwFlags); /* Restore processor state */ sti(); /* Enable interrupts */ nResult = STATUS_ACE53_IOCTL_INTERRUPT_NOT_ENABLED; break; } /* Interrupts are enabled... */ restore_flags(dwFlags); /* Restore processor state */ sti(); /* flags and enable interrupts */ /* Put to sleep until interrupt or uninstall wakes us */ //interruptible_sleep_on(&m_apWaitQue[bCardNum]); DEBUG(80, "%s: fops_ioctl: BLOCK_IN_DRIVER: before wait\n", MODULE_NAME); DEBUG(80, "%s: fops_ioctl: param2 0x%lX\n", MODULE_NAME, dwParam); *(__u32 *)dwParam = 0; wait_event_interruptible(m_apWaitQue[bCardNum], m_apWaitFlag != 0); DEBUG(80, "%s: fops_ioctl: BLOCK_IN_DRIVER: after wait\n", MODULE_NAME); m_apWaitFlag = 0; /* Save Interrupt Status Register */ DEBUG(80, "%s: fops_ioctl: param3 0x%lX\n", MODULE_NAME, dwParam); dumpStruct(); *(__u32 *)dwParam = m_aCards[bCardNum].Channel.dwIntStatus; /* this was 16 bit cast for ACE. Is this a problem? kwh */ break; /* Install Interrupt support */ case IOCTL_ACE53_INSTALL_IRQ: DEBUG(10, "%s: fops_ioctl: INSTALL_IRQ\n", MODULE_NAME); save_flags(dwFlags); /* Save processor state */ cli(); /* Disable interrupts */ /* If already enabled, return error. */ if(m_aCards[bCardNum].Channel.bIsrEnabled ) { /* restore state and return error */ restore_flags(dwFlags); sti(); nResult = STATUS_ACE53_IOCTL_IRQ_ALREADY_INSTALLED; break; } /* Otherwise, flag status as enabled and install. */ m_aCards[bCardNum].Channel.bIsrEnabled = 1; restore_flags(dwFlags); sti(); /* Create the device string name for use in '/proc/interrupts' */ m_sDevName[9] = 'a' + bCardNum; m_sDevName[10] = '\0'; /* Determine which ISR to bind to the interrupt. */ if( m_aCards[bCardNum].dwCardID == DEVID_BU65553M2_300 ) pfIsr = pcmemace_isr; else if( m_aCards[bCardNum].dwCardID == DEVID_BU65550M2_300 || m_aCards[bCardNum].dwCardID == DEVID_BU65550M2_602 || m_aCards[bCardNum].dwCardID == DEVID_BU65550M2_605 || m_aCards[bCardNum].dwCardID == DEVID_BU65551M2_300 || m_aCards[bCardNum].dwCardID == DEVID_BU65552M2_300 ) pfIsr = pcmace_isr; else { nResult = STATUS_ACE53_DEVICE_NOT_EXIST; break; } /* Register the IRQ with the kernel. */ if( request_irq(m_aCards[bCardNum].wIrq, /* IRQ Number */ pfIsr, /* ISR Function */ IRQF_SHARED | IRQF_DISABLED,/* Slow ISR */ m_sDevName, /* string for 'proc' */ bpCardNum )) /* device indentifier*/ { /* if request fails.... */ save_flags(dwFlags); cli(); m_aCards[bCardNum].Channel.bIsrEnabled = 0; restore_flags(dwFlags); sti(); nResult = STATUS_ACE53_IOCTL_REQUEST_IRQ_FAIL; break; } break; case IOCTL_ACE53_UNINSTALL_IRQ: /* Cleanup an installed IRQ. */ DEBUG(10, "%s: fops_ioctl: UNINSTALL_IRQ\n", MODULE_NAME); /* If the interrupt is not enabled, return error. */ save_flags(dwFlags); cli(); if( !m_aCards[bCardNum].Channel.bIsrEnabled ) { restore_flags(dwFlags); sti(); nResult = STATUS_ACE53_IOCTL_IRQ_NOT_INSTALLED; break; } /* Flag card status as disabled. */ m_aCards[bCardNum].Channel.bIsrEnabled = 0; restore_flags(dwFlags); sti(); /* Deregister the interrupt and free the IRQ. */ free_irq(m_aCards[bCardNum].wIrq, bpCardNum); /* Wake up the blocked IRQ thread so it can terminate. */ wake_up_interruptible(&m_apWaitQue[bCardNum]); m_apWaitFlag = 1; break; default: DEBUG(10, "%s: entering fops_ioctl: unknown cmd %u\n", MODULE_NAME, wCmd); return STATUS_ACE53_IOCTL_NOT_IMPLEMENTED; break; } dumpStruct(); return nResult; } /******************************************************************* * Function: pcmace_fops_compat_ioctl * * * * Description: Handles all 32b ioctl calls to device driver * * * * Parameters: flip - Not Used * * wCmd - ioctl command requested * * dwParam - ioctl return data variable * *******************************************************************/ static long pcmace_fops_compat_ioctl(struct file *flip, unsigned int wCmd, unsigned long dwParam) { struct inode inode; int bCardNum; /* We manage only one card in compatibility mode */ if (m_bNumberOfCards > 1) return STATUS_ACE53_IOCTL_NOT_IMPLEMENTED; /* Find the card */ for (bCardNum = 0; bCardNum < ACE53_MAX_NUM_CARDS; bCardNum++) { if(m_aCards[bCardNum].Channel.bOpen != 0) { inode.i_rdev = MKDEV(m_aCards[bCardNum].bMajor, bCardNum); return pcmace_fops_ioctl(&inode, flip, wCmd, dwParam); } } return STATUS_ACE53_IOCTL_NOT_IMPLEMENTED; } /******************************************************************* * Function: pcmace_fops_release * * * * Description: Handles closing of a single channel (device) * * * * Parameters: inode - used to get the Minor Number * * flip - Not Used * *******************************************************************/ static int pcmace_fops_release(struct inode *inode, struct file *filp) { /* Obtain index into enumerated card list from inode. */ __u8 bCardNum = MINOR(inode->i_rdev); /* Enumerated device */ DEBUG(10, "%s: entering fops_release\n", MODULE_NAME); dumpStruct(); /* Disable the interrupt processing for this channel if not already done so. */ pcmace_fops_ioctl(inode, filp, IOCTL_ACE53_UNINSTALL_IRQ, 0); /* Check that minor number corresponds to a card installed in the system. */ if ( bCardNum >= m_bNumberOfCards ) return STATUS_ACE53_DEVICE_NOT_EXIST; /* Return error if an attempt was made to close an unopened card. */ if (m_aCards[bCardNum].Channel.bOpen == 0) return STATUS_ACE53_CARD_NOT_OPEN; /* Unmap the channels REGISTER memory from user space (if not already done) */ if( m_aCards[bCardNum].Channel.dwRegWndUsrAddr) { m_aCards[bCardNum].Channel.dwRegWndUsrAddr = (__u32)NULL; } /* Unmap the channels ACEMEM memory from user space (if not already done) */ if( m_aCards[bCardNum].Channel.dwMemWndUsrAddr) { m_aCards[bCardNum].Channel.dwMemWndUsrAddr = (__u32)NULL; } /* Define device as closed */ m_aCards[bCardNum].Channel.bOpen = 0; /* Unmap the channel REGISTER memory from kernel space (if not already done) */ if( m_aCards[bCardNum].dwRegWndKrnAddr ) { iounmap( (void*)m_aCards[bCardNum].dwRegWndKrnAddr ); /* GLS */ release_mem_region(m_aCards[bCardNum].dwRegWndPcmciaAddr, ACE53_CHAN_REG_LENGTH); m_aCards[bCardNum].dwRegWndKrnAddr = (__u32)NULL; } /* Unmap the channel DATA memory from kernel space (if not already done) */ if( m_aCards[bCardNum].dwMemWndKrnAddr ) { iounmap( (void*)m_aCards[bCardNum].dwMemWndKrnAddr ); /* GLS */ release_mem_region(m_aCards[bCardNum].dwMemWndPcmciaAddr, ACE53_CHAN_MEM_LENGTH); m_aCards[bCardNum].dwMemWndKrnAddr = (__u32)NULL; } /* Clear mmap window count. */ m_aCards[bCardNum].Channel.bMmapWinNum = 0; /* Flag interrupts as disabled. */ m_aCards[bCardNum].Channel.bIsrEnabled = 0; dumpStruct(); return STATUS_ACE53_SUCCESS; } /******************************************************************* * Function: pcmace_vmops_close * * * * Description: Used in junction with unmapping memory * * * * Parameters: vma - information about the vma * *******************************************************************/ static void pcmace_vmops_close(struct vm_area_struct *vma) { /* Obtain index into enumerated card list from inode. */ __u8 u8CardNumber =MINOR(vma->vm_file->f_dentry->d_inode->i_rdev); /* Card number in system (0 - 3) */ DEBUG(10, "%s: entering vmops_close (%d)\n", MODULE_NAME, m_aCards[u8CardNumber].Channel.bMmapWinNum); dumpStruct(); /* Indicate error if too many 'munmap's were attempted. */ if( (m_aCards[u8CardNumber].Channel.bMmapWinNum == 0) || (m_aCards[u8CardNumber].Channel.bMmapWinNum > 2) ) { printk("%s: pcmace_vmops_close(): Too many 'munmap' attempts!\n", MODULE_NAME); return; } /* Null user window pointer and decrement 'mmap' count. */ if( vma->vm_start == m_aCards[u8CardNumber].Channel.dwRegWndUsrAddr ) { m_aCards[u8CardNumber].Channel.dwRegWndUsrAddr = (__u32)NULL; m_aCards[u8CardNumber].Channel.bMmapWinNum--; } else if( vma->vm_start == m_aCards[u8CardNumber].Channel.dwMemWndUsrAddr ) { m_aCards[u8CardNumber].Channel.dwMemWndUsrAddr = (__u32)NULL; m_aCards[u8CardNumber].Channel.bMmapWinNum--; } else { printk("%s: pcmace_vmops_close(): 'munmap' failed! Bad base address.\n", MODULE_NAME); } dumpStruct(); } /* VM Operation overrides */ struct vm_operations_struct vm_ops = { close: pcmace_vmops_close, }; static void mmap_error_cleanup(__u32 dwPcmciaWinSize, __u8 bCardNum) { DEBUG(10, "%s: entering mmap_error_cleanup\n", MODULE_NAME); switch(dwPcmciaWinSize) { case ACE53_CHAN_REG_LENGTH: if( m_aCards[bCardNum].Channel.bMmapWinNum == 0 ) m_aCards[bCardNum].Channel.dwRegWndUsrAddr = (__u32)NULL; break; case ACE53_CHAN_MEM_LENGTH: if( m_aCards[bCardNum].Channel.bMmapWinNum == 1 ) m_aCards[bCardNum].Channel.dwMemWndUsrAddr = (__u32)NULL; break; } } static int pcmace_fops_mmap(struct file *filp, struct vm_area_struct *vma) { /* Base address and size of PCI space window to be remapped. */ __u32 dwPcmciaWinBaseAddr, dwPcmciaWinSize = vma->vm_end - vma->vm_start; /* Obtain index into enumerated card list from file pointer. CAN THIS BE DONE VIA 'vma' kwh */ __u8 u8CardNumber = MINOR(filp->f_dentry->d_inode->i_rdev); /* Card number in system (0 - 3) */ __u32 dwVMOffset; DEBUG(10, "%s: entering fops_mmap for card %d\n", MODULE_NAME, u8CardNumber); dumpStruct(); dwVMOffset = vma->vm_pgoff<vm_ops = &vm_ops; /* Check that minor number corresponds to a card in the system. */ if ( u8CardNumber >= m_bNumberOfCards) return STATUS_ACE53_DEVICE_NOT_EXIST; /* Return error if an attempt was made to 'mmap' an unopened card. */ if( !m_aCards[u8CardNumber].Channel.bOpen ) return STATUS_ACE53_CARD_NOT_OPEN; /* Check if 'mmap' is called more times than necessary. */ if(m_aCards[u8CardNumber].Channel.bMmapWinNum == ACE53_MAX_USER_MEM_WINDOWS) return STATUS_ACE53_MMAP_CARD_ALREADY_MMAPPED; DEBUG(80, "%s: fops_mmap: winSize %d (%d %d)\n", MODULE_NAME, dwPcmciaWinSize, ACE53_CHAN_REG_LENGTH, ACE53_CHAN_MEM_LENGTH); DEBUG(80, "%s: fops_mmap: start %lx\n", MODULE_NAME, vma->vm_start); DEBUG(80, "%s: fops_mmap: end %lx\n", MODULE_NAME, vma->vm_end); DEBUG(80, "%s: fops_mmap: offset %x\n", MODULE_NAME, dwVMOffset); DEBUG(80, "%s: fops_mmap: PAGE_SHIFT %x\n", MODULE_NAME, PAGE_SHIFT); DEBUG(80, "%s: fops_mmap: PAGE_SIZE %lx\n", MODULE_NAME, PAGE_SIZE); /* See which window to mmap. */ switch(dwPcmciaWinSize) { case ACE53_CHAN_REG_LENGTH: if( !(m_aCards[u8CardNumber].Channel.bMmapWinNum == 0) ) return STATUS_ACE53_MMAP_SEQUENCE_ERROR; dwPcmciaWinBaseAddr = m_aCards[u8CardNumber].dwRegWndPcmciaAddr; m_aCards[u8CardNumber].Channel.dwRegWndUsrAddr = vma->vm_start; break; case ACE53_CHAN_MEM_LENGTH: if( !(m_aCards[u8CardNumber].Channel.bMmapWinNum == 1) ) return STATUS_ACE53_MMAP_SEQUENCE_ERROR; dwPcmciaWinBaseAddr = (m_aCards[u8CardNumber].dwMemWndPcmciaAddr); m_aCards[u8CardNumber].Channel.dwMemWndUsrAddr = vma->vm_start; break; default: return STATUS_ACE53_MMAP_INVALID_WINDOW_SIZE; } DEBUG(80, "%s: fops_mmap: WndPcmciaWinAddr %x\n", MODULE_NAME, dwPcmciaWinBaseAddr); DEBUG(80, "%s: fops_mmap: WndPcmciaWinSize %x\n", MODULE_NAME, dwPcmciaWinSize); /* Size must be a multiple of PAGE_SIZE. */ if( dwPcmciaWinSize % PAGE_SIZE ) { mmap_error_cleanup(dwPcmciaWinSize, u8CardNumber); return STATUS_ACE53_MMAP_INVALID_PAGE_SIZE; } /* Physical window must be page aligned. */ if( dwVMOffset & (PAGE_SIZE - 1) ) { mmap_error_cleanup(dwPcmciaWinSize, u8CardNumber); return STATUS_ACE53_MMAP_BAD_ALIGNMENT; } DEBUG(80, "%s: fops_mmap: remap \n", MODULE_NAME); /* Remap the PCI window to user space. */ /* GLS */ request_mem_region(vma->vm_start, dwPcmciaWinSize, MODULE_NAME); //request_mem_region(dwPcmciaWinBaseAddr, dwPcmciaWinSize, MODULE_NAME); if( io_remap_pfn_range(vma, vma->vm_start, (dwPcmciaWinBaseAddr + dwVMOffset) >> PAGE_SHIFT, dwPcmciaWinSize, vma->vm_page_prot) ) { mmap_error_cleanup(dwPcmciaWinSize, u8CardNumber); return STATUS_ACE53_MMAP_REMAP_FAIL; } /* Increment 'mmap' count. */ m_aCards[u8CardNumber].Channel.bMmapWinNum++; /* Return success. */ dumpStruct(); return STATUS_ACE53_SUCCESS; } /* Jump table used to invoke driver functions */ struct file_operations m_foFileOps = { ioctl: pcmace_fops_ioctl, compat_ioctl: pcmace_fops_compat_ioctl, mmap: pcmace_fops_mmap, open: pcmace_fops_open, release: pcmace_fops_release }; /*----------------------------END OF CHAR DRIVER FUNCTIONS-----------------------------*/ /*-------------------------START OF CARD SERVICES FUNCTIONS----------------------------*/ /*====================================================================== pcmace_cs_attach() creates an "instance" of the driver, allocating local data structures for one device. The device is registered with Card Services. The dev_link structure is initialized, but we don't actually configure the card at this point -- we wait until we receive a card insertion event. ======================================================================*/ static int pcmace_cs_attach(struct pcmcia_device *link) { local_info_t *local; //conf_reg_t client_reg; //int ret; //cs_status_t status; //config_info_t conf; DEBUG(10, "%s: entering attach: %s %s\n", MODULE_NAME, dev_driver_string(&link->dev), link->dev.bus_id); PrintServinfo(link); /* Allocate space for private device-specific data */ local = kmalloc(sizeof(local_info_t), GFP_KERNEL); if (!local) return -ENOMEM; DEBUG(80, "%s: local 0x%016llx, size %lu\n", MODULE_NAME, (__u64)local, sizeof(local_info_t)); memset(local, 0, sizeof(local_info_t)); local->link = link; link->priv = local; /* General socket configuration defaults can go here. In this client, we assume very little, and rely on the CIS for almost everything. In most clients, many details (i.e., number, sizes, and attributes of IO windows) are fixed by the nature of the device, and can be hard-wired here. */ link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.Attributes |= CONF_ENABLE_DMA; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigBase = 0x200; /* Configure Card */ pcmace_cs_config(link); return 0; } /* pcmace_cs_attach */ /*====================================================================== This deletes a driver "instance". The device is de-registered with Card Services. If it has been released, all local data structures are freed. Otherwise, the structures will be freed when the device is released. ======================================================================*/ static void pcmace_cs_detach(struct pcmcia_device *link) { DEBUG(10, "%s: entering detach: %s %s\n", MODULE_NAME, dev_driver_string(&link->dev), link->dev.bus_id); /* Release */ pcmace_cs_release(link); /* This points to the parent local_info_t struct */ kfree(link->priv); } /* pcmace_cs_detach */ /*====================================================================== pcmace_cs_suspend() manage SUSPEND/RESET_PHYSICAL events ======================================================================*/ static int pcmace_cs_suspend(struct pcmcia_device *link) { local_info_t *local = (local_info_t *)link->priv; DEBUG(10, "%s: entering suspend: %s %s\n", MODULE_NAME, dev_driver_string(&link->dev), link->dev.bus_id); /* Mark the device as stopped, to block IO until later */ local->stop = 1; if (link->open) pcmcia_disable_device(link); return 0; } /* pcmace_cs_suspend */ /*====================================================================== pcmace_cs_resume() manage RESUME/CARD_RESET events ======================================================================*/ static int pcmace_cs_resume(struct pcmcia_device *link) { local_info_t *local = (local_info_t *)link->priv; config_req_t conf; DEBUG(10, "%s: entering resume: %s %s\n", MODULE_NAME, dev_driver_string(&link->dev), link->dev.bus_id); if (link->open) pcmcia_request_configuration(link, &conf); local->stop = 0; /* In a normal driver, additional code may go here to restore the device state and restart IO. */ return 0; } /* pcmace_cs_resume */ /******************************************************************* * Function: pcmace_cs_GetTuple * * * * Description: Gets a Tuple from the PCMCIA card (use appropriate * * part of the cisparse struct requested) * * * * Parameters: nDesriedTuple - Pass a valid tuple type as * * defined in cistpl.h eg. * * CISTPL_CONFIG * * * * pcisparse - Pass a cisparse struct to Contain * * the CIS data requested * * * * return 0 - Success; * * !0 - Failure; error codes are defined by Card * * Services functions * *******************************************************************/ static int pcmace_cs_GetTuple(int nDesiredTuple, cisparse_t *pcisparse) { struct pcmcia_device *handle; tuple_t tuple; u_char buf[TUPLE_BUFFER_SIZE]; int nStatus = 1; DEBUG(10, "%s: entering GetTuple\n", MODULE_NAME); if(m_aCards[m_bNumberOfCards].plink != NULL) { if(m_aCards[m_bNumberOfCards].plink != NULL) { handle = m_aCards[m_bNumberOfCards].plink; tuple.Attributes = 0; tuple.TupleData = buf; tuple.TupleDataMax = (cisdata_t)sizeof(buf); tuple.TupleOffset = 0; tuple.DesiredTuple = nDesiredTuple; nStatus = pcmcia_get_first_tuple(handle, &tuple); if(nStatus == CS_SUCCESS) { nStatus = pcmcia_get_tuple_data(handle, &tuple); if(nStatus == CS_SUCCESS) { nStatus = pcmcia_parse_tuple(handle, &tuple, pcisparse); } } } } return nStatus; } /******************************************************************* * Function: pcmace_cs_GetDeviceTupleInfo * * * * Description: Gets a Device tuple from the PCMCIA card and * * stores info in m_aCards[m_bNumberOfCards].CIS * * * * Parameters: handle - Pass a valid client handle * * * * return 0 - Success; * * !0 - Failure; error codes are defined by Card * * Services functions * *******************************************************************/ static int pcmace_cs_GetDeviceTupleInfo(struct pcmcia_device *handle) { cisparse_t cisparse; cistpl_device_t *pdevice = &(cisparse.device); int nStatus; DEBUG(10, "%s: entering GetDeviceTupleInfo: %s %s\n", MODULE_NAME, dev_driver_string(&handle->dev), handle->dev.bus_id); if((nStatus = pcmace_cs_GetTuple(CISTPL_DEVICE, &cisparse)) == 0) { m_aCards[m_bNumberOfCards].CIS.unAccessSpeed = pdevice->dev[0].speed; m_aCards[m_bNumberOfCards].CIS.unMemorySize = pdevice->dev[0].size; } return nStatus; } /******************************************************************* * Function: pcmace_cs_GetConfigTupleInfo * * * * Description: Gets a Config tuple from the PCMCIA card and stores* * info in m_aCards[m_bNumberOfCards].CIS * * * * Parameters: handle - Pass a valid client handle * * * * return 0 - Success; * * !0 - Failure; error codes are defined by Card * * Services functions * *******************************************************************/ static int pcmace_cs_GetConfigTupleInfo(struct pcmcia_device *handle) { cisparse_t cisparse; cistpl_config_t *pconfig = &(cisparse.config); int nStatus; DEBUG(10, "%s: entering GetConfigTupleInfo: %s %s\n", MODULE_NAME, dev_driver_string(&handle->dev), handle->dev.bus_id); if((nStatus = pcmace_cs_GetTuple(CISTPL_CONFIG, &cisparse)) == 0) { m_aCards[m_bNumberOfCards].CIS.unConfigBase = pconfig->base; m_aCards[m_bNumberOfCards].CIS.unPresent = pconfig->rmask[0]; m_aCards[m_bNumberOfCards].CIS.ucConfigIndex = pconfig->last_idx; } return nStatus; } /******************************************************************* * Function: pcmace_cs_GetCFTableTupleInfo * * * * Description: Gets a Cftable_entry tuple from the PCMCIA card * * and stores info in m_aCards[m_bNumberOfCards].CIS * * * * Parameters: handle - Pass a valid client handle * * * * return 0 - Success; * * !0 - Failure; error codes are defined by Card * * Services functions * *******************************************************************/ static int pcmace_cs_GetCFTableTupleInfo(struct pcmcia_device *handle) { cisparse_t cisparse; cistpl_cftable_entry_t *pentry = &(cisparse.cftable_entry); cistpl_io_t *pio = &(pentry->io); cistpl_irq_t *pirq = &(pentry->irq); cistpl_mem_t *pmem = &(pentry->mem); int nIndex; int nStatus; DEBUG(10, "%s: entering GetCFTableTupleInfo: %s %s\n", MODULE_NAME, dev_driver_string(&handle->dev), handle->dev.bus_id); if((nStatus = pcmace_cs_GetTuple(CISTPL_CFTABLE_ENTRY, &cisparse)) == 0) { m_aCards[m_bNumberOfCards].CIS.ucConfigIndex = pentry->index; m_aCards[m_bNumberOfCards].CIS.io.flags = pio->flags; m_aCards[m_bNumberOfCards].CIS.io.nwin = pio->nwin; printk("%s: CIS: IO port windows: %d", MODULE_NAME, pio->nwin); // Store multiple IO window info for(nIndex = 0; nIndex < m_aCards[m_bNumberOfCards].CIS.io.nwin; nIndex++) { printk(" Base: 0x%04x Len: 0x%04x", pio->win[nIndex].base, pio->win[nIndex].len); m_aCards[m_bNumberOfCards].CIS.io.win[nIndex].base = pio->win[nIndex].base; m_aCards[m_bNumberOfCards].CIS.io.win[nIndex].len = pio->win[nIndex].len; } m_aCards[m_bNumberOfCards].CIS.irq.IRQInfo1 = pirq->IRQInfo1; m_aCards[m_bNumberOfCards].CIS.irq.IRQInfo2 = pirq->IRQInfo2; printk(" Allowed IRQs: "); if((pirq->IRQInfo1 & IRQ_INFO2_VALID) != 0) { for(nIndex = 0; nIndex < 16; nIndex++) // Dislpay allowed IRQs { if((pirq->IRQInfo2 & (1 << nIndex)) != 0) printk("%x", nIndex); } } else printk("%x", pirq->IRQInfo1); // Display single allowed IRQ (hope its free :) m_aCards[m_bNumberOfCards].CIS.mem.nwin = pmem->nwin; printk(" mem windows: %d", m_aCards[m_bNumberOfCards].CIS.mem.nwin); for(nIndex = 0; nIndex < pmem->nwin; nIndex++) // Store multiple memory window info { m_aCards[m_bNumberOfCards].CIS.mem.win[nIndex].len = pmem->win[nIndex].len; m_aCards[m_bNumberOfCards].CIS.mem.win[nIndex].card_addr = pmem->win[nIndex].card_addr; printk(" 0x%04x-0x%04x", m_aCards[m_bNumberOfCards].CIS.mem.win[nIndex].card_addr, m_aCards[m_bNumberOfCards].CIS.mem.win[nIndex].card_addr + m_aCards[m_bNumberOfCards].CIS.mem.win[nIndex].len); } printk("\n"); } return nStatus; } /******************************************************************* * Function: pcmace_cs_GetManfidTupleInfo * * * * Description: Gets a manfid tuple from the PCMCIA card and * * stores info in m_aCards[m_bNumberOfCards].CIS * * * * Parameters: handle - Pass a valid client handle * * * * return 0 - Success; * * !0 - Failure; error codes are defined by Card * * Services functions * *******************************************************************/ static int pcmace_cs_GetManfidTupleInfo(struct pcmcia_device *handle) { cisparse_t cisparse; int nStatus; cistpl_manfid_t *pmanfid = &cisparse.manfid; DEBUG(10, "%s: entering GetManfidTupleInfo: %s %s\n", MODULE_NAME, dev_driver_string(&handle->dev), handle->dev.bus_id); if((nStatus = pcmace_cs_GetTuple(CISTPL_MANFID, &cisparse)) == 0) { m_aCards[m_bNumberOfCards].CIS.manfid.manf = pmanfid->manf; m_aCards[m_bNumberOfCards].CIS.manfid.card = pmanfid->card; m_aCards[m_bNumberOfCards].wDeviceID = m_aCards[m_bNumberOfCards].CIS.manfid.card; } return nStatus; } /******************************************************************* * Function: pcmace_cs_GetCisIO * * * * Description: Copies an IO tuple info from the PCMCIA card into * * in m_aCards[m_bNumberOfCards].CIS * * * * Parameters: pio - Pass an io struct containing CIS data * * aquired from cisparse.cftable_entry.io * * * * return 0 - Success; * * 1 - Failure; No io windows info was available * *******************************************************************/ static int pcmace_cs_GetCisIO(io_req_t *pio) { int nStatus; DEBUG(10, "%s: entering GetCisIO\n", MODULE_NAME); if(m_aCards[m_bNumberOfCards].CIS.io.nwin > 0) // Copy first io window info if available { pio->BasePort1 = m_aCards[m_bNumberOfCards].CIS.io.win[0].base; pio->NumPorts1 = m_aCards[m_bNumberOfCards].CIS.io.win[0].len; //Set IO to 8 bit if specified by CIS if(m_aCards[m_bNumberOfCards].CIS.io.flags & CISTPL_IO_8BIT) pio->Attributes1 = IO_DATA_PATH_WIDTH_8; //Set IO to 16 bit if specified by CIS else if(m_aCards[m_bNumberOfCards].CIS.io.flags & CISTPL_IO_16BIT) pio->Attributes1 = IO_DATA_PATH_WIDTH_16; else pio->Attributes1 = IO_DATA_PATH_WIDTH_AUTO; //Set IO to Auto if not specified pio->IOAddrLines = m_aCards[m_bNumberOfCards].CIS.io.flags & CISTPL_IO_LINES_MASK; if(m_aCards[m_bNumberOfCards].CIS.io.nwin > 1) // Copy second io window info if available { pio->BasePort2 = m_aCards[m_bNumberOfCards].CIS.io.win[1].base; pio->NumPorts2 = m_aCards[m_bNumberOfCards].CIS.io.win[1].len; pio->Attributes2 = pio->Attributes1; } // Ignore other io window info, Linux Card Services can't use it anyway :) nStatus = 0; } else nStatus = 1; return nStatus; } /******************************************************************* * Function: pcmace_cs_configIO * * * * Description: Configure device IO using device CIS. IO is only * * requested, the Card Services call, * * RequestConfiguration, does the actual config. * * * * Parameters: plink - Pass the device link; Call from the * * pcmace_cs_configIO(link) function * * passing link, same as plink (used p as * * pointer prefix). * * * * return: 0 - Success; Device IO was successfully requested* * !0 - Failure. Error codes are defined by Card * * Services functions * *******************************************************************/ static int pcmace_cs_configIO(struct pcmcia_device *plink) { int nStatus; DEBUG(10, "%s: entering configIO: %s %s\n", MODULE_NAME, dev_driver_string(&plink->dev), plink->dev.bus_id); plink->io.BasePort1 = 0; //io_req_t plink->io.NumPorts1 = 0; plink->io.Attributes1 = 0; plink->io.BasePort2 = 0; plink->io.NumPorts2 = 0; plink->io.Attributes2 = 0; plink->io.IOAddrLines = 0; if((nStatus = pcmace_cs_GetCisIO(&(plink->io))) == 0) nStatus = pcmcia_request_io(plink, &(plink->io)); return nStatus; } /******************************************************************* * Function: pcmace_cs_GetCisIRQ * * * * Description: Copies an IRQ tuple info from the PCMCIA card into * * in m_aCards[m_bNumberOfCards].CIS * * * * Parameters: pirqreq - Pass an irq struct containing CIS data; * * aquired from cisparse.cftable_entry.irq * * * * return: Void * *******************************************************************/ static void pcmace_cs_GetCisIRQ(irq_req_t *pirqreq) { DEBUG(10, "%s: entering GetCisIRQ\n", MODULE_NAME); pirqreq->IRQInfo1 = m_aCards[m_bNumberOfCards].CIS.irq.IRQInfo1; pirqreq->IRQInfo2 = m_aCards[m_bNumberOfCards].CIS.irq.IRQInfo2; } /******************************************************************* * Function: pcmace_cs_configIRQ * * * * Description: Configure device IRQ using device CIS. IRQ is ONLY * * requested. A Card Services call * * RequestConfiguration does the actual config * * * * Parameters: plink - Pass the device link; Call from the * * pcmace_cs_configIO(link) function * * passing link, same as plink (used p as * * pointer prefix). * * * * return: 0 - Success; * * 1 - Failure; no io windows info was available * *******************************************************************/ static int pcmace_cs_configIRQ(struct pcmcia_device *plink) { int nStatus = 0; irq_req_t pirqreq; DEBUG(10, "%s: entering configIRQ: %s %s\n", MODULE_NAME, dev_driver_string(&plink->dev), plink->dev.bus_id); pirqreq.Attributes = IRQ_FORCED_PULSE | IRQ_TYPE_TIME | IRQ_FIRST_SHARED; pirqreq.AssignedIRQ = 0; pirqreq.IRQInfo1 = 0; pirqreq.IRQInfo2 = 0; pirqreq.Handler = NULL; pirqreq.Instance = NULL; pcmace_cs_GetCisIRQ(&pirqreq); DEBUG(80, "%s: configIRQ: after GetCisIRQ\n", MODULE_NAME); nStatus = pcmcia_request_irq(plink, &pirqreq); DEBUG(80, "%s: configIRQ: after request_irq: status %d\n", MODULE_NAME, nStatus); if(nStatus == CS_SUCCESS) { m_CardIO[m_bNumberOfCards].cIRQRequest = __REQUESTED__; } else { printk("%s: CIS IRQ request failed, searching for a spare IRQ ", MODULE_NAME); pirqreq.IRQInfo1 = 1; do // Search for an IRQ if CIS IRQ failed { if((nStatus = pcmcia_request_irq(plink, &pirqreq)) != 0) { pirqreq.IRQInfo1++; } } while((nStatus != 0) && (pirqreq.IRQInfo1 >= 1) && (pirqreq.IRQInfo1 <= 15 )); } plink->irq.AssignedIRQ = pirqreq.AssignedIRQ; return(nStatus); } /******************************************************************* * Function: pcmace_cs_GetCisWindows * * * * Description: Copies an IRQ tuple info from * * m_aCards[m_bNumberOfCards].CIS into the window * * request struct * * * * Parameters: pnNumWindows - Pass an integer; the number of * * memory windows will be passed back * * * * return: 0 - Success; CIS windows info retrieved and * * number of windows returned * * !0 - Failure; Error codes are defined by Card * * Services * *******************************************************************/ static int pcmace_cs_GetCisWindows(int *pnNumWindows) { int nIndex; int nStatus; DEBUG(10, "%s: entering GetCisWindows\n", MODULE_NAME); if(m_aCards[m_bNumberOfCards].CIS.mem.nwin > 0) { // Copy each window info for(nIndex = 0; nIndex < m_aCards[m_bNumberOfCards].CIS.mem.nwin; nIndex++) { //Check for valid length if((m_aCards[m_bNumberOfCards].CIS.mem.win[nIndex].len % 0x1000) == 0) m_CardIO[m_bNumberOfCards].WinArr[nIndex].req.Size = m_aCards[m_bNumberOfCards].CIS.mem.win[nIndex].len; else // Extend window size to a multiple of 4K required by Card Services { m_CardIO[m_bNumberOfCards].WinArr[nIndex].req.Size = m_aCards[m_bNumberOfCards].CIS.mem.win[nIndex].len - (m_aCards[m_bNumberOfCards].CIS.mem.win[nIndex].len % 0x1000) + 0x1000; printk("%s: Fixing invalid CIS window[%d] size 0x%x => 0x%x\n", MODULE_NAME, nIndex, m_aCards[m_bNumberOfCards].CIS.mem.win[nIndex].len, m_CardIO[m_bNumberOfCards].WinArr[nIndex].req.Size); } m_CardIO[m_bNumberOfCards].WinArr[nIndex].map.CardOffset = m_aCards[m_bNumberOfCards].CIS.mem.win[nIndex].card_addr; m_CardIO[m_bNumberOfCards].WinArr[nIndex].req.AccessSpeed = m_aCards[m_bNumberOfCards].CIS.unAccessSpeed; } nStatus = 0; } else nStatus = 1; *pnNumWindows = m_aCards[m_bNumberOfCards].CIS.mem.nwin; return nStatus; } /******************************************************************* * Function: pcmace_cs_RequestWindows * * * * Description: Requests device memory windows as defined by * * device CIS. CIS info is retrieved from * * m_aCard[m_bNumberOfCards].CIS Windows are * * requested using m_CardIO[m_bNumberOfCards]; the * * physical memory pointers are stored here * * * * Parameters: pnNumWindows - Pass an integer; the number of * * memory windows will be passed back * * * * return: 0 - Success; Window addresses: * * * * 1 - Failure; A window memory map failed; driver * * will not function properly * * * * 2 - Failure; A window request failed; driver will * * not function properly * *******************************************************************/ static int pcmace_cs_RequestWindows(struct pcmcia_device *plink) { int n; int nStatus = 0; DEBUG(10, "%s: entering RequestWindows: %s %s\n", MODULE_NAME, dev_driver_string(&plink->dev), plink->dev.bus_id); for(n = 0; n < m_CardIO[m_bNumberOfCards].nNumWindows; n++) // Request each memory window { if((nStatus = pcmcia_request_window(&plink, &(m_CardIO[m_bNumberOfCards].WinArr[n].req), &(m_CardIO[m_bNumberOfCards].WinArr[n].winhandle))) == 0) { if(pcmcia_map_mem_page(m_CardIO[m_bNumberOfCards].WinArr[n].winhandle, &(m_CardIO[m_bNumberOfCards].WinArr[n].map)) == 0) { m_CardIO[m_bNumberOfCards].WinArr[n].ulWindowSize = m_CardIO[m_bNumberOfCards].WinArr[n].req.Size; m_CardIO[m_bNumberOfCards].WinArr[n].pnDirectPhysicalAddr = (void*)(m_CardIO[m_bNumberOfCards].WinArr[n].req.Base); m_CardIO[m_bNumberOfCards].WinArr[n].cArrWindowRequest = __REQUESTED__; } else { printk("%s: Window map failed\n", MODULE_NAME); nStatus = 1; } } else { printk("%s: RequestWindows failed WinArr[%d] Att: 0x%x Base: 0x%lx Size: 0x%x Speed: %d\n", MODULE_NAME, n, m_CardIO[m_bNumberOfCards].WinArr[n].req.Attributes, m_CardIO[m_bNumberOfCards].WinArr[n].req.Base, m_CardIO[m_bNumberOfCards].WinArr[n].req.Size, m_CardIO[m_bNumberOfCards].WinArr[n].req.AccessSpeed); nStatus = 2; } } return nStatus; } /******************************************************************* * Function: pcmace_cs_configWindows * * * * Description: Requests device memory windows as defined by * * device CIS. CIS info is retrieved from * * ACard[0].CIS Windows are requested using * * m_CardIO[m_bNumberOfCards]; the physical memory * * pointers are stored here. Windows are ONLY * * requested; A Card Services call * * RequestConfiguration does the actual config * * * * Parameters: None * * * * return: 0 - Success; Window addresses: * * * * 1 - Failure; A window memory map failed; driver * * will not function properly * * * * 2 - Failure; A window request failed; driver will * * not function properly * *******************************************************************/ static int pcmace_cs_configWindows(struct pcmcia_device *plink) { int nNumWindows; int nStatus; DEBUG(10, "%s: entering configWindows: %s %s\n", MODULE_NAME, dev_driver_string(&plink->dev), plink->dev.bus_id); if(pcmace_cs_GetCisWindows(&nNumWindows) == 0) { m_CardIO[m_bNumberOfCards].nNumWindows = nNumWindows; nStatus = pcmace_cs_RequestWindows(plink); } else nStatus = 1; return nStatus; } /******************************************************************* * Function: pcmace_cs_WriteConfigRegister * * * * Description: Writes a value to the specified config register; * * See Card Services documentation for details * * * * Parameters: handle - Pass a valid client handle; aquired from * * plink->handle * * * * unCISReg - Pass the CISReg offset for the register* * to be updated * * * * unValue - Pass the value to be written * * * * return: 0 - success; The value was successfully written * * to the specified register * * * * !0 - Failure; Error codes are as defined by Card * * Services * *******************************************************************/ /*static int pcmace_cs_WriteConfigRegister(struct pcmcia_device *handle, u_int unCISReg, u_int unValue) { conf_reg_t confreg; DEBUG(10, "%s: entering WriteConfigRegister: %s %s\n", MODULE_NAME, dev_driver_string(&handle->dev), handle->dev.bus_id); confreg.Function = 0; confreg.Action = CS_WRITE; confreg.Offset = unCISReg; confreg.Value = unValue; return pcmcia_access_configuration_register(handle, &confreg); }*/ /******************************************************************* * Function: pcmace_cs_GetConfigOptionRegister * * * * Description: Reads the device config option register * * The register contains the following info * * COR_CONFIG_MASK is used to get the index of the * * card's current operating mode * * COR_LELEVEL_IRQ specifies that the card should * * generate level mode interrupts (default) * * COR_SOFT_RESET Setting performs a 'soft reset'. * * Use Card Services call ResetCard instead * * See Card Services documentation for more * * information * * * * Parameters: handle - Pass a valid client handle; aquired * * from plink->handle * * * * punValue - Pass an unsigned int, the register * * value will be passed back * * * * return: 0 - Success; The value was successfully read * * !0 - Failure; Error codes are as defined by Card * * Services * *******************************************************************/ /*static int pcmace_cs_GetConfigOptionRegister(struct pcmcia_device *handle, u_int *punValue) { int nStatus; conf_reg_t confreg; DEBUG(10, "%s: entering GetConfigOptionRegister: %s %s\n", MODULE_NAME, dev_driver_string(&handle->dev), handle->dev.bus_id); confreg.Function = 0; // Ignored by this Card Services function call confreg.Action = CS_READ; confreg.Offset = CISREG_COR; // Specifiy ConfigOption register if((nStatus = pcmcia_access_configuration_register(handle, &confreg)) == 0) *punValue = confreg.Value; return nStatus; }*/ /******************************************************************* * Function: pcmace_cs_SetConfigOptionRegister * * * * Description: Puts the device in the operating mode specified * * by the device CIS Writes to the device config * * option register. The register contains the * * following info:- * * COR_CONFIG_MASK is used to set the index of the * * card's current operating mode * * COR_LELEVEL_IRQ specifies that the card should * * generate level mode interrupts (default) * * COR_SOFT_RESET Setting performs a 'soft reset'. * * Use Card Services call ResetCard instead * * See Card Services documentation for more * * information * * * * Parameters: handle - Pass a valid client handle; aquired from* * plink->handle * * * * return: 0 - Success; The value was successfully read * * !0 - Failure; Error codes are as defined by * * CardServices * *******************************************************************/ static int pcmace_cs_SetConfigOptionRegister(struct pcmcia_device *handle) { conf_reg_t confreg; DEBUG(10, "%s: entering SetConfigOptionRegister: %s %s\n", MODULE_NAME, dev_driver_string(&handle->dev), handle->dev.bus_id); confreg.Function = 0; // Ignored by the AccessConfigurationRegister CS function call confreg.Action = CS_WRITE; confreg.Offset = CISREG_COR; // Sepcify the ConfigOption register confreg.Value = m_aCards[m_bNumberOfCards].CIS.ucConfigIndex; //Write Card mode to register from device CIS return pcmcia_access_configuration_register(handle, &confreg); } /******************************************************************* * Function: pcmace_cs_GetTupleInfo * * * * Description: Gets the device CIS info to configure the card * * * * Parameters: handle - Pass a valid client handle * * * * return: 0 - Success; All CIS tuples were read successfully * * !0 - Failure; Error codes are as defined by * * CardServices * *******************************************************************/ static int pcmace_cs_GetTupleInfo(struct pcmcia_device *handle) { int nStatus = 0; DEBUG(10, "%s: entering GetTupleInfo: %s %s\n", MODULE_NAME, dev_driver_string(&handle->dev), handle->dev.bus_id); if(pcmace_cs_GetDeviceTupleInfo(handle) != 0) nStatus = 1; if(pcmace_cs_GetConfigTupleInfo(handle) != 0) nStatus = 2; if(pcmace_cs_GetCFTableTupleInfo(handle) != 0) nStatus = 3; if(pcmace_cs_GetManfidTupleInfo(handle) != 0) nStatus = 4; return nStatus; } /******************************************************************* * Function: pcmace_cs_DislpayKnownCards * * * * Description: Dislpays the list of cards known by this driver * * Call this function if an unknown card is found * * to notify of cards known by this driver * * * * Parameters: handle - Pass a valid client handle; aquired from* * plink->handle * * * * return: void * *******************************************************************/ static void pcmace_cs_DislpayKnownCards(void) { int nStringIndex = 0; while(m_cszArrKnownCards[nStringIndex][0] != 0) { printk("%s: Known Cards: %s\n", MODULE_NAME, m_cszArrKnownCards[nStringIndex]); nStringIndex++; } } /******************************************************************* * Function: pcmace_cs_ProcessVersion1Tuple * * * * Description: Checks whether the card is known by the driver * * The card deatails are stored as text format in * * the Version1 tuple. The Version1 tuple contains * * 4 strings, the second string is the card model * * The card model string is matched by a list of * * models * * * * Parameters: handle - Pass a valid client handle; aquired * * from plink->handle * * * * return: 0 - Success; The CIS was read and the model text * * matched * * !0 - Failure; Error codes are as defined by * * CardServices * *******************************************************************/ static int pcmace_cs_ProcessVersion1Tuple(struct pcmcia_device *handle) { cisparse_t cisparse; cistpl_vers_1_t *pversion_1 = &(cisparse.version_1); int nStringIndex; char* szString; char szMessage[1000]; // Used to display card details int nStatus; U32BIT adwCardID[ACE53_MAX_NUM_KNOWN_CARDS] = { DEVID_BU65550M2_300, DEVID_BU65550M2_602, DEVID_BU65551M2_300, DEVID_BU65552M2_300, DEVID_BU65553M2_300, DEVID_BU65550M2_605 }; m_aCards[m_bNumberOfCards].dwCardID = UNKNOWN_CARD; DEBUG(10, "%s: entering ProcessVersion1Tuple: %s %s\n", MODULE_NAME, dev_driver_string(&handle->dev), handle->dev.bus_id); if((nStatus = pcmace_cs_GetTuple(CISTPL_VERS_1, &cisparse)) == 0) { // Dislpay Card details szMessage[0] = 0; for(nStringIndex = 0; nStringIndex < pversion_1->ns; nStringIndex++) { szString = &(pversion_1->str[pversion_1->ofs[nStringIndex]]); strcat(szMessage, szString); strcat(szMessage, " "); } printk("%s: Card: %s\n", MODULE_NAME, szMessage); if(pversion_1->ns >= 2) // Check whether model is known { szString = &(pversion_1->str[pversion_1->ofs[1]]); nStringIndex = 0; while(m_cszArrKnownCards[nStringIndex][0] != 0) // Check against each known model { if(strcmp(m_cszArrKnownCards[nStringIndex], szString) == 0) { m_aCards[m_bNumberOfCards].dwCardID = adwCardID[nStringIndex]; } nStringIndex++; } } } // Display list of known cards if card is not known if(m_aCards[m_bNumberOfCards].dwCardID == UNKNOWN_CARD) pcmace_cs_DislpayKnownCards(); return nStatus; } /******************************************************************* * Function: pcmace_cs_ClearCardIOStruct * * * * Description: Makes sure no resources are requested. Some * * cards request IO, some don't etc. Make sure * * only needed resources are requested * * * * Parameters: plink - Pass a valid device pointer. It is * * aquired from the device event handler * * generally pcmace_cs_config() * * * * return: void * *******************************************************************/ static void pcmace_cs_ClearCardIOStruct(struct pcmcia_device *plink) { int nIndex; DEBUG(10, "%s: entering ClearCardIOStruct: %s %s\n", MODULE_NAME, dev_driver_string(&plink->dev), plink->dev.bus_id); m_aCards[m_bNumberOfCards].plink = plink; m_aCards[m_bNumberOfCards].CIS.unAccessSpeed = 0; m_aCards[m_bNumberOfCards].CIS.unMemorySize = 0; m_aCards[m_bNumberOfCards].dwCardID = -1; m_CardIO[m_bNumberOfCards].cIORequest = __NOTREQUESTED__; m_CardIO[m_bNumberOfCards].cIRQRequest = __NOTREQUESTED__; m_aCards[m_bNumberOfCards].CIS.ucConfigIndex = 0; m_aCards[m_bNumberOfCards].CIS.io.nwin = 0; m_aCards[m_bNumberOfCards].CIS.irq.IRQInfo1 = 0; m_aCards[m_bNumberOfCards].CIS.irq.IRQInfo2 = 0; m_aCards[m_bNumberOfCards].CIS.mem.nwin = 0; // Initialise memory window info for(nIndex = 0; nIndex < ACE53_MAX_NUM_WINDOWS; nIndex++) { m_CardIO[m_bNumberOfCards].WinArr[nIndex].req.Attributes = WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT; m_CardIO[m_bNumberOfCards].WinArr[nIndex].req.Base = 0; m_CardIO[m_bNumberOfCards].WinArr[nIndex].winhandle = (window_handle_t)plink; m_CardIO[m_bNumberOfCards].WinArr[nIndex].ulWindowSize = 0; m_CardIO[m_bNumberOfCards].WinArr[nIndex].pnDirectPhysicalAddr = NULL; m_CardIO[m_bNumberOfCards].WinArr[nIndex].pnDirectKernelAddr = NULL; m_CardIO[m_bNumberOfCards].WinArr[nIndex].cArrWindowRequest = __NOTREQUESTED__; } } /******************************************************************* * Function: pcmace_cs_InitKnownCardList * * * * Description: Initialises the list of card model strings with * * matching macro names * * * * * * Note: When adding new known card models to the list, make sure * * the value of MAX_NUM_KNOWN_CARDS is greater than the card * * name macros used. * * * * Parameters: void * * * * return: void * *******************************************************************/ static void pcmace_cs_InitKnownCardList(void) { int nIndex; DEBUG(10, "%s: entering InitKnownCardList\n", MODULE_NAME); for(nIndex = 0; nIndex < ACE53_MAX_NUM_KNOWN_CARDS; nIndex++) m_cszArrKnownCards[nIndex][0] = 0; strcpy(m_cszArrKnownCards[DEVID_STRINGNDX_BU65550M2_300], "BU-65550M2-300"); strcpy(m_cszArrKnownCards[DEVID_STRINGNDX_BU65550M2_602], "BU-65550M2-602"); strcpy(m_cszArrKnownCards[DEVID_STRINGNDX_BU65551M2_300], "BU-65551M2-300"); strcpy(m_cszArrKnownCards[DEVID_STRINGNDX_BU65552M2_300], "BU-65552M2-300"); strcpy(m_cszArrKnownCards[DEVID_STRINGNDX_BU65553M2_300], "BU-65553M2-300"); strcpy(m_cszArrKnownCards[DEVID_STRINGNDX_BU65550M2_605], "BU-65550M2-605"); } /******************************************************************* * Function: pcmace_cs_RequestConfiguration * * * * Description: The Card configuration occurs here. It configures * * resources requested. Use CardServices calls to * * request card resources before calling this * * function * * * * * * * * Parameters: plink - Pass a valid device pointer. * * * * return: 0 - Success; All resources requested were * * successfully configured * * !0 - Failure; Error codes are as defined by * * CardServices * *******************************************************************/ static int pcmace_cs_RequestConfiguration(struct pcmcia_device *plink) { int nStatus; DEBUG(10, "%s: entering RequestConfiguration: %s %s\n", MODULE_NAME, dev_driver_string(&plink->dev), plink->dev.bus_id); /* set card information */ m_aCards[m_bNumberOfCards].Channel.bOpen = 0; /* This actually configures the PCMCIA socket -- setting up the I/O windows and the interrupt mapping, and putting the card and host interface into "Memory and IO" mode. */ plink->conf.Attributes = CONF_ENABLE_IRQ | CONF_ENABLE_DMA; plink->conf.IntType = INT_MEMORY_AND_IO; plink->conf.ConfigBase = m_aCards[m_bNumberOfCards].CIS.unConfigBase; plink->conf.ConfigIndex = m_aCards[m_bNumberOfCards].CIS.ucConfigIndex; plink->conf.Present = m_aCards[m_bNumberOfCards].CIS.unPresent; if((nStatus = pcmcia_request_configuration(plink, &plink->conf)) != 0) { printk("%s: RequestConfiguration failed\n", MODULE_NAME); pcmace_cs_release(plink); }; return nStatus; } /******************************************************************* * Function: pcmace_cs_ValidateCIS * * * * Description: Returns whether the card CIS is valid. This is * * determined by Card Services. The driver exits * * without attempting to configure if the CIS is * * invalid * * * * * * * * Parameters: plink - Pass a valid device pointer. * * * * return: 0 - Success; The CIS is valid * * !0 - Failure; Error codes are as defined by * * CardServices * *******************************************************************/ static int pcmace_cs_ValidateCIS(struct pcmcia_device *plink) { cisinfo_t cisinfo; int nStatus; DEBUG(10, "%s: entering ValidateCIS: %s %s\n", MODULE_NAME, dev_driver_string(&plink->dev), plink->dev.bus_id); nStatus = pcmcia_validate_cis(plink, &cisinfo); if(nStatus == CS_SUCCESS) { m_aCards[m_bNumberOfCards].plink = plink; } else { printk("%s: ValidateCIS failed, cannot configure card, exiting", MODULE_NAME); pcmace_cs_release(plink); } return(nStatus); } /******************************************************************* * Function: pcmace_cs_StoreCardInfo * * * * Description: Stores resource configuration deatils in m_aCards.* * Card services request configuration must be * * called before this function is called. * * * * * * * * Parameters: plink - Pass a valid device pointer. * * * * return: void * *******************************************************************/ static void pcmace_cs_StoreCardInfo(struct pcmcia_device *plink) { DEBUG(10, "%s: entering StoreCardInfo: %s %s\n", MODULE_NAME, dev_driver_string(&plink->dev), plink->dev.bus_id); /* set card information */ m_aCards[m_bNumberOfCards].dwChanMemLen = m_aCards[m_bNumberOfCards].CIS.mem.win[1].len; m_aCards[m_bNumberOfCards].bPciBusNum = 0; m_aCards[m_bNumberOfCards].bPciDevNum = 0; m_aCards[m_bNumberOfCards].bPciFcnNum = 0; m_aCards[m_bNumberOfCards].wIrq = plink->irq.AssignedIRQ; m_aCards[m_bNumberOfCards].bNumChnls = 2; m_aCards[m_bNumberOfCards].Channel.bOpen = 0; /* Pcmcia Windows */ m_aCards[m_bNumberOfCards].dwMemWndPcmciaAddr = (U32)(m_CardIO[m_bNumberOfCards].WinArr[1].req.Base); m_aCards[m_bNumberOfCards].dwRegWndPcmciaAddr = (U32)(m_CardIO[m_bNumberOfCards].WinArr[0].req.Base); m_aCards[m_bNumberOfCards].dwRegWndKrnAddr = (U32)NULL; m_aCards[m_bNumberOfCards].dwMemWndKrnAddr = (U32)NULL; /* Channel 0 */ m_aCards[m_bNumberOfCards].Channel.dwMemWndUsrAddr = (U32)NULL; m_aCards[m_bNumberOfCards].Channel.dwRegWndUsrAddr = (U32)NULL; } /******************************************************************* * Function: pcmace_cs_DisplayCardInfo * * * * Description: Displays card info. This is called after the * * card is configured. prints resource info * * * * * * * * Parameters: plink - Pass a valid device pointer. * * * * return: void * *******************************************************************/ static void pcmace_cs_DisplayCardInfo(struct pcmcia_device *plink) { int nIndex; DEBUG(10, "%s: entering DisplayCardInfo: %s %s\n", MODULE_NAME, dev_driver_string(&plink->dev), plink->dev.bus_id); /* Finally, report what we've done */ printk(KERN_INFO "%s: index 0x%02x", plink->devname, plink->conf.ConfigIndex); if (plink->io.NumPorts1) { printk(", io 0x%04x-0x%04x", plink->io.BasePort1, plink->io.BasePort1 + plink->io.NumPorts1 - 1); } if (plink->io.NumPorts2) { printk(" & 0x%04x-0x%04x", plink->io.BasePort2, plink->io.BasePort2 + plink->io.NumPorts2 - 1); } if (plink->conf.Attributes & CONF_ENABLE_IRQ) { printk(", irq %d", plink->irq.AssignedIRQ); } printk("\n%s: Memory Windows:\n", MODULE_NAME); nIndex = 0; while(m_CardIO[m_bNumberOfCards].WinArr[nIndex].cArrWindowRequest == __REQUESTED__) { printk("%s: win[%d]: 0x%lx-0x%lx @ Card Offset: 0x%x\n", MODULE_NAME, nIndex, m_CardIO[m_bNumberOfCards].WinArr[nIndex].req.Base, m_CardIO[m_bNumberOfCards].WinArr[nIndex].req.Base + m_CardIO[m_bNumberOfCards].WinArr[nIndex].req.Size - 1, m_CardIO[m_bNumberOfCards].WinArr[nIndex].map.CardOffset); nIndex++; } if(m_CardIO[m_bNumberOfCards].nNumWindows == 0) { printk("%s: No windows provided by CIS\n", MODULE_NAME); } printk("%s: Module Loaded:\n (ENHANCED MINI) ACE: - Use '/usr/sbin/ddc_pcmace_load' to use this device\n", MODULE_NAME); if(m_aCards[m_bNumberOfCards].dwCardID == UNKNOWN_CARD) { printk("%s: Unknown card, unloading module\n", MODULE_NAME); pcmace_cs_release(plink); } } /******************************************************************* * Function: pcmace_cs_config * * * * Description: Configures the card for use * * The card will be rejected if any of the following * * occurs:- * * The card CIS cannot be read * * * * The card is not known; The card will be * * configured and configuration will be displayed. A * * list of known cards will be diplayed. The * * configuration will be released. * * * * The GetConfigurationInfo Card Services function * * call failed * * * * The RequestConfiguration Card Services function * * call failed * * * * * * * * Parameters: plink - Pass a valid device pointer. * * * * return: void * *******************************************************************/ static void pcmace_cs_config(struct pcmcia_device *plink) { config_info_t conf; DEBUG(10, "%s: entering config: %s %s\n", MODULE_NAME, dev_driver_string(&plink->dev), plink->dev.bus_id); dumpStruct(); if(pcmace_cs_ValidateCIS(plink) != 0) return; dumpStruct(); pcmace_cs_InitKnownCardList(); dumpStruct(); pcmace_cs_ClearCardIOStruct(plink); dumpStruct(); pcmace_cs_ProcessVersion1Tuple(plink); dumpStruct(); pcmace_cs_GetTupleInfo(plink); dumpStruct(); if (pcmcia_get_configuration_info(plink, &conf) != CS_SUCCESS) { printk("%s: Failed to get configuration info, exiting", MODULE_NAME); pcmace_cs_release(plink); return; } dumpStruct(); /* else plink->conf.Vcc = conf.Vcc; */ pcmace_cs_configIO(plink); dumpStruct(); pcmace_cs_configIRQ(plink); dumpStruct(); if(pcmace_cs_RequestConfiguration(plink) != 0) return; dumpStruct(); pcmace_cs_configWindows(plink); dumpStruct(); pcmace_cs_SetConfigOptionRegister(plink); dumpStruct(); /* Assume card 0 (Tested driver on one socket machine) */ //m_bNumberOfCards = 0; //jmf remove to allow multiple cards pcmace_cs_StoreCardInfo(plink); dumpStruct(); /* Finally, report what we've done */ pcmace_cs_DisplayCardInfo(plink); dumpStruct(); // Used by ioctl to check for correctly configured card (two channels) m_bNumberOfCards ++; DEBUG(10, "%s: Card Nb: %d\n", MODULE_NAME, m_bNumberOfCards); } /******************************************************************* * Function: pcmace_cs_FindLinkCardNumber * * * * Description: Finds the m_aCard structure for a link * * * * * * * * Parameters: plink - Pass a valid device pointer. * * * * return: status - int * *******************************************************************/ /*static int pcmace_cs_FindLinkCardNumber(struct pcmcia_device *plink, __u8 *pbNumberOfCards) { __u8 u8CardNumber; int nStatus = -1; for(u8CardNumber = 0; u8CardNumber < ACE53_MAX_NUM_CARDS; u8CardNumber++) { if(m_aCards[u8CardNumber].plink == plink) { *pbNumberOfCards = u8CardNumber; nStatus = 0; } } return nStatus; }*/ /******************************************************************* * Function: pcmace_cs_release * * * * Description: Releases the instance of the driver and any * * resources requested * * * * * * * * Parameters: arg - Pass a valid device pointer. * * * * return: none * *******************************************************************/ static void pcmace_cs_release(struct pcmcia_device *plink) { //__u8 u8CardNumber; //int nIndex; DEBUG(10, "%s: entering release: %s %s\n", MODULE_NAME, dev_driver_string(&plink->dev), plink->dev.bus_id); /* If the device is currently in use, we won't release until it is actually closed, because until then, we can't be sure that no one will try to access the device or its data structures. */ if (plink->open) { DEBUG(1, "%s: release postponed: %s still open\n", MODULE_NAME, dev_driver_string(&plink->dev)); return; } /* Unlink the device chain */ //plink->dev = NULL; //fixing release using u8CardNumber /* Don't bother checking to see if these succeed or not */ /* GLS: according to doc, pcmcia_release_window seems not anymore necessary * the job being done by pcmcia_disable_device */ /* if(pcmace_cs_FindLinkCardNumber(plink, &u8CardNumber) == 0) { for(nIndex = 0; nIndex < ACE53_MAX_NUM_WINDOWS; nIndex++) { if(m_CardIO[u8CardNumber].WinArr[nIndex].cArrWindowRequest == __REQUESTED__) { pcmcia_release_window(m_CardIO[u8CardNumber].WinArr[nIndex].winhandle); } } } else { printk("%s: pcmace_cs_release(): Failure: Could not find card link\n", MODULE_NAME); } */ pcmcia_disable_device(plink); pcmace_cs_detach(plink); m_bNumberOfCards--; } /******************************************************************* * Function: PrintServinfo * * * * Description: Displays the card services info * * * * * * Parameters: dev - Structure containing card services info * * * * return: void * *******************************************************************/ static void PrintServinfo(struct pcmcia_device *dev) { DEBUG(99, "%s info: Manufacturer Id: 0x%04X\n", MODULE_NAME, dev->manf_id); DEBUG(99, "%s info: Card Id: 0x%04X\n", MODULE_NAME, dev->card_id); DEBUG(99, "%s info: Function Id: 0x%02X\n", MODULE_NAME, dev->func_id); DEBUG(99, "%s info: Vendor String: %s\n", MODULE_NAME, dev->prod_id[0]); DEBUG(99, "%s info: Card Model: %s\n", MODULE_NAME, dev->prod_id[1]); DEBUG(99, "%s info: Card Type: %s\n", MODULE_NAME, dev->prod_id[2]); DEBUG(99, "%s info: Revision: %s\n", MODULE_NAME, dev->prod_id[3]); } /******************************************************************* * Function: dumpStruct * * * * Description: Displays the static structures * * * * * * Parameters: void * * * * return: void * *******************************************************************/ static void dumpStruct(void) { int i, j; ACE53_CARD *ptr; Card_IO_t *pt; return; for (i = 0; i < 1; i++) { ptr = &(m_aCards[i]); DEBUG(99, "%s: m_aCards[%d]:\n", MODULE_NAME, i); DEBUG(99, " plink: 0x%016llx\n", (__u64)ptr->plink); DEBUG(99, " bPciBusNum: %d\n", ptr->bPciBusNum); DEBUG(99, " bPciDevNum: %d\n", ptr->bPciDevNum); DEBUG(99, " bPciFcnNum: %d\n", ptr->bPciFcnNum); DEBUG(99, " bMajor: %d\n", ptr->bMajor); DEBUG(99, " bMinor: %d\n", ptr->bMinor); DEBUG(99, " wDeviceID: %d\n", ptr->wDeviceID); DEBUG(99, " dwCardID: %d\n", ptr->dwCardID); DEBUG(99, " dwChanMemLen: %d\n", ptr->dwChanMemLen); DEBUG(99, " wIrq: 0x%04x\n", ptr->wIrq); DEBUG(99, " bNumChnls: %d\n", ptr->bNumChnls); DEBUG(99, " dwMemWndPcmciaAddr: 0x%08x\n", ptr->dwMemWndPcmciaAddr); DEBUG(99, " dwRegWndPcmciaAddr: 0x%08x\n", ptr->dwRegWndPcmciaAddr); DEBUG(99, " dwRegWndKrnAddr: 0x%016llx\n", ptr->dwRegWndKrnAddr); DEBUG(99, " dwMemWndKrnAddr: 0x%016llx\n", ptr->dwMemWndKrnAddr); DEBUG(99, " Channel.bCardNum: %d\n", ptr->Channel.bCardNum); DEBUG(99, " Channel.bChanNum: %d\n", ptr->Channel.bChanNum); DEBUG(99, " Channel.bSocketNum: %d\n", ptr->Channel.bSocketNum); DEBUG(99, " Channel.dwMemWndUsrAddr:0x%08x\n", ptr->Channel.dwMemWndUsrAddr); DEBUG(99, " Channel.dwRegWndUsrAddr:0x%08x\n", ptr->Channel.dwRegWndUsrAddr); DEBUG(99, " Channel.dwIntStatus:0x%08x\n", ptr->Channel.dwIntStatus); DEBUG(99, " Channel.bBlocked: %d\n", ptr->Channel.bBlocked); DEBUG(99, " Channel.bMmapWinNum:%d\n", ptr->Channel.bMmapWinNum); DEBUG(99, " Channel.bIsrEnabled:%d\n", ptr->Channel.bIsrEnabled); DEBUG(99, " Channel.wIrq: %d\n", ptr->Channel.wIrq); DEBUG(99, " Channel.bOpen: %d\n", ptr->Channel.bOpen); DEBUG(99, " Channel.bAutoFlipStk:%d\n", ptr->Channel.bAutoFlipStk); DEBUG(99, " CIS.unMemorySize: %d\n", ptr->CIS.unMemorySize); DEBUG(99, " CIS.unAccessSpeed: %d\n", ptr->CIS.unAccessSpeed); DEBUG(99, " CIS.unConfigBase: %d\n", ptr->CIS.unConfigBase); DEBUG(99, " CIS.unPresent: %d\n", ptr->CIS.unPresent); DEBUG(99, " CIS.ucConfigIndex: %d\n", ptr->CIS.ucConfigIndex); } for (i = 0; i < 1; i++) { pt = &(m_CardIO[i]); DEBUG(99, "%s: m_CardIO[%d]:\n", MODULE_NAME, i); DEBUG(99, " cIORequest: %d\n", pt->cIORequest); DEBUG(99, " cIRQRequest: %d\n", pt->cIRQRequest); DEBUG(99, " nNumWindows: %d\n", pt->nNumWindows); for (j = 0; j < 2; j++) { DEBUG(99, " WinArr[%d]:\n", j); DEBUG(99, " cArrWindowRequest:%d\n", pt->WinArr[j].cArrWindowRequest); DEBUG(99, " pnDirectPhysicalAddr:0x%016llx\n", (__u64)pt->WinArr[j].pnDirectPhysicalAddr); DEBUG(99, " cArrWindowRequest:%d\n", pt->WinArr[j].cArrWindowRequest); DEBUG(99, " pnDirectKernelAddr:0x%016llx\n", (__u64)pt->WinArr[j].pnDirectKernelAddr); DEBUG(99, " req.Base: 0x%08lx\n", pt->WinArr[j].req.Base); DEBUG(99, " req.Size: %d\n", pt->WinArr[j].req.Size); DEBUG(99, " req.AccessSpeed: %d\n", pt->WinArr[j].req.AccessSpeed); DEBUG(99, " req.Attributes: %d\n", pt->WinArr[j].req.Attributes); DEBUG(99, " map.CardOffset: %d\n", pt->WinArr[j].map.CardOffset); DEBUG(99, " map.Page: %d\n", pt->WinArr[j].map.Page); } } } static struct pcmcia_device_id pcmace_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x014C, 0x0101), PCMCIA_DEVICE_PROD_ID1("ILC DATA DEVICE CORPORATION", 0x1ea29d68), PCMCIA_DEVICE_PROD_ID2("BU-65550M2-605", 0xee6d3698), PCMCIA_DEVICE_NULL, }; MODULE_DEVICE_TABLE(pcmcia, pcmace_ids); static struct pcmcia_driver pcmace_driver = { .probe = pcmace_cs_attach, .remove = pcmace_cs_detach, .suspend = pcmace_cs_suspend, .resume = pcmace_cs_resume, .owner = THIS_MODULE, .id_table = pcmace_ids, .drv = { .name = MODULE_NAME, }, }; /******************************************************************* * Function: init_pcmace_cs * * * * Description: Registers the card services and char driver * * functionality * * * * * * Parameters: void * * * * return: void * *******************************************************************/ static int __init init_pcmace(void) { // Init Card Services int nStatus; // Init Char driver int result = 0; DEBUG(10, "%s: loading version %s\n", MODULE_NAME, ACE53_VERSION_STRING); dumpStruct(); // Init Char driver ----------------------------------------------------- /* Check kernel to user datatype compatibility */ if(sizeof(char) != sizeof(__s8) || sizeof(short int) != sizeof(__s16) || sizeof(int) != sizeof(__s32) ) { printk("%s: Kernel to user datatype mismatch, ", MODULE_NAME); printk("driver not compatible with OS!\n "); return -1; } /* Register the driver and get MAJOR number from kernel */ /* '0' means kernel assigns MAJOR number */ result = register_chrdev(0, MODULE_NAME, &m_foFileOps); /* Check if we received a MAJOR number from the kernel */ if(result < 0) { printk("%s: register_chrdev failed!\n", MODULE_NAME); return result; } DEBUG(60, "%s: major %d\n", MODULE_NAME, result); dumpStruct(); /* If MAJOR number is unset, save for later use */ if (m_dwMajorNumber == 0) m_dwMajorNumber = result; // Init Card Services ---------------------------------------------- if((nStatus = pcmcia_register_driver(&pcmace_driver)) != 0) { printk("%s: Failed to register PC Card with Card Services; return: %d\n", MODULE_NAME, nStatus); return nStatus; } dumpStruct(); return 0; } /******************************************************************* * Function: __exit exit_pcmace * * * * Description: unregisters the card services and char driver * * functionality * * * * * * Parameters: void * * * * return: void * *******************************************************************/ static void __exit exit_pcmace(void) { DEBUG(10, "%s: unloading version %s\n", MODULE_NAME, ACE53_VERSION_STRING); // Card Services exit ----------------------------------------- pcmcia_unregister_driver(&pcmace_driver); // Char driver exit-------------------------------------------- unregister_chrdev(m_dwMajorNumber, MODULE_NAME); } module_init(init_pcmace); module_exit(exit_pcmace); MODULE_LICENSE("Dual BSD/GPL"); /*---------------------------END OF CARD SERVICES FUNCTIONS----------------------------*/