Guest User

Untitled

a guest
Mar 15th, 2018
60
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 17.07 KB | None | 0 0
  1. From 311e717d2d362cec4c38ea49710f83097a8519c4 Mon Sep 17 00:00:00 2001
  2. From: Pavan Savoy <pavan_savoy@ti.com>
  3. Date: Mon, 15 Oct 2012 17:47:35 -0500
  4. Subject: [PATCH] Bluetooth: Add tty HCI driver
  5.  
  6. tty_hci driver exposes a /dev/hci_tty character device node, that intends to
  7. emulate a generic /dev/ttyX device that would be used by the user-space
  8. Bluetooth stacks to send/receive data to/from the WL combo-connectivity
  9. chipsets.
  10.  
  11. The device driver has no internal logic of its own to intrepret data & all
  12. such logic is handled by the user-space stack.
  13.  
  14. Change-Id: Ifa3860bbc7e252af210fde710bce14143239b552
  15. Signed-off-by: Pavan Savoy <pavan_savoy@ti.com>
  16.  [Fixed checkpatch warnings]
  17. Signed-off-by: Vishal Mahaveer <vishalm@ti.com>
  18.  [Fixed checkpatch --strict warnings]
  19. Signed-off-by: Eyal Reizer <eyalr@ti.com>
  20. Signed-off-by: varigigi <pierluigi.p@variscite.com>
  21. ---
  22.  drivers/misc/ti-st/Kconfig   |   8 +
  23.  drivers/misc/ti-st/Makefile  |   1 +
  24.  drivers/misc/ti-st/tty_hci.c | 542 +++++++++++++++++++++++++++++++++++++++++++
  25.  3 files changed, 551 insertions(+)
  26.  create mode 100644 drivers/misc/ti-st/tty_hci.c
  27.  
  28. diff --git a/drivers/misc/ti-st/Kconfig b/drivers/misc/ti-st/Kconfig
  29. index f34dcc514730..f2df2c7352e2 100644
  30. --- a/drivers/misc/ti-st/Kconfig
  31. +++ b/drivers/misc/ti-st/Kconfig
  32. @@ -14,4 +14,12 @@ config TI_ST
  33.       are returned to relevant protocol drivers based on their
  34.       packet types.
  35.  
  36. +config ST_HCI
  37. +   tristate "HCI TTY emulation driver for Bluetooth"
  38. +   depends on TI_ST
  39. +   help
  40. +     This enables the TTY device like emulation for HCI used by
  41. +     user-space Bluetooth stacks.
  42. +     It will provide a character device for user space Bluetooth stack to
  43. +     send/receive data over shared transport.
  44.  endmenu
  45. diff --git a/drivers/misc/ti-st/Makefile b/drivers/misc/ti-st/Makefile
  46. index 78d7ebb14749..454621909fb7 100644
  47. --- a/drivers/misc/ti-st/Makefile
  48. +++ b/drivers/misc/ti-st/Makefile
  49. @@ -4,3 +4,4 @@
  50.  #
  51.  obj-$(CONFIG_TI_ST)        += st_drv.o
  52.  st_drv-objs            := st_core.o st_kim.o st_ll.o
  53. +obj-$(CONFIG_ST_HCI)       += tty_hci.o
  54. diff --git a/drivers/misc/ti-st/tty_hci.c b/drivers/misc/ti-st/tty_hci.c
  55. new file mode 100644
  56. index 000000000000..5b27b04f2785
  57. --- /dev/null
  58. +++ b/drivers/misc/ti-st/tty_hci.c
  59. @@ -0,0 +1,542 @@
  60. +/*
  61. + *  TTY emulation for user-space Bluetooth stacks over HCI-H4
  62. + *  Copyright (C) 2011-2012 Texas Instruments
  63. + *  Author: Pavan Savoy <pavan_savoy@ti.com>
  64. + *
  65. + *  This program is free software; you can redistribute it and/or modify
  66. + *  it under the terms of the GNU General Public License version 2 as
  67. + *  published by the Free Software Foundation.
  68. + *
  69. + *  This program is distributed in the hope that it will be useful,
  70. + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  71. + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  72. + *  GNU General Public License for more details.
  73. + */
  74. +
  75. +/** define one of the following for debugging
  76. +#define DEBUG
  77. +#define VERBOSE
  78. +*/
  79. +
  80. +#define pr_fmt(fmt) "(hci_tty): " fmt
  81. +#include <linux/module.h>
  82. +#include <linux/cdev.h>
  83. +#include <linux/fs.h>
  84. +#include <linux/device.h>
  85. +
  86. +#include <linux/uaccess.h>
  87. +#include <linux/tty.h>
  88. +#include <linux/sched.h>
  89. +
  90. +#include <linux/delay.h>
  91. +#include <linux/firmware.h>
  92. +#include <linux/platform_device.h>
  93. +#include <linux/poll.h>
  94. +#include <linux/skbuff.h>
  95. +#include <linux/interrupt.h>
  96. +
  97. +#include <linux/ti_wilink_st.h>
  98. +
  99. +/* Number of seconds to wait for registration completion
  100. + * when ST returns PENDING status.
  101. + */
  102. +#define BT_REGISTER_TIMEOUT   6000 /* 6 sec */
  103. +
  104. +/**
  105. + * struct ti_st - driver operation structure
  106. + * @hdev: hci device pointer which binds to bt driver
  107. + * @reg_status: ST registration callback status
  108. + * @st_write: write function provided by the ST driver
  109. + * to be used by the driver during send_frame.
  110. + * @wait_reg_completion - completion sync between ti_st_open
  111. + * and st_reg_completion_cb.
  112. + */
  113. +struct ti_st {
  114. +   struct hci_dev *hdev;
  115. +   char reg_status;
  116. +   long (*st_write)(struct sk_buff *);
  117. +   struct completion wait_reg_completion;
  118. +   wait_queue_head_t data_q;
  119. +   struct sk_buff_head rx_list;
  120. +};
  121. +
  122. +#define DEVICE_NAME     "hci_tty"
  123. +
  124. +/***********Functions called from ST driver**********************************/
  125. +/* Called by Shared Transport layer when receive data is
  126. + * available */
  127. +static long st_receive(void *priv_data, struct sk_buff *skb)
  128. +{
  129. +   struct ti_st    *hst = (void *)priv_data;
  130. +
  131. +   pr_debug("@ %s", __func__);
  132. +#ifdef VERBOSE
  133. +   print_hex_dump(KERN_INFO, ">rx>", DUMP_PREFIX_NONE,
  134. +              16, 1, skb->data, skb->len, 0);
  135. +#endif
  136. +   skb_queue_tail(&hst->rx_list, skb);
  137. +   wake_up_interruptible(&hst->data_q);
  138. +   return 0;
  139. +}
  140. +
  141. +/* Called by ST layer to indicate protocol registration completion
  142. + * status.ti_st_open() function will wait for signal from this
  143. + * API when st_register() function returns ST_PENDING.
  144. + */
  145. +static void st_reg_completion_cb(void *priv_data, char data)
  146. +{
  147. +   struct ti_st    *lhst = (void *)priv_data;
  148. +
  149. +   pr_info("@ %s\n", __func__);
  150. +   /* Save registration status for use in ti_st_open() */
  151. +   lhst->reg_status = data;
  152. +   /* complete the wait in ti_st_open() */
  153. +   complete(&lhst->wait_reg_completion);
  154. +}
  155. +
  156. +/* protocol structure registered with shared transport */
  157. +#define MAX_BT_CHNL_IDS 3
  158. +static struct st_proto_s ti_st_proto[MAX_BT_CHNL_IDS] = {
  159. +   {
  160. +       .chnl_id = 0x04, /* HCI Events */
  161. +       .hdr_len = 2,
  162. +       .offset_len_in_hdr = 1,
  163. +       .len_size = 1, /* sizeof(plen) in struct hci_event_hdr */
  164. +       .reserve = 8,
  165. +   },
  166. +   {
  167. +       .chnl_id = 0x02, /* ACL */
  168. +       .hdr_len = 4,
  169. +       .offset_len_in_hdr = 2,
  170. +       .len_size = 2,  /* sizeof(dlen) in struct hci_acl_hdr */
  171. +       .reserve = 8,
  172. +   },
  173. +   {
  174. +       .chnl_id = 0x03, /* SCO */
  175. +       .hdr_len = 3,
  176. +       .offset_len_in_hdr = 2,
  177. +       .len_size = 1, /* sizeof(dlen) in struct hci_sco_hdr */
  178. +       .reserve = 8,
  179. +   },
  180. +};
  181. +/** hci_tty_open Function
  182. + *  This function will perform an register on ST driver.
  183. + *
  184. + *  Parameters :
  185. + *  @file  : File pointer for BT char driver
  186. + *  @inod  :
  187. + *  Returns  0 -  on success
  188. + *           else suitable error code
  189. + */
  190. +int hci_tty_open(struct inode *inod, struct file *file)
  191. +{
  192. +   int i = 0, err = 0;
  193. +   unsigned long timeleft;
  194. +   struct ti_st *hst;
  195. +
  196. +   pr_info("inside %s (%p, %p)\n", __func__, inod, file);
  197. +
  198. +   hst = kzalloc(sizeof(*hst), GFP_KERNEL);
  199. +   file->private_data = hst;
  200. +   hst = file->private_data;
  201. +
  202. +   for (i = 0; i < MAX_BT_CHNL_IDS; i++) {
  203. +       ti_st_proto[i].priv_data = hst;
  204. +       ti_st_proto[i].max_frame_size = 1026;
  205. +       ti_st_proto[i].recv = st_receive;
  206. +       ti_st_proto[i].reg_complete_cb = st_reg_completion_cb;
  207. +
  208. +       /* Prepare wait-for-completion handler */
  209. +       init_completion(&hst->wait_reg_completion);
  210. +       /* Reset ST registration callback status flag,
  211. +        * this value will be updated in
  212. +        * st_reg_completion_cb()
  213. +        * function whenever it called from ST driver.
  214. +        */
  215. +       hst->reg_status = -EINPROGRESS;
  216. +
  217. +       err = st_register(&ti_st_proto[i]);
  218. +       if (!err)
  219. +           goto done;
  220. +
  221. +       if (err != -EINPROGRESS) {
  222. +           pr_err("st_register failed %d", err);
  223. +           goto error;
  224. +       }
  225. +
  226. +       /* ST is busy with either protocol
  227. +        * registration or firmware download.
  228. +        */
  229. +       pr_debug("waiting for registration completion signal from ST");
  230. +       timeleft = wait_for_completion_timeout
  231. +           (&hst->wait_reg_completion,
  232. +            msecs_to_jiffies(BT_REGISTER_TIMEOUT));
  233. +       if (!timeleft) {
  234. +           pr_err("Timeout(%d sec),didn't get reg completion signal from ST",
  235. +                  BT_REGISTER_TIMEOUT / 1000);
  236. +           err = -ETIMEDOUT;
  237. +           goto error;
  238. +       }
  239. +
  240. +       /* Is ST registration callback
  241. +        * called with ERROR status? */
  242. +       if (hst->reg_status != 0) {
  243. +           pr_err("ST registration completed with invalid status %d",
  244. +                  hst->reg_status);
  245. +           err = -EAGAIN;
  246. +           goto error;
  247. +       }
  248. +
  249. +done:
  250. +       hst->st_write = ti_st_proto[i].write;
  251. +       if (!hst->st_write) {
  252. +           pr_err("undefined ST write function");
  253. +           for (i = 0; i < MAX_BT_CHNL_IDS; i++) {
  254. +               /* Undo registration with ST */
  255. +               err = st_unregister(&ti_st_proto[i]);
  256. +               if (err)
  257. +                   pr_err("st_unregister() failed with error %d",
  258. +                          err);
  259. +               hst->st_write = NULL;
  260. +           }
  261. +           return -EIO;
  262. +       }
  263. +   }
  264. +
  265. +   skb_queue_head_init(&hst->rx_list);
  266. +   init_waitqueue_head(&hst->data_q);
  267. +
  268. +   return 0;
  269. +
  270. +error:
  271. +   kfree(hst);
  272. +   return err;
  273. +}
  274. +
  275. +/** hci_tty_release Function
  276. + *  This function will un-registers from the ST driver.
  277. + *
  278. + *  Parameters :
  279. + *  @file  : File pointer for BT char driver
  280. + *  @inod  :
  281. + *  Returns  0 -  on success
  282. + *           else suitable error code
  283. + */
  284. +int hci_tty_release(struct inode *inod, struct file *file)
  285. +{
  286. +   int err, i;
  287. +   struct ti_st *hst = file->private_data;
  288. +
  289. +   pr_info("inside %s (%p, %p)\n", __func__, inod, file);
  290. +
  291. +   for (i = 0; i < MAX_BT_CHNL_IDS; i++) {
  292. +       err = st_unregister(&ti_st_proto[i]);
  293. +       if (err)
  294. +           pr_err("st_unregister(%d) failed with error %d",
  295. +                  ti_st_proto[i].chnl_id, err);
  296. +   }
  297. +
  298. +   hst->st_write = NULL;
  299. +   skb_queue_purge(&hst->rx_list);
  300. +   kfree(hst);
  301. +   return err;
  302. +}
  303. +
  304. +/** hci_tty_read Function
  305. + *
  306. + *  Parameters :
  307. + *  @file  : File pointer for BT char driver
  308. + *  @data  : Data which needs to be passed to APP
  309. + *  @size  : Length of the data passesd
  310. + *  offset :
  311. + *  Returns  Size of packet received -  on success
  312. + *           else suitable error code
  313. + */
  314. +ssize_t hci_tty_read(struct file *file, char __user *data, size_t size,
  315. +       loff_t *offset)
  316. +{
  317. +   int len = 0, tout;
  318. +   struct sk_buff *skb = NULL, *rskb = NULL;
  319. +   struct ti_st    *hst;
  320. +
  321. +   pr_debug("inside %s (%p, %p, %u, %p)\n",
  322. +        __func__, file, data, size, offset);
  323. +
  324. +   /* Validate input parameters */
  325. +   if ((NULL == file) || (((NULL == data) || (0 == size)))) {
  326. +       pr_err("Invalid input params passed to %s", __func__);
  327. +       return -EINVAL;
  328. +   }
  329. +
  330. +   hst = file->private_data;
  331. +
  332. +   /* cannot come here if poll-ed before reading
  333. +    * if not poll-ed wait on the same wait_q
  334. +    */
  335. +   tout = wait_event_interruptible_timeout(hst->data_q,
  336. +           !skb_queue_empty(&hst->rx_list),
  337. +               msecs_to_jiffies(1000));
  338. +   /* Check for timed out condition */
  339. +   if (0 == tout) {
  340. +       pr_err("Device Read timed out\n");
  341. +       return -ETIMEDOUT;
  342. +   }
  343. +
  344. +   /* hst->rx_list not empty skb already present */
  345. +   skb = skb_dequeue(&hst->rx_list);
  346. +   if (!skb) {
  347. +       pr_err("dequed skb is null?\n");
  348. +       return -EIO;
  349. +   }
  350. +
  351. +#ifdef VERBOSE
  352. +   print_hex_dump(KERN_INFO, ">in>", DUMP_PREFIX_NONE,
  353. +              16, 1, skb->data, skb->len, 0);
  354. +#endif
  355. +
  356. +   /* Forward the data to the user */
  357. +   if (skb->len >= size) {
  358. +       pr_err("FIONREAD not done before read\n");
  359. +       return -ENOMEM;
  360. +   } else {
  361. +       /* returning skb */
  362. +       rskb = alloc_skb(size, GFP_KERNEL);
  363. +       if (!rskb) {
  364. +           pr_err("alloc_skb error\n");
  365. +           return -ENOMEM;
  366. +       }
  367. +
  368. +       /* cb[0] has the pkt_type 0x04 or 0x02 or 0x03 */
  369. +       memcpy(skb_put(rskb, 1), &skb->cb[0], 1);
  370. +       memcpy(skb_put(rskb, skb->len), skb->data, skb->len);
  371. +
  372. +       if (copy_to_user(data, rskb->data, rskb->len)) {
  373. +           pr_err("unable to copy to user space\n");
  374. +           /* Queue the skb back to head */
  375. +           skb_queue_head(&hst->rx_list, skb);
  376. +           kfree_skb(rskb);
  377. +           return -EIO;
  378. +       }
  379. +   }
  380. +
  381. +   len = rskb->len;    /* len of returning skb */
  382. +   kfree_skb(skb);
  383. +   kfree_skb(rskb);
  384. +   pr_debug("total size read= %d\n", len);
  385. +   return len;
  386. +}
  387. +
  388. +/* hci_tty_write Function
  389. + *
  390. + *  Parameters :
  391. + *  @file   : File pointer for BT char driver
  392. + *  @data   : packet data from BT application
  393. + *  @size   : Size of the packet data
  394. + *  @offset :
  395. + *  Returns  Size of packet on success
  396. + *           else suitable error code
  397. + */
  398. +ssize_t hci_tty_write(struct file *file, const char __user *data,
  399. +       size_t size, loff_t *offset)
  400. +{
  401. +   struct ti_st *hst = file->private_data;
  402. +   struct  sk_buff *skb;
  403. +
  404. +   pr_debug("inside %s (%p, %p, %u, %p)\n",
  405. +        __func__, file, data, size, offset);
  406. +
  407. +   if (!hst->st_write) {
  408. +       pr_err(" Can't write to ST, hhci_tty->st_write null ?");
  409. +       return -EINVAL;
  410. +   }
  411. +
  412. +   skb = alloc_skb(size, GFP_KERNEL);
  413. +   /* Validate Created SKB */
  414. +   if (NULL == skb) {
  415. +       pr_err("Error aaloacting SKB");
  416. +       return -ENOMEM;
  417. +   }
  418. +
  419. +   /* Forward the data from the user space to ST core */
  420. +   if (copy_from_user(skb_put(skb, size), data, size)) {
  421. +       pr_err(" Unable to copy from user space");
  422. +       kfree_skb(skb);
  423. +       return -EIO;
  424. +   }
  425. +
  426. +#ifdef VERBOSE
  427. +   pr_debug("start data..");
  428. +   print_hex_dump(KERN_INFO, "<out<", DUMP_PREFIX_NONE,
  429. +              16, 1, skb->data, size, 0);
  430. +   pr_debug("\n..end data");
  431. +#endif
  432. +
  433. +   hst->st_write(skb);
  434. +   return size;
  435. +}
  436. +
  437. +/** hci_tty_ioctl Function
  438. + *  This will peform the functions as directed by the command and command
  439. + *  argument.
  440. + *
  441. + *  Parameters :
  442. + *  @file  : File pointer for BT char driver
  443. + *  @cmd   : IOCTL Command
  444. + *  @arg   : Command argument for IOCTL command
  445. + *  Returns  0 on success
  446. + *           else suitable error code
  447. + */
  448. +static long hci_tty_ioctl(struct file *file,
  449. +       unsigned int cmd, unsigned long arg)
  450. +{
  451. +   struct sk_buff *skb = NULL;
  452. +   int     retcode = 0;
  453. +   struct ti_st    *hst;
  454. +
  455. +   pr_debug("inside %s (%p, %u, %lx)", __func__, file, cmd, arg);
  456. +
  457. +   /* Validate input parameters */
  458. +   if ((NULL == file) || (0 == cmd)) {
  459. +       pr_err("invalid input parameters passed to %s", __func__);
  460. +       return -EINVAL;
  461. +   }
  462. +
  463. +   hst = file->private_data;
  464. +
  465. +   switch (cmd) {
  466. +   case FIONREAD:
  467. +       /* Deque the SKB from the head if rx_list is not empty
  468. +        * update the argument with skb->len to provide amount of data
  469. +        * available in the available SKB +1 for the PKT_TYPE
  470. +        * field not provided in data by TI-ST.
  471. +        */
  472. +       skb = skb_dequeue(&hst->rx_list);
  473. +       if (skb != NULL) {
  474. +           *(unsigned int *)arg = skb->len + 1;
  475. +           /* Re-Store the SKB for furtur Read operations */
  476. +           skb_queue_head(&hst->rx_list, skb);
  477. +       } else {
  478. +           *(unsigned int *)arg = 0;
  479. +       }
  480. +       pr_debug("returning %d\n", *(unsigned int *)arg);
  481. +       break;
  482. +   default:
  483. +       pr_debug("Un-Identified IOCTL %d", cmd);
  484. +       retcode = 0;
  485. +       break;
  486. +   }
  487. +
  488. +   return retcode;
  489. +}
  490. +
  491. +/** hci_tty_poll Function
  492. + *  This function will wait till some data is received to the hci_tty driver from ST
  493. + *
  494. + *  Parameters :
  495. + *  @file  : File pointer for BT char driver
  496. + *  @wait  : POLL wait information
  497. + *  Returns  status of POLL on success
  498. + *           else suitable error code
  499. + */
  500. +static unsigned int hci_tty_poll(struct file *file, poll_table *wait)
  501. +{
  502. +   struct ti_st    *hst = file->private_data;
  503. +   unsigned long mask = 0;
  504. +
  505. +   pr_debug("@ %s\n", __func__);
  506. +
  507. +   /* wait to be completed by st_receive */
  508. +   poll_wait(file, &hst->data_q, wait);
  509. +   pr_debug("poll broke\n");
  510. +
  511. +   if (!skb_queue_empty(&hst->rx_list)) {
  512. +       pr_debug("rx list que !empty\n");
  513. +       mask |= POLLIN; /* TODO: check app for mask */
  514. +   }
  515. +
  516. +   return mask;
  517. +}
  518. +
  519. +/* BT Char driver function pointers
  520. + * These functions are called from USER space by pefroming File Operations
  521. + * on /dev/hci_tty node exposed by this driver during init
  522. + */
  523. +const struct file_operations hci_tty_chrdev_ops = {
  524. +   .owner = THIS_MODULE,
  525. +   .open = hci_tty_open,
  526. +   .read = hci_tty_read,
  527. +   .write = hci_tty_write,
  528. +   .unlocked_ioctl = hci_tty_ioctl,
  529. +   .poll = hci_tty_poll,
  530. +   .release = hci_tty_release,
  531. +};
  532. +
  533. +/*********Functions called during insmod and delmod****************************/
  534. +
  535. +static int hci_tty_major;      /* major number */
  536. +static struct class *hci_tty_class;    /* class during class_create */
  537. +static struct device *hci_tty_dev; /* dev during device_create */
  538. +/** hci_tty_init Function
  539. + *  This function Initializes the hci_tty driver parametes and exposes
  540. + *  /dev/hci_tty node to user space
  541. + *
  542. + *  Parameters : NULL
  543. + *  Returns  0 on success
  544. + *           else suitable error code
  545. + */
  546. +static int __init hci_tty_init(void)
  547. +{
  548. +   pr_info("inside %s\n", __func__);
  549. +
  550. +   /* Expose the device DEVICE_NAME to user space
  551. +    * And obtain the major number for the device
  552. +    */
  553. +   hci_tty_major = register_chrdev(0, DEVICE_NAME, &hci_tty_chrdev_ops);
  554. +
  555. +   if (0 > hci_tty_major) {
  556. +       pr_err("Error when registering to char dev");
  557. +       return hci_tty_major;
  558. +   }
  559. +
  560. +   /*  udev */
  561. +   hci_tty_class = class_create(THIS_MODULE, DEVICE_NAME);
  562. +   if (IS_ERR(hci_tty_class)) {
  563. +       pr_err("Something went wrong in class_create");
  564. +       unregister_chrdev(hci_tty_major, DEVICE_NAME);
  565. +       return -1;
  566. +   }
  567. +
  568. +   hci_tty_dev =
  569. +       device_create(hci_tty_class, NULL, MKDEV(hci_tty_major, 0),
  570. +                 NULL, DEVICE_NAME);
  571. +   if (IS_ERR(hci_tty_dev)) {
  572. +       pr_err("Error in device create");
  573. +       unregister_chrdev(hci_tty_major, DEVICE_NAME);
  574. +       class_destroy(hci_tty_class);
  575. +       return -1;
  576. +   }
  577. +   pr_info("allocated %d, %d\n", hci_tty_major, 0);
  578. +   return 0;
  579. +}
  580. +
  581. +/** hci_tty_exit Function
  582. + *  This function Destroys the hci_tty driver parametes and /dev/hci_tty node
  583. + *
  584. + *  Parameters : NULL
  585. + *  Returns   NULL
  586. + */
  587. +static void __exit hci_tty_exit(void)
  588. +{
  589. +   pr_info("inside %s\n", __func__);
  590. +   pr_info("bye.. freeing up %d\n", hci_tty_major);
  591. +
  592. +   device_destroy(hci_tty_class, MKDEV(hci_tty_major, 0));
  593. +   class_destroy(hci_tty_class);
  594. +   unregister_chrdev(hci_tty_major, DEVICE_NAME);
  595. +}
  596. +
  597. +module_init(hci_tty_init);
  598. +module_exit(hci_tty_exit);
  599. +
  600. +MODULE_AUTHOR("Pavan Savoy <pavan_savoy@ti.com>");
  601. +MODULE_LICENSE("GPL");
Add Comment
Please, Sign In to add comment