ozcdev.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. /* -----------------------------------------------------------------------------
  2. * Copyright (c) 2011 Ozmo Inc
  3. * Released under the GNU General Public License Version 2 (GPLv2).
  4. * -----------------------------------------------------------------------------
  5. */
  6. #include <linux/module.h>
  7. #include <linux/fs.h>
  8. #include <linux/cdev.h>
  9. #include <linux/uaccess.h>
  10. #include <linux/netdevice.h>
  11. #include <linux/etherdevice.h>
  12. #include <linux/poll.h>
  13. #include <linux/sched.h>
  14. #include "ozdbg.h"
  15. #include "ozprotocol.h"
  16. #include "ozappif.h"
  17. #include "ozeltbuf.h"
  18. #include "ozpd.h"
  19. #include "ozproto.h"
  20. #include "ozcdev.h"
  21. #define OZ_RD_BUF_SZ 256
  22. struct oz_cdev {
  23. dev_t devnum;
  24. struct cdev cdev;
  25. wait_queue_head_t rdq;
  26. spinlock_t lock;
  27. u8 active_addr[ETH_ALEN];
  28. struct oz_pd *active_pd;
  29. };
  30. /* Per PD context for the serial service stored in the PD. */
  31. struct oz_serial_ctx {
  32. atomic_t ref_count;
  33. u8 tx_seq_num;
  34. u8 rx_seq_num;
  35. u8 rd_buf[OZ_RD_BUF_SZ];
  36. int rd_in;
  37. int rd_out;
  38. };
  39. static struct oz_cdev g_cdev;
  40. static struct class *g_oz_class;
  41. /*
  42. * Context: process and softirq
  43. */
  44. static struct oz_serial_ctx *oz_cdev_claim_ctx(struct oz_pd *pd)
  45. {
  46. struct oz_serial_ctx *ctx;
  47. spin_lock_bh(&pd->app_lock[OZ_APPID_SERIAL]);
  48. ctx = (struct oz_serial_ctx *) pd->app_ctx[OZ_APPID_SERIAL];
  49. if (ctx)
  50. atomic_inc(&ctx->ref_count);
  51. spin_unlock_bh(&pd->app_lock[OZ_APPID_SERIAL]);
  52. return ctx;
  53. }
  54. /*
  55. * Context: softirq or process
  56. */
  57. static void oz_cdev_release_ctx(struct oz_serial_ctx *ctx)
  58. {
  59. if (atomic_dec_and_test(&ctx->ref_count)) {
  60. oz_dbg(ON, "Dealloc serial context\n");
  61. kfree(ctx);
  62. }
  63. }
  64. /*
  65. * Context: process
  66. */
  67. static int oz_cdev_open(struct inode *inode, struct file *filp)
  68. {
  69. struct oz_cdev *dev = container_of(inode->i_cdev, struct oz_cdev, cdev);
  70. oz_dbg(ON, "major = %d minor = %d\n", imajor(inode), iminor(inode));
  71. filp->private_data = dev;
  72. return 0;
  73. }
  74. /*
  75. * Context: process
  76. */
  77. static int oz_cdev_release(struct inode *inode, struct file *filp)
  78. {
  79. return 0;
  80. }
  81. /*
  82. * Context: process
  83. */
  84. static ssize_t oz_cdev_read(struct file *filp, char __user *buf, size_t count,
  85. loff_t *fpos)
  86. {
  87. int n;
  88. int ix;
  89. struct oz_pd *pd;
  90. struct oz_serial_ctx *ctx;
  91. spin_lock_bh(&g_cdev.lock);
  92. pd = g_cdev.active_pd;
  93. if (pd)
  94. oz_pd_get(pd);
  95. spin_unlock_bh(&g_cdev.lock);
  96. if (pd == NULL)
  97. return -1;
  98. ctx = oz_cdev_claim_ctx(pd);
  99. if (ctx == NULL)
  100. goto out2;
  101. n = ctx->rd_in - ctx->rd_out;
  102. if (n < 0)
  103. n += OZ_RD_BUF_SZ;
  104. if (count > n)
  105. count = n;
  106. ix = ctx->rd_out;
  107. n = OZ_RD_BUF_SZ - ix;
  108. if (n > count)
  109. n = count;
  110. if (copy_to_user(buf, &ctx->rd_buf[ix], n)) {
  111. count = 0;
  112. goto out1;
  113. }
  114. ix += n;
  115. if (ix == OZ_RD_BUF_SZ)
  116. ix = 0;
  117. if (n < count) {
  118. if (copy_to_user(&buf[n], ctx->rd_buf, count-n)) {
  119. count = 0;
  120. goto out1;
  121. }
  122. ix = count-n;
  123. }
  124. ctx->rd_out = ix;
  125. out1:
  126. oz_cdev_release_ctx(ctx);
  127. out2:
  128. oz_pd_put(pd);
  129. return count;
  130. }
  131. /*
  132. * Context: process
  133. */
  134. static ssize_t oz_cdev_write(struct file *filp, const char __user *buf,
  135. size_t count, loff_t *fpos)
  136. {
  137. struct oz_pd *pd;
  138. struct oz_elt_buf *eb;
  139. struct oz_elt_info *ei;
  140. struct oz_elt *elt;
  141. struct oz_app_hdr *app_hdr;
  142. struct oz_serial_ctx *ctx;
  143. if (count > sizeof(ei->data) - sizeof(*elt) - sizeof(*app_hdr))
  144. return -EINVAL;
  145. spin_lock_bh(&g_cdev.lock);
  146. pd = g_cdev.active_pd;
  147. if (pd)
  148. oz_pd_get(pd);
  149. spin_unlock_bh(&g_cdev.lock);
  150. if (pd == NULL)
  151. return -ENXIO;
  152. if (!(pd->state & OZ_PD_S_CONNECTED))
  153. return -EAGAIN;
  154. eb = &pd->elt_buff;
  155. ei = oz_elt_info_alloc(eb);
  156. if (ei == NULL) {
  157. count = 0;
  158. goto out;
  159. }
  160. elt = (struct oz_elt *)ei->data;
  161. app_hdr = (struct oz_app_hdr *)(elt+1);
  162. elt->length = sizeof(struct oz_app_hdr) + count;
  163. elt->type = OZ_ELT_APP_DATA;
  164. ei->app_id = OZ_APPID_SERIAL;
  165. ei->length = elt->length + sizeof(struct oz_elt);
  166. app_hdr->app_id = OZ_APPID_SERIAL;
  167. if (copy_from_user(app_hdr+1, buf, count))
  168. goto out;
  169. spin_lock_bh(&pd->app_lock[OZ_APPID_USB]);
  170. ctx = (struct oz_serial_ctx *) pd->app_ctx[OZ_APPID_SERIAL];
  171. if (ctx) {
  172. app_hdr->elt_seq_num = ctx->tx_seq_num++;
  173. if (ctx->tx_seq_num == 0)
  174. ctx->tx_seq_num = 1;
  175. spin_lock(&eb->lock);
  176. if (oz_queue_elt_info(eb, 0, 0, ei) == 0)
  177. ei = NULL;
  178. spin_unlock(&eb->lock);
  179. }
  180. spin_unlock_bh(&pd->app_lock[OZ_APPID_USB]);
  181. out:
  182. if (ei) {
  183. count = 0;
  184. spin_lock_bh(&eb->lock);
  185. oz_elt_info_free(eb, ei);
  186. spin_unlock_bh(&eb->lock);
  187. }
  188. oz_pd_put(pd);
  189. return count;
  190. }
  191. /*
  192. * Context: process
  193. */
  194. static int oz_set_active_pd(const u8 *addr)
  195. {
  196. int rc = 0;
  197. struct oz_pd *pd;
  198. struct oz_pd *old_pd;
  199. pd = oz_pd_find(addr);
  200. if (pd) {
  201. spin_lock_bh(&g_cdev.lock);
  202. ether_addr_copy(g_cdev.active_addr, addr);
  203. old_pd = g_cdev.active_pd;
  204. g_cdev.active_pd = pd;
  205. spin_unlock_bh(&g_cdev.lock);
  206. if (old_pd)
  207. oz_pd_put(old_pd);
  208. } else {
  209. if (is_zero_ether_addr(addr)) {
  210. spin_lock_bh(&g_cdev.lock);
  211. pd = g_cdev.active_pd;
  212. g_cdev.active_pd = NULL;
  213. memset(g_cdev.active_addr, 0,
  214. sizeof(g_cdev.active_addr));
  215. spin_unlock_bh(&g_cdev.lock);
  216. if (pd)
  217. oz_pd_put(pd);
  218. } else {
  219. rc = -1;
  220. }
  221. }
  222. return rc;
  223. }
  224. /*
  225. * Context: process
  226. */
  227. static long oz_cdev_ioctl(struct file *filp, unsigned int cmd,
  228. unsigned long arg)
  229. {
  230. int rc = 0;
  231. if (_IOC_TYPE(cmd) != OZ_IOCTL_MAGIC)
  232. return -ENOTTY;
  233. if (_IOC_NR(cmd) > OZ_IOCTL_MAX)
  234. return -ENOTTY;
  235. if (_IOC_DIR(cmd) & _IOC_READ)
  236. rc = !access_ok(VERIFY_WRITE, (void __user *)arg,
  237. _IOC_SIZE(cmd));
  238. else if (_IOC_DIR(cmd) & _IOC_WRITE)
  239. rc = !access_ok(VERIFY_READ, (void __user *)arg,
  240. _IOC_SIZE(cmd));
  241. if (rc)
  242. return -EFAULT;
  243. switch (cmd) {
  244. case OZ_IOCTL_GET_PD_LIST: {
  245. struct oz_pd_list list;
  246. oz_dbg(ON, "OZ_IOCTL_GET_PD_LIST\n");
  247. memset(&list, 0, sizeof(list));
  248. list.count = oz_get_pd_list(list.addr, OZ_MAX_PDS);
  249. if (copy_to_user((void __user *)arg, &list,
  250. sizeof(list)))
  251. return -EFAULT;
  252. }
  253. break;
  254. case OZ_IOCTL_SET_ACTIVE_PD: {
  255. u8 addr[ETH_ALEN];
  256. oz_dbg(ON, "OZ_IOCTL_SET_ACTIVE_PD\n");
  257. if (copy_from_user(addr, (void __user *)arg, ETH_ALEN))
  258. return -EFAULT;
  259. rc = oz_set_active_pd(addr);
  260. }
  261. break;
  262. case OZ_IOCTL_GET_ACTIVE_PD: {
  263. u8 addr[ETH_ALEN];
  264. oz_dbg(ON, "OZ_IOCTL_GET_ACTIVE_PD\n");
  265. spin_lock_bh(&g_cdev.lock);
  266. ether_addr_copy(addr, g_cdev.active_addr);
  267. spin_unlock_bh(&g_cdev.lock);
  268. if (copy_to_user((void __user *)arg, addr, ETH_ALEN))
  269. return -EFAULT;
  270. }
  271. break;
  272. case OZ_IOCTL_ADD_BINDING:
  273. case OZ_IOCTL_REMOVE_BINDING: {
  274. struct oz_binding_info b;
  275. if (copy_from_user(&b, (void __user *)arg,
  276. sizeof(struct oz_binding_info))) {
  277. return -EFAULT;
  278. }
  279. /* Make sure name is null terminated. */
  280. b.name[OZ_MAX_BINDING_LEN-1] = 0;
  281. if (cmd == OZ_IOCTL_ADD_BINDING)
  282. oz_binding_add(b.name);
  283. else
  284. oz_binding_remove(b.name);
  285. }
  286. break;
  287. }
  288. return rc;
  289. }
  290. /*
  291. * Context: process
  292. */
  293. static unsigned int oz_cdev_poll(struct file *filp, poll_table *wait)
  294. {
  295. unsigned int ret = 0;
  296. struct oz_cdev *dev = filp->private_data;
  297. oz_dbg(ON, "Poll called wait = %p\n", wait);
  298. spin_lock_bh(&dev->lock);
  299. if (dev->active_pd) {
  300. struct oz_serial_ctx *ctx = oz_cdev_claim_ctx(dev->active_pd);
  301. if (ctx) {
  302. if (ctx->rd_in != ctx->rd_out)
  303. ret |= POLLIN | POLLRDNORM;
  304. oz_cdev_release_ctx(ctx);
  305. }
  306. }
  307. spin_unlock_bh(&dev->lock);
  308. if (wait)
  309. poll_wait(filp, &dev->rdq, wait);
  310. return ret;
  311. }
  312. /*
  313. */
  314. static const struct file_operations oz_fops = {
  315. .owner = THIS_MODULE,
  316. .open = oz_cdev_open,
  317. .release = oz_cdev_release,
  318. .read = oz_cdev_read,
  319. .write = oz_cdev_write,
  320. .unlocked_ioctl = oz_cdev_ioctl,
  321. .poll = oz_cdev_poll
  322. };
  323. /*
  324. * Context: process
  325. */
  326. int oz_cdev_register(void)
  327. {
  328. int err;
  329. struct device *dev;
  330. memset(&g_cdev, 0, sizeof(g_cdev));
  331. err = alloc_chrdev_region(&g_cdev.devnum, 0, 1, "ozwpan");
  332. if (err < 0)
  333. return err;
  334. oz_dbg(ON, "Alloc dev number %d:%d\n",
  335. MAJOR(g_cdev.devnum), MINOR(g_cdev.devnum));
  336. cdev_init(&g_cdev.cdev, &oz_fops);
  337. g_cdev.cdev.owner = THIS_MODULE;
  338. spin_lock_init(&g_cdev.lock);
  339. init_waitqueue_head(&g_cdev.rdq);
  340. err = cdev_add(&g_cdev.cdev, g_cdev.devnum, 1);
  341. if (err < 0) {
  342. oz_dbg(ON, "Failed to add cdev\n");
  343. goto unregister;
  344. }
  345. g_oz_class = class_create(THIS_MODULE, "ozmo_wpan");
  346. if (IS_ERR(g_oz_class)) {
  347. oz_dbg(ON, "Failed to register ozmo_wpan class\n");
  348. err = PTR_ERR(g_oz_class);
  349. goto delete;
  350. }
  351. dev = device_create(g_oz_class, NULL, g_cdev.devnum, NULL, "ozwpan");
  352. if (IS_ERR(dev)) {
  353. oz_dbg(ON, "Failed to create sysfs entry for cdev\n");
  354. err = PTR_ERR(dev);
  355. goto delete;
  356. }
  357. return 0;
  358. delete:
  359. cdev_del(&g_cdev.cdev);
  360. unregister:
  361. unregister_chrdev_region(g_cdev.devnum, 1);
  362. return err;
  363. }
  364. /*
  365. * Context: process
  366. */
  367. int oz_cdev_deregister(void)
  368. {
  369. cdev_del(&g_cdev.cdev);
  370. unregister_chrdev_region(g_cdev.devnum, 1);
  371. if (g_oz_class) {
  372. device_destroy(g_oz_class, g_cdev.devnum);
  373. class_destroy(g_oz_class);
  374. }
  375. return 0;
  376. }
  377. /*
  378. * Context: process
  379. */
  380. int oz_cdev_init(void)
  381. {
  382. oz_app_enable(OZ_APPID_SERIAL, 1);
  383. return 0;
  384. }
  385. /*
  386. * Context: process
  387. */
  388. void oz_cdev_term(void)
  389. {
  390. oz_app_enable(OZ_APPID_SERIAL, 0);
  391. }
  392. /*
  393. * Context: softirq-serialized
  394. */
  395. int oz_cdev_start(struct oz_pd *pd, int resume)
  396. {
  397. struct oz_serial_ctx *ctx;
  398. struct oz_serial_ctx *old_ctx;
  399. if (resume) {
  400. oz_dbg(ON, "Serial service resumed\n");
  401. return 0;
  402. }
  403. ctx = kzalloc(sizeof(struct oz_serial_ctx), GFP_ATOMIC);
  404. if (ctx == NULL)
  405. return -ENOMEM;
  406. atomic_set(&ctx->ref_count, 1);
  407. ctx->tx_seq_num = 1;
  408. spin_lock_bh(&pd->app_lock[OZ_APPID_SERIAL]);
  409. old_ctx = pd->app_ctx[OZ_APPID_SERIAL];
  410. if (old_ctx) {
  411. spin_unlock_bh(&pd->app_lock[OZ_APPID_SERIAL]);
  412. kfree(ctx);
  413. } else {
  414. pd->app_ctx[OZ_APPID_SERIAL] = ctx;
  415. spin_unlock_bh(&pd->app_lock[OZ_APPID_SERIAL]);
  416. }
  417. spin_lock(&g_cdev.lock);
  418. if ((g_cdev.active_pd == NULL) &&
  419. ether_addr_equal(pd->mac_addr, g_cdev.active_addr)) {
  420. oz_pd_get(pd);
  421. g_cdev.active_pd = pd;
  422. oz_dbg(ON, "Active PD arrived\n");
  423. }
  424. spin_unlock(&g_cdev.lock);
  425. oz_dbg(ON, "Serial service started\n");
  426. return 0;
  427. }
  428. /*
  429. * Context: softirq or process
  430. */
  431. void oz_cdev_stop(struct oz_pd *pd, int pause)
  432. {
  433. struct oz_serial_ctx *ctx;
  434. if (pause) {
  435. oz_dbg(ON, "Serial service paused\n");
  436. return;
  437. }
  438. spin_lock_bh(&pd->app_lock[OZ_APPID_SERIAL]);
  439. ctx = (struct oz_serial_ctx *) pd->app_ctx[OZ_APPID_SERIAL];
  440. pd->app_ctx[OZ_APPID_SERIAL] = NULL;
  441. spin_unlock_bh(&pd->app_lock[OZ_APPID_SERIAL]);
  442. if (ctx)
  443. oz_cdev_release_ctx(ctx);
  444. spin_lock(&g_cdev.lock);
  445. if (pd == g_cdev.active_pd)
  446. g_cdev.active_pd = NULL;
  447. else
  448. pd = NULL;
  449. spin_unlock(&g_cdev.lock);
  450. if (pd) {
  451. oz_pd_put(pd);
  452. oz_dbg(ON, "Active PD departed\n");
  453. }
  454. oz_dbg(ON, "Serial service stopped\n");
  455. }
  456. /*
  457. * Context: softirq-serialized
  458. */
  459. void oz_cdev_rx(struct oz_pd *pd, struct oz_elt *elt)
  460. {
  461. struct oz_serial_ctx *ctx;
  462. struct oz_app_hdr *app_hdr;
  463. u8 *data;
  464. int len;
  465. int space;
  466. int copy_sz;
  467. int ix;
  468. ctx = oz_cdev_claim_ctx(pd);
  469. if (ctx == NULL) {
  470. oz_dbg(ON, "Cannot claim serial context\n");
  471. return;
  472. }
  473. app_hdr = (struct oz_app_hdr *)(elt+1);
  474. /* If sequence number is non-zero then check it is not a duplicate.
  475. */
  476. if (app_hdr->elt_seq_num != 0) {
  477. if (((ctx->rx_seq_num - app_hdr->elt_seq_num) & 0x80) == 0) {
  478. /* Reject duplicate element. */
  479. oz_dbg(ON, "Duplicate element:%02x %02x\n",
  480. app_hdr->elt_seq_num, ctx->rx_seq_num);
  481. goto out;
  482. }
  483. }
  484. ctx->rx_seq_num = app_hdr->elt_seq_num;
  485. len = elt->length - sizeof(struct oz_app_hdr);
  486. data = ((u8 *)(elt+1)) + sizeof(struct oz_app_hdr);
  487. if (len <= 0)
  488. goto out;
  489. space = ctx->rd_out - ctx->rd_in - 1;
  490. if (space < 0)
  491. space += OZ_RD_BUF_SZ;
  492. if (len > space) {
  493. oz_dbg(ON, "Not enough space:%d %d\n", len, space);
  494. len = space;
  495. }
  496. ix = ctx->rd_in;
  497. copy_sz = OZ_RD_BUF_SZ - ix;
  498. if (copy_sz > len)
  499. copy_sz = len;
  500. memcpy(&ctx->rd_buf[ix], data, copy_sz);
  501. len -= copy_sz;
  502. ix += copy_sz;
  503. if (ix == OZ_RD_BUF_SZ)
  504. ix = 0;
  505. if (len) {
  506. memcpy(ctx->rd_buf, data+copy_sz, len);
  507. ix = len;
  508. }
  509. ctx->rd_in = ix;
  510. wake_up(&g_cdev.rdq);
  511. out:
  512. oz_cdev_release_ctx(ctx);
  513. }