emi62.c 9.0 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/* 
 * Emagic EMI 2|6 usb audio interface firmware loader.
 * Copyright (C) 2002
4
 * 	Tapio Laxström (tapio.laxstrom@iptime.fi)
L
Linus Torvalds 已提交
5 6 7 8 9 10 11 12 13 14 15
 *
 * 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, version 2.
 */
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/usb.h>
16
#include <linux/delay.h>
D
David Woodhouse 已提交
17 18
#include <linux/firmware.h>
#include <linux/ihex.h>
L
Linus Torvalds 已提交
19 20 21 22 23 24 25 26

/* include firmware (variables)*/

/* FIXME: This is quick and dirty solution! */
#define SPDIF	/* if you want SPDIF comment next line */
//#undef SPDIF	/* if you want MIDI uncomment this line */ 

#ifdef SPDIF
D
David Woodhouse 已提交
27
#define FIRMWARE_FW "emi62/spdif.fw"
L
Linus Torvalds 已提交
28
#else
D
David Woodhouse 已提交
29
#define FIRMWARE_FW "emi62/midi.fw"
L
Linus Torvalds 已提交
30 31 32 33 34 35 36 37 38 39 40 41
#endif

#define EMI62_VENDOR_ID 		0x086a  /* Emagic Soft-und Hardware GmBH */
#define EMI62_PRODUCT_ID		0x0110	/* EMI 6|2m without firmware */

#define ANCHOR_LOAD_INTERNAL	0xA0	/* Vendor specific request code for Anchor Upload/Download (This one is implemented in the core) */
#define ANCHOR_LOAD_EXTERNAL	0xA3	/* This command is not implemented in the core. Requires firmware */
#define ANCHOR_LOAD_FPGA	0xA5	/* This command is not implemented in the core. Requires firmware. Emagic extension */
#define MAX_INTERNAL_ADDRESS	0x1B3F	/* This is the highest internal RAM address for the AN2131Q */
#define CPUCS_REG		0x7F92  /* EZ-USB Control and Status Register.  Bit 0 controls 8051 reset */ 
#define INTERNAL_RAM(address)   (address <= MAX_INTERNAL_ADDRESS)

D
David Woodhouse 已提交
42 43 44
static int emi62_writememory(struct usb_device *dev, int address,
			     const unsigned char *data, int length,
			     __u8 bRequest);
L
Linus Torvalds 已提交
45 46 47 48 49 50 51 52 53
static int emi62_set_reset(struct usb_device *dev, unsigned char reset_bit);
static int emi62_load_firmware (struct usb_device *dev);
static int emi62_probe(struct usb_interface *intf, const struct usb_device_id *id);
static void emi62_disconnect(struct usb_interface *intf);
static int __init emi62_init (void);
static void __exit emi62_exit (void);


/* thanks to drivers/usb/serial/keyspan_pda.c code */
D
David Woodhouse 已提交
54 55 56
static int emi62_writememory(struct usb_device *dev, int address,
			     const unsigned char *data, int length,
			     __u8 request)
L
Linus Torvalds 已提交
57 58
{
	int result;
59
	unsigned char *buffer =  kmemdup(data, length, GFP_KERNEL);
L
Linus Torvalds 已提交
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75

	if (!buffer) {
		err("emi62: kmalloc(%d) failed.", length);
		return -ENOMEM;
	}
	/* Note: usb_control_msg returns negative value on error or length of the
	 * 		 data that was written! */
	result = usb_control_msg (dev, usb_sndctrlpipe(dev, 0), request, 0x40, address, 0, buffer, length, 300);
	kfree (buffer);
	return result;
}

/* thanks to drivers/usb/serial/keyspan_pda.c code */
static int emi62_set_reset (struct usb_device *dev, unsigned char reset_bit)
{
	int response;
76
	dev_info(&dev->dev, "%s - %d\n", __func__, reset_bit);
L
Linus Torvalds 已提交
77 78 79 80 81 82 83 84 85 86 87 88
	
	response = emi62_writememory (dev, CPUCS_REG, &reset_bit, 1, 0xa0);
	if (response < 0) {
		err("emi62: set_reset (%d) failed", reset_bit);
	}
	return response;
}

#define FW_LOAD_SIZE		1023

static int emi62_load_firmware (struct usb_device *dev)
{
D
David Woodhouse 已提交
89 90 91 92
	const struct firmware *loader_fw = NULL;
	const struct firmware *bitstream_fw = NULL;
	const struct firmware *firmware_fw = NULL;
	const struct ihex_binrec *rec;
L
Linus Torvalds 已提交
93 94 95 96 97 98 99 100
	int err;
	int i;
	__u32 addr;	/* Address to write */
	__u8 *buf;

	dev_dbg(&dev->dev, "load_firmware\n");
	buf = kmalloc(FW_LOAD_SIZE, GFP_KERNEL);
	if (!buf) {
101
		err( "%s - error loading firmware: error = %d", __func__, -ENOMEM);
L
Linus Torvalds 已提交
102 103 104 105
		err = -ENOMEM;
		goto wraperr;
	}

D
David Woodhouse 已提交
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
	err = request_ihex_firmware(&loader_fw, "emi62/loader.fw", &dev->dev);
	if (err)
		goto nofw;

	err = request_ihex_firmware(&bitstream_fw, "emi62/bitstream.fw",
				    &dev->dev);
	if (err)
		goto nofw;

	err = request_ihex_firmware(&firmware_fw, FIRMWARE_FW, &dev->dev);
	if (err) {
	nofw:
		err( "%s - request_firmware() failed", __func__);
		goto wraperr;
	}

L
Linus Torvalds 已提交
122 123 124
	/* Assert reset (stop the CPU in the EMI) */
	err = emi62_set_reset(dev,1);
	if (err < 0) {
125
		err("%s - error loading firmware: error = %d", __func__, err);
L
Linus Torvalds 已提交
126 127 128
		goto wraperr;
	}

D
David Woodhouse 已提交
129 130
	rec = (const struct ihex_binrec *)loader_fw->data;

L
Linus Torvalds 已提交
131
	/* 1. We need to put the loader for the FPGA into the EZ-USB */
D
David Woodhouse 已提交
132 133 134 135
	while (rec) {
		err = emi62_writememory(dev, be32_to_cpu(rec->addr),
					rec->data, be16_to_cpu(rec->len),
					ANCHOR_LOAD_INTERNAL);
L
Linus Torvalds 已提交
136
		if (err < 0) {
137
			err("%s - error loading firmware: error = %d", __func__, err);
L
Linus Torvalds 已提交
138 139
			goto wraperr;
		}
D
David Woodhouse 已提交
140
		rec = ihex_next_binrec(rec);
L
Linus Torvalds 已提交
141 142 143 144
	}

	/* De-assert reset (let the CPU run) */
	err = emi62_set_reset(dev,0);
O
Oliver Neukum 已提交
145
	if (err < 0) {
146
		err("%s - error loading firmware: error = %d", __func__, err);
O
Oliver Neukum 已提交
147 148
		goto wraperr;
	}
149
	msleep(250);	/* let device settle */
L
Linus Torvalds 已提交
150 151 152 153

	/* 2. We upload the FPGA firmware into the EMI
	 * Note: collect up to 1023 (yes!) bytes and send them with
	 * a single request. This is _much_ faster! */
D
David Woodhouse 已提交
154
	rec = (const struct ihex_binrec *)bitstream_fw->data;
L
Linus Torvalds 已提交
155 156
	do {
		i = 0;
D
David Woodhouse 已提交
157
		addr = be32_to_cpu(rec->addr);
L
Linus Torvalds 已提交
158 159

		/* intel hex records are terminated with type 0 element */
D
David Woodhouse 已提交
160 161 162 163
		while (rec && (i + be16_to_cpu(rec->len) < FW_LOAD_SIZE)) {
			memcpy(buf + i, rec->data, be16_to_cpu(rec->len));
			i += be16_to_cpu(rec->len);
			rec = ihex_next_binrec(rec);
L
Linus Torvalds 已提交
164 165 166
		}
		err = emi62_writememory(dev, addr, buf, i, ANCHOR_LOAD_FPGA);
		if (err < 0) {
167
			err("%s - error loading firmware: error = %d", __func__, err);
L
Linus Torvalds 已提交
168 169 170 171 172 173 174
			goto wraperr;
		}
	} while (i > 0);

	/* Assert reset (stop the CPU in the EMI) */
	err = emi62_set_reset(dev,1);
	if (err < 0) {
175
		err("%s - error loading firmware: error = %d", __func__, err);
L
Linus Torvalds 已提交
176 177 178 179
		goto wraperr;
	}

	/* 3. We need to put the loader for the firmware into the EZ-USB (again...) */
D
David Woodhouse 已提交
180 181 182 183 184
	for (rec = (const struct ihex_binrec *)loader_fw->data;
	     rec; rec = ihex_next_binrec(rec)) {
		err = emi62_writememory(dev, be32_to_cpu(rec->addr),
					rec->data, be16_to_cpu(rec->len),
					ANCHOR_LOAD_INTERNAL);
L
Linus Torvalds 已提交
185
		if (err < 0) {
186
			err("%s - error loading firmware: error = %d", __func__, err);
L
Linus Torvalds 已提交
187 188 189 190 191 192 193
			goto wraperr;
		}
	}

	/* De-assert reset (let the CPU run) */
	err = emi62_set_reset(dev,0);
	if (err < 0) {
194
		err("%s - error loading firmware: error = %d", __func__, err);
L
Linus Torvalds 已提交
195 196
		goto wraperr;
	}
197
	msleep(250);	/* let device settle */
L
Linus Torvalds 已提交
198 199 200

	/* 4. We put the part of the firmware that lies in the external RAM into the EZ-USB */

D
David Woodhouse 已提交
201 202 203 204 205 206
	for (rec = (const struct ihex_binrec *)firmware_fw->data;
	     rec; rec = ihex_next_binrec(rec)) {
		if (!INTERNAL_RAM(be32_to_cpu(rec->addr))) {
			err = emi62_writememory(dev, be32_to_cpu(rec->addr),
						rec->data, be16_to_cpu(rec->len),
						ANCHOR_LOAD_EXTERNAL);
L
Linus Torvalds 已提交
207
			if (err < 0) {
208
				err("%s - error loading firmware: error = %d", __func__, err);
L
Linus Torvalds 已提交
209 210 211 212
				goto wraperr;
			}
		}
	}
D
David Woodhouse 已提交
213

L
Linus Torvalds 已提交
214 215 216
	/* Assert reset (stop the CPU in the EMI) */
	err = emi62_set_reset(dev,1);
	if (err < 0) {
217
		err("%s - error loading firmware: error = %d", __func__, err);
L
Linus Torvalds 已提交
218 219 220
		goto wraperr;
	}

D
David Woodhouse 已提交
221 222 223 224 225 226
	for (rec = (const struct ihex_binrec *)firmware_fw->data;
	     rec; rec = ihex_next_binrec(rec)) {
		if (INTERNAL_RAM(be32_to_cpu(rec->addr))) {
			err = emi62_writememory(dev, be32_to_cpu(rec->addr),
						rec->data, be16_to_cpu(rec->len),
						ANCHOR_LOAD_EXTERNAL);
L
Linus Torvalds 已提交
227
			if (err < 0) {
228
				err("%s - error loading firmware: error = %d", __func__, err);
L
Linus Torvalds 已提交
229 230 231 232
				goto wraperr;
			}
		}
	}
D
David Woodhouse 已提交
233

L
Linus Torvalds 已提交
234 235 236
	/* De-assert reset (let the CPU run) */
	err = emi62_set_reset(dev,0);
	if (err < 0) {
237
		err("%s - error loading firmware: error = %d", __func__, err);
L
Linus Torvalds 已提交
238 239
		goto wraperr;
	}
240
	msleep(250);	/* let device settle */
L
Linus Torvalds 已提交
241

D
David Woodhouse 已提交
242 243 244 245
	release_firmware(loader_fw);
	release_firmware(bitstream_fw);
	release_firmware(firmware_fw);

L
Linus Torvalds 已提交
246 247 248 249 250 251 252
	kfree(buf);

	/* return 1 to fail the driver inialization
	 * and give real driver change to load */
	return 1;

wraperr:
D
David Woodhouse 已提交
253 254 255 256
	release_firmware(loader_fw);
	release_firmware(bitstream_fw);
	release_firmware(firmware_fw);

L
Linus Torvalds 已提交
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
	kfree(buf);
	dev_err(&dev->dev, "Error\n");
	return err;
}

static __devinitdata struct usb_device_id id_table [] = {
	{ USB_DEVICE(EMI62_VENDOR_ID, EMI62_PRODUCT_ID) },
	{ }                                             /* Terminating entry */
};

MODULE_DEVICE_TABLE (usb, id_table);

static int emi62_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
	struct usb_device *dev = interface_to_usbdev(intf);
	dev_dbg(&intf->dev, "emi62_probe\n");

274
	dev_info(&intf->dev, "%s start\n", __func__);
L
Linus Torvalds 已提交
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309

	emi62_load_firmware(dev);

	/* do not return the driver context, let real audio driver do that */
	return -EIO;
}

static void emi62_disconnect(struct usb_interface *intf)
{
}

static struct usb_driver emi62_driver = {
	.name		= "emi62 - firmware loader",
	.probe		= emi62_probe,
	.disconnect	= emi62_disconnect,
	.id_table	= id_table,
};

static int __init emi62_init (void)
{
	int retval;
	retval = usb_register (&emi62_driver);
	if (retval)
		printk(KERN_ERR "adi-emi: registration failed\n");
	return retval;
}

static void __exit emi62_exit (void)
{
	usb_deregister (&emi62_driver);
}

module_init(emi62_init);
module_exit(emi62_exit);

310
MODULE_AUTHOR("Tapio Laxström");
L
Linus Torvalds 已提交
311 312 313
MODULE_DESCRIPTION("Emagic EMI 6|2m firmware loader.");
MODULE_LICENSE("GPL");

D
David Woodhouse 已提交
314 315 316
MODULE_FIRMWARE("emi62/loader.fw");
MODULE_FIRMWARE("emi62/bitstream.fw");
MODULE_FIRMWARE(FIRMWARE_FW);
L
Linus Torvalds 已提交
317 318
/* vi:ai:syntax=c:sw=8:ts=8:tw=80
 */