blob: eb66fa0182bdcd559d5e2ee60ebc5fe09038467e [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>
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +010043#include <openbsc/debug.h>
44#include <openbsc/gsm_data.h>
45#include <openbsc/abis_nm.h>
46#include <openbsc/abis_rsl.h>
47#include <openbsc/subchan_demux.h>
48#include <openbsc/e1_input.h>
Harald Weltef338a032011-01-14 15:55:42 +010049#include <openbsc/signal.h>
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010050#include <osmocom/core/talloc.h>
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +010051
Matthew Fredricksonb1cb8eb2010-02-17 19:25:39 +010052#include "lapd.h"
53
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +010054#define TS1_ALLOC_SIZE 300
55
Harald Welte44f04da2011-02-13 14:19:26 +010056/* Corresponds to dahdi/user.h, only PRI related events */
57static const struct value_string dahdi_evt_names[] = {
58 { DAHDI_EVENT_NONE, "NONE" },
59 { DAHDI_EVENT_ALARM, "ALARM" },
60 { DAHDI_EVENT_NOALARM, "NOALARM" },
61 { DAHDI_EVENT_ABORT, "HDLC ABORT" },
62 { DAHDI_EVENT_OVERRUN, "HDLC OVERRUN" },
63 { DAHDI_EVENT_BADFCS, "HDLC BAD FCS" },
64 { DAHDI_EVENT_REMOVED, "REMOVED" },
65 { 0, NULL }
66};
67
68static void handle_dahdi_exception(struct e1inp_ts *ts)
69{
70 int rc, evt;
Harald Welte174a51a2011-02-13 14:26:54 +010071 struct input_signal_data isd;
Harald Welte44f04da2011-02-13 14:19:26 +010072
73 rc = ioctl(ts->driver.dahdi.fd.fd, DAHDI_GETEVENT, &evt);
74 if (rc < 0)
75 return;
76
77 LOGP(DMI, LOGL_NOTICE, "Line %u(%s) / TS %u DAHDI EVENT %s\n",
78 ts->line->num, ts->line->name, ts->num,
79 get_value_string(dahdi_evt_names, evt));
80
Harald Welte174a51a2011-02-13 14:26:54 +010081 isd.line = ts->line;
82
Harald Welte44f04da2011-02-13 14:19:26 +010083 switch (evt) {
84 case DAHDI_EVENT_ALARM:
Harald Welte174a51a2011-02-13 14:26:54 +010085 /* we should notify the code that the line is gone */
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +020086 osmo_signal_dispatch(SS_INPUT, S_INP_LINE_ALARM, &isd);
Harald Welte44f04da2011-02-13 14:19:26 +010087 break;
88 case DAHDI_EVENT_NOALARM:
Harald Welte174a51a2011-02-13 14:26:54 +010089 /* alarm has gone, we should re-start the SABM requests */
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +020090 osmo_signal_dispatch(SS_INPUT, S_INP_LINE_NOALARM, &isd);
Harald Welte44f04da2011-02-13 14:19:26 +010091 break;
92 }
93}
94
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +020095static int handle_ts1_read(struct osmo_fd *bfd)
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +010096{
97 struct e1inp_line *line = bfd->data;
98 unsigned int ts_nr = bfd->priv_nr;
99 struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
Matthew Fredricksonbc6649e2010-02-16 22:01:36 +0100100 struct msgb *msg = msgb_alloc(TS1_ALLOC_SIZE, "DAHDI TS1");
Harald Welteba0db5b2011-02-04 21:33:14 +0100101 lapd_mph_type prim;
102 unsigned int sapi, tei;
Pablo Neira Ayusocd986562011-08-09 23:15:38 +0200103 int ilen, ret, error = 0;
Harald Welted38f1052011-02-05 19:13:00 +0100104 uint8_t *idata;
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100105
106 if (!msg)
107 return -ENOMEM;
108
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500109 ret = read(bfd->fd, msg->data, TS1_ALLOC_SIZE - 16);
Harald Welte44f04da2011-02-13 14:19:26 +0100110 if (ret == -1)
111 handle_dahdi_exception(e1i_ts);
112 else if (ret < 0) {
Matthew Fredricksonb1cb8eb2010-02-17 19:25:39 +0100113 perror("read ");
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100114 }
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500115 msgb_put(msg, ret - 2);
Matthew Fredricksonb1cb8eb2010-02-17 19:25:39 +0100116 if (ret <= 3) {
117 perror("read ");
118 }
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100119
Harald Welteba0db5b2011-02-04 21:33:14 +0100120 sapi = msg->data[0] >> 2;
121 tei = msg->data[1] >> 1;
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500122
Harald Welteba0db5b2011-02-04 21:33:14 +0100123 DEBUGP(DMI, "<= len = %d, sapi(%d) tei(%d)", ret, sapi, tei);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100124
Pablo Neira Ayusocd986562011-08-09 23:15:38 +0200125 idata = lapd_receive(e1i_ts->driver.dahdi.lapd, msg->data, msg->len, &ilen, &prim, &error);
126 if (!idata) {
127 switch(error) {
128 case LAPD_ERR_UNKNOWN_TEI:
129 /* We don't know about this TEI, probably the BSC
130 * lost local states (it crashed or it was stopped),
131 * notify the driver to see if it can do anything to
132 * recover the existing signalling links with the BTS.
133 */
134 e1inp_event(e1i_ts, S_INP_TEI_UNKNOWN, tei, sapi);
135 return -EIO;
136 }
137 if (prim == 0)
138 return -EIO;
139 }
Matthew Fredricksonb1cb8eb2010-02-17 19:25:39 +0100140
Matthew Fredricksonb1cb8eb2010-02-17 19:25:39 +0100141 msgb_pull(msg, 2);
142
Harald Welteba0db5b2011-02-04 21:33:14 +0100143 DEBUGP(DMI, "prim %08x\n", prim);
Matthew Fredricksonb1cb8eb2010-02-17 19:25:39 +0100144
Harald Welteba0db5b2011-02-04 21:33:14 +0100145 switch (prim) {
146 case 0:
Matthew Fredricksonb1cb8eb2010-02-17 19:25:39 +0100147 break;
Harald Welteba0db5b2011-02-04 21:33:14 +0100148 case LAPD_MPH_ACTIVATE_IND:
149 DEBUGP(DMI, "MPH_ACTIVATE_IND: sapi(%d) tei(%d)\n", sapi, tei);
Harald Weltef338a032011-01-14 15:55:42 +0100150 ret = e1inp_event(e1i_ts, S_INP_TEI_UP, tei, sapi);
Matthew Fredricksonb1cb8eb2010-02-17 19:25:39 +0100151 break;
Harald Welteba0db5b2011-02-04 21:33:14 +0100152 case LAPD_MPH_DEACTIVATE_IND:
153 DEBUGP(DMI, "MPH_DEACTIVATE_IND: sapi(%d) tei(%d)\n", sapi, tei);
Harald Weltef338a032011-01-14 15:55:42 +0100154 ret = e1inp_event(e1i_ts, S_INP_TEI_DN, tei, sapi);
Matthew Fredricksonb1cb8eb2010-02-17 19:25:39 +0100155 break;
Harald Welteba0db5b2011-02-04 21:33:14 +0100156 case LAPD_DL_DATA_IND:
157 case LAPD_DL_UNITDATA_IND:
Harald Welte1dd68c32011-02-05 13:58:46 +0100158 if (prim == LAPD_DL_DATA_IND)
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500159 msg->l2h = msg->data + 2;
160 else
161 msg->l2h = msg->data + 1;
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200162 DEBUGP(DMI, "RX: %s\n", osmo_hexdump(msgb_l2(msg), ret));
Harald Welteba0db5b2011-02-04 21:33:14 +0100163 ret = e1inp_rx_ts(e1i_ts, msg, tei, sapi);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100164 break;
165 default:
Harald Welteba0db5b2011-02-04 21:33:14 +0100166 printf("ERROR: unknown prim\n");
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100167 break;
168 }
Harald Welteba0db5b2011-02-04 21:33:14 +0100169
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500170 DEBUGP(DMI, "Returned ok\n");
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100171 return ret;
172}
173
174static int ts_want_write(struct e1inp_ts *e1i_ts)
175{
Harald Welteba0db5b2011-02-04 21:33:14 +0100176 /* We never include the DAHDI B-Channel FD into the
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100177 * writeset, since it doesn't support poll() based
Harald Welte62d46032011-02-05 20:25:22 +0100178 * write flow control */
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500179 if (e1i_ts->type == E1INP_TS_TYPE_TRAU) {
180 fprintf(stderr, "Trying to write TRAU ts\n");
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100181 return 0;
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500182 }
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100183
Harald Welted38f1052011-02-05 19:13:00 +0100184 e1i_ts->driver.dahdi.fd.when |= BSC_FD_WRITE;
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100185
186 return 0;
187}
188
189static void timeout_ts1_write(void *data)
190{
191 struct e1inp_ts *e1i_ts = (struct e1inp_ts *)data;
192
193 /* trigger write of ts1, due to tx delay timer */
194 ts_want_write(e1i_ts);
195}
196
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500197static void dahdi_write_msg(uint8_t *data, int len, void *cbdata)
198{
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200199 struct osmo_fd *bfd = cbdata;
Harald Welte44f04da2011-02-13 14:19:26 +0100200 struct e1inp_line *line = bfd->data;
201 unsigned int ts_nr = bfd->priv_nr;
202 struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500203 int ret;
204
205 ret = write(bfd->fd, data, len + 2);
Harald Welte44f04da2011-02-13 14:19:26 +0100206 if (ret == -1)
207 handle_dahdi_exception(e1i_ts);
208 else if (ret < 0)
209 LOGP(DMI, LOGL_NOTICE, "%s write failed %d\n", __func__, ret);
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500210}
211
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200212static int handle_ts1_write(struct osmo_fd *bfd)
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100213{
214 struct e1inp_line *line = bfd->data;
215 unsigned int ts_nr = bfd->priv_nr;
216 struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
217 struct e1inp_sign_link *sign_link;
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100218 struct msgb *msg;
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100219
220 bfd->when &= ~BSC_FD_WRITE;
221
222 /* get the next msg for this timeslot */
223 msg = e1inp_tx_ts(e1i_ts, &sign_link);
224 if (!msg) {
225 /* no message after tx delay timer */
226 return 0;
227 }
228
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200229 DEBUGP(DMI, "TX: %s\n", osmo_hexdump(msg->data, msg->len));
Harald Welte4ee2eaf2011-02-05 20:20:50 +0100230 lapd_transmit(e1i_ts->driver.dahdi.lapd, sign_link->tei,
231 sign_link->sapi, msg->data, msg->len);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100232 msgb_free(msg);
233
234 /* set tx delay timer for next event */
235 e1i_ts->sign.tx_timer.cb = timeout_ts1_write;
236 e1i_ts->sign.tx_timer.data = e1i_ts;
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +0200237 osmo_timer_schedule(&e1i_ts->sign.tx_timer, 0, 50000);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100238
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500239 return 0;
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100240}
241
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500242
243static int invertbits = 1;
244
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200245static uint8_t flip_table[256];
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500246
247static void init_flip_bits(void)
248{
249 int i,k;
250
251 for (i = 0 ; i < 256 ; i++) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200252 uint8_t sample = 0 ;
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500253 for (k = 0; k<8; k++) {
254 if ( i & 1 << k ) sample |= 0x80 >> k;
255 }
256 flip_table[i] = sample;
257 }
258}
259
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200260static uint8_t * flip_buf_bits ( uint8_t * buf , int len)
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500261{
262 int i;
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200263 uint8_t * start = buf;
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500264
265 for (i = 0 ; i < len; i++) {
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200266 buf[i] = flip_table[(uint8_t)buf[i]];
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500267 }
268
269 return start;
270}
271
creslin287cd8b86f2010-03-26 12:57:31 -0500272#define D_BCHAN_TX_GRAN 160
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100273/* write to a B channel TS */
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200274static int handle_tsX_write(struct osmo_fd *bfd)
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100275{
276 struct e1inp_line *line = bfd->data;
277 unsigned int ts_nr = bfd->priv_nr;
278 struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
Holger Hans Peter Freytherc42ad8b2011-04-18 17:04:00 +0200279 uint8_t tx_buf[D_BCHAN_TX_GRAN];
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100280 struct subch_mux *mx = &e1i_ts->trau.mux;
281 int ret;
282
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500283 ret = subchan_mux_out(mx, tx_buf, D_BCHAN_TX_GRAN);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100284
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500285 if (ret != D_BCHAN_TX_GRAN) {
286 fprintf(stderr, "Huh, got ret of %d\n", ret);
287 if (ret < 0)
288 return ret;
289 }
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100290
291 DEBUGP(DMIB, "BCHAN TX: %s\n",
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200292 osmo_hexdump(tx_buf, D_BCHAN_TX_GRAN));
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100293
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500294 if (invertbits) {
295 flip_buf_bits(tx_buf, ret);
296 }
297
298 ret = write(bfd->fd, tx_buf, ret);
299 if (ret < D_BCHAN_TX_GRAN)
Harald Welte1dd68c32011-02-05 13:58:46 +0100300 fprintf(stderr, "send returns %d instead of %d\n", ret,
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500301 D_BCHAN_TX_GRAN);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100302
303 return ret;
304}
305
creslin287cd8b86f2010-03-26 12:57:31 -0500306#define D_TSX_ALLOC_SIZE (D_BCHAN_TX_GRAN)
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100307/* FIXME: read from a B channel TS */
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200308static int handle_tsX_read(struct osmo_fd *bfd)
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100309{
310 struct e1inp_line *line = bfd->data;
311 unsigned int ts_nr = bfd->priv_nr;
312 struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500313 struct msgb *msg = msgb_alloc(D_TSX_ALLOC_SIZE, "DAHDI TSx");
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100314 int ret;
315
316 if (!msg)
317 return -ENOMEM;
318
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500319 ret = read(bfd->fd, msg->data, D_TSX_ALLOC_SIZE);
320 if (ret < 0 || ret != D_TSX_ALLOC_SIZE) {
321 fprintf(stderr, "read error %d %s\n", ret, strerror(errno));
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100322 return ret;
323 }
324
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500325 if (invertbits) {
326 flip_buf_bits(msg->data, ret);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100327 }
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500328
329 msgb_put(msg, ret);
330
331 msg->l2h = msg->data;
332 DEBUGP(DMIB, "BCHAN RX: %s\n",
Pablo Neira Ayusoc0d17f22011-05-07 12:12:48 +0200333 osmo_hexdump(msgb_l2(msg), ret));
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500334 ret = e1inp_rx_ts(e1i_ts, msg, 0, 0);
335 /* physical layer indicates that data has been sent,
336 * we thus can send some more data */
creslin287cd8b86f2010-03-26 12:57:31 -0500337 ret = handle_tsX_write(bfd);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100338 msgb_free(msg);
339
340 return ret;
341}
342
343/* callback from select.c in case one of the fd's can be read/written */
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200344static int dahdi_fd_cb(struct osmo_fd *bfd, unsigned int what)
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100345{
346 struct e1inp_line *line = bfd->data;
347 unsigned int ts_nr = bfd->priv_nr;
348 unsigned int idx = ts_nr-1;
349 struct e1inp_ts *e1i_ts = &line->ts[idx];
350 int rc = 0;
351
352 switch (e1i_ts->type) {
353 case E1INP_TS_TYPE_SIGN:
Harald Welte00ee4b72011-02-13 15:41:25 +0100354 if (what & BSC_FD_EXCEPT)
355 handle_dahdi_exception(e1i_ts);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100356 if (what & BSC_FD_READ)
357 rc = handle_ts1_read(bfd);
358 if (what & BSC_FD_WRITE)
359 rc = handle_ts1_write(bfd);
360 break;
361 case E1INP_TS_TYPE_TRAU:
Harald Welte00ee4b72011-02-13 15:41:25 +0100362 if (what & BSC_FD_EXCEPT)
363 handle_dahdi_exception(e1i_ts);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100364 if (what & BSC_FD_READ)
365 rc = handle_tsX_read(bfd);
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500366 if (what & BSC_FD_WRITE)
367 rc = handle_tsX_write(bfd);
Harald Welteba0db5b2011-02-04 21:33:14 +0100368 /* We never include the DAHDI B-Channel FD into the
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100369 * writeset, since it doesn't support poll() based
Harald Welte62d46032011-02-05 20:25:22 +0100370 * write flow control */
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100371 break;
372 default:
373 fprintf(stderr, "unknown E1 TS type %u\n", e1i_ts->type);
374 break;
375 }
376
377 return rc;
378}
379
Harald Welte1dd68c32011-02-05 13:58:46 +0100380static int dahdi_e1_line_update(struct e1inp_line *line);
381
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100382struct e1inp_driver dahdi_driver = {
Harald Welteebec58e2011-02-14 16:31:53 +0100383 .name = "dahdi",
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100384 .want_write = ts_want_write,
Harald Welte1dd68c32011-02-05 13:58:46 +0100385 .line_update = &dahdi_e1_line_update,
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100386};
387
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500388void dahdi_set_bufinfo(int fd, int as_sigchan)
389{
390 struct dahdi_bufferinfo bi;
391 int x = 0;
392
393 if (ioctl(fd, DAHDI_GET_BUFINFO, &bi)) {
394 fprintf(stderr, "Error getting bufinfo\n");
395 exit(-1);
396 }
397
398 if (as_sigchan) {
399 bi.numbufs = 4;
400 bi.bufsize = 512;
401 } else {
creslin287cd8b86f2010-03-26 12:57:31 -0500402 bi.numbufs = 8;
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500403 bi.bufsize = D_BCHAN_TX_GRAN;
creslin287cd8b86f2010-03-26 12:57:31 -0500404 bi.txbufpolicy = DAHDI_POLICY_WHEN_FULL;
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500405 }
406
407 if (ioctl(fd, DAHDI_SET_BUFINFO, &bi)) {
408 fprintf(stderr, "Error setting bufinfo\n");
409 exit(-1);
410 }
411
412 if (!as_sigchan) {
413 if (ioctl(fd, DAHDI_AUDIOMODE, &x)) {
414 fprintf(stderr, "Error setting bufinfo\n");
415 exit(-1);
416 }
Harald Weltee9252052011-02-14 16:43:35 +0100417 } else {
418 int one = 1;
419 ioctl(fd, DAHDI_HDLCFCSMODE, &one);
420 /* we cannot reliably check for the ioctl return value here
421 * as this command will fail if the slot _already_ was a
422 * signalling slot before :( */
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500423 }
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500424}
425
Harald Welted38f1052011-02-05 19:13:00 +0100426static int dahdi_e1_setup(struct e1inp_line *line)
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100427{
428 int ts, ret;
429
430 /* TS0 is CRC4, don't need any fd for it */
431 for (ts = 1; ts < NUM_E1_TS; ts++) {
432 unsigned int idx = ts-1;
433 char openstr[128];
434 struct e1inp_ts *e1i_ts = &line->ts[idx];
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200435 struct osmo_fd *bfd = &e1i_ts->driver.dahdi.fd;
Harald Welte0b69bc32011-08-09 11:21:23 +0200436 int dev_nr;
437
438 /* DAHDI device names/numbers just keep incrementing
439 * even over multiple boards. So TS1 of the second
440 * board will be 32 */
441 dev_nr = line->num * (NUM_E1_TS-1) + ts;
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100442
443 bfd->data = line;
444 bfd->priv_nr = ts;
445 bfd->cb = dahdi_fd_cb;
Harald Welte0b69bc32011-08-09 11:21:23 +0200446 snprintf(openstr, sizeof(openstr), "/dev/dahdi/%d", dev_nr);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100447
448 switch (e1i_ts->type) {
449 case E1INP_TS_TYPE_NONE:
450 continue;
451 break;
452 case E1INP_TS_TYPE_SIGN:
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500453 bfd->fd = open(openstr, O_RDWR | O_NONBLOCK);
454 if (bfd->fd == -1) {
455 fprintf(stderr, "%s could not open %s %s\n",
456 __func__, openstr, strerror(errno));
457 exit(-1);
458 }
Harald Welte00ee4b72011-02-13 15:41:25 +0100459 bfd->when = BSC_FD_READ | BSC_FD_EXCEPT;
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500460 dahdi_set_bufinfo(bfd->fd, 1);
Harald Welte1a00d822011-02-11 18:34:51 +0100461 e1i_ts->driver.dahdi.lapd = lapd_instance_alloc(1, dahdi_write_msg, bfd);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100462 break;
463 case E1INP_TS_TYPE_TRAU:
Matthew Fredricksoncc2bc352010-03-15 12:22:37 -0500464 bfd->fd = open(openstr, O_RDWR | O_NONBLOCK);
465 if (bfd->fd == -1) {
466 fprintf(stderr, "%s could not open %s %s\n",
467 __func__, openstr, strerror(errno));
468 exit(-1);
469 }
470 dahdi_set_bufinfo(bfd->fd, 0);
Harald Welteba0db5b2011-02-04 21:33:14 +0100471 /* We never include the DAHDI B-Channel FD into the
Harald Welte62d46032011-02-05 20:25:22 +0100472 * writeset, since it doesn't support poll() based
473 * write flow control */
Harald Welte00ee4b72011-02-13 15:41:25 +0100474 bfd->when = BSC_FD_READ | BSC_FD_EXCEPT;// | BSC_FD_WRITE;
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100475 break;
476 }
477
478 if (bfd->fd < 0) {
479 fprintf(stderr, "%s could not open %s %s\n",
480 __func__, openstr, strerror(errno));
481 return bfd->fd;
482 }
483
Pablo Neira Ayuso4db92992011-05-06 12:11:23 +0200484 ret = osmo_fd_register(bfd);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100485 if (ret < 0) {
486 fprintf(stderr, "could not register FD: %s\n",
487 strerror(ret));
488 return ret;
489 }
490 }
491
492 return 0;
493}
494
Harald Welte1dd68c32011-02-05 13:58:46 +0100495static int dahdi_e1_line_update(struct e1inp_line *line)
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100496{
Matthew Fredricksonbc6649e2010-02-16 22:01:36 +0100497 if (line->driver != &dahdi_driver)
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100498 return -EINVAL;
499
Harald Welted38f1052011-02-05 19:13:00 +0100500 return dahdi_e1_setup(line);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100501}
502
Harald Welte1dd68c32011-02-05 13:58:46 +0100503int e1inp_dahdi_init(void)
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100504{
Harald Welted38f1052011-02-05 19:13:00 +0100505 init_flip_bits();
506
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100507 /* register the driver with the core */
Harald Welte50d369e2011-02-05 15:30:48 +0100508 return e1inp_driver_register(&dahdi_driver);
Matthew Fredricksonb5ddc182010-02-16 21:55:50 +0100509}
Harald Welteca17ef82011-02-05 15:13:27 +0100510
511#endif /* HAVE_DAHDI_USER_H */