blob: 6802a1e85814b488f2ff2d0e4fd60fbb1cf2a350 [file] [log] [blame]
Matthew Fredricksond105e202010-02-16 22:07:04 +01001/* OpenBSC Abis input driver for DAHDI */
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +01002
Harald Welteba0db5b2011-02-04 21:33:14 +01003/* (C) 2008-2011 by Harald Welte <laforge@gnumonks.org>
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +01004 * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
Matthew Fredricksond105e202010-02-16 22:07:04 +01005 * (C) 2010 by Digium and Matthew Fredrickson <creslin@digium.com>
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +01006 *
7 * All Rights Reserved
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 */
24
Harald Weltec08e8be2011-03-04 13:53:51 +010025#include "../../../bscconfig.h"
Harald Welteca17ef82011-02-05 15:13:27 +010026
27#ifdef HAVE_DAHDI_USER_H
28
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +010029#include <stdio.h>
30#include <unistd.h>
31#include <stdlib.h>
32#include <errno.h>
33#include <string.h>
34#include <time.h>
35#include <sys/fcntl.h>
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +010036#include <sys/socket.h>
37#include <sys/ioctl.h>
38#include <arpa/inet.h>
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -050039#include <dahdi/user.h>
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +010040
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010041#include <osmocom/core/select.h>
42#include <osmocom/core/msgb.h>
Harald Welte5da9b522011-08-11 12:58:52 +020043#include <osmocom/core/rate_ctr.h>
44
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +010045#include <openbsc/debug.h>
46#include <openbsc/gsm_data.h>
47#include <openbsc/abis_nm.h>
48#include <openbsc/abis_rsl.h>
49#include <openbsc/subchan_demux.h>
50#include <openbsc/e1_input.h>
Harald Weltef338a032011-01-14 15:55:42 +010051#include <openbsc/signal.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010052#include <osmocom/core/talloc.h>
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +010053
Matthew Fredricksonb1cb8eb2010-02-17 19:25:39 +010054#include "lapd.h"
55
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +010056#define TS1_ALLOC_SIZE 300
57
Harald Welte44f04da2011-02-13 14:19:26 +010058/* Corresponds to dahdi/user.h, only PRI related events */
59static const struct value_string dahdi_evt_names[] = {
60 { DAHDI_EVENT_NONE, "NONE" },
61 { DAHDI_EVENT_ALARM, "ALARM" },
62 { DAHDI_EVENT_NOALARM, "NOALARM" },
63 { DAHDI_EVENT_ABORT, "HDLC ABORT" },
64 { DAHDI_EVENT_OVERRUN, "HDLC OVERRUN" },
65 { DAHDI_EVENT_BADFCS, "HDLC BAD FCS" },
66 { DAHDI_EVENT_REMOVED, "REMOVED" },
67 { 0, NULL }
68};
69
70static void handle_dahdi_exception(struct e1inp_ts *ts)
71{
72 int rc, evt;
Harald Welte5da9b522011-08-11 12:58:52 +020073 struct e1inp_line *line = ts->line;
Harald Welte174a51a2011-02-13 14:26:54 +010074 struct input_signal_data isd;
Harald Welte44f04da2011-02-13 14:19:26 +010075
76 rc = ioctl(ts->driver.dahdi.fd.fd, DAHDI_GETEVENT, &evt);
77 if (rc < 0)
78 return;
79
80 LOGP(DMI, LOGL_NOTICE, "Line %u(%s) / TS %u DAHDI EVENT %s\n",
81 ts->line->num, ts->line->name, ts->num,
82 get_value_string(dahdi_evt_names, evt));
83
Harald Welte174a51a2011-02-13 14:26:54 +010084 isd.line = ts->line;
85
Harald Welte44f04da2011-02-13 14:19:26 +010086 switch (evt) {
87 case DAHDI_EVENT_ALARM:
Harald Welte174a51a2011-02-13 14:26:54 +010088 /* we should notify the code that the line is gone */
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +020089 osmo_signal_dispatch(SS_INPUT, S_INP_LINE_ALARM, &isd);
Harald Welte5da9b522011-08-11 12:58:52 +020090 rate_ctr_inc(&line->rate_ctr->ctr[E1I_CTR_ALARM]);
Harald Welte44f04da2011-02-13 14:19:26 +010091 break;
92 case DAHDI_EVENT_NOALARM:
Harald Welte174a51a2011-02-13 14:26:54 +010093 /* alarm has gone, we should re-start the SABM requests */
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +020094 osmo_signal_dispatch(SS_INPUT, S_INP_LINE_NOALARM, &isd);
Harald Welte44f04da2011-02-13 14:19:26 +010095 break;
Harald Welte5da9b522011-08-11 12:58:52 +020096 case DAHDI_EVENT_ABORT:
97 rate_ctr_inc(&line->rate_ctr->ctr[E1I_CTR_HDLC_ABORT]);
98 break;
99 case DAHDI_EVENT_OVERRUN:
100 rate_ctr_inc(&line->rate_ctr->ctr[E1I_CTR_HDLC_OVERR]);
101 break;
102 case DAHDI_EVENT_BADFCS:
103 rate_ctr_inc(&line->rate_ctr->ctr[E1I_CTR_HDLC_BADFCS]);
104 break;
105 case DAHDI_EVENT_REMOVED:
106 rate_ctr_inc(&line->rate_ctr->ctr[E1I_CTR_REMOVED]);
107 break;
Harald Welte44f04da2011-02-13 14:19:26 +0100108 }
109}
110
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200111static int handle_ts1_read(struct osmo_fd *bfd)
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100112{
113 struct e1inp_line *line = bfd->data;
114 unsigned int ts_nr = bfd->priv_nr;
115 struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
Matthew Fredricksonbc6649e2010-02-16 22:01:36 +0100116 struct msgb *msg = msgb_alloc(TS1_ALLOC_SIZE, "DAHDI TS1");
Harald Welteba0db5b2011-02-04 21:33:14 +0100117 lapd_mph_type prim;
118 unsigned int sapi, tei;
Pablo Neira Ayusocd986562011-08-09 23:15:38 +0200119 int ilen, ret, error = 0;
Harald Welted38f1052011-02-05 19:13:00 +0100120 uint8_t *idata;
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100121
122 if (!msg)
123 return -ENOMEM;
124
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500125 ret = read(bfd->fd, msg->data, TS1_ALLOC_SIZE - 16);
Harald Welte44f04da2011-02-13 14:19:26 +0100126 if (ret == -1)
127 handle_dahdi_exception(e1i_ts);
128 else if (ret < 0) {
Matthew Fredricksonb1cb8eb2010-02-17 19:25:39 +0100129 perror("read ");
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100130 }
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500131 msgb_put(msg, ret - 2);
Matthew Fredricksonb1cb8eb2010-02-17 19:25:39 +0100132 if (ret <= 3) {
133 perror("read ");
134 }
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100135
Harald Welteba0db5b2011-02-04 21:33:14 +0100136 sapi = msg->data[0] >> 2;
137 tei = msg->data[1] >> 1;
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500138
Harald Welteba0db5b2011-02-04 21:33:14 +0100139 DEBUGP(DMI, "<= len = %d, sapi(%d) tei(%d)", ret, sapi, tei);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100140
Pablo Neira Ayusocd986562011-08-09 23:15:38 +0200141 idata = lapd_receive(e1i_ts->driver.dahdi.lapd, msg->data, msg->len, &ilen, &prim, &error);
142 if (!idata) {
143 switch(error) {
144 case LAPD_ERR_UNKNOWN_TEI:
145 /* We don't know about this TEI, probably the BSC
146 * lost local states (it crashed or it was stopped),
147 * notify the driver to see if it can do anything to
148 * recover the existing signalling links with the BTS.
149 */
150 e1inp_event(e1i_ts, S_INP_TEI_UNKNOWN, tei, sapi);
151 return -EIO;
152 }
153 if (prim == 0)
154 return -EIO;
155 }
Matthew Fredricksonb1cb8eb2010-02-17 19:25:39 +0100156
Matthew Fredricksonb1cb8eb2010-02-17 19:25:39 +0100157 msgb_pull(msg, 2);
158
Harald Welteba0db5b2011-02-04 21:33:14 +0100159 DEBUGP(DMI, "prim %08x\n", prim);
Matthew Fredricksonb1cb8eb2010-02-17 19:25:39 +0100160
Harald Welteba0db5b2011-02-04 21:33:14 +0100161 switch (prim) {
162 case 0:
Matthew Fredricksonb1cb8eb2010-02-17 19:25:39 +0100163 break;
Harald Welteba0db5b2011-02-04 21:33:14 +0100164 case LAPD_MPH_ACTIVATE_IND:
165 DEBUGP(DMI, "MPH_ACTIVATE_IND: sapi(%d) tei(%d)\n", sapi, tei);
Harald Weltef338a032011-01-14 15:55:42 +0100166 ret = e1inp_event(e1i_ts, S_INP_TEI_UP, tei, sapi);
Matthew Fredricksonb1cb8eb2010-02-17 19:25:39 +0100167 break;
Harald Welteba0db5b2011-02-04 21:33:14 +0100168 case LAPD_MPH_DEACTIVATE_IND:
169 DEBUGP(DMI, "MPH_DEACTIVATE_IND: sapi(%d) tei(%d)\n", sapi, tei);
Harald Weltef338a032011-01-14 15:55:42 +0100170 ret = e1inp_event(e1i_ts, S_INP_TEI_DN, tei, sapi);
Matthew Fredricksonb1cb8eb2010-02-17 19:25:39 +0100171 break;
Harald Welteba0db5b2011-02-04 21:33:14 +0100172 case LAPD_DL_DATA_IND:
173 case LAPD_DL_UNITDATA_IND:
Harald Welte1dd68c32011-02-05 13:58:46 +0100174 if (prim == LAPD_DL_DATA_IND)
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500175 msg->l2h = msg->data + 2;
176 else
177 msg->l2h = msg->data + 1;
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200178 DEBUGP(DMI, "RX: %s\n", osmo_hexdump(msgb_l2(msg), ret));
Harald Welteba0db5b2011-02-04 21:33:14 +0100179 ret = e1inp_rx_ts(e1i_ts, msg, tei, sapi);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100180 break;
181 default:
Harald Welteba0db5b2011-02-04 21:33:14 +0100182 printf("ERROR: unknown prim\n");
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100183 break;
184 }
Harald Welteba0db5b2011-02-04 21:33:14 +0100185
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500186 DEBUGP(DMI, "Returned ok\n");
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100187 return ret;
188}
189
190static int ts_want_write(struct e1inp_ts *e1i_ts)
191{
Harald Welteba0db5b2011-02-04 21:33:14 +0100192 /* We never include the DAHDI B-Channel FD into the
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100193 * writeset, since it doesn't support poll() based
Harald Welte62d46032011-02-05 20:25:22 +0100194 * write flow control */
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500195 if (e1i_ts->type == E1INP_TS_TYPE_TRAU) {
196 fprintf(stderr, "Trying to write TRAU ts\n");
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100197 return 0;
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500198 }
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100199
Harald Welted38f1052011-02-05 19:13:00 +0100200 e1i_ts->driver.dahdi.fd.when |= BSC_FD_WRITE;
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100201
202 return 0;
203}
204
205static void timeout_ts1_write(void *data)
206{
207 struct e1inp_ts *e1i_ts = (struct e1inp_ts *)data;
208
209 /* trigger write of ts1, due to tx delay timer */
210 ts_want_write(e1i_ts);
211}
212
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500213static void dahdi_write_msg(uint8_t *data, int len, void *cbdata)
214{
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200215 struct osmo_fd *bfd = cbdata;
Harald Welte44f04da2011-02-13 14:19:26 +0100216 struct e1inp_line *line = bfd->data;
217 unsigned int ts_nr = bfd->priv_nr;
218 struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500219 int ret;
220
221 ret = write(bfd->fd, data, len + 2);
Harald Welte44f04da2011-02-13 14:19:26 +0100222 if (ret == -1)
223 handle_dahdi_exception(e1i_ts);
224 else if (ret < 0)
225 LOGP(DMI, LOGL_NOTICE, "%s write failed %d\n", __func__, ret);
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500226}
227
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200228static int handle_ts1_write(struct osmo_fd *bfd)
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100229{
230 struct e1inp_line *line = bfd->data;
231 unsigned int ts_nr = bfd->priv_nr;
232 struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
233 struct e1inp_sign_link *sign_link;
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100234 struct msgb *msg;
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100235
236 bfd->when &= ~BSC_FD_WRITE;
237
238 /* get the next msg for this timeslot */
239 msg = e1inp_tx_ts(e1i_ts, &sign_link);
240 if (!msg) {
241 /* no message after tx delay timer */
242 return 0;
243 }
244
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200245 DEBUGP(DMI, "TX: %s\n", osmo_hexdump(msg->data, msg->len));
Harald Welte4ee2eaf2011-02-05 20:20:50 +0100246 lapd_transmit(e1i_ts->driver.dahdi.lapd, sign_link->tei,
247 sign_link->sapi, msg->data, msg->len);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100248 msgb_free(msg);
249
250 /* set tx delay timer for next event */
251 e1i_ts->sign.tx_timer.cb = timeout_ts1_write;
252 e1i_ts->sign.tx_timer.data = e1i_ts;
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +0200253 osmo_timer_schedule(&e1i_ts->sign.tx_timer, 0, 50000);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100254
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500255 return 0;
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100256}
257
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500258
259static int invertbits = 1;
260
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200261static uint8_t flip_table[256];
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500262
263static void init_flip_bits(void)
264{
265 int i,k;
266
267 for (i = 0 ; i < 256 ; i++) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200268 uint8_t sample = 0 ;
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500269 for (k = 0; k<8; k++) {
270 if ( i & 1 << k ) sample |= 0x80 >> k;
271 }
272 flip_table[i] = sample;
273 }
274}
275
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200276static uint8_t * flip_buf_bits ( uint8_t * buf , int len)
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500277{
278 int i;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200279 uint8_t * start = buf;
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500280
281 for (i = 0 ; i < len; i++) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200282 buf[i] = flip_table[(uint8_t)buf[i]];
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500283 }
284
285 return start;
286}
287
creslin287cd8b86f2010-03-26 12:57:31 -0500288#define D_BCHAN_TX_GRAN 160
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100289/* write to a B channel TS */
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200290static int handle_tsX_write(struct osmo_fd *bfd)
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100291{
292 struct e1inp_line *line = bfd->data;
293 unsigned int ts_nr = bfd->priv_nr;
294 struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200295 uint8_t tx_buf[D_BCHAN_TX_GRAN];
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100296 struct subch_mux *mx = &e1i_ts->trau.mux;
297 int ret;
298
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500299 ret = subchan_mux_out(mx, tx_buf, D_BCHAN_TX_GRAN);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100300
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500301 if (ret != D_BCHAN_TX_GRAN) {
302 fprintf(stderr, "Huh, got ret of %d\n", ret);
303 if (ret < 0)
304 return ret;
305 }
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100306
307 DEBUGP(DMIB, "BCHAN TX: %s\n",
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200308 osmo_hexdump(tx_buf, D_BCHAN_TX_GRAN));
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100309
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500310 if (invertbits) {
311 flip_buf_bits(tx_buf, ret);
312 }
313
314 ret = write(bfd->fd, tx_buf, ret);
315 if (ret < D_BCHAN_TX_GRAN)
Harald Welte1dd68c32011-02-05 13:58:46 +0100316 fprintf(stderr, "send returns %d instead of %d\n", ret,
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500317 D_BCHAN_TX_GRAN);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100318
319 return ret;
320}
321
creslin287cd8b86f2010-03-26 12:57:31 -0500322#define D_TSX_ALLOC_SIZE (D_BCHAN_TX_GRAN)
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100323/* FIXME: read from a B channel TS */
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200324static int handle_tsX_read(struct osmo_fd *bfd)
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100325{
326 struct e1inp_line *line = bfd->data;
327 unsigned int ts_nr = bfd->priv_nr;
328 struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500329 struct msgb *msg = msgb_alloc(D_TSX_ALLOC_SIZE, "DAHDI TSx");
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100330 int ret;
331
332 if (!msg)
333 return -ENOMEM;
334
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500335 ret = read(bfd->fd, msg->data, D_TSX_ALLOC_SIZE);
336 if (ret < 0 || ret != D_TSX_ALLOC_SIZE) {
337 fprintf(stderr, "read error %d %s\n", ret, strerror(errno));
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100338 return ret;
339 }
340
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500341 if (invertbits) {
342 flip_buf_bits(msg->data, ret);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100343 }
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500344
345 msgb_put(msg, ret);
346
347 msg->l2h = msg->data;
348 DEBUGP(DMIB, "BCHAN RX: %s\n",
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200349 osmo_hexdump(msgb_l2(msg), ret));
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500350 ret = e1inp_rx_ts(e1i_ts, msg, 0, 0);
351 /* physical layer indicates that data has been sent,
352 * we thus can send some more data */
creslin287cd8b86f2010-03-26 12:57:31 -0500353 ret = handle_tsX_write(bfd);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100354 msgb_free(msg);
355
356 return ret;
357}
358
359/* callback from select.c in case one of the fd's can be read/written */
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200360static int dahdi_fd_cb(struct osmo_fd *bfd, unsigned int what)
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100361{
362 struct e1inp_line *line = bfd->data;
363 unsigned int ts_nr = bfd->priv_nr;
364 unsigned int idx = ts_nr-1;
365 struct e1inp_ts *e1i_ts = &line->ts[idx];
366 int rc = 0;
367
368 switch (e1i_ts->type) {
369 case E1INP_TS_TYPE_SIGN:
Harald Welte00ee4b72011-02-13 15:41:25 +0100370 if (what & BSC_FD_EXCEPT)
371 handle_dahdi_exception(e1i_ts);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100372 if (what & BSC_FD_READ)
373 rc = handle_ts1_read(bfd);
374 if (what & BSC_FD_WRITE)
375 rc = handle_ts1_write(bfd);
376 break;
377 case E1INP_TS_TYPE_TRAU:
Harald Welte00ee4b72011-02-13 15:41:25 +0100378 if (what & BSC_FD_EXCEPT)
379 handle_dahdi_exception(e1i_ts);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100380 if (what & BSC_FD_READ)
381 rc = handle_tsX_read(bfd);
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500382 if (what & BSC_FD_WRITE)
383 rc = handle_tsX_write(bfd);
Harald Welteba0db5b2011-02-04 21:33:14 +0100384 /* We never include the DAHDI B-Channel FD into the
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100385 * writeset, since it doesn't support poll() based
Harald Welte62d46032011-02-05 20:25:22 +0100386 * write flow control */
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100387 break;
388 default:
389 fprintf(stderr, "unknown E1 TS type %u\n", e1i_ts->type);
390 break;
391 }
392
393 return rc;
394}
395
Harald Welte1dd68c32011-02-05 13:58:46 +0100396static int dahdi_e1_line_update(struct e1inp_line *line);
397
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100398struct e1inp_driver dahdi_driver = {
Harald Welteebec58e2011-02-14 16:31:53 +0100399 .name = "dahdi",
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100400 .want_write = ts_want_write,
Harald Welte1dd68c32011-02-05 13:58:46 +0100401 .line_update = &dahdi_e1_line_update,
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100402};
403
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500404void dahdi_set_bufinfo(int fd, int as_sigchan)
405{
406 struct dahdi_bufferinfo bi;
407 int x = 0;
408
409 if (ioctl(fd, DAHDI_GET_BUFINFO, &bi)) {
410 fprintf(stderr, "Error getting bufinfo\n");
411 exit(-1);
412 }
413
414 if (as_sigchan) {
415 bi.numbufs = 4;
416 bi.bufsize = 512;
417 } else {
creslin287cd8b86f2010-03-26 12:57:31 -0500418 bi.numbufs = 8;
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500419 bi.bufsize = D_BCHAN_TX_GRAN;
creslin287cd8b86f2010-03-26 12:57:31 -0500420 bi.txbufpolicy = DAHDI_POLICY_WHEN_FULL;
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500421 }
422
423 if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
424 fprintf(stderr, "Error setting bufinfo\n");
425 exit(-1);
426 }
427
428 if (!as_sigchan) {
429 if (ioctl(fd, DAHDI_AUDIOMODE, &x)) {
430 fprintf(stderr, "Error setting bufinfo\n");
431 exit(-1);
432 }
Harald Weltee9252052011-02-14 16:43:35 +0100433 } else {
434 int one = 1;
435 ioctl(fd, DAHDI_HDLCFCSMODE, &one);
436 /* we cannot reliably check for the ioctl return value here
437 * as this command will fail if the slot _already_ was a
438 * signalling slot before :( */
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500439 }
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500440}
441
Harald Welted38f1052011-02-05 19:13:00 +0100442static int dahdi_e1_setup(struct e1inp_line *line)
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100443{
444 int ts, ret;
445
446 /* TS0 is CRC4, don't need any fd for it */
447 for (ts = 1; ts < NUM_E1_TS; ts++) {
448 unsigned int idx = ts-1;
449 char openstr[128];
450 struct e1inp_ts *e1i_ts = &line->ts[idx];
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200451 struct osmo_fd *bfd = &e1i_ts->driver.dahdi.fd;
Harald Welte0b69bc32011-08-09 11:21:23 +0200452 int dev_nr;
453
454 /* DAHDI device names/numbers just keep incrementing
455 * even over multiple boards. So TS1 of the second
456 * board will be 32 */
457 dev_nr = line->num * (NUM_E1_TS-1) + ts;
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100458
459 bfd->data = line;
460 bfd->priv_nr = ts;
461 bfd->cb = dahdi_fd_cb;
Harald Welte0b69bc32011-08-09 11:21:23 +0200462 snprintf(openstr, sizeof(openstr), "/dev/dahdi/%d", dev_nr);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100463
464 switch (e1i_ts->type) {
465 case E1INP_TS_TYPE_NONE:
466 continue;
467 break;
468 case E1INP_TS_TYPE_SIGN:
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500469 bfd->fd = open(openstr, O_RDWR | O_NONBLOCK);
470 if (bfd->fd == -1) {
471 fprintf(stderr, "%s could not open %s %s\n",
472 __func__, openstr, strerror(errno));
473 exit(-1);
474 }
Harald Welte00ee4b72011-02-13 15:41:25 +0100475 bfd->when = BSC_FD_READ | BSC_FD_EXCEPT;
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500476 dahdi_set_bufinfo(bfd->fd, 1);
Harald Welte1a00d822011-02-11 18:34:51 +0100477 e1i_ts->driver.dahdi.lapd = lapd_instance_alloc(1, dahdi_write_msg, bfd);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100478 break;
479 case E1INP_TS_TYPE_TRAU:
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500480 bfd->fd = open(openstr, O_RDWR | O_NONBLOCK);
481 if (bfd->fd == -1) {
482 fprintf(stderr, "%s could not open %s %s\n",
483 __func__, openstr, strerror(errno));
484 exit(-1);
485 }
486 dahdi_set_bufinfo(bfd->fd, 0);
Harald Welteba0db5b2011-02-04 21:33:14 +0100487 /* We never include the DAHDI B-Channel FD into the
Harald Welte62d46032011-02-05 20:25:22 +0100488 * writeset, since it doesn't support poll() based
489 * write flow control */
Harald Welte00ee4b72011-02-13 15:41:25 +0100490 bfd->when = BSC_FD_READ | BSC_FD_EXCEPT;// | BSC_FD_WRITE;
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100491 break;
492 }
493
494 if (bfd->fd < 0) {
495 fprintf(stderr, "%s could not open %s %s\n",
496 __func__, openstr, strerror(errno));
497 return bfd->fd;
498 }
499
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200500 ret = osmo_fd_register(bfd);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100501 if (ret < 0) {
502 fprintf(stderr, "could not register FD: %s\n",
503 strerror(ret));
504 return ret;
505 }
506 }
507
508 return 0;
509}
510
Harald Welte1dd68c32011-02-05 13:58:46 +0100511static int dahdi_e1_line_update(struct e1inp_line *line)
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100512{
Matthew Fredricksonbc6649e2010-02-16 22:01:36 +0100513 if (line->driver != &dahdi_driver)
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100514 return -EINVAL;
515
Harald Welted38f1052011-02-05 19:13:00 +0100516 return dahdi_e1_setup(line);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100517}
518
Harald Welte1dd68c32011-02-05 13:58:46 +0100519int e1inp_dahdi_init(void)
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100520{
Harald Welted38f1052011-02-05 19:13:00 +0100521 init_flip_bits();
522
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100523 /* register the driver with the core */
Harald Welte50d369e2011-02-05 15:30:48 +0100524 return e1inp_driver_register(&dahdi_driver);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100525}
Harald Welteca17ef82011-02-05 15:13:27 +0100526
527#endif /* HAVE_DAHDI_USER_H */