io_ti.c 79.9 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
 * Edgeport USB Serial Converter driver
 *
 * Copyright (C) 2000-2002 Inside Out Networks, All rights reserved.
 * Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com>
 *
 *	This program is free software; you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License as published by
 *	the Free Software Foundation; either version 2 of the License, or
 *	(at your option) any later version.
 *
 * Supports the following devices:
 *	EP/1 EP/2 EP/4 EP/21 EP/22 EP/221 EP/42 EP/421 WATCHPORT
 *
 * For questions or problems with this driver, contact Inside Out
 * Networks technical support, or Peter Berger <pberger@brimson.com>,
 * or Al Borchers <alborchers@steinerpoint.com>.
 *
 * Version history:
 *
21
22
 *	July 11, 2002 	Removed 4 port device structure since all TI UMP
 *			chips have only 2 ports
Linus Torvalds's avatar
Linus Torvalds committed
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 *			David Iacovelli (davidi@ionetworks.com)
 *
 */

#include <linux/kernel.h>
#include <linux/jiffies.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/spinlock.h>
37
#include <linux/mutex.h>
Linus Torvalds's avatar
Linus Torvalds committed
38
39
#include <linux/serial.h>
#include <linux/ioctl.h>
40
#include <linux/firmware.h>
41
#include <linux/uaccess.h>
Linus Torvalds's avatar
Linus Torvalds committed
42
#include <linux/usb.h>
43
#include <linux/usb/serial.h>
Linus Torvalds's avatar
Linus Torvalds committed
44
45
46
47
48
49
50
51

#include "io_16654.h"
#include "io_usbvend.h"
#include "io_ti.h"

/*
 * Version Information
 */
52
#define DRIVER_VERSION "v0.7mode043006"
Linus Torvalds's avatar
Linus Torvalds committed
53
54
55
56
57
58
59
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com> and David Iacovelli"
#define DRIVER_DESC "Edgeport USB Serial Driver"

#define EPROM_PAGE_SIZE		64


struct edgeport_uart_buf_desc {
60
	__u32 count;		/* Number of bytes currently in buffer */
Linus Torvalds's avatar
Linus Torvalds committed
61
62
63
64
65
66
};

/* different hardware types */
#define HARDWARE_TYPE_930	0
#define HARDWARE_TYPE_TIUMP	1

67
68
69
70
71
72
/* IOCTL_PRIVATE_TI_GET_MODE Definitions */
#define	TI_MODE_CONFIGURING	0   /* Device has not entered start device */
#define	TI_MODE_BOOT		1   /* Staying in boot mode		   */
#define TI_MODE_DOWNLOAD	2   /* Made it to download mode		   */
#define TI_MODE_TRANSITIONING	3   /* Currently in boot mode but
				       transitioning to download mode	   */
Linus Torvalds's avatar
Linus Torvalds committed
73
74
75
76
77
78
79
80
81
82
83
84

/* read urb state */
#define EDGE_READ_URB_RUNNING	0
#define EDGE_READ_URB_STOPPING	1
#define EDGE_READ_URB_STOPPED	2

#define EDGE_CLOSING_WAIT	4000	/* in .01 sec */

#define EDGE_OUT_BUF_SIZE	1024


/* Product information read from the Edgeport */
85
86
87
struct product_info {
	int	TiMode;			/* Current TI Mode  */
	__u8	hardware_type;		/* Type of hardware */
Linus Torvalds's avatar
Linus Torvalds committed
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
} __attribute__((packed));

/* circular buffer */
struct edge_buf {
	unsigned int	buf_size;
	char		*buf_buf;
	char		*buf_get;
	char		*buf_put;
};

struct edgeport_port {
	__u16 uart_base;
	__u16 dma_address;
	__u8 shadow_msr;
	__u8 shadow_mcr;
	__u8 shadow_lsr;
	__u8 lsr_mask;
105
	__u32 ump_read_timeout;		/* Number of milliseconds the UMP will
Linus Torvalds's avatar
Linus Torvalds committed
106
107
108
109
110
111
112
113
114
115
116
117
					   wait without data before completing
					   a read short */
	int baud_rate;
	int close_pending;
	int lsr_event;
	struct edgeport_uart_buf_desc tx;
	struct async_icount	icount;
	wait_queue_head_t	delta_msr_wait;	/* for handling sleeping while
						   waiting for msr change to
						   happen */
	struct edgeport_serial	*edge_serial;
	struct usb_serial_port	*port;
118
	__u8 bUartMode;		/* Port type, 0: RS232, etc. */
Linus Torvalds's avatar
Linus Torvalds committed
119
120
121
122
123
124
125
126
	spinlock_t ep_lock;
	int ep_read_urb_state;
	int ep_write_urb_in_use;
	struct edge_buf *ep_out_buf;
};

struct edgeport_serial {
	struct product_info product_info;
127
128
129
	u8 TI_I2C_Type;			/* Type of I2C in UMP */
	u8 TiReadI2C;			/* Set to TRUE if we have read the
					   I2c in Boot Mode */
130
	struct mutex es_lock;
Linus Torvalds's avatar
Linus Torvalds committed
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
	int num_ports_open;
	struct usb_serial *serial;
};


/* Devices that this driver supports */
static struct usb_device_id edgeport_1port_id_table [] = {
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_1) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1I) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_PROXIMITY) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_MOTION) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_MOISTURE) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_TEMPERATURE) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_HUMIDITY) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_POWER) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_LIGHT) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_RADIATION) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_DISTANCE) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_ACCELERATION) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_PROX_DIST) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_PLUS_PWR_HP4CD) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_PLUS_PWR_PCI) },
	{ }
};

static struct usb_device_id edgeport_2port_id_table [] = {
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2C) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2I) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_42) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4I) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22I) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_221C) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22C) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21C) },
170
	/* The 4, 8 and 16 port devices show up as multiple 2 port devices */
Linus Torvalds's avatar
Linus Torvalds committed
171
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4S) },
172
173
174
175
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_8) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_8S) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_416) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_416B) },
Linus Torvalds's avatar
Linus Torvalds committed
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
	{ }
};

/* Devices that this driver supports */
static struct usb_device_id id_table_combined [] = {
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_1) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1I) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_PROXIMITY) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_MOTION) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_MOISTURE) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_TEMPERATURE) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_HUMIDITY) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_POWER) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_LIGHT) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_RADIATION) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_DISTANCE) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_ACCELERATION) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_WP_PROX_DIST) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_PLUS_PWR_HP4CD) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_PLUS_PWR_PCI) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2C) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2I) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_421) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_42) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4I) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22I) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_221C) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_22C) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_21C) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_4S) },
210
211
212
213
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_8) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_8S) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_416) },
	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_416B) },
Linus Torvalds's avatar
Linus Torvalds committed
214
215
216
	{ }
};

217
MODULE_DEVICE_TABLE(usb, id_table_combined);
Linus Torvalds's avatar
Linus Torvalds committed
218
219
220
221
222
223

static struct usb_driver io_driver = {
	.name =		"io_ti",
	.probe =	usb_serial_probe,
	.disconnect =	usb_serial_disconnect,
	.id_table =	id_table_combined,
224
	.no_dynamic_id = 	1,
Linus Torvalds's avatar
Linus Torvalds committed
225
226
227
};


228
229
230
static unsigned char OperationalMajorVersion;
static unsigned char OperationalMinorVersion;
static unsigned short OperationalBuildNumber;
Linus Torvalds's avatar
Linus Torvalds committed
231
232
233
234

static int debug;

static int closing_wait = EDGE_CLOSING_WAIT;
235
236
static int ignore_cpu_rev;
static int default_uart_mode;		/* RS232 */
Linus Torvalds's avatar
Linus Torvalds committed
237

238
239
static void edge_tty_recv(struct device *dev, struct tty_struct *tty,
			  unsigned char *data, int length);
Linus Torvalds's avatar
Linus Torvalds committed
240
241
242
243

static void stop_read(struct edgeport_port *edge_port);
static int restart_read(struct edgeport_port *edge_port);

Alan Cox's avatar
Alan Cox committed
244
245
246
static void edge_set_termios(struct tty_struct *tty,
		struct usb_serial_port *port, struct ktermios *old_termios);
static void edge_send(struct tty_struct *tty);
Linus Torvalds's avatar
Linus Torvalds committed
247

248
249
250
251
/* sysfs attributes */
static int edge_create_sysfs_attrs(struct usb_serial_port *port);
static int edge_remove_sysfs_attrs(struct usb_serial_port *port);

Linus Torvalds's avatar
Linus Torvalds committed
252
253
254
255
256
257
258
259
260
261
262
263
/* circular buffer */
static struct edge_buf *edge_buf_alloc(unsigned int size);
static void edge_buf_free(struct edge_buf *eb);
static void edge_buf_clear(struct edge_buf *eb);
static unsigned int edge_buf_data_avail(struct edge_buf *eb);
static unsigned int edge_buf_space_avail(struct edge_buf *eb);
static unsigned int edge_buf_put(struct edge_buf *eb, const char *buf,
	unsigned int count);
static unsigned int edge_buf_get(struct edge_buf *eb, char *buf,
	unsigned int count);


264
265
static int ti_vread_sync(struct usb_device *dev, __u8 request,
				__u16 value, __u16 index, u8 *data, int size)
Linus Torvalds's avatar
Linus Torvalds committed
266
267
268
{
	int status;

269
270
271
	status = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request,
			(USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN),
			value, index, data, size, 1000);
Linus Torvalds's avatar
Linus Torvalds committed
272
273
274
	if (status < 0)
		return status;
	if (status != size) {
275
276
		dbg("%s - wanted to write %d, but only wrote %d",
					     __func__, size, status);
Linus Torvalds's avatar
Linus Torvalds committed
277
278
279
280
281
		return -ECOMM;
	}
	return 0;
}

282
283
static int ti_vsend_sync(struct usb_device *dev, __u8 request,
				__u16 value, __u16 index, u8 *data, int size)
Linus Torvalds's avatar
Linus Torvalds committed
284
285
286
{
	int status;

287
288
289
	status = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request,
			(USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT),
			value, index, data, size, 1000);
Linus Torvalds's avatar
Linus Torvalds committed
290
291
292
	if (status < 0)
		return status;
	if (status != size) {
293
		dbg("%s - wanted to write %d, but only wrote %d",
294
		     __func__, size, status);
Linus Torvalds's avatar
Linus Torvalds committed
295
296
297
298
299
		return -ECOMM;
	}
	return 0;
}

300
static int send_cmd(struct usb_device *dev, __u8 command,
Linus Torvalds's avatar
Linus Torvalds committed
301
302
303
				__u8 moduleid, __u16 value, u8 *data,
				int size)
{
304
	return ti_vsend_sync(dev, command, value, moduleid, data, size);
Linus Torvalds's avatar
Linus Torvalds committed
305
306
307
}

/* clear tx/rx buffers and fifo in TI UMP */
308
static int purge_port(struct usb_serial_port *port, __u16 mask)
Linus Torvalds's avatar
Linus Torvalds committed
309
310
311
{
	int port_number = port->number - port->serial->minor;

312
	dbg("%s - port %d, mask %x", __func__, port_number, mask);
Linus Torvalds's avatar
Linus Torvalds committed
313

314
	return send_cmd(port->serial->dev,
Linus Torvalds's avatar
Linus Torvalds committed
315
316
317
318
319
320
321
322
					UMPC_PURGE_PORT,
					(__u8)(UMPM_UART1_PORT + port_number),
					mask,
					NULL,
					0);
}

/**
323
 * read_download_mem - Read edgeport memory from TI chip
Linus Torvalds's avatar
Linus Torvalds committed
324
325
326
327
328
329
 * @dev: usb device pointer
 * @start_address: Device CPU address at which to read
 * @length: Length of above data
 * @address_type: Can read both XDATA and I2C
 * @buffer: pointer to input data buffer
 */
330
static int read_download_mem(struct usb_device *dev, int start_address,
Linus Torvalds's avatar
Linus Torvalds committed
331
332
333
334
335
				int length, __u8 address_type, __u8 *buffer)
{
	int status = 0;
	__u8 read_length;
	__be16 be_start_address;
336
337

	dbg("%s - @ %x for %d", __func__, start_address, length);
Linus Torvalds's avatar
Linus Torvalds committed
338
339
340
341
342
343

	/* Read in blocks of 64 bytes
	 * (TI firmware can't handle more than 64 byte reads)
	 */
	while (length) {
		if (length > 64)
344
			read_length = 64;
Linus Torvalds's avatar
Linus Torvalds committed
345
346
347
348
		else
			read_length = (__u8)length;

		if (read_length > 1) {
349
			dbg("%s - @ %x for %d", __func__,
Linus Torvalds's avatar
Linus Torvalds committed
350
351
			     start_address, read_length);
		}
352
353
354
355
356
		be_start_address = cpu_to_be16(start_address);
		status = ti_vread_sync(dev, UMPC_MEMORY_READ,
					(__u16)address_type,
					(__force __u16)be_start_address,
					buffer, read_length);
Linus Torvalds's avatar
Linus Torvalds committed
357
358

		if (status) {
359
			dbg("%s - ERROR %x", __func__, status);
Linus Torvalds's avatar
Linus Torvalds committed
360
361
362
			return status;
		}

363
		if (read_length > 1)
364
			usb_serial_debug_data(debug, &dev->dev, __func__,
Linus Torvalds's avatar
Linus Torvalds committed
365
366
367
368
369
370
371
					      read_length, buffer);

		/* Update pointers/length */
		start_address += read_length;
		buffer += read_length;
		length -= read_length;
	}
372

Linus Torvalds's avatar
Linus Torvalds committed
373
374
375
	return status;
}

376
377
static int read_ram(struct usb_device *dev, int start_address,
						int length, __u8 *buffer)
Linus Torvalds's avatar
Linus Torvalds committed
378
{
379
380
	return read_download_mem(dev, start_address, length,
					DTK_ADDR_SPACE_XDATA, buffer);
Linus Torvalds's avatar
Linus Torvalds committed
381
382
383
}

/* Read edgeport memory to a given block */
384
385
static int read_boot_mem(struct edgeport_serial *serial,
				int start_address, int length, __u8 *buffer)
Linus Torvalds's avatar
Linus Torvalds committed
386
387
388
389
{
	int status = 0;
	int i;

390
391
392
393
	for (i = 0; i < length; i++) {
		status = ti_vread_sync(serial->serial->dev,
				UMPC_MEMORY_READ, serial->TI_I2C_Type,
				(__u16)(start_address+i), &buffer[i], 0x01);
Linus Torvalds's avatar
Linus Torvalds committed
394
		if (status) {
395
			dbg("%s - ERROR %x", __func__, status);
Linus Torvalds's avatar
Linus Torvalds committed
396
397
398
399
			return status;
		}
	}

400
401
402
403
	dbg("%s - start_address = %x, length = %d",
					__func__, start_address, length);
	usb_serial_debug_data(debug, &serial->serial->dev->dev,
					__func__, length, buffer);
Linus Torvalds's avatar
Linus Torvalds committed
404
405
406
407
408
409
410

	serial->TiReadI2C = 1;

	return status;
}

/* Write given block to TI EPROM memory */
411
412
static int write_boot_mem(struct edgeport_serial *serial,
				int start_address, int length, __u8 *buffer)
Linus Torvalds's avatar
Linus Torvalds committed
413
414
415
416
417
418
419
{
	int status = 0;
	int i;
	__u8 temp;

	/* Must do a read before write */
	if (!serial->TiReadI2C) {
420
		status = read_boot_mem(serial, 0, 1, &temp);
Linus Torvalds's avatar
Linus Torvalds committed
421
422
423
424
		if (status)
			return status;
	}

425
426
427
428
	for (i = 0; i < length; ++i) {
		status = ti_vsend_sync(serial->serial->dev,
				UMPC_MEMORY_WRITE, buffer[i],
				(__u16)(i + start_address), NULL, 0);
Linus Torvalds's avatar
Linus Torvalds committed
429
430
431
432
		if (status)
			return status;
	}

433
434
435
436
	dbg("%s - start_sddr = %x, length = %d",
					__func__, start_address, length);
	usb_serial_debug_data(debug, &serial->serial->dev->dev,
					__func__, length, buffer);
Linus Torvalds's avatar
Linus Torvalds committed
437
438
439
440
441
442

	return status;
}


/* Write edgeport I2C memory to TI chip	*/
443
444
static int write_i2c_mem(struct edgeport_serial *serial,
		int start_address, int length, __u8 address_type, __u8 *buffer)
Linus Torvalds's avatar
Linus Torvalds committed
445
446
447
448
449
450
{
	int status = 0;
	int write_length;
	__be16 be_start_address;

	/* We can only send a maximum of 1 aligned byte page at a time */
451

Linus Torvalds's avatar
Linus Torvalds committed
452
	/* calulate the number of bytes left in the first page */
453
454
	write_length = EPROM_PAGE_SIZE -
				(start_address & (EPROM_PAGE_SIZE - 1));
Linus Torvalds's avatar
Linus Torvalds committed
455
456
457
458

	if (write_length > length)
		write_length = length;

459
460
461
462
	dbg("%s - BytesInFirstPage Addr = %x, length = %d",
					__func__, start_address, write_length);
	usb_serial_debug_data(debug, &serial->serial->dev->dev,
						__func__, write_length, buffer);
Linus Torvalds's avatar
Linus Torvalds committed
463
464

	/* Write first page */
465
466
467
468
469
	be_start_address = cpu_to_be16(start_address);
	status = ti_vsend_sync(serial->serial->dev,
				UMPC_MEMORY_WRITE, (__u16)address_type,
				(__force __u16)be_start_address,
				buffer,	write_length);
Linus Torvalds's avatar
Linus Torvalds committed
470
	if (status) {
471
		dbg("%s - ERROR %d", __func__, status);
Linus Torvalds's avatar
Linus Torvalds committed
472
473
474
475
476
477
478
		return status;
	}

	length		-= write_length;
	start_address	+= write_length;
	buffer		+= write_length;

479
480
	/* We should be aligned now -- can write
	   max page size bytes at a time */
Linus Torvalds's avatar
Linus Torvalds committed
481
482
483
484
485
486
	while (length) {
		if (length > EPROM_PAGE_SIZE)
			write_length = EPROM_PAGE_SIZE;
		else
			write_length = length;

487
488
489
490
		dbg("%s - Page Write Addr = %x, length = %d",
					__func__, start_address, write_length);
		usb_serial_debug_data(debug, &serial->serial->dev->dev,
					__func__, write_length, buffer);
Linus Torvalds's avatar
Linus Torvalds committed
491
492

		/* Write next page */
493
494
495
496
497
		be_start_address = cpu_to_be16(start_address);
		status = ti_vsend_sync(serial->serial->dev, UMPC_MEMORY_WRITE,
				(__u16)address_type,
				(__force __u16)be_start_address,
				buffer, write_length);
Linus Torvalds's avatar
Linus Torvalds committed
498
		if (status) {
499
500
			dev_err(&serial->serial->dev->dev, "%s - ERROR %d\n",
					__func__, status);
Linus Torvalds's avatar
Linus Torvalds committed
501
502
			return status;
		}
503

Linus Torvalds's avatar
Linus Torvalds committed
504
505
506
507
508
509
510
511
		length		-= write_length;
		start_address	+= write_length;
		buffer		+= write_length;
	}
	return status;
}

/* Examine the UMP DMA registers and LSR
512
 *
Linus Torvalds's avatar
Linus Torvalds committed
513
514
515
516
 * Check the MSBit of the X and Y DMA byte count registers.
 * A zero in this bit indicates that the TX DMA buffers are empty
 * then check the TX Empty bit in the UART.
 */
517
static int tx_active(struct edgeport_port *port)
Linus Torvalds's avatar
Linus Torvalds committed
518
519
520
521
522
523
{
	int status;
	struct out_endpoint_desc_block *oedb;
	__u8 *lsr;
	int bytes_left = 0;

524
	oedb = kmalloc(sizeof(*oedb), GFP_KERNEL);
Linus Torvalds's avatar
Linus Torvalds committed
525
	if (!oedb) {
526
		dev_err(&port->port->dev, "%s - out of memory\n", __func__);
Linus Torvalds's avatar
Linus Torvalds committed
527
528
529
		return -ENOMEM;
	}

530
	lsr = kmalloc(1, GFP_KERNEL);	/* Sigh, that's right, just one byte,
Linus Torvalds's avatar
Linus Torvalds committed
531
532
533
534
535
536
537
					   as not all platforms can do DMA
					   from stack */
	if (!lsr) {
		kfree(oedb);
		return -ENOMEM;
	}
	/* Read the DMA Count Registers */
538
539
	status = read_ram(port->port->serial->dev, port->dma_address,
						sizeof(*oedb), (void *)oedb);
Linus Torvalds's avatar
Linus Torvalds committed
540
541
542
	if (status)
		goto exit_is_tx_active;

543
	dbg("%s - XByteCount    0x%X", __func__, oedb->XByteCount);
Linus Torvalds's avatar
Linus Torvalds committed
544
545

	/* and the LSR */
546
547
	status = read_ram(port->port->serial->dev,
			port->uart_base + UMPMEM_OFFS_UART_LSR, 1, lsr);
Linus Torvalds's avatar
Linus Torvalds committed
548
549
550

	if (status)
		goto exit_is_tx_active;
551
552
	dbg("%s - LSR = 0x%X", __func__, *lsr);

Linus Torvalds's avatar
Linus Torvalds committed
553
	/* If either buffer has data or we are transmitting then return TRUE */
554
	if ((oedb->XByteCount & 0x80) != 0)
Linus Torvalds's avatar
Linus Torvalds committed
555
556
		bytes_left += 64;

557
	if ((*lsr & UMP_UART_LSR_TX_MASK) == 0)
Linus Torvalds's avatar
Linus Torvalds committed
558
559
560
561
		bytes_left += 1;

	/* We return Not Active if we get any kind of error */
exit_is_tx_active:
562
	dbg("%s - return %d", __func__, bytes_left);
Linus Torvalds's avatar
Linus Torvalds committed
563
564
565
566
567
568

	kfree(lsr);
	kfree(oedb);
	return bytes_left;
}

569
570
static void chase_port(struct edgeport_port *port, unsigned long timeout,
								int flush)
Linus Torvalds's avatar
Linus Torvalds committed
571
572
{
	int baud_rate;
Alan Cox's avatar
Alan Cox committed
573
	struct tty_struct *tty = tty_port_tty_get(&port->port->port);
Linus Torvalds's avatar
Linus Torvalds committed
574
575
576
577
	wait_queue_t wait;
	unsigned long flags;

	if (!timeout)
578
		timeout = (HZ * EDGE_CLOSING_WAIT)/100;
Linus Torvalds's avatar
Linus Torvalds committed
579
580
581
582
583
584
585
586
587

	/* wait for data to drain from the buffer */
	spin_lock_irqsave(&port->ep_lock, flags);
	init_waitqueue_entry(&wait, current);
	add_wait_queue(&tty->write_wait, &wait);
	for (;;) {
		set_current_state(TASK_INTERRUPTIBLE);
		if (edge_buf_data_avail(port->ep_out_buf) == 0
		|| timeout == 0 || signal_pending(current)
588
589
		|| !usb_get_intfdata(port->port->serial->interface))
			/* disconnect */
Linus Torvalds's avatar
Linus Torvalds committed
590
591
592
593
594
595
596
597
598
599
			break;
		spin_unlock_irqrestore(&port->ep_lock, flags);
		timeout = schedule_timeout(timeout);
		spin_lock_irqsave(&port->ep_lock, flags);
	}
	set_current_state(TASK_RUNNING);
	remove_wait_queue(&tty->write_wait, &wait);
	if (flush)
		edge_buf_clear(port->ep_out_buf);
	spin_unlock_irqrestore(&port->ep_lock, flags);
Alan Cox's avatar
Alan Cox committed
600
	tty_kref_put(tty);
Linus Torvalds's avatar
Linus Torvalds committed
601
602
603
604

	/* wait for data to drain from the device */
	timeout += jiffies;
	while ((long)(jiffies - timeout) < 0 && !signal_pending(current)
605
606
607
	&& usb_get_intfdata(port->port->serial->interface)) {
		/* not disconnected */
		if (!tx_active(port))
Linus Torvalds's avatar
Linus Torvalds committed
608
609
610
611
612
613
614
615
616
			break;
		msleep(10);
	}

	/* disconnected */
	if (!usb_get_intfdata(port->port->serial->interface))
		return;

	/* wait one more character time, based on baud rate */
617
618
619
	/* (tx_active doesn't seem to wait for the last byte) */
	baud_rate = port->baud_rate;
	if (baud_rate == 0)
Linus Torvalds's avatar
Linus Torvalds committed
620
		baud_rate = 50;
Julia Lawall's avatar
Julia Lawall committed
621
	msleep(max(1, DIV_ROUND_UP(10000, baud_rate)));
Linus Torvalds's avatar
Linus Torvalds committed
622
623
}

624
static int choose_config(struct usb_device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
625
{
626
627
628
629
630
631
	/*
	 * There may be multiple configurations on this device, in which case
	 * we would need to read and parse all of them to find out which one
	 * we want. However, we just support one config at this point,
	 * configuration # 1, which is Config Descriptor 0.
	 */
Linus Torvalds's avatar
Linus Torvalds committed
632

633
634
635
636
	dbg("%s - Number of Interfaces = %d",
				__func__, dev->config->desc.bNumInterfaces);
	dbg("%s - MAX Power            = %d",
				__func__, dev->config->desc.bMaxPower * 2);
Linus Torvalds's avatar
Linus Torvalds committed
637
638

	if (dev->config->desc.bNumInterfaces != 1) {
639
640
		dev_err(&dev->dev, "%s - bNumInterfaces is not 1, ERROR!\n",
								__func__);
Linus Torvalds's avatar
Linus Torvalds committed
641
642
643
644
645
646
		return -ENODEV;
	}

	return 0;
}

647
648
static int read_rom(struct edgeport_serial *serial,
				int start_address, int length, __u8 *buffer)
Linus Torvalds's avatar
Linus Torvalds committed
649
650
651
652
{
	int status;

	if (serial->product_info.TiMode == TI_MODE_DOWNLOAD) {
653
		status = read_download_mem(serial->serial->dev,
Linus Torvalds's avatar
Linus Torvalds committed
654
655
656
657
658
					       start_address,
					       length,
					       serial->TI_I2C_Type,
					       buffer);
	} else {
659
660
		status = read_boot_mem(serial, start_address, length,
								buffer);
Linus Torvalds's avatar
Linus Torvalds committed
661
662
663
664
	}
	return status;
}

665
666
static int write_rom(struct edgeport_serial *serial, int start_address,
						int length, __u8 *buffer)
Linus Torvalds's avatar
Linus Torvalds committed
667
668
{
	if (serial->product_info.TiMode == TI_MODE_BOOT)
669
670
		return write_boot_mem(serial, start_address, length,
								buffer);
Linus Torvalds's avatar
Linus Torvalds committed
671
672

	if (serial->product_info.TiMode == TI_MODE_DOWNLOAD)
673
674
		return write_i2c_mem(serial, start_address, length,
						serial->TI_I2C_Type, buffer);
Linus Torvalds's avatar
Linus Torvalds committed
675
676
677
678
679
680
	return -EINVAL;
}



/* Read a descriptor header from I2C based on type */
681
682
static int get_descriptor_addr(struct edgeport_serial *serial,
				int desc_type, struct ti_i2c_desc *rom_desc)
Linus Torvalds's avatar
Linus Torvalds committed
683
684
685
686
687
688
689
{
	int start_address;
	int status;

	/* Search for requested descriptor in I2C */
	start_address = 2;
	do {
690
		status = read_rom(serial,
Linus Torvalds's avatar
Linus Torvalds committed
691
692
				   start_address,
				   sizeof(struct ti_i2c_desc),
693
				   (__u8 *)rom_desc);
Linus Torvalds's avatar
Linus Torvalds committed
694
695
696
697
698
699
		if (status)
			return 0;

		if (rom_desc->Type == desc_type)
			return start_address;

700
701
		start_address = start_address + sizeof(struct ti_i2c_desc)
							+ rom_desc->Size;
Linus Torvalds's avatar
Linus Torvalds committed
702
703

	} while ((start_address < TI_MAX_I2C_SIZE) && rom_desc->Type);
704

Linus Torvalds's avatar
Linus Torvalds committed
705
706
707
708
	return 0;
}

/* Validate descriptor checksum */
709
static int valid_csum(struct ti_i2c_desc *rom_desc, __u8 *buffer)
Linus Torvalds's avatar
Linus Torvalds committed
710
711
712
713
{
	__u16 i;
	__u8 cs = 0;

714
	for (i = 0; i < rom_desc->Size; i++)
Linus Torvalds's avatar
Linus Torvalds committed
715
		cs = (__u8)(cs + buffer[i]);
716

Linus Torvalds's avatar
Linus Torvalds committed
717
	if (cs != rom_desc->CheckSum) {
718
		dbg("%s - Mismatch %x - %x", __func__, rom_desc->CheckSum, cs);
Linus Torvalds's avatar
Linus Torvalds committed
719
720
721
722
723
724
		return -EINVAL;
	}
	return 0;
}

/* Make sure that the I2C image is good */
725
static int check_i2c_image(struct edgeport_serial *serial)
Linus Torvalds's avatar
Linus Torvalds committed
726
727
728
729
730
731
732
733
{
	struct device *dev = &serial->serial->dev->dev;
	int status = 0;
	struct ti_i2c_desc *rom_desc;
	int start_address = 2;
	__u8 *buffer;
	__u16 ttype;

734
	rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL);
Linus Torvalds's avatar
Linus Torvalds committed
735
	if (!rom_desc) {
736
		dev_err(dev, "%s - out of memory\n", __func__);
Linus Torvalds's avatar
Linus Torvalds committed
737
738
		return -ENOMEM;
	}
739
	buffer = kmalloc(TI_MAX_I2C_SIZE, GFP_KERNEL);
Linus Torvalds's avatar
Linus Torvalds committed
740
	if (!buffer) {
741
742
743
		dev_err(dev, "%s - out of memory when allocating buffer\n",
								__func__);
		kfree(rom_desc);
Linus Torvalds's avatar
Linus Torvalds committed
744
745
746
		return -ENOMEM;
	}

747
748
	/* Read the first byte (Signature0) must be 0x52 or 0x10 */
	status = read_rom(serial, 0, 1, buffer);
Linus Torvalds's avatar
Linus Torvalds committed
749
	if (status)
750
		goto out;
Linus Torvalds's avatar
Linus Torvalds committed
751
752

	if (*buffer != UMP5152 && *buffer != UMP3410) {
753
		dev_err(dev, "%s - invalid buffer signature\n", __func__);
Linus Torvalds's avatar
Linus Torvalds committed
754
		status = -ENODEV;
755
		goto out;
Linus Torvalds's avatar
Linus Torvalds committed
756
757
758
	}

	do {
759
760
		/* Validate the I2C */
		status = read_rom(serial,
Linus Torvalds's avatar
Linus Torvalds committed
761
762
763
764
765
766
				start_address,
				sizeof(struct ti_i2c_desc),
				(__u8 *)rom_desc);
		if (status)
			break;

767
768
		if ((start_address + sizeof(struct ti_i2c_desc) +
					rom_desc->Size) > TI_MAX_I2C_SIZE) {
Linus Torvalds's avatar
Linus Torvalds committed
769
			status = -ENODEV;
770
			dbg("%s - structure too big, erroring out.", __func__);
Linus Torvalds's avatar
Linus Torvalds committed
771
772
773
			break;
		}

774
		dbg("%s Type = 0x%x", __func__, rom_desc->Type);
Linus Torvalds's avatar
Linus Torvalds committed
775

776
		/* Skip type 2 record */
Linus Torvalds's avatar
Linus Torvalds committed
777
		ttype = rom_desc->Type & 0x0f;
778
779
780
781
782
783
		if (ttype != I2C_DESC_TYPE_FIRMWARE_BASIC
			&& ttype != I2C_DESC_TYPE_FIRMWARE_AUTO) {
			/* Read the descriptor data */
			status = read_rom(serial, start_address +
						sizeof(struct ti_i2c_desc),
						rom_desc->Size, buffer);
Linus Torvalds's avatar
Linus Torvalds committed
784
785
786
			if (status)
				break;

787
			status = valid_csum(rom_desc, buffer);
Linus Torvalds's avatar
Linus Torvalds committed
788
789
790
			if (status)
				break;
		}
791
792
		start_address = start_address + sizeof(struct ti_i2c_desc) +
								rom_desc->Size;
Linus Torvalds's avatar
Linus Torvalds committed
793

794
795
	} while ((rom_desc->Type != I2C_DESC_TYPE_ION) &&
				(start_address < TI_MAX_I2C_SIZE));
Linus Torvalds's avatar
Linus Torvalds committed
796

797
798
	if ((rom_desc->Type != I2C_DESC_TYPE_ION) ||
				(start_address > TI_MAX_I2C_SIZE))
Linus Torvalds's avatar
Linus Torvalds committed
799
800
		status = -ENODEV;

801
802
803
out:
	kfree(buffer);
	kfree(rom_desc);
Linus Torvalds's avatar
Linus Torvalds committed
804
805
806
	return status;
}

807
static int get_manuf_info(struct edgeport_serial *serial, __u8 *buffer)
Linus Torvalds's avatar
Linus Torvalds committed
808
809
810
811
812
813
{
	int status;
	int start_address;
	struct ti_i2c_desc *rom_desc;
	struct edge_ti_manuf_descriptor *desc;

814
	rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL);
Linus Torvalds's avatar
Linus Torvalds committed
815
	if (!rom_desc) {
816
817
		dev_err(&serial->serial->dev->dev, "%s - out of memory\n",
								__func__);
Linus Torvalds's avatar
Linus Torvalds committed
818
819
		return -ENOMEM;
	}
820
821
	start_address = get_descriptor_addr(serial, I2C_DESC_TYPE_ION,
								rom_desc);
Linus Torvalds's avatar
Linus Torvalds committed
822
823

	if (!start_address) {
824
		dbg("%s - Edge Descriptor not found in I2C", __func__);
Linus Torvalds's avatar
Linus Torvalds committed
825
826
827
828
		status = -ENODEV;
		goto exit;
	}

829
830
831
	/* Read the descriptor data */
	status = read_rom(serial, start_address+sizeof(struct ti_i2c_desc),
						rom_desc->Size, buffer);
Linus Torvalds's avatar
Linus Torvalds committed
832
833
	if (status)
		goto exit;
834
835
836

	status = valid_csum(rom_desc, buffer);

Linus Torvalds's avatar
Linus Torvalds committed
837
	desc = (struct edge_ti_manuf_descriptor *)buffer;
838
839
840
841
842
843
	dbg("%s - IonConfig      0x%x", __func__, desc->IonConfig);
	dbg("%s - Version          %d", __func__, desc->Version);
	dbg("%s - Cpu/Board      0x%x", __func__, desc->CpuRev_BoardRev);
	dbg("%s - NumPorts         %d", __func__, desc->NumPorts);
	dbg("%s - NumVirtualPorts  %d", __func__, desc->NumVirtualPorts);
	dbg("%s - TotalPorts       %d", __func__, desc->TotalPorts);
Linus Torvalds's avatar
Linus Torvalds committed
844
845

exit:
846
	kfree(rom_desc);
Linus Torvalds's avatar
Linus Torvalds committed
847
848
849
850
	return status;
}

/* Build firmware header used for firmware update */
851
static int build_i2c_fw_hdr(__u8 *header, struct device *dev)
Linus Torvalds's avatar
Linus Torvalds committed
852
853
854
855
{
	__u8 *buffer;
	int buffer_size;
	int i;
856
	int err;
Linus Torvalds's avatar
Linus Torvalds committed
857
858
859
860
	__u8 cs = 0;
	struct ti_i2c_desc *i2c_header;
	struct ti_i2c_image_header *img_header;
	struct ti_i2c_firmware_rec *firmware_rec;
861
862
	const struct firmware *fw;
	const char *fw_name = "edgeport/down3.bin";
Linus Torvalds's avatar
Linus Torvalds committed
863

864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
	/* In order to update the I2C firmware we must change the type 2 record
	 * to type 0xF2.  This will force the UMP to come up in Boot Mode.
	 * Then while in boot mode, the driver will download the latest
	 * firmware (padded to 15.5k) into the UMP ram.  And finally when the
	 * device comes back up in download mode the driver will cause the new
	 * firmware to be copied from the UMP Ram to I2C and the firmware will
	 * update the record type from 0xf2 to 0x02.
	 */

	/* Allocate a 15.5k buffer + 2 bytes for version number
	 * (Firmware Record) */
	buffer_size = (((1024 * 16) - 512 ) +
			sizeof(struct ti_i2c_firmware_rec));

	buffer = kmalloc(buffer_size, GFP_KERNEL);
Linus Torvalds's avatar
Linus Torvalds committed
879
	if (!buffer) {
880
		dev_err(dev, "%s - out of memory\n", __func__);
Linus Torvalds's avatar
Linus Torvalds committed
881
882
		return -ENOMEM;
	}
883

Linus Torvalds's avatar
Linus Torvalds committed
884
	// Set entire image of 0xffs
885
	memset(buffer, 0xff, buffer_size);
Linus Torvalds's avatar
Linus Torvalds committed
886

887
888
889
890
891
892
893
894
895
896
897
898
899
	err = request_firmware(&fw, fw_name, dev);
	if (err) {
		printk(KERN_ERR "Failed to load image \"%s\" err %d\n",
		       fw_name, err);
		kfree(buffer);
		return err;
	}

	/* Save Download Version Number */
	OperationalMajorVersion = fw->data[0];
	OperationalMinorVersion = fw->data[1];
	OperationalBuildNumber = fw->data[2] | (fw->data[3] << 8);

900
	/* Copy version number into firmware record */
Linus Torvalds's avatar
Linus Torvalds committed
901
902
	firmware_rec = (struct ti_i2c_firmware_rec *)buffer;

903
904
	firmware_rec->Ver_Major	= OperationalMajorVersion;
	firmware_rec->Ver_Minor	= OperationalMinorVersion;
Linus Torvalds's avatar
Linus Torvalds committed
905

906
	/* Pointer to fw_down memory image */
907
	img_header = (struct ti_i2c_image_header *)&fw->data[4];
Linus Torvalds's avatar
Linus Torvalds committed
908

909
	memcpy(buffer + sizeof(struct ti_i2c_firmware_rec),
910
		&fw->data[4 + sizeof(struct ti_i2c_image_header)],
Linus Torvalds's avatar
Linus Torvalds committed
911
912
		le16_to_cpu(img_header->Length));

913
914
	release_firmware(fw);

Linus Torvalds's avatar
Linus Torvalds committed
915
916
917
918
	for (i=0; i < buffer_size; i++) {
		cs = (__u8)(cs + buffer[i]);
	}

919
	kfree(buffer);
Linus Torvalds's avatar
Linus Torvalds committed
920

921
	/* Build new header */
Linus Torvalds's avatar
Linus Torvalds committed
922
923
	i2c_header =  (struct ti_i2c_desc *)header;
	firmware_rec =  (struct ti_i2c_firmware_rec*)i2c_header->Data;
924

Linus Torvalds's avatar
Linus Torvalds committed
925
926
927
	i2c_header->Type	= I2C_DESC_TYPE_FIRMWARE_BLANK;
	i2c_header->Size	= (__u16)buffer_size;
	i2c_header->CheckSum	= cs;
928
929
	firmware_rec->Ver_Major	= OperationalMajorVersion;
	firmware_rec->Ver_Minor	= OperationalMinorVersion;
Linus Torvalds's avatar
Linus Torvalds committed
930
931
932
933
934

	return 0;
}

/* Try to figure out what type of I2c we have */
935
static int i2c_type_bootmode(struct edgeport_serial *serial)
Linus Torvalds's avatar
Linus Torvalds committed
936
937
938
{
	int status;
	__u8 data;
939
940
941
942

	/* Try to read type 2 */
	status = ti_vread_sync(serial->serial->dev, UMPC_MEMORY_READ,
				DTK_ADDR_SPACE_I2C_TYPE_II, 0, &data, 0x01);
Linus Torvalds's avatar
Linus Torvalds committed
943
	if (status)
944
		dbg("%s - read 2 status error = %d", __func__, status);
Linus Torvalds's avatar
Linus Torvalds committed
945
	else
946
		dbg("%s - read 2 data = 0x%x", __func__, data);
Linus Torvalds's avatar
Linus Torvalds committed
947
	if ((!status) && (data == UMP5152 || data == UMP3410)) {
948
		dbg("%s - ROM_TYPE_II", __func__);
Linus Torvalds's avatar
Linus Torvalds committed
949
950
951
952
		serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
		return 0;
	}

953
954
955
	/* Try to read type 3 */
	status = ti_vread_sync(serial->serial->dev, UMPC_MEMORY_READ,
				DTK_ADDR_SPACE_I2C_TYPE_III, 0,	&data, 0x01);
Linus Torvalds's avatar
Linus Torvalds committed
956
	if (status)
957
		dbg("%s - read 3 status error = %d", __func__, status);
Linus Torvalds's avatar
Linus Torvalds committed
958
	else
959
		dbg("%s - read 2 data = 0x%x", __func__, data);
Linus Torvalds's avatar
Linus Torvalds committed
960
	if ((!status) && (data == UMP5152 || data == UMP3410)) {
961
		dbg("%s - ROM_TYPE_III", __func__);
Linus Torvalds's avatar
Linus Torvalds committed
962
963
964
965
		serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_III;
		return 0;
	}

966
	dbg("%s - Unknown", __func__);
Linus Torvalds's avatar
Linus Torvalds committed
967
968
969
970
	serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
	return -ENODEV;
}

971
972
static int bulk_xfer(struct usb_serial *serial, void *buffer,
						int length, int *num_sent)
Linus Torvalds's avatar
Linus Torvalds committed
973
974
975
{
	int status;

976
977
978
979
	status = usb_bulk_msg(serial->dev,
			usb_sndbulkpipe(serial->dev,
				serial->port[0]->bulk_out_endpointAddress),
			buffer, length, num_sent, 1000);
Linus Torvalds's avatar
Linus Torvalds committed
980
981
982
983
	return status;
}

/* Download given firmware image to the device (IN BOOT MODE) */
984
985
static int download_code(struct edgeport_serial *serial, __u8 *image,
							int image_length)
Linus Torvalds's avatar
Linus Torvalds committed
986
987
988
989
990
991
{
	int status = 0;
	int pos;
	int transfer;
	int done;

992
	/* Transfer firmware image */
Linus Torvalds's avatar
Linus Torvalds committed
993
	for (pos = 0; pos < image_length; ) {
994
		/* Read the next buffer from file */
Linus Torvalds's avatar
Linus Torvalds committed
995
996
997
998
		transfer = image_length - pos;
		if (transfer > EDGE_FW_BULK_MAX_PACKET_SIZE)
			transfer = EDGE_FW_BULK_MAX_PACKET_SIZE;

999
1000
		/* Transfer data */
		status = bulk_xfer(serial->serial, &image[pos],