📄 mmc_main.c.bak
字号:
/* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that 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 * * Copyright (C) 2002 Motorola Semiconductors HK Ltd * *//** * * @defgroup MMC MMC driver **/ /**@{*/ /** * @file mmc_main.c * @brief mmc driver source code * * MMC operates as a block device, this file provides all the interface functions \n * for block device * * Modification History: * 30 DEC, 2001 * * @bug **/#ifndef __KERNEL__# define __KERNEL__#endif#ifndef MODULE# define MODULE#endif#define TESTING_PAGE (1024*1024*40/512) #define MMCSD_TEST_PAGE_NUM 8 #include <linux/config.h>#include <asm/bitops.h>#include <linux/delay.h>#include <linux/errno.h> /* error codes */#include <linux/fs.h> /* everything... */#include <linux/fcntl.h> /* O_ACCMODE */#include <linux/hdreg.h> /* HDIO_GETGEO */#include <linux/ioctl.h>#include <linux/interrupt.h>#include <linux/init.h>#include <linux/ioport.h>#include <linux/in.h>#include <linux/kernel.h> /* printk() */#include <linux/kdev_t.h>#include <linux/module.h>#include <linux/mm.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/tqueue.h>#include <linux/types.h> /* size_t */#include <linux/pm.h>#include <linux/poll.h>#include <linux/ptrace.h>#include <linux/vmalloc.h>#include <linux/version.h>#include <linux/proc_fs.h>//for proc//#include <linux/malloc.h>#include <asm/io.h>#include <linux/wait.h>#include <asm/hardware.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <asm/system.h> /* cli(), *_flags */#include <asm/dma.h>#include <linux/blkdev.h>#include <linux/devfs_fs_kernel.h>//#include <asm/arch/apmc.h>/*These symbols in <linux/blk.h> that must be defined in advance.*/#define DEVICE_NR(device) MINOR(device) #define DEVICE_NAME "mmc" /* name for messaging */#define DEVICE_NO_RANDOM /* no entropy to contribute */#include <linux/blk.h>#ifdef CONFIG_ARCH_MX1ADS#include "dbmx1_dma.h"#endif#include "mmc_def.h"#include "mmc_main.h" /* local definitions */#ifdef LINUX_20# error "This module can't run with Linux-2.0"#endif#ifdef CONFIG_PM#define PM_OPT " [pm]"#else#define PM_OPT ""#endif/* * if partition is considered then HAVE_BLKPG_H should be defined. */#include <linux/blkpg.h> /* blk_ioctl() *//* * variables will be initialized in init function. */MMCSD_Dev *g_mmcsd_devices = NULL;u8 g_mmcsd_cur_device = 0xff;u8 g_mmcsd_num = 0;u8 g_mmcsd_cmd[2] = {0,0};MMCSD_Lock g_selected_lock[2];int g_mmcsd_major;int g_mmcsd_presence = 0;volatile u32 g_mmcsd_status =0;static devfs_handle_t devfs_handle = NULL; //devfs#define MMC_PMST_SUSPEND 0#define MMC_PMST_RESUME 1static int g_mmc_status = MMC_PMST_RESUME;struct apmc_user *g_Mmc_apmc;/* Function declarations */static int mmcsd_open(struct inode *inode, struct file *filp);static int mmcsd_release(struct inode *inode, struct file *filp);static int mmcsd_revalidate(kdev_t dev);static MMCSD_Dev *mmcsd_locate_device(const struct request *req);void mmcsd_request_handler(request_queue_t * q);static int mmcsd_data_transfer(MMCSD_Dev *device,struct request *req);static int mmcsd_read( MMCSD_Dev *device, char * buffer, u32 sector, u32 nr_sector);static int mmcsd_write( MMCSD_Dev *device, char * buffer, u32 sector, u32 nr_sector);static int mmcsd_sector_erase(MMCSD_Dev *device, MMCSD_Blks *blks);MMCSD_STATUS mmcsd_ReadBlock(MMCSD_Dev *device,u32 start_addr,u16 nsects, u8 *buff);MMCSD_STATUS mmcsd_ReadSingleBlock(MMCSD_Dev *device,u32 addr,u8 * buff);MMCSD_STATUS mmcsd_DMA_ReadSingleBlock(MMCSD_Dev *device,u32 addr,u8 * buff);int mmcsd_DmaStartTransfer(MMCSD_Dev *device,u8 * buff,u32 counter, u8 mode,u8 is_4_bit);void mmcsd_dma_handler(void);static int mmcsd_ioctl(struct inode *inode,struct file *filp,unsigned command,unsigned long argument);static int mmcsd_write_protect(MMCSD_Dev *device,u32 addr, char is_set);static int mmcsd_passwd_cmd(MMCSD_Dev * device, MMCSD_PWD *pwd); static int mmcsd_is_writeprotection(MMCSD_Dev *device);void mmcsd_irq_handler(int irq,void * data, struct pt_regs * pt);static int mmcsd_getMBR(MMCSD_Dev * device);static int mmcsd_check_status(MMCSD_Dev *device,u32 *pstate);static void mmcsd_dma_isr(void * arg);static void mmcsd_dma_err_isr(int error_type);MMCSD_STATUS mmcsd_write_blks(MMCSD_Dev *device);MMCSD_STATUS mmcsd_dma_write_blks(MMCSD_Dev *device);void mmcsd_free_buffer(MMCSD_Dev *device);void _mmcsd_16_big_2_little(u8 *buf, u32 size);void _mmcsd_cp_16_little_2_big(u8 *src,u8 *target, int size);void mmcsd_delay(u32 delay);static int handle_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data);///@brief block device interface function structure, used in blkdev register.static struct block_device_operations mmcsd_bdops = { open: mmcsd_open, release: mmcsd_release, ioctl: mmcsd_ioctl, revalidate: mmcsd_revalidate,};///@brief boot_sector definition used to support format functionstruct boot_sector { __u8 ignored[3]; /*!< Boot strap short or near jump */ __u8 system_id[8]; /*!< Name - can be used to special case partition manager volumes */ __u8 sector_size[2]; /*!< bytes per logical sector */ __u8 cluster_size; /*!< sectors/cluster */ __u16 reserved; /*!< reserved sectors */ __u8 fats; /*!< number of FATs */ __u8 dir_entries[2]; /*!< root directory entries */ __u8 sectors[2]; /*!< number of sectors */ __u8 media; /*!< media code (unused) */ __u16 fat_length; /*!< sectors/FAT */ __u16 secs_track; /*!< sectors per track */ __u16 heads; /*!< number of heads */ __u32 hidden; /*!< hidden sectors (unused) */ __u32 total_sect; /*!< number of sectors (if sectors == 0) */ /*!< The following fields are only used by FAT32 */ __u32 fat32_length; /*!< sectors/FAT */ __u16 flags; /*!< bit 8: fat mirroring, low 4: active fat */ __u8 version[2]; /*!< major, minor filesystem version */ __u32 root_cluster; /*!< first cluster in root directory */ __u16 info_sector; /*!< filesystem info sector */ __u16 backup_boot; /*!< backup boot sector */ __u16 reserved2[6]; /*!< Unused */ /*!< fill up to 512 bytes */ __u8 junk[448];};static struct boot_sector gMmcSectorInfor;#define CF_LE_L(v) (((unsigned)(v)>>24) | (((unsigned)(v)>>8)&0xff00) | \ (((unsigned)(v)<<8)&0xff0000) | ((unsigned)(v)<<24))#ifndef MODULEextern int errno;#endifextern unsigned char gSDWriteProtect;static char g_socket1_info;#define SD_SOCKET_NO_CARD 0x01#define SD_SOCKET_CARD 0x02#ifdef CONFIG_ARCH_MX2ADSstatic char gSDumounted;static devfs_handle_t devfs_handle1 = NULL; //devfsvoid mmcsd_irq_handler_2(int irq,void * data, struct pt_regs * pt);static void mmcsd_dma_isr_1(void * arg);#endif/*static struct tasklet_struct mmc_tasklet; #ifdef CONFIG_ARCH_MX2ADSstatic void mmc_tasklet_action(unsigned long data){ u8* tmp; //mount the disk printk("1 implement here \n");// sys_module_mount("/dev/mmc","/mnt/mmcsd","msdos",MS_SYNC,0); tmp = kmalloc(1024,GFP_KERNEL); printk("2 implement here \n"); return;}#endif*//** *@brief irq handler for card insert/withdraw * * It is using GPIO portB16 pin to generate card detect interrupt, in the irq handler\n * will revert trigger configuration to detect card withdraw, and then clear interrupt. * * History: * 03-Feb-04 Add Card detection for MX1 silicon 2.0 (Use PB17) **/void mmcsd_socket1_irq_handler(int irq, void *dev_id, struct pt_regs * regs){ u32 status,trigger;#ifdef CONFIG_ARCH_MX1ADS status = *(u32 *)DBMX1_ISR_B; trigger = *(u32 *)DBMX1_ICR2_B; if((status & 0x00020000)==0x00020000) //get PortB17 int { if((trigger & 0x0000000C)==0x00000008) //it is positive level { g_socket1_info = SD_SOCKET_NO_CARD; *(u32 *)DBMX1_ICR2_B |= 0x0000000C; //set it to be negative level trigger detect card withdraw printk("A card is withdrawn from socket1 \n"); } else if((trigger & 0x0000000C)==0x0000000C) //it is negative level { g_socket1_info = SD_SOCKET_CARD; *(u32 *)DBMX1_ICR2_B &= ~0x00000004; // config as positive level trigger10 *(u32 *)DBMX1_ICR2_B |= 0x00000008; ;//set it to be positive level trigger detect card insert printk("A card is inserted in socket1 \n"); } }#endif#ifdef CONFIG_ARCH_MX2ADS status = _reg_GPIO_ISR(GPIOD); trigger = _reg_GPIO_ICR2(GPIOD); if((status & 0x02000000)==0x02000000) //get PortB16 int { if((trigger & 0x000C0000)==0x00080000)//it is positive level now { g_socket1_info = SD_SOCKET_NO_CARD; _reg_GPIO_ICR2(GPIOD) |= 0x000C0000; //set it to be negative level trigger detect card withdraw _mmcsd_socket1_clear_irq();// printk("A card is withdrawn from socket1 \n"); } if((trigger & 0x000C0000)==0x000C0000)//it is negative level now { g_socket1_info = SD_SOCKET_CARD; _reg_GPIO_ICR2(GPIOD) &= ~0x00040000; // config as positive level trigger10 _reg_GPIO_ICR2(GPIOD) |= 0x00080000;//set it to be positive level trigger detect card insert _mmcsd_socket1_clear_irq();// tasklet_schedule(&mmc_tasklet);// printk("A card is inserted in socket1 \n"); } }#endif// _mmcsd_socket1_clear_irq(); return;}/** *@brief proc_output function * * It will give MMC socket status information using proc file system, it will display two status:nocard/card * **/static int mmcsd_proc_output (char *buf){ char *p; char *devtype = "?"; char *devright = "w"; unsigned long flags; save_flags(flags); cli(); p = buf;//Add to proc to indicate which card in which socket if(g_socket1_info == SD_SOCKET_CARD) { devtype = "mmc"; p += sprintf(p, "%s %s \n",devtype,devright); /* if (gSDumounted == 0) { sys_module_mount("/dev/mmc","/mnt/mmcsd","msdos",MS_SYNC,0); }*/ } else if(g_socket1_info == SD_SOCKET_NO_CARD) { devtype = "n"; p += sprintf(p, "%s %s \n",devtype,devright); } restore_flags(flags); return p - buf; }static int mmcsd_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ int len = mmcsd_proc_output(page); if (len <= (off+count)) *eof = 1; *start = page + off; len -= off; if (len>count) len = count; if (len<0) len = 0; return len;}/** *@brief mmc init function * * Function Name: mmcsd_init * * *@return int return status * @li 0 sucess * @li other failure * * Description: This is the initialization routine for the driver. And this function \n * will be called while the module being installed. In this function, it will \n * register blk device,allocate request queue,request mmc irq and mmc socket irq,\n * register to power management. * * Modification History: * **/#ifdef MODULEint init_module(void)#elseint __init mmcsd_init(void)#endif{ int ret,i; printk("MMC device driver version 0.4.0\n"); TRACE("\n Begin initialize mmcsd module "); /***************************************************** * Register the block driver. *****************************************************/#ifdef CONFIG_ARCH_MX2ADS gSDumounted = 0;#endif g_mmcsd_major = MMCSD_MAJOR; ret = devfs_register_blkdev(g_mmcsd_major, "mmc", &mmcsd_bdops); if (ret < 0) { FAILED(" can't get major %d\n",MMCSD_MAJOR); return ret; } if(g_mmcsd_major == 0) { g_mmcsd_major = ret; /* dynamic */ } devfs_handle=devfs_register(NULL,"mmc",DEVFS_FL_DEFAULT,ret,0, S_IFBLK | S_IRUGO | S_IWUGO,&mmcsd_bdops,NULL);#ifdef CONFIG_ARCH_MX2ADS devfs_handle1 = devfs_register(NULL, "mmc1",DEVFS_FL_DEFAULT,ret,1, S_IFBLK | S_IRUGO | S_IWUGO,&mmcsd_bdops,NULL);#endif read_ahead[g_mmcsd_major] = MMCSD_READ_AHEAD;/* in sectors */ /******************************************************* * Allocate space for each devices. *******************************************************/ g_mmcsd_num = MMCSD_DEVICE_NUM; g_mmcsd_devices = kmalloc((g_mmcsd_num*sizeof(MMCSD_Dev)), GFP_KERNEL); if (!g_mmcsd_devices) { goto fail_init; } memset(g_mmcsd_devices,0,(g_mmcsd_num * sizeof(MMCSD_Dev))); for (i=0; i < g_mmcsd_num; i++) { spin_lock_init(&(g_mmcsd_devices[i].lock)); spin_unlock(&(g_mmcsd_devices[i].lock)); init_waitqueue_head(&(g_mmcsd_devices[i].select_wait)); sema_init(&(g_mmcsd_devices[i].sema),1); g_mmcsd_devices[i].dma_channel = 0xFFFFFFFF; } g_selected_lock[0].device = NULL; g_selected_lock[1].device = NULL; /******************************************************* * Allocate request queue for each device. *******************************************************/ /* for(i = 0;i < g_mmcsd_num; i++) { blk_init_queue(&(g_mmcsd_devices[i].queue), mmcsd_request_handler); blk_queue_headactive(&(g_mmcsd_devices[i].queue),0); } */ blk_init_queue(BLK_DEFAULT_QUEUE(g_mmcsd_major),mmcsd_request_handler); /****************************************************** * Regist Interrupt Service Routine ******************************************************/ ret = request_irq(MMCSD_IRQ, mmcsd_irq_handler, SA_INTERRUPT, "mmc", "mmc"); if(ret) { TRACE("request irq error"); goto fail_init; }#ifdef CONFIG_ARCH_MX2ADS ret = request_irq(MMCSD2_IRQ, mmcsd_irq_handler_2, SA_INTERRUPT, "mmc1", "mmc1");#endif if(ret) { TRACE("request irq error"); goto fail_init; } /****************************************************** * Regist PM device. ******************************************************/ /* We register SDHC1 & SDHC2 */ /* and the callback function will be called twice for each pm request */ pm_register(PM_SDHC1_DEV, PM_SYS_UNKNOWN, handle_pm_event); pm_register(PM_SDHC2_DEV, PM_SYS_UNKNOWN, handle_pm_event); g_Mmc_apmc = apmc_register(APMC_LEVEL_HIGHEST);// pm_register(PM_SYS_DEV, PM_SYS_UNKNOWN, handle_pm_event); /****************************************************** * Pin Configuration * *****************************************************/ _MMCSD_64M_MMC_PinConfig(); /****************************************************** * LOOP FOR THE MAXIMUM NUMBER OF CARD SLOTS ******************************************************/ for ( i = 0 ; i < MMCSD_DEVICE_NUM ; i++ ) { g_mmcsd_devices[i].card_state= MMCSD_NOTREADY; g_mmcsd_devices[i].card_rca = 1; //g_mmcsd_devices[i].card_type = MMCSD_NO_CARD; } /***************************************************** *setting for auto-mount/umount ******************************************************/ g_socket1_info = SD_SOCKET_NO_CARD; ret = request_irq(MMCSD_SOCKET1_INT, mmcsd_socket1_irq_handler, SA_INTERRUPT|SA_SHIRQ, "mmc", "mmc");/*#ifdef CONFIG_ARCH_MX2ADS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -