2 This is a block driver for the direct (mmaped) interface to the CF-slot,
3 found in Routerboard.com's RB532 board
4 See SDK provided from routerboard.com.
6 Module adapted By P.Christeas <p_christeas@yahoo.com>, 2005-6.
7 Cleaned up and adapted to platform_device by Felix Fietkau <nbd@openwrt.org>
9 This work is redistributed under the terms of the GNU General Public License.
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/time.h>
16 #include <linux/wait.h>
18 #include <linux/genhd.h>
19 #include <linux/blkdev.h>
20 #include <linux/blkpg.h>
21 #include <linux/hdreg.h>
22 #include <linux/platform_device.h>
24 #include <asm/uaccess.h>
26 #include <asm/mach-adm5120/adm5120_cf.h>
32 #define DEBUGP(format, args...)
36 #define CF_MIPS_MAJOR 13
37 #define MAJOR_NR CF_MIPS_MAJOR
38 #define CF_MAX_PART 16 /* max 15 partitions */
42 //extern struct block_device_operations cf_bdops;
44 // static struct hd_struct cf_parts[CF_MAX_PART];
45 // static int cf_part_sizes[CF_MAX_PART];
46 // static int cf_hsect_sizes[CF_MAX_PART];
47 // static int cf_max_sectors[CF_MAX_PART];
48 // static int cf_blksize_sizes[CF_MAX_PART];
50 // static spinlock_t lock = SPIN_LOCK_UNLOCKED;
52 // volatile int cf_busy = 0;
54 static struct request
*active_req
= NULL
;
56 static int cf_open (struct inode
*, struct file
*);
57 static int cf_release (struct inode
*, struct file
*);
58 static int cf_ioctl (struct inode
*, struct file
*, unsigned, unsigned long);
60 static void cf_request(request_queue_t
* q
);
61 static int cf_transfer(const struct request
*req
);
63 /*long (*unlocked_ioctl) (struct file *, unsigned, unsigned long);
64 long (*compat_ioctl) (struct file *, unsigned, unsigned long);*/
65 // int (*direct_access) (struct block_device *, sector_t, unsigned long *);
66 // int (*media_changed) (struct gendisk *);
67 // int (*revalidate_disk) (struct gendisk *);
69 static struct block_device_operations cf_bdops
= {
72 .release
= cf_release
,
74 .media_changed
= NULL
,
75 .unlocked_ioctl
= NULL
,
76 .revalidate_disk
= NULL
,
82 int cf_mips_probe(struct platform_device
*pdev
)
84 struct gendisk
* cf_gendisk
=NULL
;
85 struct cf_device
*cdev
= (struct cf_device
*) pdev
->dev
.platform_data
;
86 struct cf_mips_dev
*dev
;
90 reg_result
= register_blkdev(MAJOR_NR
, "cf-mips");
92 printk(KERN_WARNING
"cf-mips: can't get major %d\n", MAJOR_NR
);
96 dev
= (struct cf_mips_dev
*)kmalloc(sizeof(struct cf_mips_dev
),GFP_KERNEL
);
99 memset(dev
, 0, sizeof(struct cf_mips_dev
));
102 dev
->pin
= cdev
->gpio_pin
;
103 dev
->irq
= platform_get_irq_byname(pdev
, "cf_irq");
104 r
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
, "cf_membase");
105 dev
->base
= (void *) r
->start
;
107 if (cf_init(dev
)) goto out_err
;
110 spin_lock_init(&dev
->lock
);
111 dev
->queue
= blk_init_queue(cf_request
,&dev
->lock
);
113 printk(KERN_ERR
"cf-mips: no mem for queue\n");
116 blk_queue_max_sectors(dev
->queue
,ATA_MAX_SECT_PER_CMD
);
118 /* For memory devices, it is always better to avoid crossing segments
119 inside the same request. */
120 /* if (dev->dtype==0x848A){
121 printk(KERN_INFO "Setting boundary for cf to 0x%x",(dev->block_size*512)-1);
122 blk_queue_segment_boundary(dev->queue, (dev->block_size*512)-1);
125 dev
->gd
= alloc_disk(CF_MAX_PART
);
126 cf_gendisk
= dev
->gd
;
128 if (!cf_gendisk
) goto out_err
; /* Last of these goto's */
130 cf_gendisk
->major
= MAJOR_NR
;
131 cf_gendisk
->first_minor
= 0;
132 cf_gendisk
->queue
=dev
->queue
;
133 BUG_ON(cf_gendisk
->minors
!= CF_MAX_PART
);
134 strcpy(cf_gendisk
->disk_name
,"cfa");
135 cf_gendisk
->fops
= &cf_bdops
;
136 cf_gendisk
->flags
= 0 ; /* is not yet GENHD_FL_REMOVABLE */
137 cf_gendisk
->private_data
=dev
;
139 set_capacity(cf_gendisk
,dev
->sectors
* CF_KERNEL_MUL
);
141 /* Let the disk go live */
142 add_disk(cf_gendisk
);
146 /* default cfg for all partitions */
147 memset(cf_parts
, 0, sizeof (cf_parts
[0]) * CF_MAX_PART
);
148 memset(cf_part_sizes
, 0, sizeof (cf_part_sizes
[0]) * CF_MAX_PART
);
149 for (i
= 0; i
< CF_MAX_PART
; ++i
) {
150 cf_hsect_sizes
[i
] = CF_SECT_SIZE
;
151 cf_max_sectors
[i
] = ATA_MAX_SECT_PER_CMD
;
152 cf_blksize_sizes
[i
] = BLOCK_SIZE
;
155 /* setup info for whole disk (partition 0) */
156 cf_part_sizes
[0] = cf_sectors
/ 2;
157 cf_parts
[0].nr_sects
= cf_sectors
;
159 blk_size
[MAJOR_NR
] = cf_part_sizes
;
160 blksize_size
[MAJOR_NR
] = cf_blksize_sizes
;
161 max_sectors
[MAJOR_NR
] = cf_max_sectors
;
162 hardsect_size
[MAJOR_NR
] = cf_hsect_sizes
;
163 read_ahead
[MAJOR_NR
] = 8; /* (4kB) */
165 blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR
), DEVICE_REQUEST
);
167 add_gendisk(&cf_gendisk
);
169 // printk(KERN_INFO "cf-mips partition check: \n");
170 // register_disk(cf_gendisk, MKDEV(MAJOR_NR, 0), CF_MAX_PART,
171 // &cf_bdops, dev->sectors);
176 blk_cleanup_queue(dev
->queue
);
179 unregister_blkdev(MAJOR_NR
, "cf-mips");
190 cf_mips_remove(struct platform_device
*pdev
)
192 struct cf_device
*cdev
= (struct cf_device
*) pdev
->dev
.platform_data
;
193 struct cf_mips_dev
*dev
= (struct cf_mips_dev
*) cdev
->dev
;
195 unregister_blkdev(MAJOR_NR
, "cf-mips");
196 blk_cleanup_queue(dev
->queue
);
198 del_gendisk(dev
->gd
);
204 static struct platform_driver cf_driver
= {
205 .driver
.name
= "rb153-cf",
206 .probe
= cf_mips_probe
,
207 .remove
= cf_mips_remove
,
210 static int __init
cf_mips_init(void)
212 printk(KERN_INFO
"cf-mips module loaded\n");
213 return platform_driver_register(&cf_driver
);
216 static void cf_mips_cleanup(void)
218 platform_driver_unregister(&cf_driver
);
219 printk(KERN_INFO
"cf-mips module removed\n");
222 module_init(cf_mips_init
);
223 module_exit(cf_mips_cleanup
);
225 MODULE_LICENSE("GPL");
226 MODULE_ALIAS_BLOCKDEV_MAJOR(CF_MIPS_MAJOR
);
229 static int cf_open(struct inode
*inode
, struct file
*filp
)
231 struct cf_mips_dev
*dev
=inode
->i_bdev
->bd_disk
->private_data
;
232 int minor
= MINOR(inode
->i_rdev
);
234 if (minor
>= CF_MAX_PART
)
236 //DEBUGP(KERN_INFO "cf-mips module opened, minor %d\n", minor);
237 spin_lock(&dev
->lock
);
239 spin_unlock(&dev
->lock
);
240 filp
->private_data
=dev
;
242 /* dirty workaround to set CFRDY GPIO as an input when some other
243 program sets it as an output */
244 //gpio_set(CFG, (1 << dev->pin), 0);
245 return 0; /* success */
248 static int cf_release(struct inode
*inode
, struct file
*filp
)
250 int minor
= MINOR(inode
->i_rdev
);
251 struct cf_mips_dev
*dev
=inode
->i_bdev
->bd_disk
->private_data
;
252 spin_lock(&dev
->lock
);
254 spin_unlock(&dev
->lock
);
258 static int cf_ioctl(struct inode
*inode
, struct file
*filp
,
259 unsigned int cmd
, unsigned long arg
)
261 unsigned minor
= MINOR(inode
->i_rdev
);
262 struct cf_mips_dev
*dev
=inode
->i_bdev
->bd_disk
->private_data
;
264 DEBUGP(KERN_INFO
"cf_ioctl cmd %u\n", cmd
);
266 case BLKRRPART
: /* re-read partition table */
267 if (!capable(CAP_SYS_ADMIN
))
269 printk(KERN_INFO
"cf-mips partition check: \n");
270 register_disk(dev
->gd
);
275 struct hd_geometry geo
;
276 geo
.cylinders
= dev
->cyl
;
277 geo
.heads
= dev
->head
;
278 geo
.sectors
= dev
->spt
;
279 geo
.start
= (*dev
->gd
->part
)[minor
].start_sect
;
280 if (copy_to_user((void *) arg
, &geo
, sizeof (geo
)))
286 return -EINVAL
; /* unknown command */
289 static void cf_request(request_queue_t
* q
)
291 struct cf_mips_dev
* dev
;
293 struct request
* req
;
296 /* We could have q->queuedata = dev , but haven't yet. */
300 while ((req
=elv_next_request(q
))!=NULL
){
301 dev
=req
->rq_disk
->private_data
;
302 status
=cf_transfer(req
);
303 if (status
==CF_TRANS_IN_PROGRESS
){
307 end_request(req
,status
);
311 static int cf_transfer(const struct request
*req
)
313 struct cf_mips_dev
* dev
=req
->rq_disk
->private_data
;
315 if (!blk_fs_request(req
)){
316 if (printk_ratelimit())
317 printk(KERN_WARNING
"cf-mips: skipping non-fs request 0x%x\n",req
->cmd
[0]);
318 return CF_TRANS_FAILED
;
321 return cf_do_transfer(dev
,req
->sector
,req
->current_nr_sectors
,req
->buffer
,rq_data_dir(req
));
324 void cf_async_trans_done(struct cf_mips_dev
* dev
,int result
)
328 spin_lock(&dev
->lock
);
331 end_request(req
,result
);
332 spin_unlock(&dev
->lock
);
334 spin_lock(&dev
->lock
);
335 cf_request(dev
->queue
);
336 spin_unlock(&dev
->lock
);