[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