layer1: Fixed power measurement, adding ARFCN wrapping
[osmocom-bb.git] / src / target / firmware / layer1 / l23_api.c
blob2581b5bb7b73a8f78e02b2949afa86372c2ff877
1 /* Synchronous part of GSM Layer 1: API to Layer2+ */
3 /* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
5 * All Rights Reserved
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #define DEBUG
25 #include <stdint.h>
26 #include <stdio.h>
27 #include <string.h>
29 #include <debug.h>
30 #include <byteorder.h>
32 #include <asm/system.h>
34 #include <osmocom/core/msgb.h>
35 #include <osmocom/gsm/protocol/gsm_04_08.h>
36 #include <comm/sercomm.h>
38 #include <layer1/sync.h>
39 #include <layer1/async.h>
40 #include <layer1/mframe_sched.h>
41 #include <layer1/prim.h>
42 #include <layer1/tpu_window.h>
44 #include <abb/twl3025.h>
45 #include <rf/trf6151.h>
46 #include <calypso/sim.h>
48 #include <l1ctl_proto.h>
50 /* the size we will allocate struct msgb* for HDLC */
51 #define L3_MSG_HEAD 4
52 #define L3_MSG_SIZE (sizeof(struct l1ctl_hdr)+sizeof(struct l1ctl_info_dl)+sizeof(struct l1ctl_traffic_ind) + L3_MSG_HEAD)
54 void (*l1a_l23_tx_cb)(struct msgb *msg) = NULL;
56 void l1_queue_for_l2(struct msgb *msg)
58 if (l1a_l23_tx_cb) {
59 l1a_l23_tx_cb(msg);
60 return;
62 /* forward via serial for now */
63 sercomm_sendmsg(SC_DLCI_L1A_L23, msg);
66 enum mf_type {
67 MFNONE,
68 MF51,
69 MF26ODD,
70 MF26EVEN
72 static uint32_t chan_nr2mf_task_mask(uint8_t chan_nr, uint8_t neigh_mode)
74 uint8_t cbits = chan_nr >> 3;
75 uint8_t tn = chan_nr & 0x7;
76 uint8_t lch_idx;
77 enum mframe_task master_task = 0;
78 uint32_t neigh_task = 0;
79 enum mf_type multiframe;
81 if (cbits == 0x01) {
82 lch_idx = 0;
83 master_task = (tn & 1) ? MF_TASK_TCH_F_ODD : MF_TASK_TCH_F_EVEN;
84 multiframe = (tn & 1) ? MF26ODD : MF26EVEN;
85 } else if ((cbits & 0x1e) == 0x02) {
86 lch_idx = cbits & 0x1;
87 master_task = MF_TASK_TCH_H_0 + lch_idx;
88 } else if ((cbits & 0x1c) == 0x04) {
89 lch_idx = cbits & 0x3;
90 master_task = MF_TASK_SDCCH4_0 + lch_idx;
91 multiframe = MF51;
92 } else if ((cbits & 0x18) == 0x08) {
93 lch_idx = cbits & 0x7;
94 master_task = MF_TASK_SDCCH8_0 + lch_idx;
95 multiframe = MF51;
96 #if 0
97 } else if (cbits == 0x10) {
98 /* FIXME: when to do extended BCCH? */
99 master_task = MF_TASK_BCCH_NORM;
100 } else if (cbits == 0x11 || cbits == 0x12) {
101 /* FIXME: how to decide CCCH norm/extd? */
102 master_task = MF_TASK_BCCH_CCCH;
103 #endif
105 switch (neigh_mode) {
106 case NEIGH_MODE_PM:
107 switch (multiframe) {
108 case MF51:
109 neigh_task = (1 << MF_TASK_NEIGH_PM51);
110 break;
111 case MF26EVEN:
112 neigh_task = (1 << MF_TASK_NEIGH_PM26E);
113 break;
114 case MF26ODD:
115 neigh_task = (1 << MF_TASK_NEIGH_PM26O);
116 break;
118 break;
120 return (1 << master_task) | neigh_task;
123 static int chan_nr2dchan_type(uint8_t chan_nr)
125 uint8_t cbits = chan_nr >> 3;
127 if (cbits == 0x01) {
128 return GSM_DCHAN_TCH_F;
129 } else if ((cbits & 0x1e) == 0x02) {
130 return GSM_DCHAN_TCH_H;
131 } else if ((cbits & 0x1c) == 0x04) {
132 return GSM_DCHAN_SDCCH_4;
133 } else if ((cbits & 0x18) == 0x08) {
134 return GSM_DCHAN_SDCCH_8;
136 return GSM_DCHAN_UNKNOWN;
139 static int chan_nr_is_tch(uint8_t chan_nr)
141 return ((chan_nr >> 3) == 0x01 || /* TCH/F */
142 ((chan_nr >> 3) & 0x1e) == 0x02); /* TCH/H */
145 static void audio_set_enabled(uint8_t tch_mode, uint8_t audio_mode)
147 if (tch_mode == GSM48_CMODE_SIGN) {
148 twl3025_unit_enable(TWL3025_UNIT_VUL, 0);
149 twl3025_unit_enable(TWL3025_UNIT_VDL, 0);
150 } else {
151 twl3025_unit_enable(TWL3025_UNIT_VUL,
152 !!(audio_mode & AUDIO_TX_MICROPHONE));
153 twl3025_unit_enable(TWL3025_UNIT_VDL,
154 !!(audio_mode & AUDIO_RX_SPEAKER));
158 struct msgb *l1ctl_msgb_alloc(uint8_t msg_type)
160 struct msgb *msg;
161 struct l1ctl_hdr *l1h;
163 msg = msgb_alloc_headroom(L3_MSG_SIZE, L3_MSG_HEAD, "l1ctl");
164 if (!msg) {
165 while (1) {
166 puts("OOPS. Out of buffers...\n");
169 return NULL;
171 l1h = (struct l1ctl_hdr *) msgb_put(msg, sizeof(*l1h));
172 l1h->msg_type = msg_type;
173 l1h->flags = 0;
175 msg->l1h = (uint8_t *)l1h;
177 return msg;
180 struct msgb *l1_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr,
181 uint16_t arfcn)
183 struct l1ctl_info_dl *dl;
184 struct msgb *msg = l1ctl_msgb_alloc(msg_type);
186 dl = (struct l1ctl_info_dl *) msgb_put(msg, sizeof(*dl));
187 dl->frame_nr = htonl(fn);
188 dl->snr = snr;
189 dl->band_arfcn = htons(arfcn);
191 return msg;
194 /* receive a L1CTL_FBSB_REQ from L23 */
195 static void l1ctl_rx_fbsb_req(struct msgb *msg)
197 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
198 struct l1ctl_fbsb_req *sync_req = (struct l1ctl_fbsb_req *) l1h->data;
200 if (sizeof(*sync_req) > msg->len) {
201 printf("Short sync msg. %u\n", msg->len);
202 return;
205 printd("L1CTL_FBSB_REQ (arfcn=%u, flags=0x%x)\n",
206 ntohs(sync_req->band_arfcn), sync_req->flags);
208 /* reset scheduler and hardware */
209 l1s_reset();
211 /* pre-set the CCCH mode */
212 l1s.serving_cell.ccch_mode = sync_req->ccch_mode;
214 printd("Starting FCCH Recognition\n");
215 l1s_fbsb_req(1, sync_req);
218 /* receive a L1CTL_DM_EST_REQ from L23 */
219 static void l1ctl_rx_dm_est_req(struct msgb *msg)
221 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
222 struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
223 struct l1ctl_dm_est_req *est_req = (struct l1ctl_dm_est_req *) ul->payload;
225 printd("L1CTL_DM_EST_REQ (arfcn=%u, chan_nr=0x%02x, tsc=%u)\n",
226 ntohs(est_req->h0.band_arfcn), ul->chan_nr, est_req->tsc);
228 /* disable neighbour cell measurement */
229 mframe_disable(MF_TASK_NEIGH_PM51);
231 /* configure dedicated channel state */
232 l1s.dedicated.type = chan_nr2dchan_type(ul->chan_nr);
233 l1s.dedicated.tsc = est_req->tsc;
234 l1s.dedicated.tn = ul->chan_nr & 0x7;
235 l1s.dedicated.h = est_req->h;
237 if (est_req->h) {
238 int i;
239 l1s.dedicated.h1.hsn = est_req->h1.hsn;
240 l1s.dedicated.h1.maio = est_req->h1.maio;
241 l1s.dedicated.h1.n = est_req->h1.n;
242 for (i=0; i<est_req->h1.n; i++)
243 l1s.dedicated.h1.ma[i] = ntohs(est_req->h1.ma[i]);
244 } else {
245 l1s.dedicated.h0.arfcn = ntohs(est_req->h0.band_arfcn);
248 /* TCH config */
249 if (chan_nr_is_tch(ul->chan_nr)) {
250 /* Mode */
251 l1a_tch_mode_set(est_req->tch_mode);
252 l1a_audio_mode_set(est_req->audio_mode);
254 /* Sync */
255 l1s.tch_sync = 1; /* can be set without locking */
257 /* Audio path */
258 audio_set_enabled(est_req->tch_mode, est_req->audio_mode);
261 /* figure out which MF tasks to enable */
262 l1a_mftask_set(chan_nr2mf_task_mask(ul->chan_nr, NEIGH_MODE_PM));
265 /* receive a L1CTL_DM_FREQ_REQ from L23 */
266 static void l1ctl_rx_dm_freq_req(struct msgb *msg)
268 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
269 struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
270 struct l1ctl_dm_freq_req *freq_req =
271 (struct l1ctl_dm_freq_req *) ul->payload;
273 printd("L1CTL_DM_FREQ_REQ (arfcn=%u, tsc=%u)\n",
274 ntohs(freq_req->h0.band_arfcn), freq_req->tsc);
276 /* configure dedicated channel state */
277 l1s.dedicated.st_tsc = freq_req->tsc;
278 l1s.dedicated.st_h = freq_req->h;
280 if (freq_req->h) {
281 int i;
282 l1s.dedicated.st_h1.hsn = freq_req->h1.hsn;
283 l1s.dedicated.st_h1.maio = freq_req->h1.maio;
284 l1s.dedicated.st_h1.n = freq_req->h1.n;
285 for (i=0; i<freq_req->h1.n; i++)
286 l1s.dedicated.st_h1.ma[i] = ntohs(freq_req->h1.ma[i]);
287 } else {
288 l1s.dedicated.st_h0.arfcn = ntohs(freq_req->h0.band_arfcn);
291 l1a_freq_req(ntohs(freq_req->fn));
294 /* receive a L1CTL_CRYPTO_REQ from L23 */
295 static void l1ctl_rx_crypto_req(struct msgb *msg)
297 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
298 struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
299 struct l1ctl_crypto_req *cr = (struct l1ctl_crypto_req *) ul->payload;
300 uint8_t key_len = msg->len - sizeof(*l1h) - sizeof(*ul) - sizeof(*cr);
302 printd("L1CTL_CRYPTO_REQ (algo=A5/%u, len=%u)\n", cr->algo, key_len);
304 if (cr->algo && key_len != 8) {
305 printd("L1CTL_CRYPTO_REQ -> Invalid key\n");
306 return;
309 dsp_load_ciph_param(cr->algo, cr->key);
312 /* receive a L1CTL_DM_REL_REQ from L23 */
313 static void l1ctl_rx_dm_rel_req(struct msgb *msg)
315 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
316 struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
318 printd("L1CTL_DM_REL_REQ\n");
319 l1a_mftask_set(0);
320 l1s.dedicated.type = GSM_DCHAN_NONE;
321 l1a_txq_msgb_flush(&l1s.tx_queue[L1S_CHAN_MAIN]);
322 l1a_txq_msgb_flush(&l1s.tx_queue[L1S_CHAN_SACCH]);
323 l1a_txq_msgb_flush(&l1s.tx_queue[L1S_CHAN_TRAFFIC]);
324 l1a_meas_msgb_set(NULL);
325 dsp_load_ciph_param(0, NULL);
326 l1a_tch_mode_set(GSM48_CMODE_SIGN);
327 audio_set_enabled(GSM48_CMODE_SIGN, 0);
328 l1s.neigh_pm.n = 0;
331 /* receive a L1CTL_PARAM_REQ from L23 */
332 static void l1ctl_rx_param_req(struct msgb *msg)
334 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
335 struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
336 struct l1ctl_par_req *par_req = (struct l1ctl_par_req *) ul->payload;
338 printd("L1CTL_PARAM_REQ (ta=%d, tx_power=%d)\n", par_req->ta,
339 par_req->tx_power);
341 l1s.ta = par_req->ta;
342 l1s.tx_power = par_req->tx_power;
345 /* receive a L1CTL_RACH_REQ from L23 */
346 static void l1ctl_rx_rach_req(struct msgb *msg)
348 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
349 struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
350 struct l1ctl_rach_req *rach_req = (struct l1ctl_rach_req *) ul->payload;
352 printd("L1CTL_RACH_REQ (ra=0x%02x, offset=%d combined=%d)\n",
353 rach_req->ra, ntohs(rach_req->offset), rach_req->combined);
355 l1a_rach_req(ntohs(rach_req->offset), rach_req->combined,
356 rach_req->ra);
359 /* receive a L1CTL_DATA_REQ from L23 */
360 static void l1ctl_rx_data_req(struct msgb *msg)
362 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
363 struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
364 struct l1ctl_data_ind *data_ind = (struct l1ctl_data_ind *) ul->payload;
365 struct llist_head *tx_queue;
367 printd("L1CTL_DATA_REQ (link_id=0x%02x)\n", ul->link_id);
369 msg->l3h = data_ind->data;
370 if (ul->link_id & 0x40) {
371 struct gsm48_hdr *gh = (struct gsm48_hdr *)(data_ind->data + 5);
372 if (gh->proto_discr == GSM48_PDISC_RR
373 && gh->msg_type == GSM48_MT_RR_MEAS_REP) {
374 printd("updating measurement report\n");
375 l1a_meas_msgb_set(msg);
376 return;
378 tx_queue = &l1s.tx_queue[L1S_CHAN_SACCH];
379 } else
380 tx_queue = &l1s.tx_queue[L1S_CHAN_MAIN];
382 printd("ul=%p, ul->payload=%p, data_ind=%p, data_ind->data=%p l3h=%p\n",
383 ul, ul->payload, data_ind, data_ind->data, msg->l3h);
385 l1a_txq_msgb_enq(tx_queue, msg);
388 /* receive a L1CTL_PM_REQ from L23 */
389 static void l1ctl_rx_pm_req(struct msgb *msg)
391 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
392 struct l1ctl_pm_req *pm_req = (struct l1ctl_pm_req *) l1h->data;
394 switch (pm_req->type) {
395 case 1:
396 l1s.pm.mode = 1;
397 l1s.pm.range.arfcn_start =
398 ntohs(pm_req->range.band_arfcn_from);
399 l1s.pm.range.arfcn_next =
400 ntohs(pm_req->range.band_arfcn_from);
401 l1s.pm.range.arfcn_end =
402 ntohs(pm_req->range.band_arfcn_to);
403 printf("L1CTL_PM_REQ start=%u end=%u\n",
404 l1s.pm.range.arfcn_start, l1s.pm.range.arfcn_end);
405 break;
407 l1s_reset_hw(); /* must reset, otherwise measurement results are delayed */
408 l1s_pm_test(1, l1s.pm.range.arfcn_next);
411 /* Transmit a L1CTL_RESET_IND or L1CTL_RESET_CONF */
412 void l1ctl_tx_reset(uint8_t msg_type, uint8_t reset_type)
414 struct msgb *msg = l1ctl_msgb_alloc(msg_type);
415 struct l1ctl_reset *reset_resp;
416 reset_resp = (struct l1ctl_reset *)
417 msgb_put(msg, sizeof(*reset_resp));
418 reset_resp->type = reset_type;
420 l1_queue_for_l2(msg);
423 /* receive a L1CTL_RESET_REQ from L23 */
424 static void l1ctl_rx_reset_req(struct msgb *msg)
426 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
427 struct l1ctl_reset *reset_req =
428 (struct l1ctl_reset *) l1h->data;
430 switch (reset_req->type) {
431 case L1CTL_RES_T_FULL:
432 printf("L1CTL_RESET_REQ: FULL!\n");
433 l1s_reset();
434 l1s_reset_hw();
435 audio_set_enabled(GSM48_CMODE_SIGN, 0);
436 l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
437 break;
438 case L1CTL_RES_T_SCHED:
439 printf("L1CTL_RESET_REQ: SCHED!\n");
440 l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
441 sched_gsmtime_reset();
442 break;
443 default:
444 printf("unknown L1CTL_RESET_REQ type\n");
445 break;
449 /* Transmit a L1CTL_CCCH_MODE_CONF */
450 static void l1ctl_tx_ccch_mode_conf(uint8_t ccch_mode)
452 struct msgb *msg = l1ctl_msgb_alloc(L1CTL_CCCH_MODE_CONF);
453 struct l1ctl_ccch_mode_conf *mode_conf;
454 mode_conf = (struct l1ctl_ccch_mode_conf *)
455 msgb_put(msg, sizeof(*mode_conf));
456 mode_conf->ccch_mode = ccch_mode;
458 l1_queue_for_l2(msg);
461 /* receive a L1CTL_CCCH_MODE_REQ from L23 */
462 static void l1ctl_rx_ccch_mode_req(struct msgb *msg)
464 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
465 struct l1ctl_ccch_mode_req *ccch_mode_req =
466 (struct l1ctl_ccch_mode_req *) l1h->data;
467 uint8_t ccch_mode = ccch_mode_req->ccch_mode;
469 /* pre-set the CCCH mode */
470 l1s.serving_cell.ccch_mode = ccch_mode;
472 /* Update task */
473 mframe_disable(MF_TASK_CCCH_COMB);
474 mframe_disable(MF_TASK_CCCH);
476 if (ccch_mode == CCCH_MODE_COMBINED)
477 mframe_enable(MF_TASK_CCCH_COMB);
478 else if (ccch_mode == CCCH_MODE_NON_COMBINED)
479 mframe_enable(MF_TASK_CCCH);
481 l1ctl_tx_ccch_mode_conf(ccch_mode);
484 /* Transmit a L1CTL_TCH_MODE_CONF */
485 static void l1ctl_tx_tch_mode_conf(uint8_t tch_mode, uint8_t audio_mode)
487 struct msgb *msg = l1ctl_msgb_alloc(L1CTL_TCH_MODE_CONF);
488 struct l1ctl_tch_mode_conf *mode_conf;
489 mode_conf = (struct l1ctl_tch_mode_conf *)
490 msgb_put(msg, sizeof(*mode_conf));
491 mode_conf->tch_mode = tch_mode;
492 mode_conf->audio_mode = audio_mode;
494 l1_queue_for_l2(msg);
497 /* receive a L1CTL_TCH_MODE_REQ from L23 */
498 static void l1ctl_rx_tch_mode_req(struct msgb *msg)
500 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
501 struct l1ctl_tch_mode_req *tch_mode_req =
502 (struct l1ctl_tch_mode_req *) l1h->data;
503 uint8_t tch_mode = tch_mode_req->tch_mode;
504 uint8_t audio_mode = tch_mode_req->audio_mode;
506 printd("L1CTL_TCH_MODE_REQ (tch_mode=0x%02x audio_mode=0x%02x)\n",
507 tch_mode, audio_mode);
508 tch_mode = l1a_tch_mode_set(tch_mode);
509 audio_mode = l1a_audio_mode_set(audio_mode);
511 audio_set_enabled(tch_mode, audio_mode);
513 l1s.tch_sync = 1; /* Needed for audio to work */
515 l1ctl_tx_tch_mode_conf(tch_mode, audio_mode);
518 /* receive a L1CTL_NEIGH_PM_REQ from L23 */
519 static void l1ctl_rx_neigh_pm_req(struct msgb *msg)
521 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
522 struct l1ctl_neigh_pm_req *pm_req =
523 (struct l1ctl_neigh_pm_req *) l1h->data;
524 int i;
526 /* reset list in order to prevent race condition */
527 l1s.neigh_pm.n = 0; /* atomic */
528 l1s.neigh_pm.second = 0;
529 /* now reset pointer and fill list */
530 l1s.neigh_pm.pos = 0;
531 l1s.neigh_pm.running = 0;
532 for (i = 0; i < pm_req->n; i++)
533 l1s.neigh_pm.band_arfcn[i] = ntohs(pm_req->band_arfcn[i]);
534 printf("L1CTL_NEIGH_PM_REQ new list with %u entries\n", pm_req->n);
535 l1s.neigh_pm.n = pm_req->n; /* atomic */
537 /* on BCCH enable PM on frame 51 */
538 if (l1s.dedicated.type == GSM_DCHAN_NONE)
539 mframe_enable(MF_TASK_NEIGH_PM51);
542 /* receive a L1CTL_TRAFFIC_REQ from L23 */
543 static void l1ctl_rx_traffic_req(struct msgb *msg)
545 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
546 struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
547 struct l1ctl_traffic_req *tr = (struct l1ctl_traffic_req *) ul->payload;
548 int num = 0;
550 /* printd("L1CTL_TRAFFIC_REQ\n"); */ /* Very verbose, can overwelm serial */
552 msg->l2h = tr->data;
554 num = l1a_txq_msgb_count(&l1s.tx_queue[L1S_CHAN_TRAFFIC]);
555 if (num >= 4) {
556 printd("dropping traffic frame\n");
557 msgb_free(msg);
558 return;
561 l1a_txq_msgb_enq(&l1s.tx_queue[L1S_CHAN_TRAFFIC], msg);
564 void sim_apdu(uint16_t len, uint8_t *data);
566 static void l1ctl_sim_req(struct msgb *msg)
568 uint16_t len = msg->len - sizeof(struct l1ctl_hdr);
569 uint8_t *data = msg->data + sizeof(struct l1ctl_hdr);
571 #if 1 /* for debugging only */
573 int i;
574 printf("SIM Request (%u): ", len);
575 for (i = 0; i < len; i++)
576 printf("%02x ", data[i]);
577 puts("\n");
579 #endif
581 sim_apdu(len, data);
584 static struct llist_head l23_rx_queue = LLIST_HEAD_INIT(l23_rx_queue);
586 /* callback from SERCOMM when L2 sends a message to L1 */
587 void l1a_l23_rx(uint8_t dlci, struct msgb *msg)
589 unsigned long flags;
591 local_firq_save(flags);
592 msgb_enqueue(&l23_rx_queue, msg);
593 local_irq_restore(flags);
596 void l1a_l23_handler(void)
598 struct msgb *msg;
599 struct l1ctl_hdr *l1h;
600 unsigned long flags;
602 local_firq_save(flags);
603 msg = msgb_dequeue(&l23_rx_queue);
604 local_irq_restore(flags);
605 if (!msg)
606 return;
608 l1h = (struct l1ctl_hdr *) msg->data;
610 #if 0
612 int i;
613 printf("l1a_l23_rx_cb (%u): ", msg->len);
614 for (i = 0; i < msg->len; i++)
615 printf("%02x ", msg->data[i]);
616 puts("\n");
618 #endif
620 msg->l1h = msg->data;
622 if (sizeof(*l1h) > msg->len) {
623 printf("l1a_l23_cb: Short message. %u\n", msg->len);
624 goto exit_msgbfree;
627 switch (l1h->msg_type) {
628 case L1CTL_FBSB_REQ:
629 l1ctl_rx_fbsb_req(msg);
630 break;
631 case L1CTL_DM_EST_REQ:
632 l1ctl_rx_dm_est_req(msg);
633 break;
634 case L1CTL_DM_REL_REQ:
635 l1ctl_rx_dm_rel_req(msg);
636 break;
637 case L1CTL_PARAM_REQ:
638 l1ctl_rx_param_req(msg);
639 break;
640 case L1CTL_DM_FREQ_REQ:
641 l1ctl_rx_dm_freq_req(msg);
642 break;
643 case L1CTL_CRYPTO_REQ:
644 l1ctl_rx_crypto_req(msg);
645 break;
646 case L1CTL_RACH_REQ:
647 l1ctl_rx_rach_req(msg);
648 break;
649 case L1CTL_DATA_REQ:
650 l1ctl_rx_data_req(msg);
651 /* we have to keep the msgb, not free it! */
652 goto exit_nofree;
653 case L1CTL_PM_REQ:
654 l1ctl_rx_pm_req(msg);
655 break;
656 case L1CTL_RESET_REQ:
657 l1ctl_rx_reset_req(msg);
658 break;
659 case L1CTL_CCCH_MODE_REQ:
660 l1ctl_rx_ccch_mode_req(msg);
661 break;
662 case L1CTL_TCH_MODE_REQ:
663 l1ctl_rx_tch_mode_req(msg);
664 break;
665 case L1CTL_NEIGH_PM_REQ:
666 l1ctl_rx_neigh_pm_req(msg);
667 break;
668 case L1CTL_TRAFFIC_REQ:
669 l1ctl_rx_traffic_req(msg);
670 /* we have to keep the msgb, not free it! */
671 goto exit_nofree;
672 case L1CTL_SIM_REQ:
673 l1ctl_sim_req(msg);
674 break;
677 exit_msgbfree:
678 msgb_free(msg);
679 exit_nofree:
680 return;
683 void l1a_l23api_init(void)
685 sercomm_register_rx_cb(SC_DLCI_L1A_L23, l1a_l23_rx);