657d8157d09b617fcdd72581bec98f145d242ce6
[openwrt/svn-archive/archive.git] / target / linux / rb532-2.6 / patches / 120-cf.patch
1 diff -urN linux.old/drivers/block/Kconfig linux.dev/drivers/block/Kconfig
2 --- linux.old/drivers/block/Kconfig 2006-06-08 20:20:52.000000000 +0200
3 +++ linux.dev/drivers/block/Kconfig 2006-06-08 22:14:58.000000000 +0200
4 @@ -453,4 +453,12 @@
5 This driver provides Support for ATA over Ethernet block
6 devices like the Coraid EtherDrive (R) Storage Blade.
7
8 +config BLK_DEV_CF_MIPS
9 + bool "CF slot of RB532 board"
10 + depends on MIKROTIK_RB500
11 + default y
12 + help
13 + The Routerboard 532 has a CF slot on it. Enable the special block
14 + device driver for it.
15 +
16 endmenu
17 diff -urN linux.old/drivers/block/rb500/ata.c linux.dev/drivers/block/rb500/ata.c
18 --- linux.old/drivers/block/rb500/ata.c 1970-01-01 01:00:00.000000000 +0100
19 +++ linux.dev/drivers/block/rb500/ata.c 2006-06-09 01:58:40.000000000 +0200
20 @@ -0,0 +1,474 @@
21 +#include <linux/kernel.h> /* printk() */
22 +#include <linux/module.h> /* module to be loadable */
23 +#include <linux/delay.h>
24 +#include <linux/sched.h>
25 +#include <linux/pci.h>
26 +#include <linux/ioport.h> /* request_mem_region() */
27 +#include <asm/unaligned.h> /* ioremap() */
28 +#include <asm/io.h> /* ioremap() */
29 +#include <asm/rc32434/rb.h>
30 +
31 +#include "ata.h"
32 +
33 +#define REQUEST_MEM_REGION 0
34 +#define DEBUG 1
35 +
36 +#if DEBUG
37 +#define DEBUGP printk
38 +#else
39 +#define DEBUGP(format, args...)
40 +#endif
41 +
42 +#define SECS 1000000 /* unit for wait_not_busy() is 1us */
43 +
44 +unsigned cf_head = 0;
45 +unsigned cf_cyl = 0;
46 +unsigned cf_spt = 0;
47 +unsigned cf_sectors = 0;
48 +static unsigned cf_block_size = 1;
49 +static void *baddr = 0;
50 +
51 +#define DBUF32 ((volatile u32 *)((unsigned long)dev->baddr | ATA_DBUF_OFFSET))
52 +
53 +
54 +static void cf_do_tasklet(unsigned long dev_l);
55 +
56 +
57 +static inline void wareg(u8 val, unsigned reg, struct cf_mips_dev* dev)
58 +{
59 + writeb(val, dev->baddr + ATA_REG_OFFSET + reg);
60 +}
61 +
62 +static inline u8 rareg(unsigned reg, struct cf_mips_dev* dev)
63 +{
64 + return readb(dev->baddr + ATA_REG_OFFSET + reg);
65 +}
66 +
67 +static inline int get_gpio_bit(gpio_func ofs, struct cf_mips_dev *dev)
68 +{
69 + return (gpio_get(ofs) >> dev->pin) & 1;
70 +}
71 +
72 +static inline void set_gpio_bit(int bit, gpio_func ofs, struct cf_mips_dev *dev)
73 +{
74 + gpio_set(ofs, (1 << dev->pin), ((bit & 1) << dev->pin));
75 +}
76 +
77 +static inline int cfrdy(struct cf_mips_dev *dev)
78 +{
79 + return get_gpio_bit(DATA, dev);
80 +}
81 +
82 +static inline void prepare_cf_irq(struct cf_mips_dev *dev)
83 +{
84 + set_gpio_bit(1, ILEVEL, dev); /* interrupt on cf ready (not busy) */
85 + set_gpio_bit(0, ISTAT, dev); /* clear interrupt status */
86 +}
87 +
88 +static inline int cf_present(struct cf_mips_dev* dev)
89 +{
90 + /* TODO: read and configure CIS into memory mapped mode
91 + * TODO: parse CISTPL_CONFIG on CF+ cards to get base address (0x200)
92 + * TODO: maybe adjust power saving setting for Hitachi Microdrive
93 + */
94 + int i;
95 +
96 + /* setup CFRDY GPIO as input */
97 + set_gpio_bit(0, FUNC, dev);
98 + set_gpio_bit(0, CFG, dev);
99 +
100 + for (i = 0; i < 0x10; ++i) {
101 + if (rareg(i,dev) != 0xff)
102 + return 1;
103 + }
104 + return 0;
105 +}
106 +
107 +static inline int is_busy(struct cf_mips_dev *dev)
108 +{
109 + return !cfrdy(dev);
110 +}
111 +
112 +static int wait_not_busy(int to_us, int wait_for_busy,struct cf_mips_dev *dev)
113 +{
114 + int us_passed = 0;
115 + if (wait_for_busy && !is_busy(dev)) {
116 + /* busy must appear within 400ns,
117 + * but it may dissapear before we see it
118 + * => must not wait for busy in a loop
119 + */
120 + ndelay(400);
121 + }
122 +
123 + do {
124 + if (us_passed)
125 + udelay(1); /* never reached in async mode */
126 + if (!is_busy(dev)) {
127 + if (us_passed > 1 * SECS) {
128 + printk(KERN_WARNING "cf-mips: not busy ok (after %dus)"
129 + ", status 0x%02x\n", us_passed, (unsigned) rareg(ATA_REG_ST,dev));
130 + }
131 + return CF_TRANS_OK;
132 + }
133 + if (us_passed == 1 * SECS) {
134 + printk(KERN_WARNING "cf-mips: wait not busy %dus..\n", to_us);
135 + }
136 + if (dev->async_mode) {
137 + dev->to_timer.expires = jiffies + (to_us * HZ / SECS);
138 + dev->irq_enable_time = jiffies;
139 + prepare_cf_irq(dev);
140 + if (is_busy(dev)) {
141 + add_timer(&dev->to_timer);
142 + enable_irq(dev->irq);
143 + return CF_TRANS_IN_PROGRESS;
144 + }
145 + continue;
146 + }
147 + ++us_passed;
148 + } while (us_passed < to_us);
149 +
150 + printk(KERN_ERR "cf-mips: wait not busy timeout (%dus)"
151 + ", status 0x%02x, state %d\n",
152 + to_us, (unsigned) rareg(ATA_REG_ST,dev), dev->tstate);
153 + return CF_TRANS_FAILED;
154 +}
155 +
156 +static irqreturn_t cf_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
157 +{
158 + /* While tasklet has not disabled irq, irq will be retried all the time
159 + * because of ILEVEL matching GPIO pin status => deadlock.
160 + * To avoid this, we change ILEVEL to 0.
161 + */
162 + struct cf_mips_dev *dev=dev_id;
163 +
164 + set_gpio_bit(0, ILEVEL, dev);
165 + set_gpio_bit(0, ISTAT, dev);
166 +
167 + del_timer(&dev->to_timer);
168 + tasklet_schedule(&dev->tasklet);
169 + return IRQ_HANDLED;
170 +}
171 +
172 +static int do_reset(struct cf_mips_dev *dev)
173 +{
174 + printk(KERN_INFO "cf-mips: resetting..\n");
175 +
176 + wareg(ATA_REG_DC_SRST, ATA_REG_DC,dev);
177 + udelay(1); /* FIXME: how long should we wait here? */
178 + wareg(0, ATA_REG_DC,dev);
179 +
180 + return wait_not_busy(30 * SECS, 1,dev);
181 +}
182 +
183 +static int set_multiple(struct cf_mips_dev *dev)
184 +{
185 + if (dev->block_size <= 1)
186 + return CF_TRANS_OK;
187 +
188 + wareg(dev->block_size, ATA_REG_SC,dev);
189 + wareg(ATA_REG_DH_BASE | ATA_REG_DH_LBA, ATA_REG_DH,dev);
190 + wareg(ATA_CMD_SET_MULTIPLE, ATA_REG_CMD,dev);
191 +
192 + return wait_not_busy(10 * SECS, 1,dev);
193 +}
194 +
195 +static int set_cmd(struct cf_mips_dev *dev)
196 +{
197 + //DEBUGP(KERN_INFO "cf-mips: ata cmd 0x%02x\n", dev->tcmd);
198 + // sector_count should be <=24 bits..
199 + BUG_ON(dev->tsect_start>=0x10000000);
200 + // This way, it addresses 2^24 * 512 = 128G
201 +
202 + if (dev->tsector_count) {
203 + wareg(dev->tsector_count & 0xff, ATA_REG_SC,dev);
204 + wareg(dev->tsect_start & 0xff, ATA_REG_SN,dev);
205 + wareg((dev->tsect_start >> 8) & 0xff, ATA_REG_CL,dev);
206 + wareg((dev->tsect_start >> 16) & 0xff, ATA_REG_CH,dev);
207 + }
208 + wareg(((dev->tsect_start >> 24) & 0x0f) | ATA_REG_DH_BASE | ATA_REG_DH_LBA,
209 + ATA_REG_DH,dev); /* select drive on all commands */
210 + wareg(dev->tcmd, ATA_REG_CMD,dev);
211 + return wait_not_busy(10 * SECS, 1,dev);
212 +}
213 +
214 +static int do_trans(struct cf_mips_dev *dev)
215 +{
216 + int res;
217 + unsigned st;
218 + int transfered;
219 +
220 + //printk("do_trans: %d sectors left\n",dev->tsectors_left);
221 + while (dev->tsectors_left) {
222 + transfered = 0;
223 +
224 + st = rareg(ATA_REG_ST,dev);
225 + if (!(st & ATA_REG_ST_DRQ)) {
226 + printk(KERN_ERR "cf-mips: do_trans without DRQ (status 0x%x)!\n", st);
227 + if (st & ATA_REG_ST_ERR) {
228 + int errId = rareg(ATA_REG_ERR,dev);
229 + printk(KERN_ERR "cf-mips: %s error, status 0x%x, errid 0x%x\n",
230 + (dev->tread ? "read" : "write"), st, errId);
231 + }
232 + return CF_TRANS_FAILED;
233 + }
234 + do { /* Fill/read the buffer one block */
235 + u32 *qbuf, *qend;
236 + qbuf = (u32 *)dev->tbuf;
237 + qend = qbuf + CF_SECT_SIZE / sizeof(u32);
238 + if (dev->tread) {
239 + while (qbuf!=qend)
240 + put_unaligned(*DBUF32,qbuf++);
241 + //*(qbuf++) = *DBUF32;
242 + }
243 + else {
244 + while(qbuf!=qend)
245 + *DBUF32 = get_unaligned(qbuf++);
246 + }
247 +
248 + dev->tsectors_left--;
249 + dev->tbuf += CF_SECT_SIZE;
250 + dev->tbuf_size -= CF_SECT_SIZE;
251 + transfered++;
252 + } while (transfered != dev->block_size && dev->tsectors_left > 0);
253 +
254 + res = wait_not_busy(10 * SECS, 1,dev);
255 + if (res != CF_TRANS_OK)
256 + return res;
257 + };
258 +
259 + st = rareg(ATA_REG_ST,dev);
260 + if (st & (ATA_REG_ST_DRQ | ATA_REG_ST_DWF | ATA_REG_ST_ERR)) {
261 + if (st & ATA_REG_ST_DRQ) {
262 + printk(KERN_ERR "cf-mips: DRQ after all %d sectors are %s"
263 + ", status 0x%x\n", dev->tsector_count, (dev->tread ? "read" : "written"), st);
264 + } else if (st & ATA_REG_ST_DWF) {
265 + printk(KERN_ERR "cf-mips: write fault, status 0x%x\n", st);
266 + } else {
267 + int errId = rareg(ATA_REG_ERR,dev);
268 + printk(KERN_ERR "cf-mips: %s error, status 0x%x, errid 0x%x\n",
269 + (dev->tread ? "read" : "write"), st, errId);
270 + }
271 + return CF_TRANS_FAILED;
272 + }
273 + return CF_TRANS_OK;
274 +}
275 +
276 +static int cf_do_state(struct cf_mips_dev *dev)
277 +{
278 + int res;
279 + switch (dev->tstate) { /* fall through everywhere */
280 + case TS_IDLE:
281 + dev->tstate = TS_READY;
282 + if (is_busy(dev)) {
283 + dev->tstate = TS_AFTER_RESET;
284 + res = do_reset(dev);
285 + if (res != CF_TRANS_OK)
286 + break;
287 + }
288 + case TS_AFTER_RESET:
289 + if (dev->tstate == TS_AFTER_RESET) {
290 + dev->tstate = TS_READY;
291 + res = set_multiple(dev);
292 + if (res != CF_TRANS_OK)
293 + break;
294 + }
295 + case TS_READY:
296 + dev->tstate = TS_CMD;
297 + res = set_cmd(dev);
298 + if (res != CF_TRANS_OK)
299 + break;;
300 + case TS_CMD:
301 + dev->tstate = TS_TRANS;
302 + case TS_TRANS:
303 + res = do_trans(dev);
304 + break;
305 + default:
306 + printk(KERN_ERR "cf-mips: BUG: unknown tstate %d\n", dev->tstate);
307 + return CF_TRANS_FAILED;
308 + }
309 + if (res != CF_TRANS_IN_PROGRESS)
310 + dev->tstate = TS_IDLE;
311 + return res;
312 +}
313 +
314 +static void cf_do_tasklet(unsigned long dev_l)
315 +{
316 + struct cf_mips_dev* dev=(struct cf_mips_dev*) dev_l;
317 + int res;
318 +
319 + disable_irq(dev->irq);
320 +
321 + if (dev->tstate == TS_IDLE)
322 + return; /* can happen when irq is first registered */
323 +
324 +#if 0
325 + DEBUGP(KERN_WARNING "cf-mips: not busy ok (tasklet) status 0x%02x\n",
326 + (unsigned) rareg(ATA_REG_ST,dev));
327 +#endif
328 +
329 + res = cf_do_state(dev);
330 + if (res == CF_TRANS_IN_PROGRESS)
331 + return;
332 + cf_async_trans_done(dev,res);
333 +}
334 +
335 +static void cf_async_timeout(unsigned long dev_l)
336 +{
337 + struct cf_mips_dev* dev=(struct cf_mips_dev*) dev_l;
338 + disable_irq(dev->irq);
339 + /* Perhaps send abort to the device? */
340 + printk(KERN_ERR "cf-mips: wait not busy timeout (%lus)"
341 + ", status 0x%02x, state %d\n",
342 + jiffies - dev->irq_enable_time, (unsigned) rareg(ATA_REG_ST,dev), dev->tstate);
343 + dev->tstate = TS_IDLE;
344 + cf_async_trans_done(dev,CF_TRANS_FAILED);
345 +}
346 +
347 +int cf_do_transfer(struct cf_mips_dev* dev,sector_t sector, unsigned long nsect,
348 + char* buffer, int is_write)
349 +{
350 + BUG_ON(dev->tstate!=TS_IDLE);
351 + if (nsect > ATA_MAX_SECT_PER_CMD) {
352 + printk(KERN_WARNING "cf-mips: sector count %lu out of range\n",nsect);
353 + return CF_TRANS_FAILED;
354 + }
355 + if (sector + nsect > dev->sectors) {
356 + printk(KERN_WARNING "cf-mips: sector %lu out of range\n",sector);
357 + return CF_TRANS_FAILED;
358 + }
359 + dev->tbuf = buffer;
360 + dev->tbuf_size = nsect*512;
361 + dev->tsect_start = sector;
362 + dev->tsector_count = nsect;
363 + dev->tsectors_left = dev->tsector_count;
364 + dev->tread = (is_write)?0:1;
365 +
366 + dev->tcmd = (dev->block_size == 1 ?
367 + (is_write ? ATA_CMD_WRITE_SECTORS : ATA_CMD_READ_SECTORS) :
368 + (is_write ? ATA_CMD_WRITE_MULTIPLE : ATA_CMD_READ_MULTIPLE));
369 +
370 + return cf_do_state(dev);
371 +}
372 +
373 +static int do_identify(struct cf_mips_dev *dev)
374 +{
375 + u16 sbuf[CF_SECT_SIZE >> 1];
376 + int res;
377 + char tstr[17]; //serial
378 + BUG_ON(dev->tstate!=TS_IDLE);
379 + dev->tbuf = (char *) sbuf;
380 + dev->tbuf_size = CF_SECT_SIZE;
381 + dev->tsect_start = 0;
382 + dev->tsector_count = 0;
383 + dev->tsectors_left = 1;
384 + dev->tread = 1;
385 + dev->tcmd = ATA_CMD_IDENTIFY_DRIVE;
386 +
387 + DEBUGP(KERN_INFO "cf-mips: identify drive..\n");
388 + res = cf_do_state(dev);
389 + if (res == CF_TRANS_IN_PROGRESS) {
390 + printk(KERN_ERR "cf-mips: BUG: async identify cmd\n");
391 + return CF_TRANS_FAILED;
392 + }
393 + if (res != CF_TRANS_OK)
394 + return 0;
395 +
396 + dev->head = sbuf[3];
397 + dev->cyl = sbuf[1];
398 + dev->spt = sbuf[6];
399 + dev->sectors = ((unsigned long) sbuf[7] << 16) | sbuf[8];
400 + dev->dtype=sbuf[0];
401 + memcpy(tstr,&sbuf[12],16);
402 + tstr[16]=0;
403 + printk(KERN_INFO "cf-mips: %s detected, C/H/S=%d/%d/%d sectors=%u (%uMB) Serial=%s\n",
404 + (sbuf[0] == 0x848A ? "CF card" : "ATA drive"), dev->cyl, dev->head,
405 + dev->spt, dev->sectors, dev->sectors >> 11,tstr);
406 + return 1;
407 +}
408 +
409 +static void init_multiple(struct cf_mips_dev * dev)
410 +{
411 + int res;
412 + DEBUGP(KERN_INFO "cf-mips: detecting block size\n");
413 +
414 + dev->block_size = 128; /* max block size = 128 sectors (64KB) */
415 + do {
416 + wareg(dev->block_size, ATA_REG_SC,dev);
417 + wareg(ATA_REG_DH_BASE | ATA_REG_DH_LBA, ATA_REG_DH,dev);
418 + wareg(ATA_CMD_SET_MULTIPLE, ATA_REG_CMD,dev);
419 +
420 + res = wait_not_busy(10 * SECS, 1,dev);
421 + if (res != CF_TRANS_OK) {
422 + printk(KERN_ERR "cf-mips: failed to detect block size: busy!\n");
423 + dev->block_size = 1;
424 + return;
425 + }
426 + if ((rareg(ATA_REG_ST,dev) & ATA_REG_ST_ERR) == 0)
427 + break;
428 + dev->block_size /= 2;
429 + } while (dev->block_size > 1);
430 +
431 + printk(KERN_INFO "cf-mips: multiple sectors = %d\n", dev->block_size);
432 +}
433 +
434 +int cf_init(struct cf_mips_dev *dev)
435 +{
436 + tasklet_init(&dev->tasklet,cf_do_tasklet,(unsigned long)dev);
437 + dev->baddr = ioremap_nocache((unsigned long)dev->base, CFDEV_BUF_SIZE);
438 + if (!dev->baddr) {
439 + printk(KERN_ERR "cf-mips: cf_init: ioremap for (%lx,%x) failed\n",
440 + (unsigned long) dev->base, CFDEV_BUF_SIZE);
441 + return -EBUSY;
442 + }
443 +
444 + if (!cf_present(dev)) {
445 + printk(KERN_WARNING "cf-mips: cf card not present\n");
446 + iounmap(dev->baddr);
447 + return -ENODEV;
448 + }
449 +
450 + if (do_reset(dev) != CF_TRANS_OK) {
451 + printk(KERN_ERR "cf-mips: cf reset failed\n");
452 + iounmap(dev->baddr);
453 + return -EBUSY;
454 + }
455 +
456 + if (!do_identify(dev)) {
457 + printk(KERN_ERR "cf-mips: cf identify failed\n");
458 + iounmap(dev->baddr);
459 + return -EBUSY;
460 + }
461 +
462 +/* set_apm_level(ATA_APM_WITH_STANDBY); */
463 + init_multiple(dev);
464 +
465 + init_timer(&dev->to_timer);
466 + dev->to_timer.function = cf_async_timeout;
467 + dev->to_timer.data = (unsigned long)dev;
468 +
469 + prepare_cf_irq(dev);
470 + if (request_irq(dev->irq, cf_irq_handler, 0, "CF Mips", dev)) {
471 + printk(KERN_ERR "cf-mips: failed to get irq\n");
472 + iounmap(dev->baddr);
473 + return -EBUSY;
474 + }
475 + /* Disable below would be odd, because request will enable, and the tasklet
476 + will disable it itself */
477 + //disable_irq(dev->irq);
478 +
479 + dev->async_mode = 1;
480 +
481 + return 0;
482 +}
483 +
484 +void cf_cleanup(struct cf_mips_dev *dev)
485 +{
486 + iounmap(dev->baddr);
487 + free_irq(dev->irq, NULL);
488 +#if REQUEST_MEM_REGION
489 + release_mem_region((unsigned long)dev->base, CFDEV_BUF_SIZE);
490 +#endif
491 +}
492 +
493 +
494 +/*eof*/
495 diff -urN linux.old/drivers/block/rb500/ata.h linux.dev/drivers/block/rb500/ata.h
496 --- linux.old/drivers/block/rb500/ata.h 1970-01-01 01:00:00.000000000 +0100
497 +++ linux.dev/drivers/block/rb500/ata.h 2006-06-09 00:15:23.000000000 +0200
498 @@ -0,0 +1,132 @@
499 +#ifndef __CFMIPS_ATA_H__
500 +#define __CFMIPS_ATA_H__
501 +
502 +#include <linux/interrupt.h>
503 +
504 +#define CFG_DC_DEV1 (void*)0xb8010010
505 +#define CFG_DC_DEVBASE 0x0
506 +#define CFG_DC_DEVMASK 0x4
507 +#define CFG_DC_DEVC 0x8
508 +#define CFG_DC_DEVTC 0xC
509 +
510 +#define CFDEV_BUF_SIZE 0x1000
511 +#define ATA_CIS_OFFSET 0x200
512 +#define ATA_REG_OFFSET 0x800
513 +#define ATA_DBUF_OFFSET 0xC00
514 +
515 +#define ATA_REG_FEAT 0x1
516 +#define ATA_REG_SC 0x2
517 +#define ATA_REG_SN 0x3
518 +#define ATA_REG_CL 0x4
519 +#define ATA_REG_CH 0x5
520 +#define ATA_REG_DH 0x6
521 +#define ATA_REG_DH_BASE 0xa0
522 +#define ATA_REG_DH_LBA 0x40
523 +#define ATA_REG_DH_DRV 0x10
524 +#define ATA_REG_CMD 0x7
525 +#define ATA_REG_ST 0x7
526 +#define ATA_REG_ST_BUSY 0x80
527 +#define ATA_REG_ST_RDY 0x40
528 +#define ATA_REG_ST_DWF 0x20
529 +#define ATA_REG_ST_DSC 0x10
530 +#define ATA_REG_ST_DRQ 0x08
531 +#define ATA_REG_ST_CORR 0x04
532 +#define ATA_REG_ST_ERR 0x01
533 +#define ATA_REG_ERR 0xd
534 +#define ATA_REG_DC 0xe
535 +#define ATA_REG_DC_IEN 0x02
536 +#define ATA_REG_DC_SRST 0x04
537 +
538 +#define ATA_CMD_READ_SECTORS 0x20
539 +#define ATA_CMD_WRITE_SECTORS 0x30
540 +#define ATA_CMD_EXEC_DRIVE_DIAG 0x90
541 +#define ATA_CMD_READ_MULTIPLE 0xC4
542 +#define ATA_CMD_WRITE_MULTIPLE 0xC5
543 +#define ATA_CMD_SET_MULTIPLE 0xC6
544 +#define ATA_CMD_IDENTIFY_DRIVE 0xEC
545 +#define ATA_CMD_SET_FEATURES 0xEF
546 +
547 +#define ATA_FEATURE_ENABLE_APM 0x05
548 +#define ATA_FEATURE_DISABLE_APM 0x85
549 +#define ATA_APM_DISABLED 0x00
550 +#define ATA_APM_MIN_POWER 0x01
551 +#define ATA_APM_WITH_STANDBY 0x7f
552 +#define ATA_APM_WITHOUT_STANDBY 0x80
553 +#define ATA_APM_MAX_PERFORMANCE 0xfe
554 +
555 +#define CF_SECT_SIZE 0x200
556 +/* That is the ratio CF_SECT_SIZE/512 (the kernel sector size) */
557 +#define CF_KERNEL_MUL 1
558 +#define ATA_MAX_SECT_PER_CMD 0x100
559 +
560 +#define CF_TRANS_FAILED 0
561 +#define CF_TRANS_OK 1
562 +#define CF_TRANS_IN_PROGRESS 2
563 +
564 +
565 +enum trans_state {
566 + TS_IDLE = 0,
567 + TS_AFTER_RESET,
568 + TS_READY,
569 + TS_CMD,
570 + TS_TRANS
571 +};
572 +
573 +//
574 +// #if DEBUG
575 +// static unsigned long busy_time;
576 +// #endif
577 +
578 +/** Struct to hold the cfdev
579 +Actually, all the data here only has one instance. However, for
580 +reasons of programming conformity, it is passed around as a pointer
581 +*/
582 +struct cf_mips_dev {
583 + void *base; /* base address for I/O */
584 + void *baddr; /* remapped address */
585 +
586 + int pin; /* gpio pin */
587 + int irq; /* gpio irq */
588 +
589 + unsigned head;
590 + unsigned cyl;
591 + unsigned spt;
592 + unsigned sectors;
593 +
594 + unsigned short block_size;
595 + unsigned dtype ; // ATA or CF
596 + struct request_queue *queue;
597 + struct gendisk *gd;
598 +
599 + /* Transaction state */
600 + enum trans_state tstate;
601 + char *tbuf;
602 + unsigned long tbuf_size;
603 + sector_t tsect_start;
604 + unsigned tsector_count;
605 + unsigned tsectors_left;
606 + int tread;
607 + unsigned tcmd;
608 + int async_mode;
609 + unsigned long irq_enable_time;
610 +
611 + struct request *active_req; /* A request is being carried out. Is that different from tstate? */
612 + int users;
613 + struct timer_list to_timer;
614 + struct tasklet_struct tasklet;
615 +
616 + /** This lock ensures that the requests to this device are all done
617 + atomically. Transfers can run in parallel, requests are all queued
618 + one-by-one */
619 + spinlock_t lock;
620 +};
621 +
622 +int cf_do_transfer(struct cf_mips_dev* dev,sector_t sector, unsigned long nsect,
623 + char* buffer, int is_write);
624 +int cf_init(struct cf_mips_dev* dev);
625 +void cf_cleanup(struct cf_mips_dev* dev);
626 +
627 +void cf_async_trans_done(struct cf_mips_dev* dev, int result);
628 +// void *cf_get_next_buf(unsigned long *buf_size);
629 +
630 +#endif
631 diff -urN linux.old/drivers/block/rb500/bdev.c linux.dev/drivers/block/rb500/bdev.c
632 --- linux.old/drivers/block/rb500/bdev.c 1970-01-01 01:00:00.000000000 +0100
633 +++ linux.dev/drivers/block/rb500/bdev.c 2006-06-15 16:29:04.000000000 +0200
634 @@ -0,0 +1,340 @@
635 +/* CF-mips driver
636 + This is a block driver for the direct (mmaped) interface to the CF-slot,
637 + found in Routerboard.com's RB532 board
638 + See SDK provided from routerboard.com.
639 +
640 + Module adapted By P.Christeas <p_christeas@yahoo.com>, 2005-6.
641 + Cleaned up and adapted to platform_device by Felix Fietkau <nbd@openwrt.org>
642 +
643 + This work is redistributed under the terms of the GNU General Public License.
644 +*/
645 +
646 +#include <linux/kernel.h>
647 +#include <linux/module.h>
648 +#include <linux/init.h>
649 +#include <linux/time.h>
650 +#include <linux/wait.h>
651 +#include <linux/fs.h>
652 +#include <linux/genhd.h>
653 +#include <linux/blkdev.h>
654 +#include <linux/blkpg.h>
655 +#include <linux/hdreg.h>
656 +#include <linux/platform_device.h>
657 +
658 +#include <asm/uaccess.h>
659 +#include <asm/io.h>
660 +
661 +#include <asm/rc32434/rb.h>
662 +
663 +#ifdef DEBUG
664 +#define DEBUGP printk
665 +#define DLEVEL 1
666 +#else
667 +#define DEBUGP(format, args...)
668 +#define DLEVEL 0
669 +#endif
670 +
671 +#define CF_MIPS_MAJOR 13
672 +#define MAJOR_NR CF_MIPS_MAJOR
673 +#define CF_MAX_PART 16 /* max 15 partitions */
674 +
675 +#include "ata.h"
676 +
677 +//extern struct block_device_operations cf_bdops;
678 +
679 +// static struct hd_struct cf_parts[CF_MAX_PART];
680 +// static int cf_part_sizes[CF_MAX_PART];
681 +// static int cf_hsect_sizes[CF_MAX_PART];
682 +// static int cf_max_sectors[CF_MAX_PART];
683 +// static int cf_blksize_sizes[CF_MAX_PART];
684 +
685 +// static spinlock_t lock = SPIN_LOCK_UNLOCKED;
686 +
687 +// volatile int cf_busy = 0;
688 +
689 +static struct request *active_req = NULL;
690 +
691 +static int cf_open (struct inode *, struct file *);
692 +static int cf_release (struct inode *, struct file *);
693 +static int cf_ioctl (struct inode *, struct file *, unsigned, unsigned long);
694 +
695 +static void cf_request(request_queue_t * q);
696 +static int cf_transfer(const struct request *req);
697 +
698 +/*long (*unlocked_ioctl) (struct file *, unsigned, unsigned long);
699 +long (*compat_ioctl) (struct file *, unsigned, unsigned long);*/
700 +// int (*direct_access) (struct block_device *, sector_t, unsigned long *);
701 +// int (*media_changed) (struct gendisk *);
702 +// int (*revalidate_disk) (struct gendisk *);
703 +
704 +static struct block_device_operations cf_bdops = {
705 + .owner = THIS_MODULE,
706 + .open = cf_open,
707 + .release = cf_release,
708 + .ioctl = cf_ioctl,
709 + .media_changed = NULL,
710 + .unlocked_ioctl = NULL,
711 + .revalidate_disk = NULL,
712 + .compat_ioctl = NULL,
713 + .direct_access = NULL
714 +};
715 +
716 +
717 +int cf_mips_probe(struct platform_device *pdev)
718 +{
719 + struct gendisk* cf_gendisk=NULL;
720 + struct cf_device *cdev = (struct cf_device *) pdev->dev.platform_data;
721 + struct cf_mips_dev *dev;
722 + struct resource *r;
723 + int reg_result;
724 +
725 + reg_result = register_blkdev(MAJOR_NR, "cf-mips");
726 + if (reg_result < 0) {
727 + printk(KERN_WARNING "cf-mips: can't get major %d\n", MAJOR_NR);
728 + return reg_result;
729 + }
730 +
731 + dev = (struct cf_mips_dev *)kmalloc(sizeof(struct cf_mips_dev),GFP_KERNEL);
732 + if (!dev)
733 + goto out_err;
734 + memset(dev, 0, sizeof(struct cf_mips_dev));
735 + cdev->dev = dev;
736 +
737 + dev->pin = cdev->gpio_pin;
738 + dev->irq = platform_get_irq_byname(pdev, "cf_irq");
739 + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cf_membase");
740 + dev->base = (void *) r->start;
741 +
742 + if (cf_init(dev)) goto out_err;
743 + printk("init done");
744 +
745 + spin_lock_init(&dev->lock);
746 + dev->queue = blk_init_queue(cf_request,&dev->lock);
747 + if (!dev->queue){
748 + printk(KERN_ERR "cf-mips: no mem for queue\n");
749 + goto out_err;
750 + }
751 + blk_queue_max_sectors(dev->queue,ATA_MAX_SECT_PER_CMD);
752 +
753 + /* For memory devices, it is always better to avoid crossing segments
754 + inside the same request. */
755 +/* if (dev->dtype==0x848A){
756 + printk(KERN_INFO "Setting boundary for cf to 0x%x",(dev->block_size*512)-1);
757 + blk_queue_segment_boundary(dev->queue, (dev->block_size*512)-1);
758 + }*/
759 +
760 + dev->gd = alloc_disk(CF_MAX_PART);
761 + cf_gendisk = dev->gd;
762 + cdev->gd = dev->gd;
763 + if (!cf_gendisk) goto out_err; /* Last of these goto's */
764 +
765 + cf_gendisk->major = MAJOR_NR;
766 + cf_gendisk->first_minor = 0;
767 + cf_gendisk->queue=dev->queue;
768 + BUG_ON(cf_gendisk->minors != CF_MAX_PART);
769 + strcpy(cf_gendisk->disk_name,"cfa");
770 + strcpy(cf_gendisk->devfs_name,"cf/card0");
771 + cf_gendisk->fops = &cf_bdops;
772 + cf_gendisk->flags = 0 ; /* is not yet GENHD_FL_REMOVABLE */
773 + cf_gendisk->private_data=dev;
774 +
775 + set_capacity(cf_gendisk,dev->sectors * CF_KERNEL_MUL);
776 +
777 + /* Let the disk go live */
778 + add_disk(cf_gendisk);
779 +#if 0
780 + result = cf_init();
781 +
782 + /* default cfg for all partitions */
783 + memset(cf_parts, 0, sizeof (cf_parts[0]) * CF_MAX_PART);
784 + memset(cf_part_sizes, 0, sizeof (cf_part_sizes[0]) * CF_MAX_PART);
785 + for (i = 0; i < CF_MAX_PART; ++i) {
786 + cf_hsect_sizes[i] = CF_SECT_SIZE;
787 + cf_max_sectors[i] = ATA_MAX_SECT_PER_CMD;
788 + cf_blksize_sizes[i] = BLOCK_SIZE;
789 + }
790 +
791 + /* setup info for whole disk (partition 0) */
792 + cf_part_sizes[0] = cf_sectors / 2;
793 + cf_parts[0].nr_sects = cf_sectors;
794 +
795 + blk_size[MAJOR_NR] = cf_part_sizes;
796 + blksize_size[MAJOR_NR] = cf_blksize_sizes;
797 + max_sectors[MAJOR_NR] = cf_max_sectors;
798 + hardsect_size[MAJOR_NR] = cf_hsect_sizes;
799 + read_ahead[MAJOR_NR] = 8; /* (4kB) */
800 +
801 + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
802 +
803 + add_gendisk(&cf_gendisk);
804 +#endif
805 +// printk(KERN_INFO "cf-mips partition check: \n");
806 +// register_disk(cf_gendisk, MKDEV(MAJOR_NR, 0), CF_MAX_PART,
807 +// &cf_bdops, dev->sectors);
808 + return 0;
809 +
810 +out_err:
811 + if (dev->queue){
812 + blk_cleanup_queue(dev->queue);
813 + }
814 + if (reg_result) {
815 + unregister_blkdev(MAJOR_NR, "cf-mips");
816 + return reg_result;
817 + }
818 + if (dev){
819 + cf_cleanup(dev);
820 + kfree(dev);
821 + }
822 + return 1;
823 +}
824 +
825 +static int
826 +cf_mips_remove(struct platform_device *pdev)
827 +{
828 + struct cf_device *cdev = (struct cf_device *) pdev->dev.platform_data;
829 + struct cf_mips_dev *dev = (struct cf_mips_dev *) cdev->dev;
830 +
831 + unregister_blkdev(MAJOR_NR, "cf-mips");
832 + blk_cleanup_queue(dev->queue);
833 +
834 + del_gendisk(dev->gd);
835 + cf_cleanup(dev);
836 + return 0;
837 +}
838 +
839 +
840 +static struct platform_driver cf_driver = {
841 + .driver.name = "rb500-cf",
842 + .probe = cf_mips_probe,
843 + .remove = cf_mips_remove,
844 +};
845 +
846 +static int __init cf_mips_init(void)
847 +{
848 + printk(KERN_INFO "cf-mips module loaded\n");
849 + return platform_driver_register(&cf_driver);
850 +}
851 +
852 +static void cf_mips_cleanup(void)
853 +{
854 + platform_driver_unregister(&cf_driver);
855 + printk(KERN_INFO "cf-mips module removed\n");
856 +}
857 +
858 +module_init(cf_mips_init);
859 +module_exit(cf_mips_cleanup);
860 +
861 +MODULE_LICENSE("GPL");
862 +MODULE_ALIAS_BLOCKDEV_MAJOR(CF_MIPS_MAJOR);
863 +
864 +
865 +static int cf_open(struct inode *inode, struct file *filp)
866 +{
867 + struct cf_mips_dev *dev=inode->i_bdev->bd_disk->private_data;
868 + int minor = MINOR(inode->i_rdev);
869 +
870 + if (minor >= CF_MAX_PART)
871 + return -ENODEV;
872 + //DEBUGP(KERN_INFO "cf-mips module opened, minor %d\n", minor);
873 + spin_lock(&dev->lock);
874 + dev->users++;
875 + spin_unlock(&dev->lock);
876 + filp->private_data=dev;
877 +
878 + /* dirty workaround to set CFRDY GPIO as an input when some other
879 + program sets it as an output */
880 + gpio_set(CFG, (1 << dev->pin), 0);
881 + return 0; /* success */
882 +}
883 +
884 +static int cf_release(struct inode *inode, struct file *filp)
885 +{
886 + int minor = MINOR(inode->i_rdev);
887 + struct cf_mips_dev *dev=inode->i_bdev->bd_disk->private_data;
888 + spin_lock(&dev->lock);
889 + dev->users--;
890 + spin_unlock(&dev->lock);
891 + return 0;
892 +}
893 +
894 +static int cf_ioctl(struct inode *inode, struct file *filp,
895 + unsigned int cmd, unsigned long arg)
896 +{
897 + unsigned minor = MINOR(inode->i_rdev);
898 + struct cf_mips_dev *dev=inode->i_bdev->bd_disk->private_data;
899 +
900 + DEBUGP(KERN_INFO "cf_ioctl cmd %u\n", cmd);
901 + switch (cmd) {
902 + case BLKRRPART: /* re-read partition table */
903 + if (!capable(CAP_SYS_ADMIN))
904 + return -EACCES;
905 + printk(KERN_INFO "cf-mips partition check: \n");
906 + register_disk(dev->gd);
907 + return 0;
908 +
909 + case HDIO_GETGEO:
910 + {
911 + struct hd_geometry geo;
912 + geo.cylinders = dev->cyl;
913 + geo.heads = dev->head;
914 + geo.sectors = dev->spt;
915 + geo.start = (*dev->gd->part)[minor].start_sect;
916 + if (copy_to_user((void *) arg, &geo, sizeof (geo)))
917 + return -EFAULT;
918 + }
919 + return 0;
920 + }
921 +
922 + return -EINVAL; /* unknown command */
923 +}
924 +
925 +static void cf_request(request_queue_t * q)
926 +{
927 + struct cf_mips_dev* dev;
928 +
929 + struct request * req;
930 + int status;
931 +
932 + /* We could have q->queuedata = dev , but haven't yet. */
933 + if (active_req)
934 + return;
935 +
936 + while ((req=elv_next_request(q))!=NULL){
937 + dev=req->rq_disk->private_data;
938 + status=cf_transfer(req);
939 + if (status==CF_TRANS_IN_PROGRESS){
940 + active_req=req;
941 + return;
942 + }
943 + end_request(req,status);
944 + }
945 +}
946 +
947 +static int cf_transfer(const struct request *req)
948 +{
949 + struct cf_mips_dev* dev=req->rq_disk->private_data;
950 +
951 + if (!blk_fs_request(req)){
952 + if (printk_ratelimit())
953 + printk(KERN_WARNING "cf-mips: skipping non-fs request 0x%x\n",req->cmd[0]);
954 + return CF_TRANS_FAILED;
955 + }
956 +
957 + return cf_do_transfer(dev,req->sector,req->current_nr_sectors,req->buffer,rq_data_dir(req));
958 +}
959 +
960 +void cf_async_trans_done(struct cf_mips_dev * dev,int result)
961 +{
962 + struct request *req;
963 +
964 + spin_lock(&dev->lock);
965 + req=active_req;
966 + active_req=NULL;
967 + end_request(req,result);
968 + spin_unlock(&dev->lock);
969 +
970 + spin_lock(&dev->lock);
971 + cf_request(dev->queue);
972 + spin_unlock(&dev->lock);
973 +}
974 +
975 diff -urN linux.old/drivers/block/rb500/Makefile linux.dev/drivers/block/rb500/Makefile
976 --- linux.old/drivers/block/rb500/Makefile 1970-01-01 01:00:00.000000000 +0100
977 +++ linux.dev/drivers/block/rb500/Makefile 2006-06-08 22:14:58.000000000 +0200
978 @@ -0,0 +1,3 @@
979 +## Makefile for the RB532 CF port
980 +
981 +obj-y += bdev.o ata.o
982 diff -urN linux.old/drivers/Makefile linux.dev/drivers/Makefile
983 --- linux.old/drivers/Makefile 2006-06-08 20:20:52.000000000 +0200
984 +++ linux.dev/drivers/Makefile 2006-06-08 22:14:58.000000000 +0200
985 @@ -73,3 +73,4 @@
986 obj-y += firmware/
987 obj-$(CONFIG_CRYPTO) += crypto/
988 obj-$(CONFIG_SUPERH) += sh/
989 +obj-$(CONFIG_BLK_DEV_CF_MIPS) += block/rb500/
990 \ No newline at end of file