Samsung Galaxy Note 2 N7100 support
[libsamsung-ipc.git] / samsung-ipc / device / n7100 / n7100_ipc.c
1 /*
2  * This file is part of libsamsung-ipc.
3  *
4  * Copyright (C) 2013 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 "xmm6260.h"
30 #include "xmm6260_hsic.h"
31 #include "xmm6260_sec_modem.h"
32 #include "n7100_ipc.h"
33
34 int n7100_ipc_bootstrap(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
41     unsigned char *p;
42     int rc;
43
44     if (client == NULL)
45         return -1;
46
47     ipc_client_log(client, "Starting n7100 modem bootstrap");
48
49     modem_image_fd = open(N7100_MODEM_IMAGE_DEVICE, O_RDONLY);
50     if (modem_image_fd < 0) {
51         ipc_client_log(client, "Opening modem image device failed");
52         goto error;
53     }
54     ipc_client_log(client, "Opened modem image device");
55
56     modem_image_data = mmap(0, N7100_MODEM_IMAGE_SIZE, PROT_READ, MAP_SHARED, modem_image_fd, 0);
57     if (modem_image_data == NULL || modem_image_data == (void *) 0xffffffff) {
58             ipc_client_log(client, "Mapping modem image data to memory failed");
59             goto error;
60     }
61     ipc_client_log(client, "Mapped modem image data to memory");
62
63     modem_boot_fd = open(XMM6260_SEC_MODEM_BOOT0_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
64     if (modem_boot_fd < 0) {
65         ipc_client_log(client, "Opening modem boot device failed");
66         goto error;
67     }
68     ipc_client_log(client, "Opened modem boot device");
69
70     modem_link_fd = open(XMM6260_SEC_MODEM_LINK_PM_DEVICE, O_RDWR);
71     if (modem_link_fd < 0) {
72         ipc_client_log(client, "Opening modem link device failed");
73         goto error;
74     }
75     ipc_client_log(client, "Opened modem link device");
76
77     rc = xmm6260_sec_modem_hci_power(0);
78     if (rc < 0) {
79         ipc_client_log(client, "Turning the modem off failed");
80         goto error;
81     }
82     ipc_client_log(client, "Turned the modem off");
83
84     rc = xmm6260_sec_modem_power(modem_boot_fd, 1);
85     rc |= xmm6260_sec_modem_hci_power(1);
86
87     if (rc < 0) {
88         ipc_client_log(client, "Turning the modem on failed");
89         goto error;
90     }
91     ipc_client_log(client, "Turned the modem on");
92
93     rc = xmm6260_sec_modem_link_connected_wait(modem_link_fd);
94     if (rc < 0) {
95         ipc_client_log(client, "Waiting for link connected failed");
96         goto error;
97     }
98     ipc_client_log(client, "Waited for link connected");
99
100     p = (unsigned char *) modem_image_data + N7100_PSI_OFFSET;
101
102     rc = xmm6260_hsic_psi_send(client, modem_boot_fd, (void *) p, N7100_PSI_SIZE);
103     if (rc < 0) {
104         ipc_client_log(client, "Sending XMM6260 HSIC PSI failed");
105         goto error;
106     }
107     ipc_client_log(client, "Sent XMM6260 HSIC PSI");
108
109     p = (unsigned char *) modem_image_data + N7100_EBL_OFFSET;
110
111     rc = xmm6260_hsic_ebl_send(client, modem_boot_fd, (void *) p, N7100_EBL_SIZE);
112     if (rc < 0) {
113         ipc_client_log(client, "Sending XMM6260 HSIC EBL failed");
114         goto error;
115     }
116     ipc_client_log(client, "Sent XMM6260 HSIC EBL");
117
118     rc = xmm6260_hsic_port_config_send(client, modem_boot_fd);
119     if (rc < 0) {
120         ipc_client_log(client, "Sending XMM6260 HSIC port config failed");
121         goto error;
122     }
123     ipc_client_log(client, "Sent XMM6260 HSIC port config");
124
125     p = (unsigned char *) modem_image_data + N7100_SEC_START_OFFSET;
126
127     rc = xmm6260_hsic_sec_start_send(client, modem_boot_fd, (void *) p, N7100_SEC_START_SIZE);
128     if (rc < 0) {
129         ipc_client_log(client, "Sending XMM6260 HSIC SEC start failed");
130         goto error;
131     }
132     ipc_client_log(client, "Sent XMM6260 HSIC SEC start");
133
134     p = (unsigned char *) modem_image_data + N7100_FIRMWARE_OFFSET;
135
136     rc = xmm6260_hsic_firmware_send(client, modem_boot_fd, (void *) p, N7100_FIRMWARE_SIZE);
137     if (rc < 0) {
138         ipc_client_log(client, "Sending XMM6260 HSIC firmware failed");
139         goto error;
140     }
141     ipc_client_log(client, "Sent XMM6260 HSIC firmware");
142
143     rc = xmm6260_hsic_nv_data_send(client, modem_boot_fd);
144     if (rc < 0) {
145         ipc_client_log(client, "Sending XMM6260 HSIC nv_data failed");
146         goto error;
147     }
148     ipc_client_log(client, "Sent XMM6260 HSIC nv_data");
149
150     rc = xmm6260_hsic_sec_end_send(client, modem_boot_fd);
151     if (rc < 0) {
152         ipc_client_log(client, "Sending XMM6260 HSIC SEC end failed");
153         goto error;
154     }
155     ipc_client_log(client, "Sent XMM6260 HSIC SEC end");
156
157     rc = xmm6260_hsic_hw_reset_send(client, modem_boot_fd);
158     if (rc < 0) {
159         ipc_client_log(client, "Sending XMM6260 HSIC HW reset failed");
160         goto error;
161     }
162     ipc_client_log(client, "Sent XMM6260 HSIC HW reset");
163
164     usleep(300000);
165
166     rc = xmm6260_sec_modem_link_get_hostwake_wait(modem_link_fd);
167     if (rc < 0) {
168         ipc_client_log(client, "Waiting for host wake failed");
169     }
170
171     rc = xmm6260_sec_modem_link_control_enable(modem_link_fd, 0);
172     rc |= xmm6260_sec_modem_hci_power(0);
173     rc |= xmm6260_sec_modem_link_control_active(modem_link_fd, 0);
174
175     if (rc < 0) {
176         ipc_client_log(client, "Turning the modem off failed");
177         goto error;
178     }
179
180     rc = xmm6260_sec_modem_link_get_hostwake_wait(modem_link_fd);
181     if (rc < 0) {
182         ipc_client_log(client, "Waiting for host wake failed");
183         goto error;
184     }
185     ipc_client_log(client, "Waited for host wake");
186
187     rc = xmm6260_sec_modem_link_control_enable(modem_link_fd, 1);
188     rc |= xmm6260_sec_modem_hci_power(1);
189     rc |= xmm6260_sec_modem_link_control_active(modem_link_fd, 1);
190
191     if (rc < 0) {
192         ipc_client_log(client, "Turning the modem on failed");
193         goto error;
194     }
195
196     rc = xmm6260_sec_modem_link_connected_wait(modem_link_fd);
197     if (rc < 0) {
198         ipc_client_log(client, "Waiting for link connected failed");
199         goto error;
200     }
201     ipc_client_log(client, "Waited for link connected");
202
203     usleep(300000);
204
205     rc = 0;
206     goto complete;
207
208 error:
209     rc = -1;
210
211 complete:
212     if (modem_image_data != NULL)
213         munmap(modem_image_data, N7100_MODEM_IMAGE_SIZE);
214
215     if (modem_image_fd >= 0)
216         close(modem_image_fd);
217
218     if (modem_boot_fd >= 0)
219         close(modem_boot_fd);
220
221     if (modem_link_fd >= 0)
222         close(modem_link_fd);
223
224     return rc;
225 }
226
227
228 int n7100_ipc_fmt_send(struct ipc_client *client, struct ipc_message_info *request)
229 {
230     return xmm6260_sec_modem_ipc_fmt_send(client, request);
231 }
232
233 int n7100_ipc_fmt_recv(struct ipc_client *client, struct ipc_message_info *response)
234 {
235     return xmm6260_sec_modem_ipc_fmt_recv(client, response);
236 }
237
238 int n7100_ipc_rfs_send(struct ipc_client *client, struct ipc_message_info *request)
239 {
240     return xmm6260_sec_modem_ipc_rfs_send(client, request);
241 }
242
243 int n7100_ipc_rfs_recv(struct ipc_client *client, struct ipc_message_info *response)
244 {
245     return xmm6260_sec_modem_ipc_rfs_recv(client, response);
246 }
247
248 int n7100_ipc_open(void *data, int type)
249 {
250     struct n7100_ipc_transport_data *transport_data;
251
252     if (data == NULL)
253         return -1;
254
255     transport_data = (struct n7100_ipc_transport_data *) data;
256
257     transport_data->fd = xmm6260_sec_modem_ipc_open(type);
258     if (transport_data->fd < 0)
259         return -1;
260
261     return 0;
262 }
263
264 int n7100_ipc_close(void *data)
265 {
266     struct n7100_ipc_transport_data *transport_data;
267
268     if (data == NULL)
269         return -1;
270
271     transport_data = (struct n7100_ipc_transport_data *) data;
272
273     xmm6260_sec_modem_ipc_close(transport_data->fd);
274     transport_data->fd = -1;
275
276     return 0;
277 }
278
279 int n7100_ipc_read(void *data, void *buffer, unsigned int length)
280 {
281     struct n7100_ipc_transport_data *transport_data;
282     int rc;
283
284     if (data == NULL)
285         return -1;
286
287     transport_data = (struct n7100_ipc_transport_data *) data;
288
289     rc = xmm6260_sec_modem_ipc_read(transport_data->fd, buffer, length);
290     return rc;
291 }
292
293 int n7100_ipc_write(void *data, void *buffer, unsigned int length)
294 {
295     struct n7100_ipc_transport_data *transport_data;
296     int rc;
297
298     if (data == NULL)
299         return -1;
300
301     transport_data = (struct n7100_ipc_transport_data *) data;
302
303     rc = xmm6260_sec_modem_ipc_write(transport_data->fd, buffer, length);
304     return rc;
305 }
306
307 int n7100_ipc_poll(void *data, struct timeval *timeout)
308 {
309     struct n7100_ipc_transport_data *transport_data;
310     int rc;
311
312     if (data == NULL)
313         return -1;
314
315     transport_data = (struct n7100_ipc_transport_data *) data;
316
317     rc = xmm6260_sec_modem_ipc_poll(transport_data->fd, timeout);
318     return rc;
319 }
320
321 int n7100_ipc_power_on(void *data)
322 {
323     return 0;
324 }
325
326 int n7100_ipc_power_off(void *data)
327 {
328     int fd;
329     int rc;
330
331     fd = open(XMM6260_SEC_MODEM_BOOT0_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
332     if (fd < 0)
333         return -1;
334
335     rc = xmm6260_sec_modem_power(fd, 0);
336
337     close(fd);
338
339     if (rc < 0)
340         return -1;
341
342     return 0;
343 }
344
345 int n7100_ipc_data_create(void **transport_data, void **power_data, void **gprs_data)
346 {
347     if (transport_data == NULL)
348         return -1;
349
350     *transport_data = (void *) malloc(sizeof(struct n7100_ipc_transport_data));
351     memset(*transport_data, 0, sizeof(struct n7100_ipc_transport_data));
352
353     return 0;
354 }
355
356 int n7100_ipc_data_destroy(void *transport_data, void *power_data, void *gprs_data)
357 {
358     if (transport_data == NULL)
359         return -1;
360
361     free(transport_data);
362
363     return 0;
364 }
365
366 char *n7100_ipc_gprs_get_iface(int cid)
367 {
368     return xmm6260_sec_modem_ipc_gprs_get_iface(cid);
369 }
370
371
372 int n7100_ipc_gprs_get_capabilities(struct ipc_client_gprs_capabilities *capabilities)
373 {
374     return xmm6260_sec_modem_ipc_gprs_get_capabilities(capabilities);
375 }
376
377 struct ipc_ops n7100_ipc_fmt_ops = {
378     .bootstrap = n7100_ipc_bootstrap,
379     .send = n7100_ipc_fmt_send,
380     .recv = n7100_ipc_fmt_recv,
381 };
382
383 struct ipc_ops n7100_ipc_rfs_ops = {
384     .bootstrap = NULL,
385     .send = n7100_ipc_rfs_send,
386     .recv = n7100_ipc_rfs_recv,
387 };
388
389 struct ipc_handlers n7100_ipc_handlers = {
390     .read = n7100_ipc_read,
391     .write = n7100_ipc_write,
392     .open = n7100_ipc_open,
393     .close = n7100_ipc_close,
394     .poll = n7100_ipc_poll,
395     .transport_data = NULL,
396     .power_on = n7100_ipc_power_on,
397     .power_off = n7100_ipc_power_off,
398     .power_data = NULL,
399     .gprs_activate = NULL,
400     .gprs_deactivate = NULL,
401     .gprs_data = NULL,
402     .data_create = n7100_ipc_data_create,
403     .data_destroy = n7100_ipc_data_destroy,
404 };
405
406 struct ipc_gprs_specs n7100_ipc_gprs_specs = {
407     .gprs_get_iface = n7100_ipc_gprs_get_iface,
408     .gprs_get_capabilities = n7100_ipc_gprs_get_capabilities,
409 };
410
411 // vim:ts=4:sw=4:expandtab