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 + -
显示快捷键?