dumchar.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236
  1. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  2. #include <linux/module.h>
  3. #include <linux/moduleparam.h>
  4. #include <linux/init.h>
  5. #include <linux/kernel.h> /* printk() */
  6. #include <linux/slab.h> /* kmalloc() */
  7. #include <linux/fs.h> /* everything... filp_open */
  8. #include <linux/errno.h> /* error codes */
  9. #include <linux/types.h> /* size_t */
  10. #include <linux/proc_fs.h> /*proc */
  11. #include <linux/seq_file.h>
  12. #include <linux/fcntl.h> /* O_ACCMODE */
  13. #include <linux/aio.h>
  14. #include <asm/uaccess.h> /*set_fs get_fs mm_segment_t */
  15. #include <linux/miscdevice.h>
  16. #include <linux/platform_device.h>
  17. #include <linux/unistd.h>
  18. #include <linux/cdev.h>
  19. #include <linux/device.h>
  20. #include <linux/mtd/mtd.h>
  21. #include <linux/syscalls.h>
  22. #include <generated/autoconf.h>
  23. #include <linux/sched.h> /* show_stack(current,NULL) */
  24. #include <linux/genhd.h>
  25. #include <linux/mmc/host.h>
  26. /*#include <linux/mmc/sd_misc.h>*/
  27. #include "partition_define.h"
  28. #include "dumchar.h" /* local definitions */
  29. #ifdef CONFIG_OF
  30. #include <linux/of.h>
  31. #include <linux/of_address.h>
  32. #include <linux/of_irq.h>
  33. #endif
  34. struct device;
  35. static struct class *dumchar_class;
  36. static struct device *dumchar_device[PART_MAX_COUNT];
  37. static struct dumchar_dev *dumchar_devices; /* store all dum char info, allocated in dumchar_init */
  38. /* struct excel_info *PartInfo; */
  39. struct excel_info PartInfo[PART_MAX_COUNT];
  40. EXPORT_SYMBOL(PartInfo);
  41. static unsigned int major;
  42. int IsEmmc(void)
  43. {
  44. #ifdef CONFIG_MTK_EMMC_SUPPORT
  45. return 1;
  46. #else
  47. return 0;
  48. #endif
  49. }
  50. EXPORT_SYMBOL(IsEmmc);
  51. #ifdef CONFIG_MTK_EMMC_SUPPORT
  52. int eMMC_rw_x(loff_t addr, u32 *buffer, int host_num, int iswrite, u32 totalsize, int transtype,
  53. Region part)
  54. {
  55. struct msdc_ioctl cmd;
  56. int result = 0;
  57. if (addr < 0) {
  58. pr_err("DumChar ERROR:Wrong Address %llx for emmc!\n", addr);
  59. return -EINVAL;
  60. }
  61. memset(&cmd, 0, sizeof(struct msdc_ioctl));
  62. if (addr % 512 == 0) {
  63. cmd.address = addr / 512;
  64. } else {
  65. pr_err("DumChar ERROR: Wrong Address\n");
  66. return -EINVAL;
  67. }
  68. /* cmd->address =0x100000; */
  69. cmd.buffer = buffer;
  70. cmd.clock_freq = 0;
  71. cmd.host_num = host_num;
  72. cmd.iswrite = iswrite;
  73. cmd.result = -1;
  74. cmd.trans_type = transtype;
  75. cmd.total_size = totalsize;
  76. /* cmd.region = part; */
  77. cmd.partition = part;
  78. cmd.opcode = MSDC_CARD_DUNM_FUNC;
  79. result = simple_sd_ioctl_rw(&cmd);
  80. return result;
  81. }
  82. EXPORT_SYMBOL(eMMC_rw_x);
  83. void emmc_create_sys_symlink(struct mmc_card *card)
  84. {
  85. }
  86. static void emmc_create_symlink(void)
  87. {
  88. dev_t devt;
  89. int partno;
  90. struct gendisk *disk;
  91. struct disk_part_iter piter;
  92. struct hd_struct *part;
  93. char link_target[256];
  94. char link_name[256];
  95. int i;
  96. devt = blk_lookup_devt("mmcblk0", 0);
  97. disk = get_gendisk(devt, &partno);
  98. if (!disk || get_capacity(disk) == 0) {
  99. pr_debug("devt %d disk %p\n", devt, disk);
  100. return;
  101. }
  102. disk_part_iter_init(&piter, disk, 0);
  103. while ((part = disk_part_iter_next(&piter))) {
  104. for (i = 0; i < PART_NUM; i++) {
  105. if (PartInfo[i].start_address == part->start_sect * 512) {
  106. sprintf(link_target, "/dev/block/%sp%d", disk->disk_name,
  107. part->partno);
  108. sprintf(link_name, "/emmc@%s", PartInfo[i].name);
  109. pr_err("%s:target=%s, name=%s\n", __func__, link_target,
  110. link_name);
  111. sys_symlink(link_target, link_name);
  112. break;
  113. }
  114. }
  115. }
  116. disk_part_iter_exit(&piter);
  117. }
  118. #else
  119. int mtd_create_symlink(void)
  120. {
  121. char *link_target;
  122. char link_name[256];
  123. int i;
  124. for (i = 0; i < PART_NUM; i++) {
  125. if (dumchar_devices[i].actname) {
  126. memset(link_name, 0x0, sizeof(link_name));
  127. link_target = dumchar_devices[i].actname;
  128. sprintf(link_name, "/mtd@%s", dumchar_devices[i].dumname);
  129. pr_debug("[mtd_create_symlink]: target=%s, name=%s\n", link_target,
  130. link_name);
  131. sys_symlink(link_target, link_name);
  132. }
  133. }
  134. return 0;
  135. }
  136. #endif
  137. #ifdef CONFIG_MTK_EMMC_SUPPORT
  138. static int init_sd_cmd(struct msdc_ioctl *cmd, loff_t addr,
  139. u32 __user *buffer, int host_num, int iswrite,
  140. u32 totalsize, int transtype, Region part)
  141. {
  142. if (!cmd) {
  143. pr_err("DumChar ERROR:no space for msdc_ioctl\n");
  144. return -EINVAL;
  145. }
  146. if (addr < 0) {
  147. pr_err("DumChar ERROR:Wrong Address %llx for emmc!\n", addr);
  148. return -EINVAL;
  149. }
  150. if (totalsize > MAX_SD_BUFFER) {
  151. pr_err("DumChar ERROR:too mucn bytes for msdc\n");
  152. return -EINVAL;
  153. }
  154. memset(cmd, 0, sizeof(struct msdc_ioctl));
  155. if (addr % 512 == 0) {
  156. cmd->address = addr / 512;
  157. } else {
  158. pr_err("DumChar ERROR: Wrong Address\n");
  159. return -EINVAL;
  160. }
  161. cmd->buffer = buffer;
  162. cmd->clock_freq = 0;
  163. cmd->host_num = host_num;
  164. cmd->iswrite = iswrite;
  165. cmd->result = -1;
  166. cmd->trans_type = transtype;
  167. cmd->total_size = totalsize;
  168. cmd->partition = part;
  169. /* cmdtype:MSDC_SINGLE_READ_WRITE while MAX_SD_BUFFER >totalsize >512 byte;
  170. MSDC_MULTIPLE_READ_WRITE while totalsize <=512 byte;
  171. */
  172. if (totalsize <= 512)
  173. cmd->opcode = MSDC_SINGLE_READ_WRITE;
  174. else
  175. cmd->opcode = MSDC_MULTIPLE_READ_WRITE;
  176. /*
  177. pr_debug("*****************************\nDumCharDebug:in init_sd_cmd:\n");
  178. pr_debug("cmd->opcode=%d MSDC_SINGLE_READ_WRITE =(2) MSDC_MULTIPLE_READ_WRITE =(3)\n",cmd->opcode);
  179. pr_debug("cmd->host_num=%d supose=1\n",cmd->host_num);
  180. pr_debug("cmd->iswrite=%d write=1 read=0\n",cmd->iswrite);
  181. pr_debug("cmd->trans_type=%d\n",cmd->trans_type);
  182. pr_debug("cmd->total_size=%d\n",cmd->total_size);
  183. pr_debug("cmd->address=%d\n",cmd->address);
  184. pr_debug("cmd->buffer=%p\n",cmd->buffer);
  185. pr_debug("cmd->cmd_driving=%d\n",cmd->cmd_driving);
  186. pr_debug("cmd->dat_driving=%d\n",cmd->dat_driving);
  187. pr_debug("cmd->clock_freq=%d\n",cmd->clock_freq);
  188. pr_debug("cmd->result=%d\n",cmd->result);
  189. pr_debug("***************************\n");
  190. */
  191. return 0;
  192. }
  193. static ssize_t sd_single_read(struct file *filp, char __user *buf, size_t count, loff_t addr,
  194. Region part)
  195. {
  196. struct file_obj *fo = filp->private_data;
  197. struct msdc_ioctl cmd;
  198. ssize_t result = 0;
  199. if (init_sd_cmd(&cmd, addr, (u32 *) buf, 0, 0, count, 0, part)) {
  200. pr_err("DumChar:init sd_cmd fail\n");
  201. return -EINVAL;
  202. }
  203. if (fo->act_filp->f_op->unlocked_ioctl)
  204. result = fo->act_filp->f_op->unlocked_ioctl(fo->act_filp, 1, (unsigned long)&cmd);
  205. else if (fo->act_filp->f_op->compat_ioctl)
  206. result = fo->act_filp->f_op->compat_ioctl(fo->act_filp, 1, (unsigned long)&cmd);
  207. if (result == 0)
  208. result = count;
  209. return result;
  210. }
  211. static ssize_t sd_single_write(struct file *filp, const char __user *buf, size_t count,
  212. loff_t addr, Region part)
  213. {
  214. struct file_obj *fo = filp->private_data;
  215. struct msdc_ioctl cmd;
  216. int result = 0;
  217. if (init_sd_cmd(&cmd, addr, (u32 *) buf, 0, 1, count, 0, part)) {
  218. pr_err("DumChar:init sd_cmd fail\n");
  219. return -EINVAL;
  220. }
  221. if (fo->act_filp->f_op->unlocked_ioctl)
  222. result = fo->act_filp->f_op->unlocked_ioctl(fo->act_filp, 1, (unsigned long)&cmd);
  223. else if (fo->act_filp->f_op->compat_ioctl)
  224. result = fo->act_filp->f_op->compat_ioctl(fo->act_filp, 1, (unsigned long)&cmd);
  225. if (result >= 0)
  226. result = count;
  227. else
  228. result = 0;
  229. return result;
  230. }
  231. static ssize_t sd_read(struct file *filp, char __user *buf, size_t count, loff_t *pos,
  232. Region part)
  233. {
  234. struct file_obj *fo = filp->private_data;
  235. struct dumchar_dev *dev = dumchar_devices + fo->index;
  236. size_t total_retlen = 0;
  237. int retlen = 0;
  238. int len;
  239. loff_t addr = *pos;
  240. if (*pos - dev->start_address + count > dev->size)
  241. count = dev->size - (*pos - dev->start_address);
  242. if (!count)
  243. return 0;
  244. if (addr % ALIE_LEN != 0 || (addr + count) % ALIE_LEN != 0) {
  245. loff_t startaddr = addr;
  246. loff_t endaddr = addr + count;
  247. loff_t startaddr2, endaddr2;
  248. loff_t buflen;
  249. char *pbuf;
  250. char *pbuf2;
  251. mm_segment_t curr_fs;
  252. if (addr % ALIE_LEN != 0)
  253. startaddr = (addr / ALIE_LEN) * ALIE_LEN;
  254. if ((addr + count) % ALIE_LEN != 0)
  255. endaddr = ((addr + count) / ALIE_LEN + 1) * ALIE_LEN;
  256. buflen = endaddr - startaddr;
  257. startaddr2 = startaddr;
  258. endaddr2 = endaddr;
  259. pbuf = kzalloc(buflen, GFP_KERNEL);
  260. if (!pbuf) {
  261. /* pr_debug("DumChar: malloc buff fail\n"); */
  262. return -ENOMEM;
  263. }
  264. pbuf2 = pbuf;
  265. curr_fs = get_fs();
  266. set_fs(KERNEL_DS);
  267. while (buflen > 0) {
  268. if (buflen > MAX_SD_BUFFER)
  269. len = MAX_SD_BUFFER;
  270. else
  271. len = buflen;
  272. retlen = sd_single_read(filp, pbuf2, len, startaddr2, part);
  273. if (retlen > 0) {
  274. startaddr2 += retlen;
  275. total_retlen += retlen;
  276. buflen -= retlen;
  277. pbuf2 += retlen;
  278. pr_debug("while retlen > 0 total_retlen=%d\n", (int)total_retlen);
  279. } else {
  280. break;
  281. }
  282. }
  283. set_fs(curr_fs);
  284. #if defined(PrintBuff)
  285. int iter = 0;
  286. pr_debug
  287. ("******************************\nGet %d bytes from %d to %d in %s in kernel\n",
  288. (int)total_retlen, (int)startaddr, (int)endaddr, dev->dumname);
  289. for (iter = 0; iter < total_retlen; iter++) {
  290. if (iter % 16 == 0)
  291. pr_debug("\n");
  292. pr_debug(" %02x", pbuf[iter]);
  293. }
  294. pr_debug("\n********************************************************************\n");
  295. #endif
  296. if (total_retlen == (endaddr - startaddr)) {
  297. int n = copy_to_user(buf, pbuf + (addr - startaddr), count);
  298. if (n != 0)
  299. pr_err("read fail in DumChar_sd_read\n");
  300. total_retlen = count - n;
  301. } else {
  302. pr_err("read fail DumChar_sd_read!\n");
  303. }
  304. #if defined(PrintBuff)
  305. pr_debug("******************************\nGet %ld bytes from %d in %s in user:\n",
  306. count, (int)*pos, dev->dumname);
  307. for (iter = 0; iter < count; iter++) {
  308. if (iter % 16 == 0)
  309. pr_debug("\n");
  310. pr_debug(" %02x", buf[iter]);
  311. }
  312. pr_debug("\n********************************************************************\n");
  313. #endif
  314. kfree(pbuf);
  315. } else {
  316. while (count > 0) {
  317. if (count > MAX_SD_BUFFER)
  318. len = MAX_SD_BUFFER;
  319. else
  320. len = count;
  321. retlen = sd_single_read(filp, buf, len, addr, part);
  322. if (retlen > 0) {
  323. addr += retlen;
  324. total_retlen += retlen;
  325. count -= retlen;
  326. buf += retlen;
  327. } else {
  328. break;
  329. }
  330. }
  331. }
  332. *pos += total_retlen;
  333. return total_retlen;
  334. }
  335. static ssize_t sd_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos,
  336. Region part)
  337. {
  338. struct file_obj *fo = filp->private_data;
  339. struct dumchar_dev *dev = dumchar_devices + fo->index;
  340. size_t total_retlen = 0;
  341. int retlen = 0;
  342. int len;
  343. loff_t addr = *pos; /* +dev->start_address; */
  344. if (*pos + count > dev->size)
  345. count = dev->size - *pos;
  346. if (!count)
  347. return 0;
  348. while (count > 0) {
  349. if (count > MAX_SD_BUFFER)
  350. len = MAX_SD_BUFFER;
  351. else
  352. len = count;
  353. retlen = sd_single_write(filp, buf, len, addr, part);
  354. if (retlen > 0) {
  355. addr += retlen;
  356. total_retlen += retlen;
  357. count -= retlen;
  358. buf += retlen;
  359. } else {
  360. return total_retlen;
  361. }
  362. }
  363. *pos += total_retlen;
  364. return total_retlen;
  365. }
  366. #endif
  367. static ssize_t dumchar_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
  368. {
  369. struct file_obj *fo = filp->private_data;
  370. struct dumchar_dev *dev = dumchar_devices + fo->index;
  371. ssize_t result = 0;
  372. #ifdef CONFIG_MTK_EMMC_SUPPORT
  373. loff_t pos = 0;
  374. #endif
  375. if (fo->act_filp == (struct file *)0xffffffff) {
  376. pr_err("[dumchar_read] It is forbidded to access %s with dumchar(/dev/%s),the %s partition is managed by filesystem!\n",
  377. dev->dumname, dev->dumname, dev->dumname);
  378. pr_debug("[dumchar_read] show_stack*************************************\n");
  379. show_stack(NULL, NULL);
  380. return -EINVAL;
  381. }
  382. if (dev->type != NAND && dev->type != EMMC) {
  383. pr_err("DumChar:Wrong Dummy device Type %d ,it should be MTD or SDCARD!\n",
  384. dev->type);
  385. return -EINVAL;
  386. }
  387. if (dev->type == EMMC) {
  388. #ifdef CONFIG_MTK_EMMC_SUPPORT
  389. pos = *f_pos + dev->start_address;
  390. switch (dev->region) {
  391. case EMMC_PART_USER:
  392. result = vfs_read(fo->act_filp, buf, count, &pos);
  393. break;
  394. case EMMC_PART_BOOT1:
  395. result = sd_read(filp, buf, count, &pos, EMMC_PART_BOOT1);
  396. break;
  397. default:
  398. pr_err("DumChar: Wrong EMMC Region\n");
  399. return -EINVAL;
  400. }
  401. fo->act_filp->f_pos = pos - dev->start_address;
  402. *f_pos = pos - dev->start_address;
  403. #endif
  404. } else {
  405. result = vfs_read(fo->act_filp, buf, count, f_pos);
  406. fo->act_filp->f_pos = *f_pos;
  407. }
  408. return result;
  409. }
  410. ssize_t dumchar_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
  411. {
  412. struct file_obj *fo = filp->private_data;
  413. struct dumchar_dev *dev = dumchar_devices + fo->index;
  414. ssize_t result = 0;
  415. #ifdef CONFIG_MTK_EMMC_SUPPORT
  416. loff_t pos = 0;
  417. #endif
  418. #ifdef CONFIG_MTK_COMBO_NAND_SUPPORT
  419. struct mtd_info *mtd;
  420. unsigned int writesize = -1;
  421. #endif
  422. if (fo->act_filp == (struct file *)0xffffffff) {
  423. pr_err("[dumchar_write] It is forbidded to access %s with dumchar(/dev/%s),the %s partition is managed by filesystem!\n",
  424. dev->dumname, dev->dumname, dev->dumname);
  425. pr_debug("[dumchar_write] show_stack*************************************\n");
  426. show_stack(NULL, NULL);
  427. return -EINVAL;
  428. }
  429. #ifdef CONFIG_MTK_COMBO_NAND_SUPPORT
  430. mtd_for_each_device(mtd) {
  431. if (dev->mtd_index == mtd->index) {
  432. writesize = mtd->writesize;
  433. break;
  434. }
  435. }
  436. if (writesize < 0) {
  437. pr_err("[dumchar_write] Get writesize fail\n");
  438. show_stack(NULL, NULL);
  439. return -EINVAL;
  440. }
  441. if ((__u32) *f_pos % (writesize) != 0) {
  442. pr_err("[dumchar_write] Address Not alignment, write_size=%d byte, address =%lld\n",
  443. writesize, *f_pos);
  444. show_stack(NULL, NULL);
  445. return -EINVAL;
  446. }
  447. #else
  448. if (*f_pos % (WRITE_SIZE_Byte) != 0) {
  449. pr_err("[dumchar_write] Address Not alignment, write_size=%d byte, address =%lld\n",
  450. WRITE_SIZE_Byte, *f_pos);
  451. show_stack(NULL, NULL);
  452. return -EINVAL;
  453. }
  454. #endif
  455. if (dev->type != NAND && dev->type != EMMC) {
  456. pr_err("DumChar:Wrong Dummy device Type %d ,it should be MTD or SDCARD!\n",
  457. dev->type);
  458. return -EINVAL;
  459. }
  460. if (dev->type == EMMC) {
  461. #ifdef CONFIG_MTK_EMMC_SUPPORT
  462. pos = *f_pos + dev->start_address;
  463. switch (dev->region) {
  464. case EMMC_PART_USER:
  465. result = vfs_write(fo->act_filp, buf, count, &pos);
  466. break;
  467. case EMMC_PART_BOOT1:
  468. result = sd_write(filp, buf, count, &pos, EMMC_PART_BOOT1);
  469. break;
  470. default:
  471. pr_err("DumChar: Wrong EMMC Region\n");
  472. return -EINVAL;
  473. }
  474. fo->act_filp->f_pos = pos - dev->start_address;
  475. *f_pos = pos - dev->start_address;
  476. #endif
  477. } else {
  478. result = vfs_write(fo->act_filp, buf, count, f_pos);
  479. fo->act_filp->f_pos = *f_pos;
  480. }
  481. return result;
  482. }
  483. static long dumchar_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
  484. {
  485. struct file_obj *fo = filp->private_data;
  486. struct dumchar_dev *dev = dumchar_devices + fo->index;
  487. long result = 0;
  488. #ifdef CONFIG_MTK_EMMC_SUPPORT
  489. long i;
  490. struct mtd_info_user info;
  491. struct erase_info_user erase_info;
  492. void __user *argp = (void __user *)arg;
  493. u_long size;
  494. mm_segment_t curr_fs;
  495. char *ebuf;
  496. loff_t addr;
  497. __u32 count;
  498. #endif
  499. if (fo->act_filp == (struct file *)0xffffffff) {
  500. pr_err("[dumchar_ioctl] It is forbidded to access %s with dumchar(/dev/%s),the %s partition is managed by filesystem!\n",
  501. dev->dumname, dev->dumname, dev->dumname);
  502. pr_debug("[dumchar_loctl] show_stack*************************************\n");
  503. show_stack(NULL, NULL);
  504. return -EINVAL;
  505. }
  506. if (dev->type != NAND && dev->type != EMMC) {
  507. pr_err("DumChar:Wrong Dummy device Type %d ,it should be MTD or SDCARD!\n",
  508. dev->type);
  509. return -EINVAL;
  510. }
  511. if (dev->type == NAND) {
  512. if (fo->act_filp->f_op->unlocked_ioctl)
  513. result = fo->act_filp->f_op->unlocked_ioctl(fo->act_filp, cmd, arg);
  514. else if (fo->act_filp->f_op->compat_ioctl)
  515. result = fo->act_filp->f_op->compat_ioctl(fo->act_filp, cmd, arg);
  516. } else {
  517. #ifdef CONFIG_MTK_EMMC_SUPPORT
  518. size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
  519. if (cmd & IOC_IN) {
  520. if (!access_ok(VERIFY_READ, argp, size))
  521. return -EFAULT;
  522. }
  523. if (cmd & IOC_OUT) {
  524. if (!access_ok(VERIFY_WRITE, argp, size))
  525. return -EFAULT;
  526. }
  527. switch (cmd) {
  528. case MEMGETREGIONCOUNT:
  529. break;
  530. case MEMGETREGIONINFO:
  531. break;
  532. case MEMGETINFO:
  533. info.type = MTD_NANDFLASH;
  534. info.flags = MTD_WRITEABLE;
  535. info.size = dev->size;
  536. info.erasesize = 128 * 1024;
  537. info.writesize = 512;
  538. info.oobsize = 0;
  539. info.padding = 0;
  540. if (copy_to_user(argp, &info, sizeof(struct mtd_info_user)))
  541. return -EFAULT;
  542. break;
  543. case MEMERASE:
  544. if (copy_from_user(&erase_info, argp, sizeof(struct erase_info_user)))
  545. return -EFAULT;
  546. addr = (loff_t) erase_info.start + dev->start_address;
  547. count = erase_info.length;
  548. ebuf = kmalloc(MAX_SD_BUFFER, GFP_KERNEL);
  549. if (!ebuf) {
  550. pr_err("DumChar: malloc ebuf buffer fail\n");
  551. return -ENOMEM;
  552. }
  553. memset(ebuf, 0xFF, MAX_SD_BUFFER);
  554. curr_fs = get_fs();
  555. set_fs(KERNEL_DS);
  556. switch (dev->region) {
  557. case EMMC_PART_USER:
  558. for (i = 0; i < (count + MAX_SD_BUFFER - 1) / MAX_SD_BUFFER; i++) {
  559. result =
  560. vfs_write(fo->act_filp, ebuf, MAX_SD_BUFFER, &addr);
  561. }
  562. break;
  563. case EMMC_PART_BOOT1:
  564. for (i = 0; i < (count + MAX_SD_BUFFER - 1) / MAX_SD_BUFFER; i++) {
  565. result =
  566. sd_write(filp, ebuf, MAX_SD_BUFFER, &addr,
  567. EMMC_PART_BOOT1);
  568. }
  569. break;
  570. default:
  571. pr_err("DumChar: Wrong EMMC Region\n");
  572. return -EINVAL;
  573. }
  574. set_fs(curr_fs);
  575. kfree(ebuf);
  576. break;
  577. case MEMERASE64:
  578. break;
  579. case MEMWRITEOOB:
  580. break;
  581. case MEMREADOOB:
  582. break;
  583. case MEMWRITEOOB64:
  584. break;
  585. case MEMREADOOB64:
  586. break;
  587. case MEMLOCK:
  588. break;
  589. case MEMUNLOCK:
  590. break;
  591. case MEMGETOOBSEL:
  592. break;
  593. case MEMGETBADBLOCK:
  594. break;
  595. case MEMSETBADBLOCK:
  596. break;
  597. case ECCGETLAYOUT:
  598. break;
  599. case ECCGETSTATS:
  600. break;
  601. case MTDFILEMODE:
  602. break;
  603. case MTD_FILE_MODE_NORMAL:
  604. break;
  605. default:
  606. result = -EINVAL;
  607. }
  608. #endif
  609. }
  610. return result;
  611. }
  612. loff_t dumchar_llseek(struct file *filp, loff_t off, int whence)
  613. {
  614. struct file_obj *fo = filp->private_data;
  615. struct dumchar_dev *dev = dumchar_devices + fo->index;
  616. loff_t newpos;
  617. if (fo->act_filp == (struct file *)0xffffffff) {
  618. pr_err("[dumchar_llseek] It is forbidded to access %s with dumchar(/dev/%s),the %s partition is managed by filesystem!\n",
  619. dev->dumname, dev->dumname, dev->dumname);
  620. pr_debug("[dumchar_llseek] show_stack*************************************\n");
  621. show_stack(NULL, NULL);
  622. return -EINVAL;
  623. }
  624. if (dev->type != NAND && dev->type != EMMC) {
  625. pr_err("DumChar:Wrong Dummy device Type %d ,it should be MTD or SDCARD!\n",
  626. dev->type);
  627. return -EINVAL;
  628. }
  629. if (fo->act_filp->f_op->llseek) {
  630. newpos = fo->act_filp->f_op->llseek(fo->act_filp, off, whence);
  631. } else {
  632. switch (whence) {
  633. case SEEK_SET:
  634. newpos = off;
  635. break;
  636. case SEEK_CUR:
  637. newpos = fo->act_filp->f_pos + off;
  638. break;
  639. case SEEK_END:
  640. newpos = dev->size + off;
  641. break;
  642. default:
  643. return -EINVAL;
  644. }
  645. }
  646. if (newpos >= 0 && newpos <= dev->size) {
  647. fo->act_filp->f_pos = newpos;
  648. filp->f_pos = newpos;
  649. return fo->act_filp->f_pos;
  650. }
  651. return -EINVAL;
  652. }
  653. int dumchar_open(struct inode *inode, struct file *filp)
  654. {
  655. struct dumchar_dev *dev; /* device information */
  656. struct file_obj *fo;
  657. int i, result = -1, found = 0;
  658. fo = kmalloc(sizeof(struct file_obj), GFP_KERNEL);
  659. if (!fo) {
  660. /* pr_debug("DumChar: kmalloc file_obj fail!\n"); */
  661. return -ENOMEM;
  662. }
  663. filp->private_data = fo;
  664. for (i = 0; i < PART_NUM; i++) {
  665. if (!strcmp(filp->f_path.dentry->d_name.name, dumchar_devices[i].dumname)) {
  666. dev = &(dumchar_devices[i]);
  667. fo->index = i;
  668. found = 1;
  669. /* pr_debug( "DumChar: find dev %s index=%d\n",dumchar_devices[i].dumname,i); */
  670. break;
  671. }
  672. }
  673. if (found == 0) {
  674. pr_err(" DumChar:ERROR:No Such Dummy Device %s\n ",
  675. filp->f_path.dentry->d_name.name);
  676. return -EINVAL;
  677. }
  678. if (!strcmp(dev->dumname, "usrdata") || !strcmp(dev->dumname, "cache") ||
  679. !strcmp(dev->dumname, "android") || !strcmp(dev->dumname, "fat")) {
  680. pr_err("[dumchar_open] It is forbidded to access %s with dumchar(/dev/%s),the %s partition is managed by filesystem!\n",
  681. dev->dumname, dev->dumname, dev->dumname);
  682. pr_debug("[dumchar_open] show_stack*************************************\n");
  683. show_stack(NULL, NULL);
  684. fo->act_filp = (struct file *)0xffffffff;
  685. kfree(fo);
  686. return -EINVAL;
  687. }
  688. pr_debug("[dumchar_open][%s] will open %s for %s!\n", current->comm, dev->actname,
  689. filp->f_path.dentry->d_name.name);
  690. fo->act_filp = filp_open(dev->actname, filp->f_flags, 0777);
  691. if (IS_ERR(fo->act_filp)) {
  692. result = PTR_ERR(fo->act_filp);
  693. pr_err(" DumChar: [%s] open %s failed ( %s ). fo->act_filp=%p!, result=%d\n",
  694. current->comm, dev->actname, filp->f_path.dentry->d_name.name,
  695. fo->act_filp, result);
  696. pr_debug("[dumchar_open] show_stack*************************************\n");
  697. show_stack(NULL, NULL);
  698. /* pr_debug("[dumchar_open] BUG_ON*************************************\n"); */
  699. /* BUG_ON(1); */
  700. /* pr_debug("[dumchar_open] ************\n"); */
  701. goto open_fail2;
  702. } else {
  703. if (!(fo->act_filp->f_op)) {
  704. pr_err(" DumChar:open %s failed ( %s ). has no file operations registered!\n",
  705. dev->actname, filp->f_path.dentry->d_name.name);
  706. result = -EIO;
  707. goto open_fail1;
  708. }
  709. }
  710. return 0; /* success */
  711. open_fail1:
  712. filp_close(fo->act_filp, NULL);
  713. open_fail2:
  714. fo->act_filp = NULL;
  715. kfree(fo);
  716. return result;
  717. }
  718. int dumchar_release(struct inode *inode, struct file *filp)
  719. {
  720. struct file_obj *fo = filp->private_data;
  721. struct dumchar_dev *dev = &dumchar_devices[fo->index];
  722. if (!strcmp(dev->dumname, "usrdata") || !strcmp(dev->dumname, "cache") ||
  723. !strcmp(dev->dumname, "android") || !strcmp(dev->dumname, "fat")) {
  724. pr_warn("[dumchar_release] It is forbidded to access %s with dumchar(/dev/%s),the %s partition is managed by filesystem!\n",
  725. dev->dumname, dev->dumname, dev->dumname);
  726. } else {
  727. filp_close(fo->act_filp, NULL);
  728. }
  729. kfree(fo);
  730. return 0;
  731. }
  732. const struct file_operations dumchar_fops = {
  733. .owner = THIS_MODULE,
  734. .llseek = dumchar_llseek,
  735. .read = dumchar_read,
  736. .write = dumchar_write,
  737. .unlocked_ioctl = dumchar_ioctl,
  738. .open = dumchar_open,
  739. .release = dumchar_release,
  740. };
  741. int dumchar_probe(struct platform_device *dev)
  742. {
  743. int result, i, m, l;
  744. dev_t devno;
  745. #ifdef CONFIG_MTK_MTD_NAND
  746. struct mtd_info *mtd;
  747. #endif
  748. #ifdef CONFIG_MTK_EMMC_SUPPORT
  749. struct storage_info s_info = { 0 };
  750. pr_debug("[Dumchar_probe]*******************Introduction******************\n");
  751. pr_debug("[Dumchar_probe]There are 3 address in eMMC Project: Linear Address, Logical Address, Physical Address\n");
  752. pr_debug("[Dumchar_probe]Linear Address: Used in scatter file, uboot, preloader,flash tool etc.\n");
  753. pr_debug("[Dumchar_probe]Linear Address: MBR linear address is fixed in eMMCComo.mk, that is same for all chips in the project\n");
  754. pr_debug("[Dumchar_probe]Logical Address: Used in /proc/dumchar_info, mmcblk0 etc. MBR logical address is 0\n");
  755. pr_debug("[Dumchar_probe]Physical Address: Used in eMMC driver, MBR Physical Address = MBR Linear Address - (BOOT1 size + BOOT2 Size + RPMB Size)\n");
  756. pr_debug("[Dumchar_probe]define User_Region_Header (BOOT1 size + BOOT2 Size + RPMB Size)\n");
  757. pr_debug("[Dumchar_probe]*******************Introduction******************\n");
  758. init_pmt();
  759. #ifdef CONFIG_MTK_EMMC_CACHE
  760. msdc_get_cache_region();
  761. #endif
  762. msdc_get_info(EMMC_CARD_BOOT, EMMC_USER_CAPACITY, &s_info);
  763. msdc_get_info(EMMC_CARD_BOOT, EMMC_RESERVE, &s_info);
  764. #endif
  765. dumchar_devices = kcalloc(PART_NUM, sizeof(struct dumchar_dev), GFP_KERNEL);
  766. if (!dumchar_devices) {
  767. result = -ENOMEM;
  768. pr_err("DumChar: malloc dumchar_dev fail\n");
  769. goto fail_malloc;
  770. }
  771. result = alloc_chrdev_region(&devno, 0, PART_NUM, "DumChar");
  772. if (result < 0) {
  773. pr_err("DumChar: Get chrdev region fail\n");
  774. goto fail_alloc_chrdev_region;
  775. }
  776. major = MAJOR(devno);
  777. for (i = 0; i < PART_NUM; i++) {
  778. dumchar_devices[i].dumname = PartInfo[i].name;
  779. sema_init(&(dumchar_devices[i].sem), 1);
  780. devno = MKDEV(major, i);
  781. cdev_init(&dumchar_devices[i].cdev, &dumchar_fops);
  782. dumchar_devices[i].cdev.owner = THIS_MODULE;
  783. dumchar_devices[i].cdev.ops = &dumchar_fops;
  784. result = cdev_add(&dumchar_devices[i].cdev, devno, 1);
  785. if (result) {
  786. pr_err("DumChar: register char device dumchar fail!\n");
  787. goto fail_register_chrdev;
  788. }
  789. dumchar_devices[i].type = PartInfo[i].type;
  790. if (dumchar_devices[i].type == EMMC) {
  791. #ifdef CONFIG_MTK_EMMC_SUPPORT
  792. dumchar_devices[i].region = PartInfo[i].region;
  793. switch (dumchar_devices[i].region) {
  794. case EMMC_PART_BOOT1:
  795. sprintf(dumchar_devices[i].actname, MSDC_RAW_DEVICE);
  796. dumchar_devices[i].start_address = PartInfo[i].start_address;
  797. break;
  798. case EMMC_PART_USER:
  799. sprintf(dumchar_devices[i].actname, "/dev/block/mmcblk0");
  800. #ifdef CONFIG_MTK_NEW_COMBO_EMMC_SUPPORT
  801. dumchar_devices[i].start_address = PartInfo[i].start_address;
  802. #else
  803. dumchar_devices[i].start_address = PartInfo[i].start_address - MBR_START_ADDRESS_BYTE;
  804. #endif
  805. break;
  806. default:
  807. pr_err("Error! the emmc region is not supportted!\n");
  808. goto fail_register_chrdev;
  809. }
  810. dumchar_devices[i].size = PartInfo[i].size;
  811. if (!strcmp(PartInfo[i].name, "fat")) {
  812. dumchar_devices[i].size = s_info.emmc_user_capacity * 512 -
  813. dumchar_devices[i].start_address - s_info.emmc_reserve * 512;
  814. }
  815. #ifdef CONFIG_MTK_SHARED_SDCARD
  816. if (!strcmp(PartInfo[i].name, "usrdata")) {
  817. dumchar_devices[i].size = s_info.emmc_user_capacity * 512 -
  818. dumchar_devices[i].start_address - s_info.emmc_reserve * 512;
  819. }
  820. #endif
  821. pr_debug("[Dumchar] %s start address=%llx size=%llx\n",
  822. dumchar_devices[i].dumname, dumchar_devices[i].start_address,
  823. dumchar_devices[i].size);
  824. #endif
  825. } else {
  826. #ifdef CONFIG_MTK_MTD_NAND
  827. char *mtdname = dumchar_devices[i].dumname;
  828. if (!strcmp(dumchar_devices[i].dumname, "seccfg"))
  829. mtdname = "seccnfg";
  830. if (!strcmp(dumchar_devices[i].dumname, "bootimg"))
  831. mtdname = "boot";
  832. if (!strcmp(dumchar_devices[i].dumname, "sec_ro"))
  833. mtdname = "secstatic";
  834. if (!strcmp(dumchar_devices[i].dumname, "android"))
  835. mtdname = "system";
  836. if (!strcmp(dumchar_devices[i].dumname, "usrdata"))
  837. mtdname = "userdata";
  838. mtd_for_each_device(mtd) {
  839. if (!strcmp(mtd->name, mtdname)) {
  840. dumchar_devices[i].mtd_index = mtd->index;
  841. sprintf(dumchar_devices[i].actname, "/dev/mtd/mtd%d",
  842. mtd->index);
  843. dumchar_devices[i].size = mtd->size;
  844. dumchar_devices[i].start_address = mtd_partition_start_address(mtd);
  845. break;
  846. }
  847. }
  848. #endif
  849. }
  850. }
  851. dumchar_class = class_create(THIS_MODULE, "dumchar");
  852. if (IS_ERR(dumchar_class)) {
  853. pr_err("DumChar: fail in class create");
  854. result = PTR_ERR(dumchar_class);
  855. goto fail_register_chrdev;
  856. }
  857. for (l = 0; l < PART_NUM; l++) {
  858. if (!strcmp(dumchar_devices[l].dumname, "otp")) {
  859. dumchar_device[l] = device_create(dumchar_class, NULL, MKDEV(major, l), NULL, "otp_bak");
  860. } else {
  861. dumchar_device[l] = device_create(dumchar_class, NULL, MKDEV(major, l), NULL,
  862. dumchar_devices[l].dumname);
  863. }
  864. if (IS_ERR(dumchar_device[l])) {
  865. result = PTR_ERR(dumchar_device[l]);
  866. pr_err("DumChar: fail in device_create name = %s minor = %d\n",
  867. dumchar_devices[l].dumname, l);
  868. goto fail_create_device;
  869. }
  870. }
  871. #ifdef CONFIG_MTK_EMMC_SUPPORT
  872. emmc_create_symlink();
  873. #endif
  874. #ifdef CONFIG_MTK_MTD_NAND
  875. mtd_create_symlink();
  876. #endif
  877. return 0;
  878. fail_create_device:
  879. for (m = 0; m < l; m++)
  880. device_destroy(dumchar_class, MKDEV(major, m));
  881. class_destroy(dumchar_class);
  882. fail_register_chrdev:
  883. for (m = 0; m < i; m++)
  884. cdev_del(&dumchar_devices[m].cdev);
  885. unregister_chrdev_region(MKDEV(major, 0), PART_NUM);
  886. fail_alloc_chrdev_region:
  887. kfree(dumchar_devices);
  888. fail_malloc:
  889. return result;
  890. }
  891. int dumchar_remove(struct platform_device *dev)
  892. {
  893. int i;
  894. pr_debug("DumCharDebug: in dumchar_remove\n");
  895. for (i = 0; i < PART_NUM; i++) {
  896. device_destroy(dumchar_class, MKDEV(major, i));
  897. cdev_del(&dumchar_devices[i].cdev);
  898. }
  899. class_destroy(dumchar_class);
  900. unregister_chrdev_region(MKDEV(major, 0), PART_NUM);
  901. return 0;
  902. }
  903. #ifdef CONFIG_OF
  904. static const struct of_device_id dummy_char_of_ids[] = {
  905. {.compatible = "mediatek,mt8163-dummy_char",},
  906. {}
  907. };
  908. #endif
  909. static struct platform_driver dumchar_driver = {
  910. .probe = dumchar_probe,
  911. .remove = dumchar_remove,
  912. .driver = {
  913. .name = "dummy_char",
  914. .owner = THIS_MODULE,
  915. #ifdef CONFIG_OF
  916. .of_match_table = dummy_char_of_ids,
  917. #endif
  918. },
  919. };
  920. #ifndef CONFIG_MTK_NEW_COMBO_EMMC_SUPPORT
  921. static int dumchar_proc_show(struct seq_file *m, void *v)
  922. {
  923. int i;
  924. seq_puts(m, "Part_Name\tSize\tStartAddr\tType\tMapTo\n");
  925. for (i = 0; i < PART_NUM; i++) {
  926. if (dumchar_devices[i].type == NAND) {
  927. seq_printf(m, "%-10s 0x%016llx 0x%016llx 1 %s\n",
  928. dumchar_devices[i].dumname,
  929. dumchar_devices[i].size, dumchar_devices[i].start_address,
  930. /* "NAND", */
  931. dumchar_devices[i].actname);
  932. } else {
  933. if (PartInfo[i].partition_idx == 0) {
  934. seq_printf(m, "%-10s 0x%016llx 0x%016llx 2 %s\n",
  935. dumchar_devices[i].dumname,
  936. dumchar_devices[i].size,
  937. dumchar_devices[i].start_address,
  938. /*"EMMC", */
  939. dumchar_devices[i].actname);
  940. } else {
  941. seq_printf(m, "%-10s 0x%016llx 0x%016llx 2 /dev/block/mmcblk0p%d\n",
  942. dumchar_devices[i].dumname, dumchar_devices[i].size,
  943. dumchar_devices[i].start_address,
  944. /* "EMMC", */
  945. PartInfo[i].partition_idx);
  946. }
  947. }
  948. }
  949. if (dumchar_devices[i].type == NAND) {
  950. seq_printf(m,
  951. "Part_Name:Partition name you should open;\nSize:size of partition\nStartAddr:Index (MTD);\nType:Type of partition(MTD=1,EMMC=2);\nMapTo:actual device you operate\n");
  952. } else {
  953. seq_printf(m,
  954. "Part_Name:Partition name you should open;\nSize:size of partition\nStartAddr:Start Address of partition;\nType:Type of partition(MTD=1,EMMC=2)\nMapTo:actual device you operate\n");
  955. }
  956. return 0;
  957. }
  958. #else
  959. static int dumchar_proc_show(struct seq_file *m, void *v)
  960. {
  961. int i;
  962. char region[8];
  963. strcpy(region, "NAND");
  964. seq_puts(m, "Part_Name\tSize\tStartAddr\tType\tMapTo\tRegion\n");
  965. for (i = 0; i < PART_NUM; i++) {
  966. if (dumchar_devices[i].type == NAND) {
  967. seq_printf(m, "%-10s 0x%016llx 0x%016llx 1 %s\n",
  968. dumchar_devices[i].dumname,
  969. dumchar_devices[i].size, dumchar_devices[i].start_address,
  970. /* "NAND", */
  971. dumchar_devices[i].actname);
  972. } else {
  973. switch (dumchar_devices[i].region) {
  974. case EMMC_PART_BOOT1:
  975. strcpy(region, "BOOT_1");
  976. break;
  977. case EMMC_PART_BOOT2:
  978. strcpy(region, "BOOT_2");
  979. break;
  980. case EMMC_PART_RPMB:
  981. strcpy(region, "RPMB");
  982. break;
  983. case EMMC_PART_GP1:
  984. strcpy(region, "GP_1");
  985. break;
  986. case EMMC_PART_GP2:
  987. strcpy(region, "GP_2");
  988. break;
  989. case EMMC_PART_GP3:
  990. strcpy(region, "GP_3");
  991. break;
  992. case EMMC_PART_GP4:
  993. strcpy(region, "GP_4");
  994. break;
  995. case EMMC_PART_USER:
  996. strcpy(region, "USER");
  997. break;
  998. default:
  999. strcpy(region, "ERROR");
  1000. pr_err("ERROR, No such emmc region\n");
  1001. break;
  1002. }
  1003. if (PartInfo[i].partition_idx == 0) {
  1004. seq_printf(m, "%-10s 0x%016llx 0x%016llx 2 %s %s\n",
  1005. dumchar_devices[i].dumname,
  1006. dumchar_devices[i].size,
  1007. dumchar_devices[i].start_address,
  1008. /*"EMMC", */
  1009. dumchar_devices[i].actname, region);
  1010. } else {
  1011. seq_printf(m, "%-10s 0x%016llx 0x%016llx 2 /dev/block/mmcblk0p%d %s\n",
  1012. dumchar_devices[i].dumname, dumchar_devices[i].size,
  1013. dumchar_devices[i].start_address,
  1014. /* "EMMC", */
  1015. PartInfo[i].partition_idx, region);
  1016. }
  1017. }
  1018. }
  1019. if (dumchar_devices[i].type == NAND) {
  1020. seq_printf(m,
  1021. "Part_Name:Partition name you should open;\nSize:size of partition\nStartAddr:Index (MTD);\nType:Type of partition(MTD=1,EMMC=2);\nMapTo:actual device you operate\n");
  1022. } else {
  1023. seq_printf(m,
  1024. "Part_Name:Partition name you should open;\nSize:size of partition\nStartAddr:Start Address of partition;\nType:Type of partition(MTD=1,EMMC=2)\nMapTo:actual device you operate\n");
  1025. }
  1026. return 0;
  1027. }
  1028. #endif
  1029. static int dumchar_proc_open(struct inode *inode, struct file *file)
  1030. {
  1031. return single_open(file, dumchar_proc_show, NULL);
  1032. }
  1033. static const struct file_operations dumchar_proc_ops = {
  1034. .open = dumchar_proc_open,
  1035. .read = seq_read,
  1036. .llseek = seq_lseek,
  1037. .release = single_release,
  1038. };
  1039. static int __init dumchar_init(void)
  1040. {
  1041. int result;
  1042. struct proc_dir_entry *dumchar_proc_entry = NULL;
  1043. pr_debug("dumchar_int\n");
  1044. dumchar_proc_entry = proc_create("dumchar_info", S_IFREG | S_IRUGO, NULL, &dumchar_proc_ops);
  1045. if (dumchar_proc_entry) {
  1046. pr_debug("dumchar: register /proc/dumchar_info success\n");
  1047. } else {
  1048. pr_err("dumchar: unable to register /proc/dumchar_info\n");
  1049. result = -ENOMEM;
  1050. goto fail_create_proc;
  1051. }
  1052. result = platform_driver_register(&dumchar_driver);
  1053. if (result) {
  1054. pr_err("DUMCHAR: Can't register driver\n");
  1055. goto fail_driver_register;
  1056. }
  1057. pr_debug("DumChar: init USIF Done!\n");
  1058. return 0;
  1059. fail_driver_register:
  1060. remove_proc_entry("dumchar_info", NULL);
  1061. fail_create_proc:
  1062. return result;
  1063. }
  1064. static void __exit dumchar_cleanup(void)
  1065. {
  1066. remove_proc_entry("dumchar_info", NULL);
  1067. platform_driver_unregister(&dumchar_driver);
  1068. kfree(dumchar_devices);
  1069. }
  1070. /* module_init(dumchar_init); */
  1071. late_initcall(dumchar_init);
  1072. module_exit(dumchar_cleanup);
  1073. MODULE_LICENSE("GPL");
  1074. MODULE_DESCRIPTION("MediaTek Dummy Char Device Driver");
  1075. MODULE_AUTHOR("Kai Zhu <kai.zhu@mediatek.com>");