fafcbe4c9e9b4dda5606e489edcf1b7083e955ea
[libsamsung-ipc.git] / samsung-ipc / devices / i9300 / i9300.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 "i9300.h"
33
34 int i9300_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 i9300 modem boot");
47
48     modem_image_fd = open(I9300_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, I9300_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 + I9300_PSI_OFFSET;
100
101     rc = xmm626_hsic_psi_send(client, modem_boot_fd, (void *) p, I9300_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 + I9300_EBL_OFFSET;
109
110     rc = xmm626_hsic_ebl_send(client, modem_boot_fd, (void *) p, I9300_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 + I9300_SEC_START_OFFSET;
125
126     rc = xmm626_hsic_sec_start_send(client, modem_boot_fd, (void *) p, I9300_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 + I9300_FIRMWARE_OFFSET;
134
135     rc = xmm626_hsic_firmware_send(client, modem_boot_fd, (void *) p, I9300_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, I9300_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 i9300_open(void *data, int type)
227 {
228     struct i9300_transport_data *transport_data;
229
230     if (data == NULL)
231         return -1;
232
233     transport_data = (struct i9300_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 i9300_close(void *data)
243 {
244     struct i9300_transport_data *transport_data;
245
246     if (data == NULL)
247         return -1;
248
249     transport_data = (struct i9300_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 i9300_read(void *data, void *buffer, size_t length)
258 {
259     struct i9300_transport_data *transport_data;
260     int rc;
261
262     if (data == NULL)
263         return -1;
264
265     transport_data = (struct i9300_transport_data *) data;
266
267     rc = xmm626_sec_modem_read(transport_data->fd, buffer, length);
268
269     return rc;
270 }
271
272 int i9300_write(void *data, const void *buffer, size_t length)
273 {
274     struct i9300_transport_data *transport_data;
275     int rc;
276
277     if (data == NULL)
278         return -1;
279
280     transport_data = (struct i9300_transport_data *) data;
281
282     rc = xmm626_sec_modem_write(transport_data->fd, buffer, length);
283
284     return rc;
285 }
286
287 int i9300_poll(void *data, struct timeval *timeout)
288 {
289     struct i9300_transport_data *transport_data;
290     int rc;
291
292     if (data == NULL)
293         return -1;
294
295     transport_data = (struct i9300_transport_data *) data;
296
297     rc = xmm626_sec_modem_poll(transport_data->fd, timeout);
298
299     return rc;
300 }
301
302 int i9300_power_on(void *data)
303 {
304     return 0;
305 }
306
307 int i9300_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 i9300_gprs_activate(void *data, unsigned int cid)
327 {
328     return 0;
329 }
330
331 int i9300_gprs_deactivate(void *data, unsigned int cid)
332 {
333     return 0;
334 }
335
336 int i9300_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 i9300_transport_data));
343
344     return 0;
345 }
346
347 int i9300_data_destroy(void *transport_data, void *power_data, void *gprs_data)
348 {
349     if (transport_data == NULL)
350         return -1;
351
352     free(transport_data);
353
354     return 0;
355 }
356
357 struct ipc_client_ops i9300_fmt_ops = {
358     .boot = i9300_boot,
359     .send = xmm626_sec_modem_fmt_send,
360     .recv = xmm626_sec_modem_fmt_recv,
361 };
362
363 struct ipc_client_ops i9300_rfs_ops = {
364     .boot = NULL,
365     .send = xmm626_sec_modem_rfs_send,
366     .recv = xmm626_sec_modem_rfs_recv,
367 };
368
369 struct ipc_client_handlers i9300_handlers = {
370     .read = i9300_read,
371     .write = i9300_write,
372     .open = i9300_open,
373     .close = i9300_close,
374     .poll = i9300_poll,
375     .transport_data = NULL,
376     .power_on = i9300_power_on,
377     .power_off = i9300_power_off,
378     .power_data = NULL,
379     .gprs_activate = i9300_gprs_activate,
380     .gprs_deactivate = i9300_gprs_deactivate,
381     .gprs_data = NULL,
382     .data_create = i9300_data_create,
383     .data_destroy = i9300_data_destroy,
384 };
385
386 struct ipc_client_gprs_specs i9300_gprs_specs = {
387     .gprs_get_iface = xmm626_sec_modem_gprs_get_iface,
388     .gprs_get_capabilities = xmm626_sec_modem_gprs_get_capabilities,
389 };
390
391 struct ipc_client_nv_data_specs i9300_nv_data_specs = {
392     .nv_data_path = XMM626_NV_DATA_PATH,
393     .nv_data_md5_path = XMM626_NV_DATA_MD5_PATH,
394     .nv_data_backup_path = XMM626_NV_DATA_BACKUP_PATH,
395     .nv_data_backup_md5_path = XMM626_NV_DATA_BACKUP_MD5_PATH,
396     .nv_data_secret = XMM626_NV_DATA_SECRET,
397     .nv_data_size = XMM626_NV_DATA_SIZE,
398     .nv_data_chunk_size = XMM626_NV_DATA_CHUNK_SIZE,
399 };
400
401 // vim:ts=4:sw=4:expandtab