finally move buildroot-ng to trunk
[openwrt.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