cc3c73b0664333009eb42a554b5fece3ba25e1af
[libsamsung-ipc.git] / samsung-ipc / devices / n7100 / n7100.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 "n7100.h"
33
34 int n7100_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 n7100 modem boot");
47
48     modem_image_fd = open(N7100_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, N7100_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_hci_power(0);
77     if (rc < 0) {
78         ipc_client_log(client, "Turning the modem off failed");
79         goto error;
80     }
81     ipc_client_log(client, "Turned the modem off");
82
83     rc = xmm626_sec_modem_power(modem_boot_fd, 1);
84     rc |= xmm626_sec_modem_hci_power(1);
85
86     if (rc < 0) {
87         ipc_client_log(client, "Turning the modem on failed");
88         goto error;
89     }
90     ipc_client_log(client, "Turned the modem on");
91
92     rc = xmm626_sec_modem_link_connected_wait(modem_link_fd);
93     if (rc < 0) {
94         ipc_client_log(client, "Waiting for link connected failed");
95         goto error;
96     }
97     ipc_client_log(client, "Waited for link connected");
98
99     p = (unsigned char *) modem_image_data + N7100_PSI_OFFSET;
100
101     rc = xmm626_hsic_psi_send(client, modem_boot_fd, (void *) p, N7100_PSI_SIZE);
102     if (rc < 0) {
103         ipc_client_log(client, "Sending XMM626 HSIC PSI failed");
104         goto error;
105     }
106     ipc_client_log(client, "Sent XMM626 HSIC PSI");
107
108     p = (unsigned char *) modem_image_data + N7100_EBL_OFFSET;
109
110     rc = xmm626_hsic_ebl_send(client, modem_boot_fd, (void *) p, N7100_EBL_SIZE);
111     if (rc < 0) {
112         ipc_client_log(client, "Sending XMM626 HSIC EBL failed");
113         goto error;
114     }
115     ipc_client_log(client, "Sent XMM626 HSIC EBL");
116
117     rc = xmm626_hsic_port_config_send(client, modem_boot_fd);
118     if (rc < 0) {
119         ipc_client_log(client, "Sending XMM626 HSIC port config failed");
120         goto error;
121     }
122     ipc_client_log(client, "Sent XMM626 HSIC port config");
123
124     p = (unsigned char *) modem_image_data + N7100_SEC_START_OFFSET;
125
126     rc = xmm626_hsic_sec_start_send(client, modem_boot_fd, (void *) p, N7100_SEC_START_SIZE);
127     if (rc < 0) {
128         ipc_client_log(client, "Sending XMM626 HSIC SEC start failed");
129         goto error;
130     }
131     ipc_client_log(client, "Sent XMM626 HSIC SEC start");
132
133     p = (unsigned char *) modem_image_data + N7100_FIRMWARE_OFFSET;
134
135     rc = xmm626_hsic_firmware_send(client, modem_boot_fd, (void *) p, N7100_FIRMWARE_SIZE);
136     if (rc < 0) {
137         ipc_client_log(client, "Sending XMM626 HSIC firmware failed");
138         goto error;
139     }
140     ipc_client_log(client, "Sent XMM626 HSIC firmware");
141
142     rc = xmm626_hsic_nv_data_send(client, modem_boot_fd);
143     if (rc < 0) {
144         ipc_client_log(client, "Sending XMM626 HSIC nv_data failed");
145         goto error;
146     }
147     ipc_client_log(client, "Sent XMM626 HSIC nv_data");
148
149     rc = xmm626_hsic_sec_end_send(client, modem_boot_fd);
150     if (rc < 0) {
151         ipc_client_log(client, "Sending XMM626 HSIC SEC end failed");
152         goto error;
153     }
154     ipc_client_log(client, "Sent XMM626 HSIC SEC end");
155
156     rc = xmm626_hsic_hw_reset_send(client, modem_boot_fd);
157     if (rc < 0) {
158         ipc_client_log(client, "Sending XMM626 HSIC HW reset failed");
159         goto error;
160     }
161     ipc_client_log(client, "Sent XMM626 HSIC HW reset");
162
163     usleep(300000);
164
165     rc = xmm626_sec_modem_link_get_hostwake_wait(modem_link_fd);
166     if (rc < 0) {
167         ipc_client_log(client, "Waiting for host wake failed");
168     }
169
170     rc = xmm626_sec_modem_link_control_enable(modem_link_fd, 0);
171     rc |= xmm626_sec_modem_hci_power(0);
172     rc |= xmm626_sec_modem_link_control_active(modem_link_fd, 0);
173
174     if (rc < 0) {
175         ipc_client_log(client, "Turning the modem off failed");
176         goto error;
177     }
178
179     rc = xmm626_sec_modem_link_get_hostwake_wait(modem_link_fd);
180     if (rc < 0) {
181         ipc_client_log(client, "Waiting for host wake failed");
182         goto error;
183     }
184     ipc_client_log(client, "Waited for host wake");
185
186     rc = xmm626_sec_modem_link_control_enable(modem_link_fd, 1);
187     rc |= xmm626_sec_modem_hci_power(1);
188     rc |= xmm626_sec_modem_link_control_active(modem_link_fd, 1);
189
190     if (rc < 0) {
191         ipc_client_log(client, "Turning the modem on failed");
192         goto error;
193     }
194
195     rc = xmm626_sec_modem_link_connected_wait(modem_link_fd);
196     if (rc < 0) {
197         ipc_client_log(client, "Waiting for link connected failed");
198         goto error;
199     }
200     ipc_client_log(client, "Waited for link connected");
201
202     usleep(300000);
203
204     rc = 0;
205     goto complete;
206
207 error:
208     rc = -1;
209
210 complete:
211     if (modem_image_data != NULL)
212         munmap(modem_image_data, N7100_MODEM_IMAGE_SIZE);
213
214     if (modem_image_fd >= 0)
215         close(modem_image_fd);
216
217     if (modem_boot_fd >= 0)
218         close(modem_boot_fd);
219
220     if (modem_link_fd >= 0)
221         close(modem_link_fd);
222
223     return rc;
224 }
225
226 int n7100_open(void *data, int type)
227 {
228     struct n7100_transport_data *transport_data;
229
230     if (data == NULL)
231         return -1;
232
233     transport_data = (struct n7100_transport_data *) data;
234
235     transport_data->fd = xmm626_sec_modem_open(type);
236     if (transport_data->fd < 0)
237         return -1;
238
239     return 0;
240 }
241
242 int n7100_close(void *data)
243 {
244     struct n7100_transport_data *transport_data;
245
246     if (data == NULL)
247         return -1;
248
249     transport_data = (struct n7100_transport_data *) data;
250
251     xmm626_sec_modem_close(transport_data->fd);
252     transport_data->fd = -1;
253
254     return 0;
255 }
256
257 int n7100_read(void *data, void *buffer, size_t length)
258 {
259     struct n7100_transport_data *transport_data;
260     int rc;
261
262     if (data == NULL)
263         return -1;
264
265     transport_data = (struct n7100_transport_data *) data;
266
267     rc = xmm626_sec_modem_read(transport_data->fd, buffer, length);
268
269     return rc;
270 }
271
272 int n7100_write(void *data, const void *buffer, size_t length)
273 {
274     struct n7100_transport_data *transport_data;
275     int rc;
276
277     if (data == NULL)
278         return -1;
279
280     transport_data = (struct n7100_transport_data *) data;
281
282     rc = xmm626_sec_modem_write(transport_data->fd, buffer, length);
283
284     return rc;
285 }
286
287 int n7100_poll(void *data, struct timeval *timeout)
288 {
289     struct n7100_transport_data *transport_data;
290     int rc;
291
292     if (data == NULL)
293         return -1;
294
295     transport_data = (struct n7100_transport_data *) data;
296
297     rc = xmm626_sec_modem_poll(transport_data->fd, timeout);
298
299     return rc;
300 }
301
302 int n7100_power_on(void *data)
303 {
304     return 0;
305 }
306
307 int n7100_power_off(void *data)
308 {
309     int fd;
310     int rc;
311
312     fd = open(XMM626_SEC_MODEM_BOOT0_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
313     if (fd < 0)
314         return -1;
315
316     rc = xmm626_sec_modem_power(fd, 0);
317
318     close(fd);
319
320     if (rc < 0)
321         return -1;
322
323     return 0;
324 }
325
326 int n7100_gprs_activate(void *data, unsigned int cid)
327 {
328     return 0;
329 }
330
331 int n7100_gprs_deactivate(void *data, unsigned int cid)
332 {
333     return 0;
334 }
335
336 int n7100_data_create(void **transport_data, void **power_data,
337     void **gprs_data)
338 {
339     if (transport_data == NULL)
340         return -1;
341
342     *transport_data = calloc(1, sizeof(struct n7100_transport_data));
343
344     return 0;
345 }
346
347 int n7100_data_destroy(void *transport_data, void *power_data,
348     void *gprs_data)
349 {
350     if (transport_data == NULL)
351         return -1;
352
353     free(transport_data);
354
355     return 0;
356 }
357
358 struct ipc_client_ops n7100_fmt_ops = {
359     .boot = n7100_boot,
360     .send = xmm626_sec_modem_fmt_send,
361     .recv = xmm626_sec_modem_fmt_recv,
362 };
363
364 struct ipc_client_ops n7100_rfs_ops = {
365     .boot = NULL,
366     .send = xmm626_sec_modem_rfs_send,
367     .recv = xmm626_sec_modem_rfs_recv,
368 };
369
370 struct ipc_client_handlers n7100_handlers = {
371     .read = n7100_read,
372     .write = n7100_write,
373     .open = n7100_open,
374     .close = n7100_close,
375     .poll = n7100_poll,
376     .transport_data = NULL,
377     .power_on = n7100_power_on,
378     .power_off = n7100_power_off,
379     .power_data = NULL,
380     .gprs_activate = n7100_gprs_activate,
381     .gprs_deactivate = n7100_gprs_deactivate,
382     .gprs_data = NULL,
383     .data_create = n7100_data_create,
384     .data_destroy = n7100_data_destroy,
385 };
386
387 struct ipc_client_gprs_specs n7100_gprs_specs = {
388     .gprs_get_iface = xmm626_sec_modem_gprs_get_iface,
389     .gprs_get_capabilities = xmm626_sec_modem_gprs_get_capabilities,
390 };
391
392 struct ipc_client_nv_data_specs n7100_nv_data_specs = {
393     .nv_data_path = XMM626_NV_DATA_PATH,
394     .nv_data_md5_path = XMM626_NV_DATA_MD5_PATH,
395     .nv_data_backup_path = XMM626_NV_DATA_BACKUP_PATH,
396     .nv_data_backup_md5_path = XMM626_NV_DATA_BACKUP_MD5_PATH,
397     .nv_data_secret = XMM626_NV_DATA_SECRET,
398     .nv_data_size = XMM626_NV_DATA_SIZE,
399     .nv_data_chunk_size = XMM626_NV_DATA_CHUNK_SIZE,
400 };
401
402 // vim:ts=4:sw=4:expandtab