1771df5a65efedd9fb2eb690cfd2e188e3dc3a4ecVadim Bendebury/*
2bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi/*
3bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi/*Copyright (C) 2015 The Android Open Source Project
4bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi/*
5bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi/*Licensed under the Apache License, Version 2.0 (the "License");
6bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi/*you may not use this file except in compliance with the License.
7bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi/*You may obtain a copy of the License at
8bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi/*
9bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi/*     http://www.apache.org/licenses/LICENSE-2.0
10bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi/*
11bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi/*Unless required by applicable law or agreed to in writing, software
12bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi/*distributed under the License is distributed on an "AS IS" BASIS,
13bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi/*WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi/*See the License for the specific language governing permissions and
15bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi/*limitations under the License.
16bbef5dff2b94fef72012e721cd6124cd87621af4Utkarsh Sanghi */
1726f26f5ae2c7a76aa199206dece12f65aa67da12Vadim Bendebury *
1826f26f5ae2c7a76aa199206dece12f65aa67da12Vadim Bendebury * This file was copied from https://github.com/devttys0/libmpsse.git (sha1
1926f26f5ae2c7a76aa199206dece12f65aa67da12Vadim Bendebury * f1a6744b), and modified to suite the Chromium OS project.
2026f26f5ae2c7a76aa199206dece12f65aa67da12Vadim Bendebury *
21771df5a65efedd9fb2eb690cfd2e188e3dc3a4ecVadim Bendebury * Internal functions used by libmpsse.
22771df5a65efedd9fb2eb690cfd2e188e3dc3a4ecVadim Bendebury *
23771df5a65efedd9fb2eb690cfd2e188e3dc3a4ecVadim Bendebury * Craig Heffner
24771df5a65efedd9fb2eb690cfd2e188e3dc3a4ecVadim Bendebury * 27 December 2011
25771df5a65efedd9fb2eb690cfd2e188e3dc3a4ecVadim Bendebury */
26771df5a65efedd9fb2eb690cfd2e188e3dc3a4ecVadim Bendebury#include <string.h>
27771df5a65efedd9fb2eb690cfd2e188e3dc3a4ecVadim Bendebury
2826f26f5ae2c7a76aa199206dece12f65aa67da12Vadim Bendebury#include "trunks/ftdi/support.h"
29771df5a65efedd9fb2eb690cfd2e188e3dc3a4ecVadim Bendebury
30771df5a65efedd9fb2eb690cfd2e188e3dc3a4ecVadim Bendebury/* Write data to the FTDI chip */
31c9aa4123ba0b0e08bec42c3abf48687b51806ba2Vadim Bendeburyint raw_write(struct mpsse_context* mpsse, uint8_t* buf, int size) {
324dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   int retval = MPSSE_FAIL;
334dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
344dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   if (mpsse->mode) {
354dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn     if (ftdi_write_data(&mpsse->ftdi, buf, size) == size) {
364dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       retval = MPSSE_OK;
374dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn     }
384dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   }
394dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
404dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   return retval;
414dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn }
424dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
434dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn /* Read data from the FTDI chip */
444dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn int raw_read(struct mpsse_context* mpsse, uint8_t* buf, int size) {
454dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   int n = 0, r = 0;
464dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
474dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   if (mpsse->mode) {
484dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn     while (n < size) {
494dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       r = ftdi_read_data(&mpsse->ftdi, buf, size);
504dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       if (r < 0)
514dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         break;
524dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       n += r;
534dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn     }
544dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
554dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn     if (mpsse->flush_after_read) {
564dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       /*
574dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn        * Make sure the buffers are cleared after a read or subsequent reads may
584dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn        *fail.
594dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn        *
604dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn        * Is this needed anymore? It slows down repetitive read operations by
614dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn        *~8%.
624dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn        */
634dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       ftdi_usb_purge_rx_buffer(&mpsse->ftdi);
644dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn     }
654dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   }
664dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
674dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   return n;
684dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn }
694dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
704dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn /* Sets the read and write timeout periods for bulk usb data transfers. */
714dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn void set_timeouts(struct mpsse_context* mpsse, int timeout) {
724dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   if (mpsse->mode) {
734dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn     mpsse->ftdi.usb_read_timeout = timeout;
744dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn     mpsse->ftdi.usb_write_timeout = timeout;
754dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   }
764dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
774dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   return;
784dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn }
794dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
804dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn /* Convert a frequency to a clock divisor */
814dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn uint16_t freq2div(uint32_t system_clock, uint32_t freq) {
824dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   return (((system_clock / freq) / 2) - 1);
834dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn }
844dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
854dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn /* Convert a clock divisor to a frequency */
864dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn uint32_t div2freq(uint32_t system_clock, uint16_t div) {
874dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   return (system_clock / ((1 + div) * 2));
884dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn }
894dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
904dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn /* Builds a buffer of commands + data blocks */
914dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn uint8_t* build_block_buffer(struct mpsse_context* mpsse,
924dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn                             uint8_t cmd,
934dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn                             const uint8_t* data,
944dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn                             int size,
954dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn                             int* buf_size) {
964dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   uint8_t* buf = NULL;
974dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   int i = 0, j = 0, k = 0, dsize = 0, num_blocks = 0, total_size = 0,
984dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       xfer_size = 0;
994dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   uint16_t rsize = 0;
1004dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
1014dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   *buf_size = 0;
1024dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
1034dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   /* Data block size is 1 in I2C, or when in bitmode */
1044dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   if (mpsse->mode == I2C || (cmd & MPSSE_BITMODE)) {
1054dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn     xfer_size = 1;
1064dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   } else {
1074dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn     xfer_size = mpsse->xsize;
1084dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   }
1094dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
1104dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   num_blocks = (size / xfer_size);
1114dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   if (size % xfer_size) {
1124dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn     num_blocks++;
1134dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   }
1144dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
1154dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   /* The total size of the data will be the data size + the write command */
1164dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   total_size = size + (CMD_SIZE * num_blocks);
1174dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
1184dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   /* In I2C we have to add 3 additional commands per data block */
1194dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   if (mpsse->mode == I2C) {
1204dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn     total_size += (CMD_SIZE * 3 * num_blocks);
1214dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   }
1224dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
1234dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   buf = malloc(total_size);
1244dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   if (buf) {
1254dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn     memset(buf, 0, total_size);
1264dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
1274dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn     for (j = 0; j < num_blocks; j++) {
1284dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       dsize = size - k;
1294dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       if (dsize > xfer_size) {
1304dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         dsize = xfer_size;
1314dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       }
1324dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
1334dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       /* The reported size of this block is block size - 1 */
1344dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       rsize = dsize - 1;
1354dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
1364dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       /* For I2C we need to ensure that the clock pin is set low prior to
1374dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn        * clocking out data */
1384dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       if (mpsse->mode == I2C) {
1394dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         buf[i++] = SET_BITS_LOW;
1404dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         buf[i++] = mpsse->pstart & ~SK;
1414dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
1424dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         /* On receive, we need to ensure that the data out line is set as an
1434dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn          * input to avoid contention on the bus */
1444dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         if (cmd == mpsse->rx) {
1454dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn           buf[i++] = mpsse->tris & ~DO;
1464dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         } else {
1474dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn           buf[i++] = mpsse->tris;
1484dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         }
1494dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       }
1504dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
1514dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       /* Copy in the command for this block */
1524dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       buf[i++] = cmd;
1534dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       buf[i++] = (rsize & 0xFF);
1544dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       if (!(cmd & MPSSE_BITMODE)) {
1554dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         buf[i++] = ((rsize >> 8) & 0xFF);
1564dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       }
1574dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
1584dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       /* On a write, copy the data to transmit after the command */
1594dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       if (cmd == mpsse->tx || cmd == mpsse->txrx) {
1604dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         memcpy(buf + i, data + k, dsize);
1614dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
1624dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         /* i == offset into buf */
1634dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         i += dsize;
1644dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         /* k == offset into data */
1654dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         k += dsize;
1664dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       }
1674dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
1684dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       /* In I2C mode we need to clock one ACK bit after each byte */
1694dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       if (mpsse->mode == I2C) {
1704dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         /* If we are receiving data, then we need to clock out an ACK for each
1714dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn          * byte */
1724dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         if (cmd == mpsse->rx) {
1734dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn           buf[i++] = SET_BITS_LOW;
1744dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn           buf[i++] = mpsse->pstart & ~SK;
1754dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn           buf[i++] = mpsse->tris;
1764dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
1774dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn           buf[i++] = mpsse->tx | MPSSE_BITMODE;
1784dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn           buf[i++] = 0;
1794dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn           buf[i++] = mpsse->tack;
1804dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         }
1814dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         /* If we are sending data, then we need to clock in an ACK for each
1824dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn          * byte
1834dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn            */
1844dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         else if (cmd == mpsse->tx) {
1854dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn           /* Need to make data out an input to avoid contention on the bus when
1864dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn            * the slave sends an ACK */
1874dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn           buf[i++] = SET_BITS_LOW;
1884dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn           buf[i++] = mpsse->pstart & ~SK;
1894dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn           buf[i++] = mpsse->tris & ~DO;
1904dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
1914dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn           buf[i++] = mpsse->rx | MPSSE_BITMODE;
1924dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn           buf[i++] = 0;
1934dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn           buf[i++] = SEND_IMMEDIATE;
1944dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         }
1954dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       }
1964dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn     }
1974dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
1984dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn     *buf_size = i;
1994dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   }
2004dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
2014dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   return buf;
2024dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn }
2034dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
2044dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn /* Set the low bit pins high/low */
2054dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn int set_bits_low(struct mpsse_context* mpsse, int port) {
2064dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   char buf[CMD_SIZE] = {0};
2074dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
2084dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   buf[0] = SET_BITS_LOW;
2094dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   buf[1] = port;
2104dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   buf[2] = mpsse->tris;
2114dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
2124dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   return raw_write(mpsse, (uint8_t*)&buf, sizeof(buf));
2134dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn }
2144dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
2154dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn /* Set the high bit pins high/low */
2164dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn int set_bits_high(struct mpsse_context* mpsse, int port) {
2174dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   char buf[CMD_SIZE] = {0};
2184dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
2194dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   buf[0] = SET_BITS_HIGH;
2204dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   buf[1] = port;
2214dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   buf[2] = mpsse->trish;
2224dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
2234dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   return raw_write(mpsse, (uint8_t*)&buf, sizeof(buf));
2244dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn }
2254dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
2264dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn /* Set the GPIO pins high/low */
2274dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn int gpio_write(struct mpsse_context* mpsse, int pin, int direction) {
2284dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   int retval = MPSSE_FAIL;
2294dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
2304dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   if (mpsse->mode == BITBANG) {
2314dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn     if (direction == HIGH) {
2324dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       mpsse->bitbang |= (1 << pin);
2334dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn     } else {
2344dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       mpsse->bitbang &= ~(1 << pin);
2354dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn     }
2364dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
2374dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn     if (set_bits_high(mpsse, mpsse->bitbang) == MPSSE_OK) {
2384dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       retval = raw_write(mpsse, (uint8_t*)&mpsse->bitbang, 1);
2394dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn     }
2404dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   } else {
2414dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn     /* The first four pins can't be changed unless we are in a stopped status
2424dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn      */
2434dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn     if (pin < NUM_GPIOL_PINS && mpsse->status == STOPPED) {
2444dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       /* Convert pin number (0-3) to the corresponding pin bit */
2454dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       pin = (GPIO0 << pin);
2464dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
2474dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       if (direction == HIGH) {
2484dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         mpsse->pstart |= pin;
2494dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         mpsse->pidle |= pin;
2504dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         mpsse->pstop |= pin;
2514dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       } else {
2524dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         mpsse->pstart &= ~pin;
2534dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         mpsse->pidle &= ~pin;
2544dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         mpsse->pstop &= ~pin;
2554dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       }
2564dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
2574dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       retval = set_bits_low(mpsse, mpsse->pstop);
2584dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn     } else if (pin >= NUM_GPIOL_PINS && pin < NUM_GPIO_PINS) {
2594dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       /* Convert pin number (4 - 11) to the corresponding pin bit */
2604dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       pin -= NUM_GPIOL_PINS;
2614dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
2624dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       if (direction == HIGH) {
2634dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         mpsse->gpioh |= (1 << pin);
2644dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       } else {
2654dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn         mpsse->gpioh &= ~(1 << pin);
2664dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       }
2674dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
2684dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn       retval = set_bits_high(mpsse, mpsse->gpioh);
2694dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn     }
2704dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   }
2714dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
2724dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   return retval;
2734dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn }
2744dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn
2754dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn /* Checks if a given MPSSE context is valid. */
2764dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn int is_valid_context(struct mpsse_context* mpsse) {
2774dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn   return mpsse != NULL;
2784dc4629c415e7ca90ff146d7bb75b5646ecd8b17Darren Krahn }
279