diff options
Diffstat (limited to 'util/comm-lpc.c')
-rw-r--r-- | util/comm-lpc.c | 316 |
1 files changed, 0 insertions, 316 deletions
diff --git a/util/comm-lpc.c b/util/comm-lpc.c deleted file mode 100644 index d1ce761fc2..0000000000 --- a/util/comm-lpc.c +++ /dev/null @@ -1,316 +0,0 @@ -/* Copyright 2013 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* The I/O asm funcs exist only on x86. */ -#if defined(__i386__) || defined(__x86_64__) - -#include <stdint.h> -#include <stdio.h> -#include <sys/io.h> -#include <sys/param.h> -#include <unistd.h> - -#include "comm-host.h" - -#define INITIAL_UDELAY 5 /* 5 us */ -#define MAXIMUM_UDELAY 10000 /* 10 ms */ - -/* - * Wait for the EC to be unbusy. Returns 0 if unbusy, non-zero if - * timeout. - */ -static int wait_for_ec(int status_addr, int timeout_usec) -{ - int i; - int delay = INITIAL_UDELAY; - - for (i = 0; i < timeout_usec; i += delay) { - /* - * Delay first, in case we just sent out a command but the EC - * hasn't raised the busy flag. However, I think this doesn't - * happen since the LPC commands are executed in order and the - * busy flag is set by hardware. Minor issue in any case, - * since the initial delay is very short. - */ - usleep(MIN(delay, timeout_usec - i)); - - if (!(inb(status_addr) & EC_LPC_STATUS_BUSY_MASK)) - return 0; - - /* Increase the delay interval after a few rapid checks */ - if (i > 20) - delay = MIN(delay * 2, MAXIMUM_UDELAY); - } - return -1; /* Timeout */ -} - -static int ec_command_lpc(int command, int version, - const void *outdata, int outsize, - void *indata, int insize) -{ - struct ec_lpc_host_args args; - const uint8_t *d; - uint8_t *dout; - int csum; - int i; - - /* Fill in args */ - args.flags = EC_HOST_ARGS_FLAG_FROM_HOST; - args.command_version = version; - args.data_size = outsize; - - /* Initialize checksum */ - csum = command + args.flags + args.command_version + args.data_size; - - /* Write data and update checksum */ - for (i = 0, d = (uint8_t *)outdata; i < outsize; i++, d++) { - outb(*d, EC_LPC_ADDR_HOST_PARAM + i); - csum += *d; - } - - /* Finalize checksum and write args */ - args.checksum = (uint8_t)csum; - for (i = 0, d = (const uint8_t *)&args; i < sizeof(args); i++, d++) - outb(*d, EC_LPC_ADDR_HOST_ARGS + i); - - outb(command, EC_LPC_ADDR_HOST_CMD); - - if (wait_for_ec(EC_LPC_ADDR_HOST_CMD, 1000000)) { - fprintf(stderr, "Timeout waiting for EC response\n"); - return -EC_RES_ERROR; - } - - /* Check result */ - i = inb(EC_LPC_ADDR_HOST_DATA); - if (i) { - fprintf(stderr, "EC returned error result code %d\n", i); - return -EECRESULT - i; - } - - /* Read back args */ - for (i = 0, dout = (uint8_t *)&args; i < sizeof(args); i++, dout++) - *dout = inb(EC_LPC_ADDR_HOST_ARGS + i); - - /* - * If EC didn't modify args flags, then somehow we sent a new-style - * command to an old EC, which means it would have read its params - * from the wrong place. - */ - if (!(args.flags & EC_HOST_ARGS_FLAG_TO_HOST)) { - fprintf(stderr, "EC protocol mismatch\n"); - return -EC_RES_INVALID_RESPONSE; - } - - if (args.data_size > insize) { - fprintf(stderr, "EC returned too much data\n"); - return -EC_RES_INVALID_RESPONSE; - } - - /* Start calculating response checksum */ - csum = command + args.flags + args.command_version + args.data_size; - - /* Read response and update checksum */ - for (i = 0, dout = (uint8_t *)indata; i < args.data_size; - i++, dout++) { - *dout = inb(EC_LPC_ADDR_HOST_PARAM + i); - csum += *dout; - } - - /* Verify checksum */ - if (args.checksum != (uint8_t)csum) { - fprintf(stderr, "EC response has invalid checksum\n"); - return -EC_RES_INVALID_CHECKSUM; - } - - /* Return actual amount of data received */ - return args.data_size; -} - -static int ec_command_lpc_3(int command, int version, - const void *outdata, int outsize, - void *indata, int insize) -{ - struct ec_host_request rq; - struct ec_host_response rs; - const uint8_t *d; - uint8_t *dout; - int csum = 0; - int i; - - /* Fail if output size is too big */ - if (outsize + sizeof(rq) > EC_LPC_HOST_PACKET_SIZE) - return -EC_RES_REQUEST_TRUNCATED; - - /* Fill in request packet */ - /* TODO(crosbug.com/p/23825): This should be common to all protocols */ - rq.struct_version = EC_HOST_REQUEST_VERSION; - rq.checksum = 0; - rq.command = command; - rq.command_version = version; - rq.reserved = 0; - rq.data_len = outsize; - - /* Copy data and start checksum */ - for (i = 0, d = (const uint8_t *)outdata; i < outsize; i++, d++) { - outb(*d, EC_LPC_ADDR_HOST_PACKET + sizeof(rq) + i); - csum += *d; - } - - /* Finish checksum */ - for (i = 0, d = (const uint8_t *)&rq; i < sizeof(rq); i++, d++) - csum += *d; - - /* Write checksum field so the entire packet sums to 0 */ - rq.checksum = (uint8_t)(-csum); - - /* Copy header */ - for (i = 0, d = (const uint8_t *)&rq; i < sizeof(rq); i++, d++) - outb(*d, EC_LPC_ADDR_HOST_PACKET + i); - - /* Start the command */ - outb(EC_COMMAND_PROTOCOL_3, EC_LPC_ADDR_HOST_CMD); - - if (wait_for_ec(EC_LPC_ADDR_HOST_CMD, 1000000)) { - fprintf(stderr, "Timeout waiting for EC response\n"); - return -EC_RES_ERROR; - } - - /* Check result */ - i = inb(EC_LPC_ADDR_HOST_DATA); - if (i) { - fprintf(stderr, "EC returned error result code %d\n", i); - return -EECRESULT - i; - } - - /* Read back response header and start checksum */ - csum = 0; - for (i = 0, dout = (uint8_t *)&rs; i < sizeof(rs); i++, dout++) { - *dout = inb(EC_LPC_ADDR_HOST_PACKET + i); - csum += *dout; - } - - if (rs.struct_version != EC_HOST_RESPONSE_VERSION) { - fprintf(stderr, "EC response version mismatch\n"); - return -EC_RES_INVALID_RESPONSE; - } - - if (rs.reserved) { - fprintf(stderr, "EC response reserved != 0\n"); - return -EC_RES_INVALID_RESPONSE; - } - - if (rs.data_len > insize) { - fprintf(stderr, "EC returned too much data\n"); - return -EC_RES_RESPONSE_TOO_BIG; - } - - /* Read back data and update checksum */ - for (i = 0, dout = (uint8_t *)indata; i < rs.data_len; i++, dout++) { - *dout = inb(EC_LPC_ADDR_HOST_PACKET + sizeof(rs) + i); - csum += *dout; - } - - /* Verify checksum */ - if ((uint8_t)csum) { - fprintf(stderr, "EC response has invalid checksum\n"); - return -EC_RES_INVALID_CHECKSUM; - } - - /* Return actual amount of data received */ - return rs.data_len; -} - -static int ec_readmem_lpc(int offset, int bytes, void *dest) -{ - int i = offset; - char *s = (char *)(dest); - int cnt = 0; - - if (offset >= EC_MEMMAP_SIZE - bytes) - return -1; - - if (bytes) { /* fixed length */ - for (; cnt < bytes; i++, s++, cnt++) - *s = inb(EC_LPC_ADDR_MEMMAP + i); - } else { /* string */ - for (; i < EC_MEMMAP_SIZE; i++, s++) { - *s = inb(EC_LPC_ADDR_MEMMAP + i); - cnt++; - if (!*s) - break; - } - } - - return cnt; -} - -int comm_init_lpc(void) -{ - int i; - int byte = 0xff; - - /* Request I/O privilege */ - if (iopl(3) < 0) { - perror("Error getting I/O privilege"); - return -3; - } - - /* - * Test if the I/O port has been configured for Chromium EC LPC - * interface. Chromium EC guarantees that at least one status bit will - * be 0, so if the command and data bytes are both 0xff, very likely - * that Chromium EC is not present. See crosbug.com/p/10963. - */ - byte &= inb(EC_LPC_ADDR_HOST_CMD); - byte &= inb(EC_LPC_ADDR_HOST_DATA); - if (byte == 0xff) { - fprintf(stderr, "Port 0x%x,0x%x are both 0xFF.\n", - EC_LPC_ADDR_HOST_CMD, EC_LPC_ADDR_HOST_DATA); - fprintf(stderr, - "Very likely this board doesn't have a Chromium EC.\n"); - return -4; - } - - /* - * Test if LPC command args are supported. - * - * The cheapest way to do this is by looking for the memory-mapped - * flag. This is faster than sending a new-style 'hello' command and - * seeing whether the EC sets the EC_HOST_ARGS_FLAG_FROM_HOST flag - * in args when it responds. - */ - if (inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID) != 'E' || - inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID + 1) != 'C') { - fprintf(stderr, "Missing Chromium EC memory map.\n"); - return -5; - } - - /* Check which command version we'll use */ - i = inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_HOST_CMD_FLAGS); - - if (i & EC_HOST_CMD_FLAG_VERSION_3) { - /* Protocol version 3 */ - ec_command_proto = ec_command_lpc_3; - ec_max_outsize = EC_LPC_HOST_PACKET_SIZE - - sizeof(struct ec_host_request); - ec_max_insize = EC_LPC_HOST_PACKET_SIZE - - sizeof(struct ec_host_response); - - } else if (i & EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED) { - /* Protocol version 2 */ - ec_command_proto = ec_command_lpc; - ec_max_outsize = ec_max_insize = EC_PROTO2_MAX_PARAM_SIZE; - - } else { - fprintf(stderr, "EC doesn't support protocols we need.\n"); - return -5; - } - - /* Either one supports reading mapped memory directly. */ - ec_readmem = ec_readmem_lpc; - return 0; -} - -#endif |