m32r_cfc.c
来自「linux 内核源代码」· C语言 代码 · 共 811 行 · 第 1/2 页
C
811 行
/* * drivers/pcmcia/m32r_cfc.c * * Device driver for the CFC functionality of M32R. * * Copyright (c) 2001, 2002, 2003, 2004 * Hiroyuki Kondo, Naoto Sugai, Hayato Fujiwara */#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/init.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/string.h>#include <linux/kernel.h>#include <linux/errno.h>#include <linux/timer.h>#include <linux/slab.h>#include <linux/ioport.h>#include <linux/delay.h>#include <linux/workqueue.h>#include <linux/interrupt.h>#include <linux/platform_device.h>#include <linux/bitops.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/system.h>#include <pcmcia/cs_types.h>#include <pcmcia/ss.h>#include <pcmcia/cs.h>#undef MAX_IO_WIN /* FIXME */#define MAX_IO_WIN 1#undef MAX_WIN /* FIXME */#define MAX_WIN 1#include "m32r_cfc.h"#ifdef DEBUGstatic int m32r_cfc_debug;module_param(m32r_cfc_debug, int, 0644);#define debug(lvl, fmt, arg...) do { \ if (m32r_cfc_debug > (lvl)) \ printk(KERN_DEBUG "m32r_cfc: " fmt , ## arg); \} while (0)#else#define debug(n, args...) do { } while (0)#endif/* Poll status interval -- 0 means default to interrupt */static int poll_interval = 0;typedef enum pcc_space { as_none = 0, as_comm, as_attr, as_io } pcc_as_t;typedef struct pcc_socket { u_short type, flags; struct pcmcia_socket socket; unsigned int number; kio_addr_t ioaddr; u_long mapaddr; u_long base; /* PCC register base */ u_char cs_irq1, cs_irq2, intr; pccard_io_map io_map[MAX_IO_WIN]; pccard_mem_map mem_map[MAX_WIN]; u_char io_win; u_char mem_win; pcc_as_t current_space; u_char last_iodbex;#ifdef CONFIG_PROC_FS struct proc_dir_entry *proc;#endif} pcc_socket_t;static int pcc_sockets = 0;static pcc_socket_t socket[M32R_MAX_PCC] = { { 0, }, /* ... */};/*====================================================================*/static unsigned int pcc_get(u_short, unsigned int);static void pcc_set(u_short, unsigned int , unsigned int );static DEFINE_SPINLOCK(pcc_lock);#if !defined(CONFIG_PLAT_USRV)static inline u_long pcc_port2addr(unsigned long port, int size) { u_long addr = 0; u_long odd; if (size == 1) { /* byte access */ odd = (port&1) << 11; port -= port & 1; addr = CFC_IO_MAPBASE_BYTE - CFC_IOPORT_BASE + odd + port; } else if (size == 2) addr = CFC_IO_MAPBASE_WORD - CFC_IOPORT_BASE + port; return addr;}#else /* CONFIG_PLAT_USRV */static inline u_long pcc_port2addr(unsigned long port, int size) { u_long odd; u_long addr = ((port - CFC_IOPORT_BASE) & 0xf000) << 8; if (size == 1) { /* byte access */ odd = port & 1; port -= odd; odd <<= 11; addr = (addr | CFC_IO_MAPBASE_BYTE) + odd + (port & 0xfff); } else if (size == 2) /* word access */ addr = (addr | CFC_IO_MAPBASE_WORD) + (port & 0xfff); return addr;}#endif /* CONFIG_PLAT_USRV */void pcc_ioread_byte(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int flag){ u_long addr; unsigned char *bp = (unsigned char *)buf; unsigned long flags; debug(3, "m32r_cfc: pcc_ioread_byte: sock=%d, port=%#lx, buf=%p, " "size=%u, nmemb=%d, flag=%d\n", sock, port, buf, size, nmemb, flag); addr = pcc_port2addr(port, 1); if (!addr) { printk("m32r_cfc:ioread_byte null port :%#lx\n",port); return; } debug(3, "m32r_cfc: pcc_ioread_byte: addr=%#lx\n", addr); spin_lock_irqsave(&pcc_lock, flags); /* read Byte */ while (nmemb--) *bp++ = readb(addr); spin_unlock_irqrestore(&pcc_lock, flags);}void pcc_ioread_word(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int flag){ u_long addr; unsigned short *bp = (unsigned short *)buf; unsigned long flags; debug(3, "m32r_cfc: pcc_ioread_word: sock=%d, port=%#lx, " "buf=%p, size=%u, nmemb=%d, flag=%d\n", sock, port, buf, size, nmemb, flag); if (size != 2) printk("m32r_cfc: ioread_word :illigal size %u : %#lx\n", size, port); if (size == 9) printk("m32r_cfc: ioread_word :insw \n"); addr = pcc_port2addr(port, 2); if (!addr) { printk("m32r_cfc:ioread_word null port :%#lx\n",port); return; } debug(3, "m32r_cfc: pcc_ioread_word: addr=%#lx\n", addr); spin_lock_irqsave(&pcc_lock, flags); /* read Word */ while (nmemb--) *bp++ = readw(addr); spin_unlock_irqrestore(&pcc_lock, flags);}void pcc_iowrite_byte(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int flag){ u_long addr; unsigned char *bp = (unsigned char *)buf; unsigned long flags; debug(3, "m32r_cfc: pcc_iowrite_byte: sock=%d, port=%#lx, " "buf=%p, size=%u, nmemb=%d, flag=%d\n", sock, port, buf, size, nmemb, flag); /* write Byte */ addr = pcc_port2addr(port, 1); if (!addr) { printk("m32r_cfc:iowrite_byte null port:%#lx\n",port); return; } debug(3, "m32r_cfc: pcc_iowrite_byte: addr=%#lx\n", addr); spin_lock_irqsave(&pcc_lock, flags); while (nmemb--) writeb(*bp++, addr); spin_unlock_irqrestore(&pcc_lock, flags);}void pcc_iowrite_word(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int flag){ u_long addr; unsigned short *bp = (unsigned short *)buf; unsigned long flags; debug(3, "m32r_cfc: pcc_iowrite_word: sock=%d, port=%#lx, " "buf=%p, size=%u, nmemb=%d, flag=%d\n", sock, port, buf, size, nmemb, flag); if(size != 2) printk("m32r_cfc: iowrite_word :illigal size %u : %#lx\n", size, port); if(size == 9) printk("m32r_cfc: iowrite_word :outsw \n"); addr = pcc_port2addr(port, 2); if (!addr) { printk("m32r_cfc:iowrite_word null addr :%#lx\n",port); return; }#if 1 if (addr & 1) { printk("m32r_cfc:iowrite_word port addr (%#lx):%#lx\n", port, addr); return; }#endif debug(3, "m32r_cfc: pcc_iowrite_word: addr=%#lx\n", addr); spin_lock_irqsave(&pcc_lock, flags); while (nmemb--) writew(*bp++, addr); spin_unlock_irqrestore(&pcc_lock, flags);}/*====================================================================*/#define IS_REGISTERED 0x2000#define IS_ALIVE 0x8000typedef struct pcc_t { char *name; u_short flags;} pcc_t;static pcc_t pcc[] = {#if !defined(CONFIG_PLAT_USRV) { "m32r_cfc", 0 }, { "", 0 },#else /* CONFIG_PLAT_USRV */ { "m32r_cfc", 0 }, { "m32r_cfc", 0 }, { "m32r_cfc", 0 }, { "m32r_cfc", 0 }, { "m32r_cfc", 0 }, { "", 0 },#endif /* CONFIG_PLAT_USRV */};static irqreturn_t pcc_interrupt(int, void *);/*====================================================================*/static struct timer_list poll_timer;static unsigned int pcc_get(u_short sock, unsigned int reg){ unsigned int val = inw(reg); debug(3, "m32r_cfc: pcc_get: reg(0x%08x)=0x%04x\n", reg, val); return val;}static void pcc_set(u_short sock, unsigned int reg, unsigned int data){ outw(data, reg); debug(3, "m32r_cfc: pcc_set: reg(0x%08x)=0x%04x\n", reg, data);}/*====================================================================== See if a card is present, powered up, in IO mode, and already bound to a (non PC Card) Linux driver. We leave these alone. We make an exception for cards that seem to be serial devices.======================================================================*/static int __init is_alive(u_short sock){ unsigned int stat; debug(3, "m32r_cfc: is_alive:\n"); printk("CF: "); stat = pcc_get(sock, (unsigned int)PLD_CFSTS); if (!stat) printk("No "); printk("Card is detected at socket %d : stat = 0x%08x\n", sock, stat); debug(3, "m32r_cfc: is_alive: sock stat is 0x%04x\n", stat); return 0;}static void add_pcc_socket(ulong base, int irq, ulong mapaddr, kio_addr_t ioaddr){ pcc_socket_t *t = &socket[pcc_sockets]; debug(3, "m32r_cfc: add_pcc_socket: base=%#lx, irq=%d, " "mapaddr=%#lx, ioaddr=%08x\n", base, irq, mapaddr, ioaddr); /* add sockets */ t->ioaddr = ioaddr; t->mapaddr = mapaddr;#if !defined(CONFIG_PLAT_USRV) t->base = 0; t->flags = 0; t->cs_irq1 = irq; // insert irq t->cs_irq2 = irq + 1; // eject irq#else /* CONFIG_PLAT_USRV */ t->base = base; t->flags = 0; t->cs_irq1 = 0; // insert irq t->cs_irq2 = 0; // eject irq#endif /* CONFIG_PLAT_USRV */ if (is_alive(pcc_sockets)) t->flags |= IS_ALIVE; /* add pcc */#if !defined(CONFIG_PLAT_USRV) request_region((unsigned int)PLD_CFRSTCR, 0x20, "m32r_cfc");#else /* CONFIG_PLAT_USRV */ { unsigned int reg_base; reg_base = (unsigned int)PLD_CFRSTCR; reg_base |= pcc_sockets << 8; request_region(reg_base, 0x20, "m32r_cfc"); }#endif /* CONFIG_PLAT_USRV */ printk(KERN_INFO " %s ", pcc[pcc_sockets].name); printk("pcc at 0x%08lx\n", t->base); /* Update socket interrupt information, capabilities */ t->socket.features |= (SS_CAP_PCCARD | SS_CAP_STATIC_MAP); t->socket.map_size = M32R_PCC_MAPSIZE; t->socket.io_offset = ioaddr; /* use for io access offset */ t->socket.irq_mask = 0;#if !defined(CONFIG_PLAT_USRV) t->socket.pci_irq = PLD_IRQ_CFIREQ ; /* card interrupt */#else /* CONFIG_PLAT_USRV */ t->socket.pci_irq = PLD_IRQ_CF0 + pcc_sockets;#endif /* CONFIG_PLAT_USRV */#ifndef CONFIG_PLAT_USRV /* insert interrupt */ request_irq(irq, pcc_interrupt, 0, "m32r_cfc", pcc_interrupt);#ifndef CONFIG_PLAT_MAPPI3 /* eject interrupt */ request_irq(irq+1, pcc_interrupt, 0, "m32r_cfc", pcc_interrupt);#endif debug(3, "m32r_cfc: enable CFMSK, RDYSEL\n"); pcc_set(pcc_sockets, (unsigned int)PLD_CFIMASK, 0x01);#endif /* CONFIG_PLAT_USRV */#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_USRV) || defined(CONFIG_PLAT_OPSPUT) pcc_set(pcc_sockets, (unsigned int)PLD_CFCR1, 0x0200);#endif pcc_sockets++; return;}/*====================================================================*/static irqreturn_t pcc_interrupt(int irq, void *dev){ int i; u_int events = 0; int handled = 0; debug(3, "m32r_cfc: pcc_interrupt: irq=%d, dev=%p\n", irq, dev); for (i = 0; i < pcc_sockets; i++) { if (socket[i].cs_irq1 != irq && socket[i].cs_irq2 != irq) continue; handled = 1; debug(3, "m32r_cfc: pcc_interrupt: socket %d irq 0x%02x ", i, irq); events |= SS_DETECT; /* insert or eject */ if (events) pcmcia_parse_events(&socket[i].socket, events); } debug(3, "m32r_cfc: pcc_interrupt: done\n"); return IRQ_RETVAL(handled);} /* pcc_interrupt */static void pcc_interrupt_wrapper(u_long data){ debug(3, "m32r_cfc: pcc_interrupt_wrapper:\n"); pcc_interrupt(0, NULL); init_timer(&poll_timer); poll_timer.expires = jiffies + poll_interval; add_timer(&poll_timer);}/*====================================================================*/
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?