1 /*
2 * This file is part of the flashrom project.
3 *
4 * Copyright 2022 Alexander Goncharov <[email protected]>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16 #include "lifecycle.h"
17
18 #if CONFIG_CH341A_SPI == 1
19
20 /* Same macro as in ch341a_spi.c programmer. */
21 #define WRITE_EP 0x02
22 #define READ_EP 0x82
23
24 struct ch341a_spi_io_state {
25 struct libusb_transfer *transfer_out;
26 /*
27 * Since the test transfers a data that fits in one CH341 packet, we
28 * don't need an array of these transfers (as is done in the driver code).
29 */
30 struct libusb_transfer *transfer_in;
31 };
32
ch341a_libusb_alloc_transfer(void * state,int iso_packets)33 static struct libusb_transfer *ch341a_libusb_alloc_transfer(void *state, int iso_packets)
34 {
35 return calloc(1, sizeof(struct libusb_transfer));
36 }
37
38 /*
39 * The libusb code stores submitted transfers in their own context. But this
40 * function doesn't require a context pointer because libusb stores context
41 * pointers in libusb_transfer instances. Since our ch341 driver is using
42 * the default context, we store the transfer in our own.
43 */
ch341a_libusb_submit_transfer(void * state,struct libusb_transfer * transfer)44 static int ch341a_libusb_submit_transfer(void *state, struct libusb_transfer *transfer)
45 {
46 struct ch341a_spi_io_state *io_state = state;
47
48 assert_true(transfer->endpoint == WRITE_EP || transfer->endpoint == READ_EP);
49
50 if (transfer->endpoint == WRITE_EP) {
51 assert_null(io_state->transfer_out);
52 io_state->transfer_out = transfer;
53 } else if (transfer->endpoint == READ_EP) {
54 assert_null(io_state->transfer_in);
55 io_state->transfer_in = transfer;
56 }
57
58 return 0;
59 }
60
ch341a_libusb_free_transfer(void * state,struct libusb_transfer * transfer)61 static void ch341a_libusb_free_transfer(void *state, struct libusb_transfer *transfer)
62 {
63 free(transfer);
64 }
65
66 /*
67 * Handle submitted transfers by pretending that a transfer is completed and
68 * invoking its callback (that is the flashrom code).
69 */
ch341a_libusb_handle_events_timeout(void * state,libusb_context * ctx,struct timeval * tv)70 static int ch341a_libusb_handle_events_timeout(void *state, libusb_context *ctx, struct timeval *tv)
71 {
72 struct ch341a_spi_io_state *io_state = state;
73
74 if (io_state->transfer_out) {
75 io_state->transfer_out->status = LIBUSB_TRANSFER_COMPLETED;
76 io_state->transfer_out->actual_length = io_state->transfer_out->length;
77 io_state->transfer_out->callback(io_state->transfer_out);
78 io_state->transfer_out = NULL;
79 }
80
81 if (io_state->transfer_in) {
82 io_state->transfer_in->buffer[1] = reverse_byte(0xEF); /* WINBOND_NEX_ID */
83 io_state->transfer_in->buffer[2] = reverse_byte(0x40); /* WINBOND_NEX_W25Q128_V left byte */
84 io_state->transfer_in->buffer[3] = reverse_byte(0x18); /* WINBOND_NEX_W25Q128_V right byte */
85
86 io_state->transfer_in->status = LIBUSB_TRANSFER_COMPLETED;
87 io_state->transfer_in->actual_length = io_state->transfer_in->length;
88 io_state->transfer_in->callback(io_state->transfer_in);
89 io_state->transfer_in = NULL;
90 }
91
92 return 0;
93 }
94
ch341a_spi_basic_lifecycle_test_success(void ** state)95 void ch341a_spi_basic_lifecycle_test_success(void **state)
96 {
97 struct ch341a_spi_io_state ch341a_spi_io_state = { 0 };
98 struct io_mock_fallback_open_state ch341a_spi_fallback_open_state = {
99 .noc = 0,
100 .paths = { LOCK_FILE },
101 };
102 const struct io_mock ch341a_spi_io = {
103 .state = &ch341a_spi_io_state,
104 .libusb_alloc_transfer = &ch341a_libusb_alloc_transfer,
105 .libusb_submit_transfer = &ch341a_libusb_submit_transfer,
106 .libusb_free_transfer = &ch341a_libusb_free_transfer,
107 .libusb_handle_events_timeout = &ch341a_libusb_handle_events_timeout,
108 .fallback_open_state = &ch341a_spi_fallback_open_state,
109 };
110
111 run_basic_lifecycle(state, &ch341a_spi_io, &programmer_ch341a_spi, "");
112 }
113
ch341a_spi_probe_lifecycle_test_success(void ** state)114 void ch341a_spi_probe_lifecycle_test_success(void **state)
115 {
116 struct ch341a_spi_io_state ch341a_spi_io_state = { 0 };
117 struct io_mock_fallback_open_state ch341a_spi_fallback_open_state = {
118 .noc = 0,
119 .paths = { LOCK_FILE },
120 };
121 const struct io_mock ch341a_spi_io = {
122 .state = &ch341a_spi_io_state,
123 .libusb_alloc_transfer = &ch341a_libusb_alloc_transfer,
124 .libusb_submit_transfer = &ch341a_libusb_submit_transfer,
125 .libusb_free_transfer = &ch341a_libusb_free_transfer,
126 .libusb_handle_events_timeout = &ch341a_libusb_handle_events_timeout,
127 .fallback_open_state = &ch341a_spi_fallback_open_state,
128 };
129
130 run_probe_lifecycle(state, &ch341a_spi_io, &programmer_ch341a_spi, "", "W25Q128.V");
131 }
132
133 #else
134 SKIP_TEST(ch341a_spi_basic_lifecycle_test_success)
135 SKIP_TEST(ch341a_spi_probe_lifecycle_test_success)
136 #endif /* CONFIG_CH341A_SPI */
137