1/*	$NetBSD: ezload.c,v 1.11 2006/04/14 17:21:17 christos Exp $	*/
2
3/*
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by  Lennart Augustsson <lennart@augustsson.net>.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD: ezload.c,v 1.11 2006/04/14 17:21:17 christos Exp $");
34
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/kernel.h>
38#include <sys/device.h>
39#include <sys/conf.h>
40
41#include <dev/usb/usb.h>
42#include <dev/usb/usbdi.h>
43#include <dev/usb/usbdi_util.h>
44
45#include <dev/usb/ezload.h>
46
47/*
48 * Vendor specific request code for Anchor Upload/Download
49 */
50
51/* This one is implemented in the core */
52#define ANCHOR_LOAD_INTERNAL	0xA0
53
54/* This is the highest internal RAM address for the AN2131Q */
55#define ANCHOR_MAX_INTERNAL_ADDRESS  0x1B3F
56
57/*
58 * EZ-USB Control and Status Register.  Bit 0 controls 8051 reset
59 */
60#define ANCHOR_CPUCS_REG	0x7F92
61#define  ANCHOR_RESET		0x01
62
63/*
64 * Although USB does not limit you here, the Anchor docs
65 * quote 64 as a limit, and Mato@activewireinc.com suggested
66 * to use 16.
67 */
68#define ANCHOR_CHUNK 16
69
70/*
71 * This is a firmware loader for ezusb (Anchor) devices. When the firmware
72 * has been downloaded the device will simulate a disconnect and when it
73 * is next recognized by the USB software it will appear as another
74 * device.
75 */
76
77#ifdef USB_DEBUG
78#define DPRINTF(x)	if (ezloaddebug) printf x
79#define DPRINTFN(n,x)	if (ezloaddebug>(n)) printf x
80int ezloaddebug = 0;
81#else
82#define DPRINTF(x)
83#define DPRINTFN(n,x)
84#endif
85
86usbd_status
87ezload_reset(usbd_device_handle dev, int reset)
88{
89	usb_device_request_t req;
90	uByte rst;
91
92	DPRINTF(("ezload_reset: reset=%d\n", reset));
93
94	rst = reset ? ANCHOR_RESET : 0;
95	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
96	req.bRequest = ANCHOR_LOAD_INTERNAL;
97	USETW(req.wValue, ANCHOR_CPUCS_REG);
98	USETW(req.wIndex, 0);
99	USETW(req.wLength, 1);
100	return (usbd_do_request(dev, &req, &rst));
101}
102
103usbd_status
104ezload_download(usbd_device_handle dev, const struct ezdata *rec)
105{
106	usb_device_request_t req;
107	const struct ezdata *ptr;
108	u_int len, offs;
109	int err;
110
111	DPRINTF(("ezload_down record=%p\n", rec));
112
113	for (ptr = rec; ptr->length != 0; ptr++) {
114
115#if 0
116		if (ptr->address + ptr->length > ANCHOR_MAX_INTERNAL_ADDRESS)
117			return (USBD_INVAL);
118#endif
119
120		req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
121		req.bRequest = ANCHOR_LOAD_INTERNAL;
122		USETW(req.wIndex, 0);
123		for (offs = 0; offs < ptr->length; offs += ANCHOR_CHUNK) {
124			len = ptr->length - offs;
125			if (len > ANCHOR_CHUNK)
126				len = ANCHOR_CHUNK;
127			USETW(req.wValue, ptr->address + offs);
128			USETW(req.wLength, len);
129			DPRINTFN(2,("ezload_download: addr=0x%x len=%d\n",
130				    ptr->address + offs, len));
131			/*XXXUNCONST*/
132			err = usbd_do_request(dev, &req,
133			    __UNCONST(ptr->data + offs));
134			if (err)
135				return (err);
136		}
137	}
138
139	return (0);
140}
141
142usbd_status
143ezload_downloads_and_reset(usbd_device_handle dev, const struct ezdata **recs)
144{
145	usbd_status err;
146
147	/*(void)ezload_reset(dev, 1);*/
148	err = ezload_reset(dev, 1);
149	if (err)
150		return (err);
151	usbd_delay_ms(dev, 250);
152	while (*recs != NULL) {
153		err = ezload_download(dev, *recs++);
154		if (err)
155			return (err);
156	}
157	usbd_delay_ms(dev, 250);
158	err = ezload_reset(dev, 0);
159	usbd_delay_ms(dev, 250);
160	return (err);
161}
162