1 diff -urN linux.old/drivers/block/Kconfig linux.dev/drivers/block/Kconfig
2 --- linux.old/drivers/block/Kconfig 2006-10-26 02:43:39.000000000 +0200
3 +++ linux.dev/drivers/block/Kconfig 2006-10-26 00:11:14.000000000 +0200
5 This driver provides Support for ATA over Ethernet block
6 devices like the Coraid EtherDrive (R) Storage Blade.
8 +config BLK_DEV_CF_MIPS
9 + bool "CF slot of RB532 board"
10 + depends on MIKROTIK_RB500
13 + The Routerboard 532 has a CF slot on it. Enable the special block
14 + device driver for it.
17 diff -urN linux.old/drivers/block/Makefile linux.dev/drivers/block/Makefile
18 --- linux.old/drivers/block/Makefile 2006-06-18 03:49:35.000000000 +0200
19 +++ linux.dev/drivers/block/Makefile 2006-10-26 02:44:10.000000000 +0200
21 obj-$(CONFIG_VIODASD) += viodasd.o
22 obj-$(CONFIG_BLK_DEV_SX8) += sx8.o
23 obj-$(CONFIG_BLK_DEV_UB) += ub.o
24 +obj-$(CONFIG_BLK_DEV_CF_MIPS) += rb500/
26 diff -urN linux.old/drivers/block/rb500/ata.c linux.dev/drivers/block/rb500/ata.c
27 --- linux.old/drivers/block/rb500/ata.c 1970-01-01 01:00:00.000000000 +0100
28 +++ linux.dev/drivers/block/rb500/ata.c 2006-10-26 00:11:14.000000000 +0200
31 + This is a block driver for the direct (mmaped) interface to the CF-slot,
32 + found in Routerboard.com's RB532 board
33 + See SDK provided from routerboard.com.
35 + Module adapted By P.Christeas <p_christeas@yahoo.com>, 2005-6.
36 + Cleaned up and adapted to platform_device by Felix Fietkau <nbd@openwrt.org>
38 + This work is redistributed under the terms of the GNU General Public License.
41 +#include <linux/kernel.h> /* printk() */
42 +#include <linux/module.h> /* module to be loadable */
43 +#include <linux/delay.h>
44 +#include <linux/sched.h>
45 +#include <linux/pci.h>
46 +#include <linux/ioport.h> /* request_mem_region() */
47 +#include <asm/unaligned.h> /* ioremap() */
48 +#include <asm/io.h> /* ioremap() */
49 +#include <asm/rc32434/rb.h>
53 +#define REQUEST_MEM_REGION 0
57 +#define DEBUGP printk
59 +#define DEBUGP(format, args...)
62 +#define SECS 1000000 /* unit for wait_not_busy() is 1us */
64 +unsigned cf_head = 0;
67 +unsigned cf_sectors = 0;
68 +static unsigned cf_block_size = 1;
69 +static void *baddr = 0;
71 +#define DBUF32 ((volatile u32 *)((unsigned long)dev->baddr | ATA_DBUF_OFFSET))
74 +static void cf_do_tasklet(unsigned long dev_l);
77 +static inline void wareg(u8 val, unsigned reg, struct cf_mips_dev* dev)
79 + writeb(val, dev->baddr + ATA_REG_OFFSET + reg);
82 +static inline u8 rareg(unsigned reg, struct cf_mips_dev* dev)
84 + return readb(dev->baddr + ATA_REG_OFFSET + reg);
87 +static inline int get_gpio_bit(gpio_func ofs, struct cf_mips_dev *dev)
89 + return (gpio_get(ofs) >> dev->pin) & 1;
92 +static inline void set_gpio_bit(int bit, gpio_func ofs, struct cf_mips_dev *dev)
94 + gpio_set(ofs, (1 << dev->pin), ((bit & 1) << dev->pin));
97 +static inline int cfrdy(struct cf_mips_dev *dev)
99 + return get_gpio_bit(DATA, dev);
102 +static inline void prepare_cf_irq(struct cf_mips_dev *dev)
104 + set_gpio_bit(1, ILEVEL, dev); /* interrupt on cf ready (not busy) */
105 + set_gpio_bit(0, ISTAT, dev); /* clear interrupt status */
108 +static inline int cf_present(struct cf_mips_dev* dev)
110 + /* TODO: read and configure CIS into memory mapped mode
111 + * TODO: parse CISTPL_CONFIG on CF+ cards to get base address (0x200)
112 + * TODO: maybe adjust power saving setting for Hitachi Microdrive
116 + /* setup CFRDY GPIO as input */
117 + set_gpio_bit(0, FUNC, dev);
118 + set_gpio_bit(0, CFG, dev);
120 + for (i = 0; i < 0x10; ++i) {
121 + if (rareg(i,dev) != 0xff)
127 +static inline int is_busy(struct cf_mips_dev *dev)
129 + return !cfrdy(dev);
132 +static int wait_not_busy(int to_us, int wait_for_busy,struct cf_mips_dev *dev)
135 + if (wait_for_busy && !is_busy(dev)) {
136 + /* busy must appear within 400ns,
137 + * but it may dissapear before we see it
138 + * => must not wait for busy in a loop
145 + udelay(1); /* never reached in async mode */
146 + if (!is_busy(dev)) {
147 + if (us_passed > 1 * SECS) {
148 + printk(KERN_WARNING "cf-mips: not busy ok (after %dus)"
149 + ", status 0x%02x\n", us_passed, (unsigned) rareg(ATA_REG_ST,dev));
151 + return CF_TRANS_OK;
153 + if (us_passed == 1 * SECS) {
154 + printk(KERN_WARNING "cf-mips: wait not busy %dus..\n", to_us);
156 + if (dev->async_mode) {
157 + dev->to_timer.expires = jiffies + (to_us * HZ / SECS);
158 + dev->irq_enable_time = jiffies;
159 + prepare_cf_irq(dev);
160 + if (is_busy(dev)) {
161 + add_timer(&dev->to_timer);
162 + enable_irq(dev->irq);
163 + return CF_TRANS_IN_PROGRESS;
168 + } while (us_passed < to_us);
170 + printk(KERN_ERR "cf-mips: wait not busy timeout (%dus)"
171 + ", status 0x%02x, state %d\n",
172 + to_us, (unsigned) rareg(ATA_REG_ST,dev), dev->tstate);
173 + return CF_TRANS_FAILED;
176 +static irqreturn_t cf_irq_handler(int irq, void *dev_id)
178 + /* While tasklet has not disabled irq, irq will be retried all the time
179 + * because of ILEVEL matching GPIO pin status => deadlock.
180 + * To avoid this, we change ILEVEL to 0.
182 + struct cf_mips_dev *dev=dev_id;
184 + set_gpio_bit(0, ILEVEL, dev);
185 + set_gpio_bit(0, ISTAT, dev);
187 + del_timer(&dev->to_timer);
188 + tasklet_schedule(&dev->tasklet);
189 + return IRQ_HANDLED;
192 +static int do_reset(struct cf_mips_dev *dev)
194 + printk(KERN_INFO "cf-mips: resetting..\n");
196 + wareg(ATA_REG_DC_SRST, ATA_REG_DC,dev);
197 + udelay(1); /* FIXME: how long should we wait here? */
198 + wareg(0, ATA_REG_DC,dev);
200 + return wait_not_busy(30 * SECS, 1,dev);
203 +static int set_multiple(struct cf_mips_dev *dev)
205 + if (dev->block_size <= 1)
206 + return CF_TRANS_OK;
208 + wareg(dev->block_size, ATA_REG_SC,dev);
209 + wareg(ATA_REG_DH_BASE | ATA_REG_DH_LBA, ATA_REG_DH,dev);
210 + wareg(ATA_CMD_SET_MULTIPLE, ATA_REG_CMD,dev);
212 + return wait_not_busy(10 * SECS, 1,dev);
215 +static int set_cmd(struct cf_mips_dev *dev)
217 + //DEBUGP(KERN_INFO "cf-mips: ata cmd 0x%02x\n", dev->tcmd);
218 + // sector_count should be <=24 bits..
219 + BUG_ON(dev->tsect_start>=0x10000000);
220 + // This way, it addresses 2^24 * 512 = 128G
222 + if (dev->tsector_count) {
223 + wareg(dev->tsector_count & 0xff, ATA_REG_SC,dev);
224 + wareg(dev->tsect_start & 0xff, ATA_REG_SN,dev);
225 + wareg((dev->tsect_start >> 8) & 0xff, ATA_REG_CL,dev);
226 + wareg((dev->tsect_start >> 16) & 0xff, ATA_REG_CH,dev);
228 + wareg(((dev->tsect_start >> 24) & 0x0f) | ATA_REG_DH_BASE | ATA_REG_DH_LBA,
229 + ATA_REG_DH,dev); /* select drive on all commands */
230 + wareg(dev->tcmd, ATA_REG_CMD,dev);
231 + return wait_not_busy(10 * SECS, 1,dev);
234 +static int do_trans(struct cf_mips_dev *dev)
240 + //printk("do_trans: %d sectors left\n",dev->tsectors_left);
241 + while (dev->tsectors_left) {
244 + st = rareg(ATA_REG_ST,dev);
245 + if (!(st & ATA_REG_ST_DRQ)) {
246 + printk(KERN_ERR "cf-mips: do_trans without DRQ (status 0x%x)!\n", st);
247 + if (st & ATA_REG_ST_ERR) {
248 + int errId = rareg(ATA_REG_ERR,dev);
249 + printk(KERN_ERR "cf-mips: %s error, status 0x%x, errid 0x%x\n",
250 + (dev->tread ? "read" : "write"), st, errId);
252 + return CF_TRANS_FAILED;
254 + do { /* Fill/read the buffer one block */
256 + qbuf = (u32 *)dev->tbuf;
257 + qend = qbuf + CF_SECT_SIZE / sizeof(u32);
260 + put_unaligned(*DBUF32,qbuf++);
261 + //*(qbuf++) = *DBUF32;
265 + *DBUF32 = get_unaligned(qbuf++);
268 + dev->tsectors_left--;
269 + dev->tbuf += CF_SECT_SIZE;
270 + dev->tbuf_size -= CF_SECT_SIZE;
272 + } while (transfered != dev->block_size && dev->tsectors_left > 0);
274 + res = wait_not_busy(10 * SECS, 1,dev);
275 + if (res != CF_TRANS_OK)
279 + st = rareg(ATA_REG_ST,dev);
280 + if (st & (ATA_REG_ST_DRQ | ATA_REG_ST_DWF | ATA_REG_ST_ERR)) {
281 + if (st & ATA_REG_ST_DRQ) {
282 + printk(KERN_ERR "cf-mips: DRQ after all %d sectors are %s"
283 + ", status 0x%x\n", dev->tsector_count, (dev->tread ? "read" : "written"), st);
284 + } else if (st & ATA_REG_ST_DWF) {
285 + printk(KERN_ERR "cf-mips: write fault, status 0x%x\n", st);
287 + int errId = rareg(ATA_REG_ERR,dev);
288 + printk(KERN_ERR "cf-mips: %s error, status 0x%x, errid 0x%x\n",
289 + (dev->tread ? "read" : "write"), st, errId);
291 + return CF_TRANS_FAILED;
293 + return CF_TRANS_OK;
296 +static int cf_do_state(struct cf_mips_dev *dev)
299 + switch (dev->tstate) { /* fall through everywhere */
301 + dev->tstate = TS_READY;
302 + if (is_busy(dev)) {
303 + dev->tstate = TS_AFTER_RESET;
304 + res = do_reset(dev);
305 + if (res != CF_TRANS_OK)
308 + case TS_AFTER_RESET:
309 + if (dev->tstate == TS_AFTER_RESET) {
310 + dev->tstate = TS_READY;
311 + res = set_multiple(dev);
312 + if (res != CF_TRANS_OK)
316 + dev->tstate = TS_CMD;
317 + res = set_cmd(dev);
318 + if (res != CF_TRANS_OK)
321 + dev->tstate = TS_TRANS;
323 + res = do_trans(dev);
326 + printk(KERN_ERR "cf-mips: BUG: unknown tstate %d\n", dev->tstate);
327 + return CF_TRANS_FAILED;
329 + if (res != CF_TRANS_IN_PROGRESS)
330 + dev->tstate = TS_IDLE;
334 +static void cf_do_tasklet(unsigned long dev_l)
336 + struct cf_mips_dev* dev=(struct cf_mips_dev*) dev_l;
339 + disable_irq(dev->irq);
341 + if (dev->tstate == TS_IDLE)
342 + return; /* can happen when irq is first registered */
345 + DEBUGP(KERN_WARNING "cf-mips: not busy ok (tasklet) status 0x%02x\n",
346 + (unsigned) rareg(ATA_REG_ST,dev));
349 + res = cf_do_state(dev);
350 + if (res == CF_TRANS_IN_PROGRESS)
352 + cf_async_trans_done(dev,res);
355 +static void cf_async_timeout(unsigned long dev_l)
357 + struct cf_mips_dev* dev=(struct cf_mips_dev*) dev_l;
358 + disable_irq(dev->irq);
359 + /* Perhaps send abort to the device? */
360 + printk(KERN_ERR "cf-mips: wait not busy timeout (%lus)"
361 + ", status 0x%02x, state %d\n",
362 + jiffies - dev->irq_enable_time, (unsigned) rareg(ATA_REG_ST,dev), dev->tstate);
363 + dev->tstate = TS_IDLE;
364 + cf_async_trans_done(dev,CF_TRANS_FAILED);
367 +int cf_do_transfer(struct cf_mips_dev* dev,sector_t sector, unsigned long nsect,
368 + char* buffer, int is_write)
370 + BUG_ON(dev->tstate!=TS_IDLE);
371 + if (nsect > ATA_MAX_SECT_PER_CMD) {
372 + printk(KERN_WARNING "cf-mips: sector count %lu out of range\n",nsect);
373 + return CF_TRANS_FAILED;
375 + if (sector + nsect > dev->sectors) {
376 + printk(KERN_WARNING "cf-mips: sector %lu out of range\n",sector);
377 + return CF_TRANS_FAILED;
379 + dev->tbuf = buffer;
380 + dev->tbuf_size = nsect*512;
381 + dev->tsect_start = sector;
382 + dev->tsector_count = nsect;
383 + dev->tsectors_left = dev->tsector_count;
384 + dev->tread = (is_write)?0:1;
386 + dev->tcmd = (dev->block_size == 1 ?
387 + (is_write ? ATA_CMD_WRITE_SECTORS : ATA_CMD_READ_SECTORS) :
388 + (is_write ? ATA_CMD_WRITE_MULTIPLE : ATA_CMD_READ_MULTIPLE));
390 + return cf_do_state(dev);
393 +static int do_identify(struct cf_mips_dev *dev)
395 + u16 sbuf[CF_SECT_SIZE >> 1];
397 + char tstr[17]; //serial
398 + BUG_ON(dev->tstate!=TS_IDLE);
399 + dev->tbuf = (char *) sbuf;
400 + dev->tbuf_size = CF_SECT_SIZE;
401 + dev->tsect_start = 0;
402 + dev->tsector_count = 0;
403 + dev->tsectors_left = 1;
405 + dev->tcmd = ATA_CMD_IDENTIFY_DRIVE;
407 + DEBUGP(KERN_INFO "cf-mips: identify drive..\n");
408 + res = cf_do_state(dev);
409 + if (res == CF_TRANS_IN_PROGRESS) {
410 + printk(KERN_ERR "cf-mips: BUG: async identify cmd\n");
411 + return CF_TRANS_FAILED;
413 + if (res != CF_TRANS_OK)
416 + dev->head = sbuf[3];
417 + dev->cyl = sbuf[1];
418 + dev->spt = sbuf[6];
419 + dev->sectors = ((unsigned long) sbuf[7] << 16) | sbuf[8];
420 + dev->dtype=sbuf[0];
421 + memcpy(tstr,&sbuf[12],16);
423 + printk(KERN_INFO "cf-mips: %s detected, C/H/S=%d/%d/%d sectors=%u (%uMB) Serial=%s\n",
424 + (sbuf[0] == 0x848A ? "CF card" : "ATA drive"), dev->cyl, dev->head,
425 + dev->spt, dev->sectors, dev->sectors >> 11,tstr);
429 +static void init_multiple(struct cf_mips_dev * dev)
432 + DEBUGP(KERN_INFO "cf-mips: detecting block size\n");
434 + dev->block_size = 128; /* max block size = 128 sectors (64KB) */
436 + wareg(dev->block_size, ATA_REG_SC,dev);
437 + wareg(ATA_REG_DH_BASE | ATA_REG_DH_LBA, ATA_REG_DH,dev);
438 + wareg(ATA_CMD_SET_MULTIPLE, ATA_REG_CMD,dev);
440 + res = wait_not_busy(10 * SECS, 1,dev);
441 + if (res != CF_TRANS_OK) {
442 + printk(KERN_ERR "cf-mips: failed to detect block size: busy!\n");
443 + dev->block_size = 1;
446 + if ((rareg(ATA_REG_ST,dev) & ATA_REG_ST_ERR) == 0)
448 + dev->block_size /= 2;
449 + } while (dev->block_size > 1);
451 + printk(KERN_INFO "cf-mips: multiple sectors = %d\n", dev->block_size);
454 +int cf_init(struct cf_mips_dev *dev)
456 + tasklet_init(&dev->tasklet,cf_do_tasklet,(unsigned long)dev);
457 + dev->baddr = ioremap_nocache((unsigned long)dev->base, CFDEV_BUF_SIZE);
459 + printk(KERN_ERR "cf-mips: cf_init: ioremap for (%lx,%x) failed\n",
460 + (unsigned long) dev->base, CFDEV_BUF_SIZE);
464 + if (!cf_present(dev)) {
465 + printk(KERN_WARNING "cf-mips: cf card not present\n");
466 + iounmap(dev->baddr);
470 + if (do_reset(dev) != CF_TRANS_OK) {
471 + printk(KERN_ERR "cf-mips: cf reset failed\n");
472 + iounmap(dev->baddr);
476 + if (!do_identify(dev)) {
477 + printk(KERN_ERR "cf-mips: cf identify failed\n");
478 + iounmap(dev->baddr);
482 +/* set_apm_level(ATA_APM_WITH_STANDBY); */
483 + init_multiple(dev);
485 + init_timer(&dev->to_timer);
486 + dev->to_timer.function = cf_async_timeout;
487 + dev->to_timer.data = (unsigned long)dev;
489 + prepare_cf_irq(dev);
490 + if (request_irq(dev->irq, cf_irq_handler, 0, "CF Mips", dev)) {
491 + printk(KERN_ERR "cf-mips: failed to get irq\n");
492 + iounmap(dev->baddr);
495 + /* Disable below would be odd, because request will enable, and the tasklet
496 + will disable it itself */
497 + //disable_irq(dev->irq);
499 + dev->async_mode = 1;
504 +void cf_cleanup(struct cf_mips_dev *dev)
506 + iounmap(dev->baddr);
507 + free_irq(dev->irq, NULL);
508 +#if REQUEST_MEM_REGION
509 + release_mem_region((unsigned long)dev->base, CFDEV_BUF_SIZE);
515 diff -urN linux.old/drivers/block/rb500/ata.h linux.dev/drivers/block/rb500/ata.h
516 --- linux.old/drivers/block/rb500/ata.h 1970-01-01 01:00:00.000000000 +0100
517 +++ linux.dev/drivers/block/rb500/ata.h 2006-10-26 00:11:14.000000000 +0200
520 + This is a block driver for the direct (mmaped) interface to the CF-slot,
521 + found in Routerboard.com's RB532 board
522 + See SDK provided from routerboard.com.
524 + Module adapted By P.Christeas <p_christeas@yahoo.com>, 2005-6.
525 + Cleaned up and adapted to platform_device by Felix Fietkau <nbd@openwrt.org>
527 + This work is redistributed under the terms of the GNU General Public License.
530 +#ifndef __CFMIPS_ATA_H__
531 +#define __CFMIPS_ATA_H__
533 +#include <linux/interrupt.h>
535 +#define CFG_DC_DEV1 (void*)0xb8010010
536 +#define CFG_DC_DEVBASE 0x0
537 +#define CFG_DC_DEVMASK 0x4
538 +#define CFG_DC_DEVC 0x8
539 +#define CFG_DC_DEVTC 0xC
541 +#define CFDEV_BUF_SIZE 0x1000
542 +#define ATA_CIS_OFFSET 0x200
543 +#define ATA_REG_OFFSET 0x800
544 +#define ATA_DBUF_OFFSET 0xC00
546 +#define ATA_REG_FEAT 0x1
547 +#define ATA_REG_SC 0x2
548 +#define ATA_REG_SN 0x3
549 +#define ATA_REG_CL 0x4
550 +#define ATA_REG_CH 0x5
551 +#define ATA_REG_DH 0x6
552 +#define ATA_REG_DH_BASE 0xa0
553 +#define ATA_REG_DH_LBA 0x40
554 +#define ATA_REG_DH_DRV 0x10
555 +#define ATA_REG_CMD 0x7
556 +#define ATA_REG_ST 0x7
557 +#define ATA_REG_ST_BUSY 0x80
558 +#define ATA_REG_ST_RDY 0x40
559 +#define ATA_REG_ST_DWF 0x20
560 +#define ATA_REG_ST_DSC 0x10
561 +#define ATA_REG_ST_DRQ 0x08
562 +#define ATA_REG_ST_CORR 0x04
563 +#define ATA_REG_ST_ERR 0x01
564 +#define ATA_REG_ERR 0xd
565 +#define ATA_REG_DC 0xe
566 +#define ATA_REG_DC_IEN 0x02
567 +#define ATA_REG_DC_SRST 0x04
569 +#define ATA_CMD_READ_SECTORS 0x20
570 +#define ATA_CMD_WRITE_SECTORS 0x30
571 +#define ATA_CMD_EXEC_DRIVE_DIAG 0x90
572 +#define ATA_CMD_READ_MULTIPLE 0xC4
573 +#define ATA_CMD_WRITE_MULTIPLE 0xC5
574 +#define ATA_CMD_SET_MULTIPLE 0xC6
575 +#define ATA_CMD_IDENTIFY_DRIVE 0xEC
576 +#define ATA_CMD_SET_FEATURES 0xEF
578 +#define ATA_FEATURE_ENABLE_APM 0x05
579 +#define ATA_FEATURE_DISABLE_APM 0x85
580 +#define ATA_APM_DISABLED 0x00
581 +#define ATA_APM_MIN_POWER 0x01
582 +#define ATA_APM_WITH_STANDBY 0x7f
583 +#define ATA_APM_WITHOUT_STANDBY 0x80
584 +#define ATA_APM_MAX_PERFORMANCE 0xfe
586 +#define CF_SECT_SIZE 0x200
587 +/* That is the ratio CF_SECT_SIZE/512 (the kernel sector size) */
588 +#define CF_KERNEL_MUL 1
589 +#define ATA_MAX_SECT_PER_CMD 0x100
591 +#define CF_TRANS_FAILED 0
592 +#define CF_TRANS_OK 1
593 +#define CF_TRANS_IN_PROGRESS 2
606 +// static unsigned long busy_time;
609 +/** Struct to hold the cfdev
610 +Actually, all the data here only has one instance. However, for
611 +reasons of programming conformity, it is passed around as a pointer
613 +struct cf_mips_dev {
614 + void *base; /* base address for I/O */
615 + void *baddr; /* remapped address */
617 + int pin; /* gpio pin */
618 + int irq; /* gpio irq */
625 + unsigned short block_size;
626 + unsigned dtype ; // ATA or CF
627 + struct request_queue *queue;
628 + struct gendisk *gd;
630 + /* Transaction state */
631 + enum trans_state tstate;
633 + unsigned long tbuf_size;
634 + sector_t tsect_start;
635 + unsigned tsector_count;
636 + unsigned tsectors_left;
640 + unsigned long irq_enable_time;
642 + struct request *active_req; /* A request is being carried out. Is that different from tstate? */
644 + struct timer_list to_timer;
645 + struct tasklet_struct tasklet;
647 + /** This lock ensures that the requests to this device are all done
648 + atomically. Transfers can run in parallel, requests are all queued
653 +int cf_do_transfer(struct cf_mips_dev* dev,sector_t sector, unsigned long nsect,
654 + char* buffer, int is_write);
655 +int cf_init(struct cf_mips_dev* dev);
656 +void cf_cleanup(struct cf_mips_dev* dev);
658 +void cf_async_trans_done(struct cf_mips_dev* dev, int result);
659 +// void *cf_get_next_buf(unsigned long *buf_size);
662 diff -urN linux.old/drivers/block/rb500/bdev.c linux.dev/drivers/block/rb500/bdev.c
663 --- linux.old/drivers/block/rb500/bdev.c 1970-01-01 01:00:00.000000000 +0100
664 +++ linux.dev/drivers/block/rb500/bdev.c 2006-10-26 00:11:14.000000000 +0200
667 + This is a block driver for the direct (mmaped) interface to the CF-slot,
668 + found in Routerboard.com's RB532 board
669 + See SDK provided from routerboard.com.
671 + Module adapted By P.Christeas <p_christeas@yahoo.com>, 2005-6.
672 + Cleaned up and adapted to platform_device by Felix Fietkau <nbd@openwrt.org>
674 + This work is redistributed under the terms of the GNU General Public License.
677 +#include <linux/kernel.h>
678 +#include <linux/module.h>
679 +#include <linux/init.h>
680 +#include <linux/time.h>
681 +#include <linux/wait.h>
682 +#include <linux/fs.h>
683 +#include <linux/genhd.h>
684 +#include <linux/blkdev.h>
685 +#include <linux/blkpg.h>
686 +#include <linux/hdreg.h>
687 +#include <linux/platform_device.h>
689 +#include <asm/uaccess.h>
692 +#include <asm/rc32434/rb.h>
695 +#define DEBUGP printk
698 +#define DEBUGP(format, args...)
702 +#define CF_MIPS_MAJOR 13
703 +#define MAJOR_NR CF_MIPS_MAJOR
704 +#define CF_MAX_PART 16 /* max 15 partitions */
708 +//extern struct block_device_operations cf_bdops;
710 +// static struct hd_struct cf_parts[CF_MAX_PART];
711 +// static int cf_part_sizes[CF_MAX_PART];
712 +// static int cf_hsect_sizes[CF_MAX_PART];
713 +// static int cf_max_sectors[CF_MAX_PART];
714 +// static int cf_blksize_sizes[CF_MAX_PART];
716 +// static spinlock_t lock = SPIN_LOCK_UNLOCKED;
718 +// volatile int cf_busy = 0;
720 +static struct request *active_req = NULL;
722 +static int cf_open (struct inode *, struct file *);
723 +static int cf_release (struct inode *, struct file *);
724 +static int cf_ioctl (struct inode *, struct file *, unsigned, unsigned long);
726 +static void cf_request(request_queue_t * q);
727 +static int cf_transfer(const struct request *req);
729 +/*long (*unlocked_ioctl) (struct file *, unsigned, unsigned long);
730 +long (*compat_ioctl) (struct file *, unsigned, unsigned long);*/
731 +// int (*direct_access) (struct block_device *, sector_t, unsigned long *);
732 +// int (*media_changed) (struct gendisk *);
733 +// int (*revalidate_disk) (struct gendisk *);
735 +static struct block_device_operations cf_bdops = {
736 + .owner = THIS_MODULE,
738 + .release = cf_release,
740 + .media_changed = NULL,
741 + .unlocked_ioctl = NULL,
742 + .revalidate_disk = NULL,
743 + .compat_ioctl = NULL,
744 + .direct_access = NULL
748 +int cf_mips_probe(struct platform_device *pdev)
750 + struct gendisk* cf_gendisk=NULL;
751 + struct cf_device *cdev = (struct cf_device *) pdev->dev.platform_data;
752 + struct cf_mips_dev *dev;
753 + struct resource *r;
756 + reg_result = register_blkdev(MAJOR_NR, "cf-mips");
757 + if (reg_result < 0) {
758 + printk(KERN_WARNING "cf-mips: can't get major %d\n", MAJOR_NR);
762 + dev = (struct cf_mips_dev *)kmalloc(sizeof(struct cf_mips_dev),GFP_KERNEL);
765 + memset(dev, 0, sizeof(struct cf_mips_dev));
768 + dev->pin = cdev->gpio_pin;
769 + dev->irq = platform_get_irq_byname(pdev, "cf_irq");
770 + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cf_membase");
771 + dev->base = (void *) r->start;
773 + if (cf_init(dev)) goto out_err;
774 + printk("init done");
776 + spin_lock_init(&dev->lock);
777 + dev->queue = blk_init_queue(cf_request,&dev->lock);
779 + printk(KERN_ERR "cf-mips: no mem for queue\n");
782 + blk_queue_max_sectors(dev->queue,ATA_MAX_SECT_PER_CMD);
784 + /* For memory devices, it is always better to avoid crossing segments
785 + inside the same request. */
786 +/* if (dev->dtype==0x848A){
787 + printk(KERN_INFO "Setting boundary for cf to 0x%x",(dev->block_size*512)-1);
788 + blk_queue_segment_boundary(dev->queue, (dev->block_size*512)-1);
791 + dev->gd = alloc_disk(CF_MAX_PART);
792 + cf_gendisk = dev->gd;
793 + cdev->gd = dev->gd;
794 + if (!cf_gendisk) goto out_err; /* Last of these goto's */
796 + cf_gendisk->major = MAJOR_NR;
797 + cf_gendisk->first_minor = 0;
798 + cf_gendisk->queue=dev->queue;
799 + BUG_ON(cf_gendisk->minors != CF_MAX_PART);
800 + strcpy(cf_gendisk->disk_name,"cfa");
801 + cf_gendisk->fops = &cf_bdops;
802 + cf_gendisk->flags = 0 ; /* is not yet GENHD_FL_REMOVABLE */
803 + cf_gendisk->private_data=dev;
805 + set_capacity(cf_gendisk,dev->sectors * CF_KERNEL_MUL);
807 + /* Let the disk go live */
808 + add_disk(cf_gendisk);
810 + result = cf_init();
812 + /* default cfg for all partitions */
813 + memset(cf_parts, 0, sizeof (cf_parts[0]) * CF_MAX_PART);
814 + memset(cf_part_sizes, 0, sizeof (cf_part_sizes[0]) * CF_MAX_PART);
815 + for (i = 0; i < CF_MAX_PART; ++i) {
816 + cf_hsect_sizes[i] = CF_SECT_SIZE;
817 + cf_max_sectors[i] = ATA_MAX_SECT_PER_CMD;
818 + cf_blksize_sizes[i] = BLOCK_SIZE;
821 + /* setup info for whole disk (partition 0) */
822 + cf_part_sizes[0] = cf_sectors / 2;
823 + cf_parts[0].nr_sects = cf_sectors;
825 + blk_size[MAJOR_NR] = cf_part_sizes;
826 + blksize_size[MAJOR_NR] = cf_blksize_sizes;
827 + max_sectors[MAJOR_NR] = cf_max_sectors;
828 + hardsect_size[MAJOR_NR] = cf_hsect_sizes;
829 + read_ahead[MAJOR_NR] = 8; /* (4kB) */
831 + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
833 + add_gendisk(&cf_gendisk);
835 +// printk(KERN_INFO "cf-mips partition check: \n");
836 +// register_disk(cf_gendisk, MKDEV(MAJOR_NR, 0), CF_MAX_PART,
837 +// &cf_bdops, dev->sectors);
842 + blk_cleanup_queue(dev->queue);
845 + unregister_blkdev(MAJOR_NR, "cf-mips");
856 +cf_mips_remove(struct platform_device *pdev)
858 + struct cf_device *cdev = (struct cf_device *) pdev->dev.platform_data;
859 + struct cf_mips_dev *dev = (struct cf_mips_dev *) cdev->dev;
861 + unregister_blkdev(MAJOR_NR, "cf-mips");
862 + blk_cleanup_queue(dev->queue);
864 + del_gendisk(dev->gd);
870 +static struct platform_driver cf_driver = {
871 + .driver.name = "rb500-cf",
872 + .probe = cf_mips_probe,
873 + .remove = cf_mips_remove,
876 +static int __init cf_mips_init(void)
878 + printk(KERN_INFO "cf-mips module loaded\n");
879 + return platform_driver_register(&cf_driver);
882 +static void cf_mips_cleanup(void)
884 + platform_driver_unregister(&cf_driver);
885 + printk(KERN_INFO "cf-mips module removed\n");
888 +module_init(cf_mips_init);
889 +module_exit(cf_mips_cleanup);
891 +MODULE_LICENSE("GPL");
892 +MODULE_ALIAS_BLOCKDEV_MAJOR(CF_MIPS_MAJOR);
895 +static int cf_open(struct inode *inode, struct file *filp)
897 + struct cf_mips_dev *dev=inode->i_bdev->bd_disk->private_data;
898 + int minor = MINOR(inode->i_rdev);
900 + if (minor >= CF_MAX_PART)
902 + //DEBUGP(KERN_INFO "cf-mips module opened, minor %d\n", minor);
903 + spin_lock(&dev->lock);
905 + spin_unlock(&dev->lock);
906 + filp->private_data=dev;
908 + /* dirty workaround to set CFRDY GPIO as an input when some other
909 + program sets it as an output */
910 + gpio_set(CFG, (1 << dev->pin), 0);
911 + return 0; /* success */
914 +static int cf_release(struct inode *inode, struct file *filp)
916 + int minor = MINOR(inode->i_rdev);
917 + struct cf_mips_dev *dev=inode->i_bdev->bd_disk->private_data;
918 + spin_lock(&dev->lock);
920 + spin_unlock(&dev->lock);
924 +static int cf_ioctl(struct inode *inode, struct file *filp,
925 + unsigned int cmd, unsigned long arg)
927 + unsigned minor = MINOR(inode->i_rdev);
928 + struct cf_mips_dev *dev=inode->i_bdev->bd_disk->private_data;
930 + DEBUGP(KERN_INFO "cf_ioctl cmd %u\n", cmd);
932 + case BLKRRPART: /* re-read partition table */
933 + if (!capable(CAP_SYS_ADMIN))
935 + printk(KERN_INFO "cf-mips partition check: \n");
936 + register_disk(dev->gd);
941 + struct hd_geometry geo;
942 + geo.cylinders = dev->cyl;
943 + geo.heads = dev->head;
944 + geo.sectors = dev->spt;
945 + geo.start = (*dev->gd->part)[minor].start_sect;
946 + if (copy_to_user((void *) arg, &geo, sizeof (geo)))
952 + return -EINVAL; /* unknown command */
955 +static void cf_request(request_queue_t * q)
957 + struct cf_mips_dev* dev;
959 + struct request * req;
962 + /* We could have q->queuedata = dev , but haven't yet. */
966 + while ((req=elv_next_request(q))!=NULL){
967 + dev=req->rq_disk->private_data;
968 + status=cf_transfer(req);
969 + if (status==CF_TRANS_IN_PROGRESS){
973 + end_request(req,status);
977 +static int cf_transfer(const struct request *req)
979 + struct cf_mips_dev* dev=req->rq_disk->private_data;
981 + if (!blk_fs_request(req)){
982 + if (printk_ratelimit())
983 + printk(KERN_WARNING "cf-mips: skipping non-fs request 0x%x\n",req->cmd[0]);
984 + return CF_TRANS_FAILED;
987 + return cf_do_transfer(dev,req->sector,req->current_nr_sectors,req->buffer,rq_data_dir(req));
990 +void cf_async_trans_done(struct cf_mips_dev * dev,int result)
992 + struct request *req;
994 + spin_lock(&dev->lock);
997 + end_request(req,result);
998 + spin_unlock(&dev->lock);
1000 + spin_lock(&dev->lock);
1001 + cf_request(dev->queue);
1002 + spin_unlock(&dev->lock);
1005 diff -urN linux.old/drivers/block/rb500/Makefile linux.dev/drivers/block/rb500/Makefile
1006 --- linux.old/drivers/block/rb500/Makefile 1970-01-01 01:00:00.000000000 +0100
1007 +++ linux.dev/drivers/block/rb500/Makefile 2006-10-26 00:11:14.000000000 +0200
1009 +## Makefile for the RB532 CF port
1011 +obj-y += bdev.o ata.o