au1000_generic.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 697 行 · 第 1/2 页

C
697
字号
/* * * Alchemy Semi Au1000 pcmcia driver * * Copyright 2001 MontaVista Software Inc. * Author: MontaVista Software, Inc. *         	ppopov@mvista.com or source@mvista.com * * ######################################################################## * *  This program is free software; you can distribute it and/or modify it *  under the terms of the GNU General Public License (Version 2) as *  published by the Free Software Foundation. * *  This program is distributed in the hope it will be useful, but WITHOUT *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License *  for more details. * *  You should have received a copy of the GNU General Public License along *  with this program; if not, write to the Free Software Foundation, Inc., *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA. * * ######################################################################## * *  */#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/init.h>#include <linux/config.h>#include <linux/delay.h>#include <linux/ioport.h>#include <linux/kernel.h>#include <linux/tqueue.h>#include <linux/timer.h>#include <linux/mm.h>#include <linux/proc_fs.h>#include <linux/types.h>#include <linux/vmalloc.h>#include <pcmcia/version.h>#include <pcmcia/cs_types.h>#include <pcmcia/cs.h>#include <pcmcia/ss.h>#include <pcmcia/bulkmem.h>#include <pcmcia/cistpl.h>#include <pcmcia/bus_ops.h>#include "cs_internal.h"#include <asm/io.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/au1000.h>#include <asm/au1000_pcmcia.h>#ifdef DEBUGstatic int pc_debug;module_param(pc_debug, int, 0644);#define debug(lvl,fmt) do {			\	if (pc_debug > (lvl))			\		printk(KERN_DEBUG fmt);		\} while (0)#else#define debug(lvl,fmt) do { } while (0)#endifMODULE_LICENSE("GPL");MODULE_AUTHOR("Pete Popov, MontaVista Software <ppopov@mvista.com>");MODULE_DESCRIPTION("Linux PCMCIA Card Services: Au1x00 Socket Controller");#define MAP_SIZE 0x1000000/* This structure maintains housekeeping state for each socket, such * as the last known values of the card detect pins, or the Card Services * callback value associated with the socket: */static struct au1000_pcmcia_socket *pcmcia_socket;static int socket_count;/* Returned by the low-level PCMCIA interface: */static struct pcmcia_low_level *pcmcia_low_level;/* Event poll timer structure */static struct timer_list poll_timer;/* Prototypes for routines which are used internally: */static int  au1000_pcmcia_driver_init(void);static void au1000_pcmcia_driver_shutdown(void);static void au1000_pcmcia_task_handler(void *data);static void au1000_pcmcia_poll_event(unsigned long data);static void au1000_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs);static struct tq_struct au1000_pcmcia_task;#ifdef CONFIG_PROC_FSstatic int au1000_pcmcia_proc_status(char *buf, char **start, 		off_t pos, int count, int *eof, void *data);#endif/* Prototypes for operations which are exported to the * new-and-impr^H^H^H^H^H^H^H^H^H^H in-kernel PCMCIA core: */static int au1000_pcmcia_init(u32 sock);static int au1000_pcmcia_suspend(u32 sock);static int au1000_pcmcia_register_callback(u32 sock, 		void (*handler)(void *, u32), void *info);static int au1000_pcmcia_inquire_socket(u32 sock, socket_cap_t *cap);static int au1000_pcmcia_get_status(u32 sock, u_int *value);static int au1000_pcmcia_get_socket(u32 sock, socket_state_t *state);static int au1000_pcmcia_set_socket(u32 sock, socket_state_t *state);static int au1000_pcmcia_get_io_map(u32 sock, struct pccard_io_map *io);static int au1000_pcmcia_set_io_map(u32 sock, struct pccard_io_map *io);static int au1000_pcmcia_get_mem_map(u32 sock, struct pccard_mem_map *mem);static int au1000_pcmcia_set_mem_map(u32 sock, struct pccard_mem_map *mem);#ifdef CONFIG_PROC_FSstatic void au1000_pcmcia_proc_setup(u32 sock, struct proc_dir_entry *base);#endifstatic struct pccard_operations au1000_pcmcia_operations = {	au1000_pcmcia_init,	au1000_pcmcia_suspend,	au1000_pcmcia_register_callback,	au1000_pcmcia_inquire_socket,	au1000_pcmcia_get_status,	au1000_pcmcia_get_socket,	au1000_pcmcia_set_socket,	au1000_pcmcia_get_io_map,	au1000_pcmcia_set_io_map,	au1000_pcmcia_get_mem_map,	au1000_pcmcia_set_mem_map,#ifdef CONFIG_PROC_FS	au1000_pcmcia_proc_setup#endif};static spinlock_t pcmcia_lock = SPIN_LOCK_UNLOCKED;static int __init au1000_pcmcia_driver_init(void){	struct pcmcia_init pcmcia_init;	struct pcmcia_state state;	unsigned int i;	printk("\nAu1x00 PCMCIA\n");#ifndef CONFIG_64BIT_PHYS_ADDR	printk(KERN_ERR "Au1x00 PCMCIA 36 bit IO support not enabled\n");	return -1;#endif#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_PB1500)	pcmcia_low_level=&pb1x00_pcmcia_ops;#else#error Unsupported AU1000 board.#endif	pcmcia_init.handler=au1000_pcmcia_interrupt;	if((socket_count=pcmcia_low_level->init(&pcmcia_init))<0) {		printk(KERN_ERR "Unable to initialize PCMCIA service.\n");		return -EIO;	}	/* NOTE: the chip select must already be setup */	pcmcia_socket = 		kmalloc(sizeof(struct au1000_pcmcia_socket) * socket_count, 				GFP_KERNEL);	if (!pcmcia_socket) {		printk(KERN_ERR "Card Services can't get memory \n");		return -1;	}	memset(pcmcia_socket, 0,			sizeof(struct au1000_pcmcia_socket) * socket_count);				/* 	 * Assuming max of 2 sockets, which the Au1000 supports.	 * WARNING: the Pb1000 has two sockets, and both work, but you	 * can't use them both at the same time due to glue logic conflicts.	 */	for(i=0; i < socket_count; i++) {		if(pcmcia_low_level->socket_state(i, &state)<0){			printk(KERN_ERR "Unable to get PCMCIA status\n");			return -EIO;		}		pcmcia_socket[i].k_state=state;		pcmcia_socket[i].cs_state.csc_mask=SS_DETECT;				if (i == 0) {			pcmcia_socket[i].virt_io = 				(u32)ioremap((ioaddr_t)0xF00000000, 0x1000);			pcmcia_socket[i].phys_attr = (memaddr_t)0xF40000000;			pcmcia_socket[i].phys_mem = (memaddr_t)0xF80000000;		}		else  {			pcmcia_socket[i].virt_io = 				(u32)ioremap((ioaddr_t)0xF08000000, 0x1000);			pcmcia_socket[i].phys_attr = (memaddr_t)0xF48000000;			pcmcia_socket[i].phys_mem = (memaddr_t)0xF88000000;		}	}	/* Only advertise as many sockets as we can detect: */	if(register_ss_entry(socket_count, &au1000_pcmcia_operations)<0){		printk(KERN_ERR "Unable to register socket service routine\n");		return -ENXIO;	}	/* Start the event poll timer.  	 * It will reschedule by itself afterwards. 	 */	au1000_pcmcia_poll_event(0);	debug(1, "au1000: initialization complete\n");	return 0;}  /* au1000_pcmcia_driver_init() */module_init(au1000_pcmcia_driver_init);static void __exit au1000_pcmcia_driver_shutdown(void){	int i;	del_timer_sync(&poll_timer);	unregister_ss_entry(&au1000_pcmcia_operations);	pcmcia_low_level->shutdown();	flush_scheduled_tasks();	for(i=0; i < socket_count; i++) {		if (pcmcia_socket[i].virt_io) 			iounmap((void *)pcmcia_socket[i].virt_io);	}	debug(1, "au1000: shutdown complete\n");}module_exit(au1000_pcmcia_driver_shutdown);static int au1000_pcmcia_init(unsigned int sock) { return 0; }static int au1000_pcmcia_suspend(unsigned int sock){	return 0;}static inline unsigned au1000_pcmcia_events(struct pcmcia_state *state, 		struct pcmcia_state *prev_state, 		unsigned int mask, unsigned int flags){	unsigned int events=0;	if(state->detect!=prev_state->detect){		debug(2, "%s(): card detect value %u\n", 				__FUNCTION__, state->detect);		events |= mask&SS_DETECT;	}	if(state->ready!=prev_state->ready){		debug(2, "%s(): card ready value %u\n", 				__FUNCTION__, state->ready);		events |= mask&((flags&SS_IOCARD)?0:SS_READY);	}	*prev_state=*state;	return events;}  /* au1000_pcmcia_events() *//*  * Au1000_pcmcia_task_handler() * Processes socket events. */static void au1000_pcmcia_task_handler(void *data) {	struct pcmcia_state state;	int i, events, irq_status;	for(i=0; i<socket_count; i++)  {		if((irq_status = pcmcia_low_level->socket_state(i, &state))<0)			printk(KERN_ERR "low-level PCMCIA error\n");		events = au1000_pcmcia_events(&state, 				&pcmcia_socket[i].k_state, 				pcmcia_socket[i].cs_state.csc_mask, 				pcmcia_socket[i].cs_state.flags);		if(pcmcia_socket[i].handler!=NULL) {			pcmcia_socket[i].handler(pcmcia_socket[i].handler_info,					events);		}	}}  /* au1000_pcmcia_task_handler() */static struct tq_struct au1000_pcmcia_task = {	routine: au1000_pcmcia_task_handler};static void au1000_pcmcia_poll_event(unsigned long dummy){	poll_timer.function = au1000_pcmcia_poll_event;	poll_timer.expires = jiffies + AU1000_PCMCIA_POLL_PERIOD;	add_timer(&poll_timer);	schedule_task(&au1000_pcmcia_task);}/*  * au1000_pcmcia_interrupt() * The actual interrupt work is performed by au1000_pcmcia_task(),  * because the Card Services event handling code performs scheduling  * operations which cannot be executed from within an interrupt context. */static void au1000_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs){	schedule_task(&au1000_pcmcia_task);}static int au1000_pcmcia_register_callback(unsigned int sock, 		void (*handler)(void *, unsigned int), void *info){	if(handler==NULL){		pcmcia_socket[sock].handler=NULL;		MOD_DEC_USE_COUNT;	} else {		MOD_INC_USE_COUNT;		pcmcia_socket[sock].handler=handler;		pcmcia_socket[sock].handler_info=info;	}	return 0;}/* au1000_pcmcia_inquire_socket() *

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?