doc1000.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:13k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*======================================================================
  2.   $Id: doc1000.c,v 1.16 2001/12/28 22:45:17 dwmw2 Exp $
  3. ======================================================================*/
  4. #include <linux/config.h>
  5. #include <linux/module.h>
  6. #include <asm/uaccess.h>
  7. #include <linux/types.h>
  8. #include <linux/kernel.h>
  9. #include <linux/sched.h>
  10. #include <linux/ptrace.h>
  11. #include <linux/slab.h>
  12. #include <linux/string.h>
  13. #include <linux/timer.h>
  14. #include <linux/major.h>
  15. #include <linux/fs.h>
  16. #include <linux/ioctl.h>
  17. #include <asm/io.h>
  18. #include <asm/system.h>
  19. #include <asm/segment.h>
  20. #include <stdarg.h>
  21. #include <linux/delay.h>
  22. #include <linux/init.h>
  23. #include <linux/mtd/mtd.h>
  24. #include <linux/mtd/iflash.h>
  25. /* Parameters that can be set with 'insmod' */
  26. static u_long base              = 0xe0000;
  27. static int erase_timeout = 10*HZ; /* in ticks */
  28. static int retry_limit = 4; /* write retries */
  29. static u_long max_tries        = 4096; /* status polling */
  30. MODULE_PARM(base,"l");
  31. MODULE_PARM(erase_timeout, "i");
  32. MODULE_PARM(retry_limit, "i");
  33. MODULE_PARM(max_tries, "i");
  34. #define WINDOW_SIZE 0x2000
  35. #define WINDOW_MASK (WINDOW_SIZE - 1)
  36. #define PAGEREG_LO (WINDOW_SIZE)
  37. #define PAGEREG_HI (WINDOW_SIZE + 2)
  38. static struct mtd_info *mymtd;
  39. static struct timer_list flashcard_timer;
  40. #define MAX_CELLS 32
  41. #define MAX_FLASH_DEVICES       8
  42. /* A flash region is composed of one or more "cells", where we allow
  43.    simultaneous erases if they are in different cells */
  44. struct mypriv {
  45. u_char *baseaddr;
  46. u_short curpage;
  47. u_char locked;
  48. u_short numdevices;
  49. u_char interleave;
  50. struct erase_info *cur_erases;
  51. wait_queue_head_t wq;
  52. u_char devstat[MAX_FLASH_DEVICES];
  53. u_long devshift;
  54. };
  55. static void flashcard_periodic(u_long data);
  56. static int flashcard_erase (struct mtd_info *mtd, struct erase_info *instr);
  57. static int flashcard_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
  58. static int flashcard_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
  59. static void flashcard_sync (struct mtd_info *mtd);
  60. static inline void resume_erase(volatile u_char *addr);
  61. static inline int suspend_erase(volatile u_char *addr);
  62. static inline int byte_write (volatile u_char *addr, u_char byte);
  63. static inline int word_write (volatile u_char *addr, __u16 word);
  64. static inline int check_write(volatile u_char *addr);
  65. static inline void block_erase (volatile u_char *addr);
  66. static inline int check_erase(volatile u_char *addr);
  67. #ifdef CONFIG_SMP
  68. #warning This is definitely not SMP safe. Lock the paging mechanism.
  69. #endif
  70. static u_char *pagein(struct mtd_info *mtd, u_long addr)
  71. {
  72.   struct mypriv *priv=mtd->priv;
  73.   u_short page = addr >> 13;
  74.   priv->baseaddr[PAGEREG_LO] = page & 0xff;
  75.   priv->baseaddr[PAGEREG_HI] = page >> 8;
  76.   priv->curpage = page;
  77.   
  78.   return &priv->baseaddr[addr & WINDOW_MASK];
  79. }
  80. void flashcard_sync (struct mtd_info *mtd)
  81. {
  82. struct mypriv *priv=mtd->priv;
  83. flashcard_periodic((u_long) mtd);
  84. printk("sync...");
  85. if (priv->cur_erases)
  86. interruptible_sleep_on(&priv->wq);
  87. printk("Done.n");
  88. }
  89. int flashcard_erase (struct mtd_info *mtd, struct erase_info *instr)
  90. {
  91. u_char *pageaddr;
  92. struct mypriv *priv=mtd->priv;
  93. struct erase_info **tmp=&priv->cur_erases;
  94. if (instr->len != mtd->erasesize)
  95. return -EINVAL;
  96. if (instr->addr + instr->len > mtd->size)
  97. return -EINVAL;
  98. pageaddr=pagein(mtd,instr->addr);
  99. instr->mtd = mtd;
  100. instr->dev = instr->addr >> priv->devshift;
  101. instr->cell = (instr->addr - (instr->dev << priv->devshift)) / mtd->erasesize;
  102. instr->next = NULL;
  103. instr->state = MTD_ERASE_PENDING;
  104. while (*tmp)
  105. {
  106. tmp = &((*tmp) -> next);
  107. }
  108. *tmp = instr;
  109. flashcard_periodic((u_long)mtd);
  110. return 0;
  111. }
  112. int flashcard_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
  113. {
  114.   u_char *pageaddr=pagein(mtd,from);
  115. struct mypriv *priv=mtd->priv;
  116. u_char device = from >> priv->devshift;
  117. u_char cell = (int) (from - (device << priv->devshift)) / mtd->erasesize;
  118. int ret = 0, timeron = 0;
  119. if ((from & WINDOW_MASK) + len <= WINDOW_SIZE)
  120. *retlen = len;
  121. else
  122. *retlen = WINDOW_SIZE - (from & WINDOW_MASK);
  123. if (priv->devstat[device])
  124. {
  125. /* There is an erase in progress or pending for this device. Stop it */
  126. timeron = del_timer(&flashcard_timer);
  127. if (priv->cur_erases && priv->cur_erases->cell == cell) 
  128. {
  129. /* The erase is on the current cell. Just return all 0xff */ 
  130. add_timer(&flashcard_timer);
  131. printk("Cell %d currently erasing. Setting to all 0xffn",cell);
  132. memset(buf, 0xff, *retlen);
  133. return 0;
  134. }
  135. if (priv->devstat[device] == MTD_ERASING)
  136. {
  137. ret = suspend_erase(pageaddr);
  138. priv->devstat[device] = MTD_ERASE_SUSPEND;
  139.        
  140. if (ret) 
  141. {
  142. printk("flashcard: failed to suspend erasen");
  143. add_timer (&flashcard_timer);
  144. return ret;
  145. }
  146. }
  147. }
  148. writew(IF_READ_ARRAY, (u_long)pageaddr & ~1);
  149. ret = 0;
  150. memcpy (buf, pageaddr, *retlen);
  151. writew(IF_READ_CSR, (u_long)pageaddr & ~1);
  152. if (priv->devstat[device] & MTD_ERASE_SUSPEND)
  153. {
  154. resume_erase(pageaddr);
  155. priv->devstat[device]=MTD_ERASING;
  156. }
  157. if (timeron) add_timer (&flashcard_timer);
  158. return ret;
  159. }
  160. int flashcard_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
  161. {
  162. struct mypriv *priv = (struct mypriv *)mtd->priv;
  163.   u_char *endaddr, *startaddr;
  164. register u_char *pageaddr;
  165. u_char device = to >> priv->devshift;
  166. /* jiffies_t oldj=jiffies;*/
  167. int ret;
  168. while (priv->devstat[device])
  169. {
  170. flashcard_sync(mtd);
  171. }
  172. if ((to & WINDOW_MASK) + len <= WINDOW_SIZE)
  173. *retlen = len;
  174. else
  175. *retlen = WINDOW_SIZE - (to & WINDOW_MASK);
  176. pageaddr = pagein(mtd, to);
  177. startaddr = (u_char *)((u_long) pageaddr & ~1);
  178. endaddr = pageaddr+(*retlen);
  179. /* Set up to read */
  180. writew(IF_READ_CSR, startaddr);
  181. /* Make sure it's aligned by reading the first byte if necessary */
  182. if (to & 1)
  183. {
  184. /* Unaligned access */
  185. u_char cbuf;
  186. cbuf = *buf;
  187. if (!((u_long)pageaddr & 0xf))
  188. schedule();
  189. ret = byte_write(pageaddr, cbuf);
  190. if (ret) return ret;
  191. pageaddr++; buf++;
  192. }
  193. for ( ; pageaddr + 1 < endaddr; buf += 2, pageaddr += 2)
  194. {
  195. /* if ((u_long)pageaddr & 0xf) schedule();*/
  196. ret = word_write(pageaddr, *(__u16 *)buf);
  197. if (ret) 
  198. return ret;
  199. }
  200. if (pageaddr != endaddr)
  201. {
  202. /* One more byte to write at the end. */
  203. u_char cbuf;
  204. cbuf = *buf;
  205. ret = byte_write(pageaddr, cbuf);
  206. if (ret) return ret;
  207. }
  208. return check_write(startaddr);
  209. /* printk("Time taken in flashcard_write: %lx jiffiesn",jiffies - oldj);*/
  210. }
  211. /*====================================================================*/
  212. static inline int byte_write (volatile u_char *addr, u_char byte)
  213. {
  214. register u_char status;
  215. register u_short i = 0;
  216. do {
  217. status = readb(addr);
  218. if (status & CSR_WR_READY)
  219. {
  220. writeb(IF_WRITE & 0xff, addr);
  221. writeb(byte, addr);
  222. return 0;
  223. }
  224. i++;
  225. } while(i < max_tries);
  226. printk(KERN_NOTICE "flashcard: byte_write timed out, status 0x%xn",status);
  227. return -EIO;
  228. }
  229. static inline int word_write (volatile u_char *addr, __u16 word)
  230. {
  231. register u_short status;
  232. register u_short i = 0;
  233. do {
  234. status = readw(addr);
  235. if ((status & CSR_WR_READY) == CSR_WR_READY)
  236. {
  237. writew(IF_WRITE, addr);
  238. writew(word, addr);
  239. return 0;
  240. }
  241. i++;
  242. } while(i < max_tries);
  243. printk(KERN_NOTICE "flashcard: word_write timed out at %p, status 0x%xn", addr, status);
  244. return -EIO;
  245. }
  246. static inline void block_erase (volatile u_char *addr)
  247. {
  248. writew(IF_BLOCK_ERASE, addr);
  249. writew(IF_CONFIRM, addr);
  250. }
  251. static inline int check_erase(volatile u_char *addr)
  252. {
  253. __u16 status;
  254. /* writew(IF_READ_CSR, addr);*/
  255. status = readw(addr);
  256. if ((status & CSR_WR_READY) != CSR_WR_READY)
  257. return -EBUSY;
  258. if (status & (CSR_ERA_ERR | CSR_VPP_LOW | CSR_WR_ERR)) 
  259. {
  260. printk(KERN_NOTICE "flashcard: erase failed, status 0x%xn",
  261.        status);
  262. return -EIO;
  263. }
  264. return 0;
  265. }
  266. static inline int suspend_erase(volatile u_char *addr)
  267. {
  268. __u16 status;
  269. u_long i = 0;
  270. writew(IF_ERASE_SUSPEND, addr);
  271. writew(IF_READ_CSR, addr);
  272. do {
  273. status = readw(addr);
  274. if ((status & CSR_WR_READY) == CSR_WR_READY)
  275. return 0;
  276. i++;
  277. } while(i < max_tries);
  278. printk(KERN_NOTICE "flashcard: suspend_erase timed out, status 0x%xn", status);
  279. return -EIO;
  280. }
  281. static inline void resume_erase(volatile u_char *addr)
  282. {
  283. __u16 status;
  284. writew(IF_READ_CSR, addr);
  285. status = readw(addr);
  286. /* Only give resume signal if the erase is really suspended */
  287. if (status & CSR_ERA_SUSPEND)
  288. writew(IF_CONFIRM, addr);
  289. }
  290. static inline void reset_block(volatile u_char *addr)
  291. {
  292. u_short i;
  293. __u16 status;
  294. writew(IF_CLEAR_CSR, addr);
  295. for (i = 0; i < 100; i++) {
  296. writew(IF_READ_CSR, addr);
  297. status = readw(addr);
  298. if (status != 0xffff) break;
  299. udelay(1000);
  300. }
  301. writew(IF_READ_CSR, addr);
  302. }
  303. static inline int check_write(volatile u_char *addr)
  304. {
  305. u_short status, i = 0;
  306. writew(IF_READ_CSR, addr);
  307. do {
  308. status = readw(addr);
  309. if (status & (CSR_WR_ERR | CSR_VPP_LOW))
  310. {
  311. printk(KERN_NOTICE "flashcard: write failure at %p, status 0x%xn", addr, status);
  312. reset_block(addr);
  313. return -EIO;
  314. }
  315. if ((status & CSR_WR_READY) == CSR_WR_READY)
  316. return 0;
  317. i++;
  318. } while (i < max_tries);
  319. printk(KERN_NOTICE "flashcard: write timed out at %p, status 0x%xn", addr, status);
  320. return -EIO;
  321. }
  322. /*====================================================================*/
  323. static void flashcard_periodic(unsigned long data)
  324. {
  325. register struct mtd_info *mtd = (struct mtd_info *)data;
  326. register struct mypriv *priv = mtd->priv;
  327. struct erase_info *erase = priv->cur_erases;
  328. u_char *pageaddr;
  329. del_timer (&flashcard_timer);
  330. if (!erase)
  331. return;
  332. pageaddr = pagein(mtd, erase->addr);
  333. if (erase->state == MTD_ERASE_PENDING)
  334. {
  335. block_erase(pageaddr);
  336. priv->devstat[erase->dev] = erase->state = MTD_ERASING;
  337. erase->time = jiffies;
  338. erase->retries = 0;
  339. }
  340. else if (erase->state == MTD_ERASING)
  341. {
  342. /* It's trying to erase. Check whether it's finished */
  343. int ret = check_erase(pageaddr);
  344. if (!ret)
  345. {
  346. /* It's finished OK */
  347. priv->devstat[erase->dev] = 0;
  348. priv->cur_erases = erase->next;
  349. erase->state = MTD_ERASE_DONE;
  350. if (erase->callback)
  351. (*(erase->callback))(erase);
  352. else
  353. kfree(erase);
  354. }
  355. else if (ret == -EIO)
  356. {
  357. if (++erase->retries > retry_limit)
  358. {
  359. printk("Failed too many times. Giving upn");
  360. priv->cur_erases = erase->next;
  361. priv->devstat[erase->dev] = 0;
  362. erase->state = MTD_ERASE_FAILED;
  363. if (erase->callback)
  364. (*(erase->callback))(erase);
  365. else
  366. kfree(erase);
  367. }
  368. else
  369. priv->devstat[erase->dev] = erase->state = MTD_ERASE_PENDING;
  370. }
  371. else if (time_after(jiffies, erase->time + erase_timeout))
  372. {
  373. printk("Flash erase timed out. The world is broken.n");
  374. /* Just ignore and hope it goes away. For a while, read ops will give the CSR
  375.    and writes won't work. */
  376. priv->cur_erases = erase->next;
  377. priv->devstat[erase->dev] = 0;
  378. erase->state = MTD_ERASE_FAILED;
  379. if (erase->callback)
  380. (*(erase->callback))(erase);
  381. else
  382. kfree(erase);
  383. }
  384. }
  385. if (priv->cur_erases)
  386. {
  387. flashcard_timer.expires = jiffies + HZ;
  388. add_timer (&flashcard_timer);
  389. }
  390. else 
  391. wake_up_interruptible(&priv->wq);
  392. }
  393. int __init init_doc1000(void)
  394. {
  395. struct mypriv *priv;
  396. if (!base)
  397. {
  398. printk(KERN_NOTICE "flashcard: No start address for memory device.n");
  399. return -EINVAL;
  400. }
  401. mymtd  = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
  402. if (!mymtd)
  403. {
  404. printk(KERN_NOTICE "physmem: Cannot allocate memory for new MTD device.n");
  405. return -ENOMEM;
  406. }
  407. memset(mymtd,0,sizeof(struct mtd_info));
  408. mymtd->priv = (void *) kmalloc (sizeof(struct mypriv), GFP_KERNEL);
  409. if (!mymtd->priv)
  410.   {
  411.     kfree(mymtd);
  412.     printk(KERN_NOTICE "physmem: Cannot allocate memory for new MTD device's private data.n");
  413.     return -ENOMEM;
  414.   }
  415. priv=mymtd->priv;
  416. init_waitqueue_head(&priv->wq);
  417. memset (priv,0,sizeof(struct mypriv));
  418. priv->baseaddr = phys_to_virt(base);
  419. priv->numdevices = 4;
  420. mymtd->name = "M-Systems DiskOnChip 1000";
  421. mymtd->size = 0x100000;
  422. mymtd->flags = MTD_CLEAR_BITS | MTD_ERASEABLE;
  423.         mymtd->erase = flashcard_erase;
  424. mymtd->point = NULL;
  425. mymtd->unpoint = NULL;
  426. mymtd->read = flashcard_read;
  427. mymtd->write = flashcard_write;
  428. mymtd->sync = flashcard_sync;
  429. mymtd->erasesize = 0x10000;
  430. // mymtd->interleave = 2;
  431. priv->devshift =  24;
  432. mymtd->type = MTD_NORFLASH;
  433. if (add_mtd_device(mymtd))
  434. {
  435. printk(KERN_NOTICE "MTD device registration failed!n");
  436. kfree(mymtd->priv);
  437. kfree(mymtd);
  438. return -EAGAIN;
  439. }
  440. init_timer(&flashcard_timer);
  441. flashcard_timer.function = flashcard_periodic;
  442. flashcard_timer.data = (u_long)mymtd;
  443. return 0;
  444. }
  445. static void __init cleanup_doc1000(void)
  446. {
  447. kfree (mymtd->priv);
  448. del_mtd_device(mymtd);
  449. kfree(mymtd);
  450. }
  451. module_init(init_doc1000);
  452. module_exit(cleanup_doc1000);
  453. MODULE_LICENSE("GPL");
  454. MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
  455. MODULE_DESCRIPTION("MTD driver for DiskOnChip 1000");