Merge branch 'master' of ssh://jolly@www.mISDN.org/var/git/lcr
[lcr.git] / chan_lcr.c
1 /*****************************************************************************\
2 **                                                                           **
3 ** Linux Call Router                                                         **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **                                                                           **
8 ** Asterisk socket client                                                    **
9 **                                                                           **
10 \*****************************************************************************/
11
12 /*
13
14 How does it work:
15
16 To connect, open a socket and send a MESSAGE_HELLO to admin socket with
17 the application name. This name is unique an can be used for routing calls.
18
19 To make a call, send a MESSAGE_NEWREF and a new reference is received.
20 When receiving a call, a new reference is received.
21 The reference is received with MESSAGE_NEWREF.
22
23 Make a MESSAGE_SETUP or receive a MESSAGE_SETUP with the reference.
24
25 To release call and reference, send or receive MESSAGE_RELEASE.
26 From that point on, the ref is not valid, so no other message may be sent
27 with that reference.
28
29 */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <stdarg.h>
35 #include <errno.h>
36 #include <sys/types.h>
37 #include <time.h>
38 #include <unistd.h>
39 #include <fcntl.h>
40 #include <sys/ioctl.h>
41 #include <sys/socket.h>
42 #include <sys/un.h>
43
44 #include <pthread.h>
45 #include <semaphore.h>
46
47 #include "extension.h"
48 #include "message.h"
49 #include "lcrsocket.h"
50 #include "cause.h"
51 #include "bchannel.h"
52 #include "chan_lcr.h"
53
54
55
56 #include <asterisk/module.h>
57 #include <asterisk/channel.h>
58 #include <asterisk/config.h>
59 #include <asterisk/logger.h>
60 #include <asterisk/pbx.h>
61 #include <asterisk/options.h>
62 #include <asterisk/io.h>
63 #include <asterisk/frame.h>
64 #include <asterisk/translate.h>
65 #include <asterisk/cli.h>
66 #include <asterisk/musiconhold.h>
67 #include <asterisk/dsp.h>
68 #include <asterisk/translate.h>
69 #include <asterisk/file.h>
70 #include <asterisk/callerid.h>
71 #include <asterisk/indications.h>
72 #include <asterisk/app.h>
73 #include <asterisk/features.h>
74 #include <asterisk/sched.h>
75
76 int lcr_debug=1;
77 int mISDN_created=1;
78
79
80 int lcr_sock = -1;
81
82 struct admin_list {
83         struct admin_list *next;
84         struct admin_msg msg;
85 } *admin_first = NULL;
86
87 /*
88  * channel and call instances
89  */
90 struct chan_call *call_first;
91
92 struct chan_call *find_call_ref(unsigned long ref)
93 {
94         struct chan_call *call = call_first;
95
96         while(call)
97         {
98                 if (call->ref == ref)
99                         break;
100                 call = call->next;
101         }
102         return(call);
103 }
104
105 struct chan_call *find_call_handle(unsigned long handle)
106 {
107         struct chan_call *call = call_first;
108
109         while(call)
110         {
111                 if (call->bchannel_handle == handle)
112                         break;
113                 call = call->next;
114         }
115         return(call);
116 }
117
118 struct chan_call *alloc_call(void)
119 {
120         struct chan_call **callp = &call_first;
121
122         while(*callp)
123                 callp = &((*callp)->next);
124
125         *callp = (struct chan_call *)malloc(sizeof(struct chan_call));
126         return(*callp);
127 }
128
129 void free_call(struct chan_call *call)
130 {
131         struct chan_call **temp = &call_first;
132
133         while(*temp)
134         {
135                 if (*temp == call)
136                 {
137                         *temp = (*temp)->next;
138                         free(call);
139                         return;
140                 }
141                 temp = &((*temp)->next);
142         }
143 }
144
145 unsigned short new_brige_id(void)
146 {
147         struct chan_call *call;
148         unsigned short id = 1;
149
150         /* search for lowest bridge id that is not in use and not 0 */
151         while(id)
152         {
153                 call = call_first;
154                 while(call)
155                 {
156                         if (call->bridge_id == id)
157                                 break;
158                         call = call->next;
159                 }
160                 if (!call)
161                         break;
162                 id++;
163         }
164         return(id);
165 }
166
167
168 /*
169  * receive bchannel data
170  */
171 void rx_data(struct bchannel *bchannel, unsigned char *data, int len)
172 {
173 }
174
175 void rx_dtmf(struct bchannel *bchannel, char tone)
176 {
177 }
178
179 /*
180  * enque message to LCR
181  */
182 int send_message(int message_type, unsigned long ref, union parameter *param)
183 {
184         struct admin_list *admin, **adminp;
185
186         adminp = &admin_first;
187         while(*adminp)
188                 adminp = &((*adminp)->next);
189         admin = (struct admin_list *)malloc(sizeof(struct admin_list));
190         *adminp = admin;
191
192         admin->msg.type = message_type;
193         admin->msg.ref = ref;
194         memcpy(&admin->msg.param, param, sizeof(union parameter));
195
196         return(0);
197 }
198
199 /*
200  * message received from LCR
201  */
202 int receive_message(int message_type, unsigned long ref, union parameter *param)
203 {
204         union parameter newparam;
205         struct bchannel *bchannel;
206         struct chan_call *call;
207
208         memset(&newparam, 0, sizeof(union parameter));
209
210         /* handle bchannel message*/
211         if (message_type == MESSAGE_BCHANNEL)
212         {
213                 switch(param->bchannel.type)
214                 {
215                         case BCHANNEL_ASSIGN:
216                         if ((bchannel = find_bchannel_handle(param->bchannel.handle)))
217                         {
218                                 fprintf(stderr, "error: bchannel handle %x already assigned.\n", (int)param->bchannel.handle);
219                                 return(-1);
220                         }
221                         /* create bchannel */
222                         bchannel = alloc_bchannel(param->bchannel.handle);
223                         if (!bchannel)
224                         {
225                                 fprintf(stderr, "error: alloc bchannel handle %x failed.\n", (int)param->bchannel.handle);
226                                 return(-1);
227                         }
228
229                         /* configure channel */
230                         bchannel->b_tx_gain = param->bchannel.tx_gain;
231                         bchannel->b_rx_gain = param->bchannel.rx_gain;
232                         strncpy(bchannel->b_pipeline, param->bchannel.pipeline, sizeof(bchannel->b_pipeline)-1);
233                         if (param->bchannel.crypt_len)
234                         {
235                                 bchannel->b_crypt_len = param->bchannel.crypt_len;
236                                 bchannel->b_crypt_type = param->bchannel.crypt_type;
237                                 memcpy(bchannel->b_crypt_key, param->bchannel.crypt, param->bchannel.crypt_len);
238                         }
239                         bchannel->b_txdata = 0;
240                         bchannel->b_dtmf = 1;
241                         bchannel->b_tx_dejitter = 1;
242
243                         /* in case, ref is not set, this bchannel instance must
244                          * be created until it is removed again by LCR */
245                         /* link to call */
246                         if ((call = find_call_ref(ref)))
247                         {
248                                 bchannel->ref = ref;
249                                 call->bchannel_handle = param->bchannel.handle;
250 #warning hier muesen alle stati gesetzt werden falls sie vor dem b-kanal verf├╝gbar waren
251                                 bchannel_join(bchannel, call->bridge_id);
252                         }
253                         if (bchannel_create(bchannel))
254                                 bchannel_activate(bchannel, 1);
255
256                         /* acknowledge */
257                         newparam.bchannel.type = BCHANNEL_ASSIGN_ACK;
258                         newparam.bchannel.handle = param->bchannel.handle;
259                         send_message(MESSAGE_BCHANNEL, 0, &newparam);
260                         break;
261
262                         case BCHANNEL_REMOVE:
263                         if (!(bchannel = find_bchannel_handle(param->bchannel.handle)))
264                         {
265                                 #warning alle fprintf nach ast_log
266                                 fprintf(stderr, "error: bchannel handle %x not assigned.\n", (int)param->bchannel.handle);
267                                 return(-1);
268                         }
269                         /* unlink from call */
270                         if ((call = find_call_ref(bchannel->ref)))
271                         {
272                                 call->bchannel_handle = 0;
273                         }
274                         /* destroy and remove bchannel */
275                         free_bchannel(bchannel);
276
277                         /* acknowledge */
278                         newparam.bchannel.type = BCHANNEL_REMOVE_ACK;
279                         newparam.bchannel.handle = param->bchannel.handle;
280                         send_message(MESSAGE_BCHANNEL, 0, &newparam);
281                         
282                         break;
283
284                         default:
285                         fprintf(stderr, "received unknown bchannel message %d\n", param->bchannel.type);
286                 }
287                 return(0);
288         }
289
290         /* handle new ref */
291         if (message_type == MESSAGE_NEWREF)
292         {
293                 if (param->direction)
294                 {
295                         /* new ref from lcr */
296                         if (!ref || find_call_ref(ref))
297                         {
298                                 fprintf(stderr, "illegal new ref %d received\n", ref);
299                                 return(-1);
300                         }
301                         call = alloc_call();
302                         call->ref = ref;
303                 } else
304                 {
305                         /* new ref, as requested from this remote application */
306                         call = find_call_ref(0);
307                         if (!call)
308                         {
309                                 /* send release, if ref does not exist */
310                                 newparam.disconnectinfo.cause = CAUSE_NORMAL;
311                                 newparam.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
312                                 send_message(MESSAGE_RELEASE, ref, &newparam);
313                                 return(0);
314                         }
315                         call->ref = ref;
316 #warning process call (send setup, if pending)
317                 }
318                 return(0);
319         }
320
321         /* check ref */
322         if (!ref)
323         {
324                 fprintf(stderr, "received message %d without ref\n", message_type);
325                 return(-1);
326         }
327         call = find_call_ref(ref);
328         if (!call)
329         {
330                 /* ignore ref that is not used (anymore) */
331                 return(0);
332         }
333
334         /* handle messages */
335         switch(message_type)
336         {
337                 case MESSAGE_SETUP:
338 #warning todo
339                 break;
340
341                 case MESSAGE_OVERLAP:
342 #warning todo
343                 break;
344
345                 case MESSAGE_PROCEEDING:
346 #warning todo
347                 break;
348
349                 case MESSAGE_ALERTING:
350 #warning todo
351                 break;
352
353                 case MESSAGE_CONNECT:
354 #warning todo
355                 break;
356
357                 case MESSAGE_DISCONNECT:
358 #warning todo
359                 break;
360
361                 case MESSAGE_RELEASE:
362 #warning todo
363                 free_call(call);
364                 return(0);
365
366                 case MESSAGE_INFORMATION:
367 #warning todo
368                 break;
369
370                 case MESSAGE_FACILITY:
371 #warning todo
372                 break;
373
374                 case MESSAGE_PATTERN:
375 #warning todo
376                 break;
377
378                 case MESSAGE_NOPATTERN:
379 #warning todo
380                 break;
381
382                 case MESSAGE_AUDIOPATH:
383 #warning todo
384                 break;
385
386                 default:
387 #warning unhandled
388         }
389         return(0);
390 }
391
392
393 /* asterisk handler
394  * warning! not thread safe
395  * returns -1 for socket error, 0 for no work, 1 for work
396  */
397 int handle_socket(void)
398 {
399         int work = 0;
400         int len;
401         struct admin_message msg;
402         struct admin_list *admin;
403
404         int sock;
405
406         #warning SOCKET FEHLT!
407         /* read from socket */
408         len = read(sock, &msg, sizeof(msg));
409         if (len == 0)
410         {
411                 printf("Socket closed\n");
412                 return(-1); // socket closed
413         }
414         if (len > 0)
415         {
416                 if (len != sizeof(msg))
417                 {
418                         fprintf(stderr, "Socket short read (%d)\n", len);
419                         return(-1); // socket error
420                 }
421                 if (msg.message != ADMIN_MESSAGE)
422                 {
423                         fprintf(stderr, "Socket received illegal message %d\n", msg.message);
424                         return(-1); // socket error
425                 }
426                 receive_message(msg.u.msg.type, msg.u.msg.ref, &msg.u.msg.param);
427                 printf("message received %d\n", msg.u.msg.type);
428                 work = 1;
429         } else
430         {
431                 if (errno != EWOULDBLOCK)
432                 {
433                         fprintf(stderr, "Socket error %d\n", errno);
434                         return(-1);
435                 }
436         }
437
438         /* write to socket */
439         if (!admin_first)
440                 return(work);
441         admin = admin_first;
442         len = write(sock, &admin->msg, sizeof(msg));
443         if (len == 0)
444         {
445                 printf("Socket closed\n");
446                 return(-1); // socket closed
447         }
448         if (len > 0)
449         {
450                 if (len != sizeof(msg))
451                 {
452                         fprintf(stderr, "Socket short write (%d)\n", len);
453                         return(-1); // socket error
454                 }
455                 /* free head */
456                 admin_first = admin->next;
457                 free(admin);
458
459                 work = 1;
460         } else
461         {
462                 if (errno != EWOULDBLOCK)
463                 {
464                         fprintf(stderr, "Socket error %d\n", errno);
465                         return(-1);
466                 }
467         }
468
469         return(work);
470 }
471
472 /*
473  * open and close socket
474  */
475 int open_socket(void)
476 {
477         int ret;
478         int sock;
479         char *socket_name = SOCKET_NAME;
480         int conn;
481         struct sockaddr_un sock_address;
482         unsigned long on = 1;
483         union parameter param;
484
485         /* open socket */
486         if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
487         {
488                 ast_log(LOG_ERROR, "Failed to create socket.\n");
489                 return(sock);
490         }
491
492         /* set socket address and name */
493         memset(&sock_address, 0, sizeof(sock_address));
494         sock_address.sun_family = PF_UNIX;
495         strcpy(sock_address.sun_path, socket_name);
496
497         /* connect socket */
498         if ((conn = connect(sock, (struct sockaddr *)&sock_address, SUN_LEN(&sock_address))) < 0)
499         {
500                 close(sock);
501                 ast_log(LOG_ERROR, "Failed to connect to socket \"%s\". Is LCR running?\n", sock_address.sun_path);
502                 return(conn);
503         }
504
505         /* set non-blocking io */
506         if ((ret = ioctl(sock, FIONBIO, (unsigned char *)(&on))) < 0)
507         {
508                 close(sock);
509                 ast_log(LOG_ERROR, "Failed to set socket into non-blocking IO.\n");
510                 return(ret);
511         }
512
513         /* enque hello message */
514         memset(&param, 0, sizeof(param));
515         strcpy(param.hello.application, "asterisk");
516         send_message(MESSAGE_HELLO, 0, &param);
517
518         return(sock);
519 }
520
521 void close_socket(int sock)
522 {
523         /* close socket */
524         if (socket >= 0)        
525                 close(sock);
526 }
527
528
529 void lcr_thread(void)
530 {
531         int work;
532
533         while(42)
534         {
535                 work = 0;
536
537                 /* handle socket */
538                 int ret = handle_socket();
539                 if (ret < 0)
540                         break;
541                 if (ret)
542                         work = 1;
543
544                 /* handle mISDN */
545                 ret = bchannel_handle();
546                 if (ret)
547                         work = 1;
548                 
549                 if (!work)
550                         usleep(30000);
551         }
552 }
553
554 static struct ast_channel *lcr_request(const char *type, int format, void *data, int *cause)
555 {
556
557 }
558
559
560 /* call from asterisk (new instance) */
561 static int lcr_call(struct ast_channel *ast, char *dest, int timeout)
562 {
563         struct lcr_pvt *lcr=ast->tech_pvt;
564
565         if (!lcr) return -1;
566
567         char buf[128];
568         char *port_str, *dad, *p;
569
570         ast_copy_string(buf, dest, sizeof(buf)-1);
571         p=buf;
572         port_str=strsep(&p, "/");
573         dad=strsep(&p, "/");
574
575         if (lcr_debug)
576                 ast_verbose("Call: ext:%s dest:(%s) -> dad(%s) \n", ast->exten,dest, dad);
577
578
579         return 0; 
580 }
581
582 static int lcr_answer(struct ast_channel *c)
583 {
584         struct lcr_pvt *lcr=c->tech_pvt;
585         return 0;
586 }
587
588 static int lcr_hangup(struct ast_channel *c)
589 {
590         struct lcr_pvt *lcr=c->tech_pvt;
591         c->tech_pvt=NULL;
592 }
593
594
595 static int lcr_write(struct ast_channel *c, struct ast_frame *f)
596 {
597         struct lcr_pvt *lcrm= c->tech_pvt;
598 }
599
600
601 static struct ast_frame *lcr_read(struct ast_channel *c)
602 {
603         struct lcr_pvt *lcr = c->tech_pvt;
604 }
605
606 static int lcr_indicate(struct ast_channel *c, int cond, const void *data, size_t datalen)
607 {
608         int res = -1;
609
610         switch (cond) {
611                 case AST_CONTROL_BUSY:
612                 case AST_CONTROL_CONGESTION:
613                 case AST_CONTROL_RINGING:
614                         return -1;
615                 case -1:
616                         return 0;
617
618                 case AST_CONTROL_VIDUPDATE:
619                         res = -1;
620                         break;
621                 case AST_CONTROL_HOLD:
622                         ast_verbose(" << Console Has Been Placed on Hold >> \n");
623                         //ast_moh_start(c, data, g->mohinterpret);
624                         break;
625                 case AST_CONTROL_UNHOLD:
626                         ast_verbose(" << Console Has Been Retrieved from Hold >> \n");
627                         //ast_moh_stop(c);
628                         break;
629
630                 default:
631                         ast_log(LOG_WARNING, "Don't know how to display condition %d on %s\n", cond, c->name);
632                         return -1;
633         }
634
635         return 0;
636 }
637
638 static struct ast_channel_tech lcr_tech = {
639         .type="lcr",
640         .description="Channel driver for connecting to Linux-Call-Router",
641         .capabilities=AST_FORMAT_ALAW,
642         .requester=lcr_request,
643 //      .send_digit=lcr_digit,
644         .call=lcr_call,
645 //      .bridge=lcr_bridge, 
646         .hangup=lcr_hangup,
647         .answer=lcr_answer,
648         .read=lcr_read,
649         .write=lcr_write,
650         .indicate=lcr_indicate,
651 //      .fixup=lcr_fixup,
652 //      .send_text=lcr_send_text,
653         .properties=0
654 };
655
656 /*
657  * cli
658  */
659 static int cli_show_lcr (int fd, int argc, char *argv[])
660 {
661 }
662
663 static int cli_show_calls (int fd, int argc, char *argv[])
664 {
665 }
666
667 static int cli_reload_routing (int fd, int argc, char *argv[])
668 {
669 }
670
671 static int cli_reload_interfaces (int fd, int argc, char *argv[])
672 {
673 }
674
675 static int cli_port_block (int fd, int argc, char *argv[])
676 {
677 }
678
679 static int cli_port_unblock (int fd, int argc, char *argv[])
680 {
681 }
682
683 static int cli_port_unload (int fd, int argc, char *argv[])
684 {
685 }
686
687 static struct ast_cli_entry cli_show_lcr =
688 { {"lcr", "show", "lcr", NULL},
689  lcr_show_lcr,
690  "Shows current states of LCR core",
691  "Usage: lcr show lcr\n",
692 };
693
694 static struct ast_cli_entry cli_show_calls =
695 { {"lcr", "show", "calls", NULL},
696  lcr_show_calls,
697  "Shows current calls made by LCR and Asterisk",
698  "Usage: lcr show calls\n",
699 };
700
701 static struct ast_cli_entry cli_reload_routing =
702 { {"lcr", "reload", "routing", NULL},
703  lcr_reload_routing,
704  "Reloads routing conf of LCR, current uncomplete calls will be disconnected",
705  "Usage: lcr reload routing\n",
706 };
707
708 static struct ast_cli_entry cli_reload_interfaces =
709 { {"lcr", "reload", "interfaces", NULL},
710  lcr_reload_interfaces,
711  "Reloads interfaces conf of LCR",
712  "Usage: lcr reload interfaces\n",
713 };
714
715 static struct ast_cli_entry cli_port_block =
716 { {"lcr", "port", "block", NULL},
717  lcr_port_block,
718  "Blocks LCR port for further calls",
719  "Usage: lcr port block \"<port>\"\n",
720 };
721
722 static struct ast_cli_entry cli_port_unblock =
723 { {"lcr", "port", "unblock", NULL},
724  lcr_port_unblock,
725  "Unblocks or loads LCR port, port is opened my mISDN",
726  "Usage: lcr port unblock \"<port>\"\n",
727 };
728
729 static struct ast_cli_entry cli_port_unload =
730 { {"lcr", "port", "unload", NULL},
731  lcr_port_unload,
732  "Unloads LCR port, port is closes by mISDN",
733  "Usage: lcr port unload \"<port>\"\n",
734 };
735
736
737 /*
738  * module loading and destruction
739  */
740 int load_module(void)
741 {
742 //      ast_mutex_init(&release_lock);
743
744 //      lcr_cfg_update_ptp();
745
746         if (!(lcr_sock = open_socket())) {
747                 ast_log(LOG_ERROR, "Unable to connect\n");
748                 lcr_sock = -1;
749                 /* continue with closed socket */
750         }
751
752         if (!bchannel_initialize()) {
753                 ast_log(LOG_ERROR, "Unable to open mISDN device\n");
754                 return -1;
755         }
756         mISDN_created = 1;
757
758         if (ast_channel_register(&lcr_tech)) {
759                 ast_log(LOG_ERROR, "Unable to register channel class\n");
760                 return -1;
761         }
762  
763 #if 0   
764         ast_cli_register(&cli_show_lcr);
765         ast_cli_register(&cli_show_calls);
766
767         ast_cli_register(&cli_reload_routing);
768         ast_cli_register(&cli_reload_interfaces);
769         ast_cli_register(&cli_port_block);
770         ast_cli_register(&cli_port_unblock);
771         ast_cli_register(&cli_port_unload);
772   
773         ast_register_application("misdn_set_opt", misdn_set_opt_exec, "misdn_set_opt",
774                                  "misdn_set_opt(:<opt><optarg>:<opt><optarg>..):\n"
775                                  "Sets mISDN opts. and optargs\n"
776                                  "\n"
777                                  "The available options are:\n"
778                                  "    d - Send display text on called phone, text is the optparam\n"
779                                  "    n - don't detect dtmf tones on called channel\n"
780                                  "    h - make digital outgoing call\n" 
781                                  "    c - make crypted outgoing call, param is keyindex\n"
782                                  "    e - perform echo cancelation on this channel,\n"
783                                  "        takes taps as arguments (32,64,128,256)\n"
784                                  "    s - send Non Inband DTMF as inband\n"
785                                  "   vr - rxgain control\n"
786                                  "   vt - txgain control\n"
787                 );
788
789         
790         lcr_cfg_get( 0, LCR_GEN_TRACEFILE, global_tracefile, BUFFERSIZE);
791
792         chan_lcr_log(0, 0, "-- mISDN Channel Driver Registred -- (BE AWARE THIS DRIVER IS EXPERIMENTAL!)\n");
793 =======
794         //lcr_cfg_get( 0, LCR_GEN_TRACEFILE, global_tracefile, BUFFERSIZE);
795 #endif
796
797         return 0;
798 }
799
800 int unload_module(void)
801 {
802         /* First, take us out of the channel loop */
803         ast_log(LOG_VERBOSE, "-- Unregistering mISDN Channel Driver --\n");
804         
805         
806         ast_channel_unregister(&lcr_tech);
807
808         if (mISDN_created) {
809                 bchannel_deinitialize();
810                 mISDN_created = 0;
811         }
812
813         if (lcr_sock >= 0) {
814                 close(lcr_sock);
815                 lcr_sock = -1;
816         }
817
818         return 0;
819 }
820
821 static int reload_module(void)
822 {
823 //      reload_config();
824         return 0;
825 }
826
827
828 ast_mutex_t usecnt_lock;
829 int usecnt;
830
831 int usecount(void)
832 {
833         int res;
834         ast_mutex_lock(&usecnt_lock);
835         res = usecnt;
836         ast_mutex_unlock(&usecnt_lock);
837         return res;
838 }
839
840
841 char *desc="Channel driver for lcr";
842
843 char *description(void)
844 {
845         return desc;
846 }
847
848 char *key(void)
849 {
850         return ASTERISK_GPL_KEY;
851 }
852
853 #define AST_MODULE "chan_lcr"
854 AST_MODULE_INFO(ASTERISK_GPL_KEY,
855                                 AST_MODFLAG_DEFAULT,
856                                 "Channel driver for lcr",
857                                 .load = load_module,
858                                 .unload = unload_module,
859                                 .reload = reload_module,
860                            );
861