1 /* Synchronous part of GSM Layer 1: API to Layer2+ */
3 /* (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
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.
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 */
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
)
61 /* forward via serial for now */
62 sercomm_sendmsg(SC_DLCI_L1A_L23
, msg
);
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;
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;
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
;
93 } else if ((cbits
& 0x18) == 0x08) {
94 lch_idx
= cbits
& 0x7;
95 master_task
= MF_TASK_SDCCH8_0
+ lch_idx
;
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 */
103 } else if ((cbits
& 0x1f) == 0x19) {
104 /* Osmocom specific extension for CBCH on SDCCH/4 */
105 master_task
= MF_TASK_SDCCH4_CBCH
;
107 } else if ((cbits
& 0x1f) == 0x1a) {
108 /* Osmocom specific extension for CBCH on SDCCH/8 */
109 master_task
= MF_TASK_SDCCH8_CBCH
;
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
;
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
) {
128 switch (multiframe
) {
130 task_mask
|= (1 << MF_TASK_NEIGH_PM51
);
133 task_mask
|= (1 << MF_TASK_NEIGH_PM26E
);
136 task_mask
|= (1 << MF_TASK_NEIGH_PM26O
);
145 static int chan_nr2dchan_type(uint8_t chan_nr
)
147 uint8_t cbits
= chan_nr
>> 3;
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);
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
)
193 struct l1ctl_hdr
*l1h
;
195 msg
= msgb_alloc_headroom(L3_MSG_SIZE
, L3_MSG_HEAD
, "l1ctl");
198 puts("OOPS. Out of buffers...\n");
203 l1h
= (struct l1ctl_hdr
*) msgb_put(msg
, sizeof(*l1h
));
204 l1h
->msg_type
= msg_type
;
207 msg
->l1h
= (uint8_t *)l1h
;
212 struct msgb
*l1_create_l2_msg(int msg_type
, uint32_t fn
, uint16_t snr
,
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
);
221 dl
->band_arfcn
= htons(arfcn
);
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
);
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 */
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
;
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
]);
277 l1s
.dedicated
.h0
.arfcn
= ntohs(est_req
->h0
.band_arfcn
);
281 if (chan_nr_is_tch(ul
->chan_nr
)) {
283 l1a_tch_mode_set(est_req
->tch_mode
);
284 l1a_audio_mode_set(est_req
->audio_mode
);
287 l1s
.tch_sync
= 1; /* can be set without locking */
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
;
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
]);
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");
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");
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
;
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
,
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
,
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
);
409 tx_queue
= &l1s
.tx_queue
[L1S_CHAN_SACCH
];
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
) {
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
);
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");
466 audio_set_enabled(GSM48_CMODE_SIGN
, 0);
467 l1ctl_tx_reset(L1CTL_RESET_CONF
, reset_req
->type
);
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();
475 printf("unknown L1CTL_RESET_REQ type\n");
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
;
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
;
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
;
589 /* printd("L1CTL_TRAFFIC_REQ\n"); */ /* Very verbose, can overwhelm serial */
593 num
= l1a_txq_msgb_count(&l1s
.tx_queue
[L1S_CHAN_TRAFFIC
]);
595 printd("dropping traffic frame\n");
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 */
611 printf("SIM Request (%u): ", len
);
612 for (i
= 0; i
< len
; i
++)
613 printf("%02x ", data
[i
]);
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
)
628 local_firq_save(flags
);
629 msgb_enqueue(&l23_rx_queue
, msg
);
630 local_irq_restore(flags
);
633 void l1a_l23_handler(void)
636 struct l1ctl_hdr
*l1h
;
639 local_firq_save(flags
);
640 msg
= msgb_dequeue(&l23_rx_queue
);
641 local_irq_restore(flags
);
645 l1h
= (struct l1ctl_hdr
*) msg
->data
;
650 printf("l1a_l23_rx_cb (%u): ", msg
->len
);
651 for (i
= 0; i
< msg
->len
; i
++)
652 printf("%02x ", msg
->data
[i
]);
657 msg
->l1h
= msg
->data
;
659 if (sizeof(*l1h
) > msg
->len
) {
660 printf("l1a_l23_cb: Short message. %u\n", msg
->len
);
664 switch (l1h
->msg_type
) {
666 l1ctl_rx_fbsb_req(msg
);
668 case L1CTL_DM_EST_REQ
:
669 l1ctl_rx_dm_est_req(msg
);
671 case L1CTL_DM_REL_REQ
:
672 l1ctl_rx_dm_rel_req(msg
);
674 case L1CTL_PARAM_REQ
:
675 l1ctl_rx_param_req(msg
);
677 case L1CTL_DM_FREQ_REQ
:
678 l1ctl_rx_dm_freq_req(msg
);
680 case L1CTL_CRYPTO_REQ
:
681 l1ctl_rx_crypto_req(msg
);
684 l1ctl_rx_rach_req(msg
);
687 l1ctl_rx_data_req(msg
);
688 /* we have to keep the msgb, not free it! */
691 l1ctl_rx_pm_req(msg
);
693 case L1CTL_RESET_REQ
:
694 l1ctl_rx_reset_req(msg
);
696 case L1CTL_CCCH_MODE_REQ
:
697 l1ctl_rx_ccch_mode_req(msg
);
699 case L1CTL_TCH_MODE_REQ
:
700 l1ctl_rx_tch_mode_req(msg
);
702 case L1CTL_NEIGH_PM_REQ
:
703 l1ctl_rx_neigh_pm_req(msg
);
705 case L1CTL_TRAFFIC_REQ
:
706 l1ctl_rx_traffic_req(msg
);
707 /* we have to keep the msgb, not free it! */
720 void l1a_l23api_init(void)
722 sercomm_register_rx_cb(SC_DLCI_L1A_L23
, l1a_l23_rx
);