ccci_mk_node.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. #include <linux/module.h>
  2. #include <linux/device.h>
  3. #include <linux/fs.h>
  4. #include <linux/cdev.h>
  5. #include <linux/interrupt.h>
  6. #include <linux/spinlock.h>
  7. #include <linux/uaccess.h>
  8. #include <linux/mm.h>
  9. #include <linux/kfifo.h>
  10. #include <linux/firmware.h>
  11. #include <linux/syscalls.h>
  12. #include <linux/uaccess.h>
  13. #include <linux/platform_device.h>
  14. #include <linux/proc_fs.h>
  15. #include <ccci.h>
  16. struct ccci_node_t {
  17. char *name;
  18. char *type;
  19. int idx;
  20. int ext_num;
  21. };
  22. struct ccci_node_type_t {
  23. char *type;
  24. int major;
  25. int minor_start;
  26. int range;
  27. };
  28. struct ccci_node_type_table_t {
  29. int major;
  30. struct ccci_node_type_t array[CCCI_NODE_TYPE_NUM];
  31. };
  32. static struct ccci_node_t ccci1_node_list[] = {
  33. /* {"ccci_sys_rx", "std chr", 2, 0}, */
  34. /* {"ccci_sys_tx", "std chr", 3, 0}, */
  35. {"ccci_pcm_rx", "std chr", 4, 0},
  36. {"ccci_pcm_tx", "std chr", 5, 0},
  37. {"ccci_uem_rx", "std chr", 18, 0},
  38. {"ccci_uem_tx", "std chr", 19, 0},
  39. {"ccci_md_log_rx", "std chr", 42, 0},
  40. {"ccci_md_log_tx", "std chr", 43, 0},
  41. #ifdef CONFIG_MTK_ICUSB_SUPPORT
  42. {"ttyC", "tty", 0, 4},
  43. #else
  44. {"ttyC", "tty", 0, 3},
  45. #endif
  46. {"ccci_ipc_1220_0", "ipc", 0, 0}, /* used by AGPS */
  47. {"ccci_ipc_2", "ipc", 2, 0}, /* used by GPS */
  48. {"ccci_fs", "fs", 0, 0},
  49. #if defined(CONFIG_MTK_TC1_FEATURE)
  50. {"ccci_rpc", "rpc", 0, 0},
  51. #endif
  52. {"ccci_monitor", "vir chr", 0, 0},
  53. {"ccci_ioctl", "vir chr", 1, 5},
  54. };
  55. static struct ccci_node_t ccci2_node_list[] = {
  56. /* {"ccci2_sys_rx", "std chr", 2, 0}, */
  57. /* {"ccci2_sys_tx", "std chr", 3, 0}, */
  58. {"ccci2_pcm_rx", "std chr", 4, 0},
  59. {"ccci2_pcm_tx", "std chr", 5, 0},
  60. {"ccci2_uem_rx", "std chr", 18, 0},
  61. {"ccci2_uem_tx", "std chr", 19, 0},
  62. {"ccci2_md_log_rx", "std chr", 42, 0},
  63. {"ccci2_md_log_tx", "std chr", 43, 0},
  64. #ifdef CONFIG_MTK_ICUSB_SUPPORT
  65. {"ccci2_tty", "tty", 0, 4},
  66. #else
  67. {"ccci2_tty", "tty", 0, 3},
  68. #endif
  69. {"ccci2_ipc_", "ipc", 0, 1},
  70. {"ccci2_fs", "fs", 0, 0},
  71. #if defined(CONFIG_MTK_TC1_FEATURE)
  72. {"ccci2_rpc", "rpc", 0, 0},
  73. #endif
  74. {"ccci2_monitor", "vir chr", 0, 0},
  75. {"ccci2_ioctl", "vir chr", 1, 5},
  76. };
  77. static struct ccci_node_type_table_t ccci_node_type_table[MAX_MD_NUM];
  78. static void *dev_class;
  79. static void init_ccci_node_type_table(void)
  80. {
  81. int i;
  82. int curr = 0;
  83. int major;
  84. struct ccci_node_type_table_t *curr_table = NULL;
  85. memset(ccci_node_type_table, 0, sizeof(ccci_node_type_table));
  86. for (i = 0; i < MAX_MD_NUM; i++) {
  87. major = get_dev_major_for_md_sys(i);
  88. curr_table = &ccci_node_type_table[i];
  89. curr = 0;
  90. if (major < 0)
  91. continue;
  92. curr_table->major = major;
  93. curr_table->array[0].type = "std chr";
  94. curr_table->array[0].major = major;
  95. curr_table->array[0].minor_start = curr;
  96. curr_table->array[0].range = STD_CHR_DEV_NUM;
  97. curr += STD_CHR_DEV_NUM;
  98. curr_table->array[1].type = "ipc";
  99. curr_table->array[1].major = major;
  100. curr_table->array[1].minor_start = curr;
  101. curr_table->array[1].range = IPC_DEV_NUM;
  102. curr += IPC_DEV_NUM;
  103. curr_table->array[2].type = "fs";
  104. curr_table->array[2].major = major;
  105. curr_table->array[2].minor_start = curr;
  106. curr_table->array[2].range = FS_DEV_NUM;
  107. curr += FS_DEV_NUM;
  108. curr_table->array[3].type = "vir chr";
  109. curr_table->array[3].major = major;
  110. curr_table->array[3].minor_start = curr;
  111. curr_table->array[3].range = VIR_CHR_DEV_NUM;
  112. curr += VIR_CHR_DEV_NUM;
  113. curr_table->array[4].type = "tty";
  114. curr_table->array[4].major = major;
  115. curr_table->array[4].minor_start = curr;
  116. curr_table->array[4].range = TTY_DEV_NUM;
  117. curr += TTY_DEV_NUM;
  118. #if defined(CONFIG_MTK_TC1_FEATURE)
  119. curr_table->array[5].type = "rpc";
  120. curr_table->array[5].major = major;
  121. curr_table->array[5].minor_start = curr;
  122. curr_table->array[5].range = RPC_DEV_NUM;
  123. curr += RPC_DEV_NUM;
  124. #endif
  125. }
  126. }
  127. int get_md_id_by_dev_major(int dev_major)
  128. {
  129. int i;
  130. for (i = 0; i < MAX_MD_NUM; i++) {
  131. if (ccci_node_type_table[i].major == dev_major)
  132. return i;
  133. }
  134. return -1;
  135. }
  136. int get_dev_id_by_md_id(int md_id, char node_name[], int *major, int *minor)
  137. {
  138. int i;
  139. struct ccci_node_type_table_t *curr_table = NULL;
  140. curr_table = &ccci_node_type_table[md_id];
  141. for (i = 0; i < CCCI_NODE_TYPE_NUM; i++) {
  142. if (curr_table->array[i].type == NULL)
  143. break;
  144. if (strcmp(curr_table->array[i].type, node_name) == 0) {
  145. if (major != NULL)
  146. *major = curr_table->array[i].major;
  147. if (minor != NULL)
  148. *minor = curr_table->array[i].minor_start;
  149. return 0;
  150. }
  151. }
  152. return -1;
  153. }
  154. /***************************************************************************
  155. * Make device node helper function section
  156. ***************************************************************************/
  157. static void *create_dev_class(struct module *owner, const char *name)
  158. {
  159. int err = 0;
  160. struct class *dev_class = class_create(owner, name);
  161. if (IS_ERR(dev_class)) {
  162. err = PTR_ERR(dev_class);
  163. CCCI_MSG("create %s class fail: %d\n", name, err);
  164. return NULL;
  165. }
  166. return dev_class;
  167. }
  168. static int register_dev_node(void *dev_class, const char *name, int major_id,
  169. int minor_start_id, int index)
  170. {
  171. int ret = 0;
  172. dev_t dev;
  173. struct device *devices;
  174. if (index >= 0) {
  175. dev = MKDEV(major_id, minor_start_id) + index;
  176. devices =
  177. device_create((struct class *)dev_class, NULL, dev, NULL,
  178. "%s%d", name, index);
  179. } else {
  180. dev = MKDEV(major_id, minor_start_id);
  181. devices =
  182. device_create((struct class *)dev_class, NULL, dev, NULL,
  183. "%s", name);
  184. }
  185. if (IS_ERR(devices))
  186. ret = PTR_ERR(devices);
  187. return ret;
  188. }
  189. static void release_dev_node(void *dev_class, int major_id, int minor_start_id,
  190. int index)
  191. {
  192. dev_t dev;
  193. if (index >= 0) {
  194. dev = MKDEV(major_id, minor_start_id) + index;
  195. device_destroy((struct class *)dev_class, dev);
  196. } else {
  197. dev = MKDEV(major_id, minor_start_id);
  198. device_destroy((struct class *)dev_class, dev);
  199. }
  200. }
  201. /* ccci sysfs kobject */
  202. struct ccci_info_t {
  203. struct kobject kobj;
  204. unsigned int ccci_attr_count;
  205. };
  206. struct ccci_attribute_t {
  207. struct attribute attr;
  208. ssize_t (*show)(char *buf);
  209. ssize_t (*store)(const char *buf, size_t count);
  210. };
  211. #define CCCI_ATTR(_name, _mode, _show, _store)\
  212. struct ccci_attribute_t ccci_attr_##_name = {\
  213. .attr = { .name = __stringify(_name), .mode = _mode },\
  214. .show = _show,\
  215. .store = _store,\
  216. }
  217. ssize_t show_attr_version(char *buf)
  218. {
  219. return snprintf(buf, 16, "%d\n", 2); /* hardcode */
  220. }
  221. /* global vars */
  222. static struct ccci_info_t *ccci_sys_info;
  223. const struct sysfs_ops ccci_sysfs_ops = {
  224. .show = ccci_attr_show,
  225. .store = ccci_attr_store
  226. };
  227. CCCI_ATTR(boot, 0660, NULL, NULL);
  228. CCCI_ATTR(modem_info, 0644, NULL, NULL);
  229. CCCI_ATTR(md1_postfix, 0644, show_attr_md1_postfix, NULL);
  230. CCCI_ATTR(md2_postfix, 0644, show_attr_md2_postfix, NULL);
  231. CCCI_ATTR(version, 0644, show_attr_version, NULL);
  232. struct attribute *ccci_default_attrs[] = {
  233. &ccci_attr_boot.attr,
  234. &ccci_attr_modem_info.attr,
  235. &ccci_attr_md1_postfix.attr,
  236. &ccci_attr_md2_postfix.attr,
  237. &ccci_attr_version.attr,
  238. NULL
  239. };
  240. struct kobj_type ccci_ktype = {
  241. .release = ccci_attr_release,
  242. .sysfs_ops = &ccci_sysfs_ops,
  243. .default_attrs = ccci_default_attrs
  244. };
  245. /* common func implement */
  246. ssize_t ccci_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
  247. {
  248. ssize_t len = 0;
  249. struct ccci_attribute_t *a = container_of(attr, struct ccci_attribute_t, attr);
  250. if (a->show)
  251. len = a->show(buf);
  252. return len;
  253. }
  254. ssize_t ccci_attr_store(struct kobject *kobj, struct attribute *attr,
  255. const char *buf, size_t count)
  256. {
  257. ssize_t len = 0;
  258. struct ccci_attribute_t *a = container_of(attr, struct ccci_attribute_t, attr);
  259. if (a->store)
  260. len = a->store(buf, count);
  261. return len;
  262. }
  263. void ccci_attr_release(struct kobject *kobj)
  264. {
  265. struct ccci_info_t *ccci_info_temp = container_of(kobj, struct ccci_info_t, kobj);
  266. kfree(ccci_info_temp);
  267. ccci_sys_info = NULL;
  268. }
  269. ssize_t show_attr_md1_postfix(char *buf)
  270. {
  271. get_md_post_fix(MD_SYS1, buf, NULL);
  272. CCCI_MSG("md1: %s\n", buf);
  273. return strlen(buf);
  274. }
  275. ssize_t show_attr_md2_postfix(char *buf)
  276. {
  277. get_md_post_fix(MD_SYS2, buf, NULL);
  278. CCCI_MSG("md2: %s\n", buf);
  279. return strlen(buf);
  280. }
  281. int register_ccci_attr_func(const char *buf, ssize_t (*show) (char *),
  282. ssize_t (*store)(const char *, size_t))
  283. {
  284. int i = 0;
  285. struct ccci_attribute_t *ccci_attr_temp = NULL;
  286. while (ccci_default_attrs[i]) {
  287. if (!strncmp
  288. (ccci_default_attrs[i]->name, buf,
  289. strlen(ccci_default_attrs[i]->name))) {
  290. ccci_attr_temp =
  291. container_of(ccci_default_attrs[i],
  292. struct ccci_attribute_t, attr);
  293. break;
  294. }
  295. i++;
  296. }
  297. if (ccci_attr_temp) {
  298. ccci_attr_temp->show = show;
  299. ccci_attr_temp->store = store;
  300. return 0;
  301. }
  302. CCCI_MSG("fail to register ccci attibute!\n");
  303. return -1;
  304. }
  305. #define CCCI_KOBJ_NAME "ccci"
  306. int ccci_attr_install(void)
  307. {
  308. int ret = 0;
  309. ccci_sys_info = kmalloc(sizeof(struct ccci_info_t), GFP_KERNEL);
  310. if (!ccci_sys_info)
  311. return -ENOMEM;
  312. memset(ccci_sys_info, 0, sizeof(struct ccci_info_t));
  313. ret = kobject_init_and_add(&ccci_sys_info->kobj, &ccci_ktype,
  314. (struct kobject *)kernel_kobj, CCCI_KOBJ_NAME);
  315. if (ret < 0) {
  316. kobject_put(&ccci_sys_info->kobj);
  317. CCCI_MSG("fail to add ccci kobject in kernel\n");
  318. return ret;
  319. }
  320. ccci_sys_info->ccci_attr_count =
  321. sizeof(*ccci_default_attrs) / sizeof(struct attribute);
  322. return ret;
  323. }
  324. int init_ccci_dev_node(void)
  325. {
  326. int ret = 0;
  327. init_ccci_node_type_table();
  328. /* Make device class */
  329. dev_class = create_dev_class(THIS_MODULE, "ccci_node");
  330. if (dev_class == NULL)
  331. return -1;
  332. ret = ccci_attr_install();
  333. return ret;
  334. }
  335. void release_ccci_dev_node(void)
  336. {
  337. if (dev_class)
  338. class_destroy((struct class *)dev_class);
  339. if (ccci_sys_info) {
  340. if (&ccci_sys_info->kobj)
  341. kobject_put(&ccci_sys_info->kobj);
  342. kfree(ccci_sys_info);
  343. ccci_sys_info = NULL;
  344. }
  345. }
  346. int mk_ccci_dev_node(int md_id)
  347. {
  348. int i, j, major, minor, num;
  349. struct ccci_node_t *dev_node;
  350. int ret = 0;
  351. if (md_id == MD_SYS1) {
  352. dev_node = ccci1_node_list;
  353. num = sizeof(ccci1_node_list) / sizeof(struct ccci_node_t);
  354. } else if (md_id == MD_SYS2) {
  355. dev_node = ccci2_node_list;
  356. num = sizeof(ccci2_node_list) / sizeof(struct ccci_node_t);
  357. } else {
  358. return -1;
  359. }
  360. for (i = 0; i < num; i++) {
  361. if (get_dev_id_by_md_id(md_id, dev_node[i].type, &major, &minor)
  362. < 0)
  363. break;
  364. minor = minor + dev_node[i].idx;
  365. if (dev_node[i].ext_num == 0) {
  366. ret =
  367. register_dev_node(dev_class, dev_node[i].name,
  368. major, minor, -1);
  369. if (ret < 0)
  370. CCCI_MSG_INF(md_id, "cci",
  371. "create %s device fail: %d\n",
  372. dev_node[i].name, ret);
  373. } else {
  374. for (j = 0; j < dev_node[i].ext_num; j++) {
  375. ret =
  376. register_dev_node(dev_class,
  377. dev_node[i].name, major,
  378. minor, j);
  379. if (ret < 0) {
  380. CCCI_MSG_INF(md_id, "cci",
  381. "create %s device fail: %d\n",
  382. dev_node[i].name, ret);
  383. return ret;
  384. }
  385. }
  386. }
  387. }
  388. return ret;
  389. }
  390. void ccci_dev_node_exit(int md_id)
  391. {
  392. int i, j, major, minor, num;
  393. struct ccci_node_t *dev_node;
  394. if (md_id == MD_SYS1) {
  395. dev_node = ccci1_node_list;
  396. num = sizeof(ccci1_node_list) / sizeof(struct ccci_node_t);
  397. } else if (md_id == MD_SYS2) {
  398. dev_node = ccci2_node_list;
  399. num = sizeof(ccci2_node_list) / sizeof(struct ccci_node_t);
  400. } else {
  401. return;
  402. }
  403. for (i = 0; i < num; i++) {
  404. if (get_dev_id_by_md_id(md_id, dev_node[i].type, &major, &minor)
  405. < 0)
  406. break;
  407. minor = minor + dev_node[i].idx;
  408. if (dev_node[i].ext_num == 0) {
  409. release_dev_node(dev_class, major, minor, -1);
  410. } else {
  411. for (j = 0; j < dev_node[i].ext_num; j++)
  412. release_dev_node(dev_class, major, minor, j);
  413. }
  414. }
  415. }