| /* |
| * Copyright (C) 2007 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include <sysdeps.h> |
| #include "transport_pcie.h" |
| |
| #define TRACE_TAG TRACE_TRANSPORT |
| #include "adb.h" |
| |
| #ifdef HAVE_BIG_ENDIAN |
| #define H4(x) (((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24) |
| static inline void fix_endians(apacket *p) |
| { |
| p->msg.command = H4(p->msg.command); |
| p->msg.arg0 = H4(p->msg.arg0); |
| p->msg.arg1 = H4(p->msg.arg1); |
| p->msg.data_length = H4(p->msg.data_length); |
| p->msg.data_check = H4(p->msg.data_check); |
| p->msg.magic = H4(p->msg.magic); |
| } |
| unsigned host_to_le32(unsigned n) |
| { |
| return H4(n); |
| } |
| #else |
| #define fix_endians(p) do {} while (0) |
| unsigned host_to_le32(unsigned n) |
| { |
| return n; |
| } |
| #endif |
| |
| static int remote_read(apacket *p, atransport *t) |
| { |
| struct pcie_handle *pcie = t->pcie; |
| |
| if(unix_read(pcie->fd, &p->msg, sizeof(amessage)) < 0){ |
| D("remote pcie: read terminated (message)\n"); |
| return -1; |
| } |
| |
| fix_endians(p); |
| |
| if(check_header(p)) { |
| D("remote pcie: check_header failed\n"); |
| return -1; |
| } |
| |
| if(p->msg.data_length) { |
| if(unix_read(pcie->fd, p->data, p->msg.data_length) < 0){ |
| D("remote pcie: terminated (data)\n"); |
| return -1; |
| } |
| } |
| |
| if(check_data(p)) { |
| D("remote pcie: check_data failed\n"); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| static int remote_write(apacket *p, atransport *t) |
| { |
| unsigned size = p->msg.data_length; |
| struct pcie_handle *pcie = t->pcie; |
| |
| fix_endians(p); |
| |
| if(unix_write(pcie->fd, &p->msg, sizeof(amessage)) < 0) { |
| D("remote pcie: 1 - write terminated\n"); |
| return -1; |
| } |
| |
| if(p->msg.data_length == 0) |
| return 0; |
| |
| if(unix_write(pcie->fd, p->data, size) < 0) { |
| D("remote pcie: 2 - write terminated\n"); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| static void remote_close(atransport *t) |
| { |
| struct pcie_handle *pcie = t->pcie; |
| |
| unix_close(pcie->fd); |
| pcie->fd = -1; |
| } |
| |
| static void remote_kick(atransport *t) |
| { |
| struct pcie_handle *pcie = t->pcie; |
| |
| if (pcie->kick) |
| pcie->kick(pcie); |
| } |
| |
| void init_pcie_transport(atransport *t, struct pcie_handle *h, const char *devpath, int state) |
| { |
| static char *pcie_unknow = "0123456mediatek"; |
| D("transport: pcie\n"); |
| /* On host side, we need open the file here */ |
| if (h->fd < 0) |
| h->fd = unix_open(devpath, O_RDWR); |
| |
| t->close = remote_close; |
| t->kick = remote_kick; |
| t->read_from_remote = remote_read; |
| t->write_to_remote = remote_write; |
| t->sync_token = 1; |
| t->connection_state = state; |
| t->type = kTransportUsb; |
| t->pcie = h; |
| |
| /* Device information */ |
| t->serial = pcie_unknow; |
| t->device = pcie_unknow; |
| t->product = pcie_unknow; |
| |
| #if ADB_HOST |
| HOST = 1; |
| #else |
| HOST = 0; |
| #endif |
| } |
| |
| #if ADB_HOST |
| void pcie_host_init(void) |
| { |
| struct pcie_handle *pcie; |
| |
| pcie = calloc(1, sizeof(*pcie)); |
| |
| pcie->fd = unix_open(PCIE_ADB_PATH, O_RDWR); |
| |
| register_pcie_transport(pcie, PCIE_ADB_PATH, 1); |
| } |
| |
| #else |
| /* For ADBD */ |
| static void *pcie_open_thread(void *x) |
| { |
| struct pcie_handle *pcie = (struct pcie_handle *)x; |
| int fd = -1; |
| char *banner = "Start PCIe port\n"; |
| |
| while (1) { |
| adb_mutex_lock(&pcie->lock); |
| while (pcie->fd != -1) |
| adb_cond_wait(&pcie->notify, &pcie->lock); |
| adb_mutex_unlock(&pcie->lock); |
| |
| do { |
| fd = unix_open(PCIE_ADB_PATH, O_RDWR); |
| if (fd < 0) { |
| adb_sleep_ms(1000); |
| } |
| } while (fd < 0); |
| |
| pcie->fd = fd; |
| adb_write(fd, banner, strlen(banner)); |
| |
| /* Get PCIe config information */ |
| fd = unix_open(PCIE_INFO_ADB_PATH, O_RDONLY); |
| if (fd > 0) { |
| pcie->info = calloc(1, sizeof(struct pcie_info)); |
| if (pcie->info) |
| unix_read(fd, pcie->info, sizeof(pcie->info)); |
| |
| unix_close(fd); |
| } |
| |
| register_pcie_transport(pcie, PCIE_ADB_PATH, 1); |
| } |
| |
| // never gets here |
| return 0; |
| } |
| |
| static void pcie_adbd_kick(struct pcie_handle *h) |
| { |
| adb_mutex_lock(&h->lock); |
| unix_close(h->fd); |
| h->fd = -1; |
| |
| adb_cond_signal(&h->notify); |
| adb_mutex_unlock(&h->lock); |
| } |
| |
| void pcie_init(void) |
| { |
| adb_thread_t tid; |
| struct pcie_handle *h; |
| |
| h = calloc(1, sizeof(*h)); |
| |
| h->kick = pcie_adbd_kick; |
| h->fd = -1; |
| |
| adb_cond_init(&h->notify, 0); |
| adb_mutex_init(&h->lock, 0); |
| |
| D("[ pcie_init - starting thread ]\n"); |
| if (adb_thread_create(&tid, pcie_open_thread, h)) { |
| fatal_errno("[ cannot create pcie thread ]\n"); |
| } |
| } |
| #endif |