target/fw/l23_api: Enable/Disable audio path appropriately
[osmocom-bb.git] / src / target / firmware / layer1 / l23_api.c
1 /* Synchronous part of GSM Layer 1: API to Layer2+ */
2
3 /* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
4  *
5  * All Rights Reserved
6  *
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.
11  *
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.
16  *
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.
20  *
21  */
22
23 #define DEBUG
24
25 #include <stdint.h>
26 #include <stdio.h>
27 #include <string.h>
28
29 #include <debug.h>
30 #include <byteorder.h>
31
32 #include <osmocore/msgb.h>
33 #include <osmocore/protocol/gsm_04_08.h>
34 #include <comm/sercomm.h>
35
36 #include <layer1/sync.h>
37 #include <layer1/async.h>
38 #include <layer1/mframe_sched.h>
39 #include <layer1/prim.h>
40 #include <layer1/tpu_window.h>
41
42 #include <abb/twl3025.h>
43 #include <rf/trf6151.h>
44
45 #include <l1ctl_proto.h>
46
47 /* the size we will allocate struct msgb* for HDLC */
48 #define L3_MSG_HEAD 4
49 #define L3_MSG_SIZE (sizeof(struct l1ctl_hdr)+sizeof(struct l1ctl_info_dl)+sizeof(struct l1ctl_data_ind) + L3_MSG_HEAD)
50
51 void l1_queue_for_l2(struct msgb *msg)
52 {
53         /* forward via serial for now */
54         sercomm_sendmsg(SC_DLCI_L1A_L23, msg);
55 }
56
57 static enum mframe_task chan_nr2mf_task(uint8_t chan_nr)
58 {
59         uint8_t cbits = chan_nr >> 3;
60         uint8_t tn = chan_nr & 0x7;
61         uint8_t lch_idx;
62
63         if (cbits == 0x01) {
64                 lch_idx = 0;
65                 return (tn & 1) ? MF_TASK_TCH_F_ODD : MF_TASK_TCH_F_EVEN;
66         } else if ((cbits & 0x1e) == 0x02) {
67                 lch_idx = cbits & 0x1;
68                 return MF_TASK_TCH_H_0 + lch_idx;
69         } else if ((cbits & 0x1c) == 0x04) {
70                 lch_idx = cbits & 0x3;
71                 return MF_TASK_SDCCH4_0 + lch_idx;
72         } else if ((cbits & 0x18) == 0x08) {
73                 lch_idx = cbits & 0x7;
74                 return MF_TASK_SDCCH8_0 + lch_idx;
75 #if 0
76         } else if (cbits == 0x10) {
77                 /* FIXME: when to do extended BCCH? */
78                 return MF_TASK_BCCH_NORM;
79         } else if (cbits == 0x11 || cbits == 0x12) {
80                 /* FIXME: how to decide CCCH norm/extd? */
81                 return MF_TASK_BCCH_CCCH;
82 #endif
83         }
84         return 0;
85 }
86
87 static int  chan_nr2dchan_type(uint8_t chan_nr)
88 {
89         uint8_t cbits = chan_nr >> 3;
90
91         if (cbits == 0x01) {
92                 return GSM_DCHAN_TCH_F;
93         } else if ((cbits & 0x1e) == 0x02) {
94                 return GSM_DCHAN_TCH_H;
95         } else if ((cbits & 0x1c) == 0x04) {
96                 return GSM_DCHAN_SDCCH_4;
97         } else if ((cbits & 0x18) == 0x08) {
98                 return GSM_DCHAN_SDCCH_8;
99         }
100         return GSM_DCHAN_UNKNOWN;
101 }
102
103 static int chan_nr_is_tch(uint8_t chan_nr)
104 {
105         return ((chan_nr >> 3) == 0x01 ||               /* TCH/F */
106                 ((chan_nr >> 3) & 0x1e) == 0x02);       /* TCH/H */
107 }
108
109 static void audio_set_enabled(int enabled)
110 {
111         twl3025_unit_enable(TWL3025_UNIT_VUL, enabled);
112         twl3025_unit_enable(TWL3025_UNIT_VDL, enabled);
113 }
114
115 struct msgb *l1ctl_msgb_alloc(uint8_t msg_type)
116 {
117         struct msgb *msg;
118         struct l1ctl_hdr *l1h;
119
120         msg = msgb_alloc_headroom(L3_MSG_SIZE, L3_MSG_HEAD, "l1ctl");
121         if (!msg) {
122                 while (1) {
123                         puts("OOPS. Out of buffers...\n");
124                 }
125
126                 return NULL;
127         }
128         l1h = (struct l1ctl_hdr *) msgb_put(msg, sizeof(*l1h));
129         l1h->msg_type = msg_type;
130         l1h->flags = 0;
131
132         msg->l1h = (uint8_t *)l1h;
133
134         return msg;
135 }
136
137 struct msgb *l1_create_l2_msg(int msg_type, uint32_t fn, uint16_t snr,
138                               uint16_t arfcn)
139 {
140         struct l1ctl_info_dl *dl;
141         struct msgb *msg = l1ctl_msgb_alloc(msg_type);
142
143         dl = (struct l1ctl_info_dl *) msgb_put(msg, sizeof(*dl));
144         dl->frame_nr = htonl(fn);
145         dl->snr = snr;
146         dl->band_arfcn = htons(arfcn);
147
148         return msg;
149 }
150
151 /* receive a L1CTL_FBSB_REQ from L23 */
152 static void l1ctl_rx_fbsb_req(struct msgb *msg)
153 {
154         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
155         struct l1ctl_fbsb_req *sync_req = (struct l1ctl_fbsb_req *) l1h->data;
156
157         if (sizeof(*sync_req) > msg->len) {
158                 printf("Short sync msg. %u\n", msg->len);
159                 return;
160         }
161
162         printd("L1CTL_FBSB_REQ (arfcn=%u, flags=0x%x)\n",
163                 ntohs(sync_req->band_arfcn), sync_req->flags);
164
165         /* reset scheduler and hardware */
166         l1s_reset();
167
168         /* pre-set the CCCH mode */
169         l1s.serving_cell.ccch_mode = sync_req->ccch_mode;
170
171         printd("Starting FCCH Recognition\n");
172         l1s_fbsb_req(1, sync_req);
173 }
174
175 /* receive a L1CTL_DM_EST_REQ from L23 */
176 static void l1ctl_rx_dm_est_req(struct msgb *msg)
177 {
178         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
179         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
180         struct l1ctl_dm_est_req *est_req = (struct l1ctl_dm_est_req *) ul->payload;
181
182         printd("L1CTL_DM_EST_REQ (arfcn=%u, chan_nr=0x%02x, tsc=%u)\n",
183                 ntohs(est_req->h0.band_arfcn), ul->chan_nr, est_req->tsc);
184
185         /* configure dedicated channel state */
186         l1s.dedicated.type = chan_nr2dchan_type(ul->chan_nr);
187         l1s.dedicated.tsc  = est_req->tsc;
188         l1s.dedicated.tn   = ul->chan_nr & 0x7;
189         l1s.dedicated.h    = est_req->h;
190
191         if (est_req->h) {
192                 int i;
193                 l1s.dedicated.h1.hsn  = est_req->h1.hsn;
194                 l1s.dedicated.h1.maio = est_req->h1.maio;
195                 l1s.dedicated.h1.n    = est_req->h1.n;
196                 for (i=0; i<est_req->h1.n; i++)
197                         l1s.dedicated.h1.ma[i] = ntohs(est_req->h1.ma[i]);
198         } else {
199                 l1s.dedicated.h0.arfcn = ntohs(est_req->h0.band_arfcn);
200         }
201
202         /* TCH config */
203         if (chan_nr_is_tch(ul->chan_nr)) {
204                 /* Mode */
205                 l1a_tch_mode_set(est_req->tch_mode);
206
207                 /* Sync */
208                 l1s.tch_sync = 1;       /* can be set without locking */
209
210                 /* Audio path */
211                 audio_set_enabled(est_req->tch_mode != GSM48_CMODE_SIGN);
212         }
213
214         /* figure out which MF tasks to enable */
215         l1a_mftask_set(1 << chan_nr2mf_task(ul->chan_nr));
216 }
217
218 /* receive a L1CTL_DM_FREQ_REQ from L23 */
219 static void l1ctl_rx_dm_freq_req(struct msgb *msg)
220 {
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_freq_req *freq_req =
224                         (struct l1ctl_dm_freq_req *) ul->payload;
225
226         printd("L1CTL_DM_FREQ_REQ (arfcn=%u, tsc=%u)\n",
227                 ntohs(freq_req->h0.band_arfcn), freq_req->tsc);
228
229         /* configure dedicated channel state */
230         l1s.dedicated.st_tsc  = freq_req->tsc;
231         l1s.dedicated.st_h    = freq_req->h;
232
233         if (freq_req->h) {
234                 int i;
235                 l1s.dedicated.st_h1.hsn  = freq_req->h1.hsn;
236                 l1s.dedicated.st_h1.maio = freq_req->h1.maio;
237                 l1s.dedicated.st_h1.n    = freq_req->h1.n;
238                 for (i=0; i<freq_req->h1.n; i++)
239                         l1s.dedicated.st_h1.ma[i] = ntohs(freq_req->h1.ma[i]);
240         } else {
241                 l1s.dedicated.st_h0.arfcn = ntohs(freq_req->h0.band_arfcn);
242         }
243
244         l1a_freq_req(ntohs(freq_req->fn));
245 }
246
247 /* receive a L1CTL_CRYPTO_REQ from L23 */
248 static void l1ctl_rx_crypto_req(struct msgb *msg)
249 {
250         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
251         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
252         struct l1ctl_crypto_req *cr = (struct l1ctl_crypto_req *) ul->payload;
253         uint8_t key_len = msg->len - sizeof(*l1h) - sizeof(*ul) - sizeof(*cr);
254
255         printd("L1CTL_CRYPTO_REQ (algo=A5/%u, len=%u)\n", cr->algo, key_len);
256
257         if (cr->algo && key_len != 8) {
258                 printd("L1CTL_CRYPTO_REQ -> Invalid key\n");
259                 return;
260         }
261
262         dsp_load_ciph_param(cr->algo, cr->key);
263 }
264
265 /* receive a L1CTL_DM_REL_REQ from L23 */
266 static void l1ctl_rx_dm_rel_req(struct msgb *msg)
267 {
268         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
269         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
270
271         printd("L1CTL_DM_REL_REQ\n");
272         l1a_mftask_set(0);
273         l1s.dedicated.type = GSM_DCHAN_NONE;
274         l1a_txq_msgb_flush(&l1s.tx_queue[L1S_CHAN_MAIN]);
275         l1a_txq_msgb_flush(&l1s.tx_queue[L1S_CHAN_SACCH]);
276         l1a_meas_msgb_set(NULL);
277         dsp_load_ciph_param(0, NULL);
278         l1a_tch_mode_set(GSM48_CMODE_SIGN);
279         audio_set_enabled(0);
280 }
281
282 /* receive a L1CTL_PARAM_REQ from L23 */
283 static void l1ctl_rx_param_req(struct msgb *msg)
284 {
285         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
286         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
287         struct l1ctl_par_req *par_req = (struct l1ctl_par_req *) ul->payload;
288
289         printd("L1CTL_PARAM_REQ (ta=%d, tx_power=%d)\n", par_req->ta,
290                 par_req->tx_power);
291
292         l1s.ta = par_req->ta;
293         l1s.tx_power = par_req->tx_power;
294 }
295
296 /* receive a L1CTL_RACH_REQ from L23 */
297 static void l1ctl_rx_rach_req(struct msgb *msg)
298 {
299         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
300         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
301         struct l1ctl_rach_req *rach_req = (struct l1ctl_rach_req *) ul->payload;
302
303         printd("L1CTL_RACH_REQ (ra=0x%02x, fn51=%d, mf_off=%d)\n", rach_req->ra, rach_req->fn51, rach_req->mf_off);
304
305         l1a_rach_req(rach_req->fn51, rach_req->mf_off, rach_req->ra);
306 }
307
308 /* receive a L1CTL_DATA_REQ from L23 */
309 static void l1ctl_rx_data_req(struct msgb *msg)
310 {
311         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
312         struct l1ctl_info_ul *ul = (struct l1ctl_info_ul *) l1h->data;
313         struct l1ctl_data_ind *data_ind = (struct l1ctl_data_ind *) ul->payload;
314         struct llist_head *tx_queue;
315
316         printd("L1CTL_DATA_REQ (link_id=0x%02x)\n", ul->link_id);
317
318         msg->l3h = data_ind->data;
319         if (ul->link_id & 0x40) {
320                 struct gsm48_hdr *gh = (struct gsm48_hdr *)(data_ind->data + 5);
321                 if (gh->proto_discr == GSM48_PDISC_RR
322                  && gh->msg_type == GSM48_MT_RR_MEAS_REP) {
323                         printd("updating measurement report\n");
324                         l1a_meas_msgb_set(msg);
325                         return;
326                 }
327                 tx_queue = &l1s.tx_queue[L1S_CHAN_SACCH];
328         } else
329                 tx_queue = &l1s.tx_queue[L1S_CHAN_MAIN];
330
331         printd("ul=%p, ul->payload=%p, data_ind=%p, data_ind->data=%p l3h=%p\n",
332                 ul, ul->payload, data_ind, data_ind->data, msg->l3h);
333
334         l1a_txq_msgb_enq(tx_queue, msg);
335 }
336
337 /* receive a L1CTL_PM_REQ from L23 */
338 static void l1ctl_rx_pm_req(struct msgb *msg)
339 {
340         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
341         struct l1ctl_pm_req *pm_req = (struct l1ctl_pm_req *) l1h->data;
342
343         switch (pm_req->type) {
344         case 1:
345                 l1s.pm.mode = 1;
346                 l1s.pm.range.arfcn_start =
347                                 ntohs(pm_req->range.band_arfcn_from);
348                 l1s.pm.range.arfcn_next =
349                                 ntohs(pm_req->range.band_arfcn_from);
350                 l1s.pm.range.arfcn_end =
351                                 ntohs(pm_req->range.band_arfcn_to);
352                 printf("L1CTL_PM_REQ start=%u end=%u\n",
353                         l1s.pm.range.arfcn_start, l1s.pm.range.arfcn_end);
354                 break;
355         }
356
357         l1s_pm_test(1, l1s.pm.range.arfcn_next);
358 }
359
360 /* Transmit a L1CTL_RESET_IND or L1CTL_RESET_CONF */
361 void l1ctl_tx_reset(uint8_t msg_type, uint8_t reset_type)
362 {
363         struct msgb *msg = l1ctl_msgb_alloc(msg_type);
364         struct l1ctl_reset *reset_resp;
365         reset_resp = (struct l1ctl_reset *)
366                                 msgb_put(msg, sizeof(*reset_resp));
367         reset_resp->type = reset_type;
368
369         l1_queue_for_l2(msg);
370 }
371
372 /* receive a L1CTL_RESET_REQ from L23 */
373 static void l1ctl_rx_reset_req(struct msgb *msg)
374 {
375         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
376         struct l1ctl_reset *reset_req =
377                                 (struct l1ctl_reset *) l1h->data;
378
379         switch (reset_req->type) {
380         case L1CTL_RES_T_FULL:
381                 printf("L1CTL_RESET_REQ: FULL!\n");
382                 l1s_reset();
383                 l1s_reset_hw();
384                 audio_set_enabled(0);
385                 l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
386                 break;
387         case L1CTL_RES_T_SCHED:
388                 printf("L1CTL_RESET_REQ: SCHED!\n");
389                 l1ctl_tx_reset(L1CTL_RESET_CONF, reset_req->type);
390                 sched_gsmtime_reset();
391                 break;
392         default:
393                 printf("unknown L1CTL_RESET_REQ type\n");
394                 break;
395         }
396 }
397
398 /* Transmit a L1CTL_CCCH_MODE_CONF */
399 static void l1ctl_tx_ccch_mode_conf(uint8_t ccch_mode)
400 {
401         struct msgb *msg = l1ctl_msgb_alloc(L1CTL_CCCH_MODE_CONF);
402         struct l1ctl_ccch_mode_conf *mode_conf;
403         mode_conf = (struct l1ctl_ccch_mode_conf *)
404                                 msgb_put(msg, sizeof(*mode_conf));
405         mode_conf->ccch_mode = ccch_mode;
406
407         l1_queue_for_l2(msg);
408 }
409
410 /* receive a L1CTL_CCCH_MODE_REQ from L23 */
411 static void l1ctl_rx_ccch_mode_req(struct msgb *msg)
412 {
413         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
414         struct l1ctl_ccch_mode_req *ccch_mode_req =
415                 (struct l1ctl_ccch_mode_req *) l1h->data;
416         uint8_t ccch_mode = ccch_mode_req->ccch_mode;
417
418         /* pre-set the CCCH mode */
419         l1s.serving_cell.ccch_mode = ccch_mode;
420
421         /* Update task */
422         mframe_disable(MF_TASK_CCCH_COMB);
423         mframe_disable(MF_TASK_CCCH);
424
425         if (ccch_mode == CCCH_MODE_COMBINED)
426                 mframe_enable(MF_TASK_CCCH_COMB);
427         else if (ccch_mode == CCCH_MODE_NON_COMBINED)
428                 mframe_enable(MF_TASK_CCCH);
429
430         l1ctl_tx_ccch_mode_conf(ccch_mode);
431 }
432
433 /* Transmit a L1CTL_TCH_MODE_CONF */
434 static void l1ctl_tx_tch_mode_conf(uint8_t tch_mode)
435 {
436         struct msgb *msg = l1ctl_msgb_alloc(L1CTL_TCH_MODE_CONF);
437         struct l1ctl_tch_mode_conf *mode_conf;
438         mode_conf = (struct l1ctl_tch_mode_conf *)
439                                 msgb_put(msg, sizeof(*mode_conf));
440         mode_conf->tch_mode = tch_mode;
441
442         l1_queue_for_l2(msg);
443 }
444
445 /* receive a L1CTL_TCH_MODE_REQ from L23 */
446 static void l1ctl_rx_tch_mode_req(struct msgb *msg)
447 {
448         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
449         struct l1ctl_tch_mode_req *tch_mode_req =
450                 (struct l1ctl_tch_mode_req *) l1h->data;
451         uint8_t tch_mode = tch_mode_req->tch_mode;
452
453         printd("L1CTL_TCH_MODE_REQ (mode=0x%02x)\n", tch_mode);
454         tch_mode = l1a_tch_mode_set(tch_mode);
455
456         audio_set_enabled(tch_mode != GSM48_CMODE_SIGN);
457
458         l1ctl_tx_tch_mode_conf(tch_mode);
459 }
460
461 /* callback from SERCOMM when L2 sends a message to L1 */
462 static void l1a_l23_rx_cb(uint8_t dlci, struct msgb *msg)
463 {
464         struct l1ctl_hdr *l1h = (struct l1ctl_hdr *) msg->data;
465
466 #if 0
467         {
468                 int i;
469                 printf("l1a_l23_rx_cb (%u): ", msg->len);
470                 for (i = 0; i < msg->len; i++)
471                         printf("%02x ", msg->data[i]);
472                 puts("\n");
473         }
474 #endif
475
476         msg->l1h = msg->data;
477
478         if (sizeof(*l1h) > msg->len) {
479                 printf("l1a_l23_cb: Short message. %u\n", msg->len);
480                 goto exit_msgbfree;
481         }
482
483         switch (l1h->msg_type) {
484         case L1CTL_FBSB_REQ:
485                 l1ctl_rx_fbsb_req(msg);
486                 break;
487         case L1CTL_DM_EST_REQ:
488                 l1ctl_rx_dm_est_req(msg);
489                 break;
490         case L1CTL_DM_REL_REQ:
491                 l1ctl_rx_dm_rel_req(msg);
492                 break;
493         case L1CTL_PARAM_REQ:
494                 l1ctl_rx_param_req(msg);
495                 break;
496         case L1CTL_DM_FREQ_REQ:
497                 l1ctl_rx_dm_freq_req(msg);
498                 break;
499         case L1CTL_CRYPTO_REQ:
500                 l1ctl_rx_crypto_req(msg);
501                 break;
502         case L1CTL_RACH_REQ:
503                 l1ctl_rx_rach_req(msg);
504                 break;
505         case L1CTL_DATA_REQ:
506                 l1ctl_rx_data_req(msg);
507                 /* we have to keep the msgb, not free it! */
508                 goto exit_nofree;
509         case L1CTL_PM_REQ:
510                 l1ctl_rx_pm_req(msg);
511                 break;
512         case L1CTL_RESET_REQ:
513                 l1ctl_rx_reset_req(msg);
514                 break;
515         case L1CTL_CCCH_MODE_REQ:
516                 l1ctl_rx_ccch_mode_req(msg);
517                 break;
518         case L1CTL_TCH_MODE_REQ:
519                 l1ctl_rx_tch_mode_req(msg);
520                 break;
521         }
522
523 exit_msgbfree:
524         msgb_free(msg);
525 exit_nofree:
526         return;
527 }
528
529 void l1a_l23api_init(void)
530 {
531         sercomm_register_rx_cb(SC_DLCI_L1A_L23, l1a_l23_rx_cb);
532 }