treewide: remove FSF address
[osmocom-bb.git] / src / target / firmware / layer1 / l23_api.c
blob735d92aa8f141bb5f043e4f141595ee2f8047a15
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.
19 #define DEBUG
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <string.h>
25 #include <debug.h>
26 #include <byteorder.h>
28 #include <asm/system.h>
30 #include <osmocom/core/msgb.h>
31 #include <osmocom/gsm/protocol/gsm_04_08.h>
32 #include <comm/sercomm.h>
34 #include <layer1/sync.h>
35 #include <layer1/async.h>
36 #include <layer1/mframe_sched.h>
37 #include <layer1/prim.h>
38 #include <layer1/tpu_window.h>
39 #include <layer1/sched_gsmtime.h>
41 #include <abb/twl3025.h>
42 #include <rf/trf6151.h>
43 #include <calypso/sim.h>
44 #include <calypso/dsp.h>
46 #include <l1ctl_proto.h>
48 /* the size we will allocate struct msgb* for HDLC */
49 #define L3_MSG_HEAD 4
50 #define L3_MSG_DATA 200
51 #define L3_MSG_SIZE (L3_MSG_HEAD + sizeof(struct l1ctl_hdr) + L3_MSG_DATA)
53 void (*l1a_l23_tx_cb)(struct msgb *msg) = NULL;
55 void l1_queue_for_l2(struct msgb *msg)
57 if (l1a_l23_tx_cb) {
58 l1a_l23_tx_cb(msg);
59 return;
61 /* forward via serial for now */
62 sercomm_sendmsg(SC_DLCI_L1A_L23, msg);
65 enum mf_type {
66 MFNONE,
67 MF51,
68 MF26ODD,
69 MF26EVEN
71 static uint32_t chan_nr2mf_task_mask(uint8_t chan_nr, uint8_t neigh_mode)
73 uint8_t cbits = chan_nr >> 3;
74 uint8_t tn = chan_nr & 0x7;
75 uint8_t lch_idx;
76 enum mframe_task master_task = MF_TASK_BCCH_NORM;
77 enum mframe_task second_task = -1; /* optional */
78 enum mf_type multiframe = 0;
79 uint32_t task_mask = 0x00;
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 multiframe = (lch_idx & 1) ? MF26ODD : MF26EVEN;
89 } else if ((cbits & 0x1c) == 0x04) {
90 lch_idx = cbits & 0x3;
91 master_task = MF_TASK_SDCCH4_0 + lch_idx;
92 multiframe = MF51;
93 } else if ((cbits & 0x18) == 0x08) {
94 lch_idx = cbits & 0x7;
95 master_task = MF_TASK_SDCCH8_0 + lch_idx;
96 multiframe = MF51;
97 } else if ((cbits & 0x1f) == 0x18) {
98 /* Osmocom specific extension for PDTCH and PTCCH */
99 master_task = MF_TASK_GPRS_PDTCH;
100 second_task = MF_TASK_GPRS_PTCCH;
101 /* FIXME: PDCH has different multiframe structure */
102 multiframe = MFNONE;
103 } else if ((cbits & 0x1f) == 0x19) {
104 /* Osmocom specific extension for CBCH on SDCCH/4 */
105 master_task = MF_TASK_SDCCH4_CBCH;
106 multiframe = MF51;
107 } else if ((cbits & 0x1f) == 0x1a) {
108 /* Osmocom specific extension for CBCH on SDCCH/8 */
109 master_task = MF_TASK_SDCCH8_CBCH;
110 multiframe = MF51;
111 #if 0
112 } else if (cbits == 0x10) {
113 /* FIXME: when to do extended BCCH? */
114 master_task = MF_TASK_BCCH_NORM;
115 } else if (cbits == 0x11 || cbits == 0x12) {
116 /* FIXME: how to decide CCCH norm/extd? */
117 master_task = MF_TASK_BCCH_CCCH;
118 #endif
121 /* Primary and secondary tasks */
122 task_mask |= (1 << master_task);
123 if (second_task >= 0) /* optional */
124 task_mask |= (1 << second_task);
126 switch (neigh_mode) {
127 case NEIGH_MODE_PM:
128 switch (multiframe) {
129 case MF51:
130 task_mask |= (1 << MF_TASK_NEIGH_PM51);
131 break;
132 case MF26EVEN:
133 task_mask |= (1 << MF_TASK_NEIGH_PM26E);
134 break;
135 case MF26ODD:
136 task_mask |= (1 << MF_TASK_NEIGH_PM26O);
137 break;
139 break;
142 return task_mask;
145 static int chan_nr2dchan_type(uint8_t chan_nr)
147 uint8_t cbits = chan_nr >> 3;
149 if (cbits == 0x01) {
150 return GSM_DCHAN_TCH_F;
151 } else if ((cbits & 0x1e) == 0x02) {
152 return GSM_DCHAN_TCH_H;
153 } else if ((cbits & 0x1c) == 0x04) {
154 return GSM_DCHAN_SDCCH_4;
155 } else if ((cbits & 0x18) == 0x08) {
156 return GSM_DCHAN_SDCCH_8;
157 } else if ((cbits & 0x1f) == 0x18) {
158 /* Osmocom-specific extension for PDCH */
159 return GSM_DCHAN_PDCH;
160 } else if ((cbits & 0x1f) == 0x19) {
161 /* Osmocom-specific extension for CBCH on SDCCH/4 */
162 return GSM_DCHAN_SDCCH_4_CBCH;
163 } else if ((cbits & 0x1f) == 0x1a) {
164 /* Osmocom-specific extension for CBCH on SDCCH/8 */
165 return GSM_DCHAN_SDCCH_8_CBCH;
168 return GSM_DCHAN_UNKNOWN;
171 static int chan_nr_is_tch(uint8_t chan_nr)
173 return ((chan_nr >> 3) == 0x01 || /* TCH/F */
174 ((chan_nr >> 3) & 0x1e) == 0x02); /* TCH/H */
177 static void audio_set_enabled(uint8_t tch_mode, uint8_t audio_mode)
179 if (tch_mode == GSM48_CMODE_SIGN) {
180 twl3025_unit_enable(TWL3025_UNIT_VUL, 0);
181 twl3025_unit_enable(TWL3025_UNIT_VDL, 0);
182 } else {
183 twl3025_unit_enable(TWL3025_UNIT_VUL,
184 !!(audio_mode & AUDIO_TX_MICROPHONE));
185 twl3025_unit_enable(TWL3025_UNIT_VDL,
186 !!(audio_mode & AUDIO_RX_SPEAKER));
190 struct msgb *l1ctl_msgb_alloc(uint8_t msg_type)
192 struct msgb *msg;
193 struct l1ctl_hdr *l1h;
195 msg = msgb_alloc_headroom(L3_MSG_SIZE, L3_MSG_HEAD, "l1ctl");
196 if (!msg) {
197 while (1) {
198 puts("OOPS. Out of buffers...\n");
201 return NULL;
203 l1h = (struct l1ctl_hdr *) msgb_put(msg, sizeof(*l1h));
204 l1h->msg_type = msg_type;
205 l1h->flags = 0;
207 msg->l1h = (uint8_t *)l1h;
209 return msg;
212 struct msgb *l1_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr,
213 uint16_t arfcn)
215 struct l1ctl_info_dl *dl;
216 struct msgb *msg = l1ctl_msgb_alloc(msg_type);
218 dl = (struct l1ctl_info_dl *) msgb_put(msg, sizeof(*dl));
219 dl->frame_nr = htonl(fn);
220 dl->snr = snr;
221 dl->band_arfcn = htons(arfcn);
223 return msg;
226 /* receive a L1CTL_FBSB_REQ from L23 */
227 static void l1ctl_rx_fbsb_req(struct msgb *msg)
229 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
230 struct l1ctl_fbsb_req *sync_req = (struct l1ctl_fbsb_req *) l1h->data;
232 if (sizeof(*sync_req) > msg->len) {
233 printf("Short sync msg. %u\n", msg->len);
234 return;
237 printd("L1CTL_FBSB_REQ (arfcn=%u, flags=0x%x)\n",
238 ntohs(sync_req->band_arfcn), sync_req->flags);
240 /* reset scheduler and hardware */
241 l1s_reset();
243 /* pre-set the CCCH mode */
244 l1s.serving_cell.ccch_mode = sync_req->ccch_mode;
246 printd("Starting FCCH Recognition\n");
247 l1s_fbsb_req(1, sync_req);
250 /* receive a L1CTL_DM_EST_REQ from L23 */
251 static void l1ctl_rx_dm_est_req(struct msgb *msg)
253 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
254 struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
255 struct l1ctl_dm_est_req *est_req = (struct l1ctl_dm_est_req *) ul->payload;
257 printd("L1CTL_DM_EST_REQ (arfcn=%u, chan_nr=0x%02x, tsc=%u)\n",
258 ntohs(est_req->h0.band_arfcn), ul->chan_nr, est_req->tsc);
260 /* disable neighbour cell measurement of C0 TS 0 */
261 mframe_disable(MF_TASK_NEIGH_PM51_C0T0);
263 /* configure dedicated channel state */
264 l1s.dedicated.type = chan_nr2dchan_type(ul->chan_nr);
265 l1s.dedicated.tsc = est_req->tsc;
266 l1s.dedicated.tn = ul->chan_nr & 0x7;
267 l1s.dedicated.h = est_req->h;
269 if (est_req->h) {
270 int i;
271 l1s.dedicated.h1.hsn = est_req->h1.hsn;
272 l1s.dedicated.h1.maio = est_req->h1.maio;
273 l1s.dedicated.h1.n = est_req->h1.n;
274 for (i=0; i<est_req->h1.n; i++)
275 l1s.dedicated.h1.ma[i] = ntohs(est_req->h1.ma[i]);
276 } else {
277 l1s.dedicated.h0.arfcn = ntohs(est_req->h0.band_arfcn);
280 /* TCH config */
281 if (chan_nr_is_tch(ul->chan_nr)) {
282 /* Mode */
283 l1a_tch_mode_set(est_req->tch_mode);
284 l1a_audio_mode_set(est_req->audio_mode);
286 /* Sync */
287 l1s.tch_sync = 1; /* can be set without locking */
289 /* Audio path */
290 audio_set_enabled(est_req->tch_mode, est_req->audio_mode);
293 /* figure out which MF tasks to enable */
294 l1a_mftask_set(chan_nr2mf_task_mask(ul->chan_nr, NEIGH_MODE_PM));
297 /* receive a L1CTL_DM_FREQ_REQ from L23 */
298 static void l1ctl_rx_dm_freq_req(struct msgb *msg)
300 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
301 struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
302 struct l1ctl_dm_freq_req *freq_req =
303 (struct l1ctl_dm_freq_req *) ul->payload;
305 printd("L1CTL_DM_FREQ_REQ (arfcn=%u, tsc=%u)\n",
306 ntohs(freq_req->h0.band_arfcn), freq_req->tsc);
308 /* configure dedicated channel state */
309 l1s.dedicated.st_tsc = freq_req->tsc;
310 l1s.dedicated.st_h = freq_req->h;
312 if (freq_req->h) {
313 int i;
314 l1s.dedicated.st_h1.hsn = freq_req->h1.hsn;
315 l1s.dedicated.st_h1.maio = freq_req->h1.maio;
316 l1s.dedicated.st_h1.n = freq_req->h1.n;
317 for (i=0; i<freq_req->h1.n; i++)
318 l1s.dedicated.st_h1.ma[i] = ntohs(freq_req->h1.ma[i]);
319 } else {
320 l1s.dedicated.st_h0.arfcn = ntohs(freq_req->h0.band_arfcn);
323 l1a_freq_req(ntohs(freq_req->fn));
326 /* receive a L1CTL_CRYPTO_REQ from L23 */
327 static void l1ctl_rx_crypto_req(struct msgb *msg)
329 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
330 struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
331 struct l1ctl_crypto_req *cr = (struct l1ctl_crypto_req *) ul->payload;
333 printd("L1CTL_CRYPTO_REQ (algo=A5/%u, len=%u)\n", cr->algo, cr->key_len);
335 if (cr->algo && cr->key_len != 8) {
336 printd("L1CTL_CRYPTO_REQ -> Invalid key\n");
337 return;
340 dsp_load_ciph_param(cr->algo, cr->key);
343 /* receive a L1CTL_DM_REL_REQ from L23 */
344 static void l1ctl_rx_dm_rel_req(struct msgb *msg)
346 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
348 printd("L1CTL_DM_REL_REQ\n");
349 l1a_mftask_set(0);
350 l1s.dedicated.type = GSM_DCHAN_NONE;
351 l1a_txq_msgb_flush(&l1s.tx_queue[L1S_CHAN_MAIN]);
352 l1a_txq_msgb_flush(&l1s.tx_queue[L1S_CHAN_SACCH]);
353 l1a_txq_msgb_flush(&l1s.tx_queue[L1S_CHAN_TRAFFIC]);
354 l1a_meas_msgb_set(NULL);
355 dsp_load_ciph_param(0, NULL);
356 l1a_tch_mode_set(GSM48_CMODE_SIGN);
357 audio_set_enabled(GSM48_CMODE_SIGN, 0);
358 l1s.tch_loop_mode = L1CTL_TCH_LOOP_OPEN;
359 l1s.neigh_pm.n = 0;
362 /* receive a L1CTL_PARAM_REQ from L23 */
363 static void l1ctl_rx_param_req(struct msgb *msg)
365 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
366 struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
367 struct l1ctl_par_req *par_req = (struct l1ctl_par_req *) ul->payload;
369 printd("L1CTL_PARAM_REQ (ta=%d, tx_power=%u)\n", par_req->ta,
370 par_req->tx_power);
372 l1s.ta = par_req->ta;
373 l1s.tx_power = par_req->tx_power;
376 /* receive a L1CTL_RACH_REQ from L23 */
377 static void l1ctl_rx_rach_req(struct msgb *msg)
379 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
380 struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
381 struct l1ctl_rach_req *rach_req = (struct l1ctl_rach_req *) ul->payload;
383 printd("L1CTL_RACH_REQ (ra=0x%02x, offset=%d, combined=%d)\n",
384 rach_req->ra, ntohs(rach_req->offset), rach_req->combined);
386 l1a_rach_req(ntohs(rach_req->offset), rach_req->combined,
387 rach_req->ra);
390 /* receive a L1CTL_DATA_REQ from L23 */
391 static void l1ctl_rx_data_req(struct msgb *msg)
393 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
394 struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
395 struct l1ctl_data_ind *data_ind = (struct l1ctl_data_ind *) ul->payload;
396 struct llist_head *tx_queue;
398 printd("L1CTL_DATA_REQ (link_id=0x%02x)\n", ul->link_id);
400 msg->l3h = data_ind->data;
401 if (ul->link_id & 0x40) {
402 struct gsm48_hdr *gh = (struct gsm48_hdr *)(data_ind->data + 5);
403 if (gh->proto_discr == GSM48_PDISC_RR
404 && gh->msg_type == GSM48_MT_RR_MEAS_REP) {
405 printd("updating measurement report\n");
406 l1a_meas_msgb_set(msg);
407 return;
409 tx_queue = &l1s.tx_queue[L1S_CHAN_SACCH];
410 } else
411 tx_queue = &l1s.tx_queue[L1S_CHAN_MAIN];
413 printd("ul=%p, ul->payload=%p, data_ind=%p, data_ind->data=%p l3h=%p\n",
414 ul, ul->payload, data_ind, data_ind->data, msg->l3h);
416 l1a_txq_msgb_enq(tx_queue, msg);
419 /* receive a L1CTL_PM_REQ from L23 */
420 static void l1ctl_rx_pm_req(struct msgb *msg)
422 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
423 struct l1ctl_pm_req *pm_req = (struct l1ctl_pm_req *) l1h->data;
425 switch (pm_req->type) {
426 case 1:
427 l1s.pm.mode = 1;
428 l1s.pm.range.arfcn_start =
429 ntohs(pm_req->range.band_arfcn_from);
430 l1s.pm.range.arfcn_next =
431 ntohs(pm_req->range.band_arfcn_from);
432 l1s.pm.range.arfcn_end =
433 ntohs(pm_req->range.band_arfcn_to);
434 printf("L1CTL_PM_REQ start=%u end=%u\n",
435 l1s.pm.range.arfcn_start, l1s.pm.range.arfcn_end);
436 break;
438 l1s_reset_hw(); /* must reset, otherwise measurement results are delayed */
439 l1s_pm_test(1, l1s.pm.range.arfcn_next);
442 /* Transmit a L1CTL_RESET_IND or L1CTL_RESET_CONF */
443 void l1ctl_tx_reset(uint8_t msg_type, uint8_t reset_type)
445 struct msgb *msg = l1ctl_msgb_alloc(msg_type);
446 struct l1ctl_reset *reset_resp;
447 reset_resp = (struct l1ctl_reset *)
448 msgb_put(msg, sizeof(*reset_resp));
449 reset_resp->type = reset_type;
451 l1_queue_for_l2(msg);
454 /* receive a L1CTL_RESET_REQ from L23 */
455 static void l1ctl_rx_reset_req(struct msgb *msg)
457 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
458 struct l1ctl_reset *reset_req =
459 (struct l1ctl_reset *) l1h->data;
461 switch (reset_req->type) {
462 case L1CTL_RES_T_FULL:
463 printf("L1CTL_RESET_REQ: FULL!\n");
464 l1s_reset();
465 l1s_reset_hw();
466 audio_set_enabled(GSM48_CMODE_SIGN, 0);
467 l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
468 break;
469 case L1CTL_RES_T_SCHED:
470 printf("L1CTL_RESET_REQ: SCHED!\n");
471 l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
472 sched_gsmtime_reset();
473 break;
474 default:
475 printf("unknown L1CTL_RESET_REQ type\n");
476 break;
480 /* Transmit a L1CTL_CCCH_MODE_CONF */
481 static void l1ctl_tx_ccch_mode_conf(uint8_t ccch_mode)
483 struct msgb *msg = l1ctl_msgb_alloc(L1CTL_CCCH_MODE_CONF);
484 struct l1ctl_ccch_mode_conf *mode_conf;
485 mode_conf = (struct l1ctl_ccch_mode_conf *)
486 msgb_put(msg, sizeof(*mode_conf));
487 mode_conf->ccch_mode = ccch_mode;
489 l1_queue_for_l2(msg);
492 /* receive a L1CTL_CCCH_MODE_REQ from L23 */
493 static void l1ctl_rx_ccch_mode_req(struct msgb *msg)
495 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
496 struct l1ctl_ccch_mode_req *ccch_mode_req =
497 (struct l1ctl_ccch_mode_req *) l1h->data;
498 uint8_t ccch_mode = ccch_mode_req->ccch_mode;
500 /* pre-set the CCCH mode */
501 l1s.serving_cell.ccch_mode = ccch_mode;
503 /* Update task */
504 mframe_disable(MF_TASK_CCCH_COMB);
505 mframe_disable(MF_TASK_CCCH);
507 if (ccch_mode == CCCH_MODE_COMBINED)
508 mframe_enable(MF_TASK_CCCH_COMB);
509 else if (ccch_mode == CCCH_MODE_NON_COMBINED)
510 mframe_enable(MF_TASK_CCCH);
511 else if (ccch_mode == CCCH_MODE_COMBINED_CBCH) {
512 mframe_enable(MF_TASK_CCCH_COMB);
513 mframe_enable(MF_TASK_SDCCH4_CBCH);
516 l1ctl_tx_ccch_mode_conf(ccch_mode);
519 /* Transmit a L1CTL_TCH_MODE_CONF */
520 static void l1ctl_tx_tch_mode_conf(uint8_t tch_mode, uint8_t audio_mode)
522 struct msgb *msg = l1ctl_msgb_alloc(L1CTL_TCH_MODE_CONF);
523 struct l1ctl_tch_mode_conf *mode_conf;
524 mode_conf = (struct l1ctl_tch_mode_conf *)
525 msgb_put(msg, sizeof(*mode_conf));
526 mode_conf->tch_mode = tch_mode;
527 mode_conf->audio_mode = audio_mode;
528 mode_conf->tch_loop_mode = l1s.tch_loop_mode;
530 l1_queue_for_l2(msg);
533 /* receive a L1CTL_TCH_MODE_REQ from L23 */
534 static void l1ctl_rx_tch_mode_req(struct msgb *msg)
536 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
537 struct l1ctl_tch_mode_req *tch_mode_req =
538 (struct l1ctl_tch_mode_req *) l1h->data;
539 uint8_t tch_mode = tch_mode_req->tch_mode;
540 uint8_t audio_mode = tch_mode_req->audio_mode;
542 printd("L1CTL_TCH_MODE_REQ (tch_mode=0x%02x audio_mode=0x%02x)\n",
543 tch_mode, audio_mode);
544 tch_mode = l1a_tch_mode_set(tch_mode);
545 audio_mode = l1a_audio_mode_set(audio_mode);
547 audio_set_enabled(tch_mode, audio_mode);
549 l1s.tch_sync = 1; /* Needed for audio to work */
550 l1s.tch_loop_mode = tch_mode_req->tch_loop_mode;
552 l1ctl_tx_tch_mode_conf(tch_mode, audio_mode);
555 /* receive a L1CTL_NEIGH_PM_REQ from L23 */
556 static void l1ctl_rx_neigh_pm_req(struct msgb *msg)
558 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
559 struct l1ctl_neigh_pm_req *pm_req =
560 (struct l1ctl_neigh_pm_req *) l1h->data;
561 int i;
563 /* reset list in order to prevent race condition */
564 l1s.neigh_pm.n = 0; /* atomic */
565 l1s.neigh_pm.second = 0;
566 /* now reset pointer and fill list */
567 l1s.neigh_pm.pos = 0;
568 l1s.neigh_pm.running = 0;
569 for (i = 0; i < pm_req->n; i++) {
570 l1s.neigh_pm.band_arfcn[i] = ntohs(pm_req->band_arfcn[i]);
571 l1s.neigh_pm.tn[i] = pm_req->tn[i];
573 printf("L1CTL_NEIGH_PM_REQ new list with %u entries\n", pm_req->n);
574 l1s.neigh_pm.n = pm_req->n; /* atomic */
576 /* on C0 enable PM on frame 51 */
577 if (l1s.dedicated.type == GSM_DCHAN_NONE)
578 mframe_enable(MF_TASK_NEIGH_PM51_C0T0);
581 /* receive a L1CTL_TRAFFIC_REQ from L23 */
582 static void l1ctl_rx_traffic_req(struct msgb *msg)
584 struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
585 struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
586 struct l1ctl_traffic_req *tr = (struct l1ctl_traffic_req *) ul->payload;
587 int num = 0;
589 /* printd("L1CTL_TRAFFIC_REQ\n"); */ /* Very verbose, can overwhelm serial */
591 msg->l2h = tr->data;
593 num = l1a_txq_msgb_count(&l1s.tx_queue[L1S_CHAN_TRAFFIC]);
594 if (num >= 4) {
595 printd("dropping traffic frame\n");
596 msgb_free(msg);
597 return;
600 l1a_txq_msgb_enq(&l1s.tx_queue[L1S_CHAN_TRAFFIC], msg);
603 static void l1ctl_sim_req(struct msgb *msg)
605 uint16_t len = msg->len - sizeof(struct l1ctl_hdr);
606 uint8_t *data = msg->data + sizeof(struct l1ctl_hdr);
608 #if 1 /* for debugging only */
610 int i;
611 printf("SIM Request (%u): ", len);
612 for (i = 0; i < len; i++)
613 printf("%02x ", data[i]);
614 puts("\n");
616 #endif
618 sim_apdu(len, data);
621 static struct llist_head l23_rx_queue = LLIST_HEAD_INIT(l23_rx_queue);
623 /* callback from SERCOMM when L2 sends a message to L1 */
624 void l1a_l23_rx(uint8_t dlci, struct msgb *msg)
626 unsigned long flags;
628 local_firq_save(flags);
629 msgb_enqueue(&l23_rx_queue, msg);
630 local_irq_restore(flags);
633 void l1a_l23_handler(void)
635 struct msgb *msg;
636 struct l1ctl_hdr *l1h;
637 unsigned long flags;
639 local_firq_save(flags);
640 msg = msgb_dequeue(&l23_rx_queue);
641 local_irq_restore(flags);
642 if (!msg)
643 return;
645 l1h = (struct l1ctl_hdr *) msg->data;
647 #if 0
649 int i;
650 printf("l1a_l23_rx_cb (%u): ", msg->len);
651 for (i = 0; i < msg->len; i++)
652 printf("%02x ", msg->data[i]);
653 puts("\n");
655 #endif
657 msg->l1h = msg->data;
659 if (sizeof(*l1h) > msg->len) {
660 printf("l1a_l23_cb: Short message. %u\n", msg->len);
661 goto exit_msgbfree;
664 switch (l1h->msg_type) {
665 case L1CTL_FBSB_REQ:
666 l1ctl_rx_fbsb_req(msg);
667 break;
668 case L1CTL_DM_EST_REQ:
669 l1ctl_rx_dm_est_req(msg);
670 break;
671 case L1CTL_DM_REL_REQ:
672 l1ctl_rx_dm_rel_req(msg);
673 break;
674 case L1CTL_PARAM_REQ:
675 l1ctl_rx_param_req(msg);
676 break;
677 case L1CTL_DM_FREQ_REQ:
678 l1ctl_rx_dm_freq_req(msg);
679 break;
680 case L1CTL_CRYPTO_REQ:
681 l1ctl_rx_crypto_req(msg);
682 break;
683 case L1CTL_RACH_REQ:
684 l1ctl_rx_rach_req(msg);
685 break;
686 case L1CTL_DATA_REQ:
687 l1ctl_rx_data_req(msg);
688 /* we have to keep the msgb, not free it! */
689 goto exit_nofree;
690 case L1CTL_PM_REQ:
691 l1ctl_rx_pm_req(msg);
692 break;
693 case L1CTL_RESET_REQ:
694 l1ctl_rx_reset_req(msg);
695 break;
696 case L1CTL_CCCH_MODE_REQ:
697 l1ctl_rx_ccch_mode_req(msg);
698 break;
699 case L1CTL_TCH_MODE_REQ:
700 l1ctl_rx_tch_mode_req(msg);
701 break;
702 case L1CTL_NEIGH_PM_REQ:
703 l1ctl_rx_neigh_pm_req(msg);
704 break;
705 case L1CTL_TRAFFIC_REQ:
706 l1ctl_rx_traffic_req(msg);
707 /* we have to keep the msgb, not free it! */
708 goto exit_nofree;
709 case L1CTL_SIM_REQ:
710 l1ctl_sim_req(msg);
711 break;
714 exit_msgbfree:
715 msgb_free(msg);
716 exit_nofree:
717 return;
720 void l1a_l23api_init(void)
722 sercomm_register_rx_cb(SC_DLCI_L1A_L23, l1a_l23_rx);