bdev.c 8.5 KB

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