1/* $NetBSD: ezload.c,v 1.16 2016/04/23 10:15:31 skrll 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.16 2016/04/23 10:15:31 skrll 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#include <dev/usb/usbdivar.h>
45
46#include <dev/usb/ezload.h>
47
48/*
49 * Vendor specific request code for Anchor Upload/Download
50 */
51
52/* This one is implemented in the core */
53#define ANCHOR_LOAD_INTERNAL 0xA0
54
55/* This is the highest internal RAM address for the AN2131Q */
56#define ANCHOR_MAX_INTERNAL_ADDRESS 0x1B3F
57
58/*
59 * EZ-USB Control and Status Register. Bit 0 controls 8051 reset
60 */
61#define ANCHOR_CPUCS_REG 0x7F92
62#define ANCHOR_RESET 0x01
63
64/*
65 * Although USB does not limit you here, the Anchor docs
66 * quote 64 as a limit, and Mato@activewireinc.com suggested
67 * to use 16.
68 */
69#define ANCHOR_CHUNK 16
70
71/*
72 * This is a firmware loader for ezusb (Anchor) devices. When the firmware
73 * has been downloaded the device will simulate a disconnect and when it
74 * is next recognized by the USB software it will appear as another
75 * device.
76 */
77
78#ifdef EZLOAD_DEBUG
79#define DPRINTF(x) if (ezloaddebug) printf x
80#define DPRINTFN(n,x) if (ezloaddebug>(n)) printf x
81int ezloaddebug = 0;
82#else
83#define DPRINTF(x)
84#define DPRINTFN(n,x)
85#endif
86
87usbd_status
88ezload_reset(struct usbd_device *dev, int reset)
89{
90 usb_device_request_t req;
91 uByte rst;
92
93 DPRINTF(("ezload_reset: reset=%d\n", reset));
94
95 rst = reset ? ANCHOR_RESET : 0;
96 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
97 req.bRequest = ANCHOR_LOAD_INTERNAL;
98 USETW(req.wValue, ANCHOR_CPUCS_REG);
99 USETW(req.wIndex, 0);
100 USETW(req.wLength, 1);
101 return usbd_do_request(dev, &req, &rst);
102}
103
104usbd_status
105ezload_download(struct usbd_device *dev, const struct ezdata *rec)
106{
107 usb_device_request_t req;
108 const struct ezdata *ptr;
109 u_int len, offs;
110 int err;
111
112 DPRINTF(("ezload_down record=%p\n", rec));
113
114 for (ptr = rec; ptr->length != 0; ptr++) {
115
116#if 0
117 if (ptr->address + ptr->length > ANCHOR_MAX_INTERNAL_ADDRESS)
118 return USBD_INVAL;
119#endif
120
121 req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
122 req.bRequest = ANCHOR_LOAD_INTERNAL;
123 USETW(req.wIndex, 0);
124 for (offs = 0; offs < ptr->length; offs += ANCHOR_CHUNK) {
125 len = ptr->length - offs;
126 if (len > ANCHOR_CHUNK)
127 len = ANCHOR_CHUNK;
128 USETW(req.wValue, ptr->address + offs);
129 USETW(req.wLength, len);
130 DPRINTFN(2,("ezload_download: addr=0x%x len=%d\n",
131 ptr->address + offs, len));
132 /*XXXUNCONST*/
133 err = usbd_do_request(dev, &req,
134 __UNCONST(ptr->data + offs));
135 if (err)
136 return err;
137 }
138 }
139
140 return 0;
141}
142
143usbd_status
144ezload_downloads_and_reset(struct usbd_device *dev, const struct ezdata **recs)
145{
146 usbd_status err;
147
148 /*(void)ezload_reset(dev, 1);*/
149 err = ezload_reset(dev, 1);
150 if (err)
151 return err;
152 usbd_delay_ms(dev, 250);
153 while (*recs != NULL) {
154 err = ezload_download(dev, *recs++);
155 if (err)
156 return err;
157 }
158 usbd_delay_ms(dev, 250);
159 err = ezload_reset(dev, 0);
160 usbd_delay_ms(dev, 250);
161 return err;
162}
163