前一段时间,我们分别在eCos和linux上实现了ORPSoC中的sd卡控制器的基本操作。在eCos上实现了完整的,支持文件系统的driver,在linux上,也实现了基本的IO操作,但是还没有实现基于文件系统的操作,本小节就解决这个问题。
关于之前我们所做的工作,请参考:
OpenRisc-30-SD card controller模块分析与验证:http://blog.csdn.net/rill_zhen/article/details/9111213
OpenRisc-35-基于orpsoc,eCos的sd card controller的测试实验:http://blog.csdn.net/rill_zhen/article/details/9365477
OpenRisc-38-基于orpsoc,linux的sd card controller的测试实验:http://blog.csdn.net/rill_zhen/article/details/9419651
前面的基于linux的工作实现了基本的SD卡的IO,通过之前的努力,我们已经可以对SD卡进行读写操作,但是这个读写操作只能基于block,不能以文件的形式操作SD卡。
所以为了实现以文件的操作,需要文件系统的支持。
为了提高传输速度,驱动中仔细设计了中断处理程序的上半部分和下半部分。
一般情况下,上半部分和下半部分通过信号量来进行同步,我们这次使用了两外一种机制,就是completion。这种机制主要通过complete和wait_for_completion两个函数实现。
Completion是一种轻量级的机制,他允许一个线程告诉另一个线程某个工作已经完成。
此外,还需要注意的是,本驱动并没有使用linux专门为SD卡提供的framework,而是采用标准的块设备的framework。这需要重新配置linux的编译选项,如何配置内核,请参考附录部分。
为了便于读者更容易理解,这里简单介绍一下本驱动的工作机制。
1,本驱动是以model的形式编译的,编译会生成ko文件,通过insmod命令加载到内核,并会生成/dev/sdcmsc的设备节点。
2,在模块初始化部分,会对sd卡进行初始化,并注册块设备驱动,注册中断处理程序。关于中断的使用,如中断号的确定,我们之前介绍过,请参考 http://blog.csdn.net/rill_zhen/article/details/8894856
3,通过mount -t vfat /dev/sdcmmc /sdc 来挂载SD卡,其中/sdc是通过mkdir命令创建的挂载点。
4,一旦挂载成功,我们就可以使用cd ls cat cp mv rm 等命令来对SD卡进行操作了。
5,在linux进行IO操作时,首先会启动DMA传输过程,然后会唤醒一个名字为sdcmsc_queue_thread的内核线程,这个内核线程会等待DMA传输完毕之后的中断信号。一旦DMA传输完毕,中断处理程序会告诉这个内核线程。这样做的好处是,在进行DMA传输时,驱动程序会通过schedule()让出CPU,减少了CPU的占用时间。
了解了本驱动的基本思想和大体的工作机制之后,就可以开始编码了,这里直接给出代码清单。
这里需要说明的是,其实,一切细节都可以从代码中获得,所以还是建议读者在使用前仔细阅读本代码。
code list:
/* * rill create at 2013-09-18 * [email protected] */ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> #include <linux/sched.h> #include <linux/kernel.h> /* printk() */ #include <linux/slab.h> /* kmalloc() */ #include <linux/fs.h> /* everything... */ #include <linux/errno.h> /* error codes */ #include <linux/timer.h> #include <linux/types.h> /* size_t */ #include <linux/fcntl.h> /* O_ACCMODE */ #include <linux/hdreg.h> /* HDIO_GETGEO */ #include <linux/kdev_t.h> #include <linux/vmalloc.h> #include <linux/genhd.h> #include <linux/blkdev.h> #include <linux/buffer_head.h> /* invalidate_bdev */ #include <linux/bio.h> #include <linux/delay.h> #include <linux/completion.h> #include <linux/kthread.h> #include <linux/interrupt.h> #include "sdcmsc.h" MODULE_LICENSE("Dual BSD/GPL"); static struct sdcmsc_card* sdcmsc_dev_p = NULL; static DEFINE_MUTEX(block_mutex); static DEFINE_MUTEX(open_lock); DECLARE_COMPLETION(comp_dma); static struct sdcmsc_card* sdcmsc_blk_get(struct gendisk *disk) { struct sdcmsc_card* sdev; mutex_lock(&open_lock); sdev = disk->private_data; if(sdev && sdev->usage ==0) sdev = NULL; if(sdev) sdev->usage++; mutex_unlock(&open_lock); return sdev; } static void sdcmsc_blk_put(struct sdcmsc_card *dev) { mutex_lock(&open_lock); dev->usage--; if(dev->usage == 0) { blk_cleanup_queue(dev->mq.queue); put_disk(dev->gd); kfree(dev); } mutex_unlock(&open_lock); } static irqreturn_t sdcmsc_irq_dat(int irq, void *dev_id) { struct sdcmsc_card * dev= dev_id; void __iomem * sdcmsc_base = dev->sdcmsc_base; unsigned reg; // printk(KERN_ALERT "I'm in interrupt!"); reg = ioread32(sdcmsc_base + SDCMSC_DAT_INT_STATUS); reg = cpu_to_le32(reg); iowrite32(0, sdcmsc_base + SDCMSC_DAT_INT_STATUS); //Check for errors if(reg != SDCMSC_DAT_INT_STATUS_TRS) { if(reg & (1 << 5)) printk(KERN_ALERT "Transmission error\n"); if(reg & (1 << 4)) printk(KERN_ALERT "Command error\n"); if(reg & (1 << 2)) printk(KERN_ALERT "FIFO error\n"); if(reg & (1 << 1)) printk(KERN_ALERT "Retry error\n"); } // printk(KERN_ALERT "before complete!"); complete(&comp_dma); return IRQ_HANDLED; } static int sdcmsc_card_queue(struct sdcmsc_card* dev, int direction_transmit, unsigned long block_addr, unsigned long buffer_addr) { unsigned long reg; //int i; void __iomem *sdcmsc_base = dev->sdcmsc_base; // printk(KERN_ALERT "sdcmsc_base:0x%x\n", sdcmsc_base); // printk(KERN_ALERT "block_addr:%d\n", block_addr-8192); if(direction_transmit) { // printk(KERN_ALERT "I'm in writing"); reg = le32_to_cpu(buffer_addr); iowrite32(reg, sdcmsc_base + SDCMSC_BD_TX); block_addr = le32_to_cpu(block_addr); iowrite32(block_addr, sdcmsc_base + SDCMSC_BD_TX); } else { // printk(KERN_ALERT "I'm in Reading\n"); // printk(KERN_ALERT "buffer_addr:0x%x\n", buffer_addr); reg= le32_to_cpu(buffer_addr); iowrite32(reg, sdcmsc_base + SDCMSC_BD_RX); // printk(KERN_ALERT "block_addr:%d\n", block_addr); block_addr = le32_to_cpu(block_addr); iowrite32(block_addr, sdcmsc_base + SDCMSC_BD_RX); } // printk(KERN_ALERT "before wait_for_completion"); wait_for_completion(&comp_dma); // printk(KERN_ALERT "after wait_for_completion"); return 1; } static int sdcmsc_disk_read(struct sdcmsc_card* dev, unsigned long buf, unsigned long blocks, unsigned long first_block){ void __iomem *sdcmsc_base =dev->sdcmsc_base; int i; int result; unsigned int reg; // printk(KERN_ALERT "buf addr:0x%x\n", buf); // printk(KERN_ALERT "block num:%d\n", blocks); // printk(KERN_ALERT "first_block:%d\n", first_block); for(i=0; i < blocks; i++) { //Check for free receive buffers reg= ioread32(sdcmsc_base + SDCMSC_BD_BUFFER_STATUS); reg = cpu_to_le32(reg); reg >>= 8; reg &= 0xFF; if(reg == 0) { printk(KERN_ALERT "IO ERROR \n"); return -1; } // result = sdcmsc_card_queue(dev, 0, first_block, buf ); result = sdcmsc_card_queue(dev, 0, first_block+i, buf+i*512 ); if(!result){ printk(KERN_ALERT "IO ERROR \n"); return -1; } } return 1; } static int sdcmsc_disk_write(struct sdcmsc_card* dev, unsigned long buf, unsigned long blocks, unsigned long first_block){ void __iomem *sdcmsc_base = dev->sdcmsc_base; int i; int result; unsigned int reg; for(i = 0; i < blocks;i++) { //Check for free transmit buffers reg = ioread32(sdcmsc_base + SDCMSC_BD_BUFFER_STATUS); reg = cpu_to_le32(reg); reg &= 0xFF; if(reg == 0) { printk(KERN_ALERT "IO ERROR \n"); return -1; } //result = sdcmsc_card_queue(dev, 1, first_block, buf ); result = sdcmsc_card_queue(dev, 1, first_block+i, buf + i*512 ); if(!result){ printk(KERN_ALERT "IO ERROR \n"); return -1; } } return 1; } static void sdcmsc_transfer(struct sdcmsc_card *dev, unsigned long sector, unsigned long nsect, unsigned long buffer, int write) { if(write) sdcmsc_disk_write(dev, buffer, nsect, sector); else sdcmsc_disk_read(dev, buffer, nsect, sector); } static int sdcmsc_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { return 1; } static int sdcmsc_open(struct block_device *bdev, fmode_t mode) { // printk(KERN_ALERT "I'm in sdcmsc_open\n"); struct sdcmsc_card* dev= sdcmsc_blk_get(bdev->bd_disk); int ret = -ENXIO; mutex_lock(&block_mutex); if(dev){ if(dev->usage == 2) check_disk_change(bdev); ret = 0; } mutex_unlock(&block_mutex); // printk(KERN_ALERT "sdcmsc_open ok!\n"); return ret; } static int sdcmsc_release(struct gendisk *disk, fmode_t mode) { struct sdcmsc_card* dev = disk->private_data; mutex_lock(&block_mutex); sdcmsc_blk_put(dev); mutex_unlock(&block_mutex); return 0; } /*unsigned long bytes_to_sectors_checked(unsigned long size_bytes) { if(size_bytes%512) { printk(KERN_ALERT "What's the fuck!\n************"); } return size_bytes/512; }*/ static int sdcmsc_xfer_bio(struct sdcmsc_card* dev, struct bio* bio) { int i; unsigned long tmp=0; struct bio_vec *bvec; struct page *bv_page; unsigned long phy_addr; // int bvecNum =1; sector_t sector = bio->bi_sector; sector += 8192; /* Do each segment independently. */ bio_for_each_segment(bvec, bio, i){ // printk(KERN_ALERT "bvecNum:%d", bvecNum++); //char * buffer = __bio_kmap_atomic(bio, i, KM_USER0); // bv_page = bio_page(bio); bv_page = bvec->bv_page; phy_addr = page_to_phys(bv_page); phy_addr += bvec->bv_offset; // printk(KERN_ALERT "phy_addr:0x%x\n", phy_addr); // tmp=bytes_to_sectors_checked(bio_cur_bytes(bio)); // printk(KERN_ALERT "sector num:%d\n", tmp); // printk(KERN_ALERT "bv_len:%d\n", bvec->bv_len>>9); tmp = bvec->bv_len>>9; // printk(KERN_ALERT "direction:%d\n",bio_data_dir(bio)==WRITE); sdcmsc_transfer(dev, sector, /*bytes_to_sectors_checked(bio_cur_bytes(bio))*/tmp, phy_addr, bio_data_dir(bio) == WRITE); sector += /*(bytes_to_sectors_checked(bio_cur_bytes(bio)))*/tmp; //int j; /*for(j=0; j<512;j++) { printk(KERN_ALERT "%.2x\t", buffer[j]); }*/ //__bio_kunmap_atomic(bio, KM_USER0); } return 0; } static int sdcmsc_xfer_request(struct sdcmsc_card* dev, struct request *req) { struct bio *bio; unsigned long bytes_tranf=0; // int bioNum =1; __rq_for_each_bio(bio,req){ // printk(KERN_ALERT "bioNum:%d", bioNum++); sdcmsc_xfer_bio(dev, bio); bytes_tranf +=bio->bi_size; } return bytes_tranf; } static int sdcmsc_blk_issue_rq(struct mmc_queue *mq, struct request *req) { struct sdcmsc_card * dev = mq->data; unsigned long bytes_tranf =0; int ret =0; if(req) { if(req->cmd_type != REQ_TYPE_FS){ printk(KERN_ALERT "Skip non-fs request\n"); ret= -EIO; }else { bytes_tranf=sdcmsc_xfer_request(dev, req); } //__blk_end_request(req, 0,bytes_tranf); spin_lock_irq(&dev->lock); // __blk_end_request_cur(req, ret); __blk_end_request(req, 0,bytes_tranf); spin_unlock_irq(&dev->lock); } return 0; } static int sdcmsc_queue_thread(void *d) { struct mmc_queue *mq = d; struct request_queue *q = mq->queue; // current->flags |= PF_MEMALLOC; down(&mq->thread_sem); do{ struct request *req =NULL; spin_lock_irq(q->queue_lock); set_current_state(TASK_INTERRUPTIBLE); req = blk_fetch_request(q); mq->mqrq_cur = req; spin_unlock_irq(q->queue_lock); if(req || mq->mqrq_prev){ set_current_state(TASK_RUNNING); // printk(KERN_ALERT "before issue_fn"); mq->issue_fn(mq, req); } else { // printk( KERN_ALERT "I will sleep or stop"); if(kthread_should_stop()){ // printk(KERN_ALERT "I will stop"); set_current_state(TASK_RUNNING); break; } up(&mq->thread_sem); schedule(); // printk(KERN_ALERT "after schedule"); down(&mq->thread_sem); } mq->mqrq_prev = mq->mqrq_cur; mq->mqrq_cur = NULL; }while(1); up(&mq->thread_sem); return 0; } static void sdcmsc_request(struct request_queue *q) { struct mmc_queue *mq = q->queuedata; struct request *req; if(!mq) { while((req = blk_fetch_request(q)) != NULL) { req->cmd_flags |= REQ_QUIET; __blk_end_request_all(req, -EIO); } return; } // printk(KERN_ALERT "before wake_up_process"); if(!mq->mqrq_cur && !mq->mqrq_prev) { // printk(KERN_ALERT "I will wake up process"); wake_up_process(mq->thread); } } static int sdcmsc_card_cmd(void __iomem* sdcmsc_base,unsigned cmd, unsigned arg, unsigned *response){ // Send command to card cmd = le32_to_cpu(cmd); iowrite32(cmd, sdcmsc_base + SDCMSC_COMMAND); arg = le32_to_cpu(arg); iowrite32(arg, sdcmsc_base + SDCMSC_ARGUMENT); // Wait for response unsigned reg; unsigned mask = SDCMSC_NORMAL_INT_STATUS_EI | SDCMSC_NORMAL_INT_STATUS_CC; do { reg = ioread32(sdcmsc_base + SDCMSC_NORMAL_INT_STATUS); reg = cpu_to_le32(reg); } while(!(reg&mask)); iowrite32(0, sdcmsc_base + SDCMSC_NORMAL_INT_STATUS); //Optionally read response register if(response) { unsigned tmp; tmp = ioread32(sdcmsc_base + SDCMSC_RESPONSE); tmp = cpu_to_le32(tmp); *response =tmp; } // Check for errors if(reg & SDCMSC_NORMAL_INT_STATUS_EI) { reg = ioread32(sdcmsc_base + SDCMSC_ERROR_INT_STATUS); reg = cpu_to_le32(reg); if(reg & (1 << 3)) printk(KERN_ALERT "Command index error\n"); if(reg & (1 << 1)) printk(KERN_ALERT "Command CRC error\n"); if(reg & (1 << 0)) printk(KERN_ALERT "Command timeout\n"); iowrite32(0, sdcmsc_base+ SDCMSC_ERROR_INT_STATUS); return 0; } else{ return 1; } } int sdcmsc_dev_probe(void __iomem * sdcmsc_base) { unsigned cmd; unsigned reg; unsigned arg; unsigned card_capacity; unsigned int param; // Set highest possible timeout param = le32_to_cpu(0xFFFE); iowrite32(param,sdcmsc_base + SDCMSC_TIMEOUT); //Reset the peripheral param = le32_to_cpu(1); iowrite32(param, sdcmsc_base + SDCMSC_SOFTWARE_RESET); param = le32_to_cpu(2); iowrite32(param, sdcmsc_base + SDCMSC_CLOCK_DIVIDER); param = le32_to_cpu(0); iowrite32(param, sdcmsc_base + SDCMSC_SOFTWARE_RESET); //Send CMD0 to switch the card to idle state cmd = SDCMSC_COMMAND_CMDI(0); if(!sdcmsc_card_cmd(sdcmsc_base,cmd, 0, NULL)) return 0; // Send CMD8 offering 2.7V to 3.6V range // If the card doesn't response it means either: // 1. Card supports v2.0 but can't communicate using current voltage levels // 2. Card doesn't support v2.0 cmd = SDCMSC_COMMAND_CMDI(8) | SDCMSC_COMMAND_CICE | SDCMSC_COMMAND_CIRC | SDCMSC_COMMAND_RTS_48; sdcmsc_dev_p->is_v20 = sdcmsc_card_cmd(sdcmsc_base, cmd, 0x1AA, NULL); // if(sdcmsc_dev_p->is_v20) // printk(KERN_ALERT "This is sd version 2.0\n"); // else // printk(KERN_ALERT "This isn't sd version 2.0\n"); do { reg = ioread32(sdcmsc_base + SDCMSC_CARD_STATUS); reg = cpu_to_le32(reg); } while(reg & SDCMSC_CARD_STATUS_CICMD); // Repeat ACMD41 until card set the busy bit to 1 // Since ACMD is an extended command, it must be preceded // by CMD55 do { cmd = SDCMSC_COMMAND_CMDI(55) | SDCMSC_COMMAND_CICE | SDCMSC_COMMAND_CIRC | SDCMSC_COMMAND_RTS_48; if(!sdcmsc_card_cmd(sdcmsc_base, cmd, 0, NULL)) return 0; cmd = SDCMSC_COMMAND_CMDI(41) | SDCMSC_COMMAND_RTS_48; arg = sdcmsc_dev_p->is_v20 ? 0x40FF8000 : 0x00FF8000; if(!sdcmsc_card_cmd(sdcmsc_base, cmd, arg, ®)) return 0; } while(!(reg & 0x80000000)); sdcmsc_dev_p->is_sdhc = !!(reg & 0x40000000); // if(sdcmsc_dev_p->is_sdhc) // printk(KERN_ALERT "This is sdhc\n"); // else // printk(KERN_ALERT "This isn't sdhc\n"); // Issue CMD2 to switch from ready state to ident. Unfortunately, it is // not possible to read whole CID because the command can be issued only // once, and the peripheral can store only 32bit of the command at once. cmd = SDCMSC_COMMAND_CMDI(2) | SDCMSC_COMMAND_RTS_136; if(!sdcmsc_card_cmd(sdcmsc_base, cmd, 0, NULL)) return 0; //Issue CMD3 to get RCA and switch from ident state to stby cmd = SDCMSC_COMMAND_CMDI(3) | SDCMSC_COMMAND_CICE | SDCMSC_COMMAND_CIRC | SDCMSC_COMMAND_RTS_48; if(!sdcmsc_card_cmd(sdcmsc_base, cmd, 0, ®)) return 0; sdcmsc_dev_p->rca = reg & 0xFFFF0000; //Calculate card capacity. Use information stored in CSD register. if(sdcmsc_dev_p->is_sdhc) { cmd = SDCMSC_COMMAND_CMDI(9) | SDCMSC_COMMAND_CMDW(1) | SDCMSC_COMMAND_RTS_136; if(!sdcmsc_card_cmd(sdcmsc_base, cmd, sdcmsc_dev_p->rca, ®)) return 0; card_capacity = reg & 0x3F; card_capacity <<=16; cmd = SDCMSC_COMMAND_CMDI(9) | SDCMSC_COMMAND_CMDW(2) | SDCMSC_COMMAND_RTS_136; if(!sdcmsc_card_cmd(sdcmsc_base, cmd, sdcmsc_dev_p->rca, ®)) return 0; reg >>=16; card_capacity |= reg; card_capacity +=1; card_capacity *=1000; } else { cmd = SDCMSC_COMMAND_CMDI(9) | SDCMSC_COMMAND_CMDW(1) | SDCMSC_COMMAND_RTS_136; if(!sdcmsc_card_cmd(sdcmsc_base, cmd, sdcmsc_dev_p->rca, ®)) return 0; unsigned read_bl_len = (reg >>16) & 0x0F; unsigned c_size = reg & 0x3FF; c_size <<= 2; cmd = SDCMSC_COMMAND_CMDI(9) | SDCMSC_COMMAND_CMDW(2) | SDCMSC_COMMAND_RTS_136; if(!sdcmsc_card_cmd(sdcmsc_base, cmd, sdcmsc_dev_p->rca, ®)) return 0; c_size |= (reg >>30) & 0x03; unsigned c_size_mult = (reg >> 15) & 0x07; card_capacity = c_size + 1; card_capacity *= 1 << (c_size_mult + 2); card_capacity *= 1 << (read_bl_len); card_capacity >>= 9; } sdcmsc_dev_p->card_capacity = card_capacity; // printk( KERN_ALERT "card capacity:%d\n", sdcmsc_dev_p->card_capacity); // Put card in transfer state cmd = SDCMSC_COMMAND_CMDI(7) | SDCMSC_COMMAND_CICE | SDCMSC_COMMAND_CIRC | SDCMSC_COMMAND_RTS_48; if(!sdcmsc_card_cmd(sdcmsc_base, cmd, sdcmsc_dev_p->rca, ®)) return 0; if(reg != 0x700) return 0; // Set block size to 512 cmd = SDCMSC_COMMAND_CMDI(16) | SDCMSC_COMMAND_CICE | SDCMSC_COMMAND_CIRC | SDCMSC_COMMAND_RTS_48; if(!sdcmsc_card_cmd(sdcmsc_base, cmd ,512, NULL)) return 0; // Set 4-bits bus mode cmd = SDCMSC_COMMAND_CMDI(55) | SDCMSC_COMMAND_CICE | SDCMSC_COMMAND_CIRC | SDCMSC_COMMAND_RTS_48; if(!sdcmsc_card_cmd(sdcmsc_base, cmd, sdcmsc_dev_p->rca, NULL)) return 0; cmd = SDCMSC_COMMAND_CMDI(6) | SDCMSC_COMMAND_CICE | SDCMSC_COMMAND_CIRC | SDCMSC_COMMAND_RTS_48; if(!sdcmsc_card_cmd(sdcmsc_base, cmd, 0x02, NULL)) return 0; // printk(KERN_ALERT "test done!\n"); return 1; } int sdcmsc_init_queue(struct mmc_queue *mq, spinlock_t *lock ) { int ret; mq->queue = blk_init_queue(sdcmsc_request, lock); if(!mq->queue) return -ENOMEM; mq->mqrq_cur = &mq->mqrq[0]; mq->mqrq_prev = &mq->mqrq[1]; mq->queue->queuedata = mq; sema_init(&mq->thread_sem, 1); mq->thread = kthread_run(sdcmsc_queue_thread, mq, "sdcmscThread"); if(IS_ERR(mq->thread)){ ret = PTR_ERR(mq->thread); goto cleanup_queue; } return 0; cleanup_queue: blk_cleanup_queue(mq->queue); return ret; } int sdcmsc_irq_init(void __iomem* sdcmsc_base) { iowrite32(0,sdcmsc_base+ SDCMSC_NORMAL_INT_ENABLE); iowrite32(0, sdcmsc_base+SDCMSC_ERROR_INT_ENABLE); iowrite32(le32_to_cpu(0xFF),sdcmsc_base+ SDCMSC_DAT_INT_ENABLE); iowrite32(0, sdcmsc_base + SDCMSC_DAT_INT_STATUS); return 1; } static struct block_device_operations sdcmsc_ops = { .owner = THIS_MODULE, .open = sdcmsc_open, .release= sdcmsc_release, //.media_changed = sdcmsc_media_changed, //.revalidate_disk = sdcmsc_revalidate, .ioctl = sdcmsc_ioctl }; void sdcmsc_cleanup_queue(struct mmc_queue *mq) { struct request_queue *q = mq->queue; unsigned long flags; /* Then terminate our worker thread */ kthread_stop(mq->thread); /* Empty the queue */ spin_lock_irqsave(q->queue_lock, flags); q->queuedata = NULL; blk_start_queue(q); spin_unlock_irqrestore(q->queue_lock, flags); } int sdcmsc_dev_init(void) { int ret, err; if(!request_mem_region(SDCMSC_BASE,SDCMSC_ADR_LEN,"ocores-sdcmsc")) { printk(KERN_ALERT "ocores-sdcmsc request_mem_region fails!"); goto out; } sdcmsc_dev_p->sdcmsc_base= ioremap(SDCMSC_BASE,SDCMSC_ADR_LEN); // printk(KERN_ALERT "sdcmsc_dev_p->sdcmsc_base:0x%x\n", sdcmsc_dev_p->sdcmsc_base); if(!sdcmsc_dev_p->sdcmsc_base) { printk(KERN_ALERT "ocores-sdcmsc ioremap failed!"); goto out_release_mem_region; } if(!sdcmsc_dev_probe(sdcmsc_dev_p->sdcmsc_base)) goto out_iounmap; sdcmsc_dev_p->irq_dat = SDCMSC_DAT_INT_NO; sdcmsc_irq_init(sdcmsc_dev_p->sdcmsc_base); // printk(KERN_ALERT "before request_irq"); err = request_irq(SDCMSC_DAT_INT_NO, sdcmsc_irq_dat, IRQF_DISABLED, "sdcmsc", sdcmsc_dev_p); if(err) { printk(KERN_ALERT "request irq error!"); goto out_iounmap; } spin_lock_init(&sdcmsc_dev_p->lock); sdcmsc_init_queue(&sdcmsc_dev_p->mq, &sdcmsc_dev_p->lock); if(ret) goto out_freeirq; sdcmsc_dev_p->mq.issue_fn = sdcmsc_blk_issue_rq; sdcmsc_dev_p->mq.data = sdcmsc_dev_p; blk_queue_logical_block_size(sdcmsc_dev_p->mq.queue, 512); sdcmsc_dev_p->gd = alloc_disk(/*SDCMSC_MINORS*/1); if(!sdcmsc_dev_p->gd) { printk(KERN_ALERT "alloc_disk failure\n"); goto out_cleanqueue; } sdcmsc_dev_p->gd->major = MMC_BLOCK_MAJOR; sdcmsc_dev_p->gd->first_minor = 0; sdcmsc_dev_p->gd->fops = &sdcmsc_ops; snprintf(sdcmsc_dev_p->gd->disk_name, 32, "sdcmsc"); sdcmsc_dev_p->gd->queue = sdcmsc_dev_p->mq.queue; set_capacity(sdcmsc_dev_p->gd, sdcmsc_dev_p->card_capacity); sdcmsc_dev_p->gd->private_data = sdcmsc_dev_p; sdcmsc_dev_p->usage = 1; // printk(KERN_ALERT "Before add_disk"); add_disk(sdcmsc_dev_p->gd); // printk(KERN_ALERT "OK after add_disk\n"); return 1; out_cleanqueue: sdcmsc_cleanup_queue(&sdcmsc_dev_p->mq); out_freeirq: free_irq(SDCMSC_DAT_INT_NO, sdcmsc_dev_p); out_iounmap: iounmap(sdcmsc_dev_p->sdcmsc_base); out_release_mem_region: release_mem_region(SDCMSC_BASE, SDCMSC_ADR_LEN); out: return -1; } static int ocores_sdcmsc_init(void) { int res; res = register_blkdev(MMC_BLOCK_MAJOR, "mmc"); if (res) goto out; sdcmsc_dev_p = kzalloc(sizeof(struct sdcmsc_card), GFP_KERNEL); if(sdcmsc_dev_p == NULL) goto out_unregister; res=sdcmsc_dev_init(); if(res < 0) goto out_kfree; return 0; out_kfree: kfree(sdcmsc_dev_p); out_unregister: unregister_blkdev(MMC_BLOCK_MAJOR, "mmc"); out: return res; } static void ocores_sdcmsc_exit(void) { del_gendisk(sdcmsc_dev_p->gd); put_disk(sdcmsc_dev_p->gd); sdcmsc_cleanup_queue(&sdcmsc_dev_p->mq); unregister_blkdev(MMC_BLOCK_MAJOR, "mmc"); } module_init(ocores_sdcmsc_init); module_exit(ocores_sdcmsc_exit);
/* * rill create at 2013-09-18 * [email protected] */ #ifndef MMC_BLOCK_MAJOR #define MMC_BLOCK_MAJOR 179 #endif #define SDCMSC_MINORS 4 // SDCMSC address space #define SDCMSC_BASE 0x9e000000 #define SDCMSC_ADR_LEN 0xa0 // Register space #define SDCMSC_ARGUMENT 0x00 #define SDCMSC_COMMAND 0x04 #define SDCMSC_CARD_STATUS 0x08 #define SDCMSC_RESPONSE 0x0C #define SDCMSC_CONTROLLER_SETTING 0x1C #define SDCMSC_BLOCK_SIZE 0x20 #define SDCMSC_POWER_CONTROL 0x24 #define SDCMSC_SOFTWARE_RESET 0x28 #define SDCMSC_TIMEOUT 0x2C #define SDCMSC_NORMAL_INT_STATUS 0x30 #define SDCMSC_ERROR_INT_STATUS 0x34 #define SDCMSC_NORMAL_INT_ENABLE 0x38 #define SDCMSC_ERROR_INT_ENABLE 0x3C #define SDCMSC_CAPABILITY 0x48 #define SDCMSC_CLOCK_DIVIDER 0x4C #define SDCMSC_BD_BUFFER_STATUS 0x50 #define SDCMSC_DAT_INT_STATUS 0x54 #define SDCMSC_DAT_INT_ENABLE 0x58 #define SDCMSC_BD_RX 0x60 #define SDCMSC_BD_TX 0x80 // SDCMSC_COMMAND bits #define SDCMSC_COMMAND_CMDI(x) (x << 8) #define SDCMSC_COMMAND_CMDW(x) (x << 6) #define SDCMSC_COMMAND_CICE 0x10 #define SDCMSC_COMMAND_CIRC 0x08 #define SDCMSC_COMMAND_RTS_48 0x02 #define SDCMSC_COMMAND_RTS_136 0x01 //SDCMSC_CARD_STATUS bits #define SDCMSC_CARD_STATUS_CICMD 0x01 // SDCMSC_NORMAL_INT_STATUS bits #define SDCMSC_NORMAL_INT_STATUS_EI 0x8000 #define SDCMSC_NORMAL_INT_STATUS_CC 0x0001 // SDCMSC_DAT_INT_STATUS #define SDCMSC_DAT_INT_STATUS_TRS 0x01 #define SDCMSC_DAT_INT_NO 16 struct mmc_queue { //struct mmc_card *card; struct task_struct *thread; struct semaphore thread_sem; unsigned int flags; int (*issue_fn)(struct mmc_queue *, struct request *); void *data; struct request_queue *queue; struct request mqrq[2]; struct request *mqrq_cur; struct request *mqrq_prev; }; struct sdcmsc_card { spinlock_t lock; struct mmc_queue mq; struct gendisk *gd; void __iomem * sdcmsc_base; unsigned int rca; /* relative card address of device */ int is_v20; int is_sdhc; int connected; unsigned card_capacity; unsigned int usage; int irq_dat; };
ifneq ($(KERNELRELEASE), ) obj-m := sdcmsc.o else KERNELDIR ?= /home/openrisc/soc-design/linux PWD := $(shell pwd) default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules ARCH=openrisc CROSS_COMPILE=or32-linux- clean: rm -rf .*.cmd *.o *.mod.c *.ko .tm_versions *.order *.symvers endif
关于驱动模块的加载步骤,之前已经介绍过了,这里不再赘述,如有疑问请参考: http://blog.csdn.net/rill_zhen/article/details/8700937
需要注意的是,在ko模块加载成功之后,需要使用mount命令挂载SD卡。
如果一切顺利的话,我们可以事先用电脑向SD卡里存放一些文件,然后插到ORPSoC的FPGA开发板上进行测试。
测试过程中使用的命令如下:
# mount -t nfs -o nolock 192.168.1.101:/home/openrisc/nfs nfs # insmod sdcmsc.ko # cd .. # mkdir sdcmsc # mount -t vfat /dev/sdcmsc /sdcmsc/ # cd sdcmsc/ # ls # cat boot_record.txt # ls We Are The Champions.mp3 fatfs1.c boot_record.txt presentation.pdf # cp presentation.pdf presentation_back.pdf # ls # cat fatfs1.c # cp We\ Are\ The\ Champions.mp3 We_gss.mp3 # ls # ls -l
下面是整个测试过程中的终端完整打印结果,通过和电脑中事先存放的文件,进行对比,可以确认所有操作都已经正确执行了。
openrisc@openrisc-VirtualBox:~$ picocom --b 115200 --p n --d 8 --f xon /dev/ttyUSB2 picocom v1.4 port is : /dev/ttyUSB2 flowcontrol : xon/xoff baudrate is : 115200 parity is : none databits are : 8 escape is : C-a noinit is : no noreset is : no nolock is : no send_cmd is : ascii_xfr -s -v -l10 receive_cmd is : rz -vv Terminal ready Compiled-in FDT at 0xc02b04e0 Linux version 3.1.0-rc6-00002-g0da8eb1-dirty (openrisc@openrisc-VirtualBox) (gcc version 4.5.1-or32-1.0rc4 (OpenRISC 32-bit toolchain for or32-linux (built 20111017)) ) #76 Mon Aug 26 14:38:03 CEST 2013 CPU: OpenRISC-12 (revision 8) @50 MHz -- dcache: 4096 bytes total, 16 bytes/line, 1 way(s) -- icache: 8192 bytes total, 16 bytes/line, 1 way(s) -- dmmu: 64 entries, 1 way(s) -- immu: 64 entries, 1 way(s) -- additional features: -- debug unit -- PIC -- timer setup_memory: Memory: 0x0-0x2000000 Reserved - 0x01ffda90-0x00002570 Setting up paging and PTEs. map_ram: Memory: 0x0-0x2000000 On node 0 totalpages: 4096 free_area_init_node: node 0, pgdat c0294bd0, node_mem_map c0410000 Normal zone: 16 pages used for memmap Normal zone: 0 pages reserved Normal zone: 4080 pages, LIFO batch:0 dtlb_miss_handler c0002000 itlb_miss_handler c0002108 OpenRISC Linux -- http://openrisc.net pcpu-alloc: s0 r0 d32768 u32768 alloc=1*32768 pcpu-alloc: [0] 0 Built 1 zonelists in Zone order, mobility grouping off. Total pages: 4080 Kernel command line: console=uart,mmio,0x90000000,115200 Early serial console at MMIO 0x90000000 (options '115200') bootconsole [uart0] enabled PID hash table entries: 128 (order: -4, 512 bytes) Dentry cache hash table entries: 4096 (order: 1, 16384 bytes) Inode-cache hash table entries: 2048 (order: 0, 8192 bytes) Memory: 28376k/32768k available (2307k kernel code, 4392k reserved, 338k data, 1416k init, 0k highmem) mem_init_done ........................................... NR_IRQS:32 100.00 BogoMIPS (lpj=500000) pid_max: default: 32768 minimum: 301 Mount-cache hash table entries: 1024 gss done after type->mount gss done before return in mount_fs gss done after type->mount gss done before return in mount_fs gss done after type->mount gss done before return in mount_fs gss done after type->mount gss done before return in mount_fs gss done after type->mount gss done before return in mount_fs gss done after type->mount gss done before return in mount_fs devtmpfs: initialized gss done after type->mount gss done before return in mount_fs NET: Registered protocol family 16 bio: create slab <bio-0> at 0 Switching to clocksource openrisc_timer gss done after type->mount gss done before return in mount_fs gss done after type->mount Switched to NOHz mode on CPU #0 gss done before return in mount_fs NET: Registered protocol family 2 IP route cache hash table entries: 2048 (order: 0, 8192 bytes) TCP established hash table entries: 1024 (order: 0, 8192 bytes) TCP bind hash table entries: 1024 (order: -1, 4096 bytes) TCP: Hash tables configured (established 1024 bind 1024) TCP reno registered UDP hash table entries: 512 (order: 0, 8192 bytes) UDP-Lite hash table entries: 512 (order: 0, 8192 bytes) NET: Registered protocol family 1 RPC: Registered named UNIX socket transport module. RPC: Registered udp transport module. RPC: Registered tcp transport module. RPC: Registered tcp NFSv4.1 backchannel transport module. Unpacking initramfs gss done after type->mount gss done before return in mount_fs gss done after type->mount gss done before return in mount_fs Block layer SCSI generic (bsg) driver version 0.4 loaded (major 254) io scheduler noop registered io scheduler deadline registered io scheduler cfq registered (default) Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled 90000000.serial: ttyS0 at MMIO 0x90000000 (irq = 2) is a 16550A console [ttyS0] enabled, bootconsole disabled console [ttyS0] enabled, bootconsole disabled ethoc-mdio: probed NET: Registered protocol family 17 Freeing unused kernel memory: 1416k freed init started: BusyBox v1.19.0.git (2011-02-16 08:10:12 CET) gss done after type->mount gss done before return in mount_fs gss done after type->mount gss done before return in mount_fs gss done after type->mount gss done before return in mount_fsConfiguring loopback device rill add to mount nfs 2013-04-10 <--mount start--> gss done after type->mount gss done before return in mount_fsmount: RPC: Unable to receive; errno = Connection refused mount: mounting 192.168.1.101:/home/openrisc/nfs on nfs failed: Bad file descriptor <--mount end--> Please press Enter to activate this console. # mount -t nfs -o nolock 192.168.1.101:/home/openrisc/nfs nfs gss done after type->mount gss done before return in mount_fs# cd nfs # insmod sdcmsc.ko # cd .. # mkdir sdcmsc # mount -t vfat /dev/sdcmsc /sdcmsc/ b->fats:2 b->fat32_length:-383975424 gss done after fill_super gss done before mount_bdev gss done after type->mount gss done before return in mount_fs# # cd sdcmsc/ # ls We Are The Champions.mp3 fatfs1.c boot_record.txt presentation.pdf # cat boot_record.txt openrisc@openrisc-VirtualBox:~/share/ecos_sdc_test$ picocom --b 115200 --p n --d 8 --f xon /dev/ttyUSB2 picocom v1.4 port is : /dev/ttyUSB2 flowcontrol : xon/xoff baudrate is : 115200 parity is : none databits are : 8 escape is : C-a noinit is : no noreset is : no nolock is : no send_cmd is : ascii_xfr -s -v -l10 receive_cmd is : rz -vv Terminal ready is_v20:0x1 is_sdhc:0x0 rca:0xe6240000 card capacity:0x3af000 sdc init success! sddr:0x10e00,sector:135-------------> tmp[0]:0xeb tmp[1]:0x58 tmp[2]:0x90 tmp[3]:0x4d tmp[4]:0x53 tmp[5]:0x44 tmp[6]:0x4f tmp[7]:0x53 tmp[8]:0x35 tmp[9]:0x2e tmp[10]:0x30 tmp[11]:0x0 tmp[12]:0x2 tmp[13]:0x1 tmp[14]:0x7e tmp[15]:0x18 tmp[16]:0x2 tmp[17]:0x0 tmp[18]:0x0 tmp[19]:0x0 tmp[20]:0x0 tmp[21]:0xf8 tmp[22]:0x0 tmp[23]:0x0 tmp[24]:0x3f tmp[25]:0x0 tmp[26]:0xff tmp[27]:0x0 tmp[28]:0x87 tmp[29]:0x0 tmp[30]:0x0 tmp[31]:0x0 tmp[32]:0x39 tmp[33]:0xe0 tmp[34]:0x3a tmp[35]:0x0 tmp[36]:0xc1 tmp[37]:0x73 tmp[38]:0x0 tmp[39]:0x0 tmp[40]:0x0 tmp[41]:0x0 tmp[42]:0x0 tmp[43]:0x0 tmp[44]:0x2 tmp[45]:0x0 tmp[46]:0x0 tmp[47]:0x0 tmp[48]:0x1 tmp[49]:0x0 tmp[50]:0x6 tmp[51]:0x0 tmp[52]:0x0 tmp[53]:0x0 tmp[54]:0x0 tmp[55]:0x0 tmp[56]:0x0 tmp[57]:0x0 tmp[58]:0x0 tmp[59]:0x0 tmp[60]:0x0 tmp[61]:0x0 tmp[62]:0x0 tmp[63]:0x0 tmp[64]:0x80 tmp[65]:0x0 tmp[66]:0x29 tmp[67]:0x36 tmp[68]:0x8d tmp[69]:0x5a tmp[70]:0x76 tmp[71]:0x4e tmp[72]:0x4f tmp[73]:0x20 tmp[74]:0x4e tmp[75]:0x41 tmp[76]:0x4d tmp[77]:0x45 tmp[78]:0x20 tmp[79]:0x20 tmp[80]:0x20 tmp[81]:0x20 tmp[82]:0x46 tmp[83]:0x41 tmp[84]:0x54 tmp[85]:0x33 tmp[86]:0x32 tmp[87]:0x20 tmp[88]:0x20 tmp[89]:0x20 tmp[90]:0x96 tmp[91]:0xc tmp[92]:0x0 tmp[93]:0x0 tmp[94]:0x0 tmp[95]:0x5a tmp[96]:0x0 tmp[97]:0x0 tmp[98]:0x0 tmp[99]:0x0 tmp[100]:0x0 tmp[101]:0x2 tmp[102]:0xfc tmp[103]:0xf8 tmp[104]:0x0 tmp[105]:0x2 tmp[106]:0xae tmp[107]:0x78 tmp[108]:0x0 tmp[109]:0x2 tmp[110]:0xfd tmp[111]:0x3c tmp[112]:0x0 tmp[113]:0x2 tmp[114]:0x96 tmp[115]:0x19 tmp[116]:0x11 tmp[117]:0x11 tmp[118]:0x0 tmp[119]:0x18 tmp[120]:0x11 tmp[121]:0x11 tmp[122]:0x0 tmp[123]:0x1a tmp[124]:0x11 tmp[125]:0x11 tmp[126]:0x0 tmp[127]:0x1c tmp[128]:0x11 tmp[129]:0x11 tmp[130]:0x0 tmp[131]:0x1e tmp[132]:0x0 tmp[133]:0x2 tmp[134]:0xf2 tmp[135]:0xec tmp[136]:0x0 tmp[137]:0x0 tmp[138]:0xf4 tmp[139]:0x64 tmp[140]:0x0 tmp[141]:0x0 tmp[142]:0x0 tmp[143]:0x0 tmp[144]:0x0 tmp[145]:0x0 tmp[146]:0x0 tmp[147]:0x0 tmp[148]:0x0 tmp[149]:0x0 tmp[150]:0x0 tmp[151]:0x0 tmp[152]:0x0 tmp[153]:0x0 tmp[154]:0x0 tmp[155]:0x0 tmp[156]:0x0 tmp[157]:0x0 tmp[158]:0x0 tmp[159]:0x0 tmp[160]:0x0 tmp[161]:0x0 tmp[162]:0x0 tmp[163]:0x0 tmp[164]:0x0 tmp[165]:0x0 tmp[166]:0x0 tmp[167]:0x0 tmp[168]:0x0 tmp[169]:0x0 tmp[170]:0x0 tmp[171]:0x0 tmp[172]:0x0 tmp[173]:0x0 tmp[174]:0x0 tmp[175]:0x0 tmp[176]:0x0 tmp[177]:0x0 tmp[178]:0x0 tmp[179]:0x0 tmp[180]:0x0 tmp[181]:0x0 tmp[182]:0x0 tmp[183]:0x0 tmp[184]:0x0 tmp[185]:0x0 tmp[186]:0x0 tmp[187]:0x0 tmp[188]:0x0 tmp[189]:0x0 tmp[190]:0x0 tmp[191]:0x0 tmp[192]:0x0 tmp[193]:0x0 tmp[194]:0x0 tmp[195]:0x0 tmp[196]:0x0 tmp[197]:0x0 tmp[198]:0x0 tmp[199]:0x0 tmp[200]:0x0 tmp[201]:0x2 tmp[202]:0xad tmp[203]:0x78 tmp[204]:0x0 tmp[205]:0x2 tmp[206]:0xae tmp[207]:0x78 tmp[208]:0x0 tmp[209]:0x2 tmp[210]:0xae tmp[211]:0x18 tmp[212]:0x0 tmp[213]:0x2 tmp[214]:0x96 tmp[215]:0x1b tmp[216]:0x0 tmp[217]:0x2 tmp[218]:0x96 tmp[219]:0xc tmp[220]:0x0 tmp[221]:0x2 tmp[222]:0xf3 tmp[223]:0x8 tmp[224]:0x0 tmp[225]:0x0 tmp[226]:0xd1 tmp[227]:0x68 tmp[228]:0x0 tmp[229]:0x2 tmp[230]:0xd3 tmp[231]:0x10 tmp[232]:0x11 tmp[233]:0x11 tmp[234]:0x0 tmp[235]:0x10 tmp[236]:0x11 tmp[237]:0x11 tmp[238]:0x0 tmp[239]:0x12 tmp[240]:0x11 tmp[241]:0x11 tmp[242]:0x0 tmp[243]:0x14 tmp[244]:0x11 tmp[245]:0x11 tmp[246]:0x0 tmp[247]:0x16 tmp[248]:0x0 tmp[249]:0x2 tmp[250]:0xf3 tmp[251]:0x94 tmp[252]:0x0 tmp[253]:0x0 tmp[254]:0x90 tmp[255]:0xa4 tmp[256]:0x0 tmp[257]:0x0 tmp[258]:0x0 tmp[259]:0x0 tmp[260]:0x0 tmp[261]:0x0 tmp[262]:0x0 tmp[263]:0x0 tmp[264]:0x0 tmp[265]:0x0 tmp[266]:0x0 tmp[267]:0x0 tmp[268]:0x0 tmp[269]:0x0 tmp[270]:0x0 tmp[271]:0x0 tmp[272]:0x0 tmp[273]:0x0 tmp[274]:0x0 tmp[275]:0x0 tmp[276]:0x0 tmp[277]:0x0 tmp[278]:0x0 tmp[279]:0x0 tmp[280]:0x0 tmp[281]:0x0 tmp[282]:0x0 tmp[283]:0x0 tmp[284]:0x0 tmp[285]:0x2 tmp[286]:0xf3 tmp[287]:0xb0 tmp[288]:0x0 tmp[289]:0x2 tmp[290]:0xf3 tmp[291]:0xb0 tmp[292]:0x0 tmp[293]:0x2 tmp[294]:0xd3 tmp[295]:0x10 tmp[296]:0x11 tmp[297]:0x11 tmp[298]:0x0 tmp[299]:0x4 tmp[300]:0x11 tmp[301]:0x11 tmp[302]:0x0 tmp[303]:0x5 tmp[304]:0x11 tmp[305]:0x11 tmp[306]:0x0 tmp[307]:0x6 tmp[308]:0x11 tmp[309]:0x11 tmp[310]:0x0 tmp[311]:0x7 tmp[312]:0x11 tmp[313]:0x11 tmp[314]:0x0 tmp[315]:0x8 tmp[316]:0x0 tmp[317]:0x1 tmp[318]:0x8d tmp[319]:0xf0 tmp[320]:0x11 tmp[321]:0x11 tmp[322]:0x0 tmp[323]:0xa tmp[324]:0x11 tmp[325]:0x11 tmp[326]:0x0 tmp[327]:0xb tmp[328]:0x11 tmp[329]:0x11 tmp[330]:0x0 tmp[331]:0xc tmp[332]:0x11 tmp[333]:0x11 tmp[334]:0x0 tmp[335]:0xd tmp[336]:0x11 tmp[337]:0x11 tmp[338]:0x0 tmp[339]:0xe tmp[340]:0x11 tmp[341]:0x11 tmp[342]:0x0 tmp[343]:0xf tmp[344]:0x11 tmp[345]:0x11 tmp[346]:0x0 tmp[347]:0x10 tmp[348]:0x11 tmp[349]:0x11 tmp[350]:0x0 tmp[351]:0x11 tmp[352]:0x11 tmp[353]:0x11 tmp[354]:0x0 tmp[355]:0x12 tmp[356]:0x11 tmp[357]:0x11 tmp[358]:0x0 tmp[359]:0x13 tmp[360]:0x11 tmp[361]:0x11 tmp[362]:0x0 tmp[363]:0x14 tmp[364]:0xff tmp[365]:0xff tmp[366]:0xff tmp[367]:0xff tmp[368]:0x0 tmp[369]:0x2 tmp[370]:0xd3 tmp[371]:0x10 tmp[372]:0x11 tmp[373]:0x11 tmp[374]:0x0 tmp[375]:0x10 tmp[376]:0x11 tmp[377]:0x11 tmp[378]:0x0 tmp[379]:0x12 tmp[380]:0x11 tmp[381]:0x11 tmp[382]:0x0 tmp[383]:0x14 tmp[384]:0x11 tmp[385]:0x11 tmp[386]:0x0 tmp[387]:0x16 tmp[388]:0x0 tmp[389]:0x2 tmp[390]:0xf3 tmp[391]:0xa4 tmp[392]:0x0 tmp[393]:0x2 tmp[394]:0x53 tmp[395]:0xc8 tmp[396]:0x0 tmp[397]:0x2 tmp[398]:0x9b tmp[399]:0x52 tmp[400]:0x0 tmp[401]:0x0 tmp[402]:0x0 tmp[403]:0x0 tmp[404]:0x0 tmp[405]:0x2 tmp[406]:0xf3 tmp[407]:0xb0 tmp[408]:0x0 tmp[409]:0x1 tmp[410]:0x8e tmp[411]:0x24 tmp[412]:0x11 tmp[413]:0x11 tmp[414]:0x0 tmp[415]:0xe tmp[416]:0x0 tmp[417]:0x2 tmp[418]:0xf3 tmp[419]:0xb0 tmp[420]:0x0 tmp[421]:0x1 tmp[422]:0x8d tmp[423]:0xf0 tmp[424]:0x0 tmp[425]:0x1 tmp[426]:0x8d tmp[427]:0xf0 tmp[428]:0x0 tmp[429]:0x0 tmp[430]:0x0 tmp[431]:0x0 tmp[432]:0x0 tmp[433]:0x2 tmp[434]:0xf3 tmp[435]:0xbc tmp[436]:0x0 tmp[437]:0x0 tmp[438]:0x0 tmp[439]:0x0 tmp[440]:0x0 tmp[441]:0x0 tmp[442]:0x0 tmp[443]:0x0 tmp[444]:0x0 tmp[445]:0x0 tmp[446]:0x0 tmp[447]:0x0 tmp[448]:0x0 tmp[449]:0x0 tmp[450]:0x0 tmp[451]:0x0 tmp[452]:0x0 tmp[453]:0x0 tmp[454]:0x0 tmp[455]:0x1 tmp[456]:0x0 tmp[457]:0x0 tmp[458]:0x0 tmp[459]:0x0 tmp[460]:0x0 tmp[461]:0x0 tmp[462]:0x0 tmp[463]:0x0 tmp[464]:0x0 tmp[465]:0x0 tmp[466]:0x0 tmp[467]:0x0 tmp[468]:0x0 tmp[469]:0x0 tmp[470]:0x0 tmp[471]:0x0 tmp[472]:0x0 tmp[473]:0x0 tmp[474]:0x0 tmp[475]:0x0 tmp[476]:0x0 tmp[477]:0x0 tmp[478]:0x0 tmp[479]:0x0 tmp[480]:0x0 tmp[481]:0x0 tmp[482]:0x0 tmp[483]:0x0 tmp[484]:0x0 tmp[485]:0x0 tmp[486]:0x0 tmp[487]:0x0 tmp[488]:0x0 tmp[489]:0x0 tmp[490]:0x0 tmp[491]:0x1 tmp[492]:0x0 tmp[493]:0x0 tmp[494]:0x0 tmp[495]:0x0 tmp[496]:0x0 tmp[497]:0x0 tmp[498]:0x0 tmp[499]:0x0 tmp[500]:0x0 tmp[501]:0x0 tmp[502]:0x0 tmp[503]:0x0 tmp[504]:0x0 tmp[505]:0x0 tmp[506]:0x0 tmp[507]:0x0 tmp[508]:0x0 tmp[509]:0x0 tmp[510]:0x0 tmp[511]:0x1 data:0x2f208 fatfs boot record:---> sig:0x29 marker0:0x55 marker1:0xaa jump:0x58eb oem_name[0]:M oem_name[1]:S oem_name[2]:D oem_name[3]:O oem_name[4]:S oem_name[5]:5 oem_name[6]:. oem_name[7]:0 bytes_per_sec:0x200 sec_per_clu:0x1 res_sec_num:0x187e fat_tbls_num:0x2 max_root_dents:0x0 sec_num_32:0x0 media_desc:0xf8 sec_per_fat:0x0 sec_per_track:0x3f heads_num:0xff hsec_num:0x87 sec_num:0x3ae039 sec_num_32:0x0 sec_num_32:0x0 marker0:0x55 marker1:0xaa sec_per_fat_32:0x73c1 ext_flags:0x0 fs_ver:0x0 root_cluster:0x2 fs_info_sec:0x1 bk_boot_sec:0x6 drv_num:0x80 ext_sig:0x29 ser_num:0x765a8d36 vol_name[0]:N vol_name[1]:O vol_name[2]: vol_name[3]:N vol_name[4]:A vol_name[5]:M vol_name[6]:E vol_name[7]: vol_name[8]: vol_name[9]: vol_name[10]: fat_name[0]:F fat_name[1]:A fat_name[2]:T fat_name[3]:3 fat_name[4]:2 fat_name[5]: fat_name[6]: fat_name[7]: mount done! # ls We Are The Champions.mp3 fatfs1.c boot_record.txt presentation.pdf # cp presentation.pdf presentation_back.pdf # ls We Are The Champions.mp3 fatfs1.c presentation_back.pdf boot_record.txt presentation.pdf # cat fatfs1.c //========================================================================== // // fatfs1.c // // Test fileio system // //========================================================================== // ####ECOSGPLCOPYRIGHTBEGIN#### // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc. // // eCos 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 or (at your option) any later // version. // // eCos 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 eCos; if not, write to the Free Software Foundation, Inc., // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // As a special exception, if other files instantiate templates or use // macros or inline functions from this file, or you compile this file // and link it with other works to produce a work based on this file, // this file does not by itself cause the resulting work to be covered by // the GNU General Public License. However the source code for this file // must still be made available in accordance with section (3) of the GNU // General Public License v2. // // This exception does not invalidate any other reasons why a work based // on this file might be covered by the GNU General Public License. // ------------------------------------------- // ####ECOSGPLCOPYRIGHTEND#### //========================================================================== //#####DESCRIPTIONBEGIN#### // // Author(s): nickg // Contributors: nickg // Date: 2000-05-25 // Purpose: Test fileio system // Description: This test uses the testfs to check out the initialization // and basic operation of the fileio system // // // // // // // //####DESCRIPTIONEND#### // //========================================================================== #include <pkgconf/hal.h> #include <pkgconf/io_fileio.h> #include <pkgconf/fs_fat.h> #include <cyg/infra/cyg_trac.h> // tracing macros #include <cyg/infra/cyg_ass.h> // assertion macros #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> #include <errno.h> #include <string.h> #include <dirent.h> #include <stdio.h> #include <cyg/fileio/fileio.h> #include <cyg/infra/testcase.h> #include <cyg/infra/diag.h> // HAL polled output #include <cyg/fs/fatfs.h> //========================================================================== #define SHOW_RESULT( _fn, _res ) \ diag_printf("<FAIL>: " #_fn "() returned %d %s\n", _res, _res<0?strerror(errno):""); //========================================================================== #define IOSIZE 100 #define LONGNAME1 "long_file_name_that_should_take_up_more_than_one_directory_entry_1" #define LONGNAME2 "long_file_name_that_should_take_up_more_than_one_directory_entry_2" //========================================================================== #ifndef CYGPKG_LIBC_STRING char *strcat( char *s1, const char *s2 ) { char *s = s1; while( *s1 ) s1++; while( (*s1++ = *s2++) != 0); return s; } #endif //========================================================================== static void listdir( char *name, int statp, int numexpected, int *numgot ) { int err; DIR *dirp; int num=0; diag_printf("<INFO>: reading directory %s\n",name); dirp = opendir( name ); if( dirp == NULL ) SHOW_RESULT( opendir, -1 ); for(;;) { struct dirent *entry = readdir( dirp ); if( entry == NULL ) break; num++; diag_printf("<INFO>: entry %14s",entry->d_name); #ifdef CYGPKG_FS_FAT_RET_DIRENT_DTYPE diag_printf(" d_type %2x", entry->d_type); #endif if( statp ) { char fullname[PATH_MAX]; struct stat sbuf; if( name[0] ) { strcpy(fullname, name ); if( !(name[0] == '/' && name[1] == 0 ) ) strcat(fullname, "/" ); } else fullname[0] = 0; strcat(fullname, entry->d_name ); err = stat( fullname, &sbuf ); if( err < 0 ) { if( errno == ENOSYS ) diag_printf(" <no status available>"); else SHOW_RESULT( stat, err ); } else { diag_printf(" [mode %08x ino %08x nlink %d size %ld]", sbuf.st_mode,sbuf.st_ino,sbuf.st_nlink,(long)sbuf.st_size); } #ifdef CYGPKG_FS_FAT_RET_DIRENT_DTYPE if ((entry->d_type & S_IFMT) != (sbuf.st_mode & S_IFMT)) CYG_TEST_FAIL("File mode's don't match between dirent and stat"); #endif } diag_printf("\n"); } err = closedir( dirp ); if( err < 0 ) SHOW_RESULT( stat, err ); if (numexpected >= 0 && num != numexpected) CYG_TEST_FAIL("Wrong number of dir entries\n"); if ( numgot != NULL ) *numgot = num; } //========================================================================== static void createfile( char *name, size_t size ) { char buf[IOSIZE]; int fd; ssize_t wrote; int i; int err; diag_printf("<INFO>: create file %s size %zd \n",name,size); err = access( name, F_OK ); if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256; fd = open( name, O_WRONLY|O_CREAT ); if( fd < 0 ) SHOW_RESULT( open, fd ); while( size > 0 ) { ssize_t len = size; if ( len > IOSIZE ) len = IOSIZE; wrote = write( fd, buf, len ); if( wrote != len ) SHOW_RESULT( write, (int)wrote ); size -= wrote; } err = close( fd ); if( err < 0 ) SHOW_RESULT( close, err ); } //========================================================================== static void maxfile( char *name ) { char buf[IOSIZE]; int fd; ssize_t wrote; int i; int err; size_t size = 0; size_t prevsize = 0; diag_printf("<INFO>: create maximal file %s\n",name); diag_printf("<INFO>: This may take a few minutes\n"); err = access( name, F_OK ); if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); for( i = 0; i < IOSIZE; i++ ) buf[i] = i%256; fd = open( name, O_WRONLY|O_CREAT ); if( fd < 0 ) SHOW_RESULT( open, fd ); do { wrote = write( fd, buf, IOSIZE ); //if( wrote < 0 ) SHOW_RESULT( write, wrote ); if( wrote >= 0 ) size += wrote; if( (size-prevsize) > 100000 ) { diag_printf("<INFO>: size = %zd \n", size); prevsize = size; } } while( wrote == IOSIZE ); diag_printf("<INFO>: file size == %zd\n",size); err = close( fd ); if( err < 0 ) SHOW_RESULT( close, err ); } //========================================================================== static void checkfile( char *name ) { char buf[IOSIZE]; int fd; ssize_t done; int i; int err; off_t pos = 0; diag_printf("<INFO>: check file %s\n",name); err = access( name, F_OK ); if( err != 0 ) SHOW_RESULT( access, err ); fd = open( name, O_RDONLY ); if( fd < 0 ) SHOW_RESULT( open, fd ); for(;;) { done = read( fd, buf, IOSIZE ); if( done < 0 ) SHOW_RESULT( read, (int)done ); if( done == 0 ) break; for( i = 0; i < done; i++ ) if( buf[i] != i%256 ) { diag_printf("buf[%ld+%d](%02x) != %02x\n",pos,i,buf[i],i%256); CYG_TEST_FAIL("Data read not equal to data written\n"); } pos += done; } err = close( fd ); if( err < 0 ) SHOW_RESULT( close, err ); } #ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES //========================================================================== static void checkattrib(const char *name, const cyg_fs_attrib_t test_attrib ) { int err; cyg_fs_attrib_t file_attrib; diag_printf("<INFO>: check attrib %s\n",name); err = cyg_fs_get_attrib(name, &file_attrib); if( err != 0 ) SHOW_RESULT( stat, err ); if ( (file_attrib & S_FATFS_ATTRIB) != test_attrib ) diag_printf("<FAIL>: attrib %s incorrect\n\tExpected %x Was %x\n", name,test_attrib,(file_attrib & S_FATFS_ATTRIB)); } #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES //========================================================================== static void copyfile( char *name2, char *name1 ) { int err; char buf[IOSIZE]; int fd1, fd2; ssize_t done, wrote; diag_printf("<INFO>: copy file %s -> %s\n",name2,name1); err = access( name1, F_OK ); if( err < 0 && errno != EACCES ) SHOW_RESULT( access, err ); err = access( name2, F_OK ); if( err != 0 ) SHOW_RESULT( access, err ); fd1 = open( name1, O_WRONLY|O_CREAT ); if( fd1 < 0 ) SHOW_RESULT( open, fd1 ); fd2 = open( name2, O_RDONLY ); if( fd2 < 0 ) SHOW_RESULT( open, fd2 ); for(;;) { done = read( fd2, buf, IOSIZE ); if( done < 0 ) SHOW_RESULT( read, (int)done ); if( done == 0 ) break; wrote = write( fd1, buf, done ); if( wrote != done ) SHOW_RESULT( write, (int) wrote ); if( wrote != done ) break; } err = close( fd1 ); if( err < 0 ) SHOW_RESULT( close, err ); err = close( fd2 ); if( err < 0 ) SHOW_RESULT( close, err ); } //========================================================================== static void comparefiles( char *name2, char *name1 ) { int err; char buf1[IOSIZE]; char buf2[IOSIZE]; int fd1, fd2; ssize_t done1, done2; int i; diag_printf("<INFO>: compare files %s == %s\n",name2,name1); err = access( name1, F_OK ); if( err != 0 ) SHOW_RESULT( access, err ); err = access( name1, F_OK ); if( err != 0 ) SHOW_RESULT( access, err ); fd1 = open( name1, O_RDONLY ); if( fd1 < 0 ) SHOW_RESULT( open, fd1 ); fd2 = open( name2, O_RDONLY ); if( fd2 < 0 ) SHOW_RESULT( open, fd2 ); for(;;) { done1 = read( fd1, buf1, IOSIZE ); if( done1 < 0 ) SHOW_RESULT( read, (int)done1 ); done2 = read( fd2, buf2, IOSIZE ); if( done2 < 0 ) SHOW_RESULT( read, (int)done2 ); if( done1 != done2 ) diag_printf("Files different sizes\n"); if( done1 == 0 ) break; for( i = 0; i < done1; i++ ) if( buf1[i] != buf2[i] ) { diag_printf("buf1[%d](%02x) != buf1[%d](%02x)\n",i,buf1[i],i,buf2[i]); CYG_TEST_FAIL("Data in files not equal\n"); } } err = close( fd1 ); if( err < 0 ) SHOW_RESULT( close, err ); err = close( fd2 ); if( err < 0 ) SHOW_RESULT( close, err ); } //========================================================================== void checkcwd( const char *cwd ) { static char cwdbuf[PATH_MAX]; char *ret; ret = getcwd( cwdbuf, sizeof(cwdbuf)); if( ret == NULL ) SHOW_RESULT( getcwd, (int)ret ); if( strcmp( cwdbuf, cwd ) != 0 ) { diag_printf( "cwdbuf %s cwd %s\n",cwdbuf, cwd ); CYG_TEST_FAIL( "Current directory mismatch"); } } //========================================================================== // main int main( int argc, char **argv ) { int err; int existingdirents=-1; #if defined(CYGSEM_FILEIO_BLOCK_USAGE) struct cyg_fs_block_usage usage; #endif CYG_TEST_INIT(); // -------------------------------------------------------------- err = mount( CYGDAT_DEVS_DISK_TEST_DEVICE, "/", "fatfs" ); if( err < 0 ) SHOW_RESULT( mount, err ); err = chdir( "/" ); if( err < 0 ) SHOW_RESULT( chdir, err ); checkcwd( "/" ); listdir( "/", true, -1, &existingdirents ); // -------------------------------------------------------------- #if defined(CYGSEM_FILEIO_BLOCK_USAGE) err = cyg_fs_getinfo("/", FS_INFO_BLOCK_USAGE, &usage, sizeof(usage)); if( err < 0 ) SHOW_RESULT( cyg_fs_getinfo, err ); diag_printf("<INFO>: total size: %6lld blocks, %10lld bytes\n", usage.total_blocks, usage.total_blocks * usage.block_size); diag_printf("<INFO>: free size: %6lld blocks, %10lld bytes\n", usage.free_blocks, usage.free_blocks * usage.block_size); diag_printf("<INFO>: block size: %6u bytes\n", usage.block_size); #endif // -------------------------------------------------------------- createfile( "/foo", 20257 ); checkfile( "foo" ); copyfile( "foo", "fee"); checkfile( "fee" ); comparefiles( "foo", "/fee" ); diag_printf("<INFO>: mkdir bar\n"); err = mkdir( "/bar", 0 ); if( err < 0 ) SHOW_RESULT( mkdir, err ); listdir( "/" , true, existingdirents+3, NULL ); copyfile( "fee", "/bar/fum" ); checkfile( "bar/fum" ); comparefiles( "/fee", "bar/fum" ); diag_printf("<INFO>: cd bar\n"); err = chdir( "bar" ); if( err < 0 ) SHOW_RESULT( chdir, err ); checkcwd( "/bar" ); diag_printf("<INFO>: rename /foo bundy\n"); err = rename( "/foo", "bundy" ); if( err < 0 ) SHOW_RESULT( rename, err ); listdir( "/", true, existingdirents+2, NULL ); listdir( "" , true, 4, NULL ); checkfile( "/bar/bundy" ); comparefiles("/fee", "bundy" ); #if defined(CYGSEM_FILEIO_BLOCK_USAGE) err = cyg_fs_getinfo("/", FS_INFO_BLOCK_USAGE, &usage, sizeof(usage)); if( err < 0 ) SHOW_RESULT( cyg_fs_getinfo, err ); diag_printf("<INFO>: total size: %6lld blocks, %10lld bytes\n", usage.total_blocks, usage.total_blocks * usage.block_size); diag_printf("<INFO>: free size: %6lld blocks, %10lld bytes\n", usage.free_blocks, usage.free_blocks * usage.block_size); diag_printf("<INFO>: block size: %6u bytes\n", usage.block_size); #endif // -------------------------------------------------------------- diag_printf("<INFO>: unlink fee\n"); err = unlink( "/fee" ); if( err < 0 ) SHOW_RESULT( unlink, err ); diag_printf("<INFO>: unlink fum\n"); err = unlink( "fum" ); if( err < 0 ) SHOW_RESULT( unlink, err ); diag_printf("<INFO>: unlink /bar/bundy\n"); err = unlink( "/bar/bundy" ); if( err < 0 ) SHOW_RESULT( unlink, err ); diag_printf("<INFO>: cd /\n"); err = chdir( "/" ); if( err < 0 ) SHOW_RESULT( chdir, err ); checkcwd( "/" ); diag_printf("<INFO>: rmdir /bar\n"); err = rmdir( "/bar" ); if( err < 0 ) SHOW_RESULT( rmdir, err ); listdir( "/", false, existingdirents, NULL ); // -------------------------------------------------------------- #if 0 diag_printf("<INFO>: mkdir disk2\n"); err = mkdir( "/disk2", 0 ); if( err < 0 ) SHOW_RESULT( mkdir, err ); #else diag_printf("<INFO>: mount /disk2\n"); err = mount( CYGDAT_DEVS_DISK_TEST_DEVICE2, "/disk2", "fatfs" ); if( err < 0 ) SHOW_RESULT( mount, err ); #endif listdir( "/disk2" , true, -1, &existingdirents); createfile( "/disk2/tinky", 4567 ); copyfile( "/disk2/tinky", "/disk2/laalaa" ); checkfile( "/disk2/tinky"); checkfile( "/disk2/laalaa"); comparefiles( "/disk2/tinky", "/disk2/laalaa" ); diag_printf("<INFO>: cd /disk2\n"); err = chdir( "/disk2" ); if( err < 0 ) SHOW_RESULT( chdir, err ); checkcwd( "/disk2" ); diag_printf("<INFO>: mkdir noonoo\n"); err = mkdir( "noonoo", 0 ); if( err < 0 ) SHOW_RESULT( mkdir, err ); listdir( "/disk2" , true, existingdirents+3, NULL); diag_printf("<INFO>: cd noonoo\n"); err = chdir( "noonoo" ); if( err < 0 ) SHOW_RESULT( chdir, err ); checkcwd( "/disk2/noonoo" ); createfile( "tinky", 6789 ); checkfile( "tinky" ); createfile( "dipsy", 34567 ); checkfile( "dipsy" ); copyfile( "dipsy", "po" ); checkfile( "po" ); comparefiles( "dipsy", "po" ); listdir( ".", true, 5, NULL ); listdir( "", true, 5, NULL ); listdir( "..", true, existingdirents+3, NULL ); // -------------------------------------------------------------- diag_printf("<INFO>: unlink tinky\n"); err = unlink( "tinky" ); if( err < 0 ) SHOW_RESULT( unlink, err ); diag_printf("<INFO>: unlink dipsy\n"); err = unlink( "dipsy" ); if( err < 0 ) SHOW_RESULT( unlink, err ); diag_printf("<INFO>: unlink po\n"); err = unlink( "po" ); if( err < 0 ) SHOW_RESULT( unlink, err ); diag_printf("<INFO>: cd ..\n"); err = chdir( ".." ); if( err < 0 ) SHOW_RESULT( chdir, err ); checkcwd( "/disk2" ); diag_printf("<INFO>: rmdir noonoo\n"); err = rmdir( "noonoo" ); if( err < 0 ) SHOW_RESULT( rmdir, err ); // -------------------------------------------------------------- err = mkdir( "x", 0 ); if( err < 0 ) SHOW_RESULT( mkdir, err ); err = mkdir( "x/y", 0 ); if( err < 0 ) SHOW_RESULT( mkdir, err ); err = mkdir( "x/y/z", 0 ); if( err < 0 ) SHOW_RESULT( mkdir, err ); err = mkdir( "x/y/z/w", 0 ); if( err < 0 ) SHOW_RESULT( mkdir, err ); diag_printf("<INFO>: cd /disk2/x/y/z/w\n"); err = chdir( "/disk2/x/y/z/w" ); if( err < 0 ) SHOW_RESULT( chdir, err ); checkcwd( "/disk2/x/y/z/w" ); diag_printf("<INFO>: cd ..\n"); err = chdir( ".." ); if( err < 0 ) SHOW_RESULT( chdir, err ); checkcwd( "/disk2/x/y/z" ); diag_printf("<INFO>: cd .\n"); err = chdir( "." ); if( err < 0 ) SHOW_RESULT( chdir, err ); checkcwd( "/disk2/x/y/z" ); diag_printf("<INFO>: cd ../../y\n"); err = chdir( "../../y" ); if( err < 0 ) SHOW_RESULT( chdir, err ); checkcwd( "/disk2/x/y" ); diag_printf("<INFO>: cd ../..\n"); err = chdir( "../.." ); if( err < 0 ) SHOW_RESULT( chdir, err ); checkcwd( "/disk2" ); diag_printf("<INFO>: rmdir x/y/z/w\n"); err = rmdir( "x/y/z/w" ); if( err < 0 ) SHOW_RESULT( rmdir, err ); diag_printf("<INFO>: rmdir x/y/z\n"); err = rmdir( "x/y/z" ); if( err < 0 ) SHOW_RESULT( rmdir, err ); diag_printf("<INFO>: rmdir x/y\n"); err = rmdir( "x/y" ); if( err < 0 ) SHOW_RESULT( rmdir, err ); diag_printf("<INFO>: rmdir x\n"); err = rmdir( "x" ); if( err < 0 ) SHOW_RESULT( rmdir, err ); // -------------------------------------------------------------- checkcwd( "/disk2" ); diag_printf("<INFO>: unlink tinky\n"); err = unlink( "tinky" ); if( err < 0 ) SHOW_RESULT( unlink, err ); diag_printf("<INFO>: unlink laalaa\n"); err = unlink( "laalaa" ); if( err < 0 ) SHOW_RESULT( unlink, err ); diag_printf("<INFO>: cd /\n"); err = chdir( "/" ); if( err < 0 ) SHOW_RESULT( chdir, err ); checkcwd( "/" ); listdir( "/disk2", true, -1, NULL ); #if 0 diag_printf("<INFO>: rmdir dir\n"); err = rmdir( "disk2" ); if( err < 0 ) SHOW_RESULT( rmdir, err ); #else diag_printf("<INFO>: umount /disk2\n"); err = umount( "/disk2" ); if( err < 0 ) SHOW_RESULT( umount, err ); #endif #ifdef CYGCFG_FS_FAT_USE_ATTRIBUTES // Create file diag_printf("<INFO>: create /foo\n"); createfile( "/foo", 20257 ); // Verify it is created with archive bit set checkattrib( "/foo", S_FATFS_ARCHIVE ); // Make it System diag_printf("<INFO>: attrib -A+S /foo\n"); err = cyg_fs_set_attrib( "/foo", S_FATFS_SYSTEM ); if( err < 0 ) SHOW_RESULT( chmod system , err ); // Verify it is now System checkattrib( "/foo", S_FATFS_SYSTEM ); // Make it Hidden diag_printf("<INFO>: attrib -S+H /foo\n"); err = cyg_fs_set_attrib( "/foo", S_FATFS_HIDDEN ); if( err < 0 ) SHOW_RESULT( chmod system , err ); // Verify it is now Hidden checkattrib( "/foo", S_FATFS_HIDDEN ); // Make it Read-only diag_printf("<INFO>: attrib -H+R /foo\n"); err = cyg_fs_set_attrib( "/foo", S_FATFS_RDONLY ); if( err < 0 ) SHOW_RESULT( chmod system , err ); // Verify it is now Read-only checkattrib( "/foo", S_FATFS_RDONLY ); // Verify we cannot unlink a read-only file diag_printf("<INFO>: unlink /foo\n"); err = unlink( "/foo" ); if( (err != -1) || (errno != EPERM) ) SHOW_RESULT( unlink, err ); // Verify we cannot rename a read-only file diag_printf("<INFO>: rename /foo bundy\n"); err = rename( "/foo", "bundy" ); if( (err != -1) || (errno != EPERM) ) SHOW_RESULT( rename, err ); // Verify we cannot open read-only file for writing int fd; diag_printf("<INFO>: create file /foo\n"); fd = open( "/foo", O_WRONLY ); if( (err != -1) || (errno != EACCES) ) SHOW_RESULT( open, err ); if( err > 0 ) close(fd); // Make it Normal diag_printf("<INFO>: attrib -H /foo\n"); err = cyg_fs_set_attrib( "/foo", 0 ); if( err < 0 ) SHOW_RESULT( chmod none , err ); // Verify it is now nothing checkattrib( "/foo", 0 ); // Now delete our test file diag_printf("<INFO>: unlink /foo\n"); err = unlink( "/foo" ); if( err < 0 ) SHOW_RESULT( unlink, err ); #endif // CYGCFG_FS_FAT_USE_ATTRIBUTES maxfile("file.max"); listdir( "/", true, -1, NULL ); diag_printf("<INFO>: unlink file.max\n"); err = unlink( "file.max" ); if( err < 0 ) SHOW_RESULT( unlink, err ); diag_printf("<INFO>: umount /\n"); err = umount( "/" ); if( err < 0 ) SHOW_RESULT( umount, err ); CYG_TEST_PASS_FINISH("fatfs1"); } // ------------------------------------------------------------------------- // EOF fatfs1.c # ls We Are The Champions.mp3 fatfs1.c presentation_back.pdf boot_record.txt presentation.pdf # cp We\ Are\ The\ Champions.mp3 We_gss.mp3 # # ls We Are The Champions.mp3 boot_record.txt presentation.pdf We_gss.mp3 fatfs1.c presentation_back.pdf # ls -l total 9332 -rwxr-xr-x 1 root 0 3642233 Oct 9 2012 We Are The Champions.mp3 -rwxr-xr-x 1 root 0 3642233 Jan 1 00:03 We_gss.mp3 -rwxr-xr-x 1 root 0 8714 Jul 17 2013 boot_record.txt -rwxr-xr-x 1 root 0 22843 Jun 24 2013 fatfs1.c -rwxr-xr-x 1 root 0 1111309 Jun 2 2013 presentation.pdf -rwxr-xr-x 1 root 0 1111309 Jan 1 00:01 presentation_back.pdf #
通过这次努力,我们终于实现了ORPSoC中的SD控制器的linux驱动程序。至此,我们就可以在eCos和linux两个OS下自由的使用SD卡了。
enjoy!
要想本驱动能work,首先要使用make menuconfig命令来配置linux的一些选项。
1>让linux支持块设备驱动
2>其次是配置linux的文件系统选项,支持VFAT文件系统。file system -> DOS/FAT/NT Filesystems,选择MSDOS fs support 和VFAT fs support。
这里需要注意的是,在上图中提示VFAT需要437和iso8859-1两个字符集的支持,所以还要选择这两个字符集。
3>支持437和iso8859-1字符集
4>配置完成后,退出保存,直接make,编译内核。
5>完成以上内核配置工作,再编译驱动程序,就可以进行测试了。