|  | /* | 
|  | * 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 |