# -*- perl -*-
#
# Invoked from usbdescgen.pl
#

require '../../iodevs.conf';

usb_languages('en_US', 'sv_SE');

my $vendor_id    = word(0x1d50);
my $device_id    = word(0x6149);
my $version_id   = word(0x0100);

my $serial       = usb_serial('SerialNumberHere'); # 16 characters
my $manufacturer = usb_string(''   => 'Peter & Per');
my $product      = usb_string(''   => 'MAX80 I/O card for ABC');

sub acm_channels($$) {
    my($channel_count,$ep_base) = @_;
    my @d;

    for (my $c = 0; $c < $channel_count; $c++) {
	my $ep_data = $ep_base + ($c << 1);
	my $ep_intr = $ep_data + 1;

	my $mgmt_if;
	my $data_if;

	push(@d,
		# Interface association descriptor
		usb_desc('interface_association',
			 byte(\$mgmt_if), # First interface index
			 byte(2),	  # Interface count
			 # USB spec says to copy the first interface class
			 usb_class('cdc','acm','v25ter'),
			 usb_string()),

		# Management interface
		usb_dset {
		    usb_desc('interface',
			     byte($mgmt_if = usb_index),
			     byte(0),	# No alternate settings
			     byte(1),	# Endpoint count
			     usb_class('cdc','acm','v25ter'),
			     usb_string()),

			usb_desc('cs_interface.header',
				 word(0x120)), # CDC spec version 1.20

			usb_desc('cs_interface.call_management',
				 byte(0x03), # AT commands over setup or data
				 byte(\$data_if)), # Which data interface

			usb_desc('cs_interface.acm',
				 # Supports SET_CONTROL_LINE_STATE and
				 # SEND_BREAK. This also means
				 # GET|SET_LINE_CODING has to be handled,
				 # at least vacuously.
				 byte(0x06)),

			usb_desc('cs_interface.union',
				 byte(\$mgmt_if),	# Controlling interface
				 byte(\$data_if)),	# Data interface

			# Notification endpoint (input)
			usb_desc('endpoint',
				 ep_i($ep_intr),
				 byte(3),	# Interrupt, data
				 word(64),	# Max packet size
				 byte(2)),	# Interval
	    },

		# Data interface
		usb_dset {
		    usb_desc('interface',
			     byte($data_if = usb_index),
			     byte(0),	# No alternate settings
			     byte(2),	# Endpoint count
			     usb_class('cdc_data'),
			     usb_string()),

			# Data endpoint (input)
			usb_desc('endpoint',
				 ep_i($ep_data),
				 byte(2),      # Bulk, data
				 word(64),     # Max packet size
				 byte(0)),     # Interval

			# Data endpoint (output)
			usb_desc('endpoint',
				 ep_o($ep_data),
				 byte(2),	# Bulk, data
				 word(64),	# Max packet size
				 byte(0))       # Interval

	     });
    }

    return @d;
}

usb_device {
    usb_desc('device',
	     word(0x101),		# USB version
	     usb_class('multi'),	# Device with multiple interfaces
	     byte(8),			# Max packet size on endpoint 0
	     $vendor_id, $device_id, $version_id,
	     $manufacturer, $product, $serial,
	     byte(usb_children)		# Number of configurations
	),

	usb_dset {
	    usb_desc('configuration',
		     word(usb_totallen), # Total length for this dset
		     byte(usb_children), # Number of interfaces
		     byte(usb_index,1),	 # This configuration index
		     usb_string(),	 # Text description (empty)
		     byte(0xc0),	 # Self or bus powered
		     byte(500 >> 1)),	 # Up to 500 mA

		# Descriptors for each ACM channel, starting at endpoint 1
		acm_channels($consts{'TTY_CHANNELS'},1)
    },
};

usb_additional_data {
    # Line state structure
    dword(38400),		# Baud rate (largest POSIX required value)
	byte(0),		# 1 stop bit
	byte(0),		# No parity
	byte(8)			# 8 data bits
};
