[kernel] r14942 - in dists/trunk/firmware-free: . debian debian/bin debian/templates linux-free linux-free/av7110 linux-free/cis linux-free/dsp56k linux-free/keyspan_pda linux-free/usbdux

Ben Hutchings benh at alioth.debian.org
Thu Jan 14 23:13:47 UTC 2010


Author: benh
Date: Thu Jan 14 23:13:43 2010
New Revision: 14942

Log:
New source package for firmware-linux-free.

Added:
   dists/trunk/firmware-free/
   dists/trunk/firmware-free/debian/
   dists/trunk/firmware-free/debian/bin/
   dists/trunk/firmware-free/debian/bin/gencontrol.py   (contents, props changed)
   dists/trunk/firmware-free/debian/changelog
   dists/trunk/firmware-free/debian/compat
   dists/trunk/firmware-free/debian/rules   (contents, props changed)
   dists/trunk/firmware-free/debian/rules.defs
   dists/trunk/firmware-free/debian/rules.real
   dists/trunk/firmware-free/debian/templates/
   dists/trunk/firmware-free/debian/templates/control.binary.in
   dists/trunk/firmware-free/debian/templates/control.binary.udeb.in
   dists/trunk/firmware-free/debian/templates/control.source.in
   dists/trunk/firmware-free/debian/templates/copyright.binary.in
   dists/trunk/firmware-free/debian/templates/postinst.initramfs-tools.in
   dists/trunk/firmware-free/defines
   dists/trunk/firmware-free/linux-free/
   dists/trunk/firmware-free/linux-free/LICENSE
   dists/trunk/firmware-free/linux-free/av7110/
   dists/trunk/firmware-free/linux-free/av7110/Boot.S
   dists/trunk/firmware-free/linux-free/av7110/bootcode.bin   (contents, props changed)
   dists/trunk/firmware-free/linux-free/cis/
   dists/trunk/firmware-free/linux-free/cis/3CCFEM556.cis   (contents, props changed)
   dists/trunk/firmware-free/linux-free/cis/3CXEM556.cis   (contents, props changed)
   dists/trunk/firmware-free/linux-free/cis/COMpad2.cis   (contents, props changed)
   dists/trunk/firmware-free/linux-free/cis/COMpad4.cis   (contents, props changed)
   dists/trunk/firmware-free/linux-free/cis/DP83903.cis   (contents, props changed)
   dists/trunk/firmware-free/linux-free/cis/LA-PCM.cis   (contents, props changed)
   dists/trunk/firmware-free/linux-free/cis/MT5634ZLX.cis   (contents, props changed)
   dists/trunk/firmware-free/linux-free/cis/NE2K.cis   (contents, props changed)
   dists/trunk/firmware-free/linux-free/cis/PCMLM28.cis   (contents, props changed)
   dists/trunk/firmware-free/linux-free/cis/PE-200.cis   (contents, props changed)
   dists/trunk/firmware-free/linux-free/cis/RS-COM-2P.cis   (contents, props changed)
   dists/trunk/firmware-free/linux-free/cis/SW_555_SER.cis   (contents, props changed)
   dists/trunk/firmware-free/linux-free/cis/SW_7xx_SER.cis   (contents, props changed)
   dists/trunk/firmware-free/linux-free/cis/SW_8xx_SER.cis   (contents, props changed)
   dists/trunk/firmware-free/linux-free/cis/tamarack.cis   (contents, props changed)
   dists/trunk/firmware-free/linux-free/defines
   dists/trunk/firmware-free/linux-free/dsp56k/
   dists/trunk/firmware-free/linux-free/dsp56k/bootstrap.asm
   dists/trunk/firmware-free/linux-free/dsp56k/bootstrap.bin   (contents, props changed)
   dists/trunk/firmware-free/linux-free/keyspan_pda/
   dists/trunk/firmware-free/linux-free/keyspan_pda/keyspan_pda.S
   dists/trunk/firmware-free/linux-free/keyspan_pda/keyspan_pda.fw   (contents, props changed)
   dists/trunk/firmware-free/linux-free/keyspan_pda/xircom_pgs.S
   dists/trunk/firmware-free/linux-free/keyspan_pda/xircom_pgs.fw   (contents, props changed)
   dists/trunk/firmware-free/linux-free/usbdux/
   dists/trunk/firmware-free/linux-free/usbdux/Makefile_dux
   dists/trunk/firmware-free/linux-free/usbdux/README.dux
   dists/trunk/firmware-free/linux-free/usbdux/fx2-include.asm
   dists/trunk/firmware-free/linux-free/usbdux/usbdux_firmware.asm
   dists/trunk/firmware-free/linux-free/usbdux/usbduxfast_firmware.asm
   dists/trunk/firmware-free/linux-free/usbdux_firmware.bin   (contents, props changed)
   dists/trunk/firmware-free/linux-free/usbduxfast_firmware.bin   (contents, props changed)

Added: dists/trunk/firmware-free/debian/bin/gencontrol.py
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/firmware-free/debian/bin/gencontrol.py	Thu Jan 14 23:13:43 2010	(r14942)
@@ -0,0 +1,342 @@
+#!/usr/bin/env python
+
+import os, re, sys
+
+sys.path.append(sys.argv[2] + "/lib/python")
+
+from debian_linux.config import ConfigParser, SchemaItemList
+from debian_linux.debian import Package, PackageRelation
+from debian_linux.debian import PackageDescription as PackageDescriptionBase
+import debian_linux.gencontrol
+from debian_linux.gencontrol import Makefile, MakeFlags, PackagesList
+from debian_linux.utils import SortedDict, TextWrapper
+from debian_linux.utils import Templates as TemplatesBase
+
+class PackageDescription(PackageDescriptionBase):
+    __slots__ = ()
+
+    def __init__(self, value = None):
+        self.short = []
+        self.long = []
+        if value is not None:
+            value = value.split("\n", 1)
+            self.append_short(value[0])
+            if len(value) > 1:
+                self.append(value[1])
+
+    def __str__(self):
+        wrap = TextWrapper(width = 74, fix_sentence_endings = True).wrap
+        short = ', '.join(self.short)
+        long_pars = []
+        for t in self.long:
+            if isinstance(t, basestring):
+                t = wrap(t)
+            long_pars.append('\n '.join(t))
+        long = '\n .\n '.join(long_pars)
+        return short + '\n ' + long
+
+    def append_pre(self, l):
+        self.long.append(l)
+
+    def extend(self, desc):
+        if isinstance(desc, PackageDescription):
+            self.short.extend(desc.short)
+            self.long.extend(desc.long)
+        elif isinstance(desc, (list, tuple)):
+            for i in desc:
+                self.append(i)
+
+Package._fields['Description'] = PackageDescription
+
+class Template(dict):
+    _fields = SortedDict((
+        ('Template', str),
+        ('Type', str),
+        ('Default', str),
+        ('Description', PackageDescription),
+    ))
+
+    def __setitem__(self, key, value):
+        try:
+            cls = self._fields[key]
+            if not isinstance(value, cls):
+                value = cls(value)
+        except KeyError: pass
+        super(Template, self).__setitem__(key, value)
+
+    def iterkeys(self):
+        keys = set(self.keys())
+        for i in self._fields.iterkeys():
+            if self.has_key(i):
+                keys.remove(i)
+                yield i
+        for i in keys:
+            yield i
+
+    def iteritems(self):
+        for i in self.iterkeys():
+            yield (i, self[i])
+
+    def itervalues(self):
+        for i in self.iterkeys():
+            yield self[i]
+
+
+class Templates(TemplatesBase):
+    # TODO
+    def _read(self, name):
+        prefix, id = name.split('.', 1)
+
+        for dir in self.dirs:
+            filename = "%s/%s.in" % (dir, name)
+            if os.path.exists(filename):
+                f = file(filename)
+                if prefix == 'control':
+                    return self._read_control(f)
+                elif prefix == 'templates':
+                    return self._read_templates(f)
+                return f.read()
+
+    def _read_templates(self, f):
+        entries = []
+
+        while True:
+            e = Template()
+            last = None
+            lines = []
+            while True:
+                line = f.readline()
+                if not line:
+                    break
+                line = line.strip('\n')
+                if not line:
+                    break
+                if line[0] in ' \t':
+                    if not last:
+                        raise ValueError('Continuation line seen before first header')
+                    lines.append(line.lstrip())
+                    continue
+                if last:
+                    e[last] = '\n'.join(lines)
+                i = line.find(':')
+                if i < 0:
+                    raise ValueError("Not a header, not a continuation: ``%s''" % line)
+                last = line[:i]
+                lines = [line[i+1:].lstrip()]
+            if last:
+                e[last] = '\n'.join(lines)
+            if not e:
+                break
+
+            entries.append(e)
+
+        return entries
+
+
+class GenControl(debian_linux.gencontrol.Gencontrol):
+    def __init__(self, kernelversion):
+        self.config = Config()
+        self.templates = Templates()
+        self.kernelversion = kernelversion
+
+    def __call__(self):
+        packages = PackagesList()
+        makefile = Makefile()
+
+        self.do_source(packages)
+        self.do_main(packages, makefile)
+
+        self.write(packages, makefile)
+
+    def do_source(self, packages):
+        source = self.templates["control.source"]
+        packages['source'] = self.process_package(source[0], ())
+        packages['source']['Build-Depends'].append('linux-support-%s' % self.kernelversion)
+
+    def do_main(self, packages, makefile):
+        config_entry = self.config['base',]
+        vars = {}
+        vars.update(config_entry)
+
+        makeflags = MakeFlags()
+
+        for i in ('build', 'binary-arch', 'setup'):
+            makefile.add("%s_%%" % i, cmds = ["@true"])
+
+        for package in config_entry['packages']:
+            self.do_package(packages, makefile, package, vars.copy(), makeflags.copy())
+
+    def do_package(self, packages, makefile, package, vars, makeflags):
+        config_entry = self.config['base', package]
+        vars.update(config_entry)
+        vars['package'] = package
+
+        makeflags['PACKAGE'] = package
+
+        binary = self.templates["control.binary"]
+        copyright = self.templates["copyright.binary"]
+
+        if os.path.exists('%s/copyright' % package):
+            f = open('%s/copyright' % package)
+            open("debian/firmware-%s.copyright" % package, 'w').write(f.read())
+        else:
+            vars['license'] = file("%s/LICENSE" % package).read()
+            file("debian/firmware-%s.copyright" % package, 'w').write(self.substitute(copyright, vars))
+
+        files_orig = config_entry['files']
+        files_real = {}
+
+        for root, dirs, files in os.walk(package):
+            try:
+                dirs.remove('.svn')
+            except ValueError:
+                pass
+            for f in files:
+                f1  = f.rsplit('-', 1)
+                if root != package:
+                    f = root[len(package) + 1 : ] + '/' + f
+                if f in files_orig:
+                    files_real[f] = f, f, None
+                elif len(f1) > 1:
+                    f_base, f_version = f1
+                    if f_base in files_orig:
+                        if f_base in files_real:
+                            raise RuntimeError("Multiple files for %s" % f_base)
+                        files_real[f_base] = f_base, f, f_version
+
+        makeflags['FILES'] = ' '.join(["%s:%s" % (i[1], i[0]) for i in files_real.itervalues()])
+        vars['files_real'] = ' '.join(["/lib/firmware/%s" % i for i in config_entry['files']])
+
+        files_desc = ["Contents:"]
+
+        for f in config_entry['files']:
+            f, f_real, version = files_real[f]
+            c = self.config.get(('base', package, f), {})
+            desc = c.get('desc')
+            if version is None:
+                version = c.get('version')
+            if desc and version:
+                files_desc.append(" * %s, version %s (%s)" % (desc, version, f))
+            elif desc:
+                files_desc.append(" * %s (%s)" % (desc, f))
+            else:
+                files_desc.append(" * %s" % f)
+
+        packages_binary = self.process_packages(binary, vars)
+
+        packages_binary[0]['Description'].append_pre(files_desc)
+
+        if 'initramfs-tools' in config_entry.get('support', []):
+            postinst = self.templates['postinst.initramfs-tools']
+            file("debian/firmware-%s.postinst" % package, 'w').write(self.substitute(postinst, vars))
+
+        if 'license-accept' in config_entry:
+            license = file("%s/LICENSE.install" % package).read()
+            preinst = self.templates['preinst.license']
+            preinst_filename = "debian/firmware-%s.preinst" % package
+            file(preinst_filename, 'w').write(self.substitute(preinst, vars))
+
+            templates = self.process_templates(self.templates['templates.license'], vars)
+            license_split = re.split(r'\n\s*\n', license)
+            templates[0]['Description'].extend(license_split)
+            templates_filename = "debian/firmware-%s.templates" % package
+            self.write_rfc822(file(templates_filename, 'w'), templates)
+
+            desc = packages_binary[0]['Description']
+            desc.append(
+"""This firmware is covered by the %s.
+You must agree to the terms of this license before it is installed."""
+% vars['license-title'])
+            packages_binary[0]['Pre-Depends'] = PackageRelation('debconf | debconf-2.0')
+
+        packages.extend(packages_binary)
+
+        makefile.add('binary-indep', cmds = ["$(MAKE) -f debian/rules.real binary-indep %s" % makeflags])
+
+    def process_template(self, in_entry, vars):
+        e = Template()
+        for key, value in in_entry.iteritems():
+            if isinstance(value, PackageDescription):
+                e[key] = self.process_description(value, vars)
+            elif key[:2] == 'X-':
+                pass
+            else:
+                e[key] = self.substitute(value, vars)
+        return e
+
+    def process_templates(self, in_entries, vars):
+        entries = []
+        for i in in_entries:
+            entries.append(self.process_template(i, vars))
+        return entries
+
+    def substitute(self, s, vars):
+        if isinstance(s, (list, tuple)):
+            return [self.substitute(i, vars) for i in s]
+        def subst(match):
+            if match.group(1):
+                return vars.get(match.group(2), '')
+            else:
+                return vars[match.group(2)]
+        return re.sub(r'@(\??)([-_a-z]+)@', subst, s)
+
+    def write(self, packages, makefile):
+        self.write_control(packages.itervalues())
+        self.write_makefile(makefile)
+
+    def write_control(self, list):
+        self.write_rfc822(file("debian/control", 'w'), list)
+
+    def write_makefile(self, makefile):
+        f = file("debian/rules.gen", 'w')
+        makefile.write(f)
+        f.close()
+
+    def write_rfc822(self, f, list):
+        for entry in list:
+            for key, value in entry.iteritems():
+                f.write("%s: %s\n" % (key, value))
+            f.write('\n')
+
+class Config(dict):
+    config_name = "defines"
+
+    schemas = {
+        'base': {
+            'files': SchemaItemList(),
+            'packages': SchemaItemList(),
+            'support': SchemaItemList(),
+        }
+    }
+
+    def __init__(self):
+        self._read_base()
+
+    def _read_base(self):
+        config = ConfigParser(self.schemas)
+        config.read(self.config_name)
+
+        packages = config['base',]['packages']
+
+        for section in iter(config):
+            real = (section[-1],) + section[:-1]
+            self[real] = config[section]
+
+        for package in packages:
+            self._read_package(package)
+
+    def _read_package(self, package):
+        config = ConfigParser(self.schemas)
+        config.read("%s/%s" % (package, self.config_name))
+
+        for section in iter(config):
+            if len(section) > 1:
+                real = (section[-1], package, '_'.join(section[:-1]))
+            else:
+                real = (section[-1], package)
+            s = self.get(real, {})
+            s.update(config[section])
+            self[real] = s
+
+if __name__ == '__main__':
+    GenControl(sys.argv[1])()

Added: dists/trunk/firmware-free/debian/changelog
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/firmware-free/debian/changelog	Thu Jan 14 23:13:43 2010	(r14942)
@@ -0,0 +1,6 @@
+firmware-free (2.6.32.1) UNRELEASED; urgency=low
+
+  * Initial release.  Replaces firmware-linux-free built from the
+    linux-2.6 source package.
+
+ -- Ben Hutchings <ben at decadent.org.uk>  Thu, 14 Jan 2010 23:06:31 +0000

Added: dists/trunk/firmware-free/debian/compat
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/firmware-free/debian/compat	Thu Jan 14 23:13:43 2010	(r14942)
@@ -0,0 +1 @@
+5

Added: dists/trunk/firmware-free/debian/rules
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/firmware-free/debian/rules	Thu Jan 14 23:13:43 2010	(r14942)
@@ -0,0 +1,17 @@
+#!/usr/bin/make -f
+SHELL := sh -e
+
+CONTROL_FILES += debian/bin/gencontrol.py defines $(wildcard */defines) $(wildcard */copyright) $(wildcard */LICENSE*)
+
+include debian/rules.defs
+include /usr/src/linux-support-$(KERNELVERSION)/modules/rules.include
+
+GENCONTROL = debian/bin/gencontrol.py $(KERNELVERSION)
+
+maintainerclean:
+	-rm debian/control debian/control.md5sum debian/rules.gen
+	-rm debian/*.copyright
+	-rm debian/*.hook.*
+	-rm debian/*.preinst
+	-rm debian/*.postinst
+	-rm debian/*.templates

Added: dists/trunk/firmware-free/debian/rules.defs
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/firmware-free/debian/rules.defs	Thu Jan 14 23:13:43 2010	(r14942)
@@ -0,0 +1 @@
+KERNELVERSION := 2.6.32-trunk

Added: dists/trunk/firmware-free/debian/rules.real
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/firmware-free/debian/rules.real	Thu Jan 14 23:13:43 2010	(r14942)
@@ -0,0 +1,36 @@
+SHELL  := sh -e
+DEB_HOST_ARCH     := $(shell dpkg-architecture -a$(ARCH) -qDEB_HOST_ARCH)
+DEB_HOST_GNU_TYPE := $(shell dpkg-architecture -a$(ARCH) -qDEB_HOST_GNU_TYPE)
+DEB_BUILD_ARCH    := $(shell dpkg-architecture -a$(ARCH) -qDEB_BUILD_ARCH)
+
+export DH_OPTIONS
+
+include debian/rules.defs
+include /usr/src/linux-support-$(KERNELVERSION)/modules/rules.real.include
+
+#
+# Targets
+#
+binary-indep: install
+
+install: PACKAGE_NAME = firmware-$(PACKAGE)
+install: DH_OPTIONS = -p$(PACKAGE_NAME)
+install:
+	dh_testdir
+	dh_testroot
+	@for i in $(FILES); do \
+	  s=$(PACKAGE)/"$${i%:*}"; \
+	  d=/lib/firmware/"$${i#*:}"; \
+	  echo install -m644 -D "$$s" debian/$(PACKAGE_NAME)"$$d"; \
+	  install -m644 -D "$$s" debian/$(PACKAGE_NAME)"$$d"; \
+	done
+	dh_installchangelogs
+	dh_installdocs
+	dh_installdebconf
+	dh_link
+	dh_compress
+	dh_fixperms
+	dh_installdeb
+	dh_gencontrol
+	dh_md5sums
+	dh_builddeb

Added: dists/trunk/firmware-free/debian/templates/control.binary.in
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/firmware-free/debian/templates/control.binary.in	Thu Jan 14 23:13:43 2010	(r14942)
@@ -0,0 +1,9 @@
+Package: firmware- at package@
+Architecture: all
+Replaces: @?replaces@
+Conflicts: @?conflicts@
+Suggests: initramfs-tools, linux-image
+Description: Binary firmware for @desc@
+ @longdesc@
+Homepage: @uri@
+

Added: dists/trunk/firmware-free/debian/templates/control.binary.udeb.in
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/firmware-free/debian/templates/control.binary.udeb.in	Thu Jan 14 23:13:43 2010	(r14942)
@@ -0,0 +1,6 @@
+Package: firmware- at package@-di
+XC-Package-Type: udeb
+Architecture: all
+Section: non-free/debian-installer
+Description: Binary firmware for @desc@
+

Added: dists/trunk/firmware-free/debian/templates/control.source.in
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/firmware-free/debian/templates/control.source.in	Thu Jan 14 23:13:43 2010	(r14942)
@@ -0,0 +1,9 @@
+Source: firmware-free
+Section: kernel
+Priority: optional
+Maintainer: Debian Kernel Team <debian-kernel at lists.debian.org>
+Uploaders: Bastian Blank <waldi at debian.org>, Frederik Schüler <fs at debian.org>, Steve Langasek <vorlon at debian.org>, dann frazier <dannf at debian.org>, maximilian attems <maks at debian.org>, Ben Hutchings <ben at decadent.org.uk>
+Build-Depends: debhelper (>= 5)
+Standards-Version: 3.8.1
+Vcs-Browser: http://svn.debian.org/wsvn/kernel/dists/trunk/firmware-free/
+Vcs-Svn: svn://svn.debian.org/kernel/dists/trunk/firmware-free/

Added: dists/trunk/firmware-free/debian/templates/copyright.binary.in
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/firmware-free/debian/templates/copyright.binary.in	Thu Jan 14 23:13:43 2010	(r14942)
@@ -0,0 +1,3 @@
+The firmware and its source code may be downloaded from @uri at .
+
+ at license@

Added: dists/trunk/firmware-free/debian/templates/postinst.initramfs-tools.in
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/firmware-free/debian/templates/postinst.initramfs-tools.in	Thu Jan 14 23:13:43 2010	(r14942)
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+set -e
+
+case "$1" in
+	configure)
+		if [ -x /usr/sbin/update-initramfs -a -e /etc/initramfs-tools/initramfs.conf ] ; then
+			update-initramfs -u
+		fi
+	;;
+
+	abort-upgrade|abort-remove|abort-deconfigure)
+	;;
+
+	*)
+		echo "postinst called with unknown argument \`$1'" 1>&2
+		exit 1
+	;;
+esac
+
+#DEBHELPER#

Added: dists/trunk/firmware-free/defines
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/firmware-free/defines	Thu Jan 14 23:13:43 2010	(r14942)
@@ -0,0 +1,3 @@
+[base]
+packages:
+ linux-free

Added: dists/trunk/firmware-free/linux-free/LICENSE
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/firmware-free/linux-free/LICENSE	Thu Jan 14 23:13:43 2010	(r14942)
@@ -0,0 +1,90 @@
+--------------------------------------------------------------------------
+
+Driver: dsp56k - Atari DSP56k support
+
+File: dsp56k/bootstrap.bin
+Source: dsp56k/bootstrap.asm
+
+Licence: GPLv2 or later
+
+DSP56001 assembler, possibly buildable with a56 from 
+http://www.zdomain.com/a56.html
+
+--------------------------------------------------------------------------
+
+Driver: pcnet_cs - NE2000 compatible PCMCIA adapter
+
+File: cis/LA-PCM.cis
+File: cis/PCMLM28.cis
+File: cis/DP83903.cis
+File: cis/NE2K.cis
+File: cis/tamarack.cis
+File: cis/PE-200.cis
+
+Licence: GPL
+
+Originally developed by the pcmcia-cs project
+
+--------------------------------------------------------------------------
+
+Driver: 3c589_cs - 3Com PCMCIA adapter
+
+File: cis/3CXEM556.cis
+
+Licence: GPL
+
+Originally developed by the pcmcia-cs project
+
+--------------------------------------------------------------------------
+
+Driver: 3c574_cs - 3Com PCMCIA adapter
+
+File: cis/3CCFEM556.cis
+
+Licence: GPL
+
+Originally developed by the pcmcia-cs project
+
+--------------------------------------------------------------------------
+
+Driver: serial_cs - Serial PCMCIA adapter
+
+File: cis/MT5634ZLX.cis
+File: cis/RS-COM-2P.cis
+File: cis/COMpad2.cis
+File: cis/COMpad4.cis
+File: cis/SW_555_SER.cis
+File: cis/SW_7xx_SER.cis
+File: cis/SW_8xx_SER.cis
+
+Licence: GPL
+
+Originally developed by the pcmcia-cs project
+
+--------------------------------------------------------------------------
+
+Driver: dvb-ttpci -- AV7110 cards
+
+File: av7110/bootcode.bin
+Source: av7110/Boot.S
+
+Licence: GPLv2 or later
+
+--------------------------------------------------------------------------
+
+Driver: usbdux/usbduxfast - usbdux data acquisition cards
+
+File: usbdux_firmware.bin
+File: usbduxfast_firmware.bin
+Source: usbdux/fx2-include.asm
+Source: usbdux/usbduxfast_firmware.asm
+Source: usbdux/usbdux_firmware.asm
+
+Licence: GPLv2. See source code in usbdux/ subdirectory.
+
+Provided from the author, Bernd Porr <BerndPorr at f2s.com>
+
+--------------------------------------------------------------------------
+
+On Debian systems the text of the GPL version 2 can be found in
+/usr/share/common-licenses/GPL-2.

Added: dists/trunk/firmware-free/linux-free/av7110/Boot.S
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/firmware-free/linux-free/av7110/Boot.S	Thu Jan 14 23:13:43 2010	(r14942)
@@ -0,0 +1,109 @@
+/*
+   Boot.S: boot loader for Siemens DVB-S card
+
+   Copyright (C) 2001 Convergence integrated media GmbH
+	              Written by Ralph Metzler
+		                 <rjkm at convergence.de>
+   Copyright (C) 2006 Matthieu CASTET <castet.mattheiu at free.fr>
+
+   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.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
+
+*/
+
+/*
+	check AV711x_3_1.pdf for some hardware infos
+	build it with :
+	$ cc -mbig-endian -c Boot.S
+	$ ld -Ttext 0x2c000000 -EB -o Boot Boot.o
+	$ objcopy -Obinary Boot
+*/
+
+	.text
+	.align
+	.globl _start
+_start:
+	b reset			// reset vector
+	movs  pc, r14           // undefined
+	subs  pc, r14, #4       // SWI
+	subs  pc, r14, #4       // prefetch abort
+	subs  pc, r14, #8       // data abort
+	subs  pc, r14, #4       // reserved
+	subs  pc, r14, #4       // IRQ
+	subs  pc, r14, #4       // FIQ
+
+	.word tbl               // table needed by firmware ROM
+tbl:	.word (endtbl - tbl)
+	.word 0
+  	.word conf
+endtbl:	.word 0
+conf:	.word 0xa5a55a5a
+	.word 0x001f1555
+	.word 0x00000009
+
+reset:	ldr	r13, buffer
+	ldr	r4, flag
+	mov	r0, #0
+	str	r0, [r4]
+	str	r0, [r4, #4]
+
+	ldr		r1, wait_address
+	ldr		r2, flag_address
+	ldr		r3, sram
+
+copycode: // copy the code HW Sram
+	ldmia	r1!, {r5-r12}
+	stmia	r3!, {r5-r12}
+	cmp		r1, r2
+	ble 	copycode
+	ldr		pc, sram // jump to the copied code
+
+wait:	ldrh	r1, [r4]        // wait for flag!=0
+ 	cmp	r1, #0
+	beq	wait
+
+	mov	r1, r13         // buffer address
+ 	ldr	r3, [r4,#4]     // destaddr
+
+ 	ldrh	r2, [r4,#2]     // get segment length
+	add     r2, r2, #63     // round length to next 64 bytes
+	movs	r2, r2, lsr #6  // and divide by 64
+	moveq	r0, #2          // if 0, set flag to 2, else signal
+	strh	r0, [r4]        // that buffer is accepted by setting to 0
+        beq wait
+	
+copyloop:
+	ldmia	r1!, {r5-r12}
+	stmia	r3!, {r5-r12}
+	ldmia	r1!, {r5-r12}
+	stmia	r3!, {r5-r12}
+ 	subs	r2, r2, #1
+ 	bne	copyloop
+
+	eor     r13, r13, #0x1400    // switch to other buffer
+	b	wait
+
+// flag is stored at 0x2c0003f8, length at 0x2c0003fa,
+// destaddr at 0x2c0003fc
+
+flag:	.word	0x2c0003f8
+
+
+// buffer 1 is at 0x2c000400, buffer 2 at 0x2c001000
+
+buffer:	.word	0x2c000400
+
+sram: .word   0x9e000800
+wait_address: .word   wait
+flag_address: .word   flag

Added: dists/trunk/firmware-free/linux-free/av7110/bootcode.bin
==============================================================================
Binary file. No diff available.

Added: dists/trunk/firmware-free/linux-free/cis/3CCFEM556.cis
==============================================================================
Binary file. No diff available.

Added: dists/trunk/firmware-free/linux-free/cis/3CXEM556.cis
==============================================================================
Binary file. No diff available.

Added: dists/trunk/firmware-free/linux-free/cis/COMpad2.cis
==============================================================================
Binary file. No diff available.

Added: dists/trunk/firmware-free/linux-free/cis/COMpad4.cis
==============================================================================
Binary file. No diff available.

Added: dists/trunk/firmware-free/linux-free/cis/DP83903.cis
==============================================================================
Binary file. No diff available.

Added: dists/trunk/firmware-free/linux-free/cis/LA-PCM.cis
==============================================================================
Binary file. No diff available.

Added: dists/trunk/firmware-free/linux-free/cis/MT5634ZLX.cis
==============================================================================
Binary file. No diff available.

Added: dists/trunk/firmware-free/linux-free/cis/NE2K.cis
==============================================================================
Binary file. No diff available.

Added: dists/trunk/firmware-free/linux-free/cis/PCMLM28.cis
==============================================================================
Binary file. No diff available.

Added: dists/trunk/firmware-free/linux-free/cis/PE-200.cis
==============================================================================
Binary file. No diff available.

Added: dists/trunk/firmware-free/linux-free/cis/RS-COM-2P.cis
==============================================================================
Binary file. No diff available.

Added: dists/trunk/firmware-free/linux-free/cis/SW_555_SER.cis
==============================================================================
Binary file. No diff available.

Added: dists/trunk/firmware-free/linux-free/cis/SW_7xx_SER.cis
==============================================================================
Binary file. No diff available.

Added: dists/trunk/firmware-free/linux-free/cis/SW_8xx_SER.cis
==============================================================================
Binary file. No diff available.

Added: dists/trunk/firmware-free/linux-free/cis/tamarack.cis
==============================================================================
Binary file. No diff available.

Added: dists/trunk/firmware-free/linux-free/defines
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/firmware-free/linux-free/defines	Thu Jan 14 23:13:43 2010	(r14942)
@@ -0,0 +1,95 @@
+[base]
+desc: various drivers in the Linux kernel
+longdesc:
+ This package contains firmware which was previously included in the
+ Linux kernel and which is compliant with the Debian Free Software
+ Guidelines.
+ .
+ Most firmware previously included in the Linux kernel is non-free
+ and has been moved to the firmware-linux-nonfree package.
+files:
+ av7110/bootcode.bin
+ cis/3CCFEM556.cis
+ cis/3CXEM556.cis
+ cis/COMpad2.cis
+ cis/COMpad4.cis
+ cis/DP83903.cis
+ cis/LA-PCM.cis
+ cis/MT5634ZLX.cis
+ cis/NE2K.cis
+ cis/PCMLM28.cis
+ cis/PE-200.cis
+ cis/RS-COM-2P.cis
+ cis/SW_555_SER.cis
+ cis/SW_7xx_SER.cis
+ cis/SW_8xx_SER.cis
+ cis/tamarack.cis
+ dsp56k/bootstrap.bin
+ keyspan_pda/keyspan_pda.fw
+ keyspan_pda/xircom_pgs.fw
+ usbdux_firmware.bin
+ usbduxfast_firmware.bin
+uri: http://git.kernel.org/?p=linux/kernel/git/dwmw2/linux-firmware.git
+
+[av7110/bootcode.bin_base]
+desc: AV7110 DVB card firmware
+
+[cis/3CCFEM556.cis_base]
+desc: 3Com Megahertz 3CCFEM556 CIS fix
+
+[cis/3CXEM556.cis_base]
+desc: 3Com Megahertz 3CXEM556 CIS fix
+
+[cis/COMpad2.cis_base]
+desc: Advantech COMpad-32/85 CIS fix
+
+[cis/COMpad4.cis_base]
+desc: Advantech COMpad-32/85B-4 CIS fix
+
+[cis/DP83903.cis_base]
+desc: NSC DP83903 PCMCIA Ethernet card CIS fix
+
+[cis/LA-PCM.cis_base]
+desc: Allied Telesis LA-PCM CIS fix
+
+[cis/MT5634ZLX.cis_base]
+desc: MultiTech PCMCIA 56K DataFax CIS fix
+
+[cis/NE2K.cis_base]
+desc: NDC PCMCIA Ethernet card CIS fix
+
+[cis/PCMLM28.cis_base]
+desc: EN2218-LAN/MODEM CIS fix
+
+[cis/PE-200.cis_base]
+desc: PreMax PE-200 CIS fix
+
+[cis/RS-COM-2P.cis_base]
+desc: RS-COM 2P CIS fix
+
+[cis/SW_555_SER.cis_base]
+desc: Sierra Aircard 555 CIS fix
+
+[cis/SW_7xx_SER.cis_base]
+desc: Sierra Wireless AC710/AC750 CIS fix
+
+[cis/SW_8xx_SER.cis_base]
+desc: Sierra Wireless AC850/AC860 CIS fix
+
+[cis/tamarack.cis_base]
+desc: Tamarack PCMCIA Ethernet card CIS fix
+
+[dsp56k/bootstrap.bin_base]
+desc: Atari Falcon DSP56001 firmware
+
+[keyspan_pda/keyspan_pda.fw_base]
+desc: Keyspan USA-19 firmware
+
+[keyspan_pda/xircom_pgs.fw_base]
+desc: Xircom PGSDB9/Entrega PortGear firmware
+
+[usbdux_firmware.bin_base]
+desc: USB-DUX firmware
+
+[usbduxfast_firmware.bin_base]
+desc: USB-DUXfast firmware

Added: dists/trunk/firmware-free/linux-free/dsp56k/bootstrap.asm
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/firmware-free/linux-free/dsp56k/bootstrap.asm	Thu Jan 14 23:13:43 2010	(r14942)
@@ -0,0 +1,98 @@
+; Author: Frederik Noring <noring at nocrew.org>
+;
+; This file is subject to the terms and conditions of the GNU General Public
+; License.  See the file COPYING in the main directory of this archive
+; for more details.
+
+; DSP56k loader
+
+; Host Interface
+M_BCR   EQU     $FFFE           ; Port A Bus Control Register
+M_PBC   EQU     $FFE0           ; Port B Control Register
+M_PBDDR EQU     $FFE2           ; Port B Data Direction Register
+M_PBD   EQU     $FFE4           ; Port B Data Register
+M_PCC   EQU     $FFE1           ; Port C Control Register
+M_PCDDR EQU     $FFE3           ; Port C Data Direction Register
+M_PCD   EQU     $FFE5           ; Port C Data Register
+
+M_HCR   EQU     $FFE8           ; Host Control Register
+M_HSR   EQU     $FFE9           ; Host Status Register
+M_HRX   EQU     $FFEB           ; Host Receive Data Register
+M_HTX   EQU     $FFEB           ; Host Transmit Data Register
+
+; SSI, Synchronous Serial Interface
+M_RX    EQU     $FFEF           ; Serial Receive Data Register
+M_TX    EQU     $FFEF           ; Serial Transmit Data Register
+M_CRA   EQU     $FFEC           ; SSI Control Register A
+M_CRB   EQU     $FFED           ; SSI Control Register B
+M_SR    EQU     $FFEE           ; SSI Status Register
+M_TSR   EQU     $FFEE           ; SSI Time Slot Register
+
+; Exception Processing
+M_IPR   EQU     $FFFF           ; Interrupt Priority Register
+
+        org     P:$0
+start   jmp     <$40
+
+        org     P:$40
+;       ; Zero 16384 DSP X and Y words
+;       clr     A #0,r0
+;       clr     B #0,r4
+;       do      #64,<_block1
+;       rep     #256
+;       move    A,X:(r0)+ B,Y:(r4)+
+;_block1        ; Zero (32768-512) Program words
+;       clr     A #512,r0
+;       do      #126,<_block2
+;       rep     #256
+;       move    A,P:(r0)+
+;_block2
+
+        ; Copy DSP program control
+        move    #real,r0
+        move    #upload,r1
+        do      #upload_end-upload,_copy
+        movem    P:(r0)+,x0
+        movem    x0,P:(r1)+
+_copy   movep   #4,X:<<M_HCR
+        movep   #$c00,X:<<M_IPR
+        and     #<$fe,mr
+        jmp     upload
+
+real
+        org     P:$7ea9
+upload
+        movep   #1,X:<<M_PBC
+        movep   #0,X:<<M_BCR
+
+next    jclr    #0,X:<<M_HSR,*
+        movep   X:<<M_HRX,A
+        move    #>3,x0
+        cmp     x0,A #>1,x0
+        jeq     <$0
+_get_address
+        jclr    #0,X:<<M_HSR,_get_address
+        movep   X:<<M_HRX,r0
+_get_length
+        jclr    #0,X:<<M_HSR,_get_length
+        movep   X:<<M_HRX,y0
+        cmp     x0,A #>2,x0
+        jeq     load_X
+        cmp     x0,A
+        jeq     load_Y
+
+load_P  do      y0,_load_P
+        jclr    #0,X:<<M_HSR,*
+        movep   X:<<M_HRX,P:(r0)+
+_load_P jmp     next
+load_X  do      y0,_load_X
+        jclr    #0,X:<<M_HSR,*
+        movep   X:<<M_HRX,X:(r0)+
+_load_X jmp     next
+load_Y  do      y0,_load_Y
+        jclr    #0,X:<<M_HSR,*
+        movep   X:<<M_HRX,Y:(r0)+
+_load_Y jmp     next
+
+upload_end
+        end

Added: dists/trunk/firmware-free/linux-free/dsp56k/bootstrap.bin
==============================================================================
Binary file. No diff available.

Added: dists/trunk/firmware-free/linux-free/keyspan_pda/keyspan_pda.S
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/firmware-free/linux-free/keyspan_pda/keyspan_pda.S	Thu Jan 14 23:13:43 2010	(r14942)
@@ -0,0 +1,1124 @@
+/*  $Id: loop.s,v 1.23 2000/03/20 09:49:06 warner Exp $
+ * 
+ *  Firmware for the Keyspan PDA Serial Adapter, a USB serial port based on
+ *  the EzUSB microcontroller.
+ * 
+ *  (C) Copyright 2000 Brian Warner <warner at lothar.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.
+ * 
+ *  "Keyspan PDA Serial Adapter" is probably a copyright of Keyspan, the
+ *  company.
+ * 
+ *  This serial adapter is basically an EzUSB chip and an RS-232 line driver
+ *  in a little widget that has a DB-9 on one end and a USB plug on the other.
+ *  It uses the EzUSB's internal UART0 (using the pins from Port C) and timer2
+ *  as a baud-rate generator. The wiring is:
+ *   PC0/RxD0 <- rxd (DB9 pin 2)         PC4 <- dsr pin 6
+ *   PC1/TxD0 -> txd pin 3               PC5 <- ri  pin 9
+ *   PC2      -> rts pin 7               PC6 <- dcd pin 1
+ *   PC3      <- cts pin 8               PC7 -> dtr pin 4
+ *   PB1 -> line driver standby
+ *
+ *  The EzUSB register constants below come from their excellent documentation
+ *  and sample code (which used to be available at www.anchorchips.com, but
+ *  that has now been absorbed into Cypress' site and the CD-ROM contents
+ *  don't appear to be available online anymore). If we get multiple
+ *  EzUSB-based drivers into the kernel, it might be useful to pull them out
+ *  into a separate .h file.
+ * 
+ * THEORY OF OPERATION:
+ *
+ *   There are two 256-byte ring buffers, one for tx, one for rx.
+ *
+ *   EP2out is pure tx data. When it appears, the data is copied into the tx
+ *   ring and serial transmission is started if it wasn't already running. The
+ *   "tx buffer empty" interrupt may kick off another character if the ring
+ *   still has data. If the host is tx-blocked because the ring filled up,
+ *   it will request a "tx unthrottle" interrupt. If sending a serial character
+ *   empties the ring below the desired threshold, we set a bit that will send
+ *   up the tx unthrottle message as soon as the rx buffer becomes free.
+ *
+ *   EP2in (interrupt) is used to send both rx chars and rx status messages
+ *   (only "tx unthrottle" at this time) back up to the host. The first byte
+ *   of the rx message indicates data (0) or status msg (1). Status messages
+ *   are sent before any data.
+ *
+ *   Incoming serial characters are put into the rx ring by the serial
+ *   interrupt, and the EP2in buffer sent if it wasn't already in transit.
+ *   When the EP2in buffer returns, the interrupt prompts us to send more
+ *   rx chars (or status messages) if they are pending.
+ *
+ *   Device control happens through "vendor specific" control messages on EP0.
+ *   All messages are destined for the "Interface" (with the index always 0,
+ *   so that if their two-port device might someday use similar firmware, we
+ *   can use index=1 to refer to the second port). The messages defined are:
+ *
+ *    bRequest = 0 : set baud/bits/parity
+ *               1 : unused
+ *               2 : reserved for setting HW flow control (CTSRTS)
+ *               3 : get/set "modem info" (pin states: DTR, RTS, DCD, RI, etc)
+ *               4 : set break (on/off)
+ *               5 : reserved for requesting interrupts on pin state change
+ *               6 : query buffer room or chars in tx buffer
+ *               7 : request tx unthrottle interrupt
+ *
+ *  The host-side driver is set to recognize the device ID values stashed in
+ *  serial EEPROM (0x06cd, 0x0103), program this firmware into place, then
+ *  start it running. This firmware will use EzUSB's "renumeration" trick by
+ *  simulating a bus disconnect, then reconnect with a different device ID
+ *  (encoded in the desc_device descriptor below). The host driver then
+ *  recognizes the new device ID and glues it to the real serial driver code.
+ *
+ * USEFUL DOCS:
+ *  EzUSB Technical Reference Manual: <http://www.anchorchips.com>
+ *  8051 manuals: everywhere, but try www.dalsemi.com because the EzUSB is
+ *   basically the Dallas enhanced 8051 code. Remember that the EzUSB IO ports
+ *   use totally different registers!
+ *  USB 1.1 spec: www.usb.org
+ *
+ * HOW TO BUILD:
+ *  gcc -x assembler-with-cpp -P -E -o keyspan_pda.asm keyspan_pda.s
+ *  as31 -l keyspan_pda.asm
+ *  mv keyspan_pda.obj keyspan_pda.hex
+ *  perl ezusb_convert.pl keyspan_pda < keyspan_pda.hex > keyspan_pda_fw.h
+ * Get as31 from <http://www.pjrc.com/tech/8051/index.html>, and hack on it
+ * a bit to make it build.
+ *
+ * THANKS:
+ *  Greg Kroah-Hartman, for coordinating the whole usb-serial thing.
+ *  AnchorChips, for making such an incredibly useful little microcontroller.
+ *  KeySpan, for making a handy, cheap ($40) widget that was so easy to take
+ *           apart and trace with an ohmmeter.
+ *
+ * TODO:
+ *  lots. grep for TODO. Interrupt safety needs stress-testing. Better flow
+ *  control. Interrupting host upon change in DCD, etc, counting transitions.
+ *  Need to find a safe device id to use (the one used by the Keyspan firmware
+ *  under Windows would be ideal.. can anyone figure out what it is?). Parity.
+ *  More baud rates. Oh, and the string-descriptor-length silicon bug
+ *  workaround should be implemented, but I'm lazy, and the consequence is
+ *  that the device name strings that show up in your kernel log will have
+ *  lots of trailing binary garbage in them (appears as ????). Device strings
+ *  should be made more accurate.
+ *
+ * Questions, bugs, patches to Brian.
+ *
+ *  -Brian Warner <warner at lothar.com>
+ *
+ */
+	
+#define HIGH(x) (((x) & 0xff00) / 256)
+#define LOW(x) ((x) & 0xff)
+
+#define dpl1 0x84
+#define dph1 0x85
+#define dps 0x86
+
+;;; our bit assignments
+#define TX_RUNNING 0
+#define DO_TX_UNTHROTTLE 1
+	
+	;; stack from 0x60 to 0x7f: should really set SP to 0x60-1, not 0x60
+#define STACK #0x60-1
+
+#define EXIF 0x91
+#define EIE 0xe8
+	.flag EUSB, EIE.0
+	.flag ES0, IE.4
+
+#define EP0CS #0x7fb4
+#define EP0STALLbit #0x01
+#define IN0BUF #0x7f00
+#define IN0BC #0x7fb5
+#define OUT0BUF #0x7ec0
+#define OUT0BC #0x7fc5		
+#define IN2BUF #0x7e00
+#define IN2BC #0x7fb9
+#define IN2CS #0x7fb8
+#define OUT2BC #0x7fc9
+#define OUT2CS #0x7fc8
+#define OUT2BUF #0x7dc0
+#define IN4BUF #0x7d00
+#define IN4BC #0x7fbd
+#define IN4CS #0x7fbc
+#define OEB #0x7f9d
+#define OUTB #0x7f97
+#define OEC #0x7f9e
+#define OUTC #0x7f98
+#define PINSC #0x7f9b
+#define PORTCCFG #0x7f95
+#define IN07IRQ #0x7fa9
+#define OUT07IRQ #0x7faa
+#define IN07IEN #0x7fac
+#define OUT07IEN #0x7fad
+#define USBIRQ #0x7fab
+#define USBIEN #0x7fae
+#define USBBAV #0x7faf
+#define USBCS #0x7fd6
+#define SUDPTRH #0x7fd4
+#define SUDPTRL #0x7fd5
+#define SETUPDAT #0x7fe8
+		
+	;; usb interrupt : enable is EIE.0 (0xe8), flag is EXIF.4 (0x91)
+
+	.org 0
+	ljmp start
+	;; interrupt vectors
+	.org 23H
+	ljmp serial_int
+	.byte 0
+	
+	.org 43H
+	ljmp USB_Jump_Table
+	.byte 0			; filled in by the USB core
+
+;;; local variables. These are not initialized properly: do it by hand.
+	.org 30H
+rx_ring_in:	.byte 0
+rx_ring_out:	.byte 0
+tx_ring_in:	.byte 0
+tx_ring_out:	.byte 0
+tx_unthrottle_threshold:	.byte 0
+		
+	.org 0x100H		; wants to be on a page boundary
+USB_Jump_Table:
+	ljmp	ISR_Sudav	; Setup Data Available
+	.byte 0
+	ljmp	0		; Start of Frame
+	.byte 0
+	ljmp	0		; Setup Data Loading
+	.byte 0
+	ljmp	0		; Global Suspend
+	.byte 	0
+	ljmp	0		; USB Reset  	
+	.byte	0
+	ljmp	0		; Reserved
+	.byte	0
+	ljmp	0		; End Point 0 In
+	.byte	0
+	ljmp	0		; End Point 0 Out
+	.byte	0
+	ljmp	0		; End Point 1 In
+	.byte	0
+	ljmp	0		; End Point 1 Out
+	.byte	0
+	ljmp	ISR_Ep2in
+	.byte	0
+	ljmp	ISR_Ep2out
+	.byte	0
+
+
+	.org 0x200
+		
+start:	mov SP,STACK-1 ; set stack
+	;; clear local variables
+	clr a
+	mov tx_ring_in, a
+	mov tx_ring_out, a
+	mov rx_ring_in, a
+	mov rx_ring_out, a
+	mov tx_unthrottle_threshold, a
+	clr TX_RUNNING
+	clr DO_TX_UNTHROTTLE
+	
+	;; clear fifo with "fe"
+	mov r1, 0
+	mov a, #0xfe
+	mov dptr, #tx_ring
+clear_tx_ring_loop:
+	movx @dptr, a
+	inc dptr
+	djnz r1, clear_tx_ring_loop
+
+	mov a, #0xfd
+	mov dptr, #rx_ring
+clear_rx_ring_loop:
+	movx @dptr, a
+	inc dptr
+	djnz r1, clear_rx_ring_loop
+
+;;; turn on the RS-232 driver chip (bring the STANDBY pin low)
+	;; set OEB.1
+	mov a, #02H
+	mov dptr,OEB
+	movx @dptr,a
+	;; clear PB1
+	mov a, #00H
+	mov dptr,OUTB
+	movx @dptr,a
+	;; set OEC.[127]
+	mov a, #0x86
+	mov dptr,OEC
+	movx @dptr,a
+	;; set PORTCCFG.[01] to route TxD0,RxD0 to serial port
+	mov dptr, PORTCCFG
+	mov a, #0x03
+	movx @dptr, a
+	
+	;; set up interrupts, autovectoring
+	mov dptr, USBBAV
+	movx a, at dptr
+	setb acc.0		; AVEN bit to 0
+	movx @dptr, a
+
+	mov a,#0x01		; enable SUDAV:	setup data available (for ep0)
+	mov dptr, USBIRQ
+	movx @dptr, a		; clear SUDAVI
+	mov dptr, USBIEN
+	movx @dptr, a
+	
+	mov dptr, IN07IEN
+	mov a,#0x04		; enable IN2 int
+	movx @dptr, a
+	
+	mov dptr, OUT07IEN
+	mov a,#0x04		; enable OUT2 int
+	movx @dptr, a
+	mov dptr, OUT2BC
+	movx @dptr, a		; arm OUT2
+
+	mov a, #0x84		; turn on RTS, DTR
+	mov dptr,OUTC
+	movx @dptr, a
+	;; setup the serial port. 9600 8N1.
+	mov a,#01010011		; mode 1, enable rx, clear int
+	mov SCON, a
+	;;  using timer2, in 16-bit baud-rate-generator mode
+	;;   (xtal 12MHz, internal fosc 24MHz)
+	;;  RCAP2H,RCAP2L = 65536 - fosc/(32*baud)
+	;;  57600: 0xFFF2.F, say 0xFFF3
+	;;   9600: 0xFFB1.E, say 0xFFB2
+	;;    300: 0xF63C
+#define BAUD 9600
+#define BAUD_TIMEOUT(rate) (65536 - (24 * 1000 * 1000) / (32 * rate))
+#define BAUD_HIGH(rate) HIGH(BAUD_TIMEOUT(rate))
+#define BAUD_LOW(rate) LOW(BAUD_TIMEOUT(rate))
+		
+	mov T2CON, #030h	; rclk=1,tclk=1,cp=0,tr2=0(enable later)
+	mov r3, #5
+	acall set_baud
+	setb TR2
+	mov SCON, #050h
+	
+#if 0
+	mov r1, #0x40
+	mov a, #0x41
+send:	
+	mov SBUF, a
+	inc a
+	anl a, #0x3F
+	orl a, #0x40
+;	xrl a, #0x02
+wait1:	
+	jnb TI, wait1
+	clr TI
+	djnz r1, send
+;done:	sjmp done
+
+#endif
+	
+	setb EUSB
+	setb EA
+	setb ES0
+	;acall dump_stat
+
+	;; hey, what say we RENUMERATE! (TRM p.62)
+	mov a, #0
+	mov dps, a
+	mov dptr, USBCS
+	mov a, #0x02		; DISCON=0, DISCOE=0, RENUM=1
+	movx @dptr, a
+	;; now presence pin is floating, simulating disconnect. wait 0.5s
+	mov r1, #46
+renum_wait1:
+	mov r2, #0
+renum_wait2:
+	mov r3, #0
+renum_wait3:
+	djnz r3, renum_wait3
+	djnz r2, renum_wait2
+	djnz r1, renum_wait1	; wait about n*(256^2) 6MHz clocks
+	mov a, #0x06		; DISCON=0, DISCOE=1, RENUM=1
+	movx @dptr, a
+	;; we are back online. the host device will now re-query us
+	
+	
+main:	sjmp main
+
+	
+
+ISR_Sudav:
+	push dps
+	push dpl
+	push dph
+	push dpl1
+	push dph1
+	push acc
+	mov a,EXIF
+	clr acc.4
+	mov EXIF,a		; clear INT2 first
+	mov dptr, USBIRQ	; clear USB int
+	mov a,#01h
+	movx @dptr,a
+
+	;; get request type
+	mov dptr, SETUPDAT
+	movx a, @dptr
+	mov r1, a		; r1 = bmRequestType
+	inc dptr
+	movx a, @dptr
+	mov r2, a		; r2 = bRequest
+	inc dptr
+	movx a, @dptr
+	mov r3, a		; r3 = wValueL
+	inc dptr
+	movx a, @dptr
+	mov r4, a		; r4 = wValueH
+
+	;; main switch on bmRequest.type: standard or vendor
+	mov a, r1
+	anl a, #0x60
+	cjne a, #0x00, setup_bmreq_type_not_standard
+	;; standard request: now main switch is on bRequest
+	ljmp setup_bmreq_is_standard
+	
+setup_bmreq_type_not_standard:	
+	;; a still has bmreq&0x60
+	cjne a, #0x40, setup_bmreq_type_not_vendor
+	;; Anchor reserves bRequest 0xa0-0xaf, we use small ones
+	;; switch on bRequest. bmRequest will always be 0x41 or 0xc1
+	cjne r2, #0x00, setup_ctrl_not_00
+	;; 00 is set baud, wValue[0] has baud rate index
+	lcall set_baud		; index in r3, carry set if error
+	jc setup_bmreq_type_not_standard__do_stall
+	ljmp setup_done_ack
+setup_bmreq_type_not_standard__do_stall:
+	ljmp setup_stall
+setup_ctrl_not_00:
+	cjne r2, #0x01, setup_ctrl_not_01
+	;; 01 is reserved for set bits (parity). TODO
+	ljmp setup_stall
+setup_ctrl_not_01:
+	cjne r2, #0x02, setup_ctrl_not_02
+	;; 02 is set HW flow control. TODO
+	ljmp setup_stall
+setup_ctrl_not_02:
+	cjne r2, #0x03, setup_ctrl_not_03
+	;; 03 is control pins (RTS, DTR).
+	ljmp control_pins	; will jump to setup_done_ack,
+				;  or setup_return_one_byte
+setup_ctrl_not_03:
+	cjne r2, #0x04, setup_ctrl_not_04
+	;; 04 is send break (really "turn break on/off"). TODO
+	cjne r3, #0x00, setup_ctrl_do_break_on
+	;; do break off: restore PORTCCFG.1 to reconnect TxD0 to serial port
+	mov dptr, PORTCCFG
+	movx a, @dptr
+	orl a, #0x02
+	movx @dptr, a
+	ljmp setup_done_ack
+setup_ctrl_do_break_on:
+	;; do break on: clear PORTCCFG.0, set TxD high(?) (b1 low)
+	mov dptr, OUTC
+	movx a, @dptr
+	anl a, #0xfd		; ~0x02
+	movx @dptr, a
+	mov dptr, PORTCCFG
+	movx a, @dptr
+	anl a, #0xfd		; ~0x02
+	movx @dptr, a
+	ljmp setup_done_ack
+setup_ctrl_not_04:
+	cjne r2, #0x05, setup_ctrl_not_05
+	;; 05 is set desired interrupt bitmap. TODO
+	ljmp setup_stall
+setup_ctrl_not_05:
+	cjne r2, #0x06, setup_ctrl_not_06
+	;; 06 is query room
+	cjne r3, #0x00, setup_ctrl_06_not_00
+	;; 06, wValue[0]=0 is query write_room
+	mov a, tx_ring_out
+	setb c
+	subb a, tx_ring_in	; out-1-in = 255 - (in-out)
+	ljmp setup_return_one_byte
+setup_ctrl_06_not_00:
+	cjne r3, #0x01, setup_ctrl_06_not_01
+	;; 06, wValue[0]=1 is query chars_in_buffer
+	mov a, tx_ring_in
+	clr c
+	subb a, tx_ring_out	; in-out
+	ljmp setup_return_one_byte
+setup_ctrl_06_not_01:	
+	ljmp setup_stall
+setup_ctrl_not_06:
+	cjne r2, #0x07, setup_ctrl_not_07
+	;; 07 is request tx unthrottle interrupt
+	mov tx_unthrottle_threshold, r3; wValue[0] is threshold value
+	ljmp setup_done_ack
+setup_ctrl_not_07:
+	ljmp setup_stall
+	
+setup_bmreq_type_not_vendor:
+	ljmp setup_stall
+
+
+setup_bmreq_is_standard:	
+	cjne r2, #0x00, setup_breq_not_00
+	;; 00:	Get_Status (sub-switch on bmRequestType: device, ep, int)
+	cjne r1, #0x80, setup_Get_Status_not_device
+	;; Get_Status(device)
+	;;  are we self-powered? no. can we do remote wakeup? no
+	;;   so return two zero bytes. This is reusable
+setup_return_two_zero_bytes:
+	mov dptr, IN0BUF
+	clr a
+	movx @dptr, a
+	inc dptr
+	movx @dptr, a
+	mov dptr, IN0BC
+	mov a, #2
+	movx @dptr, a
+	ljmp setup_done_ack
+setup_Get_Status_not_device:
+	cjne r1, #0x82, setup_Get_Status_not_endpoint
+	;; Get_Status(endpoint)
+	;;  must get stall bit for ep[wIndexL], return two bytes, bit in lsb 0
+	;; for now: cheat. TODO
+	sjmp setup_return_two_zero_bytes
+setup_Get_Status_not_endpoint:
+	cjne r1, #0x81, setup_Get_Status_not_interface
+	;; Get_Status(interface): return two zeros
+	sjmp setup_return_two_zero_bytes
+setup_Get_Status_not_interface:	
+	ljmp setup_stall
+	
+setup_breq_not_00:
+	cjne r2, #0x01, setup_breq_not_01
+	;; 01:	Clear_Feature (sub-switch on wValueL: stall, remote wakeup)
+	cjne r3, #0x00, setup_Clear_Feature_not_stall
+	;; Clear_Feature(stall). should clear a stall bit. TODO
+	ljmp setup_stall
+setup_Clear_Feature_not_stall:
+	cjne r3, #0x01, setup_Clear_Feature_not_rwake
+	;; Clear_Feature(remote wakeup). ignored.
+	ljmp setup_done_ack
+setup_Clear_Feature_not_rwake:
+	ljmp setup_stall
+	
+setup_breq_not_01:
+	cjne r2, #0x03, setup_breq_not_03
+	;; 03:	Set_Feature (sub-switch on wValueL: stall, remote wakeup)
+	cjne r3, #0x00, setup_Set_Feature_not_stall
+	;; Set_Feature(stall). Should set a stall bit. TODO
+	ljmp setup_stall
+setup_Set_Feature_not_stall:
+	cjne r3, #0x01, setup_Set_Feature_not_rwake
+	;; Set_Feature(remote wakeup). ignored.
+	ljmp setup_done_ack
+setup_Set_Feature_not_rwake:
+	ljmp setup_stall
+	
+setup_breq_not_03:	
+	cjne r2, #0x06, setup_breq_not_06
+	;; 06:	Get_Descriptor (s-switch on wValueH: dev, config[n], string[n])
+	cjne r4, #0x01, setup_Get_Descriptor_not_device
+	;; Get_Descriptor(device)
+	mov dptr, SUDPTRH
+	mov a, #HIGH(desc_device)
+	movx @dptr, a
+	mov dptr, SUDPTRL
+	mov a, #LOW(desc_device)
+	movx @dptr, a
+	ljmp setup_done_ack
+setup_Get_Descriptor_not_device:
+	cjne r4, #0x02, setup_Get_Descriptor_not_config
+	;; Get_Descriptor(config[n])
+	cjne r3, #0x00, setup_stall; only handle n==0
+	;; Get_Descriptor(config[0])
+	mov dptr, SUDPTRH
+	mov a, #HIGH(desc_config1)
+	movx @dptr, a
+	mov dptr, SUDPTRL
+	mov a, #LOW(desc_config1)
+	movx @dptr, a
+	ljmp setup_done_ack
+setup_Get_Descriptor_not_config:
+	cjne r4, #0x03, setup_Get_Descriptor_not_string
+	;; Get_Descriptor(string[wValueL])
+	;;  if (wValueL >= maxstrings) stall
+	mov a, #((desc_strings_end-desc_strings)/2)
+	clr c
+	subb a,r3		; a=4, r3 = 0..3 . if a<=0 then stall
+	jc  setup_stall
+	jz  setup_stall
+	mov a, r3
+	add a, r3		; a = 2*wValueL
+	mov dptr, #desc_strings
+	add a, dpl
+	mov dpl, a
+	mov a, #0
+	addc a, dph
+	mov dph, a		; dph = desc_strings[a]. big endian! (handy)
+	;; it looks like my adapter uses a revision of the EZUSB that
+	;; contains "rev D errata number 8", as hinted in the EzUSB example
+	;; code. I cannot find an actual errata description on the Cypress
+	;; web site, but from the example code it looks like this bug causes
+	;; the length of string descriptors to be read incorrectly, possibly
+	;; sending back more characters than the descriptor has. The workaround
+	;; is to manually send out all of the data. The consequence of not
+	;; using the workaround is that the strings gathered by the kernel
+	;; driver are too long and are filled with trailing garbage (including
+	;; leftover strings). Writing this out by hand is a nuisance, so for
+	;; now I will just live with the bug.
+	movx a, @dptr
+	mov r1, a
+	inc dptr
+	movx a, @dptr
+	mov r2, a
+	mov dptr, SUDPTRH
+	mov a, r1
+	movx @dptr, a
+	mov dptr, SUDPTRL
+	mov a, r2
+	movx @dptr, a
+	;; done
+	ljmp setup_done_ack
+	
+setup_Get_Descriptor_not_string:
+	ljmp setup_stall
+	
+setup_breq_not_06:
+	cjne r2, #0x08, setup_breq_not_08
+	;; Get_Configuration. always 1. return one byte.
+	;; this is reusable
+	mov a, #1
+setup_return_one_byte:	
+	mov dptr, IN0BUF
+	movx @dptr, a
+	mov a, #1
+	mov dptr, IN0BC
+	movx @dptr, a
+	ljmp setup_done_ack
+setup_breq_not_08:
+	cjne r2, #0x09, setup_breq_not_09
+	;; 09: Set_Configuration. ignored.
+	ljmp setup_done_ack
+setup_breq_not_09:
+	cjne r2, #0x0a, setup_breq_not_0a
+	;; 0a: Get_Interface. get the current altsetting for int[wIndexL]
+	;;  since we only have one interface, ignore wIndexL, return a 0
+	mov a, #0
+	ljmp setup_return_one_byte
+setup_breq_not_0a:
+	cjne r2, #0x0b, setup_breq_not_0b
+	;; 0b: Set_Interface. set altsetting for interface[wIndexL]. ignored
+	ljmp setup_done_ack
+setup_breq_not_0b:
+	ljmp setup_stall
+
+		
+setup_done_ack:	
+	;; now clear HSNAK
+	mov dptr, EP0CS
+	mov a, #0x02
+	movx @dptr, a
+	sjmp setup_done
+setup_stall:	
+	;; unhandled. STALL
+	;EP0CS |= bmEPSTALL
+	mov dptr, EP0CS
+	movx a, @dptr
+	orl a, EP0STALLbit
+	movx @dptr, a
+	sjmp setup_done
+	
+setup_done:	
+	pop acc
+	pop dph1
+	pop dpl1
+	pop dph
+	pop dpl
+	pop dps
+	reti
+
+;;; ==============================================================
+	
+set_baud:			; baud index in r3
+	;; verify a < 10
+	mov a, r3
+	jb ACC.7, set_baud__badbaud
+	clr c
+	subb a, #10
+	jnc set_baud__badbaud
+	mov a, r3
+	rl a			; a = index*2
+	add a, #LOW(baud_table)
+	mov dpl, a
+	mov a, #HIGH(baud_table)
+	addc a, #0
+	mov dph, a
+	;; TODO: shut down xmit/receive
+	;; TODO: wait for current xmit char to leave
+	;; TODO: shut down timer to avoid partial-char glitch
+	movx a, at dptr		; BAUD_HIGH
+	mov RCAP2H, a
+	mov TH2, a
+	inc dptr
+	movx a, at dptr		; BAUD_LOW
+	mov RCAP2L, a
+	mov TL2, a
+	;; TODO: restart xmit/receive
+	;; TODO: reenable interrupts, resume tx if pending
+	clr c			; c=0: success
+	ret
+set_baud__badbaud:
+	setb c			; c=1: failure
+	ret
+	
+;;; ==================================================
+control_pins:
+	cjne r1, #0x41, control_pins_in
+control_pins_out:
+	mov a, r3 ; wValue[0] holds new bits:	b7 is new DTR, b2 is new RTS
+	xrl a, #0xff		; 1 means active, 0V, +12V ?
+	anl a, #0x84
+	mov r3, a
+	mov dptr, OUTC
+	movx a, @dptr		; only change bits 7 and 2
+	anl a, #0x7b		; ~0x84
+	orl a, r3
+	movx @dptr, a		; other pins are inputs, bits ignored
+	ljmp setup_done_ack
+control_pins_in:
+	mov dptr, PINSC
+	movx a, @dptr
+	xrl a, #0xff
+	ljmp setup_return_one_byte
+
+;;; ========================================
+	
+ISR_Ep2in:
+	push dps
+	push dpl
+	push dph
+	push dpl1
+	push dph1
+	push acc
+	mov a,EXIF
+	clr acc.4
+	mov EXIF,a		; clear INT2 first
+	mov dptr, IN07IRQ	; clear USB int
+	mov a,#04h
+	movx @dptr,a
+
+	;; do stuff
+	lcall start_in
+	
+	pop acc
+	pop dph1
+	pop dpl1
+	pop dph
+	pop dpl
+	pop dps
+	reti
+
+ISR_Ep2out:
+	push dps
+	push dpl
+	push dph
+	push dpl1
+	push dph1
+	push acc
+	mov a,EXIF
+	clr acc.4
+	mov EXIF,a		; clear INT2 first
+	mov dptr, OUT07IRQ	; clear USB int
+	mov a,#04h
+	movx @dptr,a
+
+	;; do stuff
+
+	;; copy data into buffer. for now, assume we will have enough space
+	mov dptr, OUT2BC	; get byte count
+	movx a, at dptr
+	mov r1, a
+	clr a
+	mov dps, a
+	mov dptr, OUT2BUF	; load DPTR0 with source
+	mov dph1, #HIGH(tx_ring)	; load DPTR1 with target
+	mov dpl1, tx_ring_in
+OUT_loop:
+	movx a, at dptr		; read
+	inc dps			; switch to DPTR1: target
+	inc dpl1		; target = tx_ring_in+1
+	movx @dptr,a		; store
+	mov a,dpl1
+	cjne a, tx_ring_out, OUT_no_overflow
+	sjmp OUT_overflow
+OUT_no_overflow:	
+	inc tx_ring_in		; tx_ring_in++
+	inc dps			; switch to DPTR0: source
+	inc dptr
+	djnz r1, OUT_loop
+	sjmp OUT_done
+OUT_overflow:
+	;; signal overflow
+	;; fall through
+OUT_done:	
+	;; ack
+	mov dptr,OUT2BC
+	movx @dptr,a
+
+	;; start tx
+	acall maybe_start_tx
+	;acall dump_stat
+	
+	pop acc
+	pop dph1
+	pop dpl1
+	pop dph
+	pop dpl
+	pop dps
+	reti
+
+dump_stat:
+	;; fill in EP4in with a debugging message:
+	;;   tx_ring_in, tx_ring_out, rx_ring_in, rx_ring_out
+	;;   tx_active
+	;;   tx_ring[0..15]
+	;;   0xfc
+	;;   rx_ring[0..15]
+	clr a
+	mov dps, a
+	
+	mov dptr, IN4CS
+	movx a, @dptr
+	jb acc.1, dump_stat__done; busy: cannot dump, old one still pending
+	mov dptr, IN4BUF
+	
+	mov a, tx_ring_in
+	movx @dptr, a
+	inc dptr
+	mov a, tx_ring_out
+	movx @dptr, a
+	inc dptr
+
+	mov a, rx_ring_in
+	movx @dptr, a
+	inc dptr
+	mov a, rx_ring_out
+	movx @dptr, a
+	inc dptr
+	
+	clr a
+	jnb TX_RUNNING, dump_stat__no_tx_running
+	inc a
+dump_stat__no_tx_running:
+	movx @dptr, a
+	inc dptr
+	;; tx_ring[0..15]
+	inc dps
+	mov dptr, #tx_ring	; DPTR1: source
+	mov r1, #16
+dump_stat__tx_ring_loop:
+	movx a, @dptr
+	inc dptr
+	inc dps
+	movx @dptr, a
+	inc dptr
+	inc dps
+	djnz r1, dump_stat__tx_ring_loop
+	inc dps
+	
+	mov a, #0xfc
+	movx @dptr, a
+	inc dptr
+	
+	;; rx_ring[0..15]
+	inc dps
+	mov dptr, #rx_ring	; DPTR1: source
+	mov r1, #16
+dump_stat__rx_ring_loop:
+	movx a, @dptr
+	inc dptr
+	inc dps
+	movx @dptr, a
+	inc dptr
+	inc dps
+	djnz r1, dump_stat__rx_ring_loop
+	
+	;; now send it
+	clr a
+	mov dps, a
+	mov dptr, IN4BC
+	mov a, #38
+	movx @dptr, a
+dump_stat__done:	
+	ret
+		
+;;; ============================================================
+	
+maybe_start_tx:
+	;; make sure the tx process is running.
+	jb TX_RUNNING, start_tx_done
+start_tx:
+	;; is there work to be done?
+	mov a, tx_ring_in
+	cjne a,tx_ring_out, start_tx__work
+	ret			; no work
+start_tx__work:	
+	;; tx was not running. send the first character, setup the TI int
+	inc tx_ring_out		; [++tx_ring_out]
+	mov dph, #HIGH(tx_ring)
+	mov dpl, tx_ring_out
+	movx a, @dptr
+	mov sbuf, a
+	setb TX_RUNNING
+start_tx_done:
+	;; can we unthrottle the host tx process?
+	;;  step 1: do we care?
+	mov a, #0
+	cjne a, tx_unthrottle_threshold, start_tx__maybe_unthrottle_tx
+	;; nope
+start_tx_really_done:
+	ret
+start_tx__maybe_unthrottle_tx:
+	;;  step 2: is there now room?
+	mov a, tx_ring_out
+	setb c
+	subb a, tx_ring_in
+	;; a is now write_room. If thresh >= a, we can unthrottle
+	clr c
+	subb a, tx_unthrottle_threshold
+	jc start_tx_really_done	; nope
+	;; yes, we can unthrottle. remove the threshold and mark a request
+	mov tx_unthrottle_threshold, #0
+	setb DO_TX_UNTHROTTLE
+	;; prod rx, which will actually send the message when in2 becomes free
+	ljmp start_in
+	
+
+serial_int:
+	push dps
+	push dpl
+	push dph
+	push dpl1
+	push dph1
+	push acc
+	jnb TI, serial_int__not_tx
+	;; tx finished. send another character if we have one
+	clr TI			; clear int
+	clr TX_RUNNING
+	lcall start_tx
+serial_int__not_tx:
+	jnb RI, serial_int__not_rx
+	lcall get_rx_char
+	clr RI			; clear int
+serial_int__not_rx:	
+	;; return
+	pop acc
+	pop dph1
+	pop dpl1
+	pop dph
+	pop dpl
+	pop dps
+	reti
+
+get_rx_char:
+	mov dph, #HIGH(rx_ring)
+	mov dpl, rx_ring_in
+	inc dpl			; target = rx_ring_in+1
+	mov a, sbuf
+	movx @dptr, a
+	;; check for overflow before incrementing rx_ring_in
+	mov a, dpl
+	cjne a, rx_ring_out, get_rx_char__no_overflow
+	;; signal overflow
+	ret
+get_rx_char__no_overflow:	
+	inc rx_ring_in
+	;; kick off USB INpipe
+	acall start_in
+	ret
+
+start_in:
+	;; check if the inpipe is already running.
+	mov dptr, IN2CS
+	movx a, @dptr
+	jb acc.1, start_in__done; int will handle it
+	jb DO_TX_UNTHROTTLE, start_in__do_tx_unthrottle
+	;; see if there is any work to do. a serial interrupt might occur
+	;; during this sequence?
+	mov a, rx_ring_in
+	cjne a, rx_ring_out, start_in__have_work
+	ret			; nope
+start_in__have_work:	
+	;; now copy as much data as possible into the pipe. 63 bytes max.
+	clr a
+	mov dps, a
+	mov dph, #HIGH(rx_ring)	; load DPTR0 with source
+	inc dps
+	mov dptr, IN2BUF	; load DPTR1 with target
+	movx @dptr, a		; in[0] signals that rest of IN is rx data
+	inc dptr
+	inc dps
+	;; loop until we run out of data, or we have copied 64 bytes
+	mov r1, #1		; INbuf size counter
+start_in__loop:
+	mov a, rx_ring_in
+	cjne a, rx_ring_out, start_inlocal_irq_enablell_copying
+	sjmp start_in__kick
+start_inlocal_irq_enablell_copying:
+	inc rx_ring_out
+	mov dpl, rx_ring_out
+	movx a, @dptr
+	inc dps
+	movx @dptr, a		; write into IN buffer
+	inc dptr
+	inc dps
+	inc r1
+	cjne r1, #64, start_in__loop; loop
+start_in__kick:
+	;; either we ran out of data, or we copied 64 bytes. r1 has byte count
+	;; kick off IN
+	mov dptr, IN2BC
+	mov a, r1
+	jz start_in__done
+	movx @dptr, a
+	;; done
+start_in__done:
+	;acall dump_stat
+	ret
+start_in__do_tx_unthrottle:
+	;; special sequence: send a tx unthrottle message
+	clr DO_TX_UNTHROTTLE
+	clr a
+	mov dps, a
+	mov dptr, IN2BUF
+	mov a, #1
+	movx @dptr, a
+	inc dptr
+	mov a, #2
+	movx @dptr, a
+	mov dptr, IN2BC
+	movx @dptr, a
+	ret
+	
+putchar:
+	clr TI
+	mov SBUF, a
+putchar_wait:
+	jnb TI, putchar_wait
+	clr TI
+	ret
+
+	
+baud_table:			; baud_high, then baud_low
+	;; baud[0]: 110
+	.byte BAUD_HIGH(110)
+	.byte BAUD_LOW(110)
+	;; baud[1]: 300
+	.byte BAUD_HIGH(300)
+	.byte BAUD_LOW(300)
+	;; baud[2]: 1200
+	.byte BAUD_HIGH(1200)
+	.byte BAUD_LOW(1200)
+	;; baud[3]: 2400
+	.byte BAUD_HIGH(2400)
+	.byte BAUD_LOW(2400)
+	;; baud[4]: 4800
+	.byte BAUD_HIGH(4800)
+	.byte BAUD_LOW(4800)
+	;; baud[5]: 9600
+	.byte BAUD_HIGH(9600)
+	.byte BAUD_LOW(9600)
+	;; baud[6]: 19200
+	.byte BAUD_HIGH(19200)
+	.byte BAUD_LOW(19200)
+	;; baud[7]: 38400
+	.byte BAUD_HIGH(38400)
+	.byte BAUD_LOW(38400)
+	;; baud[8]: 57600
+	.byte BAUD_HIGH(57600)
+	.byte BAUD_LOW(57600)
+	;; baud[9]: 115200
+	.byte BAUD_HIGH(115200)
+	.byte BAUD_LOW(115200)
+
+desc_device:
+	.byte 0x12, 0x01, 0x00, 0x01, 0xff, 0xff, 0xff, 0x40
+	.byte 0xcd, 0x06, 0x04, 0x01, 0x89, 0xab, 1, 2, 3, 0x01
+;;; The "real" device id, which must match the host driver, is that
+;;; "0xcd 0x06 0x04 0x01" sequence, which is 0x06cd, 0x0104
+	
+desc_config1:
+	.byte 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32
+	.byte 0x09, 0x04, 0x00, 0x00, 0x02, 0xff, 0xff, 0xff, 0x00
+	.byte 0x07, 0x05, 0x82, 0x03, 0x40, 0x00, 0x01
+	.byte 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00
+
+desc_strings:
+	.word string_langids, string_mfg, string_product, string_serial
+desc_strings_end:
+
+string_langids:	.byte string_langids_end-string_langids
+	.byte 3
+	.word 0
+string_langids_end:
+
+	;; sigh. These strings are Unicode, meaning UTF16? 2 bytes each. Now
+	;; *that* is a pain in the ass to encode. And they are little-endian
+	;; too. Use this perl snippet to get the bytecodes:
+	/* while (<>) {
+	    @c = split(//);
+	    foreach $c (@c) {
+	     printf("0x%02x, 0x00, ", ord($c));
+	    }
+	   }
+	*/
+
+string_mfg:	.byte string_mfg_end-string_mfg
+	.byte 3
+;	.byte "ACME usb widgets"
+	.byte 0x41, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x45, 0x00, 0x20, 0x00, 0x75, 0x00, 0x73, 0x00, 0x62, 0x00, 0x20, 0x00, 0x77, 0x00, 0x69, 0x00, 0x64, 0x00, 0x67, 0x00, 0x65, 0x00, 0x74, 0x00, 0x73, 0x00
+string_mfg_end:
+	
+string_product:	.byte string_product_end-string_product
+	.byte 3
+;	.byte "ACME USB serial widget"
+	.byte 0x41, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x45, 0x00, 0x20, 0x00, 0x55, 0x00, 0x53, 0x00, 0x42, 0x00, 0x20, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x77, 0x00, 0x69, 0x00, 0x64, 0x00, 0x67, 0x00, 0x65, 0x00, 0x74, 0x00
+string_product_end:
+	
+string_serial:	.byte string_serial_end-string_serial
+	.byte 3
+;	.byte "47"
+	.byte 0x34, 0x00, 0x37, 0x00
+string_serial_end:
+		
+;;; ring buffer memory
+	;; tx_ring_in+1 is where the next input byte will go
+	;; [tx_ring_out] has been sent
+	;; if tx_ring_in == tx_ring_out, theres no work to do
+	;; there are (tx_ring_in - tx_ring_out) chars to be written
+	;; dont let _in lap _out
+	;;   cannot inc if tx_ring_in+1 == tx_ring_out
+	;;  write [tx_ring_in+1] then tx_ring_in++
+	;;   if (tx_ring_in+1 == tx_ring_out), overflow
+	;;   else tx_ring_in++
+	;;  read/send [tx_ring_out+1], then tx_ring_out++
+
+	;; rx_ring_in works the same way
+	
+	.org 0x1000
+tx_ring:
+	.skip 0x100		; 256 bytes
+rx_ring:
+	.skip 0x100		; 256 bytes
+	
+	
+	.END
+	

Added: dists/trunk/firmware-free/linux-free/keyspan_pda/keyspan_pda.fw
==============================================================================
Binary file. No diff available.

Added: dists/trunk/firmware-free/linux-free/keyspan_pda/xircom_pgs.S
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/firmware-free/linux-free/keyspan_pda/xircom_pgs.S	Thu Jan 14 23:13:43 2010	(r14942)
@@ -0,0 +1,1192 @@
+/*  $Id: loop.s,v 1.23 2000/03/20 09:49:06 warner Exp $
+ * 
+ *  Firmware for the Keyspan PDA Serial Adapter, a USB serial port based on
+ *  the EzUSB microcontroller.
+ * 
+ *  (C) Copyright 2000 Brian Warner <warner at lothar.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.
+ * 
+ *  "Keyspan PDA Serial Adapter" is probably a copyright of Keyspan, the
+ *  company.
+ * 
+ *  This serial adapter is basically an EzUSB chip and an RS-232 line driver
+ *  in a little widget that has a DB-9 on one end and a USB plug on the other.
+ *  It uses the EzUSB's internal UART0 (using the pins from Port C) and timer2
+ *  as a baud-rate generator. The wiring is:
+ *   PC0/RxD0 <- rxd (DB9 pin 2)         PC4 <- dsr pin 6
+ *   PC1/TxD0 -> txd pin 3               PC5 <- ri  pin 9
+ *   PC2      -> rts pin 7               PC6 <- dcd pin 1
+ *   PC3      <- cts pin 8               PC7 -> dtr pin 4
+ *   PB1 -> line driver standby
+ *
+ *  The EzUSB register constants below come from their excellent documentation
+ *  and sample code (which used to be available at www.anchorchips.com, but
+ *  that has now been absorbed into Cypress' site and the CD-ROM contents
+ *  don't appear to be available online anymore). If we get multiple
+ *  EzUSB-based drivers into the kernel, it might be useful to pull them out
+ *  into a separate .h file.
+ * 
+ * THEORY OF OPERATION:
+ *
+ *   There are two 256-byte ring buffers, one for tx, one for rx.
+ *
+ *   EP2out is pure tx data. When it appears, the data is copied into the tx
+ *   ring and serial transmission is started if it wasn't already running. The
+ *   "tx buffer empty" interrupt may kick off another character if the ring
+ *   still has data. If the host is tx-blocked because the ring filled up,
+ *   it will request a "tx unthrottle" interrupt. If sending a serial character
+ *   empties the ring below the desired threshold, we set a bit that will send
+ *   up the tx unthrottle message as soon as the rx buffer becomes free.
+ *
+ *   EP2in (interrupt) is used to send both rx chars and rx status messages
+ *   (only "tx unthrottle" at this time) back up to the host. The first byte
+ *   of the rx message indicates data (0) or status msg (1). Status messages
+ *   are sent before any data.
+ *
+ *   Incoming serial characters are put into the rx ring by the serial
+ *   interrupt, and the EP2in buffer sent if it wasn't already in transit.
+ *   When the EP2in buffer returns, the interrupt prompts us to send more
+ *   rx chars (or status messages) if they are pending.
+ *
+ *   Device control happens through "vendor specific" control messages on EP0.
+ *   All messages are destined for the "Interface" (with the index always 0,
+ *   so that if their two-port device might someday use similar firmware, we
+ *   can use index=1 to refer to the second port). The messages defined are:
+ *
+ *    bRequest = 0 : set baud/bits/parity
+ *               1 : unused
+ *               2 : reserved for setting HW flow control (CTSRTS)
+ *               3 : get/set "modem info" (pin states: DTR, RTS, DCD, RI, etc)
+ *               4 : set break (on/off)
+ *               5 : reserved for requesting interrupts on pin state change
+ *               6 : query buffer room or chars in tx buffer
+ *               7 : request tx unthrottle interrupt
+ *
+ *  The host-side driver is set to recognize the device ID values stashed in
+ *  serial EEPROM (0x06cd, 0x0103), program this firmware into place, then
+ *  start it running. This firmware will use EzUSB's "renumeration" trick by
+ *  simulating a bus disconnect, then reconnect with a different device ID
+ *  (encoded in the desc_device descriptor below). The host driver then
+ *  recognizes the new device ID and glues it to the real serial driver code.
+ *
+ * USEFUL DOCS:
+ *  EzUSB Technical Reference Manual: <http://www.anchorchips.com>
+ *  8051 manuals: everywhere, but try www.dalsemi.com because the EzUSB is
+ *   basically the Dallas enhanced 8051 code. Remember that the EzUSB IO ports
+ *   use totally different registers!
+ *  USB 1.1 spec: www.usb.org
+ *
+ * HOW TO BUILD:
+ *  gcc -x assembler-with-cpp -P -E -o keyspan_pda.asm keyspan_pda.s
+ *  as31 -l keyspan_pda.asm
+ *  mv keyspan_pda.obj keyspan_pda.hex
+ *  perl ezusb_convert.pl keyspan_pda < keyspan_pda.hex > keyspan_pda_fw.h
+ * Get as31 from <http://www.pjrc.com/tech/8051/index.html>, and hack on it
+ * a bit to make it build.
+ *
+ * THANKS:
+ *  Greg Kroah-Hartman, for coordinating the whole usb-serial thing.
+ *  AnchorChips, for making such an incredibly useful little microcontroller.
+ *  KeySpan, for making a handy, cheap ($40) widget that was so easy to take
+ *           apart and trace with an ohmmeter.
+ *
+ * TODO:
+ *  lots. grep for TODO. Interrupt safety needs stress-testing. Better flow
+ *  control. Interrupting host upon change in DCD, etc, counting transitions.
+ *  Need to find a safe device id to use (the one used by the Keyspan firmware
+ *  under Windows would be ideal.. can anyone figure out what it is?). Parity.
+ *  More baud rates. Oh, and the string-descriptor-length silicon bug
+ *  workaround should be implemented, but I'm lazy, and the consequence is
+ *  that the device name strings that show up in your kernel log will have
+ *  lots of trailing binary garbage in them (appears as ????). Device strings
+ *  should be made more accurate.
+ *
+ * Questions, bugs, patches to Brian.
+ *
+ *  -Brian Warner <warner at lothar.com>
+ *
+ */
+	
+#define HIGH(x) (((x) & 0xff00) / 256)
+#define LOW(x) ((x) & 0xff)
+
+#define dpl1 0x84
+#define dph1 0x85
+#define dps 0x86
+
+;;; our bit assignments
+#define TX_RUNNING 0
+#define DO_TX_UNTHROTTLE 1
+	
+	;; stack from 0x60 to 0x7f: should really set SP to 0x60-1, not 0x60
+#define STACK #0x60-1
+
+#define EXIF 0x91
+#define EIE 0xe8
+	.flag EUSB, EIE.0
+	.flag ES0, IE.4
+
+#define EP0CS #0x7fb4
+#define EP0STALLbit #0x01
+#define IN0BUF #0x7f00
+#define IN0BC #0x7fb5
+#define OUT0BUF #0x7ec0
+#define OUT0BC #0x7fc5		
+#define IN2BUF #0x7e00
+#define IN2BC #0x7fb9
+#define IN2CS #0x7fb8
+#define OUT2BC #0x7fc9
+#define OUT2CS #0x7fc8
+#define OUT2BUF #0x7dc0
+#define IN4BUF #0x7d00
+#define IN4BC #0x7fbd
+#define IN4CS #0x7fbc
+#define OEB #0x7f9d
+#define OUTB #0x7f97
+#define OEC #0x7f9e
+#define OUTC #0x7f98
+#define PINSC #0x7f9b
+#define PORTBCFG #0x7f94
+#define PORTCCFG #0x7f95
+#define OEA	#0x7f9c
+#define IN07IRQ #0x7fa9
+#define OUT07IRQ #0x7faa
+#define IN07IEN #0x7fac
+#define OUT07IEN #0x7fad
+#define USBIRQ #0x7fab
+#define USBIEN #0x7fae
+#define USBBAV #0x7faf
+#define USBCS #0x7fd6
+#define SUDPTRH #0x7fd4
+#define SUDPTRL #0x7fd5
+#define SETUPDAT #0x7fe8
+		
+	;; usb interrupt : enable is EIE.0 (0xe8), flag is EXIF.4 (0x91)
+
+	.org 0
+	ljmp start
+	;; interrupt vectors
+	.org 23H
+	ljmp serial_int
+	.byte 0
+	
+	.org 43H
+	ljmp USB_Jump_Table
+	.byte 0			; filled in by the USB core
+
+;;; local variables. These are not initialized properly: do it by hand.
+	.org 30H
+rx_ring_in:	.byte 0
+rx_ring_out:	.byte 0
+tx_ring_in:	.byte 0
+tx_ring_out:	.byte 0
+tx_unthrottle_threshold:	.byte 0
+		
+	.org 0x100H		; wants to be on a page boundary
+USB_Jump_Table:
+	ljmp	ISR_Sudav	; Setup Data Available
+	.byte 0
+	ljmp	0		; Start of Frame
+	.byte 0
+	ljmp	0		; Setup Data Loading
+	.byte 0
+	ljmp	0		; Global Suspend
+	.byte 	0
+	ljmp	0		; USB Reset  	
+	.byte	0
+	ljmp	0		; Reserved
+	.byte	0
+	ljmp	0		; End Point 0 In
+	.byte	0
+	ljmp	0		; End Point 0 Out
+	.byte	0
+	ljmp	0		; End Point 1 In
+	.byte	0
+	ljmp	0		; End Point 1 Out
+	.byte	0
+	ljmp	ISR_Ep2in
+	.byte	0
+	ljmp	ISR_Ep2out
+	.byte	0
+
+
+	.org 0x200
+		
+start:	mov SP,STACK-1 ; set stack
+	;; clear local variables
+	clr a
+	mov tx_ring_in, a
+	mov tx_ring_out, a
+	mov rx_ring_in, a
+	mov rx_ring_out, a
+	mov tx_unthrottle_threshold, a
+	clr TX_RUNNING
+	clr DO_TX_UNTHROTTLE
+	
+	;; clear fifo with "fe"
+	mov r1, 0
+	mov a, #0xfe
+	mov dptr, #tx_ring
+clear_tx_ring_loop:
+	movx @dptr, a
+	inc dptr
+	djnz r1, clear_tx_ring_loop
+
+	mov a, #0xfd
+	mov dptr, #rx_ring
+clear_rx_ring_loop:
+	movx @dptr, a
+	inc dptr
+	djnz r1, clear_rx_ring_loop
+
+;;; turn on the RS-232 driver chip (bring the STANDBY pin low)
+;;; on Xircom the STANDBY is wired to PB6 and PC4 
+	mov dptr, PORTBCFG
+        mov a, #0xBf
+        movx @dptr, a
+	mov dptr, PORTCCFG
+        mov a, #0xef
+        movx @dptr, a
+	
+	;; set OEC.4
+        mov a, #0x10
+        mov dptr,OEC
+        movx @dptr,a
+
+        ;; clear PC4
+        mov a, #0x00
+        mov dptr,OUTC
+        movx @dptr,a
+
+	;; set OEB.6
+	mov a, #0x40
+	mov dptr,OEB
+	movx @dptr,a
+
+	;; clear PB6
+	mov a, #0x00
+	mov dptr,OUTB
+	movx @dptr,a
+
+	;; set OEC.[17]
+	mov a, #0x82
+	mov dptr,OEC
+	movx @dptr,a
+
+
+	;; set PORTCCFG.[01] to route TxD0,RxD0 to serial port
+	mov dptr, PORTCCFG
+	mov a, #0x03
+	movx @dptr, a
+	
+	;; set up interrupts, autovectoring
+	;; set BKPT
+	mov dptr, USBBAV
+	movx a, at dptr
+	setb acc.0		; AVEN bit to 0
+	movx @dptr, a
+
+	mov a,#0x01		; enable SUDAV:	setup data available (for ep0)
+	mov dptr, USBIRQ
+	movx @dptr, a		; clear SUDAVI
+	mov dptr, USBIEN
+	movx @dptr, a
+	
+	mov dptr, IN07IEN
+	mov a,#0x04		; enable IN2 int
+	movx @dptr, a
+	
+	mov dptr, OUT07IEN
+	mov a,#0x04		; enable OUT2 int
+	movx @dptr, a
+	mov dptr, OUT2BC
+	movx @dptr, a		; arm OUT2
+
+;;	mov a, #0x84		; turn on RTS, DTR
+;;	mov dptr,OUTC
+;;	movx @dptr, a
+
+	mov a, #0x7             ; turn on  DTR
+        mov dptr,USBBAV
+        movx @dptr, a
+
+	mov a, #0x20             ; turn on the RED led 
+        mov dptr,OEA
+        movx @dptr, a
+
+	mov a, #0x80            ; turn on  RTS
+        mov dptr,OUTC
+        movx @dptr, a
+
+	;; setup the serial port. 9600 8N1.
+	mov a,#0x53		; mode 1, enable rx, clear int
+	mov SCON, a
+	;;  using timer2, in 16-bit baud-rate-generator mode
+	;;   (xtal 12MHz, internal fosc 24MHz)
+	;;  RCAP2H,RCAP2L = 65536 - fosc/(32*baud)
+	;;  57600: 0xFFF2.F, say 0xFFF3
+	;;   9600: 0xFFB1.E, say 0xFFB2
+	;;    300: 0xF63C
+#define BAUD 9600
+#define BAUD_TIMEOUT(rate) (65536 - (24 * 1000 * 1000) / (32 * rate))
+#define BAUD_HIGH(rate) HIGH(BAUD_TIMEOUT(rate))
+#define BAUD_LOW(rate) LOW(BAUD_TIMEOUT(rate))
+		
+	mov T2CON, #030h	; rclk=1,tclk=1,cp=0,tr2=0(enable later)
+	mov r3, #5
+	acall set_baud
+	setb TR2
+	mov SCON, #050h
+	
+#if 0
+	mov r1, #0x40
+	mov a, #0x41
+send:	
+	mov SBUF, a
+	inc a
+	anl a, #0x3F
+	orl a, #0x40
+;	xrl a, #0x02
+wait1:	
+	jnb TI, wait1
+	clr TI
+	djnz r1, send
+;done:	sjmp done
+
+#endif
+	
+	setb EUSB
+	setb EA
+	setb ES0
+	;acall dump_stat
+
+	;; hey, what say we RENUMERATE! (TRM p.62)
+	mov a, #0
+	mov dps, a
+	mov dptr, USBCS
+	mov a, #0x02		; DISCON=0, DISCOE=0, RENUM=1
+	movx @dptr, a
+	;; now presence pin is floating, simulating disconnect. wait 0.5s
+	mov r1, #46
+renum_wait1:
+	mov r2, #0
+renum_wait2:
+	mov r3, #0
+renum_wait3:
+	djnz r3, renum_wait3
+	djnz r2, renum_wait2
+	djnz r1, renum_wait1	; wait about n*(256^2) 6MHz clocks
+	mov a, #0x06		; DISCON=0, DISCOE=1, RENUM=1
+	movx @dptr, a
+	;; we are back online. the host device will now re-query us
+	
+	
+main:	sjmp main
+
+	
+
+ISR_Sudav:
+	push dps
+	push dpl
+	push dph
+	push dpl1
+	push dph1
+	push acc
+	mov a,EXIF
+	clr acc.4
+	mov EXIF,a		; clear INT2 first
+	mov dptr, USBIRQ	; clear USB int
+	mov a,#01h
+	movx @dptr,a
+
+	;; get request type
+	mov dptr, SETUPDAT
+	movx a, @dptr
+	mov r1, a		; r1 = bmRequestType
+	inc dptr
+	movx a, @dptr
+	mov r2, a		; r2 = bRequest
+	inc dptr
+	movx a, @dptr
+	mov r3, a		; r3 = wValueL
+	inc dptr
+	movx a, @dptr
+	mov r4, a		; r4 = wValueH
+
+	;; main switch on bmRequest.type: standard or vendor
+	mov a, r1
+	anl a, #0x60
+	cjne a, #0x00, setup_bmreq_type_not_standard
+	;; standard request: now main switch is on bRequest
+	ljmp setup_bmreq_is_standard
+	
+setup_bmreq_type_not_standard:	
+	;; a still has bmreq&0x60
+	cjne a, #0x40, setup_bmreq_type_not_vendor
+	;; Anchor reserves bRequest 0xa0-0xaf, we use small ones
+	;; switch on bRequest. bmRequest will always be 0x41 or 0xc1
+	cjne r2, #0x00, setup_ctrl_not_00
+	;; 00 is set baud, wValue[0] has baud rate index
+	lcall set_baud		; index in r3, carry set if error
+	jc setup_bmreq_type_not_standard__do_stall
+	ljmp setup_done_ack
+setup_bmreq_type_not_standard__do_stall:
+	ljmp setup_stall
+setup_ctrl_not_00:
+	cjne r2, #0x01, setup_ctrl_not_01
+	;; 01 is reserved for set bits (parity). TODO
+	ljmp setup_stall
+setup_ctrl_not_01:
+	cjne r2, #0x02, setup_ctrl_not_02
+	;; 02 is set HW flow control. TODO
+	ljmp setup_stall
+setup_ctrl_not_02:
+	cjne r2, #0x03, setup_ctrl_not_03
+	;; 03 is control pins (RTS, DTR).
+	ljmp control_pins	; will jump to setup_done_ack,
+				;  or setup_return_one_byte
+setup_ctrl_not_03:
+	cjne r2, #0x04, setup_ctrl_not_04
+	;; 04 is send break (really "turn break on/off"). TODO
+	cjne r3, #0x00, setup_ctrl_do_break_on
+	;; do break off: restore PORTCCFG.1 to reconnect TxD0 to serial port
+	mov dptr, PORTCCFG
+	movx a, @dptr
+	orl a, #0x02
+	movx @dptr, a
+	ljmp setup_done_ack
+setup_ctrl_do_break_on:
+	;; do break on: clear PORTCCFG.0, set TxD high(?) (b1 low)
+	mov dptr, OUTC
+	movx a, @dptr
+	anl a, #0xfd		; ~0x02
+	movx @dptr, a
+	mov dptr, PORTCCFG
+	movx a, @dptr
+	anl a, #0xfd		; ~0x02
+	movx @dptr, a
+	ljmp setup_done_ack
+setup_ctrl_not_04:
+	cjne r2, #0x05, setup_ctrl_not_05
+	;; 05 is set desired interrupt bitmap. TODO
+	ljmp setup_stall
+setup_ctrl_not_05:
+	cjne r2, #0x06, setup_ctrl_not_06
+	;; 06 is query room
+	cjne r3, #0x00, setup_ctrl_06_not_00
+	;; 06, wValue[0]=0 is query write_room
+	mov a, tx_ring_out
+	setb c
+	subb a, tx_ring_in	; out-1-in = 255 - (in-out)
+	ljmp setup_return_one_byte
+setup_ctrl_06_not_00:
+	cjne r3, #0x01, setup_ctrl_06_not_01
+	;; 06, wValue[0]=1 is query chars_in_buffer
+	mov a, tx_ring_in
+	clr c
+	subb a, tx_ring_out	; in-out
+	ljmp setup_return_one_byte
+setup_ctrl_06_not_01:	
+	ljmp setup_stall
+setup_ctrl_not_06:
+	cjne r2, #0x07, setup_ctrl_not_07
+	;; 07 is request tx unthrottle interrupt
+	mov tx_unthrottle_threshold, r3; wValue[0] is threshold value
+	ljmp setup_done_ack
+setup_ctrl_not_07:
+	ljmp setup_stall
+	
+setup_bmreq_type_not_vendor:
+	ljmp setup_stall
+
+
+setup_bmreq_is_standard:	
+	cjne r2, #0x00, setup_breq_not_00
+	;; 00:	Get_Status (sub-switch on bmRequestType: device, ep, int)
+	cjne r1, #0x80, setup_Get_Status_not_device
+	;; Get_Status(device)
+	;;  are we self-powered? no. can we do remote wakeup? no
+	;;   so return two zero bytes. This is reusable
+setup_return_two_zero_bytes:
+	mov dptr, IN0BUF
+	clr a
+	movx @dptr, a
+	inc dptr
+	movx @dptr, a
+	mov dptr, IN0BC
+	mov a, #2
+	movx @dptr, a
+	ljmp setup_done_ack
+setup_Get_Status_not_device:
+	cjne r1, #0x82, setup_Get_Status_not_endpoint
+	;; Get_Status(endpoint)
+	;;  must get stall bit for ep[wIndexL], return two bytes, bit in lsb 0
+	;; for now: cheat. TODO
+	sjmp setup_return_two_zero_bytes
+setup_Get_Status_not_endpoint:
+	cjne r1, #0x81, setup_Get_Status_not_interface
+	;; Get_Status(interface): return two zeros
+	sjmp setup_return_two_zero_bytes
+setup_Get_Status_not_interface:	
+	ljmp setup_stall
+	
+setup_breq_not_00:
+	cjne r2, #0x01, setup_breq_not_01
+	;; 01:	Clear_Feature (sub-switch on wValueL: stall, remote wakeup)
+	cjne r3, #0x00, setup_Clear_Feature_not_stall
+	;; Clear_Feature(stall). should clear a stall bit. TODO
+	ljmp setup_stall
+setup_Clear_Feature_not_stall:
+	cjne r3, #0x01, setup_Clear_Feature_not_rwake
+	;; Clear_Feature(remote wakeup). ignored.
+	ljmp setup_done_ack
+setup_Clear_Feature_not_rwake:
+	ljmp setup_stall
+	
+setup_breq_not_01:
+	cjne r2, #0x03, setup_breq_not_03
+	;; 03:	Set_Feature (sub-switch on wValueL: stall, remote wakeup)
+	cjne r3, #0x00, setup_Set_Feature_not_stall
+	;; Set_Feature(stall). Should set a stall bit. TODO
+	ljmp setup_stall
+setup_Set_Feature_not_stall:
+	cjne r3, #0x01, setup_Set_Feature_not_rwake
+	;; Set_Feature(remote wakeup). ignored.
+	ljmp setup_done_ack
+setup_Set_Feature_not_rwake:
+	ljmp setup_stall
+	
+setup_breq_not_03:	
+	cjne r2, #0x06, setup_breq_not_06
+	;; 06:	Get_Descriptor (s-switch on wValueH: dev, config[n], string[n])
+	cjne r4, #0x01, setup_Get_Descriptor_not_device
+	;; Get_Descriptor(device)
+	mov dptr, SUDPTRH
+	mov a, #HIGH(desc_device)
+	movx @dptr, a
+	mov dptr, SUDPTRL
+	mov a, #LOW(desc_device)
+	movx @dptr, a
+	ljmp setup_done_ack
+setup_Get_Descriptor_not_device:
+	cjne r4, #0x02, setup_Get_Descriptor_not_config
+	;; Get_Descriptor(config[n])
+	cjne r3, #0x00, setup_stall; only handle n==0
+	;; Get_Descriptor(config[0])
+	mov dptr, SUDPTRH
+	mov a, #HIGH(desc_config1)
+	movx @dptr, a
+	mov dptr, SUDPTRL
+	mov a, #LOW(desc_config1)
+	movx @dptr, a
+	ljmp setup_done_ack
+setup_Get_Descriptor_not_config:
+	cjne r4, #0x03, setup_Get_Descriptor_not_string
+	;; Get_Descriptor(string[wValueL])
+	;;  if (wValueL >= maxstrings) stall
+	mov a, #((desc_strings_end-desc_strings)/2)
+	clr c
+	subb a,r3		; a=4, r3 = 0..3 . if a<=0 then stall
+	jc  setup_stall
+	jz  setup_stall
+	mov a, r3
+	add a, r3		; a = 2*wValueL
+	mov dptr, #desc_strings
+	add a, dpl
+	mov dpl, a
+	mov a, #0
+	addc a, dph
+	mov dph, a		; dph = desc_strings[a]. big endian! (handy)
+	;; it looks like my adapter uses a revision of the EZUSB that
+	;; contains "rev D errata number 8", as hinted in the EzUSB example
+	;; code. I cannot find an actual errata description on the Cypress
+	;; web site, but from the example code it looks like this bug causes
+	;; the length of string descriptors to be read incorrectly, possibly
+	;; sending back more characters than the descriptor has. The workaround
+	;; is to manually send out all of the data. The consequence of not
+	;; using the workaround is that the strings gathered by the kernel
+	;; driver are too long and are filled with trailing garbage (including
+	;; leftover strings). Writing this out by hand is a nuisance, so for
+	;; now I will just live with the bug.
+	movx a, @dptr
+	mov r1, a
+	inc dptr
+	movx a, @dptr
+	mov r2, a
+	mov dptr, SUDPTRH
+	mov a, r1
+	movx @dptr, a
+	mov dptr, SUDPTRL
+	mov a, r2
+	movx @dptr, a
+	;; done
+	ljmp setup_done_ack
+	
+setup_Get_Descriptor_not_string:
+	ljmp setup_stall
+	
+setup_breq_not_06:
+	cjne r2, #0x08, setup_breq_not_08
+	;; Get_Configuration. always 1. return one byte.
+	;; this is reusable
+	mov a, #1
+setup_return_one_byte:	
+	mov dptr, IN0BUF
+	movx @dptr, a
+	mov a, #1
+	mov dptr, IN0BC
+	movx @dptr, a
+	ljmp setup_done_ack
+setup_breq_not_08:
+	cjne r2, #0x09, setup_breq_not_09
+	;; 09: Set_Configuration. ignored.
+	ljmp setup_done_ack
+setup_breq_not_09:
+	cjne r2, #0x0a, setup_breq_not_0a
+	;; 0a: Get_Interface. get the current altsetting for int[wIndexL]
+	;;  since we only have one interface, ignore wIndexL, return a 0
+	mov a, #0
+	ljmp setup_return_one_byte
+setup_breq_not_0a:
+	cjne r2, #0x0b, setup_breq_not_0b
+	;; 0b: Set_Interface. set altsetting for interface[wIndexL]. ignored
+	ljmp setup_done_ack
+setup_breq_not_0b:
+	ljmp setup_stall
+
+		
+setup_done_ack:	
+	;; now clear HSNAK
+	mov dptr, EP0CS
+	mov a, #0x02
+	movx @dptr, a
+	sjmp setup_done
+setup_stall:	
+	;; unhandled. STALL
+	;EP0CS |= bmEPSTALL
+	mov dptr, EP0CS
+	movx a, @dptr
+	orl a, EP0STALLbit
+	movx @dptr, a
+	sjmp setup_done
+	
+setup_done:	
+	pop acc
+	pop dph1
+	pop dpl1
+	pop dph
+	pop dpl
+	pop dps
+	reti
+
+;;; ==============================================================
+	
+set_baud:			; baud index in r3
+	;; verify a < 10
+	mov a, r3
+	jb ACC.7, set_baud__badbaud
+	clr c
+	subb a, #10
+	jnc set_baud__badbaud
+	mov a, r3
+	rl a			; a = index*2
+	add a, #LOW(baud_table)
+	mov dpl, a
+	mov a, #HIGH(baud_table)
+	addc a, #0
+	mov dph, a
+	;; TODO: shut down xmit/receive
+	;; TODO: wait for current xmit char to leave
+	;; TODO: shut down timer to avoid partial-char glitch
+	movx a, at dptr		; BAUD_HIGH
+	mov RCAP2H, a
+	mov TH2, a
+	inc dptr
+	movx a, at dptr		; BAUD_LOW
+	mov RCAP2L, a
+	mov TL2, a
+	;; TODO: restart xmit/receive
+	;; TODO: reenable interrupts, resume tx if pending
+	clr c			; c=0: success
+	ret
+set_baud__badbaud:
+	setb c			; c=1: failure
+	ret
+	
+;;; ==================================================
+control_pins:
+	cjne r1, #0x41, control_pins_in
+control_pins_out:
+		;TODO BKPT is DTR
+	mov a, r3 ; wValue[0] holds new bits:	b7 is new RTS
+	xrl a, #0xff		; 1 means active, 0V, +12V ?
+	anl a, #0x80
+	mov r3, a
+	mov dptr, OUTC
+	movx a, @dptr		; only change bit 7 
+	anl a, #0x7F		; ~0x84
+	orl a, r3
+	movx @dptr, a		; other pins are inputs, bits ignored
+	ljmp setup_done_ack
+control_pins_in:
+	mov dptr, PINSC
+	movx a, @dptr
+	xrl a, #0xff
+	ljmp setup_return_one_byte
+
+;;; ========================================
+	
+ISR_Ep2in:
+	push dps
+	push dpl
+	push dph
+	push dpl1
+	push dph1
+	push acc
+	mov a,EXIF
+	clr acc.4
+	mov EXIF,a		; clear INT2 first
+	mov dptr, IN07IRQ	; clear USB int
+	mov a,#04h
+	movx @dptr,a
+
+	mov a, #0x20             ; Turn off the green LED
+        mov dptr,OEA
+        movx @dptr, a
+
+
+	;; do stuff
+	lcall start_in
+
+	mov a, #0x20             ; Turn off the green LED
+        mov dptr,OEA
+        movx @dptr, a
+
+
+	
+	pop acc
+	pop dph1
+	pop dpl1
+	pop dph
+	pop dpl
+	pop dps
+	reti
+
+ISR_Ep2out:
+	push dps
+	push dpl
+	push dph
+	push dpl1
+	push dph1
+	push acc
+
+        mov a, #0x10             ; Turn the green LED
+        mov dptr,OEA
+        movx @dptr, a
+
+
+
+	mov a,EXIF
+	clr acc.4
+	mov EXIF,a		; clear INT2 first
+	mov dptr, OUT07IRQ	; clear USB int
+	mov a,#04h
+	movx @dptr,a
+
+	;; do stuff
+
+	;; copy data into buffer. for now, assume we will have enough space
+	mov dptr, OUT2BC	; get byte count
+	movx a, at dptr
+	mov r1, a
+	clr a
+	mov dps, a
+	mov dptr, OUT2BUF	; load DPTR0 with source
+	mov dph1, #HIGH(tx_ring)	; load DPTR1 with target
+	mov dpl1, tx_ring_in
+OUT_loop:
+	movx a, at dptr		; read
+	inc dps			; switch to DPTR1: target
+	inc dpl1		; target = tx_ring_in+1
+	movx @dptr,a		; store
+	mov a,dpl1
+	cjne a, tx_ring_out, OUT_no_overflow
+	sjmp OUT_overflow
+OUT_no_overflow:	
+	inc tx_ring_in		; tx_ring_in++
+	inc dps			; switch to DPTR0: source
+	inc dptr
+	djnz r1, OUT_loop
+	sjmp OUT_done
+OUT_overflow:
+	;; signal overflow
+	;; fall through
+OUT_done:	
+	;; ack
+	mov dptr,OUT2BC
+	movx @dptr,a
+
+	;; start tx
+	acall maybe_start_tx
+	;acall dump_stat
+
+        mov a, #0x20             ; Turn off the green LED
+        mov dptr,OEA
+        movx @dptr, a
+	
+	pop acc
+	pop dph1
+	pop dpl1
+	pop dph
+	pop dpl
+	pop dps
+	reti
+
+dump_stat:
+	;; fill in EP4in with a debugging message:
+	;;   tx_ring_in, tx_ring_out, rx_ring_in, rx_ring_out
+	;;   tx_active
+	;;   tx_ring[0..15]
+	;;   0xfc
+	;;   rx_ring[0..15]
+	clr a
+	mov dps, a
+	
+	mov dptr, IN4CS
+	movx a, @dptr
+	jb acc.1, dump_stat__done; busy: cannot dump, old one still pending
+	mov dptr, IN4BUF
+	
+	mov a, tx_ring_in
+	movx @dptr, a
+	inc dptr
+	mov a, tx_ring_out
+	movx @dptr, a
+	inc dptr
+
+	mov a, rx_ring_in
+	movx @dptr, a
+	inc dptr
+	mov a, rx_ring_out
+	movx @dptr, a
+	inc dptr
+	
+	clr a
+	jnb TX_RUNNING, dump_stat__no_tx_running
+	inc a
+dump_stat__no_tx_running:
+	movx @dptr, a
+	inc dptr
+	;; tx_ring[0..15]
+	inc dps
+	mov dptr, #tx_ring	; DPTR1: source
+	mov r1, #16
+dump_stat__tx_ring_loop:
+	movx a, @dptr
+	inc dptr
+	inc dps
+	movx @dptr, a
+	inc dptr
+	inc dps
+	djnz r1, dump_stat__tx_ring_loop
+	inc dps
+	
+	mov a, #0xfc
+	movx @dptr, a
+	inc dptr
+	
+	;; rx_ring[0..15]
+	inc dps
+	mov dptr, #rx_ring	; DPTR1: source
+	mov r1, #16
+dump_stat__rx_ring_loop:
+	movx a, @dptr
+	inc dptr
+	inc dps
+	movx @dptr, a
+	inc dptr
+	inc dps
+	djnz r1, dump_stat__rx_ring_loop
+	
+	;; now send it
+	clr a
+	mov dps, a
+	mov dptr, IN4BC
+	mov a, #38
+	movx @dptr, a
+dump_stat__done:	
+	ret
+		
+;;; ============================================================
+	
+maybe_start_tx:
+	;; make sure the tx process is running.
+	jb TX_RUNNING, start_tx_done
+start_tx:
+	;; is there work to be done?
+	mov a, tx_ring_in
+	cjne a,tx_ring_out, start_tx__work
+	ret			; no work
+start_tx__work:	
+	;; tx was not running. send the first character, setup the TI int
+	inc tx_ring_out		; [++tx_ring_out]
+	mov dph, #HIGH(tx_ring)
+	mov dpl, tx_ring_out
+	movx a, @dptr
+	mov sbuf, a
+	setb TX_RUNNING
+start_tx_done:
+	;; can we unthrottle the host tx process?
+	;;  step 1: do we care?
+	mov a, #0
+	cjne a, tx_unthrottle_threshold, start_tx__maybe_unthrottle_tx
+	;; nope
+start_tx_really_done:
+	ret
+start_tx__maybe_unthrottle_tx:
+	;;  step 2: is there now room?
+	mov a, tx_ring_out
+	setb c
+	subb a, tx_ring_in
+	;; a is now write_room. If thresh >= a, we can unthrottle
+	clr c
+	subb a, tx_unthrottle_threshold
+	jc start_tx_really_done	; nope
+	;; yes, we can unthrottle. remove the threshold and mark a request
+	mov tx_unthrottle_threshold, #0
+	setb DO_TX_UNTHROTTLE
+	;; prod rx, which will actually send the message when in2 becomes free
+	ljmp start_in
+	
+
+serial_int:
+	push dps
+	push dpl
+	push dph
+	push dpl1
+	push dph1
+	push acc
+	jnb TI, serial_int__not_tx
+	;; tx finished. send another character if we have one
+	clr TI			; clear int
+	clr TX_RUNNING
+	lcall start_tx
+serial_int__not_tx:
+	jnb RI, serial_int__not_rx
+	lcall get_rx_char
+	clr RI			; clear int
+serial_int__not_rx:	
+	;; return
+	pop acc
+	pop dph1
+	pop dpl1
+	pop dph
+	pop dpl
+	pop dps
+	reti
+
+get_rx_char:
+	mov dph, #HIGH(rx_ring)
+	mov dpl, rx_ring_in
+	inc dpl			; target = rx_ring_in+1
+	mov a, sbuf
+	movx @dptr, a
+	;; check for overflow before incrementing rx_ring_in
+	mov a, dpl
+	cjne a, rx_ring_out, get_rx_char__no_overflow
+	;; signal overflow
+	ret
+get_rx_char__no_overflow:	
+	inc rx_ring_in
+	;; kick off USB INpipe
+	acall start_in
+	ret
+
+start_in:
+	;; check if the inpipe is already running.
+	mov  a,#0x10
+	mov dptr, OEA
+	movx @dptr,a
+
+	mov dptr, IN2CS
+	movx a, @dptr
+	jb acc.1, start_in__done; int will handle it
+	jb DO_TX_UNTHROTTLE, start_in__do_tx_unthrottle
+	;; see if there is any work to do. a serial interrupt might occur
+	;; during this sequence?
+	mov a, rx_ring_in
+	cjne a, rx_ring_out, start_in__have_work
+	ret			; nope
+start_in__have_work:	
+	;; now copy as much data as possible into the pipe. 63 bytes max.
+	clr a
+	mov dps, a
+	mov dph, #HIGH(rx_ring)	; load DPTR0 with source
+	inc dps
+	mov dptr, IN2BUF	; load DPTR1 with target
+	movx @dptr, a		; in[0] signals that rest of IN is rx data
+	inc dptr
+	inc dps
+	;; loop until we run out of data, or we have copied 64 bytes
+	mov r1, #1		; INbuf size counter
+start_in__loop:
+	mov a, rx_ring_in
+	cjne a, rx_ring_out, start_inlocal_irq_enablell_copying
+	sjmp start_in__kick
+start_inlocal_irq_enablell_copying:
+	inc rx_ring_out
+	mov dpl, rx_ring_out
+	movx a, @dptr
+	inc dps
+	movx @dptr, a		; write into IN buffer
+	inc dptr
+	inc dps
+	inc r1
+	cjne r1, #64, start_in__loop; loop
+start_in__kick:
+	;; either we ran out of data, or we copied 64 bytes. r1 has byte count
+	;; kick off IN
+	mov a, #0x10             ; Turn the green LED
+        mov dptr,OEA
+        movx @dptr, a
+	mov dptr, IN2BC
+	mov a, r1
+	jz start_in__done
+	movx @dptr, a
+	;; done
+start_in__done:
+	;acall dump_stat
+	ret
+start_in__do_tx_unthrottle:
+	;; special sequence: send a tx unthrottle message
+	clr DO_TX_UNTHROTTLE
+	clr a
+	mov dps, a
+	mov dptr, IN2BUF
+	mov a, #1
+	movx @dptr, a
+	inc dptr
+	mov a, #2
+	movx @dptr, a
+	mov dptr, IN2BC
+	movx @dptr, a
+	ret
+	
+putchar:
+	clr TI
+	mov SBUF, a
+putchar_wait:
+	jnb TI, putchar_wait
+	clr TI
+	ret
+
+	
+baud_table:			; baud_high, then baud_low
+	;; baud[0]: 110
+	.byte BAUD_HIGH(110)
+	.byte BAUD_LOW(110)
+	;; baud[1]: 300
+	.byte BAUD_HIGH(300)
+	.byte BAUD_LOW(300)
+	;; baud[2]: 1200
+	.byte BAUD_HIGH(1200)
+	.byte BAUD_LOW(1200)
+	;; baud[3]: 2400
+	.byte BAUD_HIGH(2400)
+	.byte BAUD_LOW(2400)
+	;; baud[4]: 4800
+	.byte BAUD_HIGH(4800)
+	.byte BAUD_LOW(4800)
+	;; baud[5]: 9600
+	.byte BAUD_HIGH(9600)
+	.byte BAUD_LOW(9600)
+	;; baud[6]: 19200
+	.byte BAUD_HIGH(19200)
+	.byte BAUD_LOW(19200)
+	;; baud[7]: 38400
+	.byte BAUD_HIGH(38400)
+	.byte BAUD_LOW(38400)
+	;; baud[8]: 57600
+	.byte BAUD_HIGH(57600)
+	.byte BAUD_LOW(57600)
+	;; baud[9]: 115200
+	.byte BAUD_HIGH(115200)
+	.byte BAUD_LOW(115200)
+
+desc_device:
+	.byte 0x12, 0x01, 0x00, 0x01, 0xff, 0xff, 0xff, 0x40
+	.byte 0xcd, 0x06, 0x04, 0x01, 0x89, 0xab, 1, 2, 3, 0x01
+;;; The "real" device id, which must match the host driver, is that
+;;; "0xcd 0x06 0x04 0x01" sequence, which is 0x06cd, 0x0104
+	
+desc_config1:
+	.byte 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32
+	.byte 0x09, 0x04, 0x00, 0x00, 0x02, 0xff, 0xff, 0xff, 0x00
+	.byte 0x07, 0x05, 0x82, 0x03, 0x40, 0x00, 0x01
+	.byte 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00
+
+desc_strings:
+	.word string_langids, string_mfg, string_product, string_serial
+desc_strings_end:
+
+string_langids:	.byte string_langids_end-string_langids
+	.byte 3
+	.word 0
+string_langids_end:
+
+	;; sigh. These strings are Unicode, meaning UTF16? 2 bytes each. Now
+	;; *that* is a pain in the ass to encode. And they are little-endian
+	;; too. Use this perl snippet to get the bytecodes:
+	/* while (<>) {
+	    @c = split(//);
+	    foreach $c (@c) {
+	     printf("0x%02x, 0x00, ", ord($c));
+	    }
+	   }
+	*/
+
+string_mfg:	.byte string_mfg_end-string_mfg
+	.byte 3
+;	.byte "ACME usb widgets"
+	.byte 0x41, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x45, 0x00, 0x20, 0x00, 0x75, 0x00, 0x73, 0x00, 0x62, 0x00, 0x20, 0x00, 0x77, 0x00, 0x69, 0x00, 0x64, 0x00, 0x67, 0x00, 0x65, 0x00, 0x74, 0x00, 0x73, 0x00
+string_mfg_end:
+	
+string_product:	.byte string_product_end-string_product
+	.byte 3
+;	.byte "ACME USB serial widget"
+	.byte 0x41, 0x00, 0x43, 0x00, 0x4d, 0x00, 0x45, 0x00, 0x20, 0x00, 0x55, 0x00, 0x53, 0x00, 0x42, 0x00, 0x20, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x77, 0x00, 0x69, 0x00, 0x64, 0x00, 0x67, 0x00, 0x65, 0x00, 0x74, 0x00
+string_product_end:
+	
+string_serial:	.byte string_serial_end-string_serial
+	.byte 3
+;	.byte "47"
+	.byte 0x34, 0x00, 0x37, 0x00
+string_serial_end:
+		
+;;; ring buffer memory
+	;; tx_ring_in+1 is where the next input byte will go
+	;; [tx_ring_out] has been sent
+	;; if tx_ring_in == tx_ring_out, theres no work to do
+	;; there are (tx_ring_in - tx_ring_out) chars to be written
+	;; dont let _in lap _out
+	;;   cannot inc if tx_ring_in+1 == tx_ring_out
+	;;  write [tx_ring_in+1] then tx_ring_in++
+	;;   if (tx_ring_in+1 == tx_ring_out), overflow
+	;;   else tx_ring_in++
+	;;  read/send [tx_ring_out+1], then tx_ring_out++
+
+	;; rx_ring_in works the same way
+	
+	.org 0x1000
+tx_ring:
+	.skip 0x100		; 256 bytes
+rx_ring:
+	.skip 0x100		; 256 bytes
+	
+	
+	.END
+	

Added: dists/trunk/firmware-free/linux-free/keyspan_pda/xircom_pgs.fw
==============================================================================
Binary file. No diff available.

Added: dists/trunk/firmware-free/linux-free/usbdux/Makefile_dux
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/firmware-free/linux-free/usbdux/Makefile_dux	Thu Jan 14 23:13:43 2010	(r14942)
@@ -0,0 +1,19 @@
+# (c) Bernd Porr
+# GNU public license
+# no warranty
+#
+
+all: as31 usbduxfast_firmware.bin usbdux_firmware.bin
+
+as31:
+	make -C as31-2.1
+
+usbduxfast_firmware.bin: fx2-include.asm usbduxfast_firmware.asm as31
+	as31-2.1/as31 -Fbin usbduxfast_firmware.asm
+
+usbdux_firmware.bin: fx2-include.asm usbdux_firmware.asm as31
+	as31-2.1/as31 -Fbin usbdux_firmware.asm
+
+clean:
+	rm -f *.bin *~ *.lst *.bin
+	make -C as31-2.1 clean

Added: dists/trunk/firmware-free/linux-free/usbdux/README.dux
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/firmware-free/linux-free/usbdux/README.dux	Thu Jan 14 23:13:43 2010	(r14942)
@@ -0,0 +1,15 @@
+To compile the firmware for the USBDUX and USBDUXfast
+-----------------------------------------------------
+Download the as31 from:
+
+http://www.berndporr.me.uk/as31/
+
+(this is a patched version of as31 which supports an
+include directive).
+
+Install it in this directory.
+
+Then run "make -f Makefile_dux".
+
+Feedback:
+BerndPorr at f2s.com

Added: dists/trunk/firmware-free/linux-free/usbdux/fx2-include.asm
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/firmware-free/linux-free/usbdux/fx2-include.asm	Thu Jan 14 23:13:43 2010	(r14942)
@@ -0,0 +1,164 @@
+; rev 0.9
+; (c) Bernd Porr, Bernd.Porr at cn.stir.ac.uk
+; GPL, GNU public license
+;
+;   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.
+;
+;   This program is distributed in the hope that it will be useful,
+;   but WITHOUT ANY WARRANTY; without even the implied warranty of
+;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;   GNU General Public License for more details.
+;
+;   You should have received a copy of the GNU General Public License
+;   along with this program; if not, write to the Free Software
+;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+;
+; In conjunction with the as31.
+; Include-file for the FX2 by Cypress. The rest of the regs is defined
+; by the as31 itself.
+;
+; from the TRM of the FX2:
+;
+	;;  CPU control
+	.equ	CPUCS,0E600H
+	.equ	REVCTL,0E60BH
+	;; interface config
+	.equ	IFCONFIG,0E601H
+	.equ	FIFORESET,0E604H
+	;; Endpoint configs
+	.equ	EP1OUTCFG,0E610H
+	.equ	EP1INCFG,0E611H
+	.equ	EP2CFG,0E612H
+	.equ	EP4CFG,0E613H
+	.equ	EP6CFG,0E614H
+	.equ	EP8CFG,0E615H
+	;; packets per frame, always one for USB 1.1
+	.equ	EP2ISOINPKTS,0E640H
+	.equ	EP4ISOINPKTS,0E641H
+	.equ	EP6ISOINPKTS,0E642H
+	.equ	EP8ISOINPKTS,0E643H
+	;; endpoint byte counts
+	.equ	EP1OUTBC,0E68DH
+	.equ	EP1INBC,0E68FH
+	.equ	EP1INCS,0E6A2H
+	.equ	EP2BCH,0E690H
+	.equ	EP2BCL,0E691H
+	.equ	EP4BCH,0E694H
+	.equ	EP4BCL,0E695H
+	.equ	EP6BCH,0E698H
+	.equ	EP6BCL,0E699H
+	.equ	EP8BCH,0E69CH
+	.equ	EP8BCL,0E69DH
+	;;
+	.equ	EP4AUTOINLENH,0E622H
+	.equ	EP4AUTOINLENL,0E623H
+	.equ	EP6AUTOINLENH,0E624H
+	.equ	EP6AUTOINLENL,0E625H
+	.equ	EP2FIFOCFG,0E618H
+	.equ	EP4FIFOCFG,0E619H
+	.equ	EP6FIFOCFG,0E61AH
+	.equ	EP8FIFOCFG,0E61BH
+	;; 
+	.equ	INPKTEND,0E648H
+	.equ	GPIFCTLCFG,0E6C3H
+	.equ	GPIFABORT,0E6F5H
+	.equ	GPIFIDLECTL,0E6C2H
+	.equ	GPIFWFSELECT,0E6C0H
+	.equ	GPIFREADYCFG,0E6F3H
+	.equ	GPIFIDLECS,0E6C1H
+	.equ	EP6GPIFFLGSEL,0E6E2H
+	.equ	EP6GPIFPDFSTOP,0E6E3H
+	.equ	EP6GPIFTRIG,0E6E4H
+	.equ	GPIFIE,0E660H
+	.equ	GPIFIRQ,0E661H
+	;; 
+	;; endpoint control
+	.equ	EP2CS,0E6A3H
+	.equ	EP4CS,0E6A4H
+	.equ	EP6CS,0E6A5H
+	.equ	EP8CS,0E6A6H
+	;; endpoint buffers
+	.equ	EP2FIFOBUF,0F000H
+	.equ	EP4FIFOBUF,0F400H
+	.equ	EP6FIFOBUF,0F800H
+	.equ	EP8FIFOBUF,0FC00H
+	;; IRQ enable for bulk NAK
+	.equ	IBNIE,0E658H
+	;; interrupt requ for NAK
+	.equ	IBNIRQ,0E659H
+	;; USB INT enables
+	.equ	USBIE,0E65CH
+	;; USB interrupt request
+	.equ	USBIRQ,0E65DH
+	;; endpoint IRQ enable
+	.equ	EPIE,0E65EH
+	;; endpoint IRQ requests
+	.equ	EPIRQ,0E65FH
+	;; USB error IRQ requests
+	.equ	USBERRIE,0E662H
+	;; USB error IRQ request
+	.equ	USBERRIRQ,0E663H
+	;; USB interrupt 2 autovector
+	.equ	INT2IVEC,0E666H
+	;; autovector enable
+	.equ	INTSETUP,0E668H
+	;; port cfg
+	.equ	PORTACFG,0E670H
+	.equ	PORTCCFG,0E671H
+	.equ	PORTECFG,0E672H
+	;; I2C bus
+	.equ	I2CS,0E678H
+	.equ	I2DAT,0E679H
+	.equ	I2CTL,0E67AH
+	;; auto pointers, read/write is directed to the pointed address
+	.equ	XAUTODAT1,0E67BH
+	.equ	XAUTODAT2,0E67CH
+	;; USB-control
+	.equ	USBCS,0E680H
+	;; force packet end
+	.equ    OUTPKTEND,0E649H
+	.equ	IOA,80H
+	.equ	DPL1,84H
+	.equ	DPH1,85H
+	.equ	DPS,86H
+	.equ	CKCON,8Eh
+	.equ	IOB,90H
+	.equ	EXIF,91h
+	.equ	MPAGE,92h
+	.equ	AUTOPTRH1,9AH
+	.equ	AUTOPTRL1,9BH
+	.equ	AUTOPTRH2,9DH
+	.equ	AUTOPTRL2,9EH
+	.equ	IOC,0A0H
+	.equ	INT2CLR,0A1H
+	.equ	INT4CLR,0A2H
+	.equ	EP2468STAT,0AAH
+	.equ	EP24FIFOFLGS,0ABH
+	.equ	EP68FIFOFLGS,0ACH
+	.equ	AUTOPTRSETUP,0AFH
+	.equ	IOD,0B0H
+	.equ	IOE,0B1H
+	.equ	OEA,0B2H
+	.equ	OEB,0B3H
+	.equ	OEC,0B4H
+	.equ	OED,0B5H
+	.equ	OEE,0B6H
+	.equ	GPIFTRIG,0BBH
+	.equ	EIE,0E8h
+	.equ	EIP,0F8h
+
+	
+	;; GPIF
+	.equ	GPIFTCB3,0E6CEH
+	.equ	GPIFTCB2,0E6CFH
+	.equ	GPIFTCB1,0E6D0H
+	.equ	GPIFTCB0,0E6D1H
+	.equ	EP4GPIFFLGSEL,0E6DAH
+	.equ	EP4GPIFPFSTOP,0E6DBH
+
+
+	;;; end of file
+	

Added: dists/trunk/firmware-free/linux-free/usbdux/usbdux_firmware.asm
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/firmware-free/linux-free/usbdux/usbdux_firmware.asm	Thu Jan 14 23:13:43 2010	(r14942)
@@ -0,0 +1,1184 @@
+;   usbdux_firmware.asm
+;   Copyright (C) 2004,2009 Bernd Porr, Bernd.Porr at f2s.com
+;   For usbdux.c
+;
+;   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.
+;
+;   This program is distributed in the hope that it will be useful,
+;   but WITHOUT ANY WARRANTY; without even the implied warranty of
+;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;   GNU General Public License for more details.
+;
+;   You should have received a copy of the GNU General Public License
+;   along with this program; if not, write to the Free Software
+;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+;
+;
+; Firmware: usbdux_firmware.asm for usbdux.c
+; Description: University of Stirling USB DAQ & INCITE Technology Limited
+; Devices: [ITL] USB-DUX (usbdux.o)
+; Author: Bernd Porr <Bernd.Porr at f2s.com>
+; Updated: 17 Apr 2009
+; Status: stable
+;
+;;;
+;;;
+;;;
+
+	.inc	fx2-include.asm
+
+	.equ	CHANNELLIST,80h	; channellist in indirect memory
+	
+	.equ	CMD_FLAG,90h	; flag if next IN transf is DIO
+	.equ	SGLCHANNEL,91h	; channel for INSN
+	.equ	PWMFLAG,92h	; PWM
+	
+	.equ	DIOSTAT0,98h	; last status of the digital port
+	.equ	DIOSTAT1,99h	; same for the second counter
+	
+	.equ	CTR0,0A0H	; counter 0
+	.equ	CTR1,0A2H	; counter 1
+			
+	.org	0000h		; after reset the processor starts here
+	ljmp	main		; jump to the main loop
+
+	.org	000bh		; timer 0 irq
+	ljmp	timer0_isr
+
+	.org	0043h		; the IRQ2-vector
+	ljmp	jmptbl		; irq service-routine
+	
+	.org	0100h		; start of the jump table
+
+jmptbl:	ljmp	sudav_isr
+	nop
+	ljmp	sof_isr
+	nop
+	ljmp	sutok_isr
+	nop
+	ljmp	suspend_isr
+	nop
+	ljmp	usbreset_isr
+	nop
+	ljmp	hispeed_isr
+	nop
+	ljmp	ep0ack_isr
+	nop
+	ljmp	spare_isr
+	nop
+	ljmp	ep0in_isr
+	nop
+	ljmp	ep0out_isr
+	nop
+	ljmp	ep1in_isr
+	nop
+	ljmp	ep1out_isr
+	nop
+	ljmp	ep2_isr
+	nop
+	ljmp	ep4_isr
+	nop
+	ljmp	ep6_isr
+	nop
+	ljmp	ep8_isr
+	nop
+	ljmp	ibn_isr
+	nop
+	ljmp	spare_isr
+	nop
+	ljmp	ep0ping_isr
+	nop
+	ljmp	ep1ping_isr
+	nop
+	ljmp	ep2ping_isr
+	nop
+	ljmp	ep4ping_isr
+	nop
+	ljmp	ep6ping_isr
+	nop
+	ljmp	ep8ping_isr
+	nop
+	ljmp	errlimit_isr
+	nop
+	ljmp	spare_isr
+	nop
+	ljmp	spare_isr
+	nop
+	ljmp	spare_isr
+	nop
+	ljmp	ep2isoerr_isr
+	nop
+	ljmp	ep4isoerr_isr
+	nop
+	ljmp	ep6isoerr_isr
+	nop
+	ljmp	ep8isoerr_isr
+
+	
+	;; dummy isr
+sudav_isr:	
+sutok_isr:	
+suspend_isr:	
+usbreset_isr:	
+hispeed_isr:	
+ep0ack_isr:	
+spare_isr:	
+ep0in_isr:	
+ep0out_isr:	
+ep1in_isr:	
+ibn_isr:	
+ep0ping_isr:	
+ep1ping_isr:	
+ep2ping_isr:	
+ep4ping_isr:	
+ep6ping_isr:	
+ep8ping_isr:	
+errlimit_isr:	
+ep2isoerr_isr:	
+ep4isoerr_isr:	
+ep6isoerr_isr:	
+ep8isoerr_isr:
+ep6_isr:
+ep2_isr:
+ep4_isr:	
+
+	push	dps
+	push	dpl
+	push	dph
+	push	dpl1
+	push	dph1
+	push	acc
+	push	psw
+
+	;; clear the USB2 irq bit and return
+	mov	a,EXIF
+	clr	acc.4
+	mov	EXIF,a
+
+	pop	psw
+	pop	acc 
+	pop	dph1 
+	pop	dpl1
+	pop	dph 
+	pop	dpl 
+	pop	dps
+	
+	reti
+
+		
+;;; main program
+;;; basically only initialises the processor and
+;;; then engages in an endless loop
+main:
+	mov	DPTR,#CPUCS	; CPU control register
+	mov	a,#00010000b	; 48Mhz
+	lcall	syncdelaywr
+
+        mov     dptr,#REVCTL
+        mov     a,#00000011b    ; allows skip
+        lcall   syncdelaywr
+
+	mov	IP,#0		; all std 8051 int have low priority
+	mov	EIP,#0FFH	; all FX2 interrupts have high priority
+	
+	mov	dptr,#INTSETUP	; IRQ setup register
+	mov	a,#08h		; enable autovector
+	lcall	syncdelaywr
+
+	lcall	initAD		; init the ports to the converters
+
+	lcall	initeps		; init the isochronous data-transfer
+
+	lcall	init_timer
+	
+mloop2:	nop
+
+;;; pwm
+	mov	r0,#PWMFLAG	; pwm on?
+	mov	a, at r0		; get info
+	jz	mloop2		; it's off
+
+	mov	a,GPIFTRIG	; GPIF status
+	anl	a,#80h		; done bit
+	jz	mloop2		; GPIF still busy
+
+        mov     a,#01h		; WR,EP4, 01 = EP4
+        mov     GPIFTRIG,a	; restart it
+
+	sjmp	mloop2		; loop for ever
+
+
+;;; GPIF waveform for PWM
+waveform:
+	;;      0     1     2     3     4     5     6     7(not used)
+	;; len (gives 50.007Hz)
+	.db	195,  195,  195,  195,  195,  195,  1,    1
+
+	;; opcode
+	.db	002H, 006H, 002H, 002H, 002H, 002H, 002H, 002H
+	
+	;; out
+	.db	0ffH, 0ffH, 0ffH, 0ffH, 0ffH, 0ffH, 0ffH, 0ffH
+
+	;; log
+	.db	000H, 000H, 000H, 000H, 000H, 000H, 000H, 000H
+
+
+stopPWM:
+	mov	r0,#PWMFLAG	; flag for PWM
+	mov	a,#0		; PWM (for the main loop)
+	mov	@r0,a		; set it
+
+	mov	dptr,#IFCONFIG	; switch off GPIF
+	mov	a,#10000000b	; gpif, 30MHz, internal IFCLK
+	lcall	syncdelaywr
+	ret
+	
+
+;;; init PWM
+startPWM:
+	mov	dptr,#IFCONFIG	; switch on IFCLK signal
+	mov	a,#10000010b	; gpif, 30MHz, internal IFCLK
+	lcall	syncdelaywr
+
+	mov	OEB,0FFH	; output to port B
+
+	mov	DPTR,#EP4CFG
+	mov	a,#10100000b	; valid, out, bulk
+	movx	@DPTR,a
+
+	;; reset the endpoint
+	mov	dptr,#FIFORESET
+	mov	a,#80h		; NAK
+	lcall	syncdelaywr
+	mov	a,#84h		; reset EP4 + NAK
+	lcall	syncdelaywr
+	mov	a,#0		; normal op
+	lcall	syncdelaywr
+
+	mov	dptr,#EP4BCL
+	mov	a,#0H		; discard packets
+	lcall	syncdelaywr	; empty FIFO buffer
+	lcall	syncdelaywr	; empty FIFO buffer
+
+	;; aborts all transfers by the GPIF
+	mov	dptr,#GPIFABORT
+	mov	a,#0ffh		; abort all transfers
+	lcall	syncdelaywr
+
+	;; wait for GPIF to finish
+wait_f_abort:
+	mov	a,GPIFTRIG	; GPIF status
+	anl	a,#80h		; done bit
+	jz	wait_f_abort	; GPIF busy
+
+        mov     dptr,#GPIFCTLCFG
+        mov     a,#10000000b    ; tri state for CTRL
+        lcall   syncdelaywr
+
+        mov     dptr,#GPIFIDLECTL
+        mov     a,#11110000b    ; all CTL outputs low
+        lcall   syncdelaywr
+
+	;; abort if FIFO is empty
+        mov     a,#00000001b    ; abort if empty
+        mov     dptr,#EP4GPIFFLGSEL
+        lcall   syncdelaywr
+
+	;; 
+        mov     a,#00000001b    ; stop if GPIF flg
+        mov     dptr,#EP4GPIFPFSTOP
+        lcall   syncdelaywr
+
+	;; transaction counter
+	mov	a,#0ffH
+	mov	dptr,#GPIFTCB3
+	lcall	syncdelaywr
+
+	;; transaction counter
+	mov	a,#0ffH
+	mov	dptr,#GPIFTCB2
+	lcall	syncdelaywr
+
+	;; transaction counter
+	mov	a,#0ffH		; 512 bytes
+	mov	dptr,#GPIFTCB1
+	lcall	syncdelaywr
+
+	;; transaction counter
+	mov	a,#0ffH
+	mov	dptr,#GPIFTCB0
+	lcall	syncdelaywr
+
+	;; RDY pins. Not used here.
+        mov     a,#0
+        mov     dptr,#GPIFREADYCFG
+        lcall   syncdelaywr
+
+	;; drives the output in the IDLE state
+        mov     a,#1
+        mov     dptr,#GPIFIDLECS
+        lcall   syncdelaywr
+
+	;; direct data transfer from the EP to the GPIF
+	mov	dptr,#EP4FIFOCFG
+	mov	a,#00010000b	; autoout=1, byte-wide
+	lcall	syncdelaywr
+
+	;; waveform 0 is used for FIFO out
+	mov	dptr,#GPIFWFSELECT
+	mov	a,#00000000b
+	movx	@dptr,a
+	lcall	syncdelay
+
+	;; transfer the delay byte from the EP to the waveform
+	mov	dptr,#0e781h	; EP1 buffer
+	movx	a, at dptr		; get the delay
+	mov	dptr,#waveform	; points to the waveform
+	mov	r2,#6		; fill 6 bytes
+timloop:
+	movx	@dptr,a		; save timing in a xxx
+	inc	dptr
+	djnz	r2,timloop	; fill the 6 delay bytes
+
+	;; load waveform
+        mov     AUTOPTRH2,#0E4H ; XDATA0H
+        lcall   syncdelay
+        mov     AUTOPTRL2,#00H  ; XDATA0L
+        lcall   syncdelay
+
+	mov	dptr,#waveform	; points to the waveform
+	
+        mov     AUTOPTRSETUP,#7 ; autoinc and enable
+        lcall   syncdelay
+
+        mov     r2,#20H         ; 32 bytes to transfer
+
+wavetr:
+        movx    a, at dptr
+	inc	dptr
+	push	dpl
+	push	dph
+	push	dpl1
+	push	dph1
+        mov     dptr,#XAUTODAT2
+        movx    @dptr,a
+        lcall   syncdelay
+	pop	dph1 
+	pop	dpl1
+	pop	dph 
+	pop	dpl
+        djnz    r2,wavetr
+
+	mov	dptr,#OUTPKTEND
+	mov	a,#084H
+	lcall	syncdelaywr
+	lcall	syncdelaywr
+
+	mov	r0,#PWMFLAG	; flag for PWM
+	mov	a,#1		; PWM (for the main loop)
+	mov	@r0,a		; set it
+
+	ret
+
+
+
+;;; initialise the ports for the AD-converter
+initAD:
+	mov	OEA,#27H	;PortA0,A1,A2,A5 Outputs
+	mov	IOA,#22H	;/CS = 1, disable transfers to the converters
+	ret
+
+
+;;; init the timer for the soft counters
+init_timer:
+	;; init the timer for 2ms sampling rate
+	mov	CKCON,#00000001b; CLKOUT/12 for timer
+	mov	TL0,#010H	; 16
+	mov	TH0,#0H		; 256
+	mov	IE,#82H		; switch on timer interrupt (80H for all IRQs)
+	mov	TMOD,#00000000b	; 13 bit counters
+	setb	TCON.4		; enable timer 0
+	ret
+
+
+;;; from here it's only IRQ handling...
+	
+;;; A/D-conversion:
+;;; control-byte in a,
+;;; result in r3(low) and r4(high)
+;;; this routine is optimised for speed
+readAD:				; mask the control byte
+	anl	a,#01111100b	; only the channel, gain+pol are left
+	orl	a,#10000001b	; start bit, external clock
+	;; set CS to low
+	clr	IOA.1		; set /CS to zero
+	;; send the control byte to the AD-converter
+	mov 	R2,#8		; bit-counter
+bitlp:	jnb     ACC.7,bitzero	; jump if Bit7 = 0?
+	setb	IOA.2		; set the DIN bit
+	sjmp	clock		; continue with the clock
+bitzero:clr	IOA.2		; clear the DIN bit
+clock:	setb	IOA.0		; SCLK = 1
+	clr	IOA.0		; SCLK = 0
+        rl      a               ; next Bit
+        djnz    R2,bitlp
+
+	;; continue the aquisition (already started)
+	clr	IOA.2		; clear the DIN bit
+	mov 	R2,#5		; five steps for the aquision
+clockaq:setb	IOA.0		; SCLK = 1
+	clr	IOA.0		; SCLK = 0
+        djnz    R2,clockaq	; loop
+	
+	;; read highbyte from the A/D-converter
+	;; and do the conversion
+	mov	r4,#0 		; Highbyte goes into R4
+	mov	R2,#4		; COUNTER 4 data bits in the MSB
+	mov	r5,#08h		; create bit-mask
+gethi:				; loop get the 8 highest bits from MSB downw
+	setb	IOA.0		; SCLK = 1
+	clr	IOA.0		; SCLK = 0
+	mov	a,IOA		; from port A
+	jnb	ACC.4,zerob	; the in-bit is zero
+	mov	a,r4		; get the byte
+	orl	a,r5		; or the bit to the result
+	mov	r4,a		; save it again in r4
+zerob:	mov	a,r5		; get r5 in order to shift the mask
+	rr	a		; rotate right
+	mov	r5,a		; back to r5
+	djnz	R2,gethi
+	;; read the lowbyte from the A/D-converter
+	mov	r3,#0 		; Lowbyte goes into R3
+	mov	r2,#8		; COUNTER 8 data-bits in the LSB
+	mov	r5,#80h		; create bit-mask
+getlo:				; loop get the 8 highest bits from MSB downw
+	setb	IOA.0		; SCLK = 1
+	clr	IOA.0		; SCLK = 0
+	mov	a,IOA		; from port A
+	jnb	ACC.4,zerob2	; the in-bit is zero
+	mov	a,r3		; get the result-byte
+	orl	a,r5		; or the bit to the result
+	mov	r3,a		; save it again in r4
+zerob2:	mov	a,r5		; get r5 in order to shift the mask
+	rr	a		; rotate right
+	mov	r5,a		; back to r5
+	djnz	R2,getlo
+	setb	IOA.1		; set /CS to one
+	;;
+	ret
+	
+
+	
+;;; aquires data from A/D channels and stores them in the EP6 buffer
+conv_ad:
+	mov	AUTOPTRH1,#0F8H	; auto pointer on EP6
+	mov	AUTOPTRL1,#00H
+	mov	AUTOPTRSETUP,#7
+	mov	r0,#CHANNELLIST	; points to the channellist
+
+	mov	a, at r0		; number of channels
+	mov	r1,a		; counter
+
+	mov 	DPTR,#XAUTODAT1	; auto pointer
+convloop:
+	inc	r0
+	mov 	a, at r0		; Channel
+	lcall 	readAD
+	mov 	a,R3		;
+	movx 	@DPTR,A
+	mov 	a,R4		;
+	movx 	@DPTR,A
+	djnz	r1,convloop
+
+	ret
+
+
+
+
+;;; initilise the transfer
+;;; It is assumed that the USB interface is in alternate setting 3
+initeps:
+	mov	dptr,#FIFORESET
+	mov	a,#80H		
+	movx	@dptr,a		; reset all fifos
+	mov	a,#2	
+	movx	@dptr,a		; 
+	mov	a,#4		
+	movx	@dptr,a		; 
+	mov	a,#6		
+	movx	@dptr,a		; 
+	mov	a,#8		
+	movx	@dptr,a		; 
+	mov	a,#0		
+	movx	@dptr,a		; normal operat
+	
+	mov	DPTR,#EP2CFG
+	mov	a,#10010010b	; valid, out, double buff, iso
+	movx	@DPTR,a
+
+	mov	dptr,#EP2FIFOCFG
+	mov	a,#00000000b	; manual
+	movx	@dptr,a
+
+	mov	dptr,#EP2BCL	; "arm" it
+	mov	a,#00h
+	movx	@DPTR,a		; can receive data
+	lcall	syncdelay	; wait to sync
+	movx	@DPTR,a		; can receive data
+	lcall	syncdelay	; wait to sync
+	movx	@DPTR,a		; can receive data
+	lcall	syncdelay	; wait to sync
+	
+	mov	DPTR,#EP1OUTCFG
+	mov	a,#10100000b	; valid
+	movx	@dptr,a
+
+	mov	dptr,#EP1OUTBC	; "arm" it
+	mov	a,#00h
+	movx	@DPTR,a		; can receive data
+	lcall	syncdelay	; wait until we can write again
+	movx	@dptr,a		; make shure its really empty
+	lcall	syncdelay	; wait
+
+	mov	DPTR,#EP6CFG	; ISO data from here to the host
+	mov	a,#11010010b	; Valid
+	movx	@DPTR,a		; ISO transfer, double buffering
+
+	mov	DPTR,#EP8CFG	; EP8
+	mov	a,#11100000b	; BULK data from here to the host
+	movx	@DPTR,a		;
+
+	mov	dptr,#EPIE	; interrupt enable
+	mov	a,#10001000b	; enable irq for ep1out,8
+	movx	@dptr,a		; do it
+
+	mov	dptr,#EPIRQ	; clear IRQs
+	mov	a,#10100000b
+	movx	@dptr,a
+
+	;; enable interrups
+        mov     DPTR,#USBIE	; USB int enables register
+        mov     a,#2            ; enables SOF (1ms/125us interrupt)
+        movx    @DPTR,a         ; 
+
+	mov	EIE,#00000001b	; enable INT2 in the 8051's SFR
+	mov	IE,#80h		; IE, enable all interrupts
+
+	ret
+
+
+;;; counter
+;;; r0: DIOSTAT
+;;; r1:	counter address
+;;; r2:	up/down-mask
+;;; r3:	reset-mask
+;;; r4:	clock-mask
+counter:	
+	mov	a,IOB		; actual IOB input state
+	mov	r5,a		; save in r5
+	anl	a,r3		; bit mask for reset
+	jz	no_reset	; reset if one
+	clr	a		; set counter to zero
+	mov	@r1,a
+	inc	r4
+	mov	@r1,a
+	sjmp	ctr_end
+no_reset:	
+	mov	a, at r0		; get last state
+	xrl	a,r5		; has it changed?
+	anl	a,r5		; is it now on?
+	anl	a,r4		; mask out the port
+	jz	ctr_end		; no rising edge
+	mov	a,r5		; get port B again
+	anl	a,r2		; test if up or down
+	jnz	ctr_up		; count up
+	mov	a, at r1
+	dec	a
+	mov	@r1,a
+	cjne	a,#0ffh,ctr_end	; underflow?
+	inc	r1		; high byte
+	mov	a, at r1
+	dec	a
+	mov	@r1,a
+	sjmp	ctr_end
+ctr_up:				; count up
+	mov	a, at r1
+	inc	a
+	mov	@r1,a
+	jnz	ctr_end
+	inc	r1		; high byte
+	mov	a, at r1
+	inc	a
+	mov	@r1,a
+ctr_end:
+	mov	a,r5
+	mov	@r0,a
+	ret
+
+;;; implements two soft counters with up/down and reset
+timer0_isr:
+	push	dps
+	push	acc
+	push	psw
+	push	00h		; R0
+	push	01h		; R1
+	push	02h		; R2
+	push	03h		; R3
+	push	04h		; R4
+	push	05h		; R5
+		
+	mov	r0,#DIOSTAT0	; status of port
+	mov	r1,#CTR0	; address of counter0
+	mov	a,#00000001b	; bit 0
+	mov	r4,a		; clock
+	rl	a		; bit 1
+	mov	r2,a		; up/down
+	rl	a		; bit 2
+	mov	r3,a		; reset mask
+	lcall	counter
+	inc	r0		; to DISTAT1
+	inc	r1		; to CTR1
+	inc	r1
+	mov	a,r3
+	rl	a		; bit 3
+	rl	a		; bit 4
+	mov	r4,a		; clock
+	rl	a		; bit 5
+	mov	r2,a		; up/down
+	rl	a		; bit 6
+	mov	r3,a		; reset
+	lcall	counter
+	
+	pop	05h		; R5
+	pop	04h		; R4
+	pop	03h		; R3
+	pop	02h		; R2
+	pop	01h		; R1
+	pop	00h		; R0
+	pop	psw
+	pop	acc 
+	pop	dps
+
+	reti
+
+;;; interrupt-routine for SOF
+;;; is for full speed
+sof_isr:
+	push	dps
+	push	dpl
+	push	dph
+	push	dpl1
+	push	dph1
+	push	acc
+	push	psw
+	push	00h		; R0
+	push	01h		; R1
+	push	02h		; R2
+	push	03h		; R3
+	push	04h		; R4
+	push	05h		; R5
+	push	06h		; R6
+	push	07h		; R7
+		
+	mov	a,EP2468STAT
+	anl	a,#20H		; full?
+	jnz	epfull		; EP6-buffer is full
+
+	lcall	conv_ad		; conversion
+
+	mov	DPTR,#EP6BCH	; byte count H
+	mov	a,#0		; is zero
+	lcall	syncdelaywr	; wait until we can write again
+	
+	mov	DPTR,#EP6BCL	; byte count L
+	mov	a,#10H		; is 8x word = 16 bytes
+	lcall	syncdelaywr	; wait until we can write again
+	
+epfull:
+	;; do the D/A conversion
+	mov	a,EP2468STAT
+	anl	a,#01H		; empty
+	jnz	epempty		; nothing to get
+
+	mov	dptr,#0F000H	; EP2 fifo buffer
+	lcall	dalo		; conversion
+
+	mov	dptr,#EP2BCL	; "arm" it
+	mov	a,#00h
+	lcall	syncdelaywr	; wait for the rec to sync
+	lcall	syncdelaywr	; wait for the rec to sync
+
+epempty:	
+	;; clear INT2
+	mov	a,EXIF		; FIRST clear the USB (INT2) interrupt request
+	clr	acc.4
+	mov	EXIF,a		; Note: EXIF reg is not 8051 bit-addressable
+	
+	mov	DPTR,#USBIRQ	; points to the SOF
+	mov	a,#2		; clear the SOF
+	movx	@DPTR,a
+
+nosof:	
+	pop	07h
+	pop	06h
+	pop	05h
+	pop	04h		; R4
+	pop	03h		; R3
+	pop	02h		; R2
+	pop	01h		; R1
+	pop	00h		; R0
+	pop	psw
+	pop	acc 
+	pop	dph1 
+	pop	dpl1
+	pop	dph 
+	pop	dpl 
+	pop	dps
+	reti
+
+
+reset_ep8:
+	;; erase all data in ep8
+	mov	dptr,#FIFORESET
+	mov	a,#80H		; NAK
+	lcall	syncdelaywr
+	mov	dptr,#FIFORESET
+	mov	a,#8		; reset EP8
+	lcall	syncdelaywr
+	mov	dptr,#FIFORESET
+	mov	a,#0		; normal operation
+	lcall	syncdelaywr
+	ret
+
+
+reset_ep6:
+	;; throw out old data
+	mov	dptr,#FIFORESET
+	mov	a,#80H		; NAK
+	lcall	syncdelaywr
+	mov	dptr,#FIFORESET
+	mov	a,#6		; reset EP6
+	lcall	syncdelaywr
+	mov	dptr,#FIFORESET
+	mov	a,#0		; normal operation
+	lcall	syncdelaywr
+	ret
+
+;;; interrupt-routine for ep1out
+;;; receives the channel list and other commands
+ep1out_isr:
+	push	dps
+	push	dpl
+	push	dph
+	push	dpl1
+	push	dph1
+	push	acc
+	push	psw
+	push	00h		; R0
+	push	01h		; R1
+	push	02h		; R2
+	push	03h		; R3
+	push	04h		; R4
+	push	05h		; R5
+	push	06h		; R6
+	push	07h		; R7
+		
+	mov	dptr,#0E780h	; FIFO buffer of EP1OUT
+	movx	a, at dptr		; get the first byte
+	mov	r0,#CMD_FLAG	; pointer to the command byte
+	mov 	@r0,a		; store the command byte for ep8
+
+	mov	dptr,#ep1out_jmp; jump table for the different functions
+	rl	a		; multiply by 2: sizeof sjmp
+	jmp	@a+dptr		; jump to the jump table
+	;; jump table, corresponds to the command bytes defined
+	;; in usbdux.c
+ep1out_jmp:
+	sjmp	storechannellist; a=0
+	sjmp	single_da	; a=1
+	sjmp	config_digital_b; a=2
+	sjmp	write_digital_b	; a=3
+	sjmp	storesglchannel	; a=4
+	sjmp	readcounter	; a=5
+	sjmp	writecounter	; a=6
+	sjmp	pwm_on		; a=7
+	sjmp	pwm_off		; a=8
+
+pwm_on:
+	lcall	startPWM
+	sjmp	over_da
+
+pwm_off:
+	lcall	stopPWM
+	sjmp	over_da
+
+	;; read the counter
+readcounter:
+	lcall	reset_ep8	; reset ep8
+	lcall	ep8_ops		; fill the counter data in there
+	sjmp	over_da		; jump to the end
+
+	;; write zeroes to the counters
+writecounter:
+	mov	dptr,#0e781h	; buffer
+	mov	r0,#CTR0	; r0 points to counter 0
+	movx	a, at dptr		; channel number
+	jz	wrctr0		; first channel
+	mov	r1,a		; counter
+wrctrl:
+	inc	r0		; next counter
+	inc	r0		; next counter
+	djnz	r1,wrctrl	; advance to the right counter
+wrctr0:
+	inc	dptr		; get to the value
+	movx	a, at dptr		; get value
+	mov	@r0,a		; save in ctr
+	inc	r0		; next byte
+	inc	dptr
+	movx	a, at dptr		; get value
+	mov	@r0,a		; save in ctr
+	sjmp	over_da		; jump to the end
+
+storesglchannel:
+	mov	r0,#SGLCHANNEL	; the conversion bytes are now stored in 80h
+	mov	dptr,#0e781h	; FIFO buffer of EP1OUT
+	movx	a, at dptr		; 
+	mov	@r0,a
+
+	lcall	reset_ep8	; reset FIFO
+	;; Save new A/D data in EP8. This is the first byte
+	;; the host will read during an INSN. If there are
+	;; more to come they will be handled by the ISR of
+	;; ep8.
+	lcall	ep8_ops		; get A/D data
+		
+	sjmp	over_da
+
+	
+;;; Channellist:
+;;; the first byte is zero:
+;;; we've just received the channel list
+;;; the channel list is stored in the addresses from CHANNELLIST which
+;;; are _only_ reachable by indirect addressing
+storechannellist:
+	mov	r0,#CHANNELLIST	; the conversion bytes are now stored in 80h
+	mov	r2,#9		; counter
+	mov	dptr,#0e781h	; FIFO buffer of EP1OUT
+chanlloop:	
+	movx	a, at dptr		; 
+	mov	@r0,a
+	inc	dptr
+	inc	r0
+	djnz	r2,chanlloop
+
+	lcall	reset_ep6	; reset FIFO
+	
+	;; load new A/D data into EP6
+	;; This must be done. Otherwise the ISR is never called.
+	;; The ISR is only called when data has _left_ the
+	;; ep buffer here it has to be refilled.
+	lcall	ep6_arm		; fill with the first data byte
+	
+	sjmp	over_da
+
+;;; Single DA conversion. The 2 bytes are in the FIFO buffer
+single_da:
+	mov	dptr,#0e781h	; FIFO buffer of EP1OUT
+	lcall	dalo		; conversion
+	sjmp	over_da
+
+;;; configure the port B as input or output (bitwise)
+config_digital_b:
+	mov	dptr,#0e781h	; FIFO buffer of EP1OUT
+	movx	a, at dptr		; get the second byte
+	mov	OEB,a		; set the output enable bits
+	sjmp	over_da
+	
+;;; Write one byte to the external digital port B
+;;; and prepare for digital read
+write_digital_b:
+	mov	dptr,#0e781h	; FIFO buffer of EP1OUT
+	movx	a, at dptr		; get the second byte
+	mov	OEB,a		; output enable
+	inc	dptr		; next byte
+	movx	a, at dptr		; bits
+	mov	IOB,a		; send the byte to the I/O port
+
+	lcall	reset_ep8	; reset FIFO of ep 8
+
+	;; fill ep8 with new data from port B
+	;; When the host requests the data it's already there.
+	;; This must be so. Otherwise the ISR is not called.
+	;; The ISR is only called when a packet has been delivered
+	;; to the host. Thus, we need a packet here in the
+	;; first instance.
+	lcall	ep8_ops		; get digital data
+
+	;; 
+	;; for all commands the same
+over_da:	
+	mov	dptr,#EP1OUTBC
+	mov	a,#00h
+	lcall	syncdelaywr	; arm
+	lcall	syncdelaywr	; arm
+	lcall	syncdelaywr	; arm
+
+	;; clear INT2
+	mov	a,EXIF		; FIRST clear the USB (INT2) interrupt request
+	clr	acc.4
+	mov	EXIF,a		; Note: EXIF reg is not 8051 bit-addressable
+
+	mov	DPTR,#EPIRQ	; 
+	mov	a,#00001000b	; clear the ep1outirq
+	movx	@DPTR,a
+
+	pop	07h
+	pop	06h
+	pop	05h
+	pop	04h		; R4
+	pop	03h		; R3
+	pop	02h		; R2
+	pop	01h		; R1
+	pop	00h		; R0
+	pop	psw
+	pop	acc 
+	pop	dph1 
+	pop	dpl1
+	pop	dph 
+	pop	dpl 
+	pop	dps
+	reti
+
+
+	
+;;; all channels
+dalo:
+	movx	a, at dptr		; number of channels
+	inc	dptr		; pointer to the first channel
+	mov	r0,a		; 4 channels
+nextDA:	
+	movx	a, at dptr		; get the first low byte
+	mov	r3,a		; store in r3 (see below)
+	inc	dptr		; point to the high byte
+	movx	a, at dptr		; get the high byte
+	mov	r4,a		; store in r4 (for writeDA)
+	inc	dptr		; point to the channel number
+	movx	a, at dptr		; get the channel number
+	inc	dptr		; get ready for the next channel
+	lcall	writeDA		; write value to the DAC
+	djnz	r0,nextDA	; next channel
+	ret
+
+
+
+;;; D/A-conversion:
+;;; control-byte in a,
+;;; value in r3(low) and r4(high)
+writeDA:			; mask the control byte
+	anl	a,#11000000b	; only the channel is left
+	orl	a,#00110000b	; internal clock, bipolar mode, +/-5V
+	orl	a,r4		; or the value of R4 to it
+	;; set CS to low
+	clr	IOA.5		; set /CS to zero
+	;; send the first byte to the DA-converter
+	mov 	R2,#8		; bit-counter
+DA1:    jnb     ACC.7,zeroda	; jump if Bit7 = 0?
+	setb	IOA.2		; set the DIN bit
+	sjmp	clkda		; continue with the clock
+zeroda: clr	IOA.2		; clear the DIN bit
+clkda:	setb	IOA.0		; SCLK = 1
+	clr	IOA.0		; SCLK = 0
+        rl      a               ; next Bit
+        djnz    R2,DA1
+
+	
+	;; send the second byte to the DA-converter
+	mov	a,r3		; low byte
+	mov 	R2,#8		; bit-counter
+DA2:    jnb     ACC.7,zeroda2	; jump if Bit7 = 0?
+	setb	IOA.2		; set the DIN bit
+	sjmp	clkda2		; continue with the clock
+zeroda2:clr	IOA.2		; clear the DIN bit
+clkda2:	setb	IOA.0		; SCLK = 1
+	clr	IOA.0		; SCLK = 0
+        rl      a               ; next Bit
+        djnz    R2,DA2
+	;; 
+	setb	IOA.5		; set /CS to one
+	;; 
+noDA:	ret
+	
+
+
+;;; arm ep6
+ep6_arm:
+	lcall	conv_ad
+	
+	mov	DPTR,#EP6BCH	; byte count H
+	mov	a,#0		; is zero
+	lcall	syncdelaywr	; wait until the length has arrived
+	
+	mov	DPTR,#EP6BCL	; byte count L
+	mov	a,#10H		; is one
+	lcall	syncdelaywr	; wait until the length has been proc
+	ret
+	
+
+
+;;; converts one analog/digital channel and stores it in EP8
+;;; also gets the content of the digital ports B and D depending on
+;;; the COMMAND flag
+ep8_ops:
+	mov	dptr,#0fc01h	; ep8 fifo buffer
+	clr	a		; high byte
+	movx	@dptr,a		; set H=0
+	mov	dptr,#0fc00h	; low byte
+	mov	r0,#CMD_FLAG
+	mov	a, at r0
+	movx	@dptr,a		; save command byte
+
+	mov	dptr,#ep8_jmp	; jump table for the different functions
+	rl	a		; multiply by 2: sizeof sjmp
+	jmp	@a+dptr		; jump to the jump table
+	;; jump table, corresponds to the command bytes defined
+	;; in usbdux.c
+ep8_jmp:
+	sjmp	ep8_err		; a=0, err
+	sjmp	ep8_err		; a=1, err
+	sjmp	ep8_err		; a=2, err
+	sjmp	ep8_dio		; a=3, digital read
+	sjmp	ep8_sglchannel	; a=4, analog A/D
+	sjmp	ep8_readctr	; a=5, read counter
+	sjmp	ep8_err		; a=6, write counter
+
+	;; reads all counters
+ep8_readctr:
+	mov	r0,#CTR0	; points to counter0
+	mov	dptr,#0fc02h	; ep8 fifo buffer
+	mov	r1,#8		; transfer 4 16bit counters
+ep8_ctrlp:
+	mov	a, at r0		; get the counter
+	movx	@dptr,a		; save in the fifo buffer
+	inc	r0		; inc pointer to the counters
+	inc	dptr		; inc pointer to the fifo buffer
+	djnz	r1,ep8_ctrlp	; loop until ready
+	
+	sjmp	ep8_send	; send the data
+	
+	;; read one A/D channel
+ep8_sglchannel:		
+	mov	r0,#SGLCHANNEL	; points to the channel
+	mov 	a, at r0		; Ch0
+	
+	lcall 	readAD		; start the conversion
+		
+	mov 	DPTR,#0fc02h	; EP8 FIFO 
+	mov 	a,R3		; get low byte
+	movx 	@DPTR,A		; store in FIFO
+	inc	dptr		; next fifo entry
+	mov 	a,R4		; get high byte
+	movx 	@DPTR,A		; store in FIFO
+
+	sjmp	ep8_send	; send the data
+
+	;; read the digital lines
+ep8_dio:	
+	mov 	DPTR,#0fc02h	; store the contents of port B
+	mov	a,IOB		; in the next
+	movx	@dptr,a		; entry of the buffer
+
+	inc	dptr
+	clr	a		; high byte is zero
+	movx	@dptr,a		; next byte of the EP
+	
+ep8_send:	
+	mov	DPTR,#EP8BCH	; byte count H
+	mov	a,#0		; is zero
+	lcall	syncdelaywr
+	
+	mov	DPTR,#EP8BCL	; byte count L
+	mov	a,#10H		; 16 bytes
+	lcall	syncdelaywr	; send the data over to the host
+
+ep8_err:	
+	ret
+
+
+
+;;; EP8 interrupt: gets one measurement from the AD converter and
+;;; sends it via EP8. The channel # is stored in address 80H.
+;;; It also gets the state of the digital registers B and D.
+ep8_isr:	
+	push	dps
+	push	dpl
+	push	dph
+	push	dpl1
+	push	dph1
+	push	acc
+	push	psw
+	push	00h		; R0
+	push	01h		; R1
+	push	02h		; R2
+	push	03h		; R3
+	push	04h		; R4
+	push	05h		; R5
+	push	06h		; R6
+	push	07h		; R7
+		
+	lcall	ep8_ops
+	
+	;; clear INT2
+	mov	a,EXIF		; FIRST clear the USB (INT2) interrupt request
+	clr	acc.4
+	mov	EXIF,a		; Note: EXIF reg is not 8051 bit-addressable
+
+	mov	DPTR,#EPIRQ	; 
+	mov	a,#10000000b	; clear the ep8irq
+	movx	@DPTR,a
+
+	pop	07h
+	pop	06h
+	pop	05h
+	pop	04h		; R4
+	pop	03h		; R3
+	pop	02h		; R2
+	pop	01h		; R1
+	pop	00h		; R0
+	pop	psw
+	pop	acc 
+	pop	dph1 
+	pop	dpl1
+	pop	dph 
+	pop	dpl 
+	pop	dps
+	reti
+
+
+;; need to delay every time the byte counters
+;; for the EPs have been changed.
+
+syncdelay:
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	ret
+
+syncdelaywr:
+	movx	@dptr,a
+	lcall	syncdelay
+	ret
+
+
+.End
+
+

Added: dists/trunk/firmware-free/linux-free/usbdux/usbduxfast_firmware.asm
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ dists/trunk/firmware-free/linux-free/usbdux/usbduxfast_firmware.asm	Thu Jan 14 23:13:43 2010	(r14942)
@@ -0,0 +1,547 @@
+;   usbduxfast_firmware.asm
+;   Copyright (C) 2004,2009 Bernd Porr, Bernd.Porr at f2s.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.
+;
+;   This program is distributed in the hope that it will be useful,
+;   but WITHOUT ANY WARRANTY; without even the implied warranty of
+;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;   GNU General Public License for more details.
+;
+;   You should have received a copy of the GNU General Public License
+;   along with this program; if not, write to the Free Software
+;   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+;
+;
+; Firmware: usbduxfast_firmware.asm for usbdux.c
+; Description: Firmware for usbduxfast
+; Devices: [ITL] USB-DUX (usbdux.o)
+; Author: Bernd Porr <Bernd.Porr at f2s.com>
+; Updated: 17 Apr 2009
+; Status: stable
+;
+;;;
+;;;
+;;;
+
+	.inc	fx2-include.asm
+
+	.equ	WFLOADED,70H	; waveform is loaded
+
+	.org	0000h		; after reset the processor starts here
+	ljmp	main		; jump to the main loop
+
+	.org	0043h		; the IRQ2-vector
+	ljmp	jmptbl		; irq service-routine
+
+	.org	0100h		; start of the jump table
+
+jmptbl:	ljmp	sudav_isr
+	nop
+	ljmp	sof_isr
+	nop
+	ljmp	sutok_isr
+	nop
+	ljmp	suspend_isr
+	nop
+	ljmp	usbreset_isr
+	nop
+	ljmp	hispeed_isr
+	nop
+	ljmp	ep0ack_isr
+	nop
+	ljmp	spare_isr
+	nop
+	ljmp	ep0in_isr
+	nop
+	ljmp	ep0out_isr
+	nop
+	ljmp	ep1in_isr
+	nop
+	ljmp	ep1out_isr
+	nop
+	ljmp	ep2_isr
+	nop
+	ljmp	ep4_isr
+	nop
+	ljmp	ep6_isr
+	nop
+	ljmp	ep8_isr
+	nop
+	ljmp	ibn_isr
+	nop
+	ljmp	spare_isr
+	nop
+	ljmp	ep0ping_isr
+	nop
+	ljmp	ep1ping_isr
+	nop
+	ljmp	ep2ping_isr
+	nop
+	ljmp	ep4ping_isr
+	nop
+	ljmp	ep6ping_isr
+	nop
+	ljmp	ep8ping_isr
+	nop
+	ljmp	errlimit_isr
+	nop
+	ljmp	spare_isr
+	nop
+	ljmp	spare_isr
+	nop
+	ljmp	spare_isr
+	nop
+	ljmp	ep2isoerr_isr
+	nop
+	ljmp	ep4isoerr_isr
+	nop
+	ljmp	ep6isoerr_isr
+	nop
+	ljmp	ep8isoerr_isr
+
+	
+	;; dummy isr
+sof_isr:
+sudav_isr:	
+sutok_isr:	
+suspend_isr:	
+usbreset_isr:	
+hispeed_isr:	
+ep0ack_isr:	
+spare_isr:	
+ep0in_isr:	
+ep0out_isr:	
+ep1out_isr:
+ep1in_isr:	
+ibn_isr:	
+ep0ping_isr:	
+ep1ping_isr:	
+ep2ping_isr:	
+ep4ping_isr:	
+ep6ping_isr:	
+ep8ping_isr:	
+errlimit_isr:	
+ep2isoerr_isr:	
+ep4isoerr_isr:	
+ep6isoerr_isr:	
+ep8isoerr_isr:
+ep6_isr:
+ep2_isr:
+ep8_isr:
+
+	push	dps
+	push	dpl
+	push	dph
+	push	dpl1
+	push	dph1
+	push	acc
+	push	psw
+
+	;; clear the USB2 irq bit and return
+	mov	a,EXIF
+	clr	acc.4
+	mov	EXIF,a
+
+	pop	psw
+	pop	acc 
+	pop	dph1 
+	pop	dpl1
+	pop	dph 
+	pop	dpl 
+	pop	dps
+	
+	reti
+
+		
+;;; main program
+;;; basically only initialises the processor and
+;;; then engages in an endless loop
+main:
+	mov	dptr,#REVCTL
+	mov	a,#00000011b	; allows skip
+	lcall	syncdelaywr
+
+	mov	DPTR,#CPUCS	; CPU control register
+	mov	a,#00010000b	; 48Mhz
+	lcall	syncdelaywr
+
+	mov	dptr,#IFCONFIG	; switch on IFCLK signal
+	mov	a,#10100010b	; gpif, 30MHz
+	lcall	syncdelaywr
+
+	mov	dptr,#FIFORESET
+	mov	a,#80h
+	lcall	syncdelaywr
+	mov	a,#8
+	lcall	syncdelaywr
+	mov	a,#2		
+	lcall	syncdelaywr
+	mov	a,#4		
+	lcall	syncdelaywr
+	mov	a,#6		
+	lcall	syncdelaywr
+	mov	a,#0		
+	lcall	syncdelaywr
+
+	mov	dptr,#INTSETUP	; IRQ setup register
+	mov	a,#08h		; enable autovector
+	lcall	syncdelaywr
+
+	lcall	initeps		; init the isochronous data-transfer
+
+	lcall	initGPIF
+
+;;; main loop
+
+mloop2:
+	lcall	gpif_run
+	sjmp	mloop2		; do nothing. The rest is done by the IRQs
+
+
+gpif_run:
+	mov	a,WFLOADED
+	jz	no_trig		; do not trigger
+	mov	a,GPIFTRIG	; GPIF status
+	anl	a,#80h		; done bit
+	jz	no_trig		; GPIF busy
+
+;;; gpif has stopped
+	mov	a,#06h		; RD,EP6
+	mov	GPIFTRIG,a
+no_trig:
+	ret
+
+	
+
+initGPIF:
+	mov	DPTR,#EP6CFG	; BLK data from here to the host
+	mov	a,#11100000b	; Valid, quad buffering
+	lcall	syncdelaywr	; write
+
+	mov	dptr,#EP6FIFOCFG
+	mov	a,#00001001b	; autoin, wordwide
+	lcall	syncdelaywr
+
+	mov	dptr,#EP6AUTOINLENH
+	mov	a,#00000010b	; 512 bytes
+	lcall	syncdelaywr	; write
+
+	mov	dptr,#EP6AUTOINLENL
+	mov	a,#00000000b	; 0
+	lcall	syncdelaywr	; write
+
+	mov	dptr,#GPIFWFSELECT
+	mov	a,#11111100b	; waveform 0 for FIFO RD
+	lcall	syncdelaywr
+
+	mov	dptr,#GPIFCTLCFG
+	mov	a,#10000000b	; tri state for CTRL
+	lcall	syncdelaywr
+
+	mov	dptr,#GPIFIDLECTL
+	mov	a,#11111111b	; all CTL outputs high
+	lcall	syncdelaywr
+	mov	a,#11111101b	; reset counter
+	lcall	syncdelaywr
+	mov	a,#11111111b	; reset to high again
+	lcall	syncdelaywr
+
+	mov	a,#00000010b	; abort when full
+	mov	dptr,#EP6GPIFFLGSEL
+	lcall	syncdelaywr
+
+	mov	a,#00000001b	; stop when buffer overfl
+	mov	dptr,#EP6GPIFPDFSTOP
+	lcall	syncdelaywr
+
+	mov	a,#0
+	mov	dptr,#GPIFREADYCFG
+	lcall	syncdelaywr
+
+	mov	a,#0
+	mov	dptr,#GPIFIDLECS
+	lcall	syncdelaywr
+
+; waveform 1
+; this is a dummy waveform which is used
+; during the upload of another waveform into
+; wavefrom 0
+; it branches directly into the IDLE state
+	mov	dptr,#0E420H
+	mov	a,#00111111b	; branch to IDLE
+	lcall	syncdelaywr
+
+	mov	dptr,#0E428H	; opcode
+	mov	a,#00000001b	; deceision point
+	lcall	syncdelaywr
+
+	mov	dptr,#0E430H
+	mov	a,#0FFH		; output is high
+	lcall	syncdelaywr
+
+	mov	dptr,#0E438H
+	mov	a,#0FFH		; logic function
+	lcall	syncdelaywr
+
+; signals that no waveform 0 is loaded so far
+	mov	WFLOADED,#0	; waveform flag
+
+	ret
+
+
+
+;;; initilise the transfer
+;;; It is assumed that the USB interface is in alternate setting 1
+initeps:
+	mov	DPTR,#EP4CFG
+	mov	a,#10100000b	; valid, bulk, out
+	lcall	syncdelaywr
+
+	mov	dptr,#EP4BCL	; "arm" it
+	mov	a,#00h
+	lcall	syncdelaywr	; wait until we can write again
+	lcall	syncdelaywr	; wait
+	lcall	syncdelaywr	; wait
+
+	mov	DPTR,#EP8CFG
+	mov	a,#0		; disable EP8, it overlaps with EP6!!
+	lcall	syncdelaywr
+
+	mov	dptr,#EPIE	; interrupt enable
+	mov	a,#00100000b	; enable irq for ep4
+	lcall	syncdelaywr	; do it
+
+	mov	dptr,#EPIRQ	; clear IRQs
+	mov	a,#00100100b
+	movx	@dptr,a
+
+        mov     DPTR,#USBIE	; USB int enable register
+        mov     a,#0            ; SOF etc
+        movx    @DPTR,a         ;
+
+        mov     DPTR,#GPIFIE	; GPIF int enable register
+        mov     a,#0            ; done IRQ
+        movx    @DPTR,a         ;
+
+	mov	EIE,#00000001b	; enable INT2 in the 8051's SFR
+	mov	IE,#80h		; IE, enable all interrupts
+
+	ret
+
+
+;;; interrupt-routine for ep4
+;;; receives the channel list and other commands
+ep4_isr:
+	push	dps
+	push	dpl
+	push	dph
+	push	dpl1
+	push	dph1
+	push	acc
+	push	psw
+	push	00h		; R0
+	push	01h		; R1
+	push	02h		; R2
+	push	03h		; R3
+	push	04h		; R4
+	push	05h		; R5
+	push	06h		; R6
+	push	07h		; R7
+		
+	mov	dptr,#0f400h	; FIFO buffer of EP4
+	movx	a, at dptr		; get the first byte
+
+	mov	dptr,#ep4_jmp	; jump table for the different functions
+	rl	a		; multiply by 2: sizeof sjmp
+	jmp	@a+dptr		; jump to the jump table
+
+ep4_jmp:
+	sjmp	storewaveform	; a=0
+	sjmp	init_ep6	; a=1
+	
+init_ep6:
+	; stop ep6
+	; just now do nothing
+
+	ljmp	over_wf
+
+
+storewaveform:
+	mov	WFLOADED,#0	; waveform flag
+
+	mov	dptr,#EP6FIFOCFG
+	mov	a,#00000000b	;
+	lcall	syncdelaywr
+
+	mov	dptr,#GPIFABORT
+	mov	a,#0ffh		; abort all transfers
+	lcall	syncdelaywr
+
+wait_f_abort:
+	mov	a,GPIFTRIG	; GPIF status
+	anl	a,#80h		; done bit
+	jz	wait_f_abort	; GPIF busy
+
+	mov	dptr,#GPIFWFSELECT
+	mov	a,#11111101b	; select dummy waveform
+	movx	@dptr,a
+	lcall	syncdelay
+
+	mov	dptr,#FIFORESET
+	mov	a,#80h		; NAK
+	lcall	syncdelaywr
+	mov	a,#6		; reset EP6
+	lcall	syncdelaywr
+	mov	a,#0		; normal op
+	lcall	syncdelaywr
+
+; change to dummy waveform 1
+	mov	a,#06h		; RD,EP6
+	mov	GPIFTRIG,a
+
+; wait a bit
+	mov	r2,255
+loopx:
+	djnz	r2,loopx
+
+; abort waveform if not already so
+	mov	dptr,#GPIFABORT
+	mov	a,#0ffh		; abort all transfers
+	lcall	syncdelaywr
+
+; wait again
+	mov	r2,255
+loopx2:
+	djnz	r2,loopx2
+
+; check for DONE
+wait_f_abort2:
+	mov	a,GPIFTRIG	; GPIF status
+	anl	a,#80h		; done bit
+	jz	wait_f_abort2	; GPIF busy
+
+; upload the new waveform into waveform 0
+	mov	AUTOPTRH2,#0E4H	; XDATA0H
+	lcall	syncdelay
+	mov	AUTOPTRL2,#00H	; XDATA0L
+	lcall	syncdelay
+
+	mov	AUTOPTRH1,#0F4H	; EP4 high
+	lcall	syncdelay
+	mov	AUTOPTRL1,#01H	; EP4 low
+	lcall	syncdelay
+
+	mov	AUTOPTRSETUP,#7	; autoinc and enable
+	lcall	syncdelay
+
+	mov 	r2,#20H		; 32 bytes to transfer
+
+wavetr:
+	mov 	dptr,#XAUTODAT1
+	movx	a, at dptr
+	lcall	syncdelay
+	mov	dptr,#XAUTODAT2
+	movx	@dptr,a
+	lcall	syncdelay
+	djnz	r2,wavetr
+
+	mov	dptr,#EP6FIFOCFG
+	mov	a,#00001001b	; autoin, wordwide
+	lcall	syncdelaywr
+
+	mov	dptr,#GPIFWFSELECT
+	mov	a,#11111100b
+	movx	@dptr,a
+	lcall	syncdelay
+
+	mov	dptr,#FIFORESET
+	mov	a,#80h		; NAK
+	lcall	syncdelaywr
+	mov	a,#6		; reset EP6
+	lcall	syncdelaywr
+	mov	a,#0		; normal op
+	lcall	syncdelaywr
+
+	mov	dptr,#0E400H+10H; waveform 0: first CTL byte
+	movx	a, at dptr		; get it
+	orl	a,#11111011b	; force all bits to one except the range bit
+	mov	dptr,#GPIFIDLECTL
+	lcall	syncdelaywr
+
+	mov	WFLOADED,#1	; waveform flag
+
+; do the common things here	
+over_wf:	
+	mov	dptr,#EP4BCL
+	mov	a,#00h
+	movx	@DPTR,a		; arm it
+	lcall	syncdelay	; wait
+	movx	@DPTR,a		; arm it
+	lcall	syncdelay	; wait
+
+	;; clear INT2
+	mov	a,EXIF		; FIRST clear the USB (INT2) interrupt request
+	clr	acc.4
+	mov	EXIF,a		; Note: EXIF reg is not 8051 bit-addressable
+
+	mov	DPTR,#EPIRQ	; 
+	mov	a,#00100000b	; clear the ep4irq
+	movx	@DPTR,a
+
+	pop	07h
+	pop	06h
+	pop	05h
+	pop	04h		; R4
+	pop	03h		; R3
+	pop	02h		; R2
+	pop	01h		; R1
+	pop	00h		; R0
+	pop	psw
+	pop	acc 
+	pop	dph1 
+	pop	dpl1
+	pop	dph 
+	pop	dpl 
+	pop	dps
+	reti
+
+
+;; need to delay every time the byte counters
+;; for the EPs have been changed.
+
+syncdelay:
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	ret
+
+
+syncdelaywr:
+	lcall	syncdelay
+	movx	@dptr,a
+	ret
+
+
+.End
+
+
+
+
+
+
+
+
+
+
+
+

Added: dists/trunk/firmware-free/linux-free/usbdux_firmware.bin
==============================================================================
Binary file. No diff available.

Added: dists/trunk/firmware-free/linux-free/usbduxfast_firmware.bin
==============================================================================
Binary file. No diff available.



More information about the Kernel-svn-changes mailing list