xref: /aosp_15_r20/external/flashrom/dediprog.c (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
1*0d6140beSAndroid Build Coastguard Worker /*
2*0d6140beSAndroid Build Coastguard Worker  * This file is part of the flashrom project.
3*0d6140beSAndroid Build Coastguard Worker  *
4*0d6140beSAndroid Build Coastguard Worker  * Copyright (C) 2010 Carl-Daniel Hailfinger
5*0d6140beSAndroid Build Coastguard Worker  * Copyright (C) 2015 Simon Glass
6*0d6140beSAndroid Build Coastguard Worker  * Copyright (C) 2015 Stefan Tauner
7*0d6140beSAndroid Build Coastguard Worker  *
8*0d6140beSAndroid Build Coastguard Worker  * This program is free software; you can redistribute it and/or modify
9*0d6140beSAndroid Build Coastguard Worker  * it under the terms of the GNU General Public License as published by
10*0d6140beSAndroid Build Coastguard Worker  * the Free Software Foundation; version 2 of the License.
11*0d6140beSAndroid Build Coastguard Worker  *
12*0d6140beSAndroid Build Coastguard Worker  * This program is distributed in the hope that it will be useful,
13*0d6140beSAndroid Build Coastguard Worker  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14*0d6140beSAndroid Build Coastguard Worker  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*0d6140beSAndroid Build Coastguard Worker  * GNU General Public License for more details.
16*0d6140beSAndroid Build Coastguard Worker  */
17*0d6140beSAndroid Build Coastguard Worker 
18*0d6140beSAndroid Build Coastguard Worker #include <sys/types.h>
19*0d6140beSAndroid Build Coastguard Worker #include <stdlib.h>
20*0d6140beSAndroid Build Coastguard Worker #include <stdio.h>
21*0d6140beSAndroid Build Coastguard Worker #include <string.h>
22*0d6140beSAndroid Build Coastguard Worker #include <limits.h>
23*0d6140beSAndroid Build Coastguard Worker #include <errno.h>
24*0d6140beSAndroid Build Coastguard Worker #include <libusb.h>
25*0d6140beSAndroid Build Coastguard Worker #include "flash.h"
26*0d6140beSAndroid Build Coastguard Worker #include "chipdrivers.h"
27*0d6140beSAndroid Build Coastguard Worker #include "programmer.h"
28*0d6140beSAndroid Build Coastguard Worker #include "spi.h"
29*0d6140beSAndroid Build Coastguard Worker 
30*0d6140beSAndroid Build Coastguard Worker /* LIBUSB_CALL ensures the right calling conventions on libusb callbacks.
31*0d6140beSAndroid Build Coastguard Worker  * However, the macro is not defined everywhere. m(
32*0d6140beSAndroid Build Coastguard Worker  */
33*0d6140beSAndroid Build Coastguard Worker #ifndef LIBUSB_CALL
34*0d6140beSAndroid Build Coastguard Worker #define LIBUSB_CALL
35*0d6140beSAndroid Build Coastguard Worker #endif
36*0d6140beSAndroid Build Coastguard Worker 
37*0d6140beSAndroid Build Coastguard Worker #define FIRMWARE_VERSION(x,y,z) ((x << 16) | (y << 8) | z)
38*0d6140beSAndroid Build Coastguard Worker #define DEFAULT_TIMEOUT 3000
39*0d6140beSAndroid Build Coastguard Worker #define DEDIPROG_ASYNC_TRANSFERS 8 /* at most 8 asynchronous transfers */
40*0d6140beSAndroid Build Coastguard Worker #define REQTYPE_OTHER_OUT (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_OTHER)	/* 0x43 */
41*0d6140beSAndroid Build Coastguard Worker #define REQTYPE_OTHER_IN (LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_OTHER)	/* 0xC3 */
42*0d6140beSAndroid Build Coastguard Worker #define REQTYPE_EP_OUT (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_ENDPOINT)	/* 0x42 */
43*0d6140beSAndroid Build Coastguard Worker #define REQTYPE_EP_IN (LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_ENDPOINT)	/* 0xC2 */
44*0d6140beSAndroid Build Coastguard Worker 
45*0d6140beSAndroid Build Coastguard Worker enum dediprog_devtype {
46*0d6140beSAndroid Build Coastguard Worker 	DEV_UNKNOWN		= 0,
47*0d6140beSAndroid Build Coastguard Worker 	DEV_SF100		= 100,
48*0d6140beSAndroid Build Coastguard Worker 	DEV_SF200		= 200,
49*0d6140beSAndroid Build Coastguard Worker 	DEV_SF600		= 600,
50*0d6140beSAndroid Build Coastguard Worker };
51*0d6140beSAndroid Build Coastguard Worker 
52*0d6140beSAndroid Build Coastguard Worker enum dediprog_leds {
53*0d6140beSAndroid Build Coastguard Worker 	LED_INVALID		= -1,
54*0d6140beSAndroid Build Coastguard Worker 	LED_NONE		= 0,
55*0d6140beSAndroid Build Coastguard Worker 	LED_PASS		= 1 << 0,
56*0d6140beSAndroid Build Coastguard Worker 	LED_BUSY		= 1 << 1,
57*0d6140beSAndroid Build Coastguard Worker 	LED_ERROR		= 1 << 2,
58*0d6140beSAndroid Build Coastguard Worker 	LED_ALL			= 7,
59*0d6140beSAndroid Build Coastguard Worker };
60*0d6140beSAndroid Build Coastguard Worker 
61*0d6140beSAndroid Build Coastguard Worker /* IO bits for CMD_SET_IO_LED message */
62*0d6140beSAndroid Build Coastguard Worker enum dediprog_ios {
63*0d6140beSAndroid Build Coastguard Worker 	IO1			= 1 << 0,
64*0d6140beSAndroid Build Coastguard Worker 	IO2			= 1 << 1,
65*0d6140beSAndroid Build Coastguard Worker 	IO3			= 1 << 2,
66*0d6140beSAndroid Build Coastguard Worker 	IO4			= 1 << 3,
67*0d6140beSAndroid Build Coastguard Worker };
68*0d6140beSAndroid Build Coastguard Worker 
69*0d6140beSAndroid Build Coastguard Worker enum dediprog_cmds {
70*0d6140beSAndroid Build Coastguard Worker 	CMD_TRANSCEIVE		= 0x01,
71*0d6140beSAndroid Build Coastguard Worker 	CMD_POLL_STATUS_REG	= 0x02,
72*0d6140beSAndroid Build Coastguard Worker 	CMD_SET_VPP		= 0x03,
73*0d6140beSAndroid Build Coastguard Worker 	CMD_SET_TARGET		= 0x04,
74*0d6140beSAndroid Build Coastguard Worker 	CMD_READ_EEPROM		= 0x05,
75*0d6140beSAndroid Build Coastguard Worker 	CMD_WRITE_EEPROM	= 0x06,
76*0d6140beSAndroid Build Coastguard Worker 	CMD_SET_IO_LED		= 0x07,
77*0d6140beSAndroid Build Coastguard Worker 	CMD_READ_PROG_INFO	= 0x08,
78*0d6140beSAndroid Build Coastguard Worker 	CMD_SET_VCC		= 0x09,
79*0d6140beSAndroid Build Coastguard Worker 	CMD_SET_STANDALONE	= 0x0A,
80*0d6140beSAndroid Build Coastguard Worker 	CMD_SET_VOLTAGE		= 0x0B,	/* Only in firmware older than 6.0.0 */
81*0d6140beSAndroid Build Coastguard Worker 	CMD_GET_BUTTON		= 0x11,
82*0d6140beSAndroid Build Coastguard Worker 	CMD_GET_UID		= 0x12,
83*0d6140beSAndroid Build Coastguard Worker 	CMD_SET_CS		= 0x14,
84*0d6140beSAndroid Build Coastguard Worker 	CMD_IO_MODE		= 0x15,
85*0d6140beSAndroid Build Coastguard Worker 	CMD_FW_UPDATE		= 0x1A,
86*0d6140beSAndroid Build Coastguard Worker 	CMD_FPGA_UPDATE		= 0x1B,
87*0d6140beSAndroid Build Coastguard Worker 	CMD_READ_FPGA_VERSION	= 0x1C,
88*0d6140beSAndroid Build Coastguard Worker 	CMD_SET_HOLD		= 0x1D,
89*0d6140beSAndroid Build Coastguard Worker 	CMD_READ		= 0x20,
90*0d6140beSAndroid Build Coastguard Worker 	CMD_WRITE		= 0x30,
91*0d6140beSAndroid Build Coastguard Worker 	CMD_WRITE_AT45DB	= 0x31,
92*0d6140beSAndroid Build Coastguard Worker 	CMD_NAND_WRITE		= 0x32,
93*0d6140beSAndroid Build Coastguard Worker 	CMD_NAND_READ		= 0x33,
94*0d6140beSAndroid Build Coastguard Worker 	CMD_SET_SPI_CLK		= 0x61,
95*0d6140beSAndroid Build Coastguard Worker 	CMD_CHECK_SOCKET	= 0x62,
96*0d6140beSAndroid Build Coastguard Worker 	CMD_DOWNLOAD_PRJ	= 0x63,
97*0d6140beSAndroid Build Coastguard Worker 	CMD_READ_PRJ_NAME	= 0x64,
98*0d6140beSAndroid Build Coastguard Worker 	// New protocol/firmware only
99*0d6140beSAndroid Build Coastguard Worker 	CMD_CHECK_SDCARD	= 0x65,
100*0d6140beSAndroid Build Coastguard Worker 	CMD_READ_PRJ		= 0x66,
101*0d6140beSAndroid Build Coastguard Worker };
102*0d6140beSAndroid Build Coastguard Worker 
103*0d6140beSAndroid Build Coastguard Worker enum dediprog_target {
104*0d6140beSAndroid Build Coastguard Worker 	FLASH_TYPE_APPLICATION_FLASH_1	= 0,
105*0d6140beSAndroid Build Coastguard Worker 	FLASH_TYPE_FLASH_CARD,
106*0d6140beSAndroid Build Coastguard Worker 	FLASH_TYPE_APPLICATION_FLASH_2,
107*0d6140beSAndroid Build Coastguard Worker 	FLASH_TYPE_SOCKET,
108*0d6140beSAndroid Build Coastguard Worker };
109*0d6140beSAndroid Build Coastguard Worker 
110*0d6140beSAndroid Build Coastguard Worker enum dediprog_readmode {
111*0d6140beSAndroid Build Coastguard Worker 	READ_MODE_STD			= 1,
112*0d6140beSAndroid Build Coastguard Worker 	READ_MODE_FAST			= 2,
113*0d6140beSAndroid Build Coastguard Worker 	READ_MODE_ATMEL45		= 3,
114*0d6140beSAndroid Build Coastguard Worker 	READ_MODE_4B_ADDR_FAST		= 4,
115*0d6140beSAndroid Build Coastguard Worker 	READ_MODE_4B_ADDR_FAST_0x0C	= 5, /* New protocol only */
116*0d6140beSAndroid Build Coastguard Worker };
117*0d6140beSAndroid Build Coastguard Worker 
118*0d6140beSAndroid Build Coastguard Worker enum dediprog_writemode {
119*0d6140beSAndroid Build Coastguard Worker 	WRITE_MODE_PAGE_PGM			= 1,
120*0d6140beSAndroid Build Coastguard Worker 	WRITE_MODE_PAGE_WRITE			= 2,
121*0d6140beSAndroid Build Coastguard Worker 	WRITE_MODE_1B_AAI			= 3,
122*0d6140beSAndroid Build Coastguard Worker 	WRITE_MODE_2B_AAI			= 4,
123*0d6140beSAndroid Build Coastguard Worker 	WRITE_MODE_128B_PAGE			= 5,
124*0d6140beSAndroid Build Coastguard Worker 	WRITE_MODE_PAGE_AT26DF041		= 6,
125*0d6140beSAndroid Build Coastguard Worker 	WRITE_MODE_SILICON_BLUE_FPGA		= 7,
126*0d6140beSAndroid Build Coastguard Worker 	WRITE_MODE_64B_PAGE_NUMONYX_PCM		= 8,	/* unit of 512 bytes */
127*0d6140beSAndroid Build Coastguard Worker 	WRITE_MODE_4B_ADDR_256B_PAGE_PGM	= 9,
128*0d6140beSAndroid Build Coastguard Worker 	WRITE_MODE_32B_PAGE_PGM_MXIC_512K	= 10,	/* unit of 512 bytes */
129*0d6140beSAndroid Build Coastguard Worker 	WRITE_MODE_4B_ADDR_256B_PAGE_PGM_0x12	= 11,
130*0d6140beSAndroid Build Coastguard Worker 	WRITE_MODE_4B_ADDR_256B_PAGE_PGM_FLAGS	= 12,
131*0d6140beSAndroid Build Coastguard Worker };
132*0d6140beSAndroid Build Coastguard Worker 
133*0d6140beSAndroid Build Coastguard Worker enum dediprog_standalone_mode {
134*0d6140beSAndroid Build Coastguard Worker 	ENTER_STANDALONE_MODE = 0,
135*0d6140beSAndroid Build Coastguard Worker 	LEAVE_STANDALONE_MODE = 1,
136*0d6140beSAndroid Build Coastguard Worker };
137*0d6140beSAndroid Build Coastguard Worker 
138*0d6140beSAndroid Build Coastguard Worker /*
139*0d6140beSAndroid Build Coastguard Worker  * These are not official designations; they are for use in flashrom only.
140*0d6140beSAndroid Build Coastguard Worker  * Order must be preserved so that comparison operators work.
141*0d6140beSAndroid Build Coastguard Worker  */
142*0d6140beSAndroid Build Coastguard Worker enum protocol {
143*0d6140beSAndroid Build Coastguard Worker 	PROTOCOL_UNKNOWN,
144*0d6140beSAndroid Build Coastguard Worker 	PROTOCOL_V1,
145*0d6140beSAndroid Build Coastguard Worker 	PROTOCOL_V2,
146*0d6140beSAndroid Build Coastguard Worker 	PROTOCOL_V3,
147*0d6140beSAndroid Build Coastguard Worker };
148*0d6140beSAndroid Build Coastguard Worker 
149*0d6140beSAndroid Build Coastguard Worker static const struct dev_entry devs_dediprog[] = {
150*0d6140beSAndroid Build Coastguard Worker 	{0x0483, 0xDADA, OK, "Dediprog", "SF100/SF200/SF600"},
151*0d6140beSAndroid Build Coastguard Worker 
152*0d6140beSAndroid Build Coastguard Worker 	{0},
153*0d6140beSAndroid Build Coastguard Worker };
154*0d6140beSAndroid Build Coastguard Worker 
155*0d6140beSAndroid Build Coastguard Worker struct dediprog_data {
156*0d6140beSAndroid Build Coastguard Worker 	struct libusb_context *usb_ctx;
157*0d6140beSAndroid Build Coastguard Worker 	libusb_device_handle *handle;
158*0d6140beSAndroid Build Coastguard Worker 	int in_endpoint;
159*0d6140beSAndroid Build Coastguard Worker 	int out_endpoint;
160*0d6140beSAndroid Build Coastguard Worker 	int firmwareversion;
161*0d6140beSAndroid Build Coastguard Worker 	enum dediprog_devtype devicetype;
162*0d6140beSAndroid Build Coastguard Worker };
163*0d6140beSAndroid Build Coastguard Worker 
164*0d6140beSAndroid Build Coastguard Worker #if defined(LIBUSB_MAJOR) && defined(LIBUSB_MINOR) && defined(LIBUSB_MICRO) && \
165*0d6140beSAndroid Build Coastguard Worker     LIBUSB_MAJOR <= 1 && LIBUSB_MINOR == 0 && LIBUSB_MICRO < 9
166*0d6140beSAndroid Build Coastguard Worker /* Quick and dirty replacement for missing libusb_error_name in libusb < 1.0.9 */
libusb_error_name(int error_code)167*0d6140beSAndroid Build Coastguard Worker const char * LIBUSB_CALL libusb_error_name(int error_code)
168*0d6140beSAndroid Build Coastguard Worker {
169*0d6140beSAndroid Build Coastguard Worker 	if (error_code >= INT16_MIN && error_code <= INT16_MAX) {
170*0d6140beSAndroid Build Coastguard Worker 		/* 18 chars for text, rest for number (16 b should be enough), sign, nullbyte. */
171*0d6140beSAndroid Build Coastguard Worker 		static char my_libusb_error[18 + 5 + 2];
172*0d6140beSAndroid Build Coastguard Worker 		sprintf(my_libusb_error, "libusb error code %i", error_code);
173*0d6140beSAndroid Build Coastguard Worker 		return my_libusb_error;
174*0d6140beSAndroid Build Coastguard Worker 	} else {
175*0d6140beSAndroid Build Coastguard Worker 		return "UNKNOWN";
176*0d6140beSAndroid Build Coastguard Worker 	}
177*0d6140beSAndroid Build Coastguard Worker }
178*0d6140beSAndroid Build Coastguard Worker #endif
179*0d6140beSAndroid Build Coastguard Worker 
protocol(const struct dediprog_data * dp_data)180*0d6140beSAndroid Build Coastguard Worker static enum protocol protocol(const struct dediprog_data *dp_data)
181*0d6140beSAndroid Build Coastguard Worker {
182*0d6140beSAndroid Build Coastguard Worker 	/* Firmware version < 5.0.0 is handled explicitly in some cases. */
183*0d6140beSAndroid Build Coastguard Worker 	switch (dp_data->devicetype) {
184*0d6140beSAndroid Build Coastguard Worker 	case DEV_SF100:
185*0d6140beSAndroid Build Coastguard Worker 	case DEV_SF200:
186*0d6140beSAndroid Build Coastguard Worker 		if (dp_data->firmwareversion < FIRMWARE_VERSION(5, 5, 0))
187*0d6140beSAndroid Build Coastguard Worker 			return PROTOCOL_V1;
188*0d6140beSAndroid Build Coastguard Worker 		else
189*0d6140beSAndroid Build Coastguard Worker 			return PROTOCOL_V2;
190*0d6140beSAndroid Build Coastguard Worker 	case DEV_SF600:
191*0d6140beSAndroid Build Coastguard Worker 		if (dp_data->firmwareversion < FIRMWARE_VERSION(6, 9, 0))
192*0d6140beSAndroid Build Coastguard Worker 			return PROTOCOL_V1;
193*0d6140beSAndroid Build Coastguard Worker 		else if (dp_data->firmwareversion <= FIRMWARE_VERSION(7, 2, 21))
194*0d6140beSAndroid Build Coastguard Worker 			return PROTOCOL_V2;
195*0d6140beSAndroid Build Coastguard Worker 		else
196*0d6140beSAndroid Build Coastguard Worker 			return PROTOCOL_V3;
197*0d6140beSAndroid Build Coastguard Worker 	default:
198*0d6140beSAndroid Build Coastguard Worker 		return PROTOCOL_UNKNOWN;
199*0d6140beSAndroid Build Coastguard Worker 	}
200*0d6140beSAndroid Build Coastguard Worker }
201*0d6140beSAndroid Build Coastguard Worker 
202*0d6140beSAndroid Build Coastguard Worker struct dediprog_transfer_status {
203*0d6140beSAndroid Build Coastguard Worker 	int error; /* OK if 0, ERROR else */
204*0d6140beSAndroid Build Coastguard Worker 	unsigned int queued_idx;
205*0d6140beSAndroid Build Coastguard Worker 	unsigned int finished_idx;
206*0d6140beSAndroid Build Coastguard Worker };
207*0d6140beSAndroid Build Coastguard Worker 
dediprog_bulk_read_cb(struct libusb_transfer * const transfer)208*0d6140beSAndroid Build Coastguard Worker static void LIBUSB_CALL dediprog_bulk_read_cb(struct libusb_transfer *const transfer)
209*0d6140beSAndroid Build Coastguard Worker {
210*0d6140beSAndroid Build Coastguard Worker 	struct dediprog_transfer_status *const status = (struct dediprog_transfer_status *)transfer->user_data;
211*0d6140beSAndroid Build Coastguard Worker 	if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
212*0d6140beSAndroid Build Coastguard Worker 		status->error = 1;
213*0d6140beSAndroid Build Coastguard Worker 		msg_perr("SPI bulk read failed!\n");
214*0d6140beSAndroid Build Coastguard Worker 	}
215*0d6140beSAndroid Build Coastguard Worker 	++status->finished_idx;
216*0d6140beSAndroid Build Coastguard Worker }
217*0d6140beSAndroid Build Coastguard Worker 
dediprog_bulk_read_poll(struct libusb_context * usb_ctx,const struct dediprog_transfer_status * const status,const int finish)218*0d6140beSAndroid Build Coastguard Worker static int dediprog_bulk_read_poll(struct libusb_context *usb_ctx,
219*0d6140beSAndroid Build Coastguard Worker 				   const struct dediprog_transfer_status *const status,
220*0d6140beSAndroid Build Coastguard Worker 				   const int finish)
221*0d6140beSAndroid Build Coastguard Worker {
222*0d6140beSAndroid Build Coastguard Worker 	if (status->finished_idx >= status->queued_idx)
223*0d6140beSAndroid Build Coastguard Worker 		return 0;
224*0d6140beSAndroid Build Coastguard Worker 
225*0d6140beSAndroid Build Coastguard Worker 	do {
226*0d6140beSAndroid Build Coastguard Worker 		struct timeval timeout = { 10, 0 };
227*0d6140beSAndroid Build Coastguard Worker 		const int ret = libusb_handle_events_timeout(usb_ctx, &timeout);
228*0d6140beSAndroid Build Coastguard Worker 		if (ret < 0) {
229*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Polling read events failed: %i %s!\n", ret, libusb_error_name(ret));
230*0d6140beSAndroid Build Coastguard Worker 			return 1;
231*0d6140beSAndroid Build Coastguard Worker 		}
232*0d6140beSAndroid Build Coastguard Worker 	} while (finish && (status->finished_idx < status->queued_idx));
233*0d6140beSAndroid Build Coastguard Worker 	return 0;
234*0d6140beSAndroid Build Coastguard Worker }
235*0d6140beSAndroid Build Coastguard Worker 
dediprog_read(libusb_device_handle * dediprog_handle,enum dediprog_cmds cmd,unsigned int value,unsigned int idx,uint8_t * bytes,size_t size)236*0d6140beSAndroid Build Coastguard Worker static int dediprog_read(libusb_device_handle *dediprog_handle,
237*0d6140beSAndroid Build Coastguard Worker 			 enum dediprog_cmds cmd, unsigned int value, unsigned int idx,
238*0d6140beSAndroid Build Coastguard Worker 			 uint8_t *bytes, size_t size)
239*0d6140beSAndroid Build Coastguard Worker {
240*0d6140beSAndroid Build Coastguard Worker 	return libusb_control_transfer(dediprog_handle, REQTYPE_EP_IN, cmd, value, idx,
241*0d6140beSAndroid Build Coastguard Worker 				      (unsigned char *)bytes, size, DEFAULT_TIMEOUT);
242*0d6140beSAndroid Build Coastguard Worker }
243*0d6140beSAndroid Build Coastguard Worker 
dediprog_write(libusb_device_handle * dediprog_handle,enum dediprog_cmds cmd,unsigned int value,unsigned int idx,const uint8_t * bytes,size_t size)244*0d6140beSAndroid Build Coastguard Worker static int dediprog_write(libusb_device_handle *dediprog_handle,
245*0d6140beSAndroid Build Coastguard Worker 			  enum dediprog_cmds cmd, unsigned int value, unsigned int idx,
246*0d6140beSAndroid Build Coastguard Worker 			  const uint8_t *bytes, size_t size)
247*0d6140beSAndroid Build Coastguard Worker {
248*0d6140beSAndroid Build Coastguard Worker 	return libusb_control_transfer(dediprog_handle, REQTYPE_EP_OUT, cmd, value, idx,
249*0d6140beSAndroid Build Coastguard Worker 				      (unsigned char *)bytes, size, DEFAULT_TIMEOUT);
250*0d6140beSAndroid Build Coastguard Worker }
251*0d6140beSAndroid Build Coastguard Worker 
252*0d6140beSAndroid Build Coastguard Worker 
253*0d6140beSAndroid Build Coastguard Worker /* This function sets the GPIOs connected to the LEDs as well as IO1-IO4. */
dediprog_set_leds(int leds,const struct dediprog_data * dp_data)254*0d6140beSAndroid Build Coastguard Worker static int dediprog_set_leds(int leds, const struct dediprog_data *dp_data)
255*0d6140beSAndroid Build Coastguard Worker {
256*0d6140beSAndroid Build Coastguard Worker 	if (leds < LED_NONE || leds > LED_ALL)
257*0d6140beSAndroid Build Coastguard Worker 		leds = LED_ALL;
258*0d6140beSAndroid Build Coastguard Worker 
259*0d6140beSAndroid Build Coastguard Worker 	/* Older Dediprogs with 2.x.x and 3.x.x firmware only had two LEDs, assigned to different bits. So map
260*0d6140beSAndroid Build Coastguard Worker 	 * them around if we have an old device. On those devices the LEDs map as follows:
261*0d6140beSAndroid Build Coastguard Worker 	 *   bit 2 == 0: green light is on.
262*0d6140beSAndroid Build Coastguard Worker 	 *   bit 0 == 0: red light is on.
263*0d6140beSAndroid Build Coastguard Worker 	 *
264*0d6140beSAndroid Build Coastguard Worker 	 * Additionally, the command structure has changed with the "new" protocol.
265*0d6140beSAndroid Build Coastguard Worker 	 *
266*0d6140beSAndroid Build Coastguard Worker 	 * FIXME: take IO pins into account
267*0d6140beSAndroid Build Coastguard Worker 	 */
268*0d6140beSAndroid Build Coastguard Worker 	int target_leds, ret;
269*0d6140beSAndroid Build Coastguard Worker 	if (protocol(dp_data) >= PROTOCOL_V2) {
270*0d6140beSAndroid Build Coastguard Worker 		target_leds = (leds ^ 7) << 8;
271*0d6140beSAndroid Build Coastguard Worker 		ret = dediprog_write(dp_data->handle, CMD_SET_IO_LED, target_leds, 0, NULL, 0);
272*0d6140beSAndroid Build Coastguard Worker 	} else {
273*0d6140beSAndroid Build Coastguard Worker 		if (dp_data->firmwareversion < FIRMWARE_VERSION(5, 0, 0)) {
274*0d6140beSAndroid Build Coastguard Worker 			target_leds = ((leds & LED_ERROR) >> 2) | ((leds & LED_PASS) << 2);
275*0d6140beSAndroid Build Coastguard Worker 		} else {
276*0d6140beSAndroid Build Coastguard Worker 			target_leds = leds;
277*0d6140beSAndroid Build Coastguard Worker 		}
278*0d6140beSAndroid Build Coastguard Worker 		target_leds ^= 7;
279*0d6140beSAndroid Build Coastguard Worker 
280*0d6140beSAndroid Build Coastguard Worker 		ret = dediprog_write(dp_data->handle, CMD_SET_IO_LED, 0x9, target_leds, NULL, 0);
281*0d6140beSAndroid Build Coastguard Worker 	}
282*0d6140beSAndroid Build Coastguard Worker 
283*0d6140beSAndroid Build Coastguard Worker 	if (ret != 0x0) {
284*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Command Set LED 0x%x failed (%s)!\n", leds, libusb_error_name(ret));
285*0d6140beSAndroid Build Coastguard Worker 		return 1;
286*0d6140beSAndroid Build Coastguard Worker 	}
287*0d6140beSAndroid Build Coastguard Worker 
288*0d6140beSAndroid Build Coastguard Worker 	return 0;
289*0d6140beSAndroid Build Coastguard Worker }
290*0d6140beSAndroid Build Coastguard Worker 
dediprog_set_spi_voltage(libusb_device_handle * dediprog_handle,int millivolt)291*0d6140beSAndroid Build Coastguard Worker static int dediprog_set_spi_voltage(libusb_device_handle *dediprog_handle, int millivolt)
292*0d6140beSAndroid Build Coastguard Worker {
293*0d6140beSAndroid Build Coastguard Worker 	int ret;
294*0d6140beSAndroid Build Coastguard Worker 	uint16_t voltage_selector;
295*0d6140beSAndroid Build Coastguard Worker 
296*0d6140beSAndroid Build Coastguard Worker 	switch (millivolt) {
297*0d6140beSAndroid Build Coastguard Worker 	case 0:
298*0d6140beSAndroid Build Coastguard Worker 		/* Admittedly this one is an assumption. */
299*0d6140beSAndroid Build Coastguard Worker 		voltage_selector = 0x0;
300*0d6140beSAndroid Build Coastguard Worker 		break;
301*0d6140beSAndroid Build Coastguard Worker 	case 1800:
302*0d6140beSAndroid Build Coastguard Worker 		voltage_selector = 0x12;
303*0d6140beSAndroid Build Coastguard Worker 		break;
304*0d6140beSAndroid Build Coastguard Worker 	case 2500:
305*0d6140beSAndroid Build Coastguard Worker 		voltage_selector = 0x11;
306*0d6140beSAndroid Build Coastguard Worker 		break;
307*0d6140beSAndroid Build Coastguard Worker 	case 3500:
308*0d6140beSAndroid Build Coastguard Worker 		voltage_selector = 0x10;
309*0d6140beSAndroid Build Coastguard Worker 		break;
310*0d6140beSAndroid Build Coastguard Worker 	default:
311*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Unknown voltage %i mV! Aborting.\n", millivolt);
312*0d6140beSAndroid Build Coastguard Worker 		return 1;
313*0d6140beSAndroid Build Coastguard Worker 	}
314*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("Setting SPI voltage to %u.%03u V\n", millivolt / 1000,
315*0d6140beSAndroid Build Coastguard Worker 		 millivolt % 1000);
316*0d6140beSAndroid Build Coastguard Worker 
317*0d6140beSAndroid Build Coastguard Worker 	if (voltage_selector == 0) {
318*0d6140beSAndroid Build Coastguard Worker 		/* Wait some time as the original driver does. */
319*0d6140beSAndroid Build Coastguard Worker 		default_delay(200 * 1000);
320*0d6140beSAndroid Build Coastguard Worker 	}
321*0d6140beSAndroid Build Coastguard Worker 	ret = dediprog_write(dediprog_handle, CMD_SET_VCC, voltage_selector, 0, NULL, 0);
322*0d6140beSAndroid Build Coastguard Worker 	if (ret != 0x0) {
323*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Command Set SPI Voltage 0x%x failed!\n",
324*0d6140beSAndroid Build Coastguard Worker 			 voltage_selector);
325*0d6140beSAndroid Build Coastguard Worker 		return 1;
326*0d6140beSAndroid Build Coastguard Worker 	}
327*0d6140beSAndroid Build Coastguard Worker 	if (voltage_selector != 0) {
328*0d6140beSAndroid Build Coastguard Worker 		/* Wait some time as the original driver does. */
329*0d6140beSAndroid Build Coastguard Worker 		default_delay(200 * 1000);
330*0d6140beSAndroid Build Coastguard Worker 	}
331*0d6140beSAndroid Build Coastguard Worker 	return 0;
332*0d6140beSAndroid Build Coastguard Worker }
333*0d6140beSAndroid Build Coastguard Worker 
334*0d6140beSAndroid Build Coastguard Worker struct dediprog_spispeeds {
335*0d6140beSAndroid Build Coastguard Worker 	const char *const name;
336*0d6140beSAndroid Build Coastguard Worker 	const int speed;
337*0d6140beSAndroid Build Coastguard Worker };
338*0d6140beSAndroid Build Coastguard Worker 
339*0d6140beSAndroid Build Coastguard Worker static const struct dediprog_spispeeds spispeeds[] = {
340*0d6140beSAndroid Build Coastguard Worker 	{ "24M",	0x0 },
341*0d6140beSAndroid Build Coastguard Worker 	{ "12M",	0x2 },
342*0d6140beSAndroid Build Coastguard Worker 	{ "8M",		0x1 },
343*0d6140beSAndroid Build Coastguard Worker 	{ "3M",		0x3 },
344*0d6140beSAndroid Build Coastguard Worker 	{ "2.18M",	0x4 },
345*0d6140beSAndroid Build Coastguard Worker 	{ "1.5M",	0x5 },
346*0d6140beSAndroid Build Coastguard Worker 	{ "750k",	0x6 },
347*0d6140beSAndroid Build Coastguard Worker 	{ "375k",	0x7 },
348*0d6140beSAndroid Build Coastguard Worker 	{ NULL,		0x0 },
349*0d6140beSAndroid Build Coastguard Worker };
350*0d6140beSAndroid Build Coastguard Worker 
dediprog_set_spi_speed(unsigned int spispeed_idx,const struct dediprog_data * dp_data)351*0d6140beSAndroid Build Coastguard Worker static int dediprog_set_spi_speed(unsigned int spispeed_idx, const struct dediprog_data *dp_data)
352*0d6140beSAndroid Build Coastguard Worker {
353*0d6140beSAndroid Build Coastguard Worker 	if (dp_data->firmwareversion < FIRMWARE_VERSION(5, 0, 0)) {
354*0d6140beSAndroid Build Coastguard Worker 		msg_pwarn("Skipping to set SPI speed because firmware is too old.\n");
355*0d6140beSAndroid Build Coastguard Worker 		return 0;
356*0d6140beSAndroid Build Coastguard Worker 	}
357*0d6140beSAndroid Build Coastguard Worker 
358*0d6140beSAndroid Build Coastguard Worker 	const struct dediprog_spispeeds *spispeed = &spispeeds[spispeed_idx];
359*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("SPI speed is %sHz\n", spispeed->name);
360*0d6140beSAndroid Build Coastguard Worker 
361*0d6140beSAndroid Build Coastguard Worker 	int ret = dediprog_write(dp_data->handle, CMD_SET_SPI_CLK, spispeed->speed, 0, NULL, 0);
362*0d6140beSAndroid Build Coastguard Worker 	if (ret != 0x0) {
363*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Command Set SPI Speed 0x%x failed!\n", spispeed->speed);
364*0d6140beSAndroid Build Coastguard Worker 		return 1;
365*0d6140beSAndroid Build Coastguard Worker 	}
366*0d6140beSAndroid Build Coastguard Worker 	return 0;
367*0d6140beSAndroid Build Coastguard Worker }
368*0d6140beSAndroid Build Coastguard Worker 
prepare_rw_cmd(struct flashctx * const flash,uint8_t * data_packet,unsigned int count,uint8_t dedi_spi_cmd,unsigned int * value,unsigned int * idx,unsigned int start,int is_read)369*0d6140beSAndroid Build Coastguard Worker static int prepare_rw_cmd(
370*0d6140beSAndroid Build Coastguard Worker 		struct flashctx *const flash, uint8_t *data_packet, unsigned int count,
371*0d6140beSAndroid Build Coastguard Worker 		uint8_t dedi_spi_cmd, unsigned int *value, unsigned int *idx, unsigned int start, int is_read)
372*0d6140beSAndroid Build Coastguard Worker {
373*0d6140beSAndroid Build Coastguard Worker 	const struct dediprog_data *dp_data = flash->mst->spi.data;
374*0d6140beSAndroid Build Coastguard Worker 
375*0d6140beSAndroid Build Coastguard Worker 	if (count >= 1 << 16) {
376*0d6140beSAndroid Build Coastguard Worker 		msg_perr("%s: Unsupported transfer length of %u blocks! "
377*0d6140beSAndroid Build Coastguard Worker 			 "Please report a bug at [email protected]\n",
378*0d6140beSAndroid Build Coastguard Worker 			 __func__, count);
379*0d6140beSAndroid Build Coastguard Worker 		return 1;
380*0d6140beSAndroid Build Coastguard Worker 	}
381*0d6140beSAndroid Build Coastguard Worker 
382*0d6140beSAndroid Build Coastguard Worker 	/* First 5 bytes are common in both generations. */
383*0d6140beSAndroid Build Coastguard Worker 	data_packet[0] = count & 0xff;
384*0d6140beSAndroid Build Coastguard Worker 	data_packet[1] = (count >> 8) & 0xff;
385*0d6140beSAndroid Build Coastguard Worker 	data_packet[2] = 0; /* RFU */
386*0d6140beSAndroid Build Coastguard Worker 	data_packet[3] = dedi_spi_cmd; /* Read/Write Mode (currently READ_MODE_STD, WRITE_MODE_PAGE_PGM or WRITE_MODE_2B_AAI) */
387*0d6140beSAndroid Build Coastguard Worker 	data_packet[4] = 0; /* "Opcode". Specs imply necessity only for READ_MODE_4B_ADDR_FAST and WRITE_MODE_4B_ADDR_256B_PAGE_PGM */
388*0d6140beSAndroid Build Coastguard Worker 
389*0d6140beSAndroid Build Coastguard Worker 	if (protocol(dp_data) >= PROTOCOL_V2) {
390*0d6140beSAndroid Build Coastguard Worker 		if (is_read && flash->chip->feature_bits & FEATURE_4BA_FAST_READ) {
391*0d6140beSAndroid Build Coastguard Worker 			data_packet[3] = READ_MODE_4B_ADDR_FAST_0x0C;
392*0d6140beSAndroid Build Coastguard Worker 			data_packet[4] = JEDEC_READ_4BA_FAST;
393*0d6140beSAndroid Build Coastguard Worker 		} else if (dedi_spi_cmd == WRITE_MODE_PAGE_PGM
394*0d6140beSAndroid Build Coastguard Worker 			   && (flash->chip->feature_bits & FEATURE_4BA_WRITE)) {
395*0d6140beSAndroid Build Coastguard Worker 			data_packet[3] = WRITE_MODE_4B_ADDR_256B_PAGE_PGM_0x12;
396*0d6140beSAndroid Build Coastguard Worker 			data_packet[4] = JEDEC_BYTE_PROGRAM_4BA;
397*0d6140beSAndroid Build Coastguard Worker 		}
398*0d6140beSAndroid Build Coastguard Worker 
399*0d6140beSAndroid Build Coastguard Worker 		*value = *idx = 0;
400*0d6140beSAndroid Build Coastguard Worker 		data_packet[5] = 0; /* RFU */
401*0d6140beSAndroid Build Coastguard Worker 		data_packet[6] = (start >>  0) & 0xff;
402*0d6140beSAndroid Build Coastguard Worker 		data_packet[7] = (start >>  8) & 0xff;
403*0d6140beSAndroid Build Coastguard Worker 		data_packet[8] = (start >> 16) & 0xff;
404*0d6140beSAndroid Build Coastguard Worker 		data_packet[9] = (start >> 24) & 0xff;
405*0d6140beSAndroid Build Coastguard Worker 		if (protocol(dp_data) >= PROTOCOL_V3) {
406*0d6140beSAndroid Build Coastguard Worker 			if (is_read) {
407*0d6140beSAndroid Build Coastguard Worker 				data_packet[10] = 0x00;	/* address length (3 or 4) */
408*0d6140beSAndroid Build Coastguard Worker 				data_packet[11] = 0x00;	/* dummy cycle / 2 */
409*0d6140beSAndroid Build Coastguard Worker 			} else {
410*0d6140beSAndroid Build Coastguard Worker 				/* 16 LSBs and 16 HSBs of page size */
411*0d6140beSAndroid Build Coastguard Worker 				/* FIXME: This assumes page size of 256. */
412*0d6140beSAndroid Build Coastguard Worker 				data_packet[10] = 0x00;
413*0d6140beSAndroid Build Coastguard Worker 				data_packet[11] = 0x01;
414*0d6140beSAndroid Build Coastguard Worker 				data_packet[12] = 0x00;
415*0d6140beSAndroid Build Coastguard Worker 				data_packet[13] = 0x00;
416*0d6140beSAndroid Build Coastguard Worker 			}
417*0d6140beSAndroid Build Coastguard Worker 		}
418*0d6140beSAndroid Build Coastguard Worker 	} else {
419*0d6140beSAndroid Build Coastguard Worker 		if (flash->chip->feature_bits & FEATURE_4BA_EAR_ANY) {
420*0d6140beSAndroid Build Coastguard Worker 			if (spi_set_extended_address(flash, start >> 24))
421*0d6140beSAndroid Build Coastguard Worker 				return 1;
422*0d6140beSAndroid Build Coastguard Worker 		} else if (start >> 24) {
423*0d6140beSAndroid Build Coastguard Worker 			msg_cerr("Can't handle 4-byte address with dediprog.\n");
424*0d6140beSAndroid Build Coastguard Worker 			return 1;
425*0d6140beSAndroid Build Coastguard Worker 		}
426*0d6140beSAndroid Build Coastguard Worker 		/*
427*0d6140beSAndroid Build Coastguard Worker 		 * We don't know how the dediprog firmware handles 4-byte
428*0d6140beSAndroid Build Coastguard Worker 		 * addresses. So let's not tell it what we are doing and
429*0d6140beSAndroid Build Coastguard Worker 		 * only send the lower 3 bytes.
430*0d6140beSAndroid Build Coastguard Worker 		 */
431*0d6140beSAndroid Build Coastguard Worker 		*value = start & 0xffff;
432*0d6140beSAndroid Build Coastguard Worker 		*idx = (start >> 16) & 0xff;
433*0d6140beSAndroid Build Coastguard Worker 	}
434*0d6140beSAndroid Build Coastguard Worker 
435*0d6140beSAndroid Build Coastguard Worker 	return 0;
436*0d6140beSAndroid Build Coastguard Worker }
437*0d6140beSAndroid Build Coastguard Worker 
438*0d6140beSAndroid Build Coastguard Worker /* Bulk read interface, will read multiple 512 byte chunks aligned to 512 bytes.
439*0d6140beSAndroid Build Coastguard Worker  * @start	start address
440*0d6140beSAndroid Build Coastguard Worker  * @len		length
441*0d6140beSAndroid Build Coastguard Worker  * @return	0 on success, 1 on failure
442*0d6140beSAndroid Build Coastguard Worker  */
dediprog_spi_bulk_read(struct flashctx * flash,uint8_t * buf,unsigned int start,unsigned int len)443*0d6140beSAndroid Build Coastguard Worker static int dediprog_spi_bulk_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len)
444*0d6140beSAndroid Build Coastguard Worker {
445*0d6140beSAndroid Build Coastguard Worker 	int err = 1;
446*0d6140beSAndroid Build Coastguard Worker 	const struct dediprog_data *dp_data = flash->mst->spi.data;
447*0d6140beSAndroid Build Coastguard Worker 
448*0d6140beSAndroid Build Coastguard Worker 	/* chunksize must be 512, other sizes will NOT work at all. */
449*0d6140beSAndroid Build Coastguard Worker 	const unsigned int chunksize = 512;
450*0d6140beSAndroid Build Coastguard Worker 	const unsigned int count = len / chunksize;
451*0d6140beSAndroid Build Coastguard Worker 
452*0d6140beSAndroid Build Coastguard Worker 	struct dediprog_transfer_status status = { 0, 0, 0 };
453*0d6140beSAndroid Build Coastguard Worker 	struct libusb_transfer *transfers[DEDIPROG_ASYNC_TRANSFERS] = { NULL, };
454*0d6140beSAndroid Build Coastguard Worker 	struct libusb_transfer *transfer;
455*0d6140beSAndroid Build Coastguard Worker 
456*0d6140beSAndroid Build Coastguard Worker 	if (len == 0)
457*0d6140beSAndroid Build Coastguard Worker 		return 0;
458*0d6140beSAndroid Build Coastguard Worker 
459*0d6140beSAndroid Build Coastguard Worker 	if ((start % chunksize) || (len % chunksize)) {
460*0d6140beSAndroid Build Coastguard Worker 		msg_perr("%s: Unaligned start=%i, len=%i! Please report a bug at [email protected]\n",
461*0d6140beSAndroid Build Coastguard Worker 			 __func__, start, len);
462*0d6140beSAndroid Build Coastguard Worker 		return 1;
463*0d6140beSAndroid Build Coastguard Worker 	}
464*0d6140beSAndroid Build Coastguard Worker 
465*0d6140beSAndroid Build Coastguard Worker 	int command_packet_size;
466*0d6140beSAndroid Build Coastguard Worker 	switch (protocol(dp_data)) {
467*0d6140beSAndroid Build Coastguard Worker 	case PROTOCOL_V1:
468*0d6140beSAndroid Build Coastguard Worker 		command_packet_size = 5;
469*0d6140beSAndroid Build Coastguard Worker 		break;
470*0d6140beSAndroid Build Coastguard Worker 	case PROTOCOL_V2:
471*0d6140beSAndroid Build Coastguard Worker 		command_packet_size = 10;
472*0d6140beSAndroid Build Coastguard Worker 		break;
473*0d6140beSAndroid Build Coastguard Worker 	case PROTOCOL_V3:
474*0d6140beSAndroid Build Coastguard Worker 		command_packet_size = 12;
475*0d6140beSAndroid Build Coastguard Worker 		break;
476*0d6140beSAndroid Build Coastguard Worker 	default:
477*0d6140beSAndroid Build Coastguard Worker 		return 1;
478*0d6140beSAndroid Build Coastguard Worker 	}
479*0d6140beSAndroid Build Coastguard Worker 
480*0d6140beSAndroid Build Coastguard Worker 	uint8_t data_packet[command_packet_size];
481*0d6140beSAndroid Build Coastguard Worker 	unsigned int value, idx;
482*0d6140beSAndroid Build Coastguard Worker 	if (prepare_rw_cmd(flash, data_packet, count, READ_MODE_STD, &value, &idx, start, 1))
483*0d6140beSAndroid Build Coastguard Worker 		return 1;
484*0d6140beSAndroid Build Coastguard Worker 
485*0d6140beSAndroid Build Coastguard Worker 	int ret = dediprog_write(dp_data->handle, CMD_READ, value, idx, data_packet, sizeof(data_packet));
486*0d6140beSAndroid Build Coastguard Worker 	if (ret != (int)sizeof(data_packet)) {
487*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Command Read SPI Bulk failed, %i %s!\n", ret, libusb_error_name(ret));
488*0d6140beSAndroid Build Coastguard Worker 		return 1;
489*0d6140beSAndroid Build Coastguard Worker 	}
490*0d6140beSAndroid Build Coastguard Worker 
491*0d6140beSAndroid Build Coastguard Worker 	/*
492*0d6140beSAndroid Build Coastguard Worker 	 * Ring buffer of bulk transfers.
493*0d6140beSAndroid Build Coastguard Worker 	 * Poll until at least one transfer is ready,
494*0d6140beSAndroid Build Coastguard Worker 	 * schedule next transfers until buffer is full.
495*0d6140beSAndroid Build Coastguard Worker 	 */
496*0d6140beSAndroid Build Coastguard Worker 
497*0d6140beSAndroid Build Coastguard Worker 	/* Allocate bulk transfers. */
498*0d6140beSAndroid Build Coastguard Worker 	unsigned int i;
499*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < MIN(DEDIPROG_ASYNC_TRANSFERS, count); ++i) {
500*0d6140beSAndroid Build Coastguard Worker 		transfers[i] = libusb_alloc_transfer(0);
501*0d6140beSAndroid Build Coastguard Worker 		if (!transfers[i]) {
502*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Allocating libusb transfer %i failed: %s!\n", i, libusb_error_name(ret));
503*0d6140beSAndroid Build Coastguard Worker 			goto err_free;
504*0d6140beSAndroid Build Coastguard Worker 		}
505*0d6140beSAndroid Build Coastguard Worker 	}
506*0d6140beSAndroid Build Coastguard Worker 
507*0d6140beSAndroid Build Coastguard Worker 	/* Now transfer requested chunks using libusb's asynchronous interface. */
508*0d6140beSAndroid Build Coastguard Worker 	while (!status.error && (status.queued_idx < count)) {
509*0d6140beSAndroid Build Coastguard Worker 		while ((status.queued_idx < count) &&
510*0d6140beSAndroid Build Coastguard Worker 		       (status.queued_idx - status.finished_idx) < DEDIPROG_ASYNC_TRANSFERS)
511*0d6140beSAndroid Build Coastguard Worker 		{
512*0d6140beSAndroid Build Coastguard Worker 			transfer = transfers[status.queued_idx % DEDIPROG_ASYNC_TRANSFERS];
513*0d6140beSAndroid Build Coastguard Worker 			libusb_fill_bulk_transfer(transfer, dp_data->handle, 0x80 | dp_data->in_endpoint,
514*0d6140beSAndroid Build Coastguard Worker 					(unsigned char *)buf + status.queued_idx * chunksize, chunksize,
515*0d6140beSAndroid Build Coastguard Worker 					dediprog_bulk_read_cb, &status, DEFAULT_TIMEOUT);
516*0d6140beSAndroid Build Coastguard Worker 			transfer->flags |= LIBUSB_TRANSFER_SHORT_NOT_OK;
517*0d6140beSAndroid Build Coastguard Worker 			ret = libusb_submit_transfer(transfer);
518*0d6140beSAndroid Build Coastguard Worker 			if (ret < 0) {
519*0d6140beSAndroid Build Coastguard Worker 				msg_perr("Submitting SPI bulk read %i failed: %s!\n",
520*0d6140beSAndroid Build Coastguard Worker 					 status.queued_idx, libusb_error_name(ret));
521*0d6140beSAndroid Build Coastguard Worker 				goto err_free;
522*0d6140beSAndroid Build Coastguard Worker 			}
523*0d6140beSAndroid Build Coastguard Worker 			++status.queued_idx;
524*0d6140beSAndroid Build Coastguard Worker 		}
525*0d6140beSAndroid Build Coastguard Worker 		if (dediprog_bulk_read_poll(dp_data->usb_ctx, &status, 0))
526*0d6140beSAndroid Build Coastguard Worker 			goto err_free;
527*0d6140beSAndroid Build Coastguard Worker 	}
528*0d6140beSAndroid Build Coastguard Worker 	/* Wait for transfers to finish. */
529*0d6140beSAndroid Build Coastguard Worker 	if (dediprog_bulk_read_poll(dp_data->usb_ctx, &status, 1))
530*0d6140beSAndroid Build Coastguard Worker 		goto err_free;
531*0d6140beSAndroid Build Coastguard Worker 	/* Check if everything has been transmitted. */
532*0d6140beSAndroid Build Coastguard Worker 	if ((status.finished_idx < count) || status.error)
533*0d6140beSAndroid Build Coastguard Worker 		goto err_free;
534*0d6140beSAndroid Build Coastguard Worker 
535*0d6140beSAndroid Build Coastguard Worker 	err = 0;
536*0d6140beSAndroid Build Coastguard Worker 
537*0d6140beSAndroid Build Coastguard Worker err_free:
538*0d6140beSAndroid Build Coastguard Worker 	dediprog_bulk_read_poll(dp_data->usb_ctx, &status, 1);
539*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < DEDIPROG_ASYNC_TRANSFERS; ++i)
540*0d6140beSAndroid Build Coastguard Worker 		if (transfers[i]) libusb_free_transfer(transfers[i]);
541*0d6140beSAndroid Build Coastguard Worker 	return err;
542*0d6140beSAndroid Build Coastguard Worker }
543*0d6140beSAndroid Build Coastguard Worker 
dediprog_spi_read(struct flashctx * flash,uint8_t * buf,unsigned int start,unsigned int len)544*0d6140beSAndroid Build Coastguard Worker static int dediprog_spi_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len)
545*0d6140beSAndroid Build Coastguard Worker {
546*0d6140beSAndroid Build Coastguard Worker 	int ret;
547*0d6140beSAndroid Build Coastguard Worker 	/* chunksize must be 512, other sizes will NOT work at all. */
548*0d6140beSAndroid Build Coastguard Worker 	const unsigned int chunksize = 0x200;
549*0d6140beSAndroid Build Coastguard Worker 	unsigned int residue = start % chunksize ? min(len, chunksize - start % chunksize) : 0;
550*0d6140beSAndroid Build Coastguard Worker 	unsigned int bulklen;
551*0d6140beSAndroid Build Coastguard Worker 	const struct dediprog_data *dp_data = flash->mst->spi.data;
552*0d6140beSAndroid Build Coastguard Worker 
553*0d6140beSAndroid Build Coastguard Worker 	dediprog_set_leds(LED_BUSY, dp_data);
554*0d6140beSAndroid Build Coastguard Worker 
555*0d6140beSAndroid Build Coastguard Worker 	if (residue) {
556*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Slow read for partial block from 0x%x, length 0x%x\n",
557*0d6140beSAndroid Build Coastguard Worker 			 start, residue);
558*0d6140beSAndroid Build Coastguard Worker 		ret = default_spi_read(flash, buf, start, residue);
559*0d6140beSAndroid Build Coastguard Worker 		if (ret)
560*0d6140beSAndroid Build Coastguard Worker 			goto err;
561*0d6140beSAndroid Build Coastguard Worker 	}
562*0d6140beSAndroid Build Coastguard Worker 
563*0d6140beSAndroid Build Coastguard Worker 	/* Round down. */
564*0d6140beSAndroid Build Coastguard Worker 	bulklen = (len - residue) / chunksize * chunksize;
565*0d6140beSAndroid Build Coastguard Worker 	ret = dediprog_spi_bulk_read(flash, buf + residue, start + residue, bulklen);
566*0d6140beSAndroid Build Coastguard Worker 	if (ret)
567*0d6140beSAndroid Build Coastguard Worker 		goto err;
568*0d6140beSAndroid Build Coastguard Worker 
569*0d6140beSAndroid Build Coastguard Worker 	len -= residue + bulklen;
570*0d6140beSAndroid Build Coastguard Worker 	if (len != 0) {
571*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Slow read for partial block from 0x%x, length 0x%x\n",
572*0d6140beSAndroid Build Coastguard Worker 			 start, len);
573*0d6140beSAndroid Build Coastguard Worker 		ret = default_spi_read(flash, buf + residue + bulklen,
574*0d6140beSAndroid Build Coastguard Worker 				       start + residue + bulklen, len);
575*0d6140beSAndroid Build Coastguard Worker 		if (ret)
576*0d6140beSAndroid Build Coastguard Worker 			goto err;
577*0d6140beSAndroid Build Coastguard Worker 	}
578*0d6140beSAndroid Build Coastguard Worker 
579*0d6140beSAndroid Build Coastguard Worker 	dediprog_set_leds(LED_PASS, dp_data);
580*0d6140beSAndroid Build Coastguard Worker 	return 0;
581*0d6140beSAndroid Build Coastguard Worker err:
582*0d6140beSAndroid Build Coastguard Worker 	dediprog_set_leds(LED_ERROR, dp_data);
583*0d6140beSAndroid Build Coastguard Worker 	return ret;
584*0d6140beSAndroid Build Coastguard Worker }
585*0d6140beSAndroid Build Coastguard Worker 
586*0d6140beSAndroid Build Coastguard Worker /* Bulk write interface, will write multiple chunksize byte chunks aligned to chunksize bytes.
587*0d6140beSAndroid Build Coastguard Worker  * @chunksize       length of data chunks, only 256 supported by now
588*0d6140beSAndroid Build Coastguard Worker  * @start           start address
589*0d6140beSAndroid Build Coastguard Worker  * @len             length
590*0d6140beSAndroid Build Coastguard Worker  * @dedi_spi_cmd    dediprog specific write command for spi bus
591*0d6140beSAndroid Build Coastguard Worker  * @return          0 on success, 1 on failure
592*0d6140beSAndroid Build Coastguard Worker  */
dediprog_spi_bulk_write(struct flashctx * flash,const uint8_t * buf,unsigned int chunksize,unsigned int start,unsigned int len,uint8_t dedi_spi_cmd)593*0d6140beSAndroid Build Coastguard Worker static int dediprog_spi_bulk_write(struct flashctx *flash, const uint8_t *buf, unsigned int chunksize,
594*0d6140beSAndroid Build Coastguard Worker 				   unsigned int start, unsigned int len, uint8_t dedi_spi_cmd)
595*0d6140beSAndroid Build Coastguard Worker {
596*0d6140beSAndroid Build Coastguard Worker 	/* USB transfer size must be 256, other sizes will NOT work at all.
597*0d6140beSAndroid Build Coastguard Worker 	 * chunksize is the real data size per USB bulk transfer. The remaining
598*0d6140beSAndroid Build Coastguard Worker 	 * space in a USB bulk transfer must be filled with 0xff padding.
599*0d6140beSAndroid Build Coastguard Worker 	 */
600*0d6140beSAndroid Build Coastguard Worker 	const unsigned int count = len / chunksize;
601*0d6140beSAndroid Build Coastguard Worker 	const struct dediprog_data *dp_data = flash->mst->spi.data;
602*0d6140beSAndroid Build Coastguard Worker 
603*0d6140beSAndroid Build Coastguard Worker 	/*
604*0d6140beSAndroid Build Coastguard Worker 	 * We should change this check to
605*0d6140beSAndroid Build Coastguard Worker 	 *   chunksize > 512
606*0d6140beSAndroid Build Coastguard Worker 	 * once we know how to handle different chunk sizes.
607*0d6140beSAndroid Build Coastguard Worker 	 */
608*0d6140beSAndroid Build Coastguard Worker 	if (chunksize != 256) {
609*0d6140beSAndroid Build Coastguard Worker 		msg_perr("%s: Chunk sizes other than 256 bytes are unsupported, chunksize=%u!\n"
610*0d6140beSAndroid Build Coastguard Worker 			 "Please report a bug at [email protected]\n", __func__, chunksize);
611*0d6140beSAndroid Build Coastguard Worker 		return 1;
612*0d6140beSAndroid Build Coastguard Worker 	}
613*0d6140beSAndroid Build Coastguard Worker 
614*0d6140beSAndroid Build Coastguard Worker 	if ((start % chunksize) || (len % chunksize)) {
615*0d6140beSAndroid Build Coastguard Worker 		msg_perr("%s: Unaligned start=%i, len=%i! Please report a bug "
616*0d6140beSAndroid Build Coastguard Worker 			 "at [email protected]\n", __func__, start, len);
617*0d6140beSAndroid Build Coastguard Worker 		return 1;
618*0d6140beSAndroid Build Coastguard Worker 	}
619*0d6140beSAndroid Build Coastguard Worker 
620*0d6140beSAndroid Build Coastguard Worker 	/* No idea if the hardware can handle empty writes, so chicken out. */
621*0d6140beSAndroid Build Coastguard Worker 	if (len == 0)
622*0d6140beSAndroid Build Coastguard Worker 		return 0;
623*0d6140beSAndroid Build Coastguard Worker 
624*0d6140beSAndroid Build Coastguard Worker 	int command_packet_size;
625*0d6140beSAndroid Build Coastguard Worker 	switch (protocol(dp_data)) {
626*0d6140beSAndroid Build Coastguard Worker 	case PROTOCOL_V1:
627*0d6140beSAndroid Build Coastguard Worker 		command_packet_size = 5;
628*0d6140beSAndroid Build Coastguard Worker 		break;
629*0d6140beSAndroid Build Coastguard Worker 	case PROTOCOL_V2:
630*0d6140beSAndroid Build Coastguard Worker 		command_packet_size = 10;
631*0d6140beSAndroid Build Coastguard Worker 		break;
632*0d6140beSAndroid Build Coastguard Worker 	case PROTOCOL_V3:
633*0d6140beSAndroid Build Coastguard Worker 		command_packet_size = 14;
634*0d6140beSAndroid Build Coastguard Worker 		break;
635*0d6140beSAndroid Build Coastguard Worker 	default:
636*0d6140beSAndroid Build Coastguard Worker 		return 1;
637*0d6140beSAndroid Build Coastguard Worker 	}
638*0d6140beSAndroid Build Coastguard Worker 
639*0d6140beSAndroid Build Coastguard Worker 	uint8_t data_packet[command_packet_size];
640*0d6140beSAndroid Build Coastguard Worker 	unsigned int value, idx;
641*0d6140beSAndroid Build Coastguard Worker 	if (prepare_rw_cmd(flash, data_packet, count, dedi_spi_cmd, &value, &idx, start, 0))
642*0d6140beSAndroid Build Coastguard Worker 		return 1;
643*0d6140beSAndroid Build Coastguard Worker 	int ret = dediprog_write(dp_data->handle, CMD_WRITE, value, idx, data_packet, sizeof(data_packet));
644*0d6140beSAndroid Build Coastguard Worker 	if (ret != (int)sizeof(data_packet)) {
645*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Command Write SPI Bulk failed, %s!\n", libusb_error_name(ret));
646*0d6140beSAndroid Build Coastguard Worker 		return 1;
647*0d6140beSAndroid Build Coastguard Worker 	}
648*0d6140beSAndroid Build Coastguard Worker 
649*0d6140beSAndroid Build Coastguard Worker 	unsigned int i;
650*0d6140beSAndroid Build Coastguard Worker 	for (i = 0; i < count; i++) {
651*0d6140beSAndroid Build Coastguard Worker 		unsigned char usbbuf[512];
652*0d6140beSAndroid Build Coastguard Worker 		memcpy(usbbuf, buf + i * chunksize, chunksize);
653*0d6140beSAndroid Build Coastguard Worker 		memset(usbbuf + chunksize, 0xff, sizeof(usbbuf) - chunksize); // fill up with 0xFF
654*0d6140beSAndroid Build Coastguard Worker 		int transferred;
655*0d6140beSAndroid Build Coastguard Worker 		ret = libusb_bulk_transfer(dp_data->handle, dp_data->out_endpoint, usbbuf, 512, &transferred,
656*0d6140beSAndroid Build Coastguard Worker 					   DEFAULT_TIMEOUT);
657*0d6140beSAndroid Build Coastguard Worker 		if ((ret < 0) || (transferred != 512)) {
658*0d6140beSAndroid Build Coastguard Worker 			msg_perr("SPI bulk write failed, expected %i, got %s!\n", 512, libusb_error_name(ret));
659*0d6140beSAndroid Build Coastguard Worker 			return 1;
660*0d6140beSAndroid Build Coastguard Worker 		}
661*0d6140beSAndroid Build Coastguard Worker 		update_progress(flash, FLASHROM_PROGRESS_WRITE, i + 1, count);
662*0d6140beSAndroid Build Coastguard Worker 	}
663*0d6140beSAndroid Build Coastguard Worker 
664*0d6140beSAndroid Build Coastguard Worker 	return 0;
665*0d6140beSAndroid Build Coastguard Worker }
666*0d6140beSAndroid Build Coastguard Worker 
dediprog_spi_write(struct flashctx * flash,const uint8_t * buf,unsigned int start,unsigned int len,uint8_t dedi_spi_cmd)667*0d6140beSAndroid Build Coastguard Worker static int dediprog_spi_write(struct flashctx *flash, const uint8_t *buf,
668*0d6140beSAndroid Build Coastguard Worker 			      unsigned int start, unsigned int len, uint8_t dedi_spi_cmd)
669*0d6140beSAndroid Build Coastguard Worker {
670*0d6140beSAndroid Build Coastguard Worker 	int ret;
671*0d6140beSAndroid Build Coastguard Worker 	const unsigned int chunksize = flash->chip->page_size;
672*0d6140beSAndroid Build Coastguard Worker 	unsigned int residue = start % chunksize ? chunksize - start % chunksize : 0;
673*0d6140beSAndroid Build Coastguard Worker 	unsigned int bulklen;
674*0d6140beSAndroid Build Coastguard Worker 	const struct dediprog_data *dp_data = flash->mst->spi.data;
675*0d6140beSAndroid Build Coastguard Worker 
676*0d6140beSAndroid Build Coastguard Worker 	dediprog_set_leds(LED_BUSY, dp_data);
677*0d6140beSAndroid Build Coastguard Worker 
678*0d6140beSAndroid Build Coastguard Worker 	if (chunksize != 256) {
679*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Page sizes other than 256 bytes are unsupported as "
680*0d6140beSAndroid Build Coastguard Worker 			 "we don't know how dediprog\nhandles them.\n");
681*0d6140beSAndroid Build Coastguard Worker 		/* Write everything like it was residue. */
682*0d6140beSAndroid Build Coastguard Worker 		residue = len;
683*0d6140beSAndroid Build Coastguard Worker 	}
684*0d6140beSAndroid Build Coastguard Worker 
685*0d6140beSAndroid Build Coastguard Worker 	if (residue) {
686*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Slow write for partial block from 0x%x, length 0x%x\n",
687*0d6140beSAndroid Build Coastguard Worker 			 start, residue);
688*0d6140beSAndroid Build Coastguard Worker 		/* No idea about the real limit. Maybe 16 including command and address, maybe more. */
689*0d6140beSAndroid Build Coastguard Worker 		ret = spi_write_chunked(flash, buf, start, residue, 11);
690*0d6140beSAndroid Build Coastguard Worker 		if (ret) {
691*0d6140beSAndroid Build Coastguard Worker 			dediprog_set_leds(LED_ERROR, dp_data);
692*0d6140beSAndroid Build Coastguard Worker 			return ret;
693*0d6140beSAndroid Build Coastguard Worker 		}
694*0d6140beSAndroid Build Coastguard Worker 	}
695*0d6140beSAndroid Build Coastguard Worker 
696*0d6140beSAndroid Build Coastguard Worker 	/* Round down. */
697*0d6140beSAndroid Build Coastguard Worker 	bulklen = (len - residue) / chunksize * chunksize;
698*0d6140beSAndroid Build Coastguard Worker 	ret = dediprog_spi_bulk_write(flash, buf + residue, chunksize, start + residue, bulklen, dedi_spi_cmd);
699*0d6140beSAndroid Build Coastguard Worker 	if (ret) {
700*0d6140beSAndroid Build Coastguard Worker 		dediprog_set_leds(LED_ERROR, dp_data);
701*0d6140beSAndroid Build Coastguard Worker 		return ret;
702*0d6140beSAndroid Build Coastguard Worker 	}
703*0d6140beSAndroid Build Coastguard Worker 
704*0d6140beSAndroid Build Coastguard Worker 	len -= residue + bulklen;
705*0d6140beSAndroid Build Coastguard Worker 	if (len) {
706*0d6140beSAndroid Build Coastguard Worker 		msg_pdbg("Slow write for partial block from 0x%x, length 0x%x\n",
707*0d6140beSAndroid Build Coastguard Worker 			 start, len);
708*0d6140beSAndroid Build Coastguard Worker 		ret = spi_write_chunked(flash, buf + residue + bulklen,
709*0d6140beSAndroid Build Coastguard Worker 				        start + residue + bulklen, len, 11);
710*0d6140beSAndroid Build Coastguard Worker 		if (ret) {
711*0d6140beSAndroid Build Coastguard Worker 			dediprog_set_leds(LED_ERROR, dp_data);
712*0d6140beSAndroid Build Coastguard Worker 			return ret;
713*0d6140beSAndroid Build Coastguard Worker 		}
714*0d6140beSAndroid Build Coastguard Worker 	}
715*0d6140beSAndroid Build Coastguard Worker 
716*0d6140beSAndroid Build Coastguard Worker 	dediprog_set_leds(LED_PASS, dp_data);
717*0d6140beSAndroid Build Coastguard Worker 	return 0;
718*0d6140beSAndroid Build Coastguard Worker }
719*0d6140beSAndroid Build Coastguard Worker 
dediprog_spi_write_256(struct flashctx * flash,const uint8_t * buf,unsigned int start,unsigned int len)720*0d6140beSAndroid Build Coastguard Worker static int dediprog_spi_write_256(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
721*0d6140beSAndroid Build Coastguard Worker {
722*0d6140beSAndroid Build Coastguard Worker 	return dediprog_spi_write(flash, buf, start, len, WRITE_MODE_PAGE_PGM);
723*0d6140beSAndroid Build Coastguard Worker }
724*0d6140beSAndroid Build Coastguard Worker 
dediprog_spi_write_aai(struct flashctx * flash,const uint8_t * buf,unsigned int start,unsigned int len)725*0d6140beSAndroid Build Coastguard Worker static int dediprog_spi_write_aai(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len)
726*0d6140beSAndroid Build Coastguard Worker {
727*0d6140beSAndroid Build Coastguard Worker 	return dediprog_spi_write(flash, buf, start, len, WRITE_MODE_2B_AAI);
728*0d6140beSAndroid Build Coastguard Worker }
729*0d6140beSAndroid Build Coastguard Worker 
dediprog_spi_send_command(const struct flashctx * flash,unsigned int writecnt,unsigned int readcnt,const unsigned char * writearr,unsigned char * readarr)730*0d6140beSAndroid Build Coastguard Worker static int dediprog_spi_send_command(const struct flashctx *flash,
731*0d6140beSAndroid Build Coastguard Worker 				     unsigned int writecnt,
732*0d6140beSAndroid Build Coastguard Worker 				     unsigned int readcnt,
733*0d6140beSAndroid Build Coastguard Worker 				     const unsigned char *writearr,
734*0d6140beSAndroid Build Coastguard Worker 				     unsigned char *readarr)
735*0d6140beSAndroid Build Coastguard Worker {
736*0d6140beSAndroid Build Coastguard Worker 	int ret;
737*0d6140beSAndroid Build Coastguard Worker 	const struct dediprog_data *dp_data = flash->mst->spi.data;
738*0d6140beSAndroid Build Coastguard Worker 
739*0d6140beSAndroid Build Coastguard Worker 	msg_pspew("%s, writecnt=%i, readcnt=%i\n", __func__, writecnt, readcnt);
740*0d6140beSAndroid Build Coastguard Worker 	if (writecnt > flash->mst->spi.max_data_write) {
741*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Invalid writecnt=%i, aborting.\n", writecnt);
742*0d6140beSAndroid Build Coastguard Worker 		return 1;
743*0d6140beSAndroid Build Coastguard Worker 	}
744*0d6140beSAndroid Build Coastguard Worker 	if (readcnt > flash->mst->spi.max_data_read) {
745*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Invalid readcnt=%i, aborting.\n", readcnt);
746*0d6140beSAndroid Build Coastguard Worker 		return 1;
747*0d6140beSAndroid Build Coastguard Worker 	}
748*0d6140beSAndroid Build Coastguard Worker 
749*0d6140beSAndroid Build Coastguard Worker 	unsigned int idx, value;
750*0d6140beSAndroid Build Coastguard Worker 	/* New protocol has options and timeout combined as value while the old one used the value field for
751*0d6140beSAndroid Build Coastguard Worker 	 * timeout and the index field for options. */
752*0d6140beSAndroid Build Coastguard Worker 	if (protocol(dp_data) >= PROTOCOL_V2) {
753*0d6140beSAndroid Build Coastguard Worker 		idx = 0;
754*0d6140beSAndroid Build Coastguard Worker 		value = readcnt ? 0x1 : 0x0; // Indicate if we require a read
755*0d6140beSAndroid Build Coastguard Worker 	} else {
756*0d6140beSAndroid Build Coastguard Worker 		idx = readcnt ? 0x1 : 0x0; // Indicate if we require a read
757*0d6140beSAndroid Build Coastguard Worker 		value = 0;
758*0d6140beSAndroid Build Coastguard Worker 	}
759*0d6140beSAndroid Build Coastguard Worker 	ret = dediprog_write(dp_data->handle, CMD_TRANSCEIVE, value, idx, writearr, writecnt);
760*0d6140beSAndroid Build Coastguard Worker 	if (ret != (int)writecnt) {
761*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Send SPI failed, expected %i, got %i %s!\n",
762*0d6140beSAndroid Build Coastguard Worker 			 writecnt, ret, libusb_error_name(ret));
763*0d6140beSAndroid Build Coastguard Worker 		return 1;
764*0d6140beSAndroid Build Coastguard Worker 	}
765*0d6140beSAndroid Build Coastguard Worker 	if (readcnt == 0) // If we don't require a response, we are done here
766*0d6140beSAndroid Build Coastguard Worker 		return 0;
767*0d6140beSAndroid Build Coastguard Worker 
768*0d6140beSAndroid Build Coastguard Worker 	/* The specifications do state the possibility to set a timeout for transceive transactions.
769*0d6140beSAndroid Build Coastguard Worker 	 * Apparently the "timeout" is a delay, and you can use long delays to accelerate writing - in case you
770*0d6140beSAndroid Build Coastguard Worker 	 * can predict the time needed by the previous command or so (untested). In any case, using this
771*0d6140beSAndroid Build Coastguard Worker 	 * "feature" to set sane-looking timouts for the read below will completely trash performance with
772*0d6140beSAndroid Build Coastguard Worker 	 * SF600 and/or firmwares >= 6.0 while they seem to be benign on SF100 with firmwares <= 5.5.2. *shrug*
773*0d6140beSAndroid Build Coastguard Worker 	 *
774*0d6140beSAndroid Build Coastguard Worker 	 * The specification also uses only 0 in its examples, so the lesson to learn here:
775*0d6140beSAndroid Build Coastguard Worker 	 * "Never trust the description of an interface in the documentation but use the example code and pray."
776*0d6140beSAndroid Build Coastguard Worker 	const uint8_t read_timeout = 10 + readcnt/512;
777*0d6140beSAndroid Build Coastguard Worker 	if (protocol() >= PROTOCOL_V2) {
778*0d6140beSAndroid Build Coastguard Worker 		idx = 0;
779*0d6140beSAndroid Build Coastguard Worker 		value = min(read_timeout, 0xFF) | (0 << 8) ; // Timeout in lower byte, option in upper byte
780*0d6140beSAndroid Build Coastguard Worker 	} else {
781*0d6140beSAndroid Build Coastguard Worker 		idx = (0 & 0xFF);  // Lower byte is option (0x01 = require SR, 0x02 keep CS low)
782*0d6140beSAndroid Build Coastguard Worker 		value = min(read_timeout, 0xFF); // Possibly two bytes but we play safe here
783*0d6140beSAndroid Build Coastguard Worker 	}
784*0d6140beSAndroid Build Coastguard Worker 	ret = dediprog_read(dp_data->dediprog_handle, CMD_TRANSCEIVE, value, idx, readarr, readcnt);
785*0d6140beSAndroid Build Coastguard Worker 	*/
786*0d6140beSAndroid Build Coastguard Worker 	ret = dediprog_read(dp_data->handle, CMD_TRANSCEIVE, 0, 0, readarr, readcnt);
787*0d6140beSAndroid Build Coastguard Worker 	if (ret != (int)readcnt) {
788*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Receive SPI failed, expected %i, got %i %s!\n", readcnt, ret, libusb_error_name(ret));
789*0d6140beSAndroid Build Coastguard Worker 		return 1;
790*0d6140beSAndroid Build Coastguard Worker 	}
791*0d6140beSAndroid Build Coastguard Worker 	return 0;
792*0d6140beSAndroid Build Coastguard Worker }
793*0d6140beSAndroid Build Coastguard Worker 
dediprog_check_devicestring(struct dediprog_data * dp_data)794*0d6140beSAndroid Build Coastguard Worker static int dediprog_check_devicestring(struct dediprog_data *dp_data)
795*0d6140beSAndroid Build Coastguard Worker {
796*0d6140beSAndroid Build Coastguard Worker 	int ret;
797*0d6140beSAndroid Build Coastguard Worker 	char buf[0x11];
798*0d6140beSAndroid Build Coastguard Worker 
799*0d6140beSAndroid Build Coastguard Worker 	/* Command Receive Device String. */
800*0d6140beSAndroid Build Coastguard Worker 	ret = dediprog_read(dp_data->handle, CMD_READ_PROG_INFO, 0, 0, (uint8_t *)buf, 0x10);
801*0d6140beSAndroid Build Coastguard Worker 	if (ret != 0x10) {
802*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Incomplete/failed Command Receive Device String!\n");
803*0d6140beSAndroid Build Coastguard Worker 		return 1;
804*0d6140beSAndroid Build Coastguard Worker 	}
805*0d6140beSAndroid Build Coastguard Worker 	buf[0x10] = '\0';
806*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg("Found a %s\n", buf);
807*0d6140beSAndroid Build Coastguard Worker 	if (memcmp(buf, "SF100", 0x5) == 0)
808*0d6140beSAndroid Build Coastguard Worker 		dp_data->devicetype = DEV_SF100;
809*0d6140beSAndroid Build Coastguard Worker 	else if (memcmp(buf, "SF200", 0x5) == 0)
810*0d6140beSAndroid Build Coastguard Worker 		dp_data->devicetype = DEV_SF200;
811*0d6140beSAndroid Build Coastguard Worker 	else if (memcmp(buf, "SF600", 0x5) == 0)
812*0d6140beSAndroid Build Coastguard Worker 		dp_data->devicetype = DEV_SF600;
813*0d6140beSAndroid Build Coastguard Worker 	else {
814*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Device not a SF100, SF200, or SF600!\n");
815*0d6140beSAndroid Build Coastguard Worker 		return 1;
816*0d6140beSAndroid Build Coastguard Worker 	}
817*0d6140beSAndroid Build Coastguard Worker 
818*0d6140beSAndroid Build Coastguard Worker 	int sfnum;
819*0d6140beSAndroid Build Coastguard Worker 	int fw[3];
820*0d6140beSAndroid Build Coastguard Worker 	if (sscanf(buf, "SF%d V:%d.%d.%d ", &sfnum, &fw[0], &fw[1], &fw[2]) != 4 ||
821*0d6140beSAndroid Build Coastguard Worker 	    sfnum != (int)dp_data->devicetype) {
822*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Unexpected firmware version string '%s'\n", buf);
823*0d6140beSAndroid Build Coastguard Worker 		return 1;
824*0d6140beSAndroid Build Coastguard Worker 	}
825*0d6140beSAndroid Build Coastguard Worker 	/* Only these major versions were tested. */
826*0d6140beSAndroid Build Coastguard Worker 	if (fw[0] < 2 || fw[0] > 7) {
827*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Unexpected firmware version %d.%d.%d!\n", fw[0], fw[1], fw[2]);
828*0d6140beSAndroid Build Coastguard Worker 		return 1;
829*0d6140beSAndroid Build Coastguard Worker 	}
830*0d6140beSAndroid Build Coastguard Worker 
831*0d6140beSAndroid Build Coastguard Worker 	dp_data->firmwareversion = FIRMWARE_VERSION(fw[0], fw[1], fw[2]);
832*0d6140beSAndroid Build Coastguard Worker 	if (protocol(dp_data) == PROTOCOL_UNKNOWN) {
833*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Internal error: Unable to determine protocol version.\n");
834*0d6140beSAndroid Build Coastguard Worker 		return 1;
835*0d6140beSAndroid Build Coastguard Worker 	}
836*0d6140beSAndroid Build Coastguard Worker 
837*0d6140beSAndroid Build Coastguard Worker 	return 0;
838*0d6140beSAndroid Build Coastguard Worker }
839*0d6140beSAndroid Build Coastguard Worker 
840*0d6140beSAndroid Build Coastguard Worker /*
841*0d6140beSAndroid Build Coastguard Worker  * Read the id from the dediprog. This should return the numeric part of the
842*0d6140beSAndroid Build Coastguard Worker  * serial number found on a sticker on the back of the dediprog. Note this
843*0d6140beSAndroid Build Coastguard Worker  * number is stored in writable eeprom, so it could get out of sync. Also note,
844*0d6140beSAndroid Build Coastguard Worker  * this function only supports SF100 at this time, but SF600 support is not too
845*0d6140beSAndroid Build Coastguard Worker  * much different.
846*0d6140beSAndroid Build Coastguard Worker  * @return  the id on success, -1 on failure
847*0d6140beSAndroid Build Coastguard Worker  */
dediprog_read_id(libusb_device_handle * dediprog_handle)848*0d6140beSAndroid Build Coastguard Worker static int dediprog_read_id(libusb_device_handle *dediprog_handle)
849*0d6140beSAndroid Build Coastguard Worker {
850*0d6140beSAndroid Build Coastguard Worker 	int ret;
851*0d6140beSAndroid Build Coastguard Worker 	uint8_t buf[3];
852*0d6140beSAndroid Build Coastguard Worker 
853*0d6140beSAndroid Build Coastguard Worker 	ret = libusb_control_transfer(dediprog_handle, REQTYPE_OTHER_IN,
854*0d6140beSAndroid Build Coastguard Worker 				      0x7,    /* request */
855*0d6140beSAndroid Build Coastguard Worker 				      0,      /* value */
856*0d6140beSAndroid Build Coastguard Worker 				      0xEF00, /* index */
857*0d6140beSAndroid Build Coastguard Worker 				      buf, sizeof(buf),
858*0d6140beSAndroid Build Coastguard Worker 				      DEFAULT_TIMEOUT);
859*0d6140beSAndroid Build Coastguard Worker 	if (ret != sizeof(buf)) {
860*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Failed to read dediprog id, error %d!\n", ret);
861*0d6140beSAndroid Build Coastguard Worker 		return -1;
862*0d6140beSAndroid Build Coastguard Worker 	}
863*0d6140beSAndroid Build Coastguard Worker 
864*0d6140beSAndroid Build Coastguard Worker 	return buf[0] << 16 | buf[1] << 8 | buf[2];
865*0d6140beSAndroid Build Coastguard Worker }
866*0d6140beSAndroid Build Coastguard Worker 
867*0d6140beSAndroid Build Coastguard Worker /*
868*0d6140beSAndroid Build Coastguard Worker  * This command presumably sets the voltage for the SF100 itself (not the
869*0d6140beSAndroid Build Coastguard Worker  * SPI flash). Only use this command with firmware older than V6.0.0. Newer
870*0d6140beSAndroid Build Coastguard Worker  * (including all SF600s) do not support it.
871*0d6140beSAndroid Build Coastguard Worker  */
872*0d6140beSAndroid Build Coastguard Worker 
873*0d6140beSAndroid Build Coastguard Worker /* This command presumably sets the voltage for the SF100 itself (not the SPI flash).
874*0d6140beSAndroid Build Coastguard Worker  * Only use dediprog_set_voltage on SF100 programmers with firmware older
875*0d6140beSAndroid Build Coastguard Worker  * than V6.0.0. Newer programmers (including all SF600s) do not support it. */
dediprog_set_voltage(libusb_device_handle * dediprog_handle)876*0d6140beSAndroid Build Coastguard Worker static int dediprog_set_voltage(libusb_device_handle *dediprog_handle)
877*0d6140beSAndroid Build Coastguard Worker {
878*0d6140beSAndroid Build Coastguard Worker 	unsigned char buf[1] = {0};
879*0d6140beSAndroid Build Coastguard Worker 	int ret = libusb_control_transfer(dediprog_handle, REQTYPE_OTHER_IN, CMD_SET_VOLTAGE, 0x0, 0x0,
880*0d6140beSAndroid Build Coastguard Worker 			      buf, 0x1, DEFAULT_TIMEOUT);
881*0d6140beSAndroid Build Coastguard Worker 	if (ret < 0) {
882*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Command Set Voltage failed (%s)!\n", libusb_error_name(ret));
883*0d6140beSAndroid Build Coastguard Worker 		return 1;
884*0d6140beSAndroid Build Coastguard Worker 	}
885*0d6140beSAndroid Build Coastguard Worker 	if ((ret != 1) || (buf[0] != 0x6f)) {
886*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Unexpected response to init!\n");
887*0d6140beSAndroid Build Coastguard Worker 		return 1;
888*0d6140beSAndroid Build Coastguard Worker 	}
889*0d6140beSAndroid Build Coastguard Worker 
890*0d6140beSAndroid Build Coastguard Worker 	return 0;
891*0d6140beSAndroid Build Coastguard Worker }
892*0d6140beSAndroid Build Coastguard Worker 
dediprog_standalone_mode(const struct dediprog_data * dp_data)893*0d6140beSAndroid Build Coastguard Worker static int dediprog_standalone_mode(const struct dediprog_data *dp_data)
894*0d6140beSAndroid Build Coastguard Worker {
895*0d6140beSAndroid Build Coastguard Worker 	int ret;
896*0d6140beSAndroid Build Coastguard Worker 
897*0d6140beSAndroid Build Coastguard Worker 	if (dp_data->devicetype != DEV_SF600)
898*0d6140beSAndroid Build Coastguard Worker 		return 0;
899*0d6140beSAndroid Build Coastguard Worker 
900*0d6140beSAndroid Build Coastguard Worker 	msg_pdbg2("Disabling standalone mode.\n");
901*0d6140beSAndroid Build Coastguard Worker 	ret = dediprog_write(dp_data->handle, CMD_SET_STANDALONE, LEAVE_STANDALONE_MODE, 0, NULL, 0);
902*0d6140beSAndroid Build Coastguard Worker 	if (ret) {
903*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Failed to disable standalone mode: %s\n", libusb_error_name(ret));
904*0d6140beSAndroid Build Coastguard Worker 		return 1;
905*0d6140beSAndroid Build Coastguard Worker 	}
906*0d6140beSAndroid Build Coastguard Worker 
907*0d6140beSAndroid Build Coastguard Worker 	return 0;
908*0d6140beSAndroid Build Coastguard Worker }
909*0d6140beSAndroid Build Coastguard Worker 
910*0d6140beSAndroid Build Coastguard Worker #if 0
911*0d6140beSAndroid Build Coastguard Worker /* Something.
912*0d6140beSAndroid Build Coastguard Worker  * Present in eng_detect_blink.log with firmware 3.1.8
913*0d6140beSAndroid Build Coastguard Worker  * Always preceded by Command Receive Device String
914*0d6140beSAndroid Build Coastguard Worker  */
915*0d6140beSAndroid Build Coastguard Worker static int dediprog_command_b(libusb_device_handle *dediprog_handle)
916*0d6140beSAndroid Build Coastguard Worker {
917*0d6140beSAndroid Build Coastguard Worker 	int ret;
918*0d6140beSAndroid Build Coastguard Worker 	char buf[0x3];
919*0d6140beSAndroid Build Coastguard Worker 
920*0d6140beSAndroid Build Coastguard Worker 	ret = usb_control_msg(dediprog_handle, REQTYPE_OTHER_IN, 0x7, 0x0, 0xef00,
921*0d6140beSAndroid Build Coastguard Worker 			      buf, 0x3, DEFAULT_TIMEOUT);
922*0d6140beSAndroid Build Coastguard Worker 	if (ret < 0) {
923*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Command B failed (%s)!\n", libusb_error_name(ret));
924*0d6140beSAndroid Build Coastguard Worker 		return 1;
925*0d6140beSAndroid Build Coastguard Worker 	}
926*0d6140beSAndroid Build Coastguard Worker 	if ((ret != 0x3) || (buf[0] != 0xff) || (buf[1] != 0xff) ||
927*0d6140beSAndroid Build Coastguard Worker 	    (buf[2] != 0xff)) {
928*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Unexpected response to Command B!\n");
929*0d6140beSAndroid Build Coastguard Worker 		return 1;
930*0d6140beSAndroid Build Coastguard Worker 	}
931*0d6140beSAndroid Build Coastguard Worker 
932*0d6140beSAndroid Build Coastguard Worker 	return 0;
933*0d6140beSAndroid Build Coastguard Worker }
934*0d6140beSAndroid Build Coastguard Worker #endif
935*0d6140beSAndroid Build Coastguard Worker 
set_target_flash(libusb_device_handle * dediprog_handle,enum dediprog_target target)936*0d6140beSAndroid Build Coastguard Worker static int set_target_flash(libusb_device_handle *dediprog_handle, enum dediprog_target target)
937*0d6140beSAndroid Build Coastguard Worker {
938*0d6140beSAndroid Build Coastguard Worker 	int ret = dediprog_write(dediprog_handle, CMD_SET_TARGET, target, 0, NULL, 0);
939*0d6140beSAndroid Build Coastguard Worker 	if (ret != 0) {
940*0d6140beSAndroid Build Coastguard Worker 		msg_perr("set_target_flash failed (%s)!\n", libusb_error_name(ret));
941*0d6140beSAndroid Build Coastguard Worker 		return 1;
942*0d6140beSAndroid Build Coastguard Worker 	}
943*0d6140beSAndroid Build Coastguard Worker 	return 0;
944*0d6140beSAndroid Build Coastguard Worker }
945*0d6140beSAndroid Build Coastguard Worker 
946*0d6140beSAndroid Build Coastguard Worker #if 0
947*0d6140beSAndroid Build Coastguard Worker /* Returns true if the button is currently pressed. */
948*0d6140beSAndroid Build Coastguard Worker static bool dediprog_get_button(libusb_device_handle *dediprog_handle)
949*0d6140beSAndroid Build Coastguard Worker {
950*0d6140beSAndroid Build Coastguard Worker 	char buf[1];
951*0d6140beSAndroid Build Coastguard Worker 	int ret = usb_control_msg(dediprog_handle, REQTYPE_EP_IN, CMD_GET_BUTTON, 0, 0,
952*0d6140beSAndroid Build Coastguard Worker 			      buf, 0x1, DEFAULT_TIMEOUT);
953*0d6140beSAndroid Build Coastguard Worker 	if (ret != 0) {
954*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Could not get button state (%s)!\n", libusb_error_name(ret));
955*0d6140beSAndroid Build Coastguard Worker 		return 1;
956*0d6140beSAndroid Build Coastguard Worker 	}
957*0d6140beSAndroid Build Coastguard Worker 	return buf[0] != 1;
958*0d6140beSAndroid Build Coastguard Worker }
959*0d6140beSAndroid Build Coastguard Worker #endif
960*0d6140beSAndroid Build Coastguard Worker 
parse_voltage(char * voltage)961*0d6140beSAndroid Build Coastguard Worker static int parse_voltage(char *voltage)
962*0d6140beSAndroid Build Coastguard Worker {
963*0d6140beSAndroid Build Coastguard Worker 	char *tmp = NULL;
964*0d6140beSAndroid Build Coastguard Worker 	int i;
965*0d6140beSAndroid Build Coastguard Worker 	int millivolt = 0, fraction = 0;
966*0d6140beSAndroid Build Coastguard Worker 
967*0d6140beSAndroid Build Coastguard Worker 	if (!voltage || !strlen(voltage)) {
968*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Empty voltage= specified.\n");
969*0d6140beSAndroid Build Coastguard Worker 		return -1;
970*0d6140beSAndroid Build Coastguard Worker 	}
971*0d6140beSAndroid Build Coastguard Worker 	millivolt = (int)strtol(voltage, &tmp, 0);
972*0d6140beSAndroid Build Coastguard Worker 	voltage = tmp;
973*0d6140beSAndroid Build Coastguard Worker 	/* Handle "," and "." as decimal point. Everything after it is assumed
974*0d6140beSAndroid Build Coastguard Worker 	 * to be in decimal notation.
975*0d6140beSAndroid Build Coastguard Worker 	 */
976*0d6140beSAndroid Build Coastguard Worker 	if ((*voltage == '.') || (*voltage == ',')) {
977*0d6140beSAndroid Build Coastguard Worker 		voltage++;
978*0d6140beSAndroid Build Coastguard Worker 		for (i = 0; i < 3; i++) {
979*0d6140beSAndroid Build Coastguard Worker 			fraction *= 10;
980*0d6140beSAndroid Build Coastguard Worker 			/* Don't advance if the current character is invalid,
981*0d6140beSAndroid Build Coastguard Worker 			 * but continue multiplying.
982*0d6140beSAndroid Build Coastguard Worker 			 */
983*0d6140beSAndroid Build Coastguard Worker 			if ((*voltage < '0') || (*voltage > '9'))
984*0d6140beSAndroid Build Coastguard Worker 				continue;
985*0d6140beSAndroid Build Coastguard Worker 			fraction += *voltage - '0';
986*0d6140beSAndroid Build Coastguard Worker 			voltage++;
987*0d6140beSAndroid Build Coastguard Worker 		}
988*0d6140beSAndroid Build Coastguard Worker 		/* Throw away remaining digits. */
989*0d6140beSAndroid Build Coastguard Worker 		voltage += strspn(voltage, "0123456789");
990*0d6140beSAndroid Build Coastguard Worker 	}
991*0d6140beSAndroid Build Coastguard Worker 	/* The remaining string must be empty or "mV" or "V". */
992*0d6140beSAndroid Build Coastguard Worker 	tolower_string(voltage);
993*0d6140beSAndroid Build Coastguard Worker 
994*0d6140beSAndroid Build Coastguard Worker 	/* No unit or "V". */
995*0d6140beSAndroid Build Coastguard Worker 	if ((*voltage == '\0') || !strncmp(voltage, "v", 1)) {
996*0d6140beSAndroid Build Coastguard Worker 		millivolt *= 1000;
997*0d6140beSAndroid Build Coastguard Worker 		millivolt += fraction;
998*0d6140beSAndroid Build Coastguard Worker 	} else if (!strncmp(voltage, "mv", 2) ||
999*0d6140beSAndroid Build Coastguard Worker 		   !strncmp(voltage, "milliv", 6)) {
1000*0d6140beSAndroid Build Coastguard Worker 		/* No adjustment. fraction is discarded. */
1001*0d6140beSAndroid Build Coastguard Worker 	} else {
1002*0d6140beSAndroid Build Coastguard Worker 		/* Garbage at the end of the string. */
1003*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Garbage voltage= specified.\n");
1004*0d6140beSAndroid Build Coastguard Worker 		return -1;
1005*0d6140beSAndroid Build Coastguard Worker 	}
1006*0d6140beSAndroid Build Coastguard Worker 	return millivolt;
1007*0d6140beSAndroid Build Coastguard Worker }
1008*0d6140beSAndroid Build Coastguard Worker 
dediprog_shutdown(void * data)1009*0d6140beSAndroid Build Coastguard Worker static int dediprog_shutdown(void *data)
1010*0d6140beSAndroid Build Coastguard Worker {
1011*0d6140beSAndroid Build Coastguard Worker 	int ret = 0;
1012*0d6140beSAndroid Build Coastguard Worker 	struct dediprog_data *dp_data = data;
1013*0d6140beSAndroid Build Coastguard Worker 
1014*0d6140beSAndroid Build Coastguard Worker 	/* URB 28. Command Set SPI Voltage to 0. */
1015*0d6140beSAndroid Build Coastguard Worker 	if (dediprog_set_spi_voltage(dp_data->handle, 0x0)) {
1016*0d6140beSAndroid Build Coastguard Worker 		ret = 1;
1017*0d6140beSAndroid Build Coastguard Worker 		goto out;
1018*0d6140beSAndroid Build Coastguard Worker 	}
1019*0d6140beSAndroid Build Coastguard Worker 
1020*0d6140beSAndroid Build Coastguard Worker 	if (libusb_release_interface(dp_data->handle, 0)) {
1021*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Could not release USB interface!\n");
1022*0d6140beSAndroid Build Coastguard Worker 		ret = 1;
1023*0d6140beSAndroid Build Coastguard Worker 		goto out;
1024*0d6140beSAndroid Build Coastguard Worker 	}
1025*0d6140beSAndroid Build Coastguard Worker 	libusb_close(dp_data->handle);
1026*0d6140beSAndroid Build Coastguard Worker 	libusb_exit(dp_data->usb_ctx);
1027*0d6140beSAndroid Build Coastguard Worker out:
1028*0d6140beSAndroid Build Coastguard Worker 	free(data);
1029*0d6140beSAndroid Build Coastguard Worker 	return ret;
1030*0d6140beSAndroid Build Coastguard Worker }
1031*0d6140beSAndroid Build Coastguard Worker 
1032*0d6140beSAndroid Build Coastguard Worker static struct spi_master spi_master_dediprog = {
1033*0d6140beSAndroid Build Coastguard Worker 	.features	= SPI_MASTER_NO_4BA_MODES,
1034*0d6140beSAndroid Build Coastguard Worker 	.max_data_read	= 16, /* 18 seems to work fine as well, but 19 times out sometimes with FW 5.15. */
1035*0d6140beSAndroid Build Coastguard Worker 	.max_data_write	= 16,
1036*0d6140beSAndroid Build Coastguard Worker 	.command	= dediprog_spi_send_command,
1037*0d6140beSAndroid Build Coastguard Worker 	.read		= dediprog_spi_read,
1038*0d6140beSAndroid Build Coastguard Worker 	.write_256	= dediprog_spi_write_256,
1039*0d6140beSAndroid Build Coastguard Worker 	.write_aai	= dediprog_spi_write_aai,
1040*0d6140beSAndroid Build Coastguard Worker 	.shutdown	= dediprog_shutdown,
1041*0d6140beSAndroid Build Coastguard Worker };
1042*0d6140beSAndroid Build Coastguard Worker 
1043*0d6140beSAndroid Build Coastguard Worker /*
1044*0d6140beSAndroid Build Coastguard Worker  * Open a dediprog_handle with the USB device at the given index.
1045*0d6140beSAndroid Build Coastguard Worker  * @index   index of the USB device
1046*0d6140beSAndroid Build Coastguard Worker  * @return  0 for success, -1 for error, -2 for busy device
1047*0d6140beSAndroid Build Coastguard Worker  */
dediprog_open(int index,struct dediprog_data * dp_data)1048*0d6140beSAndroid Build Coastguard Worker static int dediprog_open(int index, struct dediprog_data *dp_data)
1049*0d6140beSAndroid Build Coastguard Worker {
1050*0d6140beSAndroid Build Coastguard Worker 	const uint16_t vid = devs_dediprog[0].vendor_id;
1051*0d6140beSAndroid Build Coastguard Worker 	const uint16_t pid = devs_dediprog[0].device_id;
1052*0d6140beSAndroid Build Coastguard Worker 	int ret;
1053*0d6140beSAndroid Build Coastguard Worker 
1054*0d6140beSAndroid Build Coastguard Worker 	dp_data->handle = usb_dev_get_by_vid_pid_number(dp_data->usb_ctx, vid, pid, (unsigned int) index);
1055*0d6140beSAndroid Build Coastguard Worker 	if (!dp_data->handle) {
1056*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Could not find a Dediprog programmer on USB.\n");
1057*0d6140beSAndroid Build Coastguard Worker 		libusb_exit(dp_data->usb_ctx);
1058*0d6140beSAndroid Build Coastguard Worker 		return -1;
1059*0d6140beSAndroid Build Coastguard Worker 	}
1060*0d6140beSAndroid Build Coastguard Worker 	ret = libusb_set_configuration(dp_data->handle, 1);
1061*0d6140beSAndroid Build Coastguard Worker 	if (ret != 0) {
1062*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Could not set USB device configuration: %i %s\n",
1063*0d6140beSAndroid Build Coastguard Worker 			 ret, libusb_error_name(ret));
1064*0d6140beSAndroid Build Coastguard Worker 		libusb_close(dp_data->handle);
1065*0d6140beSAndroid Build Coastguard Worker 		return -2;
1066*0d6140beSAndroid Build Coastguard Worker 	}
1067*0d6140beSAndroid Build Coastguard Worker 	ret = libusb_claim_interface(dp_data->handle, 0);
1068*0d6140beSAndroid Build Coastguard Worker 	if (ret < 0) {
1069*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Could not claim USB device interface %i: %i %s\n",
1070*0d6140beSAndroid Build Coastguard Worker 			 0, ret, libusb_error_name(ret));
1071*0d6140beSAndroid Build Coastguard Worker 		libusb_close(dp_data->handle);
1072*0d6140beSAndroid Build Coastguard Worker 		return -2;
1073*0d6140beSAndroid Build Coastguard Worker 	}
1074*0d6140beSAndroid Build Coastguard Worker 	return 0;
1075*0d6140beSAndroid Build Coastguard Worker }
1076*0d6140beSAndroid Build Coastguard Worker 
dediprog_init(const struct programmer_cfg * cfg)1077*0d6140beSAndroid Build Coastguard Worker static int dediprog_init(const struct programmer_cfg *cfg)
1078*0d6140beSAndroid Build Coastguard Worker {
1079*0d6140beSAndroid Build Coastguard Worker 	char *param_str;
1080*0d6140beSAndroid Build Coastguard Worker 	int spispeed_idx = 1;
1081*0d6140beSAndroid Build Coastguard Worker 	int millivolt = 3500;
1082*0d6140beSAndroid Build Coastguard Worker 	int id = -1; /* -1 defaults to enumeration order */
1083*0d6140beSAndroid Build Coastguard Worker 	int found_id;
1084*0d6140beSAndroid Build Coastguard Worker 	long usedevice = 0;
1085*0d6140beSAndroid Build Coastguard Worker 	long target = FLASH_TYPE_APPLICATION_FLASH_1;
1086*0d6140beSAndroid Build Coastguard Worker 	int i, ret;
1087*0d6140beSAndroid Build Coastguard Worker 
1088*0d6140beSAndroid Build Coastguard Worker 	param_str = extract_programmer_param_str(cfg, "spispeed");
1089*0d6140beSAndroid Build Coastguard Worker 	if (param_str) {
1090*0d6140beSAndroid Build Coastguard Worker 		for (i = 0; spispeeds[i].name; ++i) {
1091*0d6140beSAndroid Build Coastguard Worker 			if (!strcasecmp(spispeeds[i].name, param_str)) {
1092*0d6140beSAndroid Build Coastguard Worker 				spispeed_idx = i;
1093*0d6140beSAndroid Build Coastguard Worker 				break;
1094*0d6140beSAndroid Build Coastguard Worker 			}
1095*0d6140beSAndroid Build Coastguard Worker 		}
1096*0d6140beSAndroid Build Coastguard Worker 		if (!spispeeds[i].name) {
1097*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: Invalid spispeed value: '%s'.\n", param_str);
1098*0d6140beSAndroid Build Coastguard Worker 			free(param_str);
1099*0d6140beSAndroid Build Coastguard Worker 			return 1;
1100*0d6140beSAndroid Build Coastguard Worker 		}
1101*0d6140beSAndroid Build Coastguard Worker 		free(param_str);
1102*0d6140beSAndroid Build Coastguard Worker 	}
1103*0d6140beSAndroid Build Coastguard Worker 
1104*0d6140beSAndroid Build Coastguard Worker 	param_str = extract_programmer_param_str(cfg, "voltage");
1105*0d6140beSAndroid Build Coastguard Worker 	if (param_str) {
1106*0d6140beSAndroid Build Coastguard Worker 		millivolt = parse_voltage(param_str);
1107*0d6140beSAndroid Build Coastguard Worker 		free(param_str);
1108*0d6140beSAndroid Build Coastguard Worker 		if (millivolt < 0)
1109*0d6140beSAndroid Build Coastguard Worker 			return 1;
1110*0d6140beSAndroid Build Coastguard Worker 		msg_pinfo("Setting voltage to %i mV\n", millivolt);
1111*0d6140beSAndroid Build Coastguard Worker 	}
1112*0d6140beSAndroid Build Coastguard Worker 
1113*0d6140beSAndroid Build Coastguard Worker 	param_str = extract_programmer_param_str(cfg, "id");
1114*0d6140beSAndroid Build Coastguard Worker 	if (param_str) {
1115*0d6140beSAndroid Build Coastguard Worker 		char prefix0, prefix1;
1116*0d6140beSAndroid Build Coastguard Worker 		if (sscanf(param_str, "%c%c%d", &prefix0, &prefix1, &id) != 3) {
1117*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: Could not parse dediprog 'id'.\n");
1118*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Expected a string like SF012345 or DP012345.\n");
1119*0d6140beSAndroid Build Coastguard Worker 			free(param_str);
1120*0d6140beSAndroid Build Coastguard Worker 			return 1;
1121*0d6140beSAndroid Build Coastguard Worker 		}
1122*0d6140beSAndroid Build Coastguard Worker 		if (id < 0 || id >= 0x1000000) {
1123*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: id %s is out of range!\n", param_str);
1124*0d6140beSAndroid Build Coastguard Worker 			free(param_str);
1125*0d6140beSAndroid Build Coastguard Worker 			return 1;
1126*0d6140beSAndroid Build Coastguard Worker 		}
1127*0d6140beSAndroid Build Coastguard Worker 		if (!(prefix0 == 'S' && prefix1 == 'F') && !(prefix0 == 'D' && prefix1 == 'P')) {
1128*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: %s is an invalid id!\n", param_str);
1129*0d6140beSAndroid Build Coastguard Worker 			free(param_str);
1130*0d6140beSAndroid Build Coastguard Worker 			return 1;
1131*0d6140beSAndroid Build Coastguard Worker 		}
1132*0d6140beSAndroid Build Coastguard Worker 		msg_pinfo("Will search for dediprog id %s.\n", param_str);
1133*0d6140beSAndroid Build Coastguard Worker 	}
1134*0d6140beSAndroid Build Coastguard Worker 	free(param_str);
1135*0d6140beSAndroid Build Coastguard Worker 
1136*0d6140beSAndroid Build Coastguard Worker 	param_str = extract_programmer_param_str(cfg, "device");
1137*0d6140beSAndroid Build Coastguard Worker 	if (param_str) {
1138*0d6140beSAndroid Build Coastguard Worker 		char *dev_suffix;
1139*0d6140beSAndroid Build Coastguard Worker 		if (id != -1) {
1140*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: Cannot use 'id' and 'device'.\n");
1141*0d6140beSAndroid Build Coastguard Worker 		}
1142*0d6140beSAndroid Build Coastguard Worker 		errno = 0;
1143*0d6140beSAndroid Build Coastguard Worker 		usedevice = strtol(param_str, &dev_suffix, 10);
1144*0d6140beSAndroid Build Coastguard Worker 		if (errno != 0 || param_str == dev_suffix) {
1145*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: Could not convert 'device'.\n");
1146*0d6140beSAndroid Build Coastguard Worker 			free(param_str);
1147*0d6140beSAndroid Build Coastguard Worker 			return 1;
1148*0d6140beSAndroid Build Coastguard Worker 		}
1149*0d6140beSAndroid Build Coastguard Worker 		if (usedevice < 0 || usedevice > INT_MAX) {
1150*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: Value for 'device' is out of range.\n");
1151*0d6140beSAndroid Build Coastguard Worker 			free(param_str);
1152*0d6140beSAndroid Build Coastguard Worker 			return 1;
1153*0d6140beSAndroid Build Coastguard Worker 		}
1154*0d6140beSAndroid Build Coastguard Worker 		if (strlen(dev_suffix) > 0) {
1155*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: Garbage following 'device' value.\n");
1156*0d6140beSAndroid Build Coastguard Worker 			free(param_str);
1157*0d6140beSAndroid Build Coastguard Worker 			return 1;
1158*0d6140beSAndroid Build Coastguard Worker 		}
1159*0d6140beSAndroid Build Coastguard Worker 		msg_pinfo("Using device %li.\n", usedevice);
1160*0d6140beSAndroid Build Coastguard Worker 	}
1161*0d6140beSAndroid Build Coastguard Worker 	free(param_str);
1162*0d6140beSAndroid Build Coastguard Worker 
1163*0d6140beSAndroid Build Coastguard Worker 	param_str = extract_programmer_param_str(cfg, "target");
1164*0d6140beSAndroid Build Coastguard Worker 	if (param_str) {
1165*0d6140beSAndroid Build Coastguard Worker 		char *target_suffix;
1166*0d6140beSAndroid Build Coastguard Worker 		errno = 0;
1167*0d6140beSAndroid Build Coastguard Worker 		target = strtol(param_str, &target_suffix, 10);
1168*0d6140beSAndroid Build Coastguard Worker 		if (errno != 0 || param_str == target_suffix) {
1169*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: Could not convert 'target'.\n");
1170*0d6140beSAndroid Build Coastguard Worker 			free(param_str);
1171*0d6140beSAndroid Build Coastguard Worker 			return 1;
1172*0d6140beSAndroid Build Coastguard Worker 		}
1173*0d6140beSAndroid Build Coastguard Worker 		if (target < 1 || target > 2) {
1174*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: Value for 'target' is out of range.\n");
1175*0d6140beSAndroid Build Coastguard Worker 			free(param_str);
1176*0d6140beSAndroid Build Coastguard Worker 			return 1;
1177*0d6140beSAndroid Build Coastguard Worker 		}
1178*0d6140beSAndroid Build Coastguard Worker 		if (strlen(target_suffix) > 0) {
1179*0d6140beSAndroid Build Coastguard Worker 			msg_perr("Error: Garbage following 'target' value.\n");
1180*0d6140beSAndroid Build Coastguard Worker 			free(param_str);
1181*0d6140beSAndroid Build Coastguard Worker 			return 1;
1182*0d6140beSAndroid Build Coastguard Worker 		}
1183*0d6140beSAndroid Build Coastguard Worker 		switch (target) {
1184*0d6140beSAndroid Build Coastguard Worker 		case 1:
1185*0d6140beSAndroid Build Coastguard Worker 			msg_pinfo("Using target %s.\n", "FLASH_TYPE_APPLICATION_FLASH_1");
1186*0d6140beSAndroid Build Coastguard Worker 			target = FLASH_TYPE_APPLICATION_FLASH_1;
1187*0d6140beSAndroid Build Coastguard Worker 			break;
1188*0d6140beSAndroid Build Coastguard Worker 		case 2:
1189*0d6140beSAndroid Build Coastguard Worker 			msg_pinfo("Using target %s.\n", "FLASH_TYPE_APPLICATION_FLASH_2");
1190*0d6140beSAndroid Build Coastguard Worker 			target = FLASH_TYPE_APPLICATION_FLASH_2;
1191*0d6140beSAndroid Build Coastguard Worker 			break;
1192*0d6140beSAndroid Build Coastguard Worker 		default:
1193*0d6140beSAndroid Build Coastguard Worker 			break;
1194*0d6140beSAndroid Build Coastguard Worker 		}
1195*0d6140beSAndroid Build Coastguard Worker 	}
1196*0d6140beSAndroid Build Coastguard Worker 	free(param_str);
1197*0d6140beSAndroid Build Coastguard Worker 
1198*0d6140beSAndroid Build Coastguard Worker 	struct dediprog_data *dp_data = calloc(1, sizeof(*dp_data));
1199*0d6140beSAndroid Build Coastguard Worker 	if (!dp_data) {
1200*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Unable to allocate space for SPI master data\n");
1201*0d6140beSAndroid Build Coastguard Worker 		return 1;
1202*0d6140beSAndroid Build Coastguard Worker 	}
1203*0d6140beSAndroid Build Coastguard Worker 	dp_data->firmwareversion = FIRMWARE_VERSION(0, 0, 0);
1204*0d6140beSAndroid Build Coastguard Worker 	dp_data->devicetype = DEV_UNKNOWN;
1205*0d6140beSAndroid Build Coastguard Worker 
1206*0d6140beSAndroid Build Coastguard Worker 	/* Here comes the USB stuff. */
1207*0d6140beSAndroid Build Coastguard Worker 	ret = libusb_init(&dp_data->usb_ctx);
1208*0d6140beSAndroid Build Coastguard Worker 	if (ret) {
1209*0d6140beSAndroid Build Coastguard Worker 		msg_perr("Could not initialize libusb!\n");
1210*0d6140beSAndroid Build Coastguard Worker 		goto init_err_exit;
1211*0d6140beSAndroid Build Coastguard Worker 	}
1212*0d6140beSAndroid Build Coastguard Worker 
1213*0d6140beSAndroid Build Coastguard Worker 	if (id != -1) {
1214*0d6140beSAndroid Build Coastguard Worker 		for (i = 0; ; i++) {
1215*0d6140beSAndroid Build Coastguard Worker 			ret = dediprog_open(i, dp_data);
1216*0d6140beSAndroid Build Coastguard Worker 			if (ret == -1) {
1217*0d6140beSAndroid Build Coastguard Worker 				/* no dev */
1218*0d6140beSAndroid Build Coastguard Worker 				goto init_err_exit;
1219*0d6140beSAndroid Build Coastguard Worker 			} else if (ret == -2) {
1220*0d6140beSAndroid Build Coastguard Worker 				/* busy dev */
1221*0d6140beSAndroid Build Coastguard Worker 				continue;
1222*0d6140beSAndroid Build Coastguard Worker 			}
1223*0d6140beSAndroid Build Coastguard Worker 
1224*0d6140beSAndroid Build Coastguard Worker 			/* Notice we can only call dediprog_read_id() after
1225*0d6140beSAndroid Build Coastguard Worker 			 * libusb_set_configuration() and
1226*0d6140beSAndroid Build Coastguard Worker 			 * libusb_claim_interface(). When searching by id and
1227*0d6140beSAndroid Build Coastguard Worker 			 * either configuration or claim fails (usually the
1228*0d6140beSAndroid Build Coastguard Worker 			 * device is in use by another instance of flashrom),
1229*0d6140beSAndroid Build Coastguard Worker 			 * the device is skipped and the next device is tried.
1230*0d6140beSAndroid Build Coastguard Worker 			 */
1231*0d6140beSAndroid Build Coastguard Worker 			found_id = dediprog_read_id(dp_data->handle);
1232*0d6140beSAndroid Build Coastguard Worker 			if (found_id < 0) {
1233*0d6140beSAndroid Build Coastguard Worker 				msg_perr("Could not read id.\n");
1234*0d6140beSAndroid Build Coastguard Worker 				libusb_release_interface(dp_data->handle, 0);
1235*0d6140beSAndroid Build Coastguard Worker 				libusb_close(dp_data->handle);
1236*0d6140beSAndroid Build Coastguard Worker 				continue;
1237*0d6140beSAndroid Build Coastguard Worker 			}
1238*0d6140beSAndroid Build Coastguard Worker 			msg_pinfo("Found dediprog id SF%06d.\n", found_id);
1239*0d6140beSAndroid Build Coastguard Worker 			if (found_id != id) {
1240*0d6140beSAndroid Build Coastguard Worker 				libusb_release_interface(dp_data->handle, 0);
1241*0d6140beSAndroid Build Coastguard Worker 				libusb_close(dp_data->handle);
1242*0d6140beSAndroid Build Coastguard Worker 				continue;
1243*0d6140beSAndroid Build Coastguard Worker 			}
1244*0d6140beSAndroid Build Coastguard Worker 			break;
1245*0d6140beSAndroid Build Coastguard Worker 		}
1246*0d6140beSAndroid Build Coastguard Worker 	} else {
1247*0d6140beSAndroid Build Coastguard Worker 		if (dediprog_open(usedevice, dp_data)) {
1248*0d6140beSAndroid Build Coastguard Worker 			goto init_err_exit;
1249*0d6140beSAndroid Build Coastguard Worker 		}
1250*0d6140beSAndroid Build Coastguard Worker 		found_id = dediprog_read_id(dp_data->handle);
1251*0d6140beSAndroid Build Coastguard Worker 	}
1252*0d6140beSAndroid Build Coastguard Worker 
1253*0d6140beSAndroid Build Coastguard Worker 	if (found_id >= 0) {
1254*0d6140beSAndroid Build Coastguard Worker 		msg_pinfo("Using dediprog id SF%06d.\n", found_id);
1255*0d6140beSAndroid Build Coastguard Worker 	}
1256*0d6140beSAndroid Build Coastguard Worker 
1257*0d6140beSAndroid Build Coastguard Worker 	/* Try reading the devicestring. If that fails and the device is old (FW < 6.0.0, which we can not know)
1258*0d6140beSAndroid Build Coastguard Worker 	 * then we need to try the "set voltage" command and then attempt to read the devicestring again. */
1259*0d6140beSAndroid Build Coastguard Worker 	if (dediprog_check_devicestring(dp_data)) {
1260*0d6140beSAndroid Build Coastguard Worker 		if (dediprog_set_voltage(dp_data->handle))
1261*0d6140beSAndroid Build Coastguard Worker 			goto init_err_cleanup_exit;
1262*0d6140beSAndroid Build Coastguard Worker 		if (dediprog_check_devicestring(dp_data))
1263*0d6140beSAndroid Build Coastguard Worker 			goto init_err_cleanup_exit;
1264*0d6140beSAndroid Build Coastguard Worker 	}
1265*0d6140beSAndroid Build Coastguard Worker 
1266*0d6140beSAndroid Build Coastguard Worker 	/* SF100/SF200 uses one in/out endpoint, SF600 uses separate in/out endpoints */
1267*0d6140beSAndroid Build Coastguard Worker 	dp_data->in_endpoint = 2;
1268*0d6140beSAndroid Build Coastguard Worker 	switch (dp_data->devicetype) {
1269*0d6140beSAndroid Build Coastguard Worker 	case DEV_SF100:
1270*0d6140beSAndroid Build Coastguard Worker 	case DEV_SF200:
1271*0d6140beSAndroid Build Coastguard Worker 		dp_data->out_endpoint = 2;
1272*0d6140beSAndroid Build Coastguard Worker 		break;
1273*0d6140beSAndroid Build Coastguard Worker 	default:
1274*0d6140beSAndroid Build Coastguard Worker 		dp_data->out_endpoint = 1;
1275*0d6140beSAndroid Build Coastguard Worker 		break;
1276*0d6140beSAndroid Build Coastguard Worker 	}
1277*0d6140beSAndroid Build Coastguard Worker 
1278*0d6140beSAndroid Build Coastguard Worker 	/* Set all possible LEDs as soon as possible to indicate activity.
1279*0d6140beSAndroid Build Coastguard Worker 	 * Because knowing the firmware version is required to set the LEDs correctly we need to this after
1280*0d6140beSAndroid Build Coastguard Worker 	 * dediprog_check_devicestring() has queried the device. */
1281*0d6140beSAndroid Build Coastguard Worker 	dediprog_set_leds(LED_ALL, dp_data);
1282*0d6140beSAndroid Build Coastguard Worker 
1283*0d6140beSAndroid Build Coastguard Worker 	/* Select target/socket, frequency and VCC. */
1284*0d6140beSAndroid Build Coastguard Worker 	if (set_target_flash(dp_data->handle, target) ||
1285*0d6140beSAndroid Build Coastguard Worker 	    dediprog_set_spi_speed(spispeed_idx, dp_data) ||
1286*0d6140beSAndroid Build Coastguard Worker 	    dediprog_set_spi_voltage(dp_data->handle, millivolt)) {
1287*0d6140beSAndroid Build Coastguard Worker 		dediprog_set_leds(LED_ERROR, dp_data);
1288*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
1289*0d6140beSAndroid Build Coastguard Worker 	}
1290*0d6140beSAndroid Build Coastguard Worker 
1291*0d6140beSAndroid Build Coastguard Worker 	if (dediprog_standalone_mode(dp_data))
1292*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
1293*0d6140beSAndroid Build Coastguard Worker 
1294*0d6140beSAndroid Build Coastguard Worker 	if ((dp_data->devicetype == DEV_SF100) ||
1295*0d6140beSAndroid Build Coastguard Worker 	    (dp_data->devicetype == DEV_SF600 && protocol(dp_data) == PROTOCOL_V3))
1296*0d6140beSAndroid Build Coastguard Worker 		spi_master_dediprog.features &= ~SPI_MASTER_NO_4BA_MODES;
1297*0d6140beSAndroid Build Coastguard Worker 
1298*0d6140beSAndroid Build Coastguard Worker 	if (protocol(dp_data) >= PROTOCOL_V2)
1299*0d6140beSAndroid Build Coastguard Worker 		spi_master_dediprog.features |= SPI_MASTER_4BA;
1300*0d6140beSAndroid Build Coastguard Worker 
1301*0d6140beSAndroid Build Coastguard Worker 	if (dediprog_set_leds(LED_NONE, dp_data))
1302*0d6140beSAndroid Build Coastguard Worker 		goto init_err_cleanup_exit;
1303*0d6140beSAndroid Build Coastguard Worker 
1304*0d6140beSAndroid Build Coastguard Worker 	return register_spi_master(&spi_master_dediprog, dp_data);
1305*0d6140beSAndroid Build Coastguard Worker 
1306*0d6140beSAndroid Build Coastguard Worker init_err_cleanup_exit:
1307*0d6140beSAndroid Build Coastguard Worker 	dediprog_shutdown(dp_data);
1308*0d6140beSAndroid Build Coastguard Worker 	return 1;
1309*0d6140beSAndroid Build Coastguard Worker 
1310*0d6140beSAndroid Build Coastguard Worker init_err_exit:
1311*0d6140beSAndroid Build Coastguard Worker 	free(dp_data);
1312*0d6140beSAndroid Build Coastguard Worker 	return 1;
1313*0d6140beSAndroid Build Coastguard Worker }
1314*0d6140beSAndroid Build Coastguard Worker 
1315*0d6140beSAndroid Build Coastguard Worker const struct programmer_entry programmer_dediprog = {
1316*0d6140beSAndroid Build Coastguard Worker 	.name			= "dediprog",
1317*0d6140beSAndroid Build Coastguard Worker 	.type			= USB,
1318*0d6140beSAndroid Build Coastguard Worker 	.devs.dev		= devs_dediprog,
1319*0d6140beSAndroid Build Coastguard Worker 	.init			= dediprog_init,
1320*0d6140beSAndroid Build Coastguard Worker };
1321