blob: 8351d68c42bfbf6146d4e8d82a1f2d95301a7610 [file] [log] [blame]
Andreas Eversberga23c7ee2012-12-18 10:47:28 +01001/* Interface handler for Sysmocom L1 (real hardware) */
2
3/* (C) 2011 by Harald Welte <laforge@gnumonks.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 Affero General Public License as published by
9 * the Free Software Foundation; either version 3 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 Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include <assert.h>
23#include <stdint.h>
24#include <unistd.h>
25#include <errno.h>
26#include <fcntl.h>
Holger Hans Peter Freyther81e8f0a2013-12-12 13:24:52 +010027#include <string.h>
Andreas Eversberga23c7ee2012-12-18 10:47:28 +010028
29#include <sys/types.h>
30#include <sys/stat.h>
31
32#include <osmocom/core/talloc.h>
33#include <osmocom/core/utils.h>
34#include <osmocom/core/select.h>
35#include <osmocom/core/write_queue.h>
36#include <osmocom/core/timer.h>
37#include <osmocom/gsm/gsm_utils.h>
38
39#include <sysmocom/femtobts/superfemto.h>
40#include <sysmocom/femtobts/gsml1prim.h>
41#include <sysmocom/femtobts/gsml1const.h>
42#include <sysmocom/femtobts/gsml1types.h>
43
44#include "gprs_debug.h"
45#include "femtobts.h"
46#include "sysmo_l1_if.h"
47
48
49#ifdef HW_SYSMOBTS_V1
50#define DEV_SYS_DSP2ARM_NAME "/dev/msgq/femtobts_dsp2arm"
51#define DEV_SYS_ARM2DSP_NAME "/dev/msgq/femtobts_arm2dsp"
52#define DEV_L1_DSP2ARM_NAME "/dev/msgq/gsml1_dsp2arm"
53#define DEV_L1_ARM2DSP_NAME "/dev/msgq/gsml1_arm2dsp"
54#else
55#define DEV_SYS_DSP2ARM_NAME "/dev/msgq/superfemto_dsp2arm"
56#define DEV_SYS_ARM2DSP_NAME "/dev/msgq/superfemto_arm2dsp"
57#define DEV_L1_DSP2ARM_NAME "/dev/msgq/gsml1_sig_dsp2arm"
58#define DEV_L1_ARM2DSP_NAME "/dev/msgq/gsml1_sig_arm2dsp"
59
60#define DEV_TCH_DSP2ARM_NAME "/dev/msgq/gsml1_tch_dsp2arm"
61#define DEV_TCH_ARM2DSP_NAME "/dev/msgq/gsml1_tch_arm2dsp"
62#define DEV_PDTCH_DSP2ARM_NAME "/dev/msgq/gsml1_pdtch_dsp2arm"
63#define DEV_PDTCH_ARM2DSP_NAME "/dev/msgq/gsml1_pdtch_arm2dsp"
64#endif
65
66static const char *rd_devnames[] = {
67 [MQ_SYS_READ] = DEV_SYS_DSP2ARM_NAME,
68 [MQ_L1_READ] = DEV_L1_DSP2ARM_NAME,
69#ifndef HW_SYSMOBTS_V1
70 [MQ_TCH_READ] = DEV_TCH_DSP2ARM_NAME,
71 [MQ_PDTCH_READ] = DEV_PDTCH_DSP2ARM_NAME,
72#endif
73};
74
75static const char *wr_devnames[] = {
76 [MQ_SYS_WRITE] = DEV_SYS_ARM2DSP_NAME,
77 [MQ_L1_WRITE] = DEV_L1_ARM2DSP_NAME,
78#ifndef HW_SYSMOBTS_V1
79 [MQ_TCH_WRITE] = DEV_TCH_ARM2DSP_NAME,
80 [MQ_PDTCH_WRITE]= DEV_PDTCH_ARM2DSP_NAME,
81#endif
82};
83
84/* callback when there's something to read from the l1 msg_queue */
85static int l1if_fd_cb(struct osmo_fd *ofd, unsigned int what)
86{
87 //struct msgb *msg = l1p_msgb_alloc();
88 struct msgb *msg = msgb_alloc_headroom(sizeof(SuperFemto_Prim_t) + 128,
89 128, "1l_fd");
90 struct femtol1_hdl *fl1h = ofd->data;
91 int rc;
92
93 msg->l1h = msg->data;
94 rc = read(ofd->fd, msg->l1h, msgb_tailroom(msg));
95 if (rc < 0) {
96 if (rc != -1)
97 LOGP(DL1IF, LOGL_ERROR, "error reading from L1 msg_queue: %s\n",
98 strerror(errno));
99 msgb_free(msg);
100 return rc;
101 }
102 msgb_put(msg, rc);
103
104 switch (ofd->priv_nr) {
105 case MQ_SYS_WRITE:
106 if (rc != sizeof(SuperFemto_Prim_t))
107 LOGP(DL1IF, LOGL_NOTICE, "%u != "
108 "sizeof(SuperFemto_Prim_t)\n", rc);
109 return l1if_handle_sysprim(fl1h, msg);
110 case MQ_L1_WRITE:
111#ifndef HW_SYSMOBTS_V1
112 case MQ_TCH_WRITE:
113 case MQ_PDTCH_WRITE:
114#endif
115 if (rc != sizeof(GsmL1_Prim_t))
116 LOGP(DL1IF, LOGL_NOTICE, "%u != "
117 "sizeof(GsmL1_Prim_t)\n", rc);
118 return l1if_handle_l1prim(ofd->priv_nr, fl1h, msg);
119 default:
120 /* The compiler can't know that priv_nr is an enum. Assist. */
121 LOGP(DL1IF, LOGL_FATAL, "writing on a wrong queue: %d\n",
122 ofd->priv_nr);
123 exit(0);
124 break;
125 }
126};
127
128/* callback when we can write to one of the l1 msg_queue devices */
129static int l1fd_write_cb(struct osmo_fd *ofd, struct msgb *msg)
130{
131 int rc;
132
133 rc = write(ofd->fd, msg->l1h, msgb_l1len(msg));
134 if (rc < 0) {
135 LOGP(DL1IF, LOGL_ERROR, "error writing to L1 msg_queue: %s\n",
136 strerror(errno));
137 return rc;
138 } else if (rc < msg->len) {
139 LOGP(DL1IF, LOGL_ERROR, "short write to L1 msg_queue: "
140 "%u < %u\n", rc, msg->len);
141 return -EIO;
142 }
143
144 return 0;
145}
146
147int l1if_transport_open(int q, struct femtol1_hdl *hdl)
148{
149 int rc;
150
151 /* Step 1: Open all msg_queue file descriptors */
152 struct osmo_fd *read_ofd = &hdl->read_ofd[q];
153 struct osmo_wqueue *wq = &hdl->write_q[q];
154 struct osmo_fd *write_ofd = &hdl->write_q[q].bfd;
155
156 rc = open(rd_devnames[q], O_RDONLY);
157 if (rc < 0) {
158 LOGP(DL1IF, LOGL_FATAL, "unable to open msg_queue: %s\n",
159 strerror(errno));
160 return rc;
161 }
162 read_ofd->fd = rc;
163 read_ofd->priv_nr = q;
164 read_ofd->data = hdl;
165 read_ofd->cb = l1if_fd_cb;
166 read_ofd->when = BSC_FD_READ;
167 rc = osmo_fd_register(read_ofd);
168 if (rc < 0) {
169 close(read_ofd->fd);
170 read_ofd->fd = -1;
171 return rc;
172 }
173
174 rc = open(wr_devnames[q], O_WRONLY);
175 if (rc < 0) {
176 LOGP(DL1IF, LOGL_FATAL, "unable to open msg_queue: %s\n",
177 strerror(errno));
178 goto out_read;
179 }
180 osmo_wqueue_init(wq, 10);
181 wq->write_cb = l1fd_write_cb;
182 write_ofd->fd = rc;
183 write_ofd->priv_nr = q;
184 write_ofd->data = hdl;
185 write_ofd->when = BSC_FD_WRITE;
186 rc = osmo_fd_register(write_ofd);
187 if (rc < 0) {
188 close(write_ofd->fd);
189 write_ofd->fd = -1;
190 goto out_read;
191 }
192
193 return 0;
194
195out_read:
196 close(hdl->read_ofd[q].fd);
197 osmo_fd_unregister(&hdl->read_ofd[q]);
198
199 return rc;
200}
201
202int l1if_transport_close(int q, struct femtol1_hdl *hdl)
203{
204 struct osmo_fd *read_ofd = &hdl->read_ofd[q];
205 struct osmo_fd *write_ofd = &hdl->write_q[q].bfd;
206
207 osmo_fd_unregister(read_ofd);
208 close(read_ofd->fd);
209 read_ofd->fd = -1;
210
211 osmo_fd_unregister(write_ofd);
212 close(write_ofd->fd);
213 write_ofd->fd = -1;
214
215 return 0;
216}