m32r_pcc.c
来自「linux 内核源代码」· C语言 代码 · 共 772 行 · 第 1/2 页
C
772 行
/* * drivers/pcmcia/m32r_pcc.c * * Device driver for the PCMCIA 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 <asm/addrspace.h>#include <pcmcia/cs_types.h>#include <pcmcia/ss.h>#include <pcmcia/cs.h>/* XXX: should be moved into asm/irq.h */#define PCC0_IRQ 24#define PCC1_IRQ 25#include "m32r_pcc.h"#define CHAOS_PCC_DEBUG#ifdef CHAOS_PCC_DEBUG static volatile u_short dummy_readbuf;#endif#define PCC_DEBUG_DBEX#ifdef DEBUGstatic int m32r_pcc_debug;module_param(m32r_pcc_debug, int, 0644);#define debug(lvl, fmt, arg...) do { \ if (m32r_pcc_debug > (lvl)) \ printk(KERN_DEBUG "m32r_pcc: " 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_irq, 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 CHAOS_PCC_DEBUG u_char last_iosize;#endif#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);void pcc_iorw(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int wr, int flag){ u_long addr; u_long flags; int need_ex;#ifdef PCC_DEBUG_DBEX int _dbex;#endif pcc_socket_t *t = &socket[sock];#ifdef CHAOS_PCC_DEBUG int map_changed = 0;#endif /* Need lock ? */ spin_lock_irqsave(&pcc_lock, flags); /* * Check if need dbex */ need_ex = (size > 1 && flag == 0) ? PCMOD_DBEX : 0;#ifdef PCC_DEBUG_DBEX _dbex = need_ex; need_ex = 0;#endif /* * calculate access address */ addr = t->mapaddr + port - t->ioaddr + KSEG1; /* XXX */ /* * Check current mapping */ if (t->current_space != as_io || t->last_iodbex != need_ex) { u_long cbsz; /* * Disable first */ pcc_set(sock, PCCR, 0); /* * Set mode and io address */ cbsz = (t->flags & MAP_16BIT) ? 0 : PCMOD_CBSZ; pcc_set(sock, PCMOD, PCMOD_AS_IO | cbsz | need_ex); pcc_set(sock, PCADR, addr & 0x1ff00000); /* * Enable and read it */ pcc_set(sock, PCCR, 1);#ifdef CHAOS_PCC_DEBUG#if 0 map_changed = (t->current_space == as_attr && size == 2); /* XXX */#else map_changed = 1;#endif#endif t->current_space = as_io; } /* * access to IO space */ if (size == 1) { /* Byte */ unsigned char *bp = (unsigned char *)buf;#ifdef CHAOS_DEBUG if (map_changed) { dummy_readbuf = readb(addr); }#endif if (wr) { /* write Byte */ while (nmemb--) { writeb(*bp++, addr); } } else { /* read Byte */ while (nmemb--) { *bp++ = readb(addr); } } } else { /* Word */ unsigned short *bp = (unsigned short *)buf;#ifdef CHAOS_PCC_DEBUG if (map_changed) { dummy_readbuf = readw(addr); }#endif if (wr) { /* write Word */ while (nmemb--) {#ifdef PCC_DEBUG_DBEX if (_dbex) { unsigned char *cp = (unsigned char *)bp; unsigned short tmp; tmp = cp[1] << 8 | cp[0]; writew(tmp, addr); bp++; } else#endif writew(*bp++, addr); } } else { /* read Word */ while (nmemb--) {#ifdef PCC_DEBUG_DBEX if (_dbex) { unsigned char *cp = (unsigned char *)bp; unsigned short tmp; tmp = readw(addr); cp[0] = tmp & 0xff; cp[1] = (tmp >> 8) & 0xff; bp++; } else#endif *bp++ = readw(addr); } } }#if 1 /* addr is no longer used */ if ((addr = pcc_get(sock, PCIRC)) & PCIRC_BWERR) { printk("m32r_pcc: BWERR detected : port 0x%04lx : iosize %dbit\n", port, size * 8); pcc_set(sock, PCIRC, addr); }#endif /* * save state */ t->last_iosize = size; t->last_iodbex = need_ex; /* Need lock ? */ spin_unlock_irqrestore(&pcc_lock,flags); return;}void pcc_ioread(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int flag) { pcc_iorw(sock, port, buf, size, nmemb, 0, flag);}void pcc_iowrite(int sock, unsigned long port, void *buf, size_t size, size_t nmemb, int flag) { pcc_iorw(sock, port, buf, size, nmemb, 1, flag);}/*====================================================================*/#define IS_REGISTERED 0x2000#define IS_ALIVE 0x8000typedef struct pcc_t { char *name; u_short flags;} pcc_t;static pcc_t pcc[] = { { "xnux2", 0 }, { "xnux2", 0 },};static irqreturn_t pcc_interrupt(int, void *);/*====================================================================*/static struct timer_list poll_timer;static unsigned int pcc_get(u_short sock, unsigned int reg){ return inl(socket[sock].base + reg);}static void pcc_set(u_short sock, unsigned int reg, unsigned int data){ outl(data, socket[sock].base + reg);}/*====================================================================== 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; unsigned int f; stat = pcc_get(sock, PCIRC); f = (stat & (PCIRC_CDIN1 | PCIRC_CDIN2)) >> 16; if(!f){ printk("m32r_pcc: No Card is detected at socket %d : stat = 0x%08x\n",stat,sock); return 0; } if(f!=3) printk("m32r_pcc: Insertion fail (%.8x) at socket %d\n",stat,sock); else printk("m32r_pcc: Card is Inserted at socket %d(%.8x)\n",sock,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]; /* add sockets */ t->ioaddr = ioaddr; t->mapaddr = mapaddr; t->base = base;#ifdef CHAOS_PCC_DEBUG t->flags = MAP_16BIT;#else t->flags = 0;#endif if (is_alive(pcc_sockets)) t->flags |= IS_ALIVE; /* add pcc */ if (t->base > 0) { request_region(t->base, 0x20, "m32r-pcc"); } 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; t->socket.pci_irq = 2 + pcc_sockets; /* XXX */ request_irq(irq, pcc_interrupt, 0, "m32r-pcc", pcc_interrupt); pcc_sockets++; return;}/*====================================================================*/static irqreturn_t pcc_interrupt(int irq, void *dev){ int i, j, irc; u_int events, active; int handled = 0; debug(4, "m32r: pcc_interrupt(%d)\n", irq); for (j = 0; j < 20; j++) { active = 0; for (i = 0; i < pcc_sockets; i++) { if ((socket[i].cs_irq != irq) && (socket[i].socket.pci_irq != irq)) continue; handled = 1; irc = pcc_get(i, PCIRC); irc >>=16; debug(2, "m32r-pcc:interrput: socket %d pcirc 0x%02x ", i, irc); if (!irc) continue; events = (irc) ? SS_DETECT : 0; events |= (pcc_get(i,PCCR) & PCCR_PCEN) ? SS_READY : 0; debug(2, " event 0x%02x\n", events); if (events) pcmcia_parse_events(&socket[i].socket, events); active |= events; active = 0; } if (!active) break; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?