⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ar6000_cs.c

📁 linux下的SDIO 驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 2004-2006 Atheros Communications Inc. * All rights reserved. * * It also includes code from the Linux PCMCIA package, (C) David Hinds. *  Wireless Network driver for Atheros AR6001 * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License version 2 as *  published by the Free Software Foundation; * *  Software distributed under the License is distributed on an "AS *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or *  implied. See the License for the specific language governing *  rights and limitations under the License. * * */#include <linux/config.h>#ifdef  __IN_PCMCIA_PACKAGE__#include <pcmcia/k_compat.h>#endif /* __IN_PCMCIA_PACKAGE__ */#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/ptrace.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/ioport.h>#include <linux/wireless.h>#include <linux/interrupt.h>#include <pcmcia/version.h>#include <pcmcia/cs_types.h>#include <pcmcia/cs.h>#include <pcmcia/cistpl.h>#include <pcmcia/cisreg.h>#include <pcmcia/ds.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/system.h>#include "ar6000_cs_internal.h"/********************************************************************//* Module stuff							    *//********************************************************************/MODULE_DESCRIPTION("Driver for Atheros PCMCIA WLAN Card");#define CS_CHECK(fn, ret) \do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)/* * 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 = "ar6000_cs";/* * A linked list of "instances" of the device.  Each actual PCMCIA * card corresponds to one device instance, and is described by one * dev_link_t structure (defined in ds.h). */static dev_link_t *dev_list;/* List of upper driver instances */static CFFUNCTION *drv_list;static struct rw_semaphore dev_lock;static struct rw_semaphore drv_lock;static struct work_struct hotPlugTask;#ifdef DEBUGA_UINT32 debugbusdrv=0;enum {    ATH_LOG_SEND = 0x0001,    ATH_LOG_RECV = 0x0002,    ATH_LOG_SYNC = 0x0004,    ATH_LOG_DUMP = 0x0008,    ATH_LOG_INF  = 0x0010,    ATH_LOG_TRC  = 0x0020,    ATH_LOG_WARN = 0x0040,    ATH_LOG_ERR  = 0x0080,    ATH_LOG_ANY  = 0xFFFF,};#define BUSDRV_DEBUG_PRINTF(flag, args...) do {        \    if (debugbusdrv) {                    \        printk(KERN_ALERT args);      \    }                                            \} while (0)#endif //DEBUG/********************************************************************//* Function prototypes						    *//********************************************************************/static void ar6000_cs_config(dev_link_t * link);static void ar6000_cs_release(dev_link_t * link);static int ar6000_cs_event(event_t event, int priority,			    event_callback_args_t * args);static dev_link_t *ar6000_cs_attach(void);static void ar6000_cs_detach(dev_link_t *);/********************************************************************* API exposed to Upper layer.********************************************************************//* Go thru the list of devices maintained in this layer and if it* matches the upper layer module, call the module's probe function.* Also pass a device's instance as an opaque reference to the upper* layer module.*/CF_STATUS CF_RegisterFunction(PCFFUNCTION pFunction) {	struct dev_link_t *ptr = NULL;	CF_DEVICE *pCfDevice = NULL;	PCF_PNP_INFO pnpPtr = NULL;	CF_STATUS status = CF_STATUS_SUCCESS;	//Insert the upper layer driver ctx in the list maintained in this layer.	insert_drv_list(pFunction);	// Acquire Lock	down_read(&dev_lock);	//traverse the dev_link_t list	for ( ptr=dev_list; (ptr); ptr=ptr->next ) {	/* check if ptr->priv->pCfDevice.pId matches that provided by the	 * upper layer If so insert the pFunction ctx into that devices	 * function list. and call that devices probe function & return.	 */		pCfDevice = (CF_DEVICE *)&(((struct ar6000_pccard *)(ptr->priv))->CfDevice);		// Go thru the list of PNP Ids & if any of them match, call probe().		/* Check for NULL Manf-Code to traverse the Pnp List that is		 * null terminated.		 */		for ( pnpPtr = pFunction->pIds; pnpPtr->CF_ManufacturerCode != 0 ; \					pnpPtr++ ) {			BUSDRV_DEBUG_PRINTF(ATH_LOG_INF, "CFRegisterFunc b4 manfid comp %04x, %04x\n", pCfDevice->pId.CF_ManufacturerID, pnpPtr->CF_ManufacturerID);			if( pCfDevice->pId.CF_ManufacturerID == pnpPtr->CF_ManufacturerID )			{				pCfDevice->pFunction = pFunction;				if ( !((*pFunction->pProbe)(pFunction, pCfDevice)) ) {					/* The device is not successfuly probed by this					* fuction driver. disassociate them.					*/					pCfDevice->pFunction = NULL;					status = CF_STATUS_ERROR;				}				status = CF_STATUS_SUCCESS;				break;			}		}	}	up_read(&dev_lock);	return status;}CF_STATUS CF_UnregisterFunction(PCFFUNCTION pFunction) {	/* Release the device structure if a card is present or else	* remove the function instance from the FuncList	*/	struct dev_link_t *ptr = NULL;	CF_DEVICE *pCfDevice = NULL;	PCF_PNP_INFO pnpPtr = NULL;	down_read(&dev_lock);	//traverse the dev_link_t list	for ( ptr=dev_list; (ptr); ptr=ptr->next ) {	/* check if ptr->priv->pCfDevice.pId matches that provided by the	 * upper layer If so remove the association between the device and the     * upper layer driver. 	 */		pCfDevice = (CF_DEVICE *)&(((struct ar6000_pccard *)(ptr->priv))->CfDevice);		for ( pnpPtr = pFunction->pIds; pnpPtr->CF_ManufacturerCode != 0 ; \					pnpPtr++ ) {			BUSDRV_DEBUG_PRINTF(ATH_LOG_INF, "CF_UnRegisterFunc manfid comp %04x, %04x\n", pCfDevice->pId.CF_ManufacturerID, pFunction->pIds->CF_ManufacturerID);			if( pCfDevice->pId.CF_ManufacturerID == pnpPtr->CF_ManufacturerID)			{				pCfDevice->pFunction = NULL;				break;			}		}	}	up_read(&dev_lock);	remove_drv_list(pFunction);	return CF_STATUS_SUCCESS;}static CF_STATUS ar6000_cs_read_byte(CF_DEVICE *pDev, PCFREQUEST pReq) {	A_UINT32 len = pReq->length;	A_UCHAR *buff = pReq->pDataBuffer;	A_UINT32 ctr=0;	A_UCHAR *port = ((A_UCHAR *)pDev->mem_start) + pReq->address;	for (ctr=0;ctr<len;ctr++) {		*buff = readb(port);		BUSDRV_DEBUG_PRINTF(ATH_DEBUG_DUMP, "R: data: %x, address: %p\n",*buff,port);		buff++;		if (!(pReq->Flags & CFREQ_FLAGS_FIXED_ADDRESS))			port += 1;	}	return CF_STATUS_SUCCESS;}static CF_STATUS ar6000_cs_write_byte(CF_DEVICE *pDev, PCFREQUEST pReq) {	A_UINT32 ctr = 0;	A_UINT32 len = pReq->length;	A_UCHAR *buff = pReq->pDataBuffer;	A_UCHAR *port = ((A_UCHAR *)pDev->mem_start) + pReq->address;	for (ctr=0;ctr<len;ctr++) {		BUSDRV_DEBUG_PRINTF(ATH_DEBUG_DUMP, "W: data: %x, address: %p\n",*buff,port);		writeb(*buff, port);		buff++;		if (!(pReq->Flags & CFREQ_FLAGS_FIXED_ADDRESS))			port += 1;	}	return CF_STATUS_SUCCESS;}static CF_STATUS ar6000_cs_read_word(CF_DEVICE *pDev, PCFREQUEST pReq) {	A_UINT32 len = pReq->length;	A_UINT16 *buff = pReq->pDataBuffer;	A_UINT32 ctr=0;	A_UCHAR *port = ((A_UCHAR *)pDev->mem_start) + pReq->address;	for (ctr=0;(ctr+1)<len;) {		*buff = readw(port);		BUSDRV_DEBUG_PRINTF(ATH_DEBUG_DUMP,"R: data: %x, address: %p\n",*buff,port);		buff++;		if (!(pReq->Flags & CFREQ_FLAGS_FIXED_ADDRESS))			port += 2;		ctr += 2;	}	//Read the last byte	if ( ctr < len ) {		*((unsigned char *)buff) = readb(port);		BUSDRV_DEBUG_PRINTF(ATH_DEBUG_DUMP,"R: data: %x, address: %p\n",*((unsigned char *)buff),port);	}	return CF_STATUS_SUCCESS;}static CF_STATUS ar6000_cs_write_word(CF_DEVICE *pDev, PCFREQUEST pReq) {	A_UINT32 ctr = 0;	A_UINT32 len = pReq->length;	A_UINT16 *buff = pReq->pDataBuffer;	A_UCHAR *port = ((A_UCHAR *)pDev->mem_start) + pReq->address;	for (ctr=0;(ctr+1)<len;) {		BUSDRV_DEBUG_PRINTF(ATH_DEBUG_DUMP,"W: data: %x, address: %p\n",*buff,port);		writew(*buff, port);		buff++;		if (!(pReq->Flags & CFREQ_FLAGS_FIXED_ADDRESS))			port += 2;		ctr += 2;	}	// Write the last byte	if ( ctr < len ) {		BUSDRV_DEBUG_PRINTF(ATH_DEBUG_DUMP,"W: data: %x, address: %p\n",*((unsigned char *)buff),port);		writeb(*((unsigned char *)buff), port);	}	return CF_STATUS_SUCCESS;}CF_STATUS CF_BusRequest_Word(PCFDEVICE pDev, PCFREQUEST pReq){	CF_STATUS status;	if ( pReq->Flags & CFREQ_FLAGS_DATA_WRITE ) {		status = ar6000_cs_write_word((CF_DEVICE *)pDev, pReq);	} else {		status = ar6000_cs_read_word((CF_DEVICE *)pDev, pReq);	}	return status;}CF_STATUS CF_BusRequest_Byte(PCFDEVICE pDev, PCFREQUEST pReq){	CF_STATUS status;	if ( pReq->Flags & CFREQ_FLAGS_DATA_WRITE ) {		status = ar6000_cs_write_byte((CF_DEVICE *)pDev, pReq);	} else {		status = ar6000_cs_read_byte((CF_DEVICE *)pDev, pReq);	}	return status;}void CF_SetIrqHandler(PCFDEVICE pDev, pIsrHandler pFn1, pDsrHandler pFn2, void * pContext) {    ((CF_DEVICE *)pDev)->pIrqFunction = (pFn1);    ((CF_DEVICE *)pDev)->IrqContext = (void *)(pContext);	if (pFn2) {		tasklet_init(&(((CF_DEVICE *)pDev)->tasklet),pFn2,(unsigned long)pContext);	}}/********************************************************************//* PCMCIA stuff     						    *//********************************************************************//* For 2.4 kernels, cs_error is not exported. providing our own...*/static voidar6000_cs_error(client_handle_t handle, int func, int ret){	error_info_t err = { func, ret };	pcmcia_report_error(handle, &err);}/* Device List manipulation routines */static void insert_dev_list(struct ar6000_pccard *dev){	dev_link_t *temp=NULL;	down_write(&dev_lock);	//Check for empty dev list.	if(!dev_list) {		dev_list = &dev->link;	} else {		//traverse to the end of the list.		for(temp=dev_list;(temp->next);temp=temp->next);		temp->next = &dev->link;	}	up_write(&dev_lock);	return;}static struct dev_link_t * remove_dev_list(struct ar6000_pccard *dev){	struct dev_link_t *curr,*prev;	curr = prev = NULL;	down_write(&dev_lock);	for(curr=prev=dev_list;(curr);prev=curr,curr=curr->next) {		if(curr->priv == dev) {			if(curr!=prev)				prev->next = curr->next;			else				dev_list = curr->next;			break;		}	}	up_write(&dev_lock);	return curr;}/* Upper driver instance list manipulation routines*/static void insert_drv_list(PCFFUNCTION pFunction) {	CFFUNCTION *temp=NULL;	down_write(&drv_lock);	//Check for empty dev list.	if(!drv_list) {		drv_list = pFunction;	} else {		//traverse to the end of the list.		for(temp=drv_list;(temp->next);temp=temp->next);		temp->next = pFunction;	}	pFunction->next = NULL;	up_write(&drv_lock);	return;}static PCFFUNCTION remove_drv_list(PCFFUNCTION pFunction){	CFFUNCTION *curr,*prev;	curr = prev = NULL;	down_write(&drv_lock);	for(curr=prev=drv_list;(curr);prev=curr,curr=curr->next) {		if(curr == pFunction) {			if(curr!=prev)				prev->next = curr->next;			else				drv_list = curr->next;			break;		}	}	up_write(&drv_lock);	return curr;}/* * Create an instance of the card and register with Card Services. */static dev_link_t *ar6000_cs_attach(void){	struct ar6000_pccard *info;	dev_link_t *link;	client_reg_t client_reg;	A_UINT32 ret;	BUSDRV_DEBUG_PRINTF(ATH_DEBUG_TRC, "Enter - ar6000_cs_attach\n");	/* Create new device */   	info = A_MALLOC(sizeof(struct ar6000_pccard));   	if (!info) return NULL;   	A_MEMZERO(info, sizeof(*info));   	link = &info->link; link->priv = info;	/* Initialize the CF device structure */	info->CfDevice.backPtr = link;	/* Interrupt setup */	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;	link->irq.IRQInfo1 = IRQ_LEVEL_ID;	link->irq.Handler = NULL;	link->conf.Attributes = 0;	link->conf.IntType = INT_MEMORY_AND_IO;	/* Insert into the global devlist */	insert_dev_list(info);	/* Register with Card Services */	client_reg.dev_info = &dev_info;	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;	client_reg.EventMask =		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;	client_reg.event_handler = &ar6000_cs_event;	client_reg.Version = 0x0210; /* FIXME: what does this mean? */	client_reg.event_callback_args.client_data = link;	ret = pcmcia_register_client(&link->handle, &client_reg);	if (ret != CS_SUCCESS) {		ar6000_cs_error(link->handle, RegisterClient, ret);		BUSDRV_DEBUG_PRINTF(ATH_LOG_ERR, "pcmcia register failed\n");		ar6000_cs_detach(link);		return NULL;	}	BUSDRV_DEBUG_PRINTF(ATH_DEBUG_TRC, "Exit - ar6000_cs_attach\n");	return link;} /* ar6000_cs_attach *//* * Deregister with card services & free the device structure. */static voidar6000_cs_detach(dev_link_t * link){	CF_DEVICE *pCfDevice = NULL;	BUSDRV_DEBUG_PRINTF(ATH_DEBUG_TRC, "Enter - ar6000_cs_detach\n");	/* Call the pRemove function of the top level driver */	pCfDevice = (CF_DEVICE *)&(((struct ar6000_pccard *)(link->priv))->CfDevice);	if (pCfDevice->pFunction) {		(*pCfDevice->pFunction->pRemove)(pCfDevice->pFunction, pCfDevice);		pCfDevice->pFunction = NULL;	}	if (link->state & DEV_CONFIG)		ar6000_cs_release(link);	/* Unregister with Card Services */	if (link->handle)		pcmcia_deregister_client(link->handle);	/* Unlink device structure, and free it */	BUSDRV_DEBUG_PRINTF(ATH_LOG_INF, "ar6000_cs: detach: link=%p link->dev=%p\n", link, link->dev);

⌨️ 快捷键说明

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