ircomm_core.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:12k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*********************************************************************
  2.  *                
  3.  * Filename:      ircomm_core.c
  4.  * Version:       1.0
  5.  * Description:   IrCOMM service interface
  6.  * Status:        Experimental.
  7.  * Author:        Dag Brattli <dagb@cs.uit.no>
  8.  * Created at:    Sun Jun  6 20:37:34 1999
  9.  * Modified at:   Tue Dec 21 13:26:41 1999
  10.  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  11.  * 
  12.  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
  13.  *     
  14.  *     This program is free software; you can redistribute it and/or 
  15.  *     modify it under the terms of the GNU General Public License as 
  16.  *     published by the Free Software Foundation; either version 2 of 
  17.  *     the License, or (at your option) any later version.
  18.  * 
  19.  *     This program is distributed in the hope that it will be useful,
  20.  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
  21.  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  22.  *     GNU General Public License for more details.
  23.  * 
  24.  *     You should have received a copy of the GNU General Public License 
  25.  *     along with this program; if not, write to the Free Software 
  26.  *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
  27.  *     MA 02111-1307 USA
  28.  *     
  29.  ********************************************************************/
  30. #include <linux/config.h>
  31. #include <linux/module.h>
  32. #include <linux/sched.h>
  33. #include <linux/proc_fs.h>
  34. #include <linux/init.h>
  35. #include <net/irda/irda.h>
  36. #include <net/irda/irmod.h>
  37. #include <net/irda/irlmp.h>
  38. #include <net/irda/iriap.h>
  39. #include <net/irda/irttp.h>
  40. #include <net/irda/irias_object.h>
  41. #include <net/irda/ircomm_event.h>
  42. #include <net/irda/ircomm_lmp.h>
  43. #include <net/irda/ircomm_ttp.h>
  44. #include <net/irda/ircomm_param.h>
  45. #include <net/irda/ircomm_core.h>
  46. static int __ircomm_close(struct ircomm_cb *self);
  47. static void ircomm_control_indication(struct ircomm_cb *self, 
  48.       struct sk_buff *skb, int clen);
  49. #ifdef CONFIG_PROC_FS
  50. static int ircomm_proc_read(char *buf, char **start, off_t offset, int len);
  51. extern struct proc_dir_entry *proc_irda;
  52. #endif /* CONFIG_PROC_FS */
  53. hashbin_t *ircomm = NULL;
  54. int __init ircomm_init(void)
  55. {
  56. ircomm = hashbin_new(HB_LOCAL); 
  57. if (ircomm == NULL) {
  58. ERROR(__FUNCTION__ "(), can't allocate hashbin!n");
  59. return -ENOMEM;
  60. }
  61. #ifdef CONFIG_PROC_FS
  62. create_proc_info_entry("ircomm", 0, proc_irda, ircomm_proc_read);
  63. #endif /* CONFIG_PROC_FS */
  64. MESSAGE("IrCOMM protocol (Dag Brattli)n");
  65. return 0;
  66. }
  67. #ifdef MODULE
  68. void ircomm_cleanup(void)
  69. {
  70. IRDA_DEBUG(2, __FUNCTION__ "()n");
  71. hashbin_delete(ircomm, (FREE_FUNC) __ircomm_close);
  72. #ifdef CONFIG_PROC_FS
  73. remove_proc_entry("ircomm", proc_irda);
  74. #endif /* CONFIG_PROC_FS */
  75. }
  76. #endif /* MODULE */
  77. /*
  78.  * Function ircomm_open (client_notify)
  79.  *
  80.  *    Start a new IrCOMM instance
  81.  *
  82.  */
  83. struct ircomm_cb *ircomm_open(notify_t *notify, __u8 service_type, int line)
  84. {
  85. struct ircomm_cb *self = NULL;
  86. int ret;
  87. IRDA_DEBUG(2, __FUNCTION__ "(), service_type=0x%02xn",
  88.    service_type);
  89. ASSERT(ircomm != NULL, return NULL;);
  90. self = kmalloc(sizeof(struct ircomm_cb), GFP_ATOMIC);
  91. if (self == NULL)
  92. return NULL;
  93. memset(self, 0, sizeof(struct ircomm_cb));
  94. self->notify = *notify;
  95. self->magic = IRCOMM_MAGIC;
  96. /* Check if we should use IrLMP or IrTTP */
  97. if (service_type & IRCOMM_3_WIRE_RAW) {
  98. self->flow_status = FLOW_START;
  99. ret = ircomm_open_lsap(self);
  100. } else
  101. ret = ircomm_open_tsap(self);
  102. if (ret < 0)
  103. return NULL;
  104. self->service_type = service_type;
  105. self->line = line;
  106. hashbin_insert(ircomm, (irda_queue_t *) self, line, NULL);
  107. ircomm_next_state(self, IRCOMM_IDLE);
  108. return self;
  109. }
  110. /*
  111.  * Function ircomm_close_instance (self)
  112.  *
  113.  *    Remove IrCOMM instance
  114.  *
  115.  */
  116. static int __ircomm_close(struct ircomm_cb *self)
  117. {
  118. IRDA_DEBUG(2, __FUNCTION__"()n");
  119. /* Disconnect link if any */
  120. ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, NULL, NULL);
  121. /* Remove TSAP */
  122. if (self->tsap) {
  123. irttp_close_tsap(self->tsap);
  124. self->tsap = NULL;
  125. }
  126. /* Remove LSAP */
  127. if (self->lsap) {
  128. irlmp_close_lsap(self->lsap);
  129. self->lsap = NULL;
  130. }
  131. self->magic = 0;
  132. kfree(self);
  133. return 0;
  134. }
  135. /*
  136.  * Function ircomm_close (self)
  137.  *
  138.  *    Closes and removes the specified IrCOMM instance
  139.  *
  140.  */
  141. int ircomm_close(struct ircomm_cb *self)
  142. {
  143. struct ircomm_cb *entry;
  144. ASSERT(self != NULL, return -EIO;);
  145. ASSERT(self->magic == IRCOMM_MAGIC, return -EIO;);
  146. IRDA_DEBUG(0, __FUNCTION__ "()n");
  147. entry = hashbin_remove(ircomm, self->line, NULL);
  148. ASSERT(entry == self, return -1;);
  149.         return __ircomm_close(self);
  150. }
  151. /*
  152.  * Function ircomm_connect_request (self, service_type)
  153.  *
  154.  *    Impl. of this function is differ from one of the reference. This
  155.  *    function does discovery as well as sending connect request
  156.  * 
  157.  */
  158. int ircomm_connect_request(struct ircomm_cb *self, __u8 dlsap_sel, 
  159.    __u32 saddr, __u32 daddr, struct sk_buff *skb,
  160.    __u8 service_type)
  161. {
  162. struct ircomm_info info;
  163. int ret;
  164. IRDA_DEBUG(2 , __FUNCTION__"()n");
  165. ASSERT(self != NULL, return -1;);
  166. ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
  167. self->service_type= service_type;
  168. info.dlsap_sel = dlsap_sel;
  169. info.saddr = saddr;
  170. info.daddr = daddr;
  171. ret = ircomm_do_event(self, IRCOMM_CONNECT_REQUEST, skb, &info);
  172. return ret;
  173. }
  174. /*
  175.  * Function ircomm_connect_indication (self, qos, skb)
  176.  *
  177.  *    Notify user layer about the incoming connection
  178.  *
  179.  */
  180. void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb,
  181.        struct ircomm_info *info)
  182. {
  183. int clen = 0;
  184. IRDA_DEBUG(2, __FUNCTION__ "()n");
  185. /* Check if the packet contains data on the control channel */
  186. if (skb->len > 0)
  187. clen = skb->data[0];
  188. /* 
  189.  * If there are any data hiding in the control channel, we must 
  190.  * deliver it first. The side effect is that the control channel 
  191.  * will be removed from the skb
  192.  */
  193. if (self->notify.connect_indication)
  194. self->notify.connect_indication(self->notify.instance, self, 
  195. info->qos, info->max_data_size,
  196. info->max_header_size, skb);
  197. else {
  198. IRDA_DEBUG(0, __FUNCTION__ "(), missing handlern");
  199. dev_kfree_skb(skb);
  200. }
  201. }
  202. /*
  203.  * Function ircomm_connect_response (self, userdata, max_sdu_size)
  204.  *
  205.  *    User accepts connection
  206.  *
  207.  */
  208. int ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata)
  209. {
  210. int ret;
  211. ASSERT(self != NULL, return -1;);
  212. ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
  213. IRDA_DEBUG(4, __FUNCTION__ "()n");
  214. ret = ircomm_do_event(self, IRCOMM_CONNECT_RESPONSE, userdata, NULL);
  215. return ret;
  216. }
  217. /*
  218.  * Function connect_confirm (self, skb)
  219.  *
  220.  *    Notify user layer that the link is now connected
  221.  *
  222.  */
  223. void ircomm_connect_confirm(struct ircomm_cb *self, struct sk_buff *skb,
  224.     struct ircomm_info *info)
  225. {
  226. IRDA_DEBUG(4, __FUNCTION__"()n");
  227. if (self->notify.connect_confirm )
  228. self->notify.connect_confirm(self->notify.instance,
  229.      self, info->qos, 
  230.      info->max_data_size,
  231.      info->max_header_size, skb);
  232. else {
  233. IRDA_DEBUG(0, __FUNCTION__ "(), missing handlern");
  234. dev_kfree_skb(skb);
  235. }
  236. }
  237. /*
  238.  * Function ircomm_data_request (self, userdata)
  239.  *
  240.  *    Send IrCOMM data to peer device
  241.  *
  242.  */
  243. int ircomm_data_request(struct ircomm_cb *self, struct sk_buff *skb)
  244. {
  245. int ret;
  246. IRDA_DEBUG(4, __FUNCTION__"()n");
  247. ASSERT(self != NULL, return -EFAULT;);
  248. ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;);
  249. ASSERT(skb != NULL, return -EFAULT;);
  250. ret = ircomm_do_event(self, IRCOMM_DATA_REQUEST, skb, NULL);
  251. return ret;
  252. }
  253. /*
  254.  * Function ircomm_data_indication (self, skb)
  255.  *
  256.  *    Data arrived, so deliver it to user
  257.  *
  258.  */
  259. void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb)
  260. {
  261. IRDA_DEBUG(4, __FUNCTION__"()n");
  262. ASSERT(skb->len > 0, return;);
  263. if (self->notify.data_indication)
  264. self->notify.data_indication(self->notify.instance, self, skb);
  265. else {
  266. IRDA_DEBUG(0, __FUNCTION__ "(), missing handlern");
  267. dev_kfree_skb(skb);
  268. }
  269. }
  270. /*
  271.  * Function ircomm_process_data (self, skb)
  272.  *
  273.  *    Data arrived which may contain control channel data
  274.  *
  275.  */
  276. void ircomm_process_data(struct ircomm_cb *self, struct sk_buff *skb)
  277. {
  278. int clen;
  279. ASSERT(skb->len > 0, return;);
  280. clen = skb->data[0];
  281. /* 
  282.  * If there are any data hiding in the control channel, we must 
  283.  * deliver it first. The side effect is that the control channel 
  284.  * will be removed from the skb
  285.  */
  286. if (clen > 0)
  287. ircomm_control_indication(self, skb, clen);
  288. /* Remove control channel from data channel */
  289. skb_pull(skb, clen+1);
  290. if (skb->len)
  291. ircomm_data_indication(self, skb);
  292. else {
  293. IRDA_DEBUG(4, __FUNCTION__ 
  294.    "(), data was control info only!n");
  295. dev_kfree_skb(skb);
  296. }
  297. }
  298. /*
  299.  * Function ircomm_control_request (self, params)
  300.  *
  301.  *    Send control data to peer device
  302.  *
  303.  */
  304. int ircomm_control_request(struct ircomm_cb *self, struct sk_buff *skb)
  305. {
  306. int ret;
  307. IRDA_DEBUG(2, __FUNCTION__"()n");
  308. ASSERT(self != NULL, return -EFAULT;);
  309. ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;);
  310. ASSERT(skb != NULL, return -EFAULT;);
  311. ret = ircomm_do_event(self, IRCOMM_CONTROL_REQUEST, skb, NULL);
  312. return ret;
  313. }
  314. /*
  315.  * Function ircomm_control_indication (self, skb)
  316.  *
  317.  *    Data has arrived on the control channel
  318.  *
  319.  */
  320. static void ircomm_control_indication(struct ircomm_cb *self, 
  321.       struct sk_buff *skb, int clen)
  322. {
  323. struct sk_buff *ctrl_skb;
  324. IRDA_DEBUG(2, __FUNCTION__"()n");
  325. ctrl_skb = skb_clone(skb, GFP_ATOMIC);
  326. if (!ctrl_skb)
  327. return;
  328. /* Remove data channel from control channel */
  329. skb_trim(ctrl_skb, clen+1);
  330. /* Use udata for delivering data on the control channel */
  331. if (self->notify.udata_indication)
  332. self->notify.udata_indication(self->notify.instance, self, 
  333.       ctrl_skb);
  334. else {
  335. IRDA_DEBUG(0, __FUNCTION__ "(), missing handlern");
  336. dev_kfree_skb(skb);
  337. }
  338. }
  339. /*
  340.  * Function ircomm_disconnect_request (self, userdata, priority)
  341.  *
  342.  *    User layer wants to disconnect the IrCOMM connection
  343.  *
  344.  */
  345. int ircomm_disconnect_request(struct ircomm_cb *self, struct sk_buff *userdata)
  346. {
  347. struct ircomm_info info;
  348. int ret;
  349. IRDA_DEBUG(2, __FUNCTION__"()n");
  350. ASSERT(self != NULL, return -1;);
  351. ASSERT(self->magic == IRCOMM_MAGIC, return -1;);
  352. ret = ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, userdata, 
  353.       &info);
  354. return ret;
  355. }
  356. /*
  357.  * Function disconnect_indication (self, skb)
  358.  *
  359.  *    Tell user that the link has been disconnected
  360.  *
  361.  */
  362. void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb,
  363.   struct ircomm_info *info)
  364. {
  365. IRDA_DEBUG(2, __FUNCTION__ "()n");
  366.        
  367. ASSERT(info != NULL, return;);
  368. if (self->notify.disconnect_indication) {
  369. self->notify.disconnect_indication(self->notify.instance, self,
  370.    info->reason, skb);
  371. } else {
  372. IRDA_DEBUG(0, __FUNCTION__ "(), missing handlern");
  373. dev_kfree_skb(skb);
  374. }
  375. }
  376. /*
  377.  * Function ircomm_flow_request (self, flow)
  378.  *
  379.  *    
  380.  *
  381.  */
  382. void ircomm_flow_request(struct ircomm_cb *self, LOCAL_FLOW flow)
  383. {
  384. IRDA_DEBUG(2, __FUNCTION__ "()n");
  385. ASSERT(self != NULL, return;);
  386. ASSERT(self->magic == IRCOMM_MAGIC, return;);
  387. if (self->service_type == IRCOMM_3_WIRE_RAW)
  388. return;
  389. irttp_flow_request(self->tsap, flow);
  390. }
  391. #ifdef CONFIG_PROC_FS
  392. /*
  393.  * Function ircomm_proc_read (buf, start, offset, len, unused)
  394.  *
  395.  *    
  396.  *
  397.  */
  398. int ircomm_proc_read(char *buf, char **start, off_t offset, int len)
  399. struct ircomm_cb *self;
  400. unsigned long flags;
  401. save_flags(flags);
  402. cli();
  403. len = 0;
  404. self = (struct ircomm_cb *) hashbin_get_first(ircomm);
  405. while (self != NULL) {
  406. ASSERT(self->magic == IRCOMM_MAGIC, return len;);
  407. if(self->line < 0x10)
  408. len += sprintf(buf+len, "ircomm%d", self->line);
  409. else
  410. len += sprintf(buf+len, "irlpt%d", self->line - 0x10);
  411. len += sprintf(buf+len, " state: %s, ",
  412.        ircomm_state[ self->state]);
  413. len += sprintf(buf+len, 
  414.        "slsap_sel: %#02x, dlsap_sel: %#02x, mode:",
  415.        self->slsap_sel, self->dlsap_sel); 
  416. if(self->service_type & IRCOMM_3_WIRE_RAW)
  417. len += sprintf(buf+len, " 3-wire-raw");
  418. if(self->service_type & IRCOMM_3_WIRE)
  419. len += sprintf(buf+len, " 3-wire");
  420. if(self->service_type & IRCOMM_9_WIRE)
  421. len += sprintf(buf+len, " 9-wire");
  422. if(self->service_type & IRCOMM_CENTRONICS)
  423. len += sprintf(buf+len, " Centronics");
  424. len += sprintf(buf+len, "n");
  425. self = (struct ircomm_cb *) hashbin_get_next(ircomm);
  426.   } 
  427. restore_flags(flags);
  428. return len;
  429. }
  430. #endif /* CONFIG_PROC_FS */
  431. #ifdef MODULE
  432. MODULE_AUTHOR("Dag Brattli <dag@brattli.net>");
  433. MODULE_DESCRIPTION("IrCOMM protocol");
  434. MODULE_LICENSE("GPL");
  435. int init_module(void) 
  436. {
  437. return ircomm_init();
  438. }
  439. void cleanup_module(void)
  440. {
  441. ircomm_cleanup();
  442. }
  443. #endif /* MODULE */