synaptics_tcm_device.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  1. /*
  2. * Synaptics TCM touchscreen driver
  3. *
  4. * Copyright (C) 2017-2019 Synaptics Incorporated. All rights reserved.
  5. *
  6. * Copyright (C) 2017-2019 Scott Lin <[email protected]>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
  19. * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
  20. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
  21. * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
  22. * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
  24. * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
  25. * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  26. * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
  27. * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
  28. * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
  29. * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
  30. * DOLLARS.
  31. */
  32. #include <linux/cdev.h>
  33. #include <linux/gpio.h>
  34. #include <linux/uaccess.h>
  35. #include "synaptics_tcm_core.h"
  36. #define CHAR_DEVICE_NAME "tcm"
  37. #define CONCURRENT true
  38. #define DEVICE_IOC_MAGIC 's'
  39. #define DEVICE_IOC_RESET _IO(DEVICE_IOC_MAGIC, 0) /* 0x00007300 */
  40. #define DEVICE_IOC_IRQ _IOW(DEVICE_IOC_MAGIC, 1, int) /* 0x40047301 */
  41. #define DEVICE_IOC_RAW _IOW(DEVICE_IOC_MAGIC, 2, int) /* 0x40047302 */
  42. #define DEVICE_IOC_CONCURRENT _IOW(DEVICE_IOC_MAGIC, 3, int) /* 0x40047303 */
  43. struct device_hcd {
  44. dev_t dev_num;
  45. bool raw_mode;
  46. bool concurrent;
  47. unsigned int ref_count;
  48. struct cdev char_dev;
  49. struct class *class;
  50. struct device *device;
  51. struct syna_tcm_buffer out;
  52. struct syna_tcm_buffer resp;
  53. struct syna_tcm_buffer report;
  54. struct syna_tcm_hcd *tcm_hcd;
  55. };
  56. DECLARE_COMPLETION(device_remove_complete);
  57. static struct device_hcd *device_hcd;
  58. static int rmidev_major_num;
  59. static void device_capture_touch_report(unsigned int count)
  60. {
  61. int retval;
  62. unsigned char id;
  63. unsigned int idx;
  64. unsigned int size;
  65. unsigned char *data;
  66. struct syna_tcm_hcd *tcm_hcd = device_hcd->tcm_hcd;
  67. static bool report;
  68. static unsigned int offset;
  69. static unsigned int remaining_size;
  70. if (count < 2)
  71. return;
  72. data = &device_hcd->resp.buf[0];
  73. if (data[0] != MESSAGE_MARKER)
  74. return;
  75. id = data[1];
  76. size = 0;
  77. LOCK_BUFFER(device_hcd->report);
  78. switch (id) {
  79. case REPORT_TOUCH:
  80. if (count >= 4) {
  81. remaining_size = le2_to_uint(&data[2]);
  82. } else {
  83. report = false;
  84. goto exit;
  85. }
  86. retval = syna_tcm_alloc_mem(tcm_hcd,
  87. &device_hcd->report,
  88. remaining_size);
  89. if (retval < 0) {
  90. LOGE(tcm_hcd->pdev->dev.parent,
  91. "Failed to allocate memory for report.buf\n");
  92. report = false;
  93. goto exit;
  94. }
  95. idx = 4;
  96. size = count - idx;
  97. offset = 0;
  98. report = true;
  99. break;
  100. case STATUS_CONTINUED_READ:
  101. if (report == false)
  102. goto exit;
  103. if (count >= 2) {
  104. idx = 2;
  105. size = count - idx;
  106. }
  107. break;
  108. default:
  109. goto exit;
  110. }
  111. if (size) {
  112. size = MIN(size, remaining_size);
  113. retval = secure_memcpy(&device_hcd->report.buf[offset],
  114. device_hcd->report.buf_size - offset,
  115. &data[idx],
  116. count - idx,
  117. size);
  118. if (retval < 0) {
  119. LOGE(tcm_hcd->pdev->dev.parent,
  120. "Failed to copy touch report data\n");
  121. report = false;
  122. goto exit;
  123. } else {
  124. offset += size;
  125. remaining_size -= size;
  126. device_hcd->report.data_length += size;
  127. }
  128. }
  129. if (remaining_size)
  130. goto exit;
  131. LOCK_BUFFER(tcm_hcd->report.buffer);
  132. tcm_hcd->report.buffer.buf = device_hcd->report.buf;
  133. tcm_hcd->report.buffer.buf_size = device_hcd->report.buf_size;
  134. tcm_hcd->report.buffer.data_length = device_hcd->report.data_length;
  135. tcm_hcd->report_touch();
  136. UNLOCK_BUFFER(tcm_hcd->report.buffer);
  137. report = false;
  138. exit:
  139. UNLOCK_BUFFER(device_hcd->report);
  140. }
  141. static int device_capture_touch_report_config(unsigned int count)
  142. {
  143. int retval;
  144. unsigned int size;
  145. unsigned int buf_size;
  146. unsigned char *data;
  147. struct syna_tcm_hcd *tcm_hcd = device_hcd->tcm_hcd;
  148. if (device_hcd->raw_mode) {
  149. if (count < 3) {
  150. LOGE(tcm_hcd->pdev->dev.parent,
  151. "Invalid write data\n");
  152. return -EINVAL;
  153. }
  154. size = le2_to_uint(&device_hcd->out.buf[1]);
  155. if (count - 3 < size) {
  156. LOGE(tcm_hcd->pdev->dev.parent,
  157. "Incomplete write data\n");
  158. return -EINVAL;
  159. }
  160. if (!size)
  161. return 0;
  162. data = &device_hcd->out.buf[3];
  163. buf_size = device_hcd->out.buf_size - 3;
  164. } else {
  165. size = count - 1;
  166. if (!size)
  167. return 0;
  168. data = &device_hcd->out.buf[1];
  169. buf_size = device_hcd->out.buf_size - 1;
  170. }
  171. LOCK_BUFFER(tcm_hcd->config);
  172. retval = syna_tcm_alloc_mem(tcm_hcd,
  173. &tcm_hcd->config,
  174. size);
  175. if (retval < 0) {
  176. LOGE(tcm_hcd->pdev->dev.parent,
  177. "Failed to allocate memory for tcm_hcd->config.buf\n");
  178. UNLOCK_BUFFER(tcm_hcd->config);
  179. return retval;
  180. }
  181. retval = secure_memcpy(tcm_hcd->config.buf,
  182. tcm_hcd->config.buf_size,
  183. data,
  184. buf_size,
  185. size);
  186. if (retval < 0) {
  187. LOGE(tcm_hcd->pdev->dev.parent,
  188. "Failed to copy touch report config data\n");
  189. UNLOCK_BUFFER(tcm_hcd->config);
  190. return retval;
  191. }
  192. tcm_hcd->config.data_length = size;
  193. UNLOCK_BUFFER(tcm_hcd->config);
  194. return 0;
  195. }
  196. #ifdef HAVE_UNLOCKED_IOCTL
  197. static long device_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
  198. #else
  199. static int device_ioctl(struct inode *inp, struct file *filp, unsigned int cmd,
  200. unsigned long arg)
  201. #endif
  202. {
  203. int retval;
  204. struct syna_tcm_hcd *tcm_hcd = device_hcd->tcm_hcd;
  205. mutex_lock(&tcm_hcd->extif_mutex);
  206. retval = 0;
  207. switch (cmd) {
  208. case DEVICE_IOC_RESET:
  209. retval = tcm_hcd->reset(tcm_hcd, false, true);
  210. break;
  211. case DEVICE_IOC_IRQ:
  212. if (arg == 0)
  213. retval = tcm_hcd->enable_irq(tcm_hcd, false, false);
  214. else if (arg == 1)
  215. retval = tcm_hcd->enable_irq(tcm_hcd, true, NULL);
  216. break;
  217. case DEVICE_IOC_RAW:
  218. if (arg == 0) {
  219. device_hcd->raw_mode = false;
  220. tcm_hcd->update_watchdog(tcm_hcd, true);
  221. } else if (arg == 1) {
  222. device_hcd->raw_mode = true;
  223. tcm_hcd->update_watchdog(tcm_hcd, false);
  224. }
  225. break;
  226. case DEVICE_IOC_CONCURRENT:
  227. if (arg == 0)
  228. device_hcd->concurrent = false;
  229. else if (arg == 1)
  230. device_hcd->concurrent = true;
  231. break;
  232. default:
  233. retval = -ENOTTY;
  234. break;
  235. }
  236. mutex_unlock(&tcm_hcd->extif_mutex);
  237. return retval;
  238. }
  239. static loff_t device_llseek(struct file *filp, loff_t off, int whence)
  240. {
  241. return -EINVAL;
  242. }
  243. static ssize_t device_read(struct file *filp, char __user *buf,
  244. size_t count, loff_t *f_pos)
  245. {
  246. int retval;
  247. struct syna_tcm_hcd *tcm_hcd = device_hcd->tcm_hcd;
  248. if (count == 0)
  249. return 0;
  250. mutex_lock(&tcm_hcd->extif_mutex);
  251. LOCK_BUFFER(device_hcd->resp);
  252. if (device_hcd->raw_mode) {
  253. retval = syna_tcm_alloc_mem(tcm_hcd,
  254. &device_hcd->resp,
  255. count);
  256. if (retval < 0) {
  257. LOGE(tcm_hcd->pdev->dev.parent,
  258. "Failed to allocate memory for resp.buf\n");
  259. UNLOCK_BUFFER(device_hcd->resp);
  260. goto exit;
  261. }
  262. retval = tcm_hcd->read_message(tcm_hcd,
  263. device_hcd->resp.buf,
  264. count);
  265. if (retval < 0) {
  266. LOGE(tcm_hcd->pdev->dev.parent,
  267. "Failed to read message\n");
  268. UNLOCK_BUFFER(device_hcd->resp);
  269. goto exit;
  270. }
  271. } else {
  272. if (count != device_hcd->resp.data_length) {
  273. LOGE(tcm_hcd->pdev->dev.parent,
  274. "Invalid length information\n");
  275. UNLOCK_BUFFER(device_hcd->resp);
  276. retval = -EINVAL;
  277. goto exit;
  278. }
  279. }
  280. if (copy_to_user(buf, device_hcd->resp.buf, count)) {
  281. LOGE(tcm_hcd->pdev->dev.parent,
  282. "Failed to copy data to user space\n");
  283. UNLOCK_BUFFER(device_hcd->resp);
  284. retval = -EINVAL;
  285. goto exit;
  286. }
  287. if (!device_hcd->concurrent)
  288. goto skip_concurrent;
  289. if (tcm_hcd->report_touch == NULL) {
  290. LOGE(tcm_hcd->pdev->dev.parent,
  291. "Unable to report touch\n");
  292. device_hcd->concurrent = false;
  293. }
  294. if (device_hcd->raw_mode)
  295. device_capture_touch_report(count);
  296. skip_concurrent:
  297. UNLOCK_BUFFER(device_hcd->resp);
  298. retval = count;
  299. exit:
  300. mutex_unlock(&tcm_hcd->extif_mutex);
  301. return retval;
  302. }
  303. static ssize_t device_write(struct file *filp, const char __user *buf,
  304. size_t count, loff_t *f_pos)
  305. {
  306. int retval;
  307. struct syna_tcm_hcd *tcm_hcd = device_hcd->tcm_hcd;
  308. if (count == 0)
  309. return 0;
  310. mutex_lock(&tcm_hcd->extif_mutex);
  311. LOCK_BUFFER(device_hcd->out);
  312. retval = syna_tcm_alloc_mem(tcm_hcd,
  313. &device_hcd->out,
  314. count == 1 ? count + 1 : count);
  315. if (retval < 0) {
  316. LOGE(tcm_hcd->pdev->dev.parent,
  317. "Failed to allocate memory for device_hcd->out.buf\n");
  318. UNLOCK_BUFFER(device_hcd->out);
  319. goto exit;
  320. }
  321. if (copy_from_user(device_hcd->out.buf, buf, count)) {
  322. LOGE(tcm_hcd->pdev->dev.parent,
  323. "Failed to copy data from user space\n");
  324. UNLOCK_BUFFER(device_hcd->out);
  325. retval = -EINVAL;
  326. goto exit;
  327. }
  328. LOCK_BUFFER(device_hcd->resp);
  329. if (device_hcd->raw_mode) {
  330. retval = tcm_hcd->write_message(tcm_hcd,
  331. device_hcd->out.buf[0],
  332. &device_hcd->out.buf[1],
  333. count - 1,
  334. NULL,
  335. NULL,
  336. NULL,
  337. NULL,
  338. 0);
  339. } else {
  340. mutex_lock(&tcm_hcd->reset_mutex);
  341. retval = tcm_hcd->write_message(tcm_hcd,
  342. device_hcd->out.buf[0],
  343. &device_hcd->out.buf[1],
  344. count - 1,
  345. &device_hcd->resp.buf,
  346. &device_hcd->resp.buf_size,
  347. &device_hcd->resp.data_length,
  348. NULL,
  349. 0);
  350. mutex_unlock(&tcm_hcd->reset_mutex);
  351. }
  352. if (retval < 0) {
  353. LOGE(tcm_hcd->pdev->dev.parent,
  354. "Failed to write command 0x%02x\n",
  355. device_hcd->out.buf[0]);
  356. UNLOCK_BUFFER(device_hcd->resp);
  357. UNLOCK_BUFFER(device_hcd->out);
  358. goto exit;
  359. }
  360. if (count && device_hcd->out.buf[0] == CMD_SET_TOUCH_REPORT_CONFIG) {
  361. retval = device_capture_touch_report_config(count);
  362. if (retval < 0) {
  363. LOGE(tcm_hcd->pdev->dev.parent,
  364. "Failed to capture touch report config\n");
  365. }
  366. }
  367. UNLOCK_BUFFER(device_hcd->out);
  368. if (device_hcd->raw_mode)
  369. retval = count;
  370. else
  371. retval = device_hcd->resp.data_length;
  372. UNLOCK_BUFFER(device_hcd->resp);
  373. exit:
  374. mutex_unlock(&tcm_hcd->extif_mutex);
  375. return retval;
  376. }
  377. static int device_open(struct inode *inp, struct file *filp)
  378. {
  379. int retval;
  380. struct syna_tcm_hcd *tcm_hcd = device_hcd->tcm_hcd;
  381. mutex_lock(&tcm_hcd->extif_mutex);
  382. if (device_hcd->ref_count < 1) {
  383. device_hcd->ref_count++;
  384. retval = 0;
  385. } else {
  386. retval = -EACCES;
  387. }
  388. mutex_unlock(&tcm_hcd->extif_mutex);
  389. return retval;
  390. }
  391. static int device_release(struct inode *inp, struct file *filp)
  392. {
  393. struct syna_tcm_hcd *tcm_hcd = device_hcd->tcm_hcd;
  394. mutex_lock(&tcm_hcd->extif_mutex);
  395. if (device_hcd->ref_count)
  396. device_hcd->ref_count--;
  397. mutex_unlock(&tcm_hcd->extif_mutex);
  398. return 0;
  399. }
  400. static char *device_devnode(struct device *dev, umode_t *mode)
  401. {
  402. if (!mode)
  403. return NULL;
  404. /* S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; */
  405. *mode = 0666;
  406. return kasprintf(GFP_KERNEL, "%s/%s", PLATFORM_DRIVER_NAME,
  407. dev_name(dev));
  408. }
  409. static int device_create_class(void)
  410. {
  411. struct syna_tcm_hcd *tcm_hcd = device_hcd->tcm_hcd;
  412. if (device_hcd->class != NULL)
  413. return 0;
  414. device_hcd->class = class_create(THIS_MODULE, PLATFORM_DRIVER_NAME);
  415. if (IS_ERR(device_hcd->class)) {
  416. LOGE(tcm_hcd->pdev->dev.parent,
  417. "Failed to create class\n");
  418. return -ENODEV;
  419. }
  420. device_hcd->class->devnode = device_devnode;
  421. return 0;
  422. }
  423. static const struct file_operations device_fops = {
  424. .owner = THIS_MODULE,
  425. #ifdef HAVE_UNLOCKED_IOCTL
  426. .unlocked_ioctl = device_ioctl,
  427. #ifdef HAVE_COMPAT_IOCTL
  428. .compat_ioctl = device_ioctl,
  429. #endif
  430. #else
  431. .ioctl = device_ioctl,
  432. #endif
  433. .llseek = device_llseek,
  434. .read = device_read,
  435. .write = device_write,
  436. .open = device_open,
  437. .release = device_release,
  438. };
  439. static int device_init(struct syna_tcm_hcd *tcm_hcd)
  440. {
  441. int retval;
  442. dev_t dev_num;
  443. const struct syna_tcm_board_data *bdata = tcm_hcd->hw_if->bdata;
  444. device_hcd = kzalloc(sizeof(*device_hcd), GFP_KERNEL);
  445. if (!device_hcd) {
  446. LOGE(tcm_hcd->pdev->dev.parent,
  447. "Failed to allocate memory for device_hcd\n");
  448. return -ENOMEM;
  449. }
  450. device_hcd->tcm_hcd = tcm_hcd;
  451. device_hcd->concurrent = CONCURRENT;
  452. INIT_BUFFER(device_hcd->out, false);
  453. INIT_BUFFER(device_hcd->resp, false);
  454. INIT_BUFFER(device_hcd->report, false);
  455. if (rmidev_major_num) {
  456. dev_num = MKDEV(rmidev_major_num, 0);
  457. retval = register_chrdev_region(dev_num, 1,
  458. PLATFORM_DRIVER_NAME);
  459. if (retval < 0) {
  460. LOGE(tcm_hcd->pdev->dev.parent,
  461. "Failed to register char device\n");
  462. goto err_register_chrdev_region;
  463. }
  464. } else {
  465. retval = alloc_chrdev_region(&dev_num, 0, 1,
  466. PLATFORM_DRIVER_NAME);
  467. if (retval < 0) {
  468. LOGE(tcm_hcd->pdev->dev.parent,
  469. "Failed to allocate char device\n");
  470. goto err_alloc_chrdev_region;
  471. }
  472. rmidev_major_num = MAJOR(dev_num);
  473. }
  474. device_hcd->dev_num = dev_num;
  475. cdev_init(&device_hcd->char_dev, &device_fops);
  476. retval = cdev_add(&device_hcd->char_dev, dev_num, 1);
  477. if (retval < 0) {
  478. LOGE(tcm_hcd->pdev->dev.parent,
  479. "Failed to add char device\n");
  480. goto err_add_chardev;
  481. }
  482. retval = device_create_class();
  483. if (retval < 0) {
  484. LOGE(tcm_hcd->pdev->dev.parent,
  485. "Failed to create class\n");
  486. goto err_create_class;
  487. }
  488. device_hcd->device = device_create(device_hcd->class, NULL,
  489. device_hcd->dev_num, NULL, CHAR_DEVICE_NAME"%d",
  490. MINOR(device_hcd->dev_num));
  491. if (IS_ERR(device_hcd->device)) {
  492. LOGE(tcm_hcd->pdev->dev.parent,
  493. "Failed to create device\n");
  494. retval = -ENODEV;
  495. goto err_create_device;
  496. }
  497. if (bdata->irq_gpio >= 0) {
  498. retval = gpio_export(bdata->irq_gpio, false);
  499. if (retval < 0) {
  500. LOGE(tcm_hcd->pdev->dev.parent,
  501. "Failed to export GPIO\n");
  502. } else {
  503. retval = gpio_export_link(&tcm_hcd->pdev->dev,
  504. "attn", bdata->irq_gpio);
  505. if (retval < 0)
  506. LOGE(tcm_hcd->pdev->dev.parent,
  507. "Failed to export GPIO link\n");
  508. }
  509. }
  510. return 0;
  511. err_create_device:
  512. class_destroy(device_hcd->class);
  513. err_create_class:
  514. cdev_del(&device_hcd->char_dev);
  515. err_add_chardev:
  516. unregister_chrdev_region(dev_num, 1);
  517. err_alloc_chrdev_region:
  518. err_register_chrdev_region:
  519. RELEASE_BUFFER(device_hcd->report);
  520. RELEASE_BUFFER(device_hcd->resp);
  521. RELEASE_BUFFER(device_hcd->out);
  522. kfree(device_hcd);
  523. device_hcd = NULL;
  524. return retval;
  525. }
  526. static int device_remove(struct syna_tcm_hcd *tcm_hcd)
  527. {
  528. if (!device_hcd)
  529. goto exit;
  530. device_destroy(device_hcd->class, device_hcd->dev_num);
  531. class_destroy(device_hcd->class);
  532. cdev_del(&device_hcd->char_dev);
  533. unregister_chrdev_region(device_hcd->dev_num, 1);
  534. RELEASE_BUFFER(device_hcd->report);
  535. RELEASE_BUFFER(device_hcd->resp);
  536. RELEASE_BUFFER(device_hcd->out);
  537. kfree(device_hcd);
  538. device_hcd = NULL;
  539. exit:
  540. complete(&device_remove_complete);
  541. return 0;
  542. }
  543. static int device_reset(struct syna_tcm_hcd *tcm_hcd)
  544. {
  545. int retval;
  546. if (!device_hcd) {
  547. retval = device_init(tcm_hcd);
  548. return retval;
  549. }
  550. return 0;
  551. }
  552. static struct syna_tcm_module_cb device_module = {
  553. .type = TCM_DEVICE,
  554. .init = device_init,
  555. .remove = device_remove,
  556. .syncbox = NULL,
  557. .asyncbox = NULL,
  558. .reset = device_reset,
  559. .suspend = NULL,
  560. .resume = NULL,
  561. .early_suspend = NULL,
  562. };
  563. static int __init device_module_init(void)
  564. {
  565. return syna_tcm_add_module(&device_module, true);
  566. }
  567. static void __exit device_module_exit(void)
  568. {
  569. syna_tcm_add_module(&device_module, false);
  570. wait_for_completion(&device_remove_complete);
  571. }
  572. module_init(device_module_init);
  573. module_exit(device_module_exit);
  574. MODULE_AUTHOR("Synaptics, Inc.");
  575. MODULE_DESCRIPTION("Synaptics TCM Device Module");
  576. MODULE_LICENSE("GPL v2");