OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [or32/] [drivers/] [sd_card.c] - Diff between revs 18 and 19

Only display areas with differences | Details | Blame | View Log

Rev 18 Rev 19
/*
/*
 *
 *
 * Block driver for spiMaster to drive SD card
 * Block driver for spiMaster to drive SD card
 *
 *
 * Copyright (c) 2008 by:
 * Copyright (c) 2008 by:
 *      Xianfeng Zeng <xianfeng.zeng@gmail.com>
 *      Xianfeng Zeng <xianfeng.zeng@gmail.com>
 *
 *
 * This program is free software; you can redistribute it and/or modify
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the BSD Licence, GNU General Public License
 * it under the terms of the BSD Licence, GNU General Public License
 * as published by the Free Software Foundation; either version 2 of the
 * as published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version
 * License, or (at your option) any later version
 *
 *
 * ChangeLog:
 * ChangeLog:
 *      2009-11-28 15:11:18   Xianfeng Zeng
 *      2009-11-28 15:11:18   Xianfeng Zeng
 *          Init.
 *          Init.
 *
 *
 */
 */
 
 
#include <linux/version.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/fs.h>
#include <linux/genhd.h>
#include <linux/genhd.h>
#include <linux/delay.h>
#include <linux/delay.h>
 
 
#include <linux/slab.h>         /* kmalloc() */
#include <linux/slab.h>         /* kmalloc() */
#include <linux/errno.h>        /* error codes */
#include <linux/errno.h>        /* error codes */
#include <linux/timer.h>
#include <linux/timer.h>
#include <linux/types.h>        /* size_t */
#include <linux/types.h>        /* size_t */
#include <linux/fcntl.h>        /* O_ACCMODE */
#include <linux/fcntl.h>        /* O_ACCMODE */
#include <linux/hdreg.h>        /* HDIO_GETGEO */
#include <linux/hdreg.h>        /* HDIO_GETGEO */
#include <linux/kdev_t.h>
#include <linux/kdev_t.h>
#include <linux/vmalloc.h>
#include <linux/vmalloc.h>
#include <linux/genhd.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>
#include <linux/blkdev.h>
#include <linux/buffer_head.h>  /* invalidate_bdev */
#include <linux/buffer_head.h>  /* invalidate_bdev */
#include <linux/bio.h>
#include <linux/bio.h>
 
 
 
 
#include "sd_card.h"
#include "sd_card.h"
 
 
#define SDC_DEBUG 1
//#define SDC_DEBUG 1
 
 
#ifdef SDC_DEBUG
#ifdef SDC_DEBUG
#       define SDC_PRINTK(fmt, args...) printk( KERN_WARNING "sd_card:" fmt, ## args)
#       define SDC_PRINTK(fmt, args...) printk( KERN_WARNING "sd_card:" fmt, ## args)
#else
#else
#       define SDC_PRINTK(fmt, args...)
#       define SDC_PRINTK(fmt, args...)
#endif
#endif
 
 
#define DRIVER_NAME     "sd_card"
#define DRIVER_NAME     "sd_card"
#define SD_CARD_MINORS  8
#define SD_CARD_MINORS  8
#define SD_CARD_SIZE    1995440128
#define SD_CARD_SIZE    1995440128
 
//(512*1024*1024)
 
//1995440128
 
 
static int major = 8;
static int major = 8;
 
 
 
 
/**
/**
 * ============================================================
 * ============================================================
 *
 *
 * ============================================================
 * ============================================================
 */
 */
int spiMaster_init(void *vbase)
int spiMaster_init(void *vbase)
{
{
        unsigned char data;
        unsigned char data;
        int   i;
        int   i;
 
 
        SDC_PRINTK("spiMaster_init begin\n");
        SDC_PRINTK("spiMaster_init begin\n");
 
 
        for (i = 0; i < 5; i++) {
        for (i = 0; i < 5; i++) {
                REG8(vbase + SD_TRANS_TYPE_REG) = SD_INIT_SD;
                REG8(vbase + SD_TRANS_TYPE_REG) = SD_INIT_SD;
                REG8(vbase + SD_TRANS_CTRL_REG) = 1; // TRANS_START;
                REG8(vbase + SD_TRANS_CTRL_REG) = 1; // TRANS_START;
 
 
                mdelay(1);
                mdelay(1);
 
 
                while (REG8(vbase + SD_TRANS_STS_REG) & 0x1) { // exit while !TRABS_BUSY
                while (REG8(vbase + SD_TRANS_STS_REG) & 0x1) { // exit while !TRABS_BUSY
                        ;
                        ;
                }
                }
 
 
                data = REG8(vbase + SD_TRANS_ERROR_REG) & 0x3;
                data = REG8(vbase + SD_TRANS_ERROR_REG) & 0x3;
 
 
                if (data == 0) {
                if (data == 0) {
                        SDC_PRINTK("spiMaster_init done\n");
                        SDC_PRINTK("spiMaster_init done\n");
                        return 0;
                        return 0;
                }
                }
        }
        }
 
 
        SDC_PRINTK("spiMaster_init failed\n");
        SDC_PRINTK("spiMaster_init failed\n");
 
 
        return data;
        return data;
}
}
 
 
/**
/**
 * ============================================================
 * ============================================================
 *             Request Handling
 *             Request Handling
 * ============================================================
 * ============================================================
 */
 */
 
 
static int read_sd_block(void *sd_vbase, unsigned long sector,
static int read_sd_block(void *sd_vbase, unsigned long sector,
                unsigned long nsect, char *buffer)
                unsigned long nsect, char *buffer)
{
{
        unsigned char data;
        unsigned char data;
        unsigned char transError;
        unsigned char transError;
        int i;
        int i;
        unsigned int buffer_offset = 0;
        unsigned int buffer_offset = 0;
        unsigned int blockCnt;
        unsigned int blockCnt;
 
        unsigned int start = sector << 9; /* x512*/
 
 
        SDC_PRINTK("read_sd_block begin: sector=%d, nsect=%d\n", sector, nsect);
        SDC_PRINTK("read_sd_block begin: sector=%ld, nsect=%ld\n", sector, nsect);
 
 
        for (blockCnt = 0; blockCnt < nsect; blockCnt++) {
        for (blockCnt = 0; blockCnt < nsect; blockCnt++) {
                REG8(sd_vbase + SD_ADDR_7_0_REG)   = 0;
                REG8(sd_vbase + SD_ADDR_7_0_REG)   = 0;
                REG8(sd_vbase + SD_ADDR_15_8_REG)  = (unsigned char) ((sector >> 8) & 0xff);
                REG8(sd_vbase + SD_ADDR_15_8_REG)  = (unsigned char) ((start >> 8) & 0xff);
                REG8(sd_vbase + SD_ADDR_23_16_REG) = (unsigned char) ((sector >> 16) & 0xff);
                REG8(sd_vbase + SD_ADDR_23_16_REG) = (unsigned char) ((start >> 16) & 0xff);
                REG8(sd_vbase + SD_ADDR_31_24_REG) = (unsigned char) ((sector >> 24) & 0xff);
                REG8(sd_vbase + SD_ADDR_31_24_REG) = (unsigned char) ((start >> 24) & 0xff);
 
 
                REG8(sd_vbase + SD_TRANS_TYPE_REG) = SD_RW_READ_SD_BLOCK;
                REG8(sd_vbase + SD_TRANS_TYPE_REG) = SD_RW_READ_SD_BLOCK;
                REG8(sd_vbase + SD_RX_FIFO_CONTROL_REG) = 0x1; /* Clean the RX FIFO */
                REG8(sd_vbase + SD_RX_FIFO_CONTROL_REG) = 0x1; /* Clean the RX FIFO */
                REG8(sd_vbase + SD_TRANS_CTRL_REG) = 0x1; /* TRANS_START */
                REG8(sd_vbase + SD_TRANS_CTRL_REG) = 0x1; /* TRANS_START */
 
 
 
 
                while (REG8(sd_vbase + SD_TRANS_STS_REG) & 0x1) { /* exit while !TRABS_BUSY */
                while (REG8(sd_vbase + SD_TRANS_STS_REG) & 0x1) { /* exit while !TRABS_BUSY */
                        ;
                        ;
                }
                }
 
 
                transError = REG8(sd_vbase + SD_TRANS_ERROR_REG) & 0xc;
                transError = REG8(sd_vbase + SD_TRANS_ERROR_REG) & 0xc;
                if ( transError == SD_READ_NO_ERROR) {
                if ( transError == SD_READ_NO_ERROR) {
                        for (i = 0; i < 512; i++) {
                        for (i = 0; i < 512; i++) {
                                data = REG8(sd_vbase + SD_RX_FIFO_DATA_REG) ;
                                data = REG8(sd_vbase + SD_RX_FIFO_DATA_REG) ;
                                REG8(buffer + buffer_offset + i) = data ;
                                //REG8(buffer + buffer_offset + i) = data ;
 
                                buffer[buffer_offset + i] = data ;
 
//                              printk("%x\t",data);
 
//                              if (i%16 == 0) {
 
//                                      printk("\n");
 
//                              }
                        }
                        }
 
//                      printk("\n");
                        buffer_offset += 512;
                        buffer_offset += 512;
                        sector += 512;
                        start += 512;
                } else {
                } else {
                        SDC_PRINTK("read_sd_block failed. Re-try\n");
                        SDC_PRINTK("read_sd_block failed. Re-try\n");
                        spiMaster_init(sd_vbase); /* Init again and retry */
                        spiMaster_init(sd_vbase); /* Init again and retry */
                        blockCnt--; /* read the same block again */
                        blockCnt--; /* read the same block again */
                }
                }
        }
        }
 
 
        SDC_PRINTK("read_sd_block done\n");
        SDC_PRINTK("read_sd_block done\n");
 
 
        return 0;
        return 0;
}
}
 
 
static int write_sd_block(void *sd_vbase, unsigned long sector,
static int write_sd_block(void *sd_vbase, unsigned long sector,
                unsigned long nsect, char *buffer)
                unsigned long nsect, char *buffer)
{
{
        int i;
        int i;
        unsigned char data;
        unsigned char data;
        unsigned int blockCnt;
        unsigned int blockCnt;
        char *p = buffer;
        char *p = buffer;
 
        unsigned int start = sector << 9; /* x512*/
 
 
        SDC_PRINTK("write_sd_block begin: sector=%d, nsect=%d\n", sector, nsect);
 
 
        SDC_PRINTK("write_sd_block begin: sector=%ld, nsect=%ld\n", sector, nsect);
 
 
        for (blockCnt = 0; blockCnt < nsect; blockCnt++) {
        for (blockCnt = 0; blockCnt < nsect; blockCnt++) {
 
 
                /* Clean the TX FIFO */
                /* Clean the TX FIFO */
                REG8(sd_vbase + SD_TX_FIFO_CONTROL_REG) = 0x1;
                REG8(sd_vbase + SD_TX_FIFO_CONTROL_REG) = 0x1;
 
 
                REG8(sd_vbase + SD_ADDR_7_0_REG)   = 0;
                REG8(sd_vbase + SD_ADDR_7_0_REG)   = 0;
                REG8(sd_vbase + SD_ADDR_15_8_REG)  = (unsigned char) ((sector >> 8) & 0xff);
                REG8(sd_vbase + SD_ADDR_15_8_REG)  = (unsigned char) ((start >> 8) & 0xff);
                REG8(sd_vbase + SD_ADDR_23_16_REG) = (unsigned char) ((sector >> 16) & 0xff);
                REG8(sd_vbase + SD_ADDR_23_16_REG) = (unsigned char) ((start >> 16) & 0xff);
                REG8(sd_vbase + SD_ADDR_31_24_REG) = (unsigned char) ((sector >> 24) & 0xff);
                REG8(sd_vbase + SD_ADDR_31_24_REG) = (unsigned char) ((start >> 24) & 0xff);
 
 
 
 
                // Write data to TX_FIFO_DATA_REG
                // Write data to TX_FIFO_DATA_REG
                for (i = 0; i < 512; i++) {
                for (i = 0; i < 512; i++) {
                        REG8(sd_vbase + SD_TX_FIFO_DATA_REG) = p[i];
                        REG8(sd_vbase + SD_TX_FIFO_DATA_REG) = p[i];
                }
                }
 
 
 
 
                REG8(sd_vbase + SD_TRANS_TYPE_REG) = SD_RW_WRITE_SD_BLOCK;
                REG8(sd_vbase + SD_TRANS_TYPE_REG) = SD_RW_WRITE_SD_BLOCK;
                REG8(sd_vbase + SD_TRANS_CTRL_REG) = 1; /* TRANS_START */
                REG8(sd_vbase + SD_TRANS_CTRL_REG) = 1; /* TRANS_START */
 
 
 
                udelay(10);
                while (REG8(sd_vbase + SD_TRANS_STS_REG) & 0x1) { /* exit while !TRABS_BUSY */
                while (REG8(sd_vbase + SD_TRANS_STS_REG) & 0x1) { /* exit while !TRABS_BUSY */
                        ;
                        ;
                }
                }
 
 
                data = REG8(sd_vbase + SD_TRANS_ERROR_REG) & 0x30;
                data = REG8(sd_vbase + SD_TRANS_ERROR_REG) & 0x30;
                if (data == 1) {
                if (data == 1) {
                        SDC_PRINTK("WRITE_CMD_ERROR\n\r");
                        printk("sd_card:WRITE_CMD_ERROR\n\r");
                } else if (data == 2) {
                } else if (data == 2) {
                        SDC_PRINTK("WRITE_DATA_ERROR\n\r");
                        printk("sd_card:WRITE_DATA_ERROR\n\r");
                } else if (data == 3) {
                } else if (data == 3) {
                        SDC_PRINTK("WRITE_BUSY_ERROR\n\r");
                        printk("sd_card:WRITE_BUSY_ERROR\n\r");
                }
                }
 
 
                sector += 512;
                start += 512;
                p += 512;
                p += 512;
        }
        }
 
 
        SDC_PRINTK("write_sd_block done\n");
        SDC_PRINTK("write_sd_block done\n");
        return 0;
        return 0;
}
}
 
 
/*
/*
 * Handle an I/O request.
 * Handle an I/O request.
 */
 */
static void sd_card_transfer(struct sd_card_dev *dev, unsigned long sector,
static void sd_card_transfer(struct sd_card_dev *dev, unsigned long sector,
                unsigned long nsect, char *buffer, int write)
                unsigned long nsect, char *buffer, int write)
{
{
        unsigned long offset = sector*512;
        unsigned long offset = sector*512;
        unsigned long nbytes = nsect*512;
        unsigned long nbytes = nsect*512;
 
 
        if ((offset + nbytes) > dev->size) {
        if ((offset + nbytes) > dev->size) {
                printk (KERN_NOTICE "Beyond-end write (%ld %ld)\n", offset, nbytes);
                printk (KERN_NOTICE "Beyond-end write (%ld %ld)\n", offset, nbytes);
                return;
                return;
        }
        }
        if (write)
        if (write)
                write_sd_block(dev->vir_base, sector, nsect, buffer);
                write_sd_block(dev->vir_base, sector, nsect, buffer);
        else
        else
                read_sd_block(dev->vir_base, sector, nsect, buffer);
                read_sd_block(dev->vir_base, sector, nsect, buffer);
}
}
 
 
 
 
/*
/*
 * The simple form of the request function.
 * The simple form of the request function.
 */
 */
static void sd_card_request(request_queue_t *q)
static void sd_card_request(request_queue_t *q)
{
{
        struct request *req;
        struct request *req;
 
 
        while ((req = elv_next_request(q)) != NULL) {
        while ((req = elv_next_request(q)) != NULL) {
                struct sd_card_dev *dev = req->rq_disk->private_data;
                struct sd_card_dev *dev = req->rq_disk->private_data;
                if (! blk_fs_request(req)) {
                if (! blk_fs_request(req)) {
                        printk (KERN_NOTICE "Skip non-fs request\n");
                        printk (KERN_NOTICE "Skip non-fs request\n");
                        end_request(req, 0);
                        end_request(req, 0);
                        continue;
                        continue;
                }
                }
    //          printk (KERN_NOTICE "Req dev %d dir %ld sec %ld, nr %d f %lx\n",
    //          printk (KERN_NOTICE "Req dev %d dir %ld sec %ld, nr %d f %lx\n",
    //                          dev - Devices, rq_data_dir(req),
    //                          dev - Devices, rq_data_dir(req),
    //                          req->sector, req->current_nr_sectors,
    //                          req->sector, req->current_nr_sectors,
    //                          req->flags);
    //                          req->flags);
                sd_card_transfer(dev, req->sector, req->current_nr_sectors,
                sd_card_transfer(dev, req->sector, req->current_nr_sectors,
                                req->buffer, rq_data_dir(req));
                                req->buffer, rq_data_dir(req));
                end_request(req, 1);
                end_request(req, 1);
        }
        }
}
}
 
 
/**
/**
 * ============================================================
 * ============================================================
 *             Block device operations
 *             Block device operations
 * ============================================================
 * ============================================================
 */
 */
static int sd_card_open(struct inode *inode, struct file *filp)
static int sd_card_open(struct inode *inode, struct file *filp)
{
{
        struct sd_card_dev *dev = inode->i_bdev->bd_disk->private_data;
        struct sd_card_dev *dev = inode->i_bdev->bd_disk->private_data;
 
 
        SDC_PRINTK("sd_card_open beging\n");
        SDC_PRINTK("sd_card_open beging\n");
 
 
        filp->private_data = dev;
        filp->private_data = dev;
        spin_lock(&dev->lock);
        spin_lock(&dev->lock);
        if (! dev->users)
        if (! dev->users)
                check_disk_change(inode->i_bdev);
                check_disk_change(inode->i_bdev);
 
 
        /* Init SD card controller */
        /* Init SD card controller */
        spiMaster_init(dev->vir_base);
        spiMaster_init(dev->vir_base);
 
 
        dev->users++;
        dev->users++;
        spin_unlock(&dev->lock);
        spin_unlock(&dev->lock);
 
 
        SDC_PRINTK("sd_card_open done\n");
        SDC_PRINTK("sd_card_open done\n");
 
 
        return 0;
        return 0;
}
}
 
 
static int sd_card_release(struct inode *inode, struct file *filp)
static int sd_card_release(struct inode *inode, struct file *filp)
{
{
        struct sd_card_dev *dev = inode->i_bdev->bd_disk->private_data;
        struct sd_card_dev *dev = inode->i_bdev->bd_disk->private_data;
 
 
        SDC_PRINTK("sd_card_release beging\n");
        SDC_PRINTK("sd_card_release beging\n");
 
 
        spin_lock(&dev->lock);
        spin_lock(&dev->lock);
        dev->users--;
        dev->users--;
 
 
        spin_unlock(&dev->lock);
        spin_unlock(&dev->lock);
 
 
        SDC_PRINTK("sd_card_release done\n");
        SDC_PRINTK("sd_card_release done\n");
 
 
        return 0;
        return 0;
}
}
 
 
/*
/*
 * Look for a (simulated) media change.
 * Look for a (simulated) media change.
 */
 */
int sd_card_media_changed(struct gendisk *gd)
int sd_card_media_changed(struct gendisk *gd)
{
{
        //struct sd_card_dev *dev = gd->private_data;
        //struct sd_card_dev *dev = gd->private_data;
 
 
        return 0; //dev->media_change;
        return 0; //dev->media_change;
}
}
 
 
/*
/*
 * Revalidate.  WE DO NOT TAKE THE LOCK HERE, for fear of deadlocking
 * Revalidate.  WE DO NOT TAKE THE LOCK HERE, for fear of deadlocking
 * with open.  That needs to be reevaluated.
 * with open.  That needs to be reevaluated.
 */
 */
int sd_card_revalidate(struct gendisk *gd)
int sd_card_revalidate(struct gendisk *gd)
{
{
        struct sd_card_dev *dev = gd->private_data;
        struct sd_card_dev *dev = gd->private_data;
 
 
        if (dev->media_change) {
        if (dev->media_change) {
                dev->media_change = 0;
                dev->media_change = 0;
//              memset (dev->data, 0, dev->size);
//              memset (dev->data, 0, dev->size);
        }
        }
        return 0;
        return 0;
}
}
 
 
 
 
/*
/*
 * The ioctl() implementation
 * The ioctl() implementation
 */
 */
 
 
 
static int sd_card_getgeo(struct block_device *bdev,
 
                struct hd_geometry *geo)
 
{
 
        /*
 
         * capacity        heads        sectors        cylinders
 
         * 0~16M             1             1           0~32768
 
         * 16M~512M          1             32          1024~32768
 
         * 512M~16G          32            32          1024~32768
 
         * 16G~...           255           63          2088~...
 
         */
 
        if (SD_CARD_SIZE < 16 * 1024 * 1024) {
 
                geo->heads = 1;
 
                geo->sectors = 1;
 
 
 
        } else if (SD_CARD_SIZE < 512 * 1024 * 1024) {
 
                geo->heads = 1;
 
                geo->sectors = 32;
 
        } else if (SD_CARD_SIZE < 16ULL * 1024 * 1024 * 1024) {
 
                geo->heads = 32;
 
                geo->sectors = 32;
 
        } else {
 
                geo->heads = 255;
 
                geo->sectors = 63;
 
        }
 
 
 
        geo->cylinders = SD_CARD_SIZE>>9/geo->heads/geo->sectors;
 
 
 
        return 0;
 
}
 
 
int sd_card_ioctl (struct inode *inode, struct file *filp,
int sd_card_ioctl (struct inode *inode, struct file *filp,
                 unsigned int cmd, unsigned long arg)
                 unsigned int cmd, unsigned long arg)
{
{
        long size;
        long size;
        struct hd_geometry geo;
        struct hd_geometry geo;
        struct sd_card_dev *dev = filp->private_data;
        struct sd_card_dev *dev = filp->private_data;
 
 
        switch(cmd) {
        switch(cmd) {
            case HDIO_GETGEO:
            case HDIO_GETGEO:
                /*
                /*
                 * Get geometry: since we are a virtual device, we have to make
                 * Get geometry: since we are a virtual device, we have to make
                 * up something plausible.  So we claim 16 sectors, four heads,
                 * up something plausible.  So we claim 16 sectors, four heads,
                 * and calculate the corresponding number of cylinders.  We set the
                 * and calculate the corresponding number of cylinders.  We set the
                 * start of data at sector four.
                 * start of data at sector four.
                 */
                 */
                size = dev->size;
                size = dev->size;
                geo.cylinders = (size & ~0x3f) >> 6;
                geo.cylinders = (size & ~0x3f) >> 6;
                geo.heads = 62; //32;
                geo.heads = 62; //32;
                geo.sectors = 62; //63;
                geo.sectors = 62; //63;
                geo.start = get_start_sect(inode->i_bdev);
                geo.start = get_start_sect(inode->i_bdev);
                if (copy_to_user((void __user *) arg, &geo, sizeof(geo)))
                if (copy_to_user((void __user *) arg, &geo, sizeof(geo)))
                        return -EFAULT;
                        return -EFAULT;
                return 0;
                return 0;
        }
        }
 
 
        return -ENOTTY; /* unknown command */
        return -ENOTTY; /* unknown command */
}
}
 
 
 
 
/*
/*
 * The device operations structure.
 * The device operations structure.
 */
 */
static struct block_device_operations sd_card_ops = {
static struct block_device_operations sd_card_ops = {
        .owner           = THIS_MODULE,
        .owner           = THIS_MODULE,
        .open            = sd_card_open,
        .open            = sd_card_open,
        .release         = sd_card_release,
        .release         = sd_card_release,
        .media_changed   = sd_card_media_changed,
        .media_changed   = sd_card_media_changed,
        .revalidate_disk = sd_card_revalidate,
        .revalidate_disk = sd_card_revalidate,
        .ioctl           = sd_card_ioctl
//      .ioctl           = sd_card_ioctl,
 
        .getgeo          = sd_card_getgeo
};
};
 
 
/**
/**
 * ============================================================
 * ============================================================
 *                 Driver Entry and clean up
 *                 Driver Entry and clean up
 * ============================================================
 * ============================================================
 */
 */
static int __init sd_card_init(void)
static int __init sd_card_init(void)
{
{
        int ret;
        int ret;
        struct sd_card_dev  *dev;
        struct sd_card_dev  *dev;
 
 
        /* Put the init code here */
        /* Put the init code here */
        printk(KERN_INFO "SD Card Driver Enter.\n");
        printk(KERN_INFO "SD Card Driver Enter.\n");
 
 
        dev = (struct sd_card_dev *)kmalloc(sizeof(struct sd_card_dev), GFP_KERNEL);
        dev = (struct sd_card_dev *)kmalloc(sizeof(struct sd_card_dev), GFP_KERNEL);
        if (dev < 0) {
        if (dev < 0) {
                printk(KERN_WARNING "lack of memory\n");
                printk(KERN_WARNING "lack of memory\n");
                return -1;
                return -1;
        }
        }
        memset(dev, 0, sizeof(struct sd_card_dev));
        memset(dev, 0, sizeof(struct sd_card_dev));
 
 
        ret = register_blkdev(major, DRIVER_NAME);
        ret = register_blkdev(major, DRIVER_NAME);
        if (ret <0) {
        if (ret <0) {
                printk(KERN_WARNING "sd_card: unable to get major number\n");
                printk(KERN_WARNING "sd_card: unable to get major number\n");
                kfree(dev);
                kfree(dev);
                return -EBUSY;
                return -EBUSY;
        }
        }
 
 
        dev->size = SD_CARD_SIZE; //1015808000; /* 1GB */
        dev->size = SD_CARD_SIZE; //1015808000; /* 1GB */
        spin_lock_init(&dev->lock);
        spin_lock_init(&dev->lock);
        dev->queue = blk_init_queue(sd_card_request, &dev->lock);
        dev->queue = blk_init_queue(sd_card_request, &dev->lock);
        blk_queue_hardsect_size(dev->queue, 512);
        blk_queue_hardsect_size(dev->queue, 512);
 
 
        dev->vir_base = ioremap(SD_BASE_ADD, 0x2000);
        dev->vir_base = ioremap(SD_BASE_ADD, 0x2000);
 
 
        /* Reset spiMaster controller */
        /* Reset spiMaster controller */
        REG8(dev->vir_base + SD_TRANS_CTRL_REG) = 0x1;  /* reset spiMaster */
        REG8(dev->vir_base + SD_TRANS_CTRL_REG) = 0x1;  /* reset spiMaster */
        mdelay(1);
        mdelay(1);
        REG8(dev->vir_base + SD_TRANS_CTRL_REG) = 0x0;
        REG8(dev->vir_base + SD_TRANS_CTRL_REG) = 0x0;
        REG8(dev->vir_base + SD_CLK_DEL_REG) = 0x1;
        REG8(dev->vir_base + SD_CLK_DEL_REG) = 0x1;
 
 
        /* allocate gendsik and init it */
        /* allocate gendsik and init it */
        dev->gd = alloc_disk(SD_CARD_MINORS);
        dev->gd = alloc_disk(SD_CARD_MINORS);
        if (!dev->gd) {
        if (!dev->gd) {
                printk(KERN_WARNING "alloc_disk failed\n");
                printk(KERN_WARNING "alloc_disk failed\n");
                kfree(dev);
                kfree(dev);
                unregister_blkdev(major, DRIVER_NAME);
                unregister_blkdev(major, DRIVER_NAME);
                return -1;
                return -1;
        }
        }
        dev->gd->major          = major;
        dev->gd->major          = major;
        dev->gd->first_minor    = 0;
        dev->gd->first_minor    = 0;
        dev->gd->fops           = &sd_card_ops;
        dev->gd->fops           = &sd_card_ops;
        dev->gd->queue          = dev->queue;
        dev->gd->queue          = dev->queue;
        dev->gd->private_data   = dev;
        dev->gd->private_data   = dev;
        snprintf(dev->gd->disk_name, 32, "sd%c", 'a');
        snprintf(dev->gd->disk_name, 32, "sd%c", 'a');
 
 
        set_capacity(dev->gd, dev->size/512);
        set_capacity(dev->gd, dev->size/512);
 
 
        add_disk(dev->gd);
        add_disk(dev->gd);
 
 
        SDC_PRINTK("sd_card_init done\n");
        SDC_PRINTK("sd_card_init done\n");
 
 
        return 0;
        return 0;
}
}
 
 
 
 
static void __exit sd_card_exit(void)
static void __exit sd_card_exit(void)
{
{
        /* Put the driver clean up code here */
        /* Put the driver clean up code here */
 
 
        unregister_blkdev(major, DRIVER_NAME);
        unregister_blkdev(major, DRIVER_NAME);
 
 
        printk(KERN_INFO "SD Card Driver Exit.\n");
        printk(KERN_INFO "SD Card Driver Exit.\n");
}
}
 
 
//module_init(sd_card_init);
//module_init(sd_card_init);
late_initcall(sd_card_init);
late_initcall(sd_card_init);
module_exit(sd_card_exit);
module_exit(sd_card_exit);
 
 
MODULE_LICENSE("Dual BSD/GPL");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Xianfeng Zeng - Xianfeng.zeng@SierraAtlantic.com, http://www.LinuxExperts.cn");
MODULE_AUTHOR("Xianfeng Zeng - Xianfeng.zeng@SierraAtlantic.com, http://www.LinuxExperts.cn");
MODULE_DESCRIPTION("spiMaster driver");
MODULE_DESCRIPTION("spiMaster driver");
MODULE_VERSION("0.1");
MODULE_VERSION("0.1");
 
 
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.