📄 mss_sdio.c
字号:
/** @file if_sdio.c * @brief This file contains SDIO IF (interface) module * related functions. * * (c) Copyright ?2003-2007, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 * (the "License"). You may use, redistribute and/or modify this File in * accordance with the terms and conditions of the License, a copy of which * is available along with the File in the gpl.txt file or by writing to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. * * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE * ARE EXPRESSLY DISCLAIMED. The License provides additional details about * this warranty disclaimer. * *//****************************************************Change log: 10/14/05: add Doxygen format comments 01/05/06: add kernel 2.6.x support ****************************************************/#include <linux/config.h>#include <linux/module.h>#include <linux/sched.h>#include <linux/kernel.h> #include <linux/fs.h> #include <linux/errno.h> #include <linux/types.h> #include <linux/fcntl.h> #include <linux/init.h>#include <linux/devfs_fs_kernel.h>#include <asm/system.h>#include <asm/uaccess.h>#include <asm/scatterlist.h>#include <linux/mm.h>
#include <asm/page.h>#include <linux/cdev.h>#include "mss_sdio.h"/* define Data block size for data Tx/Rx */#define CMMB_DATA_BLOCK_SIZE 512//#define DEFAULT_DEBUG_MASK (0xffffffff & ~DBG_EVENT)#define SDIO_QUEUE_EXIT (1 << 0)#define CMMB_FRAME_SIZE_MAX 131072 typedef struct{ struct cdev *cdev; struct mss_card *card; struct class *sdio_class; wait_queue_head_t wq; unsigned char *databuf; unsigned char *readp; unsigned char *writep; unsigned int datalen; unsigned int flags;}sdio_dev;/******************************************************** Local Variables********************************************************///u32 drvdbg = DEFAULT_DEBUG_MASK;sdio_dev cmmb_dev;/******************************************************** Global Variables********************************************************//******************************************************** Local Functions********************************************************/static intsdio_rw(struct mss_card *card, u8 func, u32 reg, u32 blksz, u32 nob, int opcode, u32 data, int rw){ struct mss_request mreq; struct mss_rw_arg marg; struct mss_rw_result mres; struct scatterlist sg; int ret; memset(&mreq, 0x0, sizeof(mreq)); memset(&marg, 0x0, sizeof(marg)); memset(&mres, 0x0, sizeof(mres)); mreq.arg = &marg; mreq.result = &mres; mreq.card = card; mreq.action = rw ? MSS_WRITE_MEM : MSS_READ_MEM; marg.nob = nob; marg.func = func; marg.opcode = opcode; marg.block_len = blksz; marg.block = reg; if (rw) marg.val = data; /* Read/Write one register */ if (blksz == 0 && nob == 1) { marg.sg = NULL; marg.sg_len = 0; } else { sg.page = virt_to_page((u8 *) data); sg.offset = offset_in_page((u8 *) data); sg.length = blksz * nob; marg.sg = &sg; marg.sg_len = 1; } ret = mss_send_request(&mreq); if (ret) { return -EIO; } if (blksz == 0 && nob == 1 && !rw) *(u8 *) data = (u8) (mres.bytes_xfered); return 0;}static inline intsdio_read_ioreg(struct mss_card *card, u8 func, u32 reg, u8 * data){ return sdio_rw(card, func, reg, 0, 1, 0, (u32) data, 0);}static inline intsdio_write_ioreg(struct mss_card *card, u8 func, u32 reg, u8 data){ return sdio_rw(card, func, reg, 0, 1, 0, data, 1);}static inline intsdio_read_iomem(struct mss_card *card, u8 func, u32 reg, u8 blockmode, int opcode, u32 nob, u32 blksz, u8 * buf){ return sdio_rw(card, func, reg, blksz, nob, opcode, (u32) buf, 0);}static inline intsdio_write_iomem(struct mss_card *card, u8 func, u32 reg, u8 blockmode, int opcode, u32 nob, u32 blksz, u8 * buf){// PRINTM(INFO, "iomem: func:%d, reg:%d, opcode:%d, nob:%d, blksz:%d\n", func, reg, opcode, nob, blksz); return sdio_rw(card, func, reg, blksz, nob, opcode, (u32) buf, 1);}int sdio_media_read(void){ unsigned char lengthdata[3],tmp; unsigned char *tmpbuf; int len,readlen,i; int ret; ret = sdio_read_ioreg(cmmb_dev.card, FN1, FUNC1_DATA_COUNTER1_REG, &lengthdata[0]); if (ret < 0) return ret; ret = sdio_read_ioreg(cmmb_dev.card, FN1, FUNC1_DATA_COUNTER2_REG, &lengthdata[1]); if (ret < 0) return ret; ret = sdio_read_ioreg(cmmb_dev.card, FN1, FUNC1_DATA_COUNTER3_REG, &lengthdata[2]); if (ret < 0) return ret; len = (lengthdata[2]<<16) + (lengthdata[1]<<8) + lengthdata[0]; if (len <= 0) return 0; //printk("read Functon 1 count register %x\n", len); readlen = len; while(readlen > CMMB_DATA_BLOCK_SIZE) { if (cmmb_dev.writep+CMMB_DATA_BLOCK_SIZE >= cmmb_dev.databuf+CMMB_FRAME_SIZE_MAX)//buffer end { //printk("into buffer end branch1\n"); tmpbuf = kzalloc(CMMB_DATA_BLOCK_SIZE, GFP_KERNEL); if (tmpbuf == 0) { printk("kzalloc error\n"); goto ClearCounter; } ret = sdio_read_iomem(cmmb_dev.card, FN1, FUNC1_DATA_REG, BLOCK_MODE, FIXED_ADDRESS, 1, CMMB_DATA_BLOCK_SIZE, tmpbuf); if (ret < 0) { printk("while read Functon 1 register FUNC1_DATA_REG error1\n"); kfree(tmpbuf); goto ClearCounter; } else { i = cmmb_dev.databuf+CMMB_FRAME_SIZE_MAX-cmmb_dev.writep; memcpy(cmmb_dev.writep, tmpbuf, i); memcpy(cmmb_dev.databuf, tmpbuf+i, CMMB_DATA_BLOCK_SIZE-i); cmmb_dev.writep = cmmb_dev.databuf+CMMB_DATA_BLOCK_SIZE-i; readlen -= CMMB_DATA_BLOCK_SIZE; } kfree(tmpbuf); } else { ret = sdio_read_iomem(cmmb_dev.card, FN1, FUNC1_DATA_REG, BLOCK_MODE, FIXED_ADDRESS, 1, CMMB_DATA_BLOCK_SIZE, cmmb_dev.writep); if (ret < 0) { printk("while read Functon 1 register FUNC1_DATA_REG error2\n"); goto ClearCounter; } readlen -= CMMB_DATA_BLOCK_SIZE; cmmb_dev.writep += CMMB_DATA_BLOCK_SIZE; } } if (readlen > 0) { if (cmmb_dev.writep+readlen >= cmmb_dev.databuf+CMMB_FRAME_SIZE_MAX) { //printk("into buffer end branch2\n"); tmpbuf = kzalloc(readlen, GFP_KERNEL); if (tmpbuf == 0) { printk("kzalloc error\n"); goto ClearCounter; } ret = sdio_read_iomem(cmmb_dev.card, FN1, FUNC1_DATA_REG, BLOCK_MODE, FIXED_ADDRESS, 1, readlen, tmpbuf); if (ret < 0) { printk("while read Functon 1 register FUNC1_DATA_REG error3\n"); } else { i = cmmb_dev.databuf+CMMB_FRAME_SIZE_MAX-cmmb_dev.writep; memcpy(cmmb_dev.writep, tmpbuf, i); memcpy(cmmb_dev.databuf, tmpbuf+i, readlen-i); cmmb_dev.writep = cmmb_dev.writep+readlen-CMMB_FRAME_SIZE_MAX; } kfree(tmpbuf); } else { ret = sdio_read_iomem(cmmb_dev.card, FN1, FUNC1_DATA_REG, BLOCK_MODE, FIXED_ADDRESS, 1, readlen, cmmb_dev.writep); if (ret < 0) { printk("read Functon 1 register FUNC1_DATA_REG error4 readlen %d\n",readlen); } else cmmb_dev.writep += readlen; } }ClearCounter: sdio_read_ioreg(cmmb_dev.card, FN1, FUNC1_INT_IDENTIFY_REG, &tmp); sdio_write_ioreg(cmmb_dev.card, FN1, FUNC1_DATA_COUNTER1_REG, 0); sdio_write_ioreg(cmmb_dev.card, FN1, FUNC1_DATA_COUNTER2_REG, 0); sdio_write_ioreg(cmmb_dev.card, FN1, FUNC1_DATA_COUNTER3_REG, 0); mss_set_sdio_int(cmmb_dev.card->slot->host, 1); if (ret >= 0) cmmb_dev.datalen += len; return 0;}static int sdio_queue_thread(void *d){ DECLARE_WAITQUEUE(wait, current); current->flags |= PF_MEMALLOC; add_wait_queue(&cmmb_dev.wq, &wait); do { set_current_state(TASK_INTERRUPTIBLE); schedule(); if (cmmb_dev.flags & SDIO_QUEUE_EXIT) break; if (signal_pending (current)) break; sdio_media_read(); } while (1); remove_wait_queue(&cmmb_dev.wq, &wait); return 0;}static int sdio_open(struct inode *inode, struct file *file){ unsigned char tmp; int ret; init_waitqueue_head(&cmmb_dev.wq);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -