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