i4l.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. /*
  2. * Stuff used by all variants of the driver
  3. *
  4. * Copyright (c) 2001 by Stefan Eilers (Eilers.Stefan@epost.de),
  5. * Hansjoerg Lipp (hjlipp@web.de),
  6. * Tilman Schmidt (tilman@imap.cc).
  7. *
  8. * =====================================================================
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License as
  11. * published by the Free Software Foundation; either version 2 of
  12. * the License, or (at your option) any later version.
  13. * =====================================================================
  14. * ToDo: ...
  15. * =====================================================================
  16. * Version: $Id: i4l.c,v 1.3.2.9 2006/02/04 18:28:16 hjlipp Exp $
  17. * =====================================================================
  18. */
  19. #include "gigaset.h"
  20. /* == Handling of I4L IO ============================================================================*/
  21. /* writebuf_from_LL
  22. * called by LL to transmit data on an open channel
  23. * inserts the buffer data into the send queue and starts the transmission
  24. * Note that this operation must not sleep!
  25. * When the buffer is processed completely, gigaset_skb_sent() should be called.
  26. * parameters:
  27. * driverID driver ID as assigned by LL
  28. * channel channel number
  29. * ack if != 0 LL wants to be notified on completion via statcallb(ISDN_STAT_BSENT)
  30. * skb skb containing data to send
  31. * return value:
  32. * number of accepted bytes
  33. * 0 if temporarily unable to accept data (out of buffer space)
  34. * <0 on error (eg. -EINVAL)
  35. */
  36. static int writebuf_from_LL(int driverID, int channel, int ack, struct sk_buff *skb)
  37. {
  38. struct cardstate *cs;
  39. struct bc_state *bcs;
  40. unsigned len;
  41. unsigned skblen;
  42. if (!(cs = gigaset_get_cs_by_id(driverID))) {
  43. err("%s: invalid driver ID (%d)", __func__, driverID);
  44. return -ENODEV;
  45. }
  46. if (channel < 0 || channel >= cs->channels) {
  47. err("%s: invalid channel ID (%d)", __func__, channel);
  48. return -ENODEV;
  49. }
  50. bcs = &cs->bcs[channel];
  51. len = skb->len;
  52. dbg(DEBUG_LLDATA,
  53. "Receiving data from LL (id: %d, channel: %d, ack: %d, size: %d)",
  54. driverID, channel, ack, len);
  55. if (!len) {
  56. if (ack)
  57. warn("not ACKing empty packet from LL");
  58. return 0;
  59. }
  60. if (len > MAX_BUF_SIZE) {
  61. err("%s: packet too large (%d bytes)", __func__, channel);
  62. return -EINVAL;
  63. }
  64. if (!atomic_read(&cs->connected))
  65. return -ENODEV;
  66. skblen = ack ? len : 0;
  67. skb->head[0] = skblen & 0xff;
  68. skb->head[1] = skblen >> 8;
  69. dbg(DEBUG_MCMD, "skb: len=%u, skblen=%u: %02x %02x", len, skblen,
  70. (unsigned) skb->head[0], (unsigned) skb->head[1]);
  71. /* pass to device-specific module */
  72. return cs->ops->send_skb(bcs, skb);
  73. }
  74. void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb)
  75. {
  76. unsigned len;
  77. isdn_ctrl response;
  78. ++bcs->trans_up;
  79. if (skb->len)
  80. warn("%s: skb->len==%d", __func__, skb->len);
  81. len = (unsigned char) skb->head[0] |
  82. (unsigned) (unsigned char) skb->head[1] << 8;
  83. if (len) {
  84. dbg(DEBUG_MCMD,
  85. "Acknowledge sending to LL (id: %d, channel: %d size: %u)",
  86. bcs->cs->myid, bcs->channel, len);
  87. response.driver = bcs->cs->myid;
  88. response.command = ISDN_STAT_BSENT;
  89. response.arg = bcs->channel;
  90. response.parm.length = len;
  91. bcs->cs->iif.statcallb(&response);
  92. }
  93. }
  94. EXPORT_SYMBOL_GPL(gigaset_skb_sent);
  95. /* This function will be called by LL to send commands
  96. * NOTE: LL ignores the returned value, for commands other than ISDN_CMD_IOCTL,
  97. * so don't put too much effort into it.
  98. */
  99. static int command_from_LL(isdn_ctrl *cntrl)
  100. {
  101. struct cardstate *cs = gigaset_get_cs_by_id(cntrl->driver);
  102. //isdn_ctrl response;
  103. //unsigned long flags;
  104. struct bc_state *bcs;
  105. int retval = 0;
  106. struct setup_parm *sp;
  107. //dbg(DEBUG_ANY, "Gigaset_HW: Receiving command");
  108. gigaset_debugdrivers();
  109. /* Terminate this call if no device is present. Bt if the command is "ISDN_CMD_LOCK" or
  110. * "ISDN_CMD_UNLOCK" then execute it due to the fact that they are device independent !
  111. */
  112. //FIXME "remove test for &connected"
  113. if ((!cs || !atomic_read(&cs->connected))) {
  114. warn("LL tried to access unknown device with nr. %d",
  115. cntrl->driver);
  116. return -ENODEV;
  117. }
  118. switch (cntrl->command) {
  119. case ISDN_CMD_IOCTL:
  120. dbg(DEBUG_ANY, "ISDN_CMD_IOCTL (driver:%d,arg: %ld)",
  121. cntrl->driver, cntrl->arg);
  122. warn("ISDN_CMD_IOCTL is not supported.");
  123. return -EINVAL;
  124. case ISDN_CMD_DIAL:
  125. dbg(DEBUG_ANY, "ISDN_CMD_DIAL (driver: %d, channel: %ld, "
  126. "phone: %s,ownmsn: %s, si1: %d, si2: %d)",
  127. cntrl->driver, cntrl->arg,
  128. cntrl->parm.setup.phone, cntrl->parm.setup.eazmsn,
  129. cntrl->parm.setup.si1, cntrl->parm.setup.si2);
  130. if (cntrl->arg >= cs->channels) {
  131. err("invalid channel (%d)", (int) cntrl->arg);
  132. return -EINVAL;
  133. }
  134. bcs = cs->bcs + cntrl->arg;
  135. if (!gigaset_get_channel(bcs)) {
  136. err("channel not free");
  137. return -EBUSY;
  138. }
  139. sp = kmalloc(sizeof *sp, GFP_ATOMIC);
  140. if (!sp) {
  141. gigaset_free_channel(bcs);
  142. err("ISDN_CMD_DIAL: out of memory");
  143. return -ENOMEM;
  144. }
  145. *sp = cntrl->parm.setup;
  146. if (!gigaset_add_event(cs, &bcs->at_state, EV_DIAL, sp,
  147. atomic_read(&bcs->at_state.seq_index),
  148. NULL)) {
  149. //FIXME what should we do?
  150. kfree(sp);
  151. gigaset_free_channel(bcs);
  152. return -ENOMEM;
  153. }
  154. dbg(DEBUG_CMD, "scheduling DIAL");
  155. gigaset_schedule_event(cs);
  156. break;
  157. case ISDN_CMD_ACCEPTD: //FIXME
  158. dbg(DEBUG_ANY, "ISDN_CMD_ACCEPTD");
  159. if (cntrl->arg >= cs->channels) {
  160. err("invalid channel (%d)", (int) cntrl->arg);
  161. return -EINVAL;
  162. }
  163. if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg].at_state,
  164. EV_ACCEPT, NULL, 0, NULL)) {
  165. //FIXME what should we do?
  166. return -ENOMEM;
  167. }
  168. dbg(DEBUG_CMD, "scheduling ACCEPT");
  169. gigaset_schedule_event(cs);
  170. break;
  171. case ISDN_CMD_ACCEPTB:
  172. dbg(DEBUG_ANY, "ISDN_CMD_ACCEPTB");
  173. break;
  174. case ISDN_CMD_HANGUP:
  175. dbg(DEBUG_ANY,
  176. "ISDN_CMD_HANGUP (channel: %d)", (int) cntrl->arg);
  177. if (cntrl->arg >= cs->channels) {
  178. err("ISDN_CMD_HANGUP: invalid channel (%u)",
  179. (unsigned) cntrl->arg);
  180. return -EINVAL;
  181. }
  182. if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg].at_state,
  183. EV_HUP, NULL, 0, NULL)) {
  184. //FIXME what should we do?
  185. return -ENOMEM;
  186. }
  187. dbg(DEBUG_CMD, "scheduling HUP");
  188. gigaset_schedule_event(cs);
  189. break;
  190. case ISDN_CMD_CLREAZ: /* Do not signal incoming signals */ //FIXME
  191. dbg(DEBUG_ANY, "ISDN_CMD_CLREAZ");
  192. break;
  193. case ISDN_CMD_SETEAZ: /* Signal incoming calls for given MSN */ //FIXME
  194. dbg(DEBUG_ANY,
  195. "ISDN_CMD_SETEAZ (id:%d, channel: %ld, number: %s)",
  196. cntrl->driver, cntrl->arg, cntrl->parm.num);
  197. break;
  198. case ISDN_CMD_SETL2: /* Set L2 to given protocol */
  199. dbg(DEBUG_ANY, "ISDN_CMD_SETL2 (Channel: %ld, Proto: %lx)",
  200. cntrl->arg & 0xff, (cntrl->arg >> 8));
  201. if ((cntrl->arg & 0xff) >= cs->channels) {
  202. err("invalid channel (%u)",
  203. (unsigned) cntrl->arg & 0xff);
  204. return -EINVAL;
  205. }
  206. if (!gigaset_add_event(cs, &cs->bcs[cntrl->arg & 0xff].at_state,
  207. EV_PROTO_L2, NULL, cntrl->arg >> 8,
  208. NULL)) {
  209. //FIXME what should we do?
  210. return -ENOMEM;
  211. }
  212. dbg(DEBUG_CMD, "scheduling PROTO_L2");
  213. gigaset_schedule_event(cs);
  214. break;
  215. case ISDN_CMD_SETL3: /* Set L3 to given protocol */
  216. dbg(DEBUG_ANY, "ISDN_CMD_SETL3 (Channel: %ld, Proto: %lx)",
  217. cntrl->arg & 0xff, (cntrl->arg >> 8));
  218. if ((cntrl->arg & 0xff) >= cs->channels) {
  219. err("invalid channel (%u)",
  220. (unsigned) cntrl->arg & 0xff);
  221. return -EINVAL;
  222. }
  223. if (cntrl->arg >> 8 != ISDN_PROTO_L3_TRANS) {
  224. err("invalid protocol %lu", cntrl->arg >> 8);
  225. return -EINVAL;
  226. }
  227. break;
  228. case ISDN_CMD_PROCEED:
  229. dbg(DEBUG_ANY, "ISDN_CMD_PROCEED"); //FIXME
  230. break;
  231. case ISDN_CMD_ALERT:
  232. dbg(DEBUG_ANY, "ISDN_CMD_ALERT"); //FIXME
  233. if (cntrl->arg >= cs->channels) {
  234. err("invalid channel (%d)", (int) cntrl->arg);
  235. return -EINVAL;
  236. }
  237. //bcs = cs->bcs + cntrl->arg;
  238. //bcs->proto2 = -1;
  239. // FIXME
  240. break;
  241. case ISDN_CMD_REDIR:
  242. dbg(DEBUG_ANY, "ISDN_CMD_REDIR"); //FIXME
  243. break;
  244. case ISDN_CMD_PROT_IO:
  245. dbg(DEBUG_ANY, "ISDN_CMD_PROT_IO");
  246. break;
  247. case ISDN_CMD_FAXCMD:
  248. dbg(DEBUG_ANY, "ISDN_CMD_FAXCMD");
  249. break;
  250. case ISDN_CMD_GETL2:
  251. dbg(DEBUG_ANY, "ISDN_CMD_GETL2");
  252. break;
  253. case ISDN_CMD_GETL3:
  254. dbg(DEBUG_ANY, "ISDN_CMD_GETL3");
  255. break;
  256. case ISDN_CMD_GETEAZ:
  257. dbg(DEBUG_ANY, "ISDN_CMD_GETEAZ");
  258. break;
  259. case ISDN_CMD_SETSIL:
  260. dbg(DEBUG_ANY, "ISDN_CMD_SETSIL");
  261. break;
  262. case ISDN_CMD_GETSIL:
  263. dbg(DEBUG_ANY, "ISDN_CMD_GETSIL");
  264. break;
  265. default:
  266. err("unknown command %d from LL",
  267. cntrl->command);
  268. return -EINVAL;
  269. }
  270. return retval;
  271. }
  272. void gigaset_i4l_cmd(struct cardstate *cs, int cmd)
  273. {
  274. isdn_ctrl command;
  275. command.driver = cs->myid;
  276. command.command = cmd;
  277. command.arg = 0;
  278. cs->iif.statcallb(&command);
  279. }
  280. void gigaset_i4l_channel_cmd(struct bc_state *bcs, int cmd)
  281. {
  282. isdn_ctrl command;
  283. command.driver = bcs->cs->myid;
  284. command.command = cmd;
  285. command.arg = bcs->channel;
  286. bcs->cs->iif.statcallb(&command);
  287. }
  288. int gigaset_isdn_setup_dial(struct at_state_t *at_state, void *data)
  289. {
  290. struct bc_state *bcs = at_state->bcs;
  291. unsigned proto;
  292. const char *bc;
  293. size_t length[AT_NUM];
  294. size_t l;
  295. int i;
  296. struct setup_parm *sp = data;
  297. switch (bcs->proto2) {
  298. case ISDN_PROTO_L2_HDLC:
  299. proto = 1; /* 0: Bitsynchron, 1: HDLC, 2: voice */
  300. break;
  301. case ISDN_PROTO_L2_TRANS:
  302. proto = 2; /* 0: Bitsynchron, 1: HDLC, 2: voice */
  303. break;
  304. default:
  305. err("invalid protocol: %u", bcs->proto2);
  306. return -EINVAL;
  307. }
  308. switch (sp->si1) {
  309. case 1: /* audio */
  310. bc = "9090A3"; /* 3.1 kHz audio, A-law */
  311. break;
  312. case 7: /* data */
  313. default: /* hope the app knows what it is doing */
  314. bc = "8890"; /* unrestricted digital information */
  315. }
  316. //FIXME add missing si1 values from 1TR6, inspect si2, set HLC/LLC
  317. length[AT_DIAL ] = 1 + strlen(sp->phone) + 1 + 1;
  318. l = strlen(sp->eazmsn);
  319. length[AT_MSN ] = l ? 6 + l + 1 + 1 : 0;
  320. length[AT_BC ] = 5 + strlen(bc) + 1 + 1;
  321. length[AT_PROTO] = 6 + 1 + 1 + 1; /* proto: 1 character */
  322. length[AT_ISO ] = 6 + 1 + 1 + 1; /* channel: 1 character */
  323. length[AT_TYPE ] = 6 + 1 + 1 + 1; /* call type: 1 character */
  324. length[AT_HLC ] = 0;
  325. for (i = 0; i < AT_NUM; ++i) {
  326. kfree(bcs->commands[i]);
  327. bcs->commands[i] = NULL;
  328. if (length[i] &&
  329. !(bcs->commands[i] = kmalloc(length[i], GFP_ATOMIC))) {
  330. err("out of memory");
  331. return -ENOMEM;
  332. }
  333. }
  334. /* type = 1: extern, 0: intern, 2: recall, 3: door, 4: centrex */
  335. if (sp->phone[0] == '*' && sp->phone[1] == '*') {
  336. /* internal call: translate ** prefix to CTP value */
  337. snprintf(bcs->commands[AT_DIAL], length[AT_DIAL],
  338. "D%s\r", sp->phone+2);
  339. strncpy(bcs->commands[AT_TYPE], "^SCTP=0\r", length[AT_TYPE]);
  340. } else {
  341. snprintf(bcs->commands[AT_DIAL], length[AT_DIAL],
  342. "D%s\r", sp->phone);
  343. strncpy(bcs->commands[AT_TYPE], "^SCTP=1\r", length[AT_TYPE]);
  344. }
  345. if (bcs->commands[AT_MSN])
  346. snprintf(bcs->commands[AT_MSN], length[AT_MSN], "^SMSN=%s\r", sp->eazmsn);
  347. snprintf(bcs->commands[AT_BC ], length[AT_BC ], "^SBC=%s\r", bc);
  348. snprintf(bcs->commands[AT_PROTO], length[AT_PROTO], "^SBPR=%u\r", proto);
  349. snprintf(bcs->commands[AT_ISO ], length[AT_ISO ], "^SISO=%u\r", (unsigned)bcs->channel + 1);
  350. return 0;
  351. }
  352. int gigaset_isdn_setup_accept(struct at_state_t *at_state)
  353. {
  354. unsigned proto;
  355. size_t length[AT_NUM];
  356. int i;
  357. struct bc_state *bcs = at_state->bcs;
  358. switch (bcs->proto2) {
  359. case ISDN_PROTO_L2_HDLC:
  360. proto = 1; /* 0: Bitsynchron, 1: HDLC, 2: voice */
  361. break;
  362. case ISDN_PROTO_L2_TRANS:
  363. proto = 2; /* 0: Bitsynchron, 1: HDLC, 2: voice */
  364. break;
  365. default:
  366. err("invalid protocol: %u", bcs->proto2);
  367. return -EINVAL;
  368. }
  369. length[AT_DIAL ] = 0;
  370. length[AT_MSN ] = 0;
  371. length[AT_BC ] = 0;
  372. length[AT_PROTO] = 6 + 1 + 1 + 1; /* proto: 1 character */
  373. length[AT_ISO ] = 6 + 1 + 1 + 1; /* channel: 1 character */
  374. length[AT_TYPE ] = 0;
  375. length[AT_HLC ] = 0;
  376. for (i = 0; i < AT_NUM; ++i) {
  377. kfree(bcs->commands[i]);
  378. bcs->commands[i] = NULL;
  379. if (length[i] &&
  380. !(bcs->commands[i] = kmalloc(length[i], GFP_ATOMIC))) {
  381. err("out of memory");
  382. return -ENOMEM;
  383. }
  384. }
  385. snprintf(bcs->commands[AT_PROTO], length[AT_PROTO], "^SBPR=%u\r", proto);
  386. snprintf(bcs->commands[AT_ISO ], length[AT_ISO ], "^SISO=%u\r", (unsigned) bcs->channel + 1);
  387. return 0;
  388. }
  389. int gigaset_isdn_icall(struct at_state_t *at_state)
  390. {
  391. struct cardstate *cs = at_state->cs;
  392. struct bc_state *bcs = at_state->bcs;
  393. isdn_ctrl response;
  394. int retval;
  395. /* fill ICALL structure */
  396. response.parm.setup.si1 = 0; /* default: unknown */
  397. response.parm.setup.si2 = 0;
  398. response.parm.setup.screen = 0; //FIXME how to set these?
  399. response.parm.setup.plan = 0;
  400. if (!at_state->str_var[STR_ZBC]) {
  401. /* no BC (internal call): assume speech, A-law */
  402. response.parm.setup.si1 = 1;
  403. } else if (!strcmp(at_state->str_var[STR_ZBC], "8890")) {
  404. /* unrestricted digital information */
  405. response.parm.setup.si1 = 7;
  406. } else if (!strcmp(at_state->str_var[STR_ZBC], "8090A3")) {
  407. /* speech, A-law */
  408. response.parm.setup.si1 = 1;
  409. } else if (!strcmp(at_state->str_var[STR_ZBC], "9090A3")) {
  410. /* 3,1 kHz audio, A-law */
  411. response.parm.setup.si1 = 1;
  412. response.parm.setup.si2 = 2;
  413. } else {
  414. warn("RING ignored - unsupported BC %s",
  415. at_state->str_var[STR_ZBC]);
  416. return ICALL_IGNORE;
  417. }
  418. if (at_state->str_var[STR_NMBR]) {
  419. strncpy(response.parm.setup.phone, at_state->str_var[STR_NMBR],
  420. sizeof response.parm.setup.phone - 1);
  421. response.parm.setup.phone[sizeof response.parm.setup.phone - 1] = 0;
  422. } else
  423. response.parm.setup.phone[0] = 0;
  424. if (at_state->str_var[STR_ZCPN]) {
  425. strncpy(response.parm.setup.eazmsn, at_state->str_var[STR_ZCPN],
  426. sizeof response.parm.setup.eazmsn - 1);
  427. response.parm.setup.eazmsn[sizeof response.parm.setup.eazmsn - 1] = 0;
  428. } else
  429. response.parm.setup.eazmsn[0] = 0;
  430. if (!bcs) {
  431. notice("no channel for incoming call");
  432. dbg(DEBUG_CMD, "Sending ICALLW");
  433. response.command = ISDN_STAT_ICALLW;
  434. response.arg = 0; //FIXME
  435. } else {
  436. dbg(DEBUG_CMD, "Sending ICALL");
  437. response.command = ISDN_STAT_ICALL;
  438. response.arg = bcs->channel; //FIXME
  439. }
  440. response.driver = cs->myid;
  441. retval = cs->iif.statcallb(&response);
  442. dbg(DEBUG_CMD, "Response: %d", retval);
  443. switch (retval) {
  444. case 0: /* no takers */
  445. return ICALL_IGNORE;
  446. case 1: /* alerting */
  447. bcs->chstate |= CHS_NOTIFY_LL;
  448. return ICALL_ACCEPT;
  449. case 2: /* reject */
  450. return ICALL_REJECT;
  451. case 3: /* incomplete */
  452. warn("LL requested unsupported feature: Incomplete Number");
  453. return ICALL_IGNORE;
  454. case 4: /* proceeding */
  455. /* Gigaset will send ALERTING anyway.
  456. * There doesn't seem to be a way to avoid this.
  457. */
  458. return ICALL_ACCEPT;
  459. case 5: /* deflect */
  460. warn("LL requested unsupported feature: Call Deflection");
  461. return ICALL_IGNORE;
  462. default:
  463. err("LL error %d on ICALL", retval);
  464. return ICALL_IGNORE;
  465. }
  466. }
  467. /* Set Callback function pointer */
  468. int gigaset_register_to_LL(struct cardstate *cs, const char *isdnid)
  469. {
  470. isdn_if *iif = &cs->iif;
  471. dbg(DEBUG_ANY, "Register driver capabilities to LL");
  472. //iif->id[sizeof(iif->id) - 1]=0;
  473. //strncpy(iif->id, isdnid, sizeof(iif->id) - 1);
  474. if (snprintf(iif->id, sizeof iif->id, "%s_%u", isdnid, cs->minor_index)
  475. >= sizeof iif->id)
  476. return -ENOMEM; //FIXME EINVAL/...??
  477. iif->owner = THIS_MODULE;
  478. iif->channels = cs->channels; /* I am supporting just one channel *//* I was supporting...*/
  479. iif->maxbufsize = MAX_BUF_SIZE;
  480. iif->features = ISDN_FEATURE_L2_TRANS | /* Our device is very advanced, therefore */
  481. ISDN_FEATURE_L2_HDLC |
  482. #ifdef GIG_X75
  483. ISDN_FEATURE_L2_X75I |
  484. #endif
  485. ISDN_FEATURE_L3_TRANS |
  486. ISDN_FEATURE_P_EURO;
  487. iif->hl_hdrlen = HW_HDR_LEN; /* Area for storing ack */
  488. iif->command = command_from_LL;
  489. iif->writebuf_skb = writebuf_from_LL;
  490. iif->writecmd = NULL; /* Don't support isdnctrl */
  491. iif->readstat = NULL; /* Don't support isdnctrl */
  492. iif->rcvcallb_skb = NULL; /* Will be set by LL */
  493. iif->statcallb = NULL; /* Will be set by LL */
  494. if (!register_isdn(iif))
  495. return 0;
  496. cs->myid = iif->channels; /* Set my device id */
  497. return 1;
  498. }