blob: b58a2f48714c4c2c947b5e82e1964f86fb829bf1 [file] [log] [blame]
Yves Godin660709d2016-05-19 11:08:03 +02001/* Interface handler for Nuran Wireless Litecell 1.5 L1 (real hardware) */
2
3/* Copyright (C) 2015 by Yves Godin <support@nuranwireless.com>
4 * based on:
5 * femto_l1_hw.c
6 * (C) 2011 by Harald Welte <laforge@gnumonks.org>
7 *
8 * All Rights Reserved
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Affero General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU Affero General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24
25#include <assert.h>
26#include <stdint.h>
27#include <unistd.h>
28#include <errno.h>
29#include <fcntl.h>
30#include <string.h>
31#include <limits.h>
32
33#include <sys/types.h>
34#include <sys/stat.h>
35
36#include <osmocom/core/talloc.h>
37#include <osmocom/core/utils.h>
38#include <osmocom/core/select.h>
39#include <osmocom/core/write_queue.h>
40#include <osmocom/core/timer.h>
41#include <osmocom/gsm/gsm_utils.h>
42
43#include <nrw/litecell15/litecell15.h>
44#include <nrw/litecell15/gsml1prim.h>
45#include <nrw/litecell15/gsml1const.h>
46#include <nrw/litecell15/gsml1types.h>
47
48#include "gprs_debug.h"
49#include "lc15bts.h"
50#include "lc15_l1_if.h"
51
52#define DEV_SYS_DSP2ARM_NAME "/dev/msgq/litecell15_dsp2arm_trx"
53#define DEV_SYS_ARM2DSP_NAME "/dev/msgq/litecell15_arm2dsp_trx"
54#define DEV_L1_DSP2ARM_NAME "/dev/msgq/gsml1_sig_dsp2arm_trx"
55#define DEV_L1_ARM2DSP_NAME "/dev/msgq/gsml1_sig_arm2dsp_trx"
56
57#define DEV_TCH_DSP2ARM_NAME "/dev/msgq/gsml1_tch_dsp2arm_trx"
58#define DEV_TCH_ARM2DSP_NAME "/dev/msgq/gsml1_tch_arm2dsp_trx"
59#define DEV_PDTCH_DSP2ARM_NAME "/dev/msgq/gsml1_pdtch_dsp2arm_trx"
60#define DEV_PDTCH_ARM2DSP_NAME "/dev/msgq/gsml1_pdtch_arm2dsp_trx"
61
62static const char *rd_devnames[] = {
63 [MQ_SYS_READ] = DEV_SYS_DSP2ARM_NAME,
64 [MQ_L1_READ] = DEV_L1_DSP2ARM_NAME,
65 [MQ_TCH_READ] = DEV_TCH_DSP2ARM_NAME,
66 [MQ_PDTCH_READ] = DEV_PDTCH_DSP2ARM_NAME,
67};
68
69static const char *wr_devnames[] = {
70 [MQ_SYS_WRITE] = DEV_SYS_ARM2DSP_NAME,
71 [MQ_L1_WRITE] = DEV_L1_ARM2DSP_NAME,
72 [MQ_TCH_WRITE] = DEV_TCH_ARM2DSP_NAME,
73 [MQ_PDTCH_WRITE]= DEV_PDTCH_ARM2DSP_NAME,
74};
75
76/* callback when there's something to read from the l1 msg_queue */
77static int l1if_fd_cb(struct osmo_fd *ofd, unsigned int what)
78{
79 //struct msgb *msg = l1p_msgb_alloc();
80 struct msgb *msg = msgb_alloc_headroom(sizeof(Litecell15_Prim_t) + 128,
81 128, "1l_fd");
82 struct lc15l1_hdl *fl1h = ofd->data;
83 int rc;
84
85 msg->l1h = msg->data;
86 rc = read(ofd->fd, msg->l1h, msgb_tailroom(msg));
87 if (rc < 0) {
88 if (rc != -1)
89 LOGP(DL1IF, LOGL_ERROR, "error reading from L1 msg_queue: %s\n",
90 strerror(errno));
91 msgb_free(msg);
92 return rc;
93 }
94 msgb_put(msg, rc);
95
96 switch (ofd->priv_nr) {
97 case MQ_SYS_WRITE:
98 if (rc != sizeof(Litecell15_Prim_t))
99 LOGP(DL1IF, LOGL_NOTICE, "%u != "
100 "sizeof(Litecell15_Prim_t)\n", rc);
101 return l1if_handle_sysprim(fl1h, msg);
102 case MQ_L1_WRITE:
103 case MQ_TCH_WRITE:
104 case MQ_PDTCH_WRITE:
105 if (rc != sizeof(GsmL1_Prim_t))
106 LOGP(DL1IF, LOGL_NOTICE, "%u != "
107 "sizeof(GsmL1_Prim_t)\n", rc);
108 return l1if_handle_l1prim(ofd->priv_nr, fl1h, msg);
109 default:
110 /* The compiler can't know that priv_nr is an enum. Assist. */
111 LOGP(DL1IF, LOGL_FATAL, "writing on a wrong queue: %d\n",
112 ofd->priv_nr);
113 exit(0);
114 break;
115 }
116};
117
118/* callback when we can write to one of the l1 msg_queue devices */
119static int l1fd_write_cb(struct osmo_fd *ofd, struct msgb *msg)
120{
121 int rc;
122
123 rc = write(ofd->fd, msg->l1h, msgb_l1len(msg));
124 if (rc < 0) {
125 LOGP(DL1IF, LOGL_ERROR, "error writing to L1 msg_queue: %s\n",
126 strerror(errno));
127 return rc;
128 } else if (rc < msg->len) {
129 LOGP(DL1IF, LOGL_ERROR, "short write to L1 msg_queue: "
130 "%u < %u\n", rc, msg->len);
131 return -EIO;
132 }
133
134 return 0;
135}
136
137int l1if_transport_open(int q, struct lc15l1_hdl *hdl)
138{
139 int rc;
140 char buf[PATH_MAX];
141
142 /* Step 1: Open all msg_queue file descriptors */
143 struct osmo_fd *read_ofd = &hdl->read_ofd[q];
144 struct osmo_wqueue *wq = &hdl->write_q[q];
145 struct osmo_fd *write_ofd = &hdl->write_q[q].bfd;
146
147 snprintf(buf, sizeof(buf)-1, "%s%d", rd_devnames[q], hdl->hw_info.trx_nr);
148 buf[sizeof(buf)-1] = '\0';
149
150 rc = open(buf, O_RDONLY);
151 if (rc < 0) {
152 LOGP(DL1IF, LOGL_FATAL, "unable to open msg_queue %s: %s\n",
153 buf, strerror(errno));
154 return rc;
155 }
Harald Welte83473592020-10-19 12:56:30 +0200156 osmo_fd_setup(read_ofd, rc, OSMO_FD_READ, l1if_fd_cb, hdl, q);
Yves Godin660709d2016-05-19 11:08:03 +0200157 rc = osmo_fd_register(read_ofd);
158 if (rc < 0) {
159 close(read_ofd->fd);
160 read_ofd->fd = -1;
161 return rc;
162 }
163
164 snprintf(buf, sizeof(buf)-1, "%s%d", wr_devnames[q], hdl->hw_info.trx_nr);
165 buf[sizeof(buf)-1] = '\0';
166
167 rc = open(buf, O_WRONLY);
168 if (rc < 0) {
169 LOGP(DL1IF, LOGL_FATAL, "unable to open msg_queue %s: %s\n",
170 buf, strerror(errno));
171 goto out_read;
172 }
173 osmo_wqueue_init(wq, 10);
174 wq->write_cb = l1fd_write_cb;
Harald Welte83473592020-10-19 12:56:30 +0200175 osmo_fd_setup(write_ofd, rc, OSMO_FD_WRITE, osmo_wqueue_bfd_cb, hdl, q);
Yves Godin660709d2016-05-19 11:08:03 +0200176 rc = osmo_fd_register(write_ofd);
177 if (rc < 0) {
178 close(write_ofd->fd);
179 write_ofd->fd = -1;
180 goto out_read;
181 }
182
183 return 0;
184
185out_read:
186 close(hdl->read_ofd[q].fd);
187 osmo_fd_unregister(&hdl->read_ofd[q]);
188
189 return rc;
190}
191
192int l1if_transport_close(int q, struct lc15l1_hdl *hdl)
193{
194 struct osmo_fd *read_ofd = &hdl->read_ofd[q];
195 struct osmo_fd *write_ofd = &hdl->write_q[q].bfd;
196
197 osmo_fd_unregister(read_ofd);
198 close(read_ofd->fd);
199 read_ofd->fd = -1;
200
201 osmo_fd_unregister(write_ofd);
202 close(write_ofd->fd);
203 write_ofd->fd = -1;
204
205 return 0;
206}