Mercurial > ecos
changeset 2493:3adca3f92ff7
* Generic USB Serial package created.
Some files were rearranged during the import and the Documentation
written Andrew Lunn.
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/io/usb/serial/slave/current/ChangeLog @@ -0,0 +1,37 @@ +2008-07-12 Frank Pagliughi <fpagliughi@mindspring.com> + + * Generic USB Serial package created. + Some files were rearranged during the import and the Documentation + written Andrew Lunn. + +//=========================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 2008 FSF +// +// eCos 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 or (at your option) any later version. +// +// eCos 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 eCos; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or inline functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. However the source code for this file must still be made available +// in accordance with section (3) of the GNU General Public License. +// +// This exception does not invalidate any other reasons why a work based on +// this file might be covered by the GNU General Public License. +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//===========================================================================
new file mode 100644 --- /dev/null +++ b/packages/io/usb/serial/slave/current/cdl/usbs_serial.cdl @@ -0,0 +1,260 @@ +# ==================================================================== +# +# usbs_serial.cdl +# +# USB slave-side serial package. +# +# ==================================================================== +#####ECOSGPLCOPYRIGHTBEGIN#### +## ------------------------------------------- +## This file is part of eCos, the Embedded Configurable Operating System. +## +## eCos 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 or (at your option) any later version. +## +## eCos 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 eCos; if not, write to the Free Software Foundation, Inc., +## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +## +## As a special exception, if other files instantiate templates or use macros +## or inline functions from this file, or you compile this file and link it +## with other works to produce a work based on this file, this file does not +## by itself cause the resulting work to be covered by the GNU General Public +## License. However the source code for this file must still be made available +## in accordance with section (3) of the GNU General Public License. +## +## This exception does not invalidate any other reasons why a work based on +## this file might be covered by the GNU General Public License. +## +## ------------------------------------------- +#####ECOSGPLCOPYRIGHTEND#### +# ==================================================================== +######DESCRIPTIONBEGIN#### +# +# Author(s): Frank M. Pagliughi (fmp), SoRo Systems, Inc. +# Contributors: +# Date: 2008-06-04 +# +#####DESCRIPTIONEND#### +# ==================================================================== + +cdl_package CYGPKG_IO_USB_SLAVE_SERIAL { + display "USB slave serial support" + include_dir "cyg/io/usb" + parent CYGPKG_IO_USB_SLAVE + requires { CYGHWR_IO_USB_SLAVE_OUT_ENDPOINTS >= 1 } + requires { CYGHWR_IO_USB_SLAVE_IN_ENDPOINTS >= 1 } + compile usbs_serial.c + implements CYGINT_IO_USB_SLAVE_CLIENTS +# doc ref/io-usb-slave-eth.html + + description " + The USB slave serial package supports the development of USB + peripherals which mimic a serial connection to the host + machine. Such a device creates a relatively simple upgrade to + USB from a legacy serial connection, especially from the + perspective of the host software and device drivers." + + cdl_option CYGDAT_IO_USB_SLAVE_CLASS_TYPE { + display "Serial USB Class" + flavor data + default_value { "ACM" } + legal_values { "ACM" "generic" } + description " + The USB serial module can enumerate as either a generic + (vendor-specific) usb device or a communications class ACM + device. The generic device requires a pair of Bulk + endpoints, while the ACM device also requires an Interrupt + IN endpoint. For a Windows host, the ACM configuration is + required to use the standard 'usbser.sys' device driver, + but for a Linux host, the generic configuration works, and + saves the additional endpoint." + } + cdl_option CYGDAT_IO_USB_SLAVE_SERIAL_EP0 { + display "Name of EP0 structure" + flavor data + default_value { "usbs_at91_ep0" } + description " + The name of the variable that contains the endpoint 0 + structure. This should be set to the EP0 structure for + the desired USB device driver such as usbs_at91_ep0, + usbs_sa11x0_ep0, etc" + } + cdl_option CYGNUM_IO_USB_SLAVE_SERIAL_EP0_MAX_PACKET_SIZE { + display "The size of EP0" + flavor data + default_value 8 + legal_values { 8 16 64 } + description " + The size of the EP0 hardware buffer on the specific USB + chip used." + } + cdl_option CYGNUM_IO_USB_SLAVE_SERIAL_TX_EP_NUM { + display "Tx (USB IN) endpoint number" + flavor data + default_value 1 + description " + The endpoint that should be used for the device-side + transmitter, which is the USB IN direction." + } + cdl_option CYGDAT_IO_USB_SLAVE_SERIAL_TX_EP { + display "The Tx (USB IN) endpoint structure" + flavor data + default_value { "usbs_at91_ep1" } + description " + The endpoint structure that corresponds to the selected + Tx endpoint number. This is dependent on the USBS device + driver selected, and could be usbs_at91_ep1, + usbs_sa11x0_ep1, etc" + + } + cdl_option CYGNUM_IO_USB_SLAVE_SERIAL_RX_EP_NUM { + display "Rx (USB OUT) endpoint number" + flavor data + default_value 2 + description " + The endpoint that should be used for the device-side + receiver, which is the USB OUT direction." + } + cdl_option CYGDAT_IO_USB_SLAVE_SERIAL_RX_EP { + display "The Rx (USB OUT) endpoint structure" + flavor data + default_value { "usbs_at91_ep2" } + description " + The endpoint structure that corresponds to the selected + Rx endpoint number. This is dependent on the USBS device + driver selected, and could be usbs_at91_ep2, + usbs_sa11x0_ep2, etc" + } + cdl_option CYGNUM_IO_USB_SLAVE_SERIAL_INTR_EP_NUM { + display "Interrupt IN endpoint number" + flavor data + default_value 3 + active_if { CYGDAT_IO_USB_SLAVE_CLASS_TYPE == "ACM" } + description " + The endpoint that should be used for the ACM Interrupt IN" + } + cdl_option CYGDAT_IO_USB_SLAVE_SERIAL_INTR_EP { + display "Interrupt IN endpoint structure" + flavor data + default_value { "usbs_at91_ep3" } + active_if { CYGDAT_IO_USB_SLAVE_CLASS_TYPE == "ACM" } + description " + The endpoint structure that corresponds to the selected ACM + Interrupt IN endpoint." + } + cdl_option CYGNUM_IO_USB_SLAVE_SERIAL_VENDOR_ID { + display "USB Forum Vendor ID" + flavor data + default_value 0xFFFF + legal_values 1 to 0xFFFF + description " + Each USB vendor has an Vendor ID allocated to it by the + USB-IF organization. Any arbitrary value can be selected + for testing provided that it doesn't conflict with devices + on the development host, but a device should NEVER be + released publicly without a valid Vendor ID" + + } + cdl_option CYGNUM_IO_USB_SLAVE_SERIAL_PRODUCT_ID { + display "USB product ID" + flavor data + default_value 1 + legal_values 1 to 0xFFFF + description " + You are free to select an arbitrary 16-bit Product ID for + a device. The combination of Vendor ID and Product ID + uniquely identified a USB device." + } + cdl_option CYGDAT_IO_USB_SLAVE_SERIAL_MFG_STR { + display "The Device Vendor's Name (Manufacturer String)" + flavor data + default_value { "\"eCos\"" } + description " + The standard USB enumeration allows for a + manufacturer's name which is normally reported to the + user when the device is first plugged into the host." + } + cdl_option CYGDAT_IO_USB_SLAVE_SERIAL_PRODUCT_STR { + display "The Device Product Name" + flavor data + default_value { "\"eCos USB Serial Device\"" } + description " + The standard USB enumeration allows for a product name + which is normally reported to the user when the device + is first plugged into the host." + } + + cdl_option CYGBLD_IO_USB_SLAVE_SERIAL_DEBUG { + display "Enable debug output from the driver" + default_value 0 + flavor bool + description " + The driver may produce debug output which can be + useful to work out why it is not working as expected." + } + + cdl_component CYGPKG_IO_USB_SLAVE_SERIAL_OPTIONS { + display "Build options" + flavor none + + description " + Package-specific build options including control over compiler + flags used only in building this package." + + cdl_option CYGPKG_IO_USB_SLAVE_SERIAL_CFLAGS_ADD { + display "Additional compiler flags" + flavor data + no_define + default_value { "" } + description " + This option modifies the set of compiler flags for + building this package. These flags are used in addition + to the set of global flags." + } + + cdl_option CYGPKG_IO_USB_SLAVE_SERIAL_CFLAGS_REMOVE { + display "Suppressed compiler flags" + flavor data + no_define + default_value { "" } + description " + This option modifies the set of compiler flags for + building this package. These flags are removed from + the set of global flags if present." + } + + + cdl_component CYGBLD_IO_USB_SLAVE_SERIAL_EXAMPLES { + display "Build example programs" + no_define + requires { CYGPKG_IO_FILEIO } + requires { CYGPKG_IO_SERIAL_DEVICES } + description " + Enabling this option will cause the example programs + to be built using the normal test case infrastructure. + They are however not test cases and should not be used + with any automatic test farm running all the + tests. Hence this option is disabled by default." + + cdl_option CYGPKG_IO_USB_SLAVE_SERIAL_TESTS { + display "USBS serial example/test programs" + no_define + flavor data + calculated { "tests/usbserial_echo.c tests/usb2serial.c" } + description " + usbserial_echo will echo charactors received + over the usb serial port back to the sender. + usb2serial acts as a bridge between a USB serial + slave and a real serial port. It is hard coded to use + /dev/ser0." + } + } + } +} \ No newline at end of file
new file mode 100644 --- /dev/null +++ b/packages/io/usb/serial/slave/current/doc/usbs_serial.sgml @@ -0,0 +1,391 @@ +<!-- DOCTYPE reference PUBLIC "-//OASIS//DTD DocBook V3.1//EN" --> + +<!-- {{{ Banner --> + +<!-- =============================================================== --> +<!-- --> +<!-- usbs_serial.sgml --> +<!-- --> +<!-- USB slave-side serial port package. --> +<!-- --> +<!-- =============================================================== --> +<!-- ####COPYRIGHTBEGIN#### --> +<!-- --> +<!-- =============================================================== --> +<!-- Copyright (C) 2008 FSF --> +<!-- This material may be distributed only subject to the terms --> +<!-- and conditions set forth in the Open Publication License, v1.0 --> +<!-- or later (the latest version is presently available at --> +<!-- http://www.opencontent.org/openpub/) --> +<!-- Distribution of the work or derivative of the work in any --> +<!-- standard (paper) book form is prohibited unless prior --> +<!-- permission obtained from the copyright holder --> +<!-- =============================================================== --> +<!-- --> +<!-- ####COPYRIGHTEND#### --> +<!-- =============================================================== --> +<!-- #####DESCRIPTIONBEGIN#### --> +<!-- --> +<!-- Author(s): Andrew Lunn, Frank Pagliughi --> +<!-- Contact(s): asl --> +<!-- Date: 2008/06/18 --> +<!-- Version: 0.01 --> +<!-- --> +<!-- ####DESCRIPTIONEND#### --> +<!-- =============================================================== --> + +<!-- }}} --> + +<part id="io-usb-slave-serial"> + <!-- reference id="io-usb-slave-serial" --> + <title>eCos Support for USB Serial like Peripherals</title> + + <!-- {{{ Intro --> + + <refentry id="usbs-serial-intro"> + <refmeta> + <refentrytitle>Introduction</refentrytitle> + </refmeta> + <refnamediv> + <refname>Introduction</refname> + <refpurpose> + eCos support for USB Serial like Peripherals + </refpurpose> + </refnamediv> + + <refsect1><title>Introduction</title> + <para> + The eCos USB-Serial package provides additional support for + USB peripherals that look like a serial port to the + host. These can follow the ACM communication device + specification or simpler devices which just have two bulk + endpoints. Microsoft Windows requires ACM mode. Linux should + operate with both modes, however ACM may cause problems since + the eCos driver does not implement all the class descriptors, + so generic mode is recommended. + </para> + <para> + The USB-Serial package is not tied to any specific + hardware. It requires the presence of USB hardware on the + target and a suitable device driver to make endpoints + available for this code to use. The configuration system + cannot load the eCos package automatically for specific + targets, in the way that a USB device driver or an ethernet + driver can be loaded automatically. Instead, the package has + to be added explicitly. When using the command line tools this + will involve an operation like the following: + </para> + <screen width=72 format=linespecific> + $ ecosconfig add usbs_serial + </screen> + <para> + Typically, this will automatically cause the USB device driver + to become active. + </para> + </refsect1> + </refentry> + + <!-- }}} --> + <!-- {{{ Config --> + + <refentry id="usbs-serial-config"> + <refmeta> + <refentrytitle>Configuration</refentrytitle> + </refmeta> + <refnamediv> + <refname>Configuration</refname> + <refpurpose>Configuration USB Serial like Peripherals</refpurpose> + </refnamediv> + + <refsect1><title>Configuration</title> + <para> + The package requires a few basic configurations plus + optionally some additional configuration options. + </para> + <para> + The driver needs two or three endpoints, depending if ACM + communications or a more generic model is used. This is + configured + with <literal>CYGDAT_IO_USB_SLAVE_CLASS_TYPE</literal> which + can take the value <literal>ACM</literal> + or <literal>generic</literal>. + </para> + <para> + The <literal>CYGDAT_IO_USB_SLAVE_SERIAL_EP0</literal> must be + configured with the control end point of the USB + device. <literal>CYGDAT_IO_USB_SLAVE_SERIAL_TX_EP</literal> + must be configured with the endpoint to be used for + transmission and + <literal>CYGDAT_IO_USB_SLAVE_SERIAL_RX_EP</literal> must be + configured with the end point used for reception. Associated + with these + are <literal>CYGNUM_IO_USB_SLAVE_SERIAL_RX_EP_NUM</literal> + and <literal>CYGNUM_IO_USB_SLAVE_SERIAL_TX_EP_NUM</literal> + which are the endpoint numbers and are used during enumeration + of the device. The TX and RX endpoints must operate in BULK + mode. + </para> + <para> + If operation mode ACM is selected a third endpoint is + needed. This must operate in interrupt mode and should be + configured + in <literal>CYGNUM_IO_USB_SLAVE_SERIAL_INTR_EP</literal> + and <literal> + CYGNUM_IO_USB_SLAVE_SERIAL_INTR_EP_NUM</literal>. + </para> + <para> + The USB serial device will make its vendor:product ID known to + the host. This should be configured + with <literal>CYGNUM_IO_USB_SLAVE_SERIAL_VENDOR_ID</literal> + and <literal>CYGNUM_IO_USB_SLAVE_SERIAL_PRODUCT_ID</literal>. NOTE: + The default configurations are not valid for products, but + should work for testing. + </para> + <para> + The USB enumeration also contains text strings to describe the + device. This text string can be set + with <literal>CYGDAT_IO_USB_SLAVE_SERIAL_PRODUCT_STR</literal>. + </para> + <para> + The last configuration option of interest + is <literal>CYGPKG_IO_USB_SLAVE_SERIAL_EXAMPLES</literal>. When + true example programs will be built when the eCos tests are + built. These are not pass/fail test like other eCos tests, but + examples of how the eCos USB serial class can be used. + </para> + </refsect1> + </refentry> + + <!-- }}} --> + <!-- {{{ Host Config --> + + <refentry id="usbs-serial-host-config"> + <refmeta> + <refentrytitle>Host Configuration</refentrytitle> + </refmeta> + <refnamediv> + <refname>Host Configuration</refname> + <refpurpose>Host Configuration for USB Serial like Peripherals + </refpurpose> + </refnamediv> + + <refsect1> + <title>Host Configuration</title> + <para> + Configuration for two hosts are listed here, Microsoft Windows + and Linux. It should also be possible to use the eCos USB + serial like peripheral driver with other hosts. + </para> + <refsect2><title>Linux</title> + <para> + The eCos USB serial like peripheral driver can be used in + Linux in one of two ways. + <itemizedlist> + <listitem> + <para> + Using the generic usbserial kernel module passing the + vendor and product ID as module parameters. e.g. + </para> + <programlisting width=72> + modprobe usbserial vendor=0xabcd product=0x1234 + </programlisting> + <para> + would load the kernel module so that it would use a + USB device abcd:1234 as a serial device. + </para> + </listitem> + <listitem> + <para> + Using the mini driver provided with eCos in the + <filename class=directory>host/linux</filename> + directory. This driver must be edited and the correct + vendor and product ID set to match the vendor and + product ID used by the device. Once compiled this + driver can be loaded with: + </para> + <programlisting width=72> + modprobe usbserial + modprobe ecos_usbserial + </programlisting> + <para> + This driver is known to compile with kernel versions + 2.6.18 and probably works fine with other + kernels. However it fails to compile with kernels + after 2.6.25. + </para> + </listitem> + </itemizedlist> + Both of these methods will result in the Linux Kernel making + a new serial device available. This is typically + named <filename>/dev/ttyUSB0</filename>. + </para> + </refsect2> + <refsect2><title>Microsoft Windows</title> + <para> + To install the device in a Microsoft Windows system make use + of the INF file + in <filename>host/windows/eCosUsbSerial.inf</filename>. Copy + this INF file and <filename>usbser.sys</filename> from your + version of Windows into an empty directory. Then plug in the + USB device. When prompted to load a driver navigate to the + INF file and select it. + </para> + </refsect2> + </refsect1> + + </refentry> + + <!-- }}} --> + <!-- {{{ Using --> + <refentry id="usbs-serial-using"> + <refmeta> + <refentrytitle>API Function</refentrytitle> + </refmeta> + <refnamediv> + <refname>usbs_serial_start</refname> + <refname>usbs_serial_init</refname> + <refname>usbs_serial_start</refname> + <refname>usbs_serial_wait_until_configured</refname> + <refname>usbs_serial_is_configured</refname> + <refname>usbs_serial_start_tx</refname> + <refname>usbs_serial_wait_for_tx</refname> + <refname>usbs_serial_tx</refname> + <refname>usbs_serial_start_rx</refname> + <refname>usbs_serial_wait_for_rx</refname> + <refname>usbs_serial_rx</refname> + <refname>usbs_serial_state_change_handler</refname> + <refpurpose> + eCos USB Serial like Peripherals API + </refpurpose> + </refnamediv> + + <refsynopsisdiv> + <funcsynopsis> + <funcsynopsisinfo> +#include <cyg/io/usb/usbs_serial.h> + </funcsynopsisinfo> + <funcprototype> + <funcdef>void + <function>usbs_serial_start</function> + </funcdef> + <paramdef>void</paramdef> + </funcprototype> + <funcprototype> + <funcdef>void + <function>usbs_serial_init</function> + </funcdef> + <paramdef>usbs_serial * <parameter>ser</parameter></paramdef> + <paramdef>usbs_tx_endpoint * <parameter>tx_ep</parameter></paramdef> + <paramdef>usbs_rx_endpoint * <parameter>rx_ep</parameter></paramdef> + </funcprototype> + <funcprototype> + <funcdef>void + <function>usbs_serial_wait_until_configured</function> + </funcdef> + <paramdef>void></paramdef> + </funcprototype> + <funcprototype> + <funcdef>cyg_bool + <function>usbs_serial_is_configured</function> + </funcdef> + <paramdef>void</paramdef> + </funcprototype> + <funcprototype> + <funcdef>void + <function>usbs_serial_start_tx</function> + </funcdef> + <paramdef>usbs_serial * <parameter>ser</parameter></paramdef> + <paramdef>const void *<parameter>buf</parameter></paramdef> + <paramdef>int * <parameter>n</parameter></paramdef> + </funcprototype> + <funcprototype> + <funcdef>int + <function>usbs_serial_wait_for_tx</function> + </funcdef> + <paramdef>usbs_serial * <parameter>ser</parameter></paramdef> + </funcprototype> + <funcprototype> + <funcdef>void + <function>usbs_serial_start_rx</function> + </funcdef> + <paramdef>usbs_serial * <parameter>ser</parameter></paramdef> + <paramdef>const void *<parameter>buf</parameter></paramdef> + <paramdef>int * <parameter>n</parameter></paramdef> + </funcprototype> + <funcprototype> + <funcdef>int + <function>usbs_serial_wait_for_rx</function> + </funcdef> + <paramdef>usbs_serial * <parameter>ser</parameter></paramdef> + </funcprototype> + <funcprototype> + <funcdef>int + <function>usbs_serial_rx</function> + </funcdef> + <paramdef>usbs_serial * <parameter>ser</parameter></paramdef> + <paramdef>const void *<parameter>buf</parameter></paramdef> + <paramdef>int * <parameter>n</parameter></paramdef> + </funcprototype> + <funcprototype> + <funcdef>void + <function>usbs_serial_state_change_handler</function> + </funcdef> + <paramdef>usbs_control_endpoint * <parameter>ep</parameter></paramdef> + <paramdef>void * <parameter>data</parameter></paramdef> + <paramdef>usbs_state_change <parameter>change</parameter></paramdef> + <paramdef>int <parameter>prev_state</parameter></paramdef> + </funcprototype> + </funcsynopsis> + </refsynopsisdiv> + + <refsect1 id="usbs-serial-api-description"> + <title>Description</title> + <para> + For examples of how to use this API see the + files <filename>.../tests/usbserial_echo.c</filename> + and <filename>.../tests/usb2serial.c</filename> + </para> + + <para> + The first function that needs calling + is <function>usbs_serial_start()</function>. This will initialise + the eCos USB slave layer, creating all the enumeration data and + then let the host know that the device exists. + </para> + <para> + Once the USB subsystem has been started it is necessary to wait + for the host to configure the device using the + function <function>usbs_serial_wait_until_configured()</function>. The + host will assign the device an ID and then load the appropriate + device driver in the host in order to make use the device. + </para> + <para> + Once the device is configured it is then possible to make use of + it, i.e. send and receive data. This transfer of data can be + accomplished either asynchronously or synchronously. It is also + possible to mix asynchronously and synchronously between + receiving and sending data. + </para> + <para> + To perform asynchronous operations the + functions <function>usbs_serial_start_rx()</function> + and <function>usbs_serial_start_tx()</function> is used to + start the operation. These functions start the necessary + actions and then return immediately. At a later time the + functions <function>usbs_serial_wait_for_tx()</function> + or <function>usbs_serial_wait_for_rx()</function> should be + called. These will, if necessary, block and then return the + status and any data for the previously started asynchronous + call. + </para> + <para> + To perform synchronous operations the + functions <function>usbs_serial_rx()</function> + and <function>usbs_serial_tx()</function> are used. These + functions will block until the requested action is complete. + </para> + </refsect1> + </refentry> + <!-- }}} --> +</part> +<!-- /reference -->
new file mode 100644 --- /dev/null +++ b/packages/io/usb/serial/slave/current/host/linux/.cvsignore @@ -0,0 +1,3 @@ +.ecos_usbserial.o.d +.tmp_versions +*.ko \ No newline at end of file
new file mode 100644 --- /dev/null +++ b/packages/io/usb/serial/slave/current/host/linux/Makefile @@ -0,0 +1,11 @@ +# Makefile for ecos_usbserial Linux kernel module + +ifneq ($(KERNELRELEASE),) + obj-m := ecos_usbserial.o +else + KDIR ?= /lib/modules/$(shell uname -r)/build + PWD := $(shell pwd) +default: + $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules +endif +
new file mode 100644 --- /dev/null +++ b/packages/io/usb/serial/slave/current/host/linux/ecos_usbserial.c @@ -0,0 +1,111 @@ +//========================================================================== +// +// ecos_usbserial.c +// +// Kernel driver for the eCos USB serial driver +// +//========================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// +// eCos 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 or (at your option) any later version. +// +// eCos 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 eCos; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or inline functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. However the source code for this file must still be made available +// in accordance with section (3) of the GNU General Public License. +// +// This exception does not invalidate any other reasons why a work based on +// this file might be covered by the GNU General Public License. +// +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//=========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Frank M. Pagliughi (fmp), SoRo Systems, Inc. +// Contributors: +// Date: 2008-06-02 +// Description: Kernel driver for the eCos USB serial driver +// +//####DESCRIPTIONEND#### +//=========================================================================== + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/tty.h> +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> + +#define VENDOR_ID 0xFFFF +#define PRODUCT_ID 1 + +static struct usb_device_id id_table[] = { + { USB_DEVICE(VENDOR_ID, PRODUCT_ID) }, + { } +}; + +MODULE_DEVICE_TABLE(usb, id_table); + +static struct usb_driver ecos_usbserial_driver = { + .name = "ecos_usbserial", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table +}; + +static struct usb_serial_driver ecos_usbserial_device = { + .driver = { + .owner = THIS_MODULE, + .name = "ecos_usbserial", + }, + .id_table = id_table, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = NUM_DONT_CARE, + .num_bulk_out = NUM_DONT_CARE, + .num_ports = 1 +}; + +static int __init ecos_usbserial_init(void) +{ + int retval; + + retval = usb_serial_register(&ecos_usbserial_device); + if (retval) + return retval; + + retval = usb_register(&ecos_usbserial_driver); + if (retval) { + usb_serial_deregister(&ecos_usbserial_device); + return retval; + } + + return 0; +} + +static void __exit ecos_usbserial_exit(void) +{ + usb_deregister(&ecos_usbserial_driver); + usb_serial_deregister(&ecos_usbserial_device); +} + +module_init(ecos_usbserial_init); +module_exit(ecos_usbserial_exit); + +MODULE_LICENSE("GPL"); +
new file mode 100644 --- /dev/null +++ b/packages/io/usb/serial/slave/current/host/windows/eCosUsbSerial.inf @@ -0,0 +1,49 @@ +; eCos USB Serial INF file for Windows +; This can be used for any USB device that emulates a serial port connection. +; Simply set the VID & PID numbers in this file to the proper values for the +; device, copy this file and the 'usbser.sys' file from your version of Windows +; into the same directory, and load these when prompted by the Windows device +; manager. + +[Version] +Signature="$Windows NT$" +Class=Ports +ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318} +Provider=eCosUsbSerial +DriverVer=06/02/2008,0.0.0.1 + +[DestinationDirs] +DefaultDestDir=12 ; %windir$\System32\drivers + +[Manufacturer] +eCosUsbSerial=eCosDevices + +[eCosDevices] +"eCosUsbSerial"=InstalleCosUsbSerial,USB\VID_FFFF&PID_0001 + +[InstalleCosUsbSerial] +CopyFiles=CopyeCosUsbFiles +AddReg=eCosUsbReg + +[CopyeCosUsbFiles] +usbser.sys ; The standard Windows USB serial driver + +[eCosUsbReg] +HKR,,DevLoader,,*ntkern +HKR,,NTMPDriver,,usbser.sys +HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider" + +[InstalleCosUsbSerial.Services] +AddService = usbser,2,eCosUsbSerialService + +[eCosUsbSerialService] +DisplayName = ECOS_USB_SERIAL_NAME +ServiceType = 1 ; driver +StartType = 3 ; on-demand or manual +ErrorControl = 1 ; report errors +ServiceBinary = %12%\usbser.sys ; Driver path: %windir%\System32\drivers +LoadOrderGroup = Base + +[Strings] +ECOS_USB_SERIAL_NAME = "eCos USB Serial Driver" +
new file mode 100644 --- /dev/null +++ b/packages/io/usb/serial/slave/current/include/usbs_serial.h @@ -0,0 +1,184 @@ +#ifndef CYGONCE_USBS_SERIAL_H +#define CYGONCE_USBS_SERIAL_H +//========================================================================== +// +// include/usbs_serial.h +// +// Description of the USB slave-side serial device support +// +//========================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// +// eCos 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 or (at your option) any later version. +// +// eCos 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 eCos; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or inline functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. However the source code for this file must still be made available +// in accordance with section (3) of the GNU General Public License. +// +// This exception does not invalidate any other reasons why a work based on +// this file might be covered by the GNU General Public License. +// +// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. +// at http://sources.redhat.com/ecos/ecos-license/ +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Frank M. Pagliughi (fmp), SoRo Systems, Inc. +// Contributors: +// Date: 2008-06-02 +// Purpose: +// Description: USB slave-side serial support +// +// +//####DESCRIPTIONEND#### +//========================================================================== + +#ifdef __cplusplus +extern "C" { +#endif + +// +// The primary purpose of the USB slave-side serial code is to provide a +// simple USB connection to the host, especially for embedded systems that +// are upgrading from RS-232 serial connections. The host would see the +// device as if through a serial port, and thus the host software would +// remain unchanged. It would also eliminate the need for a new device +// driver on the host. +// +// On this side (the eCos USB slave side), the application sees the host +// through a normal USB slave connection with two Bulk endpoints - one in +// the IN direction and one in the OUT direction. This module provides the +// necessary USB descriptors to enumerate the device for a single serial +// port, but then the application is free to communicate with the host +// using any desired API: +// - The standard eCos USB slave API +// - The low-level File I/O layer (if USB devtab entries configured) +// - The C stdio functions (again, if USB devtab entries configured) +// - The USB serial API defined here. +// +// The USB serial API is a thin layer over the standard eCos USB functions +// to provide common synchronous and asynchronous transfers over the assigned +// Bulk endpoints. +// + +#include <cyg/infra/cyg_type.h> +#include <cyg/io/usb/usbs.h> + +// ---------------------------------------------------------------------------- +// The ACM class requests +// + +#define USBS_SERIAL_SEND_ENCAPSULATED_COMMAND 0x00 +#define USBS_SERIAL_GET_ENCAPSULATED_RESPONSE 0x01 +#define USBS_SERIAL_SET_COMM_FEATURE 0x02 +#define USBS_SERIAL_GET_COMM_FEATURE 0x03 +#define USBS_SERIAL_CLEAR_COMM_FEATURE 0x04 + +#define USBS_SERIAL_SET_LINE_CODING 0x20 +#define USBS_SERIAL_GET_LINE_CODING 0x21 +#define USBS_SERIAL_SET_CONTROL_LINE_STATE 0x22 +#define USBS_SERIAL_SEND_BREAK 0x23 + +// ---------------------------------------------------------------------------- +// Data structure to manage the pair of USB endpoints that comprise a single +// serial port connection. Each "port" requires one Bulk IN endpoint and one +// Bulk OUT endpoint. + +typedef struct usbs_serial { + // The communication endpoints. For the first (default) channel, these + // are normally set by the configuration, but can be changed by the + // application, if desired. + usbs_tx_endpoint* tx_ep; + usbs_rx_endpoint* rx_ep; + + // The signal that a transmit operation is complete, and it's result. + cyg_sem_t tx_ready; + int tx_result; + + // The signal that a receive operation is complete, and it's result. + cyg_sem_t rx_ready; + int rx_result; + +} usbs_serial; + +// The package contains one USB serial device. +extern usbs_serial usbs_ser0; + +// It's assumed that there's a single USB slave chip in the system, with a +// single control endpoint 0. The actual variable is contained in the device +// driver, but the USB serial code keeps a pointer to it for driver +// independence. The application might find it useful for overriding low-level +// code or callbacks. +extern usbs_control_endpoint* usbs_serial_ep0; + +// ---------------------------------------------------------------------------- +// A C interface to the serial USB code. +// The application can use this interface, the standard (low-level) USB slave +// API, the standard Unix-like I/O API, or C stdio API. + +// Initialize support for a particular USB serial "port" +// This associates a usbs_serial structure with specific endpoints and +// initializes the structure for communications. +void usbs_serial_init(usbs_serial*, usbs_tx_endpoint*, usbs_rx_endpoint*); + +// Block the calling thread until the host configures the USB device. +void usbs_serial_wait_until_configured(void); + +// Determines if the USB subsystem is configured +cyg_bool usbs_serial_is_configured(void); + +// Start an asynchronous transmit of a single buffer. +void usbs_serial_start_tx(usbs_serial*, const void* buf, int n); + +// Block the calling thread until the transmit completes. +// Returns the result code for the transfer +int usbs_serial_wait_for_tx(usbs_serial*); + +// Blocking, synchronous transmit of a single buffer. +int usbs_serial_tx(usbs_serial*, const void* buf, int n); + +// Start an asynchronous receive of a buffer. +void usbs_serial_start_rx(usbs_serial*, void* buf, int n); + +// Block the calling thread until the receive completes. +// Returns the result code for the transfer +int usbs_serial_wait_for_rx(usbs_serial*); + +// Blocking, synchronous receive of a single buffer. +int usbs_serial_rx(usbs_serial*, void* buf, int n); + +// The default USB-serial state change handler paces the functions +// usbs_serial_wait_until_configured() and usbs_serial_is_configured(). +// The application can override the state chain handler, but chain to +// this function to keep the full USB-serial system working. +void usbs_serial_state_change_handler(usbs_control_endpoint*, void*, + usbs_state_change, int); + +// Starts the USB subsystem +void usbs_serial_start(void); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // CYGONCE_USBS_SERIAL_H +
new file mode 100644 --- /dev/null +++ b/packages/io/usb/serial/slave/current/src/usbs_serial.c @@ -0,0 +1,545 @@ +//========================================================================== +// +// usbs_serial.c +// +// Support for slave-side USB serial devices. +// +//========================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// +// eCos 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 or (at your option) any later version. +// +// eCos 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 eCos; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or inline functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. However the source code for this file must still be made available +// in accordance with section (3) of the GNU General Public License. +// +// This exception does not invalidate any other reasons why a work based on +// this file might be covered by the GNU General Public License. +// +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Frank M. Pagliughi (fmp), SoRo Systems, Inc. +// Date: 2008-06-02 +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include <cyg/infra/cyg_type.h> +#include <cyg/infra/cyg_ass.h> +#include <cyg/infra/cyg_trac.h> +#include <cyg/infra/diag.h> +#include <cyg/hal/hal_arch.h> +#include <cyg/hal/drv_api.h> +#include <cyg/kernel/kapi.h> + +#include <pkgconf/io_usb_slave_serial.h> +#include <cyg/io/usb/usbs_serial.h> +#include <string.h> + +#if defined(CYGBLD_IO_USB_SLAVE_SERIAL_DEBUG) +#define DBG diag_printf +#else +#define DBG (1) ? (void)0 : diag_printf +#endif + +#define EP0_MAX_PACKET_SIZE CYGNUM_IO_USB_SLAVE_SERIAL_EP0_MAX_PACKET_SIZE + +extern usbs_control_endpoint CYGDAT_IO_USB_SLAVE_SERIAL_EP0; +extern usbs_tx_endpoint CYGDAT_IO_USB_SLAVE_SERIAL_TX_EP; +extern usbs_rx_endpoint CYGDAT_IO_USB_SLAVE_SERIAL_RX_EP; + +#define TX_EP_NUM CYGNUM_IO_USB_SLAVE_SERIAL_TX_EP_NUM +#define RX_EP_NUM CYGNUM_IO_USB_SLAVE_SERIAL_RX_EP_NUM +#define INTR_EP_NUM CYGNUM_IO_USB_SLAVE_SERIAL_INTR_EP_NUM +#define EP0 (&CYGDAT_IO_USB_SLAVE_SERIAL_EP0) +#define TX_EP (&CYGDAT_IO_USB_SLAVE_SERIAL_TX_EP) +#define RX_EP (&CYGDAT_IO_USB_SLAVE_SERIAL_RX_EP) +#define INTR_EP (&CYGDAT_IO_USB_SLAVE_SERIAL_INTR_EP) + + +#define VENDOR_ID CYGNUM_IO_USB_SLAVE_SERIAL_VENDOR_ID +#define PRODUCT_ID CYGNUM_IO_USB_SLAVE_SERIAL_PRODUCT_ID + +#define USB_MAX_STR_LEN 256 + +#define LO_BYTE_16(word16) ((cyg_uint8) ((word16) & 0xFF)) +#define HI_BYTE_16(word16) ((cyg_uint8) (((word16) >> 8) & 0xFF)) + +#define BYTE0_32(word32) ((cyg_uint8) ((word32) & 0xFF)) +#define BYTE1_32(word32) ((cyg_uint8) (((word32) >> 8) & 0xFF)) +#define BYTE2_32(word32) ((cyg_uint8) (((word32) >> 16) & 0xFF)) +#define BYTE3_32(word32) ((cyg_uint8) (((word32) >> 24) & 0xFF)) + + +#define MFG_STR_INDEX '\x01' +#define PRODUCT_STR_INDEX '\x02' + +#define USB_CONFIGURATION_DESCRIPTOR_TOTAL_LENGTH(interfaces, endpoints) \ + (USB_CONFIGURATION_DESCRIPTOR_LENGTH + \ + ((interfaces) * USB_INTERFACE_DESCRIPTOR_LENGTH) + \ + ((endpoints) * USB_ENDPOINT_DESCRIPTOR_LENGTH)) + + +#ifdef CYGDAT_IO_USB_SLAVE_CLASS_TYPE_ACM + #define USBS_SERIAL_DEVICE_CLASS 2 + #define USBS_SERIAL_NUM_IFACE 2 + #define USBS_SERIAL_NUM_ENDP 3 + #define USBS_SERIAL_DATA_IFACE_CLASS 0x0A // Data +#else + #define USBS_SERIAL_DEVICE_CLASS 0 + #define USBS_SERIAL_NUM_IFACE 1 + #define USBS_SERIAL_NUM_ENDP 2 + #define USBS_SERIAL_DATA_IFACE_CLASS 0xFF // Vendor +#endif + +// ----- Configuration Descriptor ----- + +static const usb_configuration_descriptor usb_configuration = { + length: sizeof(usb_configuration_descriptor), + type: USB_CONFIGURATION_DESCRIPTOR_TYPE, + total_length_lo: + USB_CONFIGURATION_DESCRIPTOR_TOTAL_LENGTH_LO(USBS_SERIAL_NUM_IFACE, + USBS_SERIAL_NUM_ENDP), + total_length_hi: + USB_CONFIGURATION_DESCRIPTOR_TOTAL_LENGTH_HI(USBS_SERIAL_NUM_IFACE, + USBS_SERIAL_NUM_ENDP), + number_interfaces: USBS_SERIAL_NUM_IFACE, + configuration_id: 1, + configuration_str: 0, + attributes: (USB_CONFIGURATION_DESCRIPTOR_ATTR_REQUIRED | + USB_CONFIGURATION_DESCRIPTOR_ATTR_SELF_POWERED), + max_power: 50 +}; + +// ----- Interface Descriptor ----- + +static const usb_interface_descriptor usb_interface[] = { + +#ifdef CYGDAT_IO_USB_SLAVE_CLASS_TYPE_ACM + { + length: sizeof(usb_interface_descriptor), + type: USB_INTERFACE_DESCRIPTOR_TYPE, + interface_id: 0, + alternate_setting: 0, + number_endpoints: 1, + interface_class: 0x02, // Comm class + interface_subclass: 0x02, + interface_protocol: 0x01, + interface_str: 0x00 + }, + { + length: sizeof(usb_interface_descriptor), + type: USB_INTERFACE_DESCRIPTOR_TYPE, + interface_id: 1, + alternate_setting: 0, + number_endpoints: 2, + interface_class: USBS_SERIAL_DATA_IFACE_CLASS, + interface_subclass: 0x00, + interface_protocol: 0x00, + interface_str: 0x00 + } +#else + { + length: sizeof(usb_interface_descriptor), + type: USB_INTERFACE_DESCRIPTOR_TYPE, + interface_id: 0, + alternate_setting: 0, + number_endpoints: 2, + interface_class: USBS_SERIAL_DATA_IFACE_CLASS, + interface_subclass: 0x00, + interface_protocol: 0x00, + interface_str: 0x00 + } +#endif +}; + +// ----- Endpoint Descriptors ----- + +static const usb_endpoint_descriptor usb_endpoints[] = +{ +#ifdef CYGDAT_IO_USB_SLAVE_CLASS_TYPE_ACM + // Interrupt in endpoint + { + sizeof(usb_endpoint_descriptor), + USB_ENDPOINT_DESCRIPTOR_TYPE, + USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN | INTR_EP_NUM, + USB_ENDPOINT_DESCRIPTOR_ATTR_INTERRUPT, + 0x40, + 0, + 255 + }, +#endif + + // Tx (Bulk IN) Endpoint Descriptor + { + sizeof(usb_endpoint_descriptor), + USB_ENDPOINT_DESCRIPTOR_TYPE, + USB_ENDPOINT_DESCRIPTOR_ENDPOINT_IN | TX_EP_NUM, + USB_ENDPOINT_DESCRIPTOR_ATTR_BULK, + 0x40, + 0, + 0 + }, + + // Rx (Bulk OUT) Endpoint Descriptor + { + sizeof(usb_endpoint_descriptor), + USB_ENDPOINT_DESCRIPTOR_TYPE, + USB_ENDPOINT_DESCRIPTOR_ENDPOINT_OUT | RX_EP_NUM, + USB_ENDPOINT_DESCRIPTOR_ATTR_BULK, + 0x40, + 0, + 0 + } +}; + +// ----- String Descriptors ----- + +static char mfg_str_descr[USB_MAX_STR_LEN], + product_str_descr[USB_MAX_STR_LEN]; + + +static const char* usb_strings[] = { + "\x04\x03\x09\x04", + mfg_str_descr, + product_str_descr +}; + +// ----- Enumeration Data w/ Device Descriptor ----- + +static usbs_enumeration_data usb_enum_data = { + { + length: sizeof(usb_device_descriptor), + type: USB_DEVICE_DESCRIPTOR_TYPE, + usb_spec_lo: 0x00, + usb_spec_hi: 0x02, + device_class: USBS_SERIAL_DEVICE_CLASS, + device_subclass: 0, + device_protocol: 0, + max_packet_size: EP0_MAX_PACKET_SIZE, + vendor_lo: LO_BYTE_16(VENDOR_ID), + vendor_hi: HI_BYTE_16(VENDOR_ID), + product_lo: LO_BYTE_16(PRODUCT_ID), + product_hi: HI_BYTE_16(PRODUCT_ID), + device_lo: 0x00, + device_hi: 0x00, + manufacturer_str: MFG_STR_INDEX, + product_str: PRODUCT_STR_INDEX, + serial_number_str: 0, + number_configurations: 1 + }, + + total_number_interfaces: USBS_SERIAL_NUM_IFACE, + total_number_endpoints: USBS_SERIAL_NUM_ENDP, + total_number_strings: 3, + configurations: &usb_configuration, + interfaces: usb_interface, + endpoints: usb_endpoints, + strings: (const unsigned char **) usb_strings +}; + +// -------------------------------------------------------------------------- +// USBS Serial Data +// -------------------------------------------------------------------------- + +usbs_control_endpoint* usbs_serial_ep0 = EP0; + +// Lock for the state. +cyg_mutex_t usbs_serial_lock; + +// Condition variable for state changes +cyg_cond_t usbs_serial_state_cond; + +int usbs_serial_state; + +usbs_serial usbs_ser0 = { + tx_ep: TX_EP, + rx_ep: RX_EP, + tx_result: 0, + rx_result: 0, +}; + +static void (*usbs_serial_app_state_change_fn)(struct usbs_control_endpoint*, + void*, usbs_state_change, int) += 0; + +// -------------------------------------------------------------------------- +// Create a USB String Descriptor from a C string. + +void +usbs_serial_create_str_descriptor(char descr[], const char *str) +{ + int i, n = strlen(str); + + if (n > (USB_MAX_STR_LEN/2 - 2)) + n = USB_MAX_STR_LEN/2 - 2; + + descr[0] = (cyg_uint8) (2*n + 2); + descr[1] = USB_DEVREQ_DESCRIPTOR_TYPE_STRING; + + for (i=0; i<n; i++) { + descr[i*2+2] = str[i]; + descr[i*2+3] = '\x00'; + } +} + +// -------------------------------------------------------------------------- +// ACM Class Handler +// +// For a Windows host, the device must, at least, respond to a SetLineCoding +// request (0x20), otherwise Windows will report that it's unable to open the +// port. This request normally sets the standard serial parameters: +// baud rate, # stop bits, parity, and # data bits +// If we're just making believe that we're a serial port to communicate with +// the host via USB, then these values don't matter. So we ACK the request, +// but ignore the parameters. +// If we were actually creating a USB-serial converter, then we would need to +// read these values and configure the serial port accordingly. +// +// Similarly, the host can request the current settings through a +// GetLineCoding request (0x21). Since we're just faking it, we return some +// arbitrary values: 38400,1,N,8 + +#ifdef CYGDAT_IO_USB_SLAVE_CLASS_TYPE_ACM + +static usbs_control_return +usbs_serial_acm_class_handler(usbs_control_endpoint* ep0, void* data) +{ + usbs_control_return result = USBS_CONTROL_RETURN_UNKNOWN; + usb_devreq *req = (usb_devreq *) ep0->control_buffer; + static cyg_uint8 rsp_buf[32]; + cyg_uint32 baud = 38400; // Arbitrary, fake value to return to the host. + + DBG("USB Serial ACM Class Handler: "); + + switch (req->request) { + + case USBS_SERIAL_SET_LINE_CODING : + DBG("ACM Request: Set Line Coding\n"); + result = USBS_CONTROL_RETURN_HANDLED; + break; + + case USBS_SERIAL_GET_LINE_CODING : + DBG("ACM Request: Get Line Coding\n"); + rsp_buf[0] = BYTE0_32(baud); + rsp_buf[1] = BYTE1_32(baud); + rsp_buf[2] = BYTE2_32(baud); + rsp_buf[3] = BYTE3_32(baud); + rsp_buf[4] = 0; // One stop bit + rsp_buf[5] = 0; // No parity + rsp_buf[6] = 8; // 8 data bits + ep0->buffer = rsp_buf; + ep0->buffer_size = 7; + result = USBS_CONTROL_RETURN_HANDLED; + break; + + default : + DBG("*** Unhandled ACM Request: 0x%02X ***\n", + (unsigned) req->request); + } + + return result; +} +#endif // CYGDAT_IO_USB_SLAVE_CLASS_TYPE_ACM + +// -------------------------------------------------------------------------- +// Callback for a USB state change + +void +usbs_serial_state_change_handler(usbs_control_endpoint* ep, void* data, + usbs_state_change change, int prev_state) +{ +#if defined(CYGBLD_IO_USB_SLAVE_SERIAL_DEBUG) + const char *STATE_CHG_STR[] = { "Detached", "Attached", "Powered", "Reset", + "Addressed", "Configured", "Deconfigured", + "Suspended", "Resumed" }; + + if (change > 0) { + DBG("### %d:%s ###\n", change, STATE_CHG_STR[(int) change-1]); + } +#endif + + // Called from DSR, cond broadcast should be ok without mutex lock + usbs_serial_state = usbs_serial_ep0->state; + cyg_cond_broadcast(&usbs_serial_state_cond); + + if (usbs_serial_app_state_change_fn) + (*usbs_serial_app_state_change_fn)(ep, data, change, prev_state); +} + +// -------------------------------------------------------------------------- +// Block the calling thread until the USB is configured. + +void +usbs_serial_wait_until_configured(void) +{ + cyg_mutex_lock(&usbs_serial_lock); + while (usbs_serial_state != USBS_STATE_CONFIGURED) + cyg_cond_wait(&usbs_serial_state_cond); + cyg_mutex_unlock(&usbs_serial_lock); +} + +// -------------------------------------------------------------------------- +// Determine if the device is currently configured. + +cyg_bool +usbs_serial_is_configured(void) +{ + return usbs_serial_state == USBS_STATE_CONFIGURED; +} + +// -------------------------------------------------------------------------- +// Callback for when a transmit is complete + +static void +usbs_serial_tx_complete(void *p, int result) +{ + usbs_serial* ser = (usbs_serial*) p; + ser->tx_result = result; + cyg_semaphore_post(&ser->tx_ready); +} + +// -------------------------------------------------------------------------- +// Callback for when a receive is complete + +static void +usbs_serial_rx_complete(void *p, int result) +{ + usbs_serial* ser = (usbs_serial*) p; + ser->rx_result = result; + cyg_semaphore_post(&ser->rx_ready); +} + +// -------------------------------------------------------------------------- +// Start an asynchronous transmit of a buffer. +// + +void +usbs_serial_start_tx(usbs_serial* ser, const void* buf, int n) +{ + usbs_start_tx_buffer(ser->tx_ep, (unsigned char*) buf, n, + usbs_serial_tx_complete, ser); +} + +// -------------------------------------------------------------------------- +// Block the caller until the transmit is complete + +int +usbs_serial_wait_for_tx(usbs_serial* ser) +{ + cyg_semaphore_wait(&ser->tx_ready); + return ser->tx_result; +} + +// -------------------------------------------------------------------------- +// Perform a synchronous transmit and wait for it to complete. + +int +usbs_serial_tx(usbs_serial* ser, const void* buf, int n) +{ + usbs_serial_start_tx(ser, buf, n); + return usbs_serial_wait_for_tx(ser); +} + +// -------------------------------------------------------------------------- +// Start an asynchronous receive of a buffer. + +void +usbs_serial_start_rx(usbs_serial* ser, void* buf, int n) +{ + usbs_start_rx_buffer(ser->rx_ep, (unsigned char*) buf, n, + usbs_serial_rx_complete, ser); +} + +// -------------------------------------------------------------------------- +// Block the caller until the receive is complete + +int +usbs_serial_wait_for_rx(usbs_serial* ser) +{ + cyg_semaphore_wait(&ser->rx_ready); + return ser->rx_result; +} + +// -------------------------------------------------------------------------- +// Perform a synchronous receive and wait for it to complete. + +int +usbs_serial_rx(usbs_serial* ser, void* buf, int n) +{ + usbs_serial_start_rx(ser, buf, n); + return usbs_serial_wait_for_rx(ser); +} + +// -------------------------------------------------------------------------- +// Initialize a serial port structure. + +void +usbs_serial_init(usbs_serial* ser, usbs_tx_endpoint* tx_ep, + usbs_rx_endpoint* rx_ep) +{ + ser->tx_ep = tx_ep; + ser->rx_ep = rx_ep; + + cyg_semaphore_init(&ser->tx_ready, 0); + cyg_semaphore_init(&ser->rx_ready, 0); +} + +// -------------------------------------------------------------------------- +// Start the USB subsystem + +void +usbs_serial_start(void) +{ + usbs_serial_init(&usbs_ser0, TX_EP, RX_EP); + + cyg_mutex_init(&usbs_serial_lock); + cyg_cond_init(&usbs_serial_state_cond, &usbs_serial_lock); + + // Make the mfg & product names into USB string descriptors + + usbs_serial_create_str_descriptor(mfg_str_descr, + CYGDAT_IO_USB_SLAVE_SERIAL_MFG_STR); + usbs_serial_create_str_descriptor(product_str_descr, + CYGDAT_IO_USB_SLAVE_SERIAL_PRODUCT_STR); + + // ----- Set up enumeration & USB callbacks ----- + + usbs_serial_state = usbs_serial_ep0->state; + + usbs_serial_ep0->enumeration_data = &usb_enum_data; + + if (usbs_serial_ep0->state_change_fn) + usbs_serial_app_state_change_fn = usbs_serial_ep0->state_change_fn; + + usbs_serial_ep0->state_change_fn = usbs_serial_state_change_handler; + +#ifdef CYGDAT_IO_USB_SLAVE_CLASS_TYPE_ACM + if (!usbs_serial_ep0->class_control_fn) + usbs_serial_ep0->class_control_fn = usbs_serial_acm_class_handler; +#endif + + // ----- Start USB subsystem ----- + + usbs_start(usbs_serial_ep0); +}
new file mode 100644 --- /dev/null +++ b/packages/io/usb/serial/slave/current/tests/usb2serial.c @@ -0,0 +1,358 @@ +//========================================================================== +// +// usb2serial.c +// +// Example application for the USB serial layer in eCos. +// +//========================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// +// eCos 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 or (at your option) any later version. +// +// eCos 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 eCos; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or inline functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. However the source code for this file must still be made available +// in accordance with section (3) of the GNU General Public License. +// +// This exception does not invalidate any other reasons why a work based on +// this file might be covered by the GNU General Public License. +// +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//=========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Frank M. Pagliughi (fmp), SoRo Systems, Inc. +// Contributors: +// Date: 2008-06-02 +// Description: USB serial example application. +// +//####DESCRIPTIONEND#### +//=========================================================================== + +#include <cyg/kernel/kapi.h> +#include <cyg/hal/hal_arch.h> +#include <cyg/infra/diag.h> +#include <pkgconf/kernel.h> +#include <cyg/io/serialio.h> + +// Replace this with any other USB driver desired. +#include <cyg/io/usb/usbs_at91.h> +#include <cyg/io/usb/usbs_serial.h> +#include <pkgconf/io_usb_slave_serial.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> + +// This application creates a USB-serial converter. To the host it will appear +// as a single serial USB port, such as /dev/ttyUSB0 for a Linux host. +// Any characters received from the USB host will be sent out the serial port +// and visa-verse. It creates a separate, dedicated thread for each direction. +// +// It uses the eCos USB-serial layer to enumerate with the USB host and monitor +// the connection, but then uses standard C I/O functions to perform the +// communications. +// +// The USB serial module can be configured as a generic adapter or an an ACM +// communications class device. For the latter, the application handles the +// USB communications class requests which allows it to receive requests from +// the host to set serial parameters, like the baud rate. This actually turns +// this example into a more realistic USB-serial adapter that can be configured +// dynamically by the host. +// +// The eCos library must be configured with the packages for USB slave, USB +// serial, and File I/O. It also requires the proper serial port driver for the +// target platform. +// +// This example was tested with the AT91SAM7S-EK board, but should work with any +// board that has a USB slave and serial port, and the necessary drivers. + + +// Comment this line out to remove debug output. +#define DEBUG_OUTPUT + +#if defined(DEBUG_OUTPUT) +#define DBG diag_printf +#else +#define DBG (1) ? (void)0 : diag_printf +#endif + +// Set these to the USB devtab entries for the Tx and Rx Bulk endpoints +// selected in the configuration of the USB serial subsystem. +#define USB_TX_DEV "/dev/usbs1" +#define USB_RX_DEV "/dev/usbs2" + +// Set this for any available serial port on the target. +#define SER_DEV "/dev/ser0" + +// Buffer for incoming USB bulk data. The local USB driver can probably split +// packets, but just in case, making this the page size of the host might be +// helpful. +#define BUF_SIZE 4096 +static char usb2ser_buf[BUF_SIZE]; + +// The threads +cyg_thread thread[2]; + +// Space for two 4K stacks +#define THREAD_STACK_SIZE 4096 +char stack[2][THREAD_STACK_SIZE]; + +// The handles for the threads +cyg_handle_t usb2ser_thread, + ser2usb_thread; + +// -------------------------------------------------------------------------- +// For an ACM serial device we can handle the USB class messages to deal with +// requests from the host like setting the serial parameters (baud rate, +// etc). + +#ifdef CYGDAT_IO_USB_SLAVE_CLASS_TYPE_ACM + +static cyg_uint8 acm_buf[32]; +static cyg_uint32 baud = 34800; + +// -------------------------------------------------------------------------- +// Handler for the completion of a SetLineCoding request from the host. +// The 'acm_buf' should contain the 7-byte request OUT packet from the +// host. This contains a request to change the serial parameters. +// In this example function, we will accept a few different baud rates. +// To keep the example relatively simple, though, we keep the other serial +// parameters to 1 stop bit, no parity, 8 data bits. + +static usbs_control_return +acm_set_line_coding(usbs_control_endpoint* ep0, int n) +{ + int err; + cyg_uint32 req_baud; + cyg_io_handle_t handle; + + // Get the requested baud rate from the received ctrl OUT packet + req_baud = ((acm_buf[3] << 24) | (acm_buf[2] << 16) | + (acm_buf[1] << 8) | acm_buf[0]); + + DBG("Set Baud: %u\n", (unsigned) baud); + + // Look up the serial handle and attempt to set the baud rate. + if (cyg_io_lookup(SER_DEV, &handle) == 0) { + cyg_serial_info_t ser_info; + cyg_uint32 len = sizeof(ser_info); + + switch (baud) { + case 9600 : ser_info.baud = CYGNUM_SERIAL_BAUD_9600; break; + case 38400 : ser_info.baud = CYGNUM_SERIAL_BAUD_38400; break; + case 115200 : ser_info.baud = CYGNUM_SERIAL_BAUD_115200; break; + default: + DBG("Unsupported baud rate\n"); + return USBS_CONTROL_RETURN_HANDLED; + } + ser_info.stop = CYGNUM_SERIAL_STOP_1; + ser_info.parity = CYGNUM_SERIAL_PARITY_NONE; + ser_info.word_length = CYGNUM_SERIAL_WORD_LENGTH_8; + ser_info.flags = 0; + + err = cyg_io_set_config(handle, CYG_IO_SET_CONFIG_SERIAL_INFO, + &ser_info, &len); + if (err == 0) + baud = req_baud; + else { + DBG("Error setting serial params\n"); + } + } + else { + DBG("Error looking up serial device: %s\n", SER_DEV); + } + return USBS_CONTROL_RETURN_HANDLED; +} + +// -------------------------------------------------------------------------- +// Handler for the ACM class messages. +// +static usbs_control_return +acm_class_handler(usbs_control_endpoint* ep0, void* data) +{ + usbs_control_return result = USBS_CONTROL_RETURN_UNKNOWN; + + usb_devreq *req = (usb_devreq *) ep0->control_buffer; + + static cyg_uint8 rsp_buf[32]; + + DBG("ACM Class Handler\n"); + + switch (req->request) { + + case USBS_SERIAL_SET_LINE_CODING : + DBG("Set Line Coding\n"); + memset(acm_buf, 0, 32); + ep0->buffer = acm_buf; + ep0->buffer_size = 7; + ep0->complete_fn = acm_set_line_coding; + result = USBS_CONTROL_RETURN_HANDLED; + break; + + case USBS_SERIAL_GET_LINE_CODING : + DBG("Get Line Coding\n"); + rsp_buf[0] = baud & 0xFF; + rsp_buf[1] = (baud >> 8) & 0xFF; + rsp_buf[2] = (baud >> 16) & 0xFF; + rsp_buf[3] = (baud >> 24) & 0xFF; + rsp_buf[4] = 0; // One stop bit + rsp_buf[5] = 0; // No parity + rsp_buf[6] = 8; // 8 data bits + ep0->buffer = rsp_buf; + ep0->buffer_size = 7; + result = USBS_CONTROL_RETURN_HANDLED; + break; + + default : + DBG("*** Unhandled ACM Request: 0x%02X ***\n", + (unsigned) req->request); + } + + return result; +} + +#endif // CYGDAT_IO_USB_SLAVE_CLASS_TYPE_ACM + +// -------------------------------------------------------------------------- +// Thread receives packets from the USB and sends them out the serial port +// It uses a buffered stdio input, an un-buffered low-level file output. +// This isn't terribly efficient, but rather an example of both methods. + +void usb2ser_func(cyg_addrword_t data) +{ + int c; + FILE *rxf = fopen(USB_RX_DEV, "r"); + int txh = open(SER_DEV, O_WRONLY, 0); + + DBG("Usb2Ser: Thread starting\n"); + + if (!rxf) { + DBG("Error opening USB rx port\n"); + return; + } + + if (txh < 0) { + DBG("Error opening serial tx port\n"); + return; + } + + // Give the USB receiver an adequate buffer. + setvbuf(rxf, usb2ser_buf, _IOFBF, BUF_SIZE); + + while (1) { + + // ----- Wait for the host to configure ----- + + DBG("Usb2Ser: Waiting for USB configuration\n"); + usbs_serial_wait_until_configured(); + cyg_thread_delay((cyg_tick_count_t) 10); + + // ----- While configured read data & send out serial port ----- + + DBG("Usb2Ser: USB configured\n"); + while (usbs_serial_is_configured()) { + if ((c = getc(rxf)) < 0) { + DBG("*** USB Read Error: %d ***\n", c); + } + else { + char ch = (char) c; + write(txh, &ch, 1); + } + } + } +} + +// -------------------------------------------------------------------------- +// Thread receives packets from the serial port and sends them out the USB +// It uses a buffered stdio input, an un-buffered low-level file output. +// This isn't terribly efficient, but rather an example of both methods. + +void ser2usb_func(cyg_addrword_t data) +{ + int c; + FILE *rxf = fopen(SER_DEV, "r"); + int txh = open(USB_TX_DEV, O_WRONLY, 0); + + DBG("Ser2Usb: Thread starting\n"); + + if (!rxf) { + DBG("Error opening serial rx port\n"); + return; + } + + if (txh < 0) { + DBG("Error opening USB tx port\n"); + return; + } + + while (1) { + + // ----- Wait for the host to configure ----- + + DBG("Ser2Usb: Waiting for USB configuration\n"); + usbs_serial_wait_until_configured(); + cyg_thread_delay((cyg_tick_count_t) 10); + + // ----- While configured read data & send out serial port ----- + + DBG("Ser2Usb: USB configured\n"); + while (usbs_serial_is_configured()) { + if ((c = getc(rxf)) < 0) { + DBG("*** Console Read Error: %d ***\n", c); + } + else { + char ch = (char) c; + write(txh, &ch, 1); + } + } + } +} + +// -------------------------------------------------------------------------- +// Application Startup +// -------------------------------------------------------------------------- + +void cyg_user_start(void) +{ + DBG("Entering cyg_user_start() function\n"); + +#ifdef CYGDAT_IO_USB_SLAVE_CLASS_TYPE_ACM + // Override the class handler to use ours. + usbs_serial_ep0->class_control_fn = acm_class_handler; +#endif + + cyg_thread_create(4, usb2ser_func, (cyg_addrword_t) 0, + "Usb2Serial", (void *) stack[0], THREAD_STACK_SIZE, + &usb2ser_thread, &thread[0]); + + cyg_thread_create(4, ser2usb_func, (cyg_addrword_t) 1, + "Serial2Usb", (void *) stack[1], THREAD_STACK_SIZE, + &ser2usb_thread, &thread[1]); + + // Start USB subsystem + usbs_serial_start(); + + // Start the threads running. + cyg_thread_resume(usb2ser_thread); + cyg_thread_resume(ser2usb_thread); +} +
new file mode 100644 --- /dev/null +++ b/packages/io/usb/serial/slave/current/tests/usbserial_echo.c @@ -0,0 +1,126 @@ +//========================================================================== +// +// usb_serial_echo.c +// +// Example application for the USB serial layer in eCos. +// +//========================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// +// eCos 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 or (at your option) any later version. +// +// eCos 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 eCos; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or inline functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. However the source code for this file must still be made available +// in accordance with section (3) of the GNU General Public License. +// +// This exception does not invalidate any other reasons why a work based on +// this file might be covered by the GNU General Public License. +// +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//=========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Frank M. Pagliughi (fmp), SoRo Systems, Inc. +// Contributors: +// Date: 2008-06-02 +// Description: USB serial example application. +// +//####DESCRIPTIONEND#### +//=========================================================================== + +#include <cyg/kernel/kapi.h> +#include <cyg/hal/hal_arch.h> +#include <cyg/infra/diag.h> +#include <pkgconf/kernel.h> +#include <cyg/io/usb/usbs_at91.h> +#include <cyg/io/usb/usbs_serial.h> + +#include <stdio.h> +#include <stdlib.h> + +#define DEBUG_OUTPUT + +#if defined(DEBUG_OUTPUT) +#define DBG diag_printf +#else +#define DBG (1) ? (void)0 : diag_printf +#endif + +typedef unsigned char byte; + +// -------------------------------------------------------------------------- +// Data & Callback(s) +// -------------------------------------------------------------------------- + +#define BUF_SIZE 4096 + +static byte rx_buf[2][BUF_SIZE+1], tx_buf[BUF_SIZE+1]; + +// -------------------------------------------------------------------------- +// Main Routine +// -------------------------------------------------------------------------- + +int main(void) +{ + int n; + unsigned ibuf, next_buf; + + // ----- Start USB subsystem ----- + + usbs_serial_start(); + + // ----- Get data from host and send it back ----- + + while (1) { + ibuf = 0; + + // ----- Wait for the host to configure ----- + + usbs_serial_wait_until_configured(); + cyg_thread_delay((cyg_tick_count_t) 10); + + // ----- While configured read data & print to screen ----- + + usbs_serial_start_rx(&usbs_ser0, rx_buf[ibuf], BUF_SIZE); + + while (usbs_serial_is_configured()) { + + n = usbs_serial_wait_for_rx(&usbs_ser0); + next_buf = ibuf ^ 1; + + usbs_serial_start_rx(&usbs_ser0, rx_buf[next_buf], BUF_SIZE); + + if (n < 0) { + DBG("*** I/O Error: %d ***\n", n); + } + else { + memcpy(tx_buf, rx_buf[ibuf], n); + usbs_serial_tx(&usbs_ser0, tx_buf, n); + rx_buf[ibuf][n] = '\0'; + DBG("%s", rx_buf[ibuf]); + } + + ibuf = next_buf; + } + } + + return 0; +} +
