19ddd73fd55690024e4274ec09cbd59d9c12baed
[libsamsung-ipc.git] / samsung-ipc / devices / galaxys2 / galaxys2.c
1 /*
2  * This file is part of libsamsung-ipc.
3  *
4  * Copyright (C) 2013-2014 Paul Kocialkowski <contact@paulk.fr>
5  *
6  * libsamsung-ipc is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * libsamsung-ipc is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with libsamsung-ipc.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <string.h>
23 #include <fcntl.h>
24 #include <sys/mman.h>
25
26 #include <samsung-ipc.h>
27 #include <ipc.h>
28
29 #include "xmm626.h"
30 #include "xmm626_hsic.h"
31 #include "xmm626_sec_modem.h"
32 #include "galaxys2.h"
33
34 int galaxys2_boot(struct ipc_client *client)
35 {
36     void *modem_image_data = NULL;
37     int modem_image_fd = -1;
38     int modem_boot_fd = -1;
39     int modem_link_fd = -1;
40     unsigned char *p;
41     int rc;
42
43     if (client == NULL)
44         return -1;
45
46     ipc_client_log(client, "Starting galaxys2 modem boot");
47
48     modem_image_fd = open(GALAXYS2_MODEM_IMAGE_DEVICE, O_RDONLY);
49     if (modem_image_fd < 0) {
50         ipc_client_log(client, "Opening modem image device failed");
51         goto error;
52     }
53     ipc_client_log(client, "Opened modem image device");
54
55     modem_image_data = mmap(0, GALAXYS2_MODEM_IMAGE_SIZE, PROT_READ, MAP_SHARED, modem_image_fd, 0);
56     if (modem_image_data == NULL || modem_image_data == (void *) 0xffffffff) {
57             ipc_client_log(client, "Mapping modem image data to memory failed");
58             goto error;
59     }
60     ipc_client_log(client, "Mapped modem image data to memory");
61
62     modem_boot_fd = open(XMM626_SEC_MODEM_BOOT0_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
63     if (modem_boot_fd < 0) {
64         ipc_client_log(client, "Opening modem boot device failed");
65         goto error;
66     }
67     ipc_client_log(client, "Opened modem boot device");
68
69     modem_link_fd = open(XMM626_SEC_MODEM_LINK_PM_DEVICE, O_RDWR);
70     if (modem_link_fd < 0) {
71         ipc_client_log(client, "Opening modem link device failed");
72         goto error;
73     }
74     ipc_client_log(client, "Opened modem link device");
75
76     rc = xmm626_sec_modem_power(modem_boot_fd, 0);
77     rc |= xmm626_sec_modem_link_control_enable(modem_link_fd, 0);
78     rc |= xmm626_sec_modem_hci_power(0);
79     rc |= xmm626_sec_modem_link_control_active(modem_link_fd, 0);
80
81     if (rc < 0) {
82         ipc_client_log(client, "Turning the modem off failed");
83         goto error;
84     }
85     ipc_client_log(client, "Turned the modem off");
86
87     rc = xmm626_sec_modem_power(modem_boot_fd, 1);
88     rc |= xmm626_sec_modem_link_control_enable(modem_link_fd, 1);
89     rc |= xmm626_sec_modem_hci_power(1);
90     rc |= xmm626_sec_modem_link_control_active(modem_link_fd, 1);
91
92     if (rc < 0) {
93         ipc_client_log(client, "Turning the modem on failed");
94         goto error;
95     }
96     ipc_client_log(client, "Turned the modem on");
97
98     rc = xmm626_sec_modem_link_connected_wait(modem_link_fd);
99     if (rc < 0) {
100         ipc_client_log(client, "Waiting for link connected failed");
101         goto error;
102     }
103     ipc_client_log(client, "Waited for link connected");
104
105     p = (unsigned char *) modem_image_data + GALAXYS2_PSI_OFFSET;
106
107     rc = xmm626_hsic_psi_send(client, modem_boot_fd, (void *) p, GALAXYS2_PSI_SIZE);
108     if (rc < 0) {
109         ipc_client_log(client, "Sending XMM626 HSIC PSI failed");
110         goto error;
111     }
112     ipc_client_log(client, "Sent XMM626 HSIC PSI");
113
114     p = (unsigned char *) modem_image_data + GALAXYS2_EBL_OFFSET;
115
116     rc = xmm626_hsic_ebl_send(client, modem_boot_fd, (void *) p, GALAXYS2_EBL_SIZE);
117     if (rc < 0) {
118         ipc_client_log(client, "Sending XMM626 HSIC EBL failed");
119         goto error;
120     }
121     ipc_client_log(client, "Sent XMM626 HSIC EBL");
122
123     rc = xmm626_hsic_port_config_send(client, modem_boot_fd);
124     if (rc < 0) {
125         ipc_client_log(client, "Sending XMM626 HSIC port config failed");
126         goto error;
127     }
128     ipc_client_log(client, "Sent XMM626 HSIC port config");
129
130     p = (unsigned char *) modem_image_data + GALAXYS2_SEC_START_OFFSET;
131
132     rc = xmm626_hsic_sec_start_send(client, modem_boot_fd, (void *) p, GALAXYS2_SEC_START_SIZE);
133     if (rc < 0) {
134         ipc_client_log(client, "Sending XMM626 HSIC SEC start failed");
135         goto error;
136     }
137     ipc_client_log(client, "Sent XMM626 HSIC SEC start");
138
139     p = (unsigned char *) modem_image_data + GALAXYS2_FIRMWARE_OFFSET;
140
141     rc = xmm626_hsic_firmware_send(client, modem_boot_fd, (void *) p, GALAXYS2_FIRMWARE_SIZE);
142     if (rc < 0) {
143         ipc_client_log(client, "Sending XMM626 HSIC firmware failed");
144         goto error;
145     }
146     ipc_client_log(client, "Sent XMM626 HSIC firmware");
147
148     rc = xmm626_hsic_nv_data_send(client, modem_boot_fd);
149     if (rc < 0) {
150         ipc_client_log(client, "Sending XMM626 HSIC nv_data failed");
151         goto error;
152     }
153     ipc_client_log(client, "Sent XMM626 HSIC nv_data");
154
155     rc = xmm626_hsic_sec_end_send(client, modem_boot_fd);
156     if (rc < 0) {
157         ipc_client_log(client, "Sending XMM626 HSIC SEC end failed");
158         goto error;
159     }
160     ipc_client_log(client, "Sent XMM626 HSIC SEC end");
161
162     rc = xmm626_hsic_hw_reset_send(client, modem_boot_fd);
163     if (rc < 0) {
164         ipc_client_log(client, "Sending XMM626 HSIC HW reset failed");
165         goto error;
166     }
167     ipc_client_log(client, "Sent XMM626 HSIC HW reset");
168
169     usleep(300000);
170
171     rc = xmm626_sec_modem_link_get_hostwake_wait(modem_link_fd);
172     if (rc < 0) {
173         ipc_client_log(client, "Waiting for host wake failed");
174     }
175
176     rc = xmm626_sec_modem_link_control_enable(modem_link_fd, 0);
177     rc |= xmm626_sec_modem_hci_power(0);
178     rc |= xmm626_sec_modem_link_control_active(modem_link_fd, 0);
179
180     if (rc < 0) {
181         ipc_client_log(client, "Turning the modem off failed");
182         goto error;
183     }
184
185     rc = xmm626_sec_modem_link_get_hostwake_wait(modem_link_fd);
186     if (rc < 0) {
187         ipc_client_log(client, "Waiting for host wake failed");
188         goto error;
189     }
190     ipc_client_log(client, "Waited for host wake");
191
192     rc = xmm626_sec_modem_link_control_enable(modem_link_fd, 1);
193     rc |= xmm626_sec_modem_hci_power(1);
194     rc |= xmm626_sec_modem_link_control_active(modem_link_fd, 1);
195
196     if (rc < 0) {
197         ipc_client_log(client, "Turning the modem on failed");
198         goto error;
199     }
200
201     rc = xmm626_sec_modem_link_connected_wait(modem_link_fd);
202     if (rc < 0) {
203         ipc_client_log(client, "Waiting for link connected failed");
204         goto error;
205     }
206     ipc_client_log(client, "Waited for link connected");
207
208     usleep(300000);
209
210     rc = 0;
211     goto complete;
212
213 error:
214     rc = -1;
215
216 complete:
217     if (modem_image_data != NULL)
218         munmap(modem_image_data, GALAXYS2_MODEM_IMAGE_SIZE);
219
220     if (modem_image_fd >= 0)
221         close(modem_image_fd);
222
223     if (modem_boot_fd >= 0)
224         close(modem_boot_fd);
225
226     if (modem_link_fd >= 0)
227         close(modem_link_fd);
228
229     return rc;
230 }
231
232 int galaxys2_open(void *data, int type)
233 {
234     struct galaxys2_transport_data *transport_data;
235
236     if (data == NULL)
237         return -1;
238
239     transport_data = (struct galaxys2_transport_data *) data;
240
241     transport_data->fd = xmm626_sec_modem_open(type);
242     if (transport_data->fd < 0)
243         return -1;
244
245     return 0;
246 }
247
248 int galaxys2_close(void *data)
249 {
250     struct galaxys2_transport_data *transport_data;
251
252     if (data == NULL)
253         return -1;
254
255     transport_data = (struct galaxys2_transport_data *) data;
256
257     xmm626_sec_modem_close(transport_data->fd);
258     transport_data->fd = -1;
259
260     return 0;
261 }
262
263 int galaxys2_read(void *data, void *buffer, size_t length)
264 {
265     struct galaxys2_transport_data *transport_data;
266     int rc;
267
268     if (data == NULL)
269         return -1;
270
271     transport_data = (struct galaxys2_transport_data *) data;
272
273     rc = xmm626_sec_modem_read(transport_data->fd, buffer, length);
274
275     return rc;
276 }
277
278 int galaxys2_write(void *data, const void *buffer, size_t length)
279 {
280     struct galaxys2_transport_data *transport_data;
281     int rc;
282
283     if (data == NULL)
284         return -1;
285
286     transport_data = (struct galaxys2_transport_data *) data;
287
288     rc = xmm626_sec_modem_write(transport_data->fd, buffer, length);
289
290     return rc;
291 }
292
293 int galaxys2_poll(void *data, struct timeval *timeout)
294 {
295     struct galaxys2_transport_data *transport_data;
296     int rc;
297
298     if (data == NULL)
299         return -1;
300
301     transport_data = (struct galaxys2_transport_data *) data;
302
303     rc = xmm626_sec_modem_poll(transport_data->fd, timeout);
304
305     return rc;
306 }
307
308 int galaxys2_power_on(void *data)
309 {
310     return 0;
311 }
312
313 int galaxys2_power_off(void *data)
314 {
315     int fd;
316     int rc;
317
318     fd = open(XMM626_SEC_MODEM_BOOT0_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
319     if (fd < 0)
320         return -1;
321
322     rc = xmm626_sec_modem_power(fd, 0);
323
324     close(fd);
325
326     if (rc < 0)
327         return -1;
328
329     return 0;
330 }
331
332 int galaxys2_gprs_activate(void *data, unsigned int cid)
333 {
334     return 0;
335 }
336
337 int galaxys2_gprs_deactivate(void *data, unsigned int cid)
338 {
339     return 0;
340 }
341
342 int galaxys2_data_create(void **transport_data, void **power_data,
343     void **gprs_data)
344 {
345     if (transport_data == NULL)
346         return -1;
347
348     *transport_data = calloc(1, sizeof(struct galaxys2_transport_data));
349
350     return 0;
351 }
352
353 int galaxys2_data_destroy(void *transport_data, void *power_data,
354     void *gprs_data)
355 {
356     if (transport_data == NULL)
357         return -1;
358
359     free(transport_data);
360
361     return 0;
362 }
363
364 struct ipc_client_ops galaxys2_fmt_ops = {
365     .boot = galaxys2_boot,
366     .send = xmm626_sec_modem_fmt_send,
367     .recv = xmm626_sec_modem_fmt_recv,
368 };
369
370 struct ipc_client_ops galaxys2_rfs_ops = {
371     .boot = NULL,
372     .send = xmm626_sec_modem_rfs_send,
373     .recv = xmm626_sec_modem_rfs_recv,
374 };
375
376 struct ipc_client_handlers galaxys2_handlers = {
377     .read = galaxys2_read,
378     .write = galaxys2_write,
379     .open = galaxys2_open,
380     .close = galaxys2_close,
381     .poll = galaxys2_poll,
382     .transport_data = NULL,
383     .power_on = galaxys2_power_on,
384     .power_off = galaxys2_power_off,
385     .power_data = NULL,
386     .gprs_activate = galaxys2_gprs_activate,
387     .gprs_deactivate = galaxys2_gprs_deactivate,
388     .gprs_data = NULL,
389     .data_create = galaxys2_data_create,
390     .data_destroy = galaxys2_data_destroy,
391 };
392
393 struct ipc_client_gprs_specs galaxys2_gprs_specs = {
394     .gprs_get_iface = xmm626_sec_modem_gprs_get_iface,
395     .gprs_get_capabilities = xmm626_sec_modem_gprs_get_capabilities,
396 };
397
398 struct ipc_client_nv_data_specs galaxys2_nv_data_specs = {
399     .nv_data_path = XMM626_NV_DATA_PATH,
400     .nv_data_md5_path = XMM626_NV_DATA_MD5_PATH,
401     .nv_data_backup_path = XMM626_NV_DATA_BACKUP_PATH,
402     .nv_data_backup_md5_path = XMM626_NV_DATA_BACKUP_MD5_PATH,
403     .nv_data_secret = XMM626_NV_DATA_SECRET,
404     .nv_data_size = XMM626_NV_DATA_SIZE,
405     .nv_data_chunk_size = XMM626_NV_DATA_CHUNK_SIZE,
406 };
407
408 // vim:ts=4:sw=4:expandtab