xref: /aosp_15_r20/external/flashrom/tests/ch341a_spi.c (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
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