source: trunk/target/linux/rb532-2.6/patches/120-cf.patch @ 6518

Last change on this file since 6518 was 6518, checked in by nbd, 9 years ago

fix a compile error caused by the devfs removal

  • Property svn:eol-style set to native
File size: 27.6 KB
  • drivers/block/Kconfig

    diff -urN linux.old/drivers/block/Kconfig linux.dev/drivers/block/Kconfig
    old new  
    456456        This driver provides Support for ATA over Ethernet block 
    457457        devices like the Coraid EtherDrive (R) Storage Blade. 
    458458 
     459config BLK_DEV_CF_MIPS 
     460        bool "CF slot of RB532 board" 
     461        depends on MIKROTIK_RB500 
     462        default y 
     463        help 
     464          The Routerboard 532 has a CF slot on it. Enable the special block 
     465          device driver for it. 
     466 
    459467endmenu 
  • drivers/block/Makefile

    diff -urN linux.old/drivers/block/Makefile linux.dev/drivers/block/Makefile
    old new  
    2929obj-$(CONFIG_VIODASD)           += viodasd.o 
    3030obj-$(CONFIG_BLK_DEV_SX8)       += sx8.o 
    3131obj-$(CONFIG_BLK_DEV_UB)        += ub.o 
     32obj-$(CONFIG_BLK_DEV_CF_MIPS)   += rb500/ 
    3233 
  • drivers/block/rb500/ata.c

    diff -urN linux.old/drivers/block/rb500/ata.c linux.dev/drivers/block/rb500/ata.c
    old new  
     1/* CF-mips driver 
     2   This is a block driver for the direct (mmaped) interface to the CF-slot, 
     3   found in Routerboard.com's RB532 board 
     4   See SDK provided from routerboard.com. 
     5    
     6   Module adapted By P.Christeas <p_christeas@yahoo.com>, 2005-6. 
     7   Cleaned up and adapted to platform_device by Felix Fietkau <nbd@openwrt.org> 
     8 
     9   This work is redistributed under the terms of the GNU General Public License. 
     10*/ 
     11 
     12#include <linux/kernel.h>       /* printk() */ 
     13#include <linux/module.h>       /* module to be loadable */ 
     14#include <linux/delay.h> 
     15#include <linux/sched.h> 
     16#include <linux/pci.h> 
     17#include <linux/ioport.h>       /* request_mem_region() */ 
     18#include <asm/unaligned.h>              /* ioremap() */ 
     19#include <asm/io.h>             /* ioremap() */ 
     20#include <asm/rc32434/rb.h> 
     21 
     22#include "ata.h" 
     23 
     24#define REQUEST_MEM_REGION 0 
     25#define DEBUG 1 
     26 
     27#if DEBUG 
     28#define DEBUGP printk 
     29#else 
     30#define DEBUGP(format, args...) 
     31#endif 
     32 
     33#define SECS    1000000         /* unit for wait_not_busy() is 1us */ 
     34 
     35unsigned cf_head = 0; 
     36unsigned cf_cyl = 0; 
     37unsigned cf_spt = 0; 
     38unsigned cf_sectors = 0; 
     39static unsigned cf_block_size = 1; 
     40static void *baddr = 0; 
     41 
     42#define DBUF32 ((volatile u32 *)((unsigned long)dev->baddr | ATA_DBUF_OFFSET)) 
     43 
     44 
     45static void cf_do_tasklet(unsigned long dev_l); 
     46 
     47 
     48static inline void wareg(u8 val, unsigned reg, struct cf_mips_dev* dev) 
     49{ 
     50        writeb(val, dev->baddr + ATA_REG_OFFSET + reg); 
     51} 
     52 
     53static inline u8 rareg(unsigned reg, struct cf_mips_dev* dev) 
     54{ 
     55        return readb(dev->baddr + ATA_REG_OFFSET + reg); 
     56} 
     57 
     58static inline int get_gpio_bit(gpio_func ofs, struct cf_mips_dev *dev) 
     59{ 
     60        return (gpio_get(ofs) >> dev->pin) & 1; 
     61} 
     62 
     63static inline void set_gpio_bit(int bit, gpio_func ofs, struct cf_mips_dev *dev) 
     64{ 
     65        gpio_set(ofs, (1 << dev->pin), ((bit & 1) << dev->pin)); 
     66} 
     67 
     68static inline int cfrdy(struct cf_mips_dev *dev) 
     69{ 
     70        return get_gpio_bit(DATA, dev); 
     71} 
     72 
     73static inline void prepare_cf_irq(struct cf_mips_dev *dev) 
     74{ 
     75        set_gpio_bit(1, ILEVEL, dev);   /* interrupt on cf ready (not busy) */ 
     76        set_gpio_bit(0, ISTAT, dev);    /* clear interrupt status */ 
     77} 
     78 
     79static inline int cf_present(struct cf_mips_dev* dev) 
     80{ 
     81        /* TODO: read and configure CIS into memory mapped mode 
     82         * TODO:   parse CISTPL_CONFIG on CF+ cards to get base address (0x200) 
     83         * TODO:   maybe adjust power saving setting for Hitachi Microdrive 
     84         */ 
     85        int i; 
     86 
     87        /* setup CFRDY GPIO as input */ 
     88        set_gpio_bit(0, FUNC, dev); 
     89        set_gpio_bit(0, CFG, dev); 
     90 
     91        for (i = 0; i < 0x10; ++i) { 
     92                if (rareg(i,dev) != 0xff) 
     93                        return 1; 
     94        } 
     95        return 0; 
     96} 
     97 
     98static inline int is_busy(struct cf_mips_dev *dev) 
     99{ 
     100        return !cfrdy(dev); 
     101} 
     102 
     103static int wait_not_busy(int to_us, int wait_for_busy,struct cf_mips_dev *dev) 
     104{ 
     105        int us_passed = 0; 
     106        if (wait_for_busy && !is_busy(dev)) { 
     107                /* busy must appear within 400ns, 
     108                 * but it may dissapear before we see it 
     109                 *  => must not wait for busy in a loop 
     110                 */ 
     111                ndelay(400); 
     112        } 
     113 
     114        do { 
     115                if (us_passed) 
     116                        udelay(1);      /* never reached in async mode */ 
     117                if (!is_busy(dev)) { 
     118                        if (us_passed > 1 * SECS) { 
     119                                printk(KERN_WARNING "cf-mips:   not busy ok (after %dus)" 
     120                                       ", status 0x%02x\n", us_passed, (unsigned) rareg(ATA_REG_ST,dev)); 
     121                        } 
     122                        return CF_TRANS_OK; 
     123                } 
     124                if (us_passed == 1 * SECS) { 
     125                        printk(KERN_WARNING "cf-mips: wait not busy %dus..\n", to_us); 
     126                } 
     127                if (dev->async_mode) { 
     128                        dev->to_timer.expires = jiffies + (to_us * HZ / SECS); 
     129                        dev->irq_enable_time = jiffies; 
     130                        prepare_cf_irq(dev); 
     131                        if (is_busy(dev)) { 
     132                                add_timer(&dev->to_timer); 
     133                                enable_irq(dev->irq); 
     134                                return CF_TRANS_IN_PROGRESS; 
     135                        } 
     136                        continue; 
     137                } 
     138                ++us_passed; 
     139        } while (us_passed < to_us); 
     140 
     141        printk(KERN_ERR "cf-mips:  wait not busy timeout (%dus)" 
     142               ", status 0x%02x, state %d\n", 
     143               to_us, (unsigned) rareg(ATA_REG_ST,dev), dev->tstate); 
     144        return CF_TRANS_FAILED; 
     145} 
     146 
     147static irqreturn_t cf_irq_handler(int irq, void *dev_id) 
     148{ 
     149        /* While tasklet has not disabled irq, irq will be retried all the time 
     150         * because of ILEVEL matching GPIO pin status => deadlock. 
     151         * To avoid this, we change ILEVEL to 0. 
     152         */ 
     153        struct cf_mips_dev *dev=dev_id; 
     154         
     155        set_gpio_bit(0, ILEVEL, dev); 
     156        set_gpio_bit(0, ISTAT, dev); 
     157         
     158        del_timer(&dev->to_timer); 
     159        tasklet_schedule(&dev->tasklet); 
     160        return IRQ_HANDLED; 
     161} 
     162 
     163static int do_reset(struct cf_mips_dev *dev) 
     164{ 
     165        printk(KERN_INFO "cf-mips: resetting..\n"); 
     166 
     167        wareg(ATA_REG_DC_SRST, ATA_REG_DC,dev); 
     168        udelay(1);              /* FIXME: how long should we wait here? */ 
     169        wareg(0, ATA_REG_DC,dev); 
     170 
     171        return wait_not_busy(30 * SECS, 1,dev); 
     172} 
     173 
     174static int set_multiple(struct cf_mips_dev *dev) 
     175{ 
     176        if (dev->block_size <= 1) 
     177                return CF_TRANS_OK; 
     178 
     179        wareg(dev->block_size, ATA_REG_SC,dev); 
     180        wareg(ATA_REG_DH_BASE | ATA_REG_DH_LBA, ATA_REG_DH,dev); 
     181        wareg(ATA_CMD_SET_MULTIPLE, ATA_REG_CMD,dev); 
     182 
     183        return wait_not_busy(10 * SECS, 1,dev); 
     184} 
     185 
     186static int set_cmd(struct cf_mips_dev *dev) 
     187{ 
     188        //DEBUGP(KERN_INFO "cf-mips: ata cmd 0x%02x\n", dev->tcmd); 
     189        // sector_count should be <=24 bits.. 
     190        BUG_ON(dev->tsect_start>=0x10000000); 
     191        // This way, it addresses 2^24 * 512 = 128G 
     192 
     193        if (dev->tsector_count) { 
     194                wareg(dev->tsector_count & 0xff, ATA_REG_SC,dev); 
     195                wareg(dev->tsect_start & 0xff, ATA_REG_SN,dev); 
     196                wareg((dev->tsect_start >> 8) & 0xff, ATA_REG_CL,dev); 
     197                wareg((dev->tsect_start >> 16) & 0xff, ATA_REG_CH,dev); 
     198        } 
     199        wareg(((dev->tsect_start >> 24) & 0x0f) | ATA_REG_DH_BASE | ATA_REG_DH_LBA, 
     200              ATA_REG_DH,dev);  /* select drive on all commands */ 
     201        wareg(dev->tcmd, ATA_REG_CMD,dev); 
     202        return wait_not_busy(10 * SECS, 1,dev); 
     203} 
     204 
     205static int do_trans(struct cf_mips_dev *dev) 
     206{ 
     207        int res; 
     208        unsigned st; 
     209        int transfered; 
     210         
     211        //printk("do_trans: %d sectors left\n",dev->tsectors_left); 
     212        while (dev->tsectors_left) { 
     213                transfered = 0; 
     214 
     215                st = rareg(ATA_REG_ST,dev); 
     216                if (!(st & ATA_REG_ST_DRQ)) { 
     217                        printk(KERN_ERR "cf-mips: do_trans without DRQ (status 0x%x)!\n", st); 
     218                        if (st & ATA_REG_ST_ERR) { 
     219                                int errId = rareg(ATA_REG_ERR,dev); 
     220                                printk(KERN_ERR "cf-mips: %s error, status 0x%x, errid 0x%x\n", 
     221                                       (dev->tread ? "read" : "write"), st, errId); 
     222                        } 
     223                        return CF_TRANS_FAILED; 
     224                } 
     225                do { /* Fill/read the buffer one block */ 
     226                        u32 *qbuf, *qend; 
     227                        qbuf = (u32 *)dev->tbuf; 
     228                        qend = qbuf + CF_SECT_SIZE / sizeof(u32); 
     229                        if (dev->tread) { 
     230                            while (qbuf!=qend) 
     231                                put_unaligned(*DBUF32,qbuf++); 
     232                                //*(qbuf++) = *DBUF32; 
     233                        } 
     234                        else { 
     235                            while(qbuf!=qend) 
     236                                *DBUF32 = get_unaligned(qbuf++); 
     237                        } 
     238 
     239                        dev->tsectors_left--; 
     240                        dev->tbuf += CF_SECT_SIZE; 
     241                        dev->tbuf_size -= CF_SECT_SIZE; 
     242                        transfered++; 
     243                } while (transfered != dev->block_size && dev->tsectors_left > 0); 
     244 
     245                res = wait_not_busy(10 * SECS, 1,dev); 
     246                if (res != CF_TRANS_OK) 
     247                        return res; 
     248        }; 
     249 
     250        st = rareg(ATA_REG_ST,dev); 
     251        if (st & (ATA_REG_ST_DRQ | ATA_REG_ST_DWF | ATA_REG_ST_ERR)) { 
     252                if (st & ATA_REG_ST_DRQ) { 
     253                        printk(KERN_ERR "cf-mips: DRQ after all %d sectors are %s" 
     254                               ", status 0x%x\n", dev->tsector_count, (dev->tread ? "read" : "written"), st); 
     255                } else if (st & ATA_REG_ST_DWF) { 
     256                        printk(KERN_ERR "cf-mips: write fault, status 0x%x\n", st); 
     257                } else { 
     258                        int errId = rareg(ATA_REG_ERR,dev); 
     259                        printk(KERN_ERR "cf-mips: %s error, status 0x%x, errid 0x%x\n", 
     260                               (dev->tread ? "read" : "write"), st, errId); 
     261                } 
     262                return CF_TRANS_FAILED; 
     263        } 
     264        return CF_TRANS_OK; 
     265} 
     266 
     267static int cf_do_state(struct cf_mips_dev *dev) 
     268{ 
     269        int res; 
     270        switch (dev->tstate) {  /* fall through everywhere */ 
     271        case TS_IDLE: 
     272                dev->tstate = TS_READY; 
     273                if (is_busy(dev)) { 
     274                        dev->tstate = TS_AFTER_RESET; 
     275                        res = do_reset(dev); 
     276                        if (res != CF_TRANS_OK) 
     277                                break; 
     278                } 
     279        case TS_AFTER_RESET: 
     280                if (dev->tstate == TS_AFTER_RESET) { 
     281                        dev->tstate = TS_READY; 
     282                        res = set_multiple(dev); 
     283                        if (res != CF_TRANS_OK) 
     284                                break; 
     285                } 
     286        case TS_READY: 
     287                dev->tstate = TS_CMD; 
     288                res = set_cmd(dev); 
     289                if (res != CF_TRANS_OK) 
     290                        break;; 
     291        case TS_CMD: 
     292                dev->tstate = TS_TRANS; 
     293        case TS_TRANS: 
     294                res = do_trans(dev); 
     295                break; 
     296        default: 
     297                printk(KERN_ERR "cf-mips: BUG: unknown tstate %d\n", dev->tstate); 
     298                return CF_TRANS_FAILED; 
     299        } 
     300        if (res != CF_TRANS_IN_PROGRESS) 
     301                dev->tstate = TS_IDLE; 
     302        return res; 
     303} 
     304 
     305static void cf_do_tasklet(unsigned long dev_l) 
     306{ 
     307        struct cf_mips_dev* dev=(struct cf_mips_dev*) dev_l; 
     308        int res; 
     309 
     310        disable_irq(dev->irq); 
     311 
     312        if (dev->tstate == TS_IDLE) 
     313                return;         /* can happen when irq is first registered */ 
     314 
     315#if 0 
     316        DEBUGP(KERN_WARNING "cf-mips:   not busy ok (tasklet)  status 0x%02x\n", 
     317               (unsigned) rareg(ATA_REG_ST,dev)); 
     318#endif 
     319 
     320        res = cf_do_state(dev); 
     321        if (res == CF_TRANS_IN_PROGRESS) 
     322                return; 
     323        cf_async_trans_done(dev,res); 
     324} 
     325 
     326static void cf_async_timeout(unsigned long dev_l) 
     327{ 
     328        struct cf_mips_dev* dev=(struct cf_mips_dev*) dev_l; 
     329        disable_irq(dev->irq); 
     330        /* Perhaps send abort to the device? */ 
     331        printk(KERN_ERR "cf-mips:  wait not busy timeout (%lus)" 
     332               ", status 0x%02x, state %d\n", 
     333               jiffies - dev->irq_enable_time, (unsigned) rareg(ATA_REG_ST,dev), dev->tstate); 
     334        dev->tstate = TS_IDLE; 
     335        cf_async_trans_done(dev,CF_TRANS_FAILED); 
     336} 
     337 
     338int cf_do_transfer(struct cf_mips_dev* dev,sector_t sector, unsigned long nsect,  
     339        char* buffer, int is_write) 
     340{ 
     341        BUG_ON(dev->tstate!=TS_IDLE); 
     342        if (nsect > ATA_MAX_SECT_PER_CMD) { 
     343                printk(KERN_WARNING "cf-mips: sector count %lu out of range\n",nsect); 
     344                return CF_TRANS_FAILED; 
     345        } 
     346        if (sector + nsect > dev->sectors) { 
     347                printk(KERN_WARNING "cf-mips: sector %lu out of range\n",sector); 
     348                return CF_TRANS_FAILED; 
     349        } 
     350        dev->tbuf = buffer; 
     351        dev->tbuf_size = nsect*512; 
     352        dev->tsect_start = sector; 
     353        dev->tsector_count = nsect; 
     354        dev->tsectors_left = dev->tsector_count; 
     355        dev->tread = (is_write)?0:1; 
     356         
     357        dev->tcmd = (dev->block_size == 1 ? 
     358                (is_write ? ATA_CMD_WRITE_SECTORS : ATA_CMD_READ_SECTORS) : 
     359                (is_write ? ATA_CMD_WRITE_MULTIPLE : ATA_CMD_READ_MULTIPLE)); 
     360 
     361        return cf_do_state(dev); 
     362} 
     363 
     364static int do_identify(struct cf_mips_dev *dev) 
     365{ 
     366        u16 sbuf[CF_SECT_SIZE >> 1]; 
     367        int res; 
     368        char tstr[17]; //serial 
     369        BUG_ON(dev->tstate!=TS_IDLE); 
     370        dev->tbuf = (char *) sbuf; 
     371        dev->tbuf_size = CF_SECT_SIZE; 
     372        dev->tsect_start = 0; 
     373        dev->tsector_count = 0; 
     374        dev->tsectors_left = 1; 
     375        dev->tread = 1; 
     376        dev->tcmd = ATA_CMD_IDENTIFY_DRIVE; 
     377 
     378        DEBUGP(KERN_INFO "cf-mips: identify drive..\n"); 
     379        res = cf_do_state(dev); 
     380        if (res == CF_TRANS_IN_PROGRESS) { 
     381                printk(KERN_ERR "cf-mips: BUG: async identify cmd\n"); 
     382                return CF_TRANS_FAILED; 
     383        } 
     384        if (res != CF_TRANS_OK) 
     385                return 0; 
     386 
     387        dev->head = sbuf[3]; 
     388        dev->cyl = sbuf[1]; 
     389        dev->spt = sbuf[6]; 
     390        dev->sectors = ((unsigned long) sbuf[7] << 16) | sbuf[8]; 
     391        dev->dtype=sbuf[0]; 
     392        memcpy(tstr,&sbuf[12],16); 
     393        tstr[16]=0; 
     394        printk(KERN_INFO "cf-mips: %s detected, C/H/S=%d/%d/%d sectors=%u (%uMB) Serial=%s\n", 
     395               (sbuf[0] == 0x848A ? "CF card" : "ATA drive"), dev->cyl, dev->head, 
     396               dev->spt, dev->sectors, dev->sectors >> 11,tstr); 
     397        return 1; 
     398} 
     399 
     400static void init_multiple(struct cf_mips_dev * dev) 
     401{ 
     402        int res; 
     403        DEBUGP(KERN_INFO "cf-mips: detecting block size\n"); 
     404 
     405        dev->block_size = 128;  /* max block size = 128 sectors (64KB) */ 
     406        do { 
     407                wareg(dev->block_size, ATA_REG_SC,dev); 
     408                wareg(ATA_REG_DH_BASE | ATA_REG_DH_LBA, ATA_REG_DH,dev); 
     409                wareg(ATA_CMD_SET_MULTIPLE, ATA_REG_CMD,dev); 
     410 
     411                res = wait_not_busy(10 * SECS, 1,dev); 
     412                if (res != CF_TRANS_OK) { 
     413                        printk(KERN_ERR "cf-mips: failed to detect block size: busy!\n"); 
     414                        dev->block_size = 1; 
     415                        return; 
     416                } 
     417                if ((rareg(ATA_REG_ST,dev) & ATA_REG_ST_ERR) == 0) 
     418                        break; 
     419                dev->block_size /= 2; 
     420        } while (dev->block_size > 1); 
     421 
     422        printk(KERN_INFO "cf-mips: multiple sectors = %d\n", dev->block_size); 
     423} 
     424 
     425int cf_init(struct cf_mips_dev *dev) 
     426{ 
     427        tasklet_init(&dev->tasklet,cf_do_tasklet,(unsigned long)dev); 
     428        dev->baddr = ioremap_nocache((unsigned long)dev->base, CFDEV_BUF_SIZE); 
     429        if (!dev->baddr) { 
     430                printk(KERN_ERR "cf-mips: cf_init: ioremap for (%lx,%x) failed\n", 
     431                       (unsigned long) dev->base, CFDEV_BUF_SIZE); 
     432                return -EBUSY; 
     433        } 
     434 
     435        if (!cf_present(dev)) { 
     436                printk(KERN_WARNING "cf-mips: cf card not present\n"); 
     437                iounmap(dev->baddr); 
     438                return -ENODEV; 
     439        } 
     440 
     441        if (do_reset(dev) != CF_TRANS_OK) { 
     442                printk(KERN_ERR "cf-mips: cf reset failed\n"); 
     443                iounmap(dev->baddr); 
     444                return -EBUSY; 
     445        } 
     446 
     447        if (!do_identify(dev)) { 
     448                printk(KERN_ERR "cf-mips: cf identify failed\n"); 
     449                iounmap(dev->baddr); 
     450                return -EBUSY; 
     451        } 
     452 
     453/*      set_apm_level(ATA_APM_WITH_STANDBY); */ 
     454        init_multiple(dev); 
     455 
     456        init_timer(&dev->to_timer); 
     457        dev->to_timer.function = cf_async_timeout; 
     458        dev->to_timer.data = (unsigned long)dev; 
     459 
     460        prepare_cf_irq(dev); 
     461        if (request_irq(dev->irq, cf_irq_handler, 0, "CF Mips", dev)) { 
     462                printk(KERN_ERR "cf-mips: failed to get irq\n"); 
     463                iounmap(dev->baddr); 
     464                return -EBUSY; 
     465        } 
     466        /* Disable below would be odd, because request will enable, and the tasklet 
     467          will disable it itself */ 
     468        //disable_irq(dev->irq); 
     469         
     470        dev->async_mode = 1; 
     471 
     472        return 0; 
     473} 
     474 
     475void cf_cleanup(struct cf_mips_dev *dev) 
     476{ 
     477        iounmap(dev->baddr); 
     478        free_irq(dev->irq, NULL); 
     479#if REQUEST_MEM_REGION 
     480        release_mem_region((unsigned long)dev->base, CFDEV_BUF_SIZE); 
     481#endif 
     482} 
     483 
     484 
     485/*eof*/ 
  • drivers/block/rb500/ata.h

    diff -urN linux.old/drivers/block/rb500/ata.h linux.dev/drivers/block/rb500/ata.h
    old new  
     1/* CF-mips driver 
     2   This is a block driver for the direct (mmaped) interface to the CF-slot, 
     3   found in Routerboard.com's RB532 board 
     4   See SDK provided from routerboard.com. 
     5    
     6   Module adapted By P.Christeas <p_christeas@yahoo.com>, 2005-6. 
     7   Cleaned up and adapted to platform_device by Felix Fietkau <nbd@openwrt.org> 
     8 
     9   This work is redistributed under the terms of the GNU General Public License. 
     10*/ 
     11 
     12#ifndef __CFMIPS_ATA_H__ 
     13#define __CFMIPS_ATA_H__ 
     14 
     15#include <linux/interrupt.h> 
     16 
     17#define CFG_DC_DEV1     (void*)0xb8010010 
     18#define   CFG_DC_DEVBASE        0x0 
     19#define   CFG_DC_DEVMASK        0x4 
     20#define   CFG_DC_DEVC           0x8 
     21#define   CFG_DC_DEVTC          0xC 
     22 
     23#define CFDEV_BUF_SIZE  0x1000 
     24#define ATA_CIS_OFFSET  0x200 
     25#define ATA_REG_OFFSET  0x800 
     26#define ATA_DBUF_OFFSET 0xC00 
     27 
     28#define ATA_REG_FEAT    0x1 
     29#define ATA_REG_SC      0x2 
     30#define ATA_REG_SN      0x3 
     31#define ATA_REG_CL      0x4 
     32#define ATA_REG_CH      0x5 
     33#define ATA_REG_DH      0x6 
     34#define   ATA_REG_DH_BASE       0xa0 
     35#define   ATA_REG_DH_LBA        0x40 
     36#define   ATA_REG_DH_DRV        0x10 
     37#define ATA_REG_CMD     0x7 
     38#define ATA_REG_ST      0x7 
     39#define   ATA_REG_ST_BUSY       0x80 
     40#define   ATA_REG_ST_RDY        0x40 
     41#define   ATA_REG_ST_DWF        0x20 
     42#define   ATA_REG_ST_DSC        0x10 
     43#define   ATA_REG_ST_DRQ        0x08 
     44#define   ATA_REG_ST_CORR       0x04 
     45#define   ATA_REG_ST_ERR        0x01 
     46#define ATA_REG_ERR     0xd 
     47#define ATA_REG_DC      0xe 
     48#define   ATA_REG_DC_IEN        0x02 
     49#define   ATA_REG_DC_SRST       0x04 
     50 
     51#define ATA_CMD_READ_SECTORS    0x20 
     52#define ATA_CMD_WRITE_SECTORS   0x30 
     53#define ATA_CMD_EXEC_DRIVE_DIAG 0x90 
     54#define ATA_CMD_READ_MULTIPLE   0xC4 
     55#define ATA_CMD_WRITE_MULTIPLE  0xC5 
     56#define ATA_CMD_SET_MULTIPLE    0xC6 
     57#define ATA_CMD_IDENTIFY_DRIVE  0xEC 
     58#define ATA_CMD_SET_FEATURES    0xEF 
     59 
     60#define ATA_FEATURE_ENABLE_APM  0x05 
     61#define ATA_FEATURE_DISABLE_APM 0x85 
     62#define ATA_APM_DISABLED        0x00 
     63#define ATA_APM_MIN_POWER       0x01 
     64#define ATA_APM_WITH_STANDBY    0x7f 
     65#define ATA_APM_WITHOUT_STANDBY 0x80 
     66#define ATA_APM_MAX_PERFORMANCE 0xfe 
     67 
     68#define CF_SECT_SIZE    0x200 
     69/* That is the ratio CF_SECT_SIZE/512 (the kernel sector size) */ 
     70#define CF_KERNEL_MUL   1 
     71#define ATA_MAX_SECT_PER_CMD    0x100 
     72 
     73#define CF_TRANS_FAILED         0 
     74#define CF_TRANS_OK             1 
     75#define CF_TRANS_IN_PROGRESS    2 
     76 
     77 
     78enum trans_state { 
     79        TS_IDLE = 0, 
     80        TS_AFTER_RESET, 
     81        TS_READY, 
     82        TS_CMD, 
     83        TS_TRANS 
     84}; 
     85 
     86//  
     87// #if DEBUG 
     88// static unsigned long busy_time; 
     89// #endif 
     90 
     91/** Struct to hold the cfdev 
     92Actually, all the data here only has one instance. However, for  
     93reasons of programming conformity, it is passed around as a pointer 
     94*/ 
     95struct cf_mips_dev { 
     96        void *base; /* base address for I/O */ 
     97        void *baddr; /* remapped address */ 
     98 
     99        int pin; /* gpio pin */ 
     100        int irq; /* gpio irq */ 
     101         
     102        unsigned head; 
     103        unsigned cyl; 
     104        unsigned spt; 
     105        unsigned sectors; 
     106         
     107        unsigned short block_size; 
     108        unsigned dtype ; // ATA or CF 
     109        struct request_queue *queue; 
     110        struct gendisk  *gd; 
     111         
     112        /* Transaction state */ 
     113        enum trans_state tstate; 
     114        char *tbuf; 
     115        unsigned long tbuf_size; 
     116        sector_t tsect_start; 
     117        unsigned tsector_count; 
     118        unsigned tsectors_left; 
     119        int tread; 
     120        unsigned tcmd; 
     121        int async_mode; 
     122        unsigned long irq_enable_time; 
     123         
     124        struct request *active_req; /* A request is being carried out. Is that different from tstate? */ 
     125        int users; 
     126        struct timer_list to_timer; 
     127        struct tasklet_struct tasklet; 
     128 
     129        /** This lock ensures that the requests to this device are all done 
     130        atomically. Transfers can run in parallel, requests are all queued 
     131        one-by-one */ 
     132        spinlock_t lock; 
     133}; 
     134 
     135int cf_do_transfer(struct cf_mips_dev* dev,sector_t sector, unsigned long nsect,  
     136        char* buffer, int is_write); 
     137int cf_init(struct cf_mips_dev* dev); 
     138void cf_cleanup(struct cf_mips_dev* dev); 
     139 
     140void cf_async_trans_done(struct cf_mips_dev* dev, int result); 
     141// void *cf_get_next_buf(unsigned long *buf_size); 
     142 
     143#endif 
  • drivers/block/rb500/bdev.c

    diff -urN linux.old/drivers/block/rb500/bdev.c linux.dev/drivers/block/rb500/bdev.c
    old new  
     1/* CF-mips driver 
     2   This is a block driver for the direct (mmaped) interface to the CF-slot, 
     3   found in Routerboard.com's RB532 board 
     4   See SDK provided from routerboard.com. 
     5    
     6   Module adapted By P.Christeas <p_christeas@yahoo.com>, 2005-6. 
     7   Cleaned up and adapted to platform_device by Felix Fietkau <nbd@openwrt.org> 
     8 
     9   This work is redistributed under the terms of the GNU General Public License. 
     10*/ 
     11 
     12#include <linux/kernel.h> 
     13#include <linux/module.h> 
     14#include <linux/init.h> 
     15#include <linux/time.h> 
     16#include <linux/wait.h> 
     17#include <linux/fs.h> 
     18#include <linux/genhd.h> 
     19#include <linux/blkdev.h> 
     20#include <linux/blkpg.h> 
     21#include <linux/hdreg.h> 
     22#include <linux/platform_device.h> 
     23 
     24#include <asm/uaccess.h> 
     25#include <asm/io.h> 
     26 
     27#include <asm/rc32434/rb.h> 
     28 
     29#ifdef DEBUG 
     30#define DEBUGP printk 
     31#define DLEVEL 1 
     32#else 
     33#define DEBUGP(format, args...) 
     34#define DLEVEL 0 
     35#endif 
     36 
     37#define CF_MIPS_MAJOR 13 
     38#define MAJOR_NR        CF_MIPS_MAJOR 
     39#define CF_MAX_PART     16              /* max 15 partitions */ 
     40 
     41#include "ata.h" 
     42 
     43//extern struct block_device_operations cf_bdops; 
     44 
     45// static struct hd_struct cf_parts[CF_MAX_PART]; 
     46// static int cf_part_sizes[CF_MAX_PART]; 
     47// static int cf_hsect_sizes[CF_MAX_PART]; 
     48// static int cf_max_sectors[CF_MAX_PART]; 
     49// static int cf_blksize_sizes[CF_MAX_PART]; 
     50 
     51// static spinlock_t lock = SPIN_LOCK_UNLOCKED; 
     52 
     53// volatile int cf_busy = 0; 
     54 
     55static struct request *active_req = NULL; 
     56 
     57static int cf_open (struct inode *, struct file *); 
     58static int cf_release (struct inode *, struct file *); 
     59static int cf_ioctl (struct inode *, struct file *, unsigned, unsigned long); 
     60 
     61static void cf_request(request_queue_t * q); 
     62static int cf_transfer(const struct request *req); 
     63 
     64/*long (*unlocked_ioctl) (struct file *, unsigned, unsigned long); 
     65long (*compat_ioctl) (struct file *, unsigned, unsigned long);*/ 
     66// int (*direct_access) (struct block_device *, sector_t, unsigned long *); 
     67// int (*media_changed) (struct gendisk *); 
     68// int (*revalidate_disk) (struct gendisk *); 
     69 
     70static struct block_device_operations cf_bdops = { 
     71      .owner = THIS_MODULE, 
     72      .open = cf_open, 
     73      .release = cf_release, 
     74      .ioctl = cf_ioctl, 
     75      .media_changed = NULL, 
     76      .unlocked_ioctl = NULL, 
     77      .revalidate_disk = NULL, 
     78      .compat_ioctl = NULL, 
     79      .direct_access = NULL 
     80}; 
     81 
     82 
     83int cf_mips_probe(struct platform_device *pdev) 
     84{ 
     85        struct gendisk* cf_gendisk=NULL; 
     86        struct cf_device *cdev = (struct cf_device *) pdev->dev.platform_data; 
     87        struct cf_mips_dev *dev; 
     88        struct resource *r; 
     89        int reg_result; 
     90 
     91        reg_result = register_blkdev(MAJOR_NR, "cf-mips"); 
     92        if (reg_result < 0) { 
     93                printk(KERN_WARNING "cf-mips: can't get major %d\n", MAJOR_NR); 
     94                return reg_result; 
     95        } 
     96 
     97        dev = (struct cf_mips_dev *)kmalloc(sizeof(struct cf_mips_dev),GFP_KERNEL); 
     98        if (!dev) 
     99                goto out_err; 
     100        memset(dev, 0, sizeof(struct cf_mips_dev)); 
     101        cdev->dev = dev; 
     102         
     103        dev->pin = cdev->gpio_pin; 
     104        dev->irq = platform_get_irq_byname(pdev, "cf_irq"); 
     105        r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cf_membase"); 
     106        dev->base = (void *) r->start; 
     107         
     108        if (cf_init(dev)) goto out_err; 
     109        printk("init done"); 
     110         
     111        spin_lock_init(&dev->lock); 
     112        dev->queue = blk_init_queue(cf_request,&dev->lock); 
     113        if (!dev->queue){ 
     114                printk(KERN_ERR "cf-mips: no mem for queue\n"); 
     115                goto out_err; 
     116        } 
     117        blk_queue_max_sectors(dev->queue,ATA_MAX_SECT_PER_CMD); 
     118 
     119        /* For memory devices, it is always better to avoid crossing segments 
     120        inside the same request. */ 
     121/*      if (dev->dtype==0x848A){ 
     122                printk(KERN_INFO "Setting boundary for cf to 0x%x",(dev->block_size*512)-1); 
     123                blk_queue_segment_boundary(dev->queue, (dev->block_size*512)-1); 
     124        }*/ 
     125 
     126        dev->gd = alloc_disk(CF_MAX_PART); 
     127        cf_gendisk = dev->gd; 
     128        cdev->gd = dev->gd; 
     129        if (!cf_gendisk) goto out_err; /* Last of these goto's */ 
     130         
     131        cf_gendisk->major = MAJOR_NR; 
     132        cf_gendisk->first_minor = 0; 
     133        cf_gendisk->queue=dev->queue; 
     134        BUG_ON(cf_gendisk->minors != CF_MAX_PART); 
     135        strcpy(cf_gendisk->disk_name,"cfa"); 
     136        cf_gendisk->fops = &cf_bdops; 
     137        cf_gendisk->flags = 0 ; /* is not yet GENHD_FL_REMOVABLE */ 
     138        cf_gendisk->private_data=dev; 
     139         
     140        set_capacity(cf_gendisk,dev->sectors * CF_KERNEL_MUL); 
     141         
     142        /* Let the disk go live */ 
     143        add_disk(cf_gendisk); 
     144#if 0 
     145        result = cf_init(); 
     146         
     147        /* default cfg for all partitions */ 
     148        memset(cf_parts, 0, sizeof (cf_parts[0]) * CF_MAX_PART); 
     149        memset(cf_part_sizes, 0, sizeof (cf_part_sizes[0]) * CF_MAX_PART); 
     150        for (i = 0; i < CF_MAX_PART; ++i) { 
     151                cf_hsect_sizes[i] = CF_SECT_SIZE; 
     152                cf_max_sectors[i] = ATA_MAX_SECT_PER_CMD; 
     153                cf_blksize_sizes[i] = BLOCK_SIZE; 
     154        } 
     155 
     156        /* setup info for whole disk (partition 0) */ 
     157        cf_part_sizes[0] = cf_sectors / 2; 
     158        cf_parts[0].nr_sects = cf_sectors; 
     159 
     160        blk_size[MAJOR_NR] = cf_part_sizes; 
     161        blksize_size[MAJOR_NR] = cf_blksize_sizes; 
     162        max_sectors[MAJOR_NR] = cf_max_sectors; 
     163        hardsect_size[MAJOR_NR] = cf_hsect_sizes; 
     164        read_ahead[MAJOR_NR] = 8;       /* (4kB) */ 
     165 
     166        blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); 
     167 
     168        add_gendisk(&cf_gendisk); 
     169#endif 
     170//      printk(KERN_INFO "cf-mips partition check: \n"); 
     171//      register_disk(cf_gendisk, MKDEV(MAJOR_NR, 0), CF_MAX_PART, 
     172//                    &cf_bdops, dev->sectors); 
     173        return 0; 
     174 
     175out_err: 
     176        if (dev->queue){ 
     177                blk_cleanup_queue(dev->queue); 
     178        } 
     179        if (reg_result) { 
     180                unregister_blkdev(MAJOR_NR, "cf-mips"); 
     181                return reg_result; 
     182        } 
     183        if (dev){ 
     184                cf_cleanup(dev); 
     185                kfree(dev); 
     186        } 
     187        return 1; 
     188} 
     189 
     190static int 
     191cf_mips_remove(struct platform_device *pdev) 
     192{ 
     193        struct cf_device *cdev = (struct cf_device *) pdev->dev.platform_data; 
     194        struct cf_mips_dev *dev = (struct cf_mips_dev *) cdev->dev; 
     195         
     196        unregister_blkdev(MAJOR_NR, "cf-mips"); 
     197        blk_cleanup_queue(dev->queue); 
     198 
     199        del_gendisk(dev->gd); 
     200        cf_cleanup(dev); 
     201        return 0; 
     202} 
     203 
     204 
     205static struct platform_driver cf_driver = { 
     206        .driver.name = "rb500-cf", 
     207        .probe = cf_mips_probe, 
     208        .remove = cf_mips_remove, 
     209}; 
     210 
     211static int __init cf_mips_init(void) 
     212{ 
     213        printk(KERN_INFO "cf-mips module loaded\n"); 
     214        return platform_driver_register(&cf_driver); 
     215} 
     216 
     217static void cf_mips_cleanup(void) 
     218{ 
     219        platform_driver_unregister(&cf_driver); 
     220        printk(KERN_INFO "cf-mips module removed\n"); 
     221} 
     222 
     223module_init(cf_mips_init); 
     224module_exit(cf_mips_cleanup); 
     225 
     226MODULE_LICENSE("GPL"); 
     227MODULE_ALIAS_BLOCKDEV_MAJOR(CF_MIPS_MAJOR); 
     228 
     229 
     230static int cf_open(struct inode *inode, struct file *filp) 
     231{ 
     232        struct cf_mips_dev  *dev=inode->i_bdev->bd_disk->private_data; 
     233        int minor = MINOR(inode->i_rdev); 
     234         
     235        if (minor >= CF_MAX_PART) 
     236                return -ENODEV; 
     237        //DEBUGP(KERN_INFO "cf-mips module opened, minor %d\n", minor); 
     238        spin_lock(&dev->lock); 
     239        dev->users++; 
     240        spin_unlock(&dev->lock); 
     241        filp->private_data=dev; 
     242         
     243        /* dirty workaround to set CFRDY GPIO as an input when some other 
     244           program sets it as an output */ 
     245        gpio_set(CFG, (1 << dev->pin), 0); 
     246        return 0;               /* success */ 
     247} 
     248 
     249static int cf_release(struct inode *inode, struct file *filp) 
     250{ 
     251        int minor = MINOR(inode->i_rdev); 
     252        struct cf_mips_dev  *dev=inode->i_bdev->bd_disk->private_data; 
     253        spin_lock(&dev->lock); 
     254        dev->users--; 
     255        spin_unlock(&dev->lock); 
     256        return 0; 
     257} 
     258 
     259static int cf_ioctl(struct inode *inode, struct file *filp, 
     260         unsigned int cmd, unsigned long arg) 
     261{ 
     262        unsigned minor = MINOR(inode->i_rdev); 
     263        struct cf_mips_dev  *dev=inode->i_bdev->bd_disk->private_data; 
     264 
     265        DEBUGP(KERN_INFO "cf_ioctl cmd %u\n", cmd); 
     266        switch (cmd) { 
     267        case BLKRRPART: /* re-read partition table */ 
     268                if (!capable(CAP_SYS_ADMIN)) 
     269                        return -EACCES; 
     270                printk(KERN_INFO "cf-mips partition check: \n"); 
     271                register_disk(dev->gd); 
     272                return 0; 
     273 
     274        case HDIO_GETGEO: 
     275                { 
     276                        struct hd_geometry geo; 
     277                        geo.cylinders = dev->cyl; 
     278                        geo.heads = dev->head; 
     279                        geo.sectors = dev->spt; 
     280                        geo.start = (*dev->gd->part)[minor].start_sect; 
     281                        if (copy_to_user((void *) arg, &geo, sizeof (geo))) 
     282                                return -EFAULT; 
     283                } 
     284                return 0; 
     285        } 
     286 
     287        return -EINVAL;         /* unknown command */ 
     288} 
     289 
     290static void cf_request(request_queue_t * q) 
     291{ 
     292        struct cf_mips_dev* dev; 
     293         
     294        struct request * req; 
     295        int status; 
     296 
     297        /* We could have q->queuedata = dev , but haven't yet. */ 
     298        if (active_req) 
     299                return; 
     300 
     301        while ((req=elv_next_request(q))!=NULL){ 
     302                dev=req->rq_disk->private_data; 
     303                status=cf_transfer(req); 
     304                if (status==CF_TRANS_IN_PROGRESS){ 
     305                        active_req=req; 
     306                        return; 
     307                } 
     308                end_request(req,status); 
     309        } 
     310} 
     311 
     312static int cf_transfer(const struct request *req) 
     313{ 
     314        struct cf_mips_dev* dev=req->rq_disk->private_data; 
     315 
     316        if (!blk_fs_request(req)){       
     317                if (printk_ratelimit()) 
     318                        printk(KERN_WARNING "cf-mips: skipping non-fs request 0x%x\n",req->cmd[0]); 
     319                return CF_TRANS_FAILED; 
     320        } 
     321         
     322        return cf_do_transfer(dev,req->sector,req->current_nr_sectors,req->buffer,rq_data_dir(req)); 
     323} 
     324 
     325void cf_async_trans_done(struct cf_mips_dev * dev,int result) 
     326{ 
     327        struct request *req; 
     328         
     329        spin_lock(&dev->lock); 
     330        req=active_req; 
     331        active_req=NULL; 
     332        end_request(req,result); 
     333        spin_unlock(&dev->lock); 
     334 
     335        spin_lock(&dev->lock); 
     336        cf_request(dev->queue); 
     337        spin_unlock(&dev->lock); 
     338} 
     339 
  • drivers/block/rb500/Makefile

    diff -urN linux.old/drivers/block/rb500/Makefile linux.dev/drivers/block/rb500/Makefile
    old new  
     1## Makefile for the RB532 CF port 
     2 
     3obj-y           += bdev.o ata.o 
Note: See TracBrowser for help on using the repository browser.