The module will be called empeg.o. If you want to compile it as a
module, say M here and read Documentation/modules.txt.
+USB MCT Single Port Serial Driver
+CONFIG_USB_SERIAL_MCT_U232
+ Say Y here if you want to use a USB Serial single port adapter from
+ Magic Control Technology Corp. (U232 is one of the model numbers).
+
+ This code is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called mct_u232.o. If you want to compile it as
+ a module, say M here and read Documentation/modules.txt.
+
USB Serial Converter verbose debug
CONFIG_USB_SERIAL_DEBUG
Say Y here if you want verbose debug messages from the USB Serial
Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
- Version 2.2.8 for Linux 2.2.16
- Version 2.4.8 for Linux 2.4.0
+ Version 2.2.9 for Linux 2.2.17
+ Version 2.4.9 for Linux 2.4.0
PRODUCTION RELEASE
- 19 August 2000
+ 7 September 2000
Leonard N. Zubkoff
Dandelion Digital
DRIVER INSTALLATION
-This distribution was prepared for Linux kernel version 2.2.16 or 2.4.0.
+This distribution was prepared for Linux kernel version 2.2.17 or 2.4.0.
To install the DAC960 RAID driver, you may use the following commands,
replacing "/usr/src" with wherever you keep your Linux kernel source tree:
cd /usr/src
- tar -xvzf DAC960-2.2.8.tar.gz (or DAC960-2.4.8.tar.gz)
+ tar -xvzf DAC960-2.2.9.tar.gz (or DAC960-2.4.9.tar.gz)
mv README.DAC960 linux/Documentation
mv DAC960.[ch] linux/drivers/block
patch -p0 < DAC960.patch (if DAC960.patch is included)
-ENODEV specified USB-device or bus doesn't exist
USB_ST_REQUEST_ERROR
--ENXIO a) specified endpoint doesn't exist on the device
- b) an URB is already queued to this endpoint and
- USB_QUEUE_BULK wasn't used (UHCI HCDs only)
+-ENXIO a control or interrupt URB is already queued to this endpoint; or
+ a bulk URB is already queued to this endpoint and
+ USB_QUEUE_BULK wasn't used (UHCI HCDs only)
USB_ST_URB_INVALID_ERROR
-EINVAL a) Invalid transfer type specified (or not supported)
helpful. :)
+MCT USB Single Port Serial Adapter U232
+
+ This driver is for the MCT USB-RS232 Converter (25 pin, Model No.
+ U232-P25) from Magic Control Technology Corp. (there is also a 9 pin
+ Model No. U232-P9). More information about this device can be found
+ at the manufacture's web-site: http://www.mct.com.tw.
+
+ The driver is generally working, though it still needs some more
+ testing. It is derived from the Belkin USB Serial Adapter F5U103
+ driver and its TODO list is valid for this driver as well.
+
+
Generic Serial driver
If your device is not one of the above listed devices, compatible with
* Nov 1999, Version 1.11
* Jan 2000, Version 1.12
* Feb 2000, Version 1.13
+ * Nov 2000, Version 1.14
*
* History:
* 0.6b: first version in official kernel, Linux 1.3.46
* <tmh@magenta-logic.com> and <zlatko@iskon.hr>) modified by sfr.
* Remove CONFIG_APM_SUSPEND_BOUNCE. The bounce ignore
* interval is now configurable.
+ * 1.14: Make connection version persist across module unload/load.
+ * Enable and engage power management earlier.
+ * Disengage power management on module unload.
*
* APM 1.1 Reference:
*
static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
-static struct apm_user * user_list = NULL;
+static struct apm_user * user_list;
-static char driver_version[] = "1.13"; /* no spaces */
+static char driver_version[] = "1.14"; /* no spaces */
static char * apm_event_name[] = {
"system standby",
&dummy, &dummy))
return (eax >> 8) & 0xff;
*event = ebx;
- if (apm_bios_info.version < 0x0102)
+ if (apm_info.connection_version < 0x0102)
*info = ~0; /* indicate info not valid */
else
*info = ecx;
#ifdef ALWAYS_CALL_BUSY
clock_slowed = 1;
#else
- clock_slowed = (apm_bios_info.flags & APM_IDLE_SLOWS_CLOCK) != 0;
+ clock_slowed = (apm_info.bios.flags & APM_IDLE_SLOWS_CLOCK) != 0;
#endif
return 1;
}
{
u32 eax;
- if ((enable == 0) && (apm_bios_info.flags & APM_BIOS_DISENGAGED))
+ if ((enable == 0) && (apm_info.bios.flags & APM_BIOS_DISENGAGED))
return APM_NOT_ENGAGED;
if (apm_bios_call_simple(APM_FUNC_ENABLE_PM, APM_DEVICE_BALL,
enable, &eax))
return (eax >> 8) & 0xff;
if (enable)
- apm_bios_info.flags &= ~APM_BIOS_DISABLED;
+ apm_info.bios.flags &= ~APM_BIOS_DISABLED;
else
- apm_bios_info.flags |= APM_BIOS_DISABLED;
+ apm_info.bios.flags |= APM_BIOS_DISABLED;
return APM_SUCCESS;
}
#endif
u32 edx;
u32 dummy;
+ if (apm_info.get_power_status_broken)
+ return APM_32_UNSUPPORTED;
if (apm_bios_call(APM_FUNC_GET_STATUS, APM_DEVICE_ALL, 0,
&eax, &ebx, &ecx, &edx, &dummy))
return (eax >> 8) & 0xff;
u32 edx;
u32 esi;
- if (apm_bios_info.version < 0x0102) {
+ if (apm_info.connection_version < 0x0102) {
/* pretend we only have one battery. */
if (which != 1)
return APM_BAD_DEVICE;
u32 eax;
if ((enable == 0) && (device == APM_DEVICE_ALL)
- && (apm_bios_info.flags & APM_BIOS_DISABLED))
+ && (apm_info.bios.flags & APM_BIOS_DISABLED))
return APM_DISABLED;
if (apm_bios_call_simple(APM_FUNC_ENGAGE_PM, device, enable, &eax))
return (eax >> 8) & 0xff;
if (device == APM_DEVICE_ALL) {
if (enable)
- apm_bios_info.flags &= ~APM_BIOS_DISENGAGED;
+ apm_info.bios.flags &= ~APM_BIOS_DISENGAGED;
else
- apm_bios_info.flags |= APM_BIOS_DISENGAGED;
+ apm_info.bios.flags |= APM_BIOS_DISENGAGED;
}
return APM_SUCCESS;
}
printk(KERN_CRIT "apm: Critical suspend was vetoed, expect armageddon\n" );
return 0;
}
- if (apm_bios_info.version > 0x100)
+ if (apm_info.connection_version > 0x100)
apm_set_power_state(APM_STATE_REJECT);
return 0;
}
case APM_USER_SUSPEND:
#ifdef CONFIG_APM_IGNORE_USER_SUSPEND
- if (apm_bios_info.version > 0x100)
+ if (apm_info.connection_version > 0x100)
apm_set_power_state(APM_STATE_REJECT);
break;
#endif
case APM_SYS_SUSPEND:
if (ignore_bounce) {
- if (apm_bios_info.version > 0x100)
+ if (apm_info.connection_version > 0x100)
apm_set_power_state(APM_STATE_REJECT);
break;
}
int err;
if ((standbys_pending > 0) || (suspends_pending > 0)) {
- if ((apm_bios_info.version > 0x100) && (pending_count-- <= 0)) {
+ if ((apm_info.connection_version > 0x100) && (pending_count-- <= 0)) {
pending_count = 4;
if (debug)
printk(KERN_DEBUG "apm: setting state busy\n");
unsigned short bx;
unsigned short cx;
unsigned short dx;
- unsigned short error;
+ int error;
unsigned short ac_line_status = 0xff;
unsigned short battery_status = 0xff;
unsigned short battery_flag = 0xff;
if ((cx & 0xff) != 0xff)
percentage = cx & 0xff;
- if (apm_bios_info.version > 0x100) {
+ if (apm_info.connection_version > 0x100) {
battery_flag = (cx >> 8) & 0xff;
if (dx != 0xffff) {
units = (dx & 0x8000) ? "min" : "sec";
p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
driver_version,
- (apm_bios_info.version >> 8) & 0xff,
- apm_bios_info.version & 0xff,
- apm_bios_info.flags,
+ (apm_info.bios.version >> 8) & 0xff,
+ apm_info.bios.version & 0xff,
+ apm_info.bios.flags,
ac_line_status,
battery_status,
battery_flag,
unsigned short bx;
unsigned short cx;
unsigned short dx;
- unsigned short error;
+ int error;
char * power_stat;
char * bat_stat;
sigfillset(¤t->blocked);
current->tty = NULL; /* get rid of controlling tty */
- if (apm_bios_info.version > 0x100) {
+ if (apm_info.connection_version == 0) {
+ apm_info.connection_version = apm_info.bios.version;
+ if (apm_info.connection_version > 0x100) {
+ /*
+ * We only support BIOSs up to version 1.2
+ */
+ if (apm_info.connection_version > 0x0102)
+ apm_info.connection_version = 0x0102;
+ error = apm_driver_version(&apm_info.connection_version);
+ if (error != APM_SUCCESS) {
+ apm_error("driver version", error);
+ /* Fall back to an APM 1.0 connection. */
+ apm_info.connection_version = 0x100;
+ }
+ }
+ }
+
+ if (debug)
+ printk(KERN_INFO "apm: Connection version %d.%d\n",
+ (apm_info.connection_version >> 8) & 0xff,
+ apm_info.connection_version & 0xff);
+
+#ifdef CONFIG_APM_DO_ENABLE
+ if (apm_info.bios.flags & APM_BIOS_DISABLED) {
/*
- * We only support BIOSs up to version 1.2
+ * This call causes my NEC UltraLite Versa 33/C to hang if it
+ * is booted with PM disabled but not in the docking station.
+ * Unfortunate ...
*/
- if (apm_bios_info.version > 0x0102)
- apm_bios_info.version = 0x0102;
- if (apm_driver_version(&apm_bios_info.version) != APM_SUCCESS) {
- /* Fall back to an APM 1.0 connection. */
- apm_bios_info.version = 0x100;
+ error = apm_enable_power_management(1);
+ if (error) {
+ apm_error("enable power management", error);
+ return -1;
+ }
+ }
+#endif
+
+ if ((apm_info.bios.flags & APM_BIOS_DISENGAGED)
+ && (apm_info.connection_version > 0x0100)) {
+ error = apm_engage_power_management(APM_DEVICE_ALL, 1);
+ if (error) {
+ apm_error("engage power management", error);
+ return -1;
}
}
- if (debug && (smp_num_cpus == 1)) {
- printk(KERN_INFO "apm: Connection version %d.%d\n",
- (apm_bios_info.version >> 8) & 0xff,
- apm_bios_info.version & 0xff);
+ if (debug && (smp_num_cpus == 1)) {
error = apm_get_power_status(&bx, &cx, &dx);
if (error)
printk(KERN_INFO "apm: power status not available\n");
printk("unknown\n");
else
printk("%d%%\n", cx & 0xff);
- if (apm_bios_info.version > 0x100) {
+ if (apm_info.connection_version > 0x100) {
printk(KERN_INFO
"apm: battery flag 0x%02x, battery life ",
(cx >> 8) & 0xff);
}
}
-#ifdef CONFIG_APM_DO_ENABLE
- if (apm_bios_info.flags & APM_BIOS_DISABLED) {
- /*
- * This call causes my NEC UltraLite Versa 33/C to hang if it
- * is booted with PM disabled but not in the docking station.
- * Unfortunate ...
- */
- error = apm_enable_power_management(1);
- if (error) {
- apm_error("enable power management", error);
- return -1;
- }
- }
-#endif
- if ((apm_bios_info.flags & APM_BIOS_DISENGAGED)
- && (apm_bios_info.version > 0x0100)) {
- error = apm_engage_power_management(APM_DEVICE_ALL, 1);
- if (error) {
- apm_error("engage power management", error);
- return -1;
- }
- }
-
/* Install our power off handler.. */
if (power_off)
pm_power_off = apm_power_off;
*/
static int __init apm_init(void)
{
- if (apm_bios_info.version == 0) {
+ struct proc_dir_entry *apm_proc;
+
+ if (apm_info.bios.version == 0) {
printk(KERN_INFO "apm: BIOS not found.\n");
return -ENODEV;
}
printk(KERN_INFO
"apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n",
- ((apm_bios_info.version >> 8) & 0xff),
- (apm_bios_info.version & 0xff),
- apm_bios_info.flags,
+ ((apm_info.bios.version >> 8) & 0xff),
+ (apm_info.bios.version & 0xff),
+ apm_info.bios.flags,
driver_version);
- if ((apm_bios_info.flags & APM_32_BIT_SUPPORT) == 0) {
+ if ((apm_info.bios.flags & APM_32_BIT_SUPPORT) == 0) {
printk(KERN_INFO "apm: no 32 bit BIOS support\n");
return -ENODEV;
}
* Fix for the Compaq Contura 3/25c which reports BIOS version 0.1
* but is reportedly a 1.0 BIOS.
*/
- if (apm_bios_info.version == 0x001)
- apm_bios_info.version = 0x100;
+ if (apm_info.bios.version == 0x001)
+ apm_info.bios.version = 0x100;
/* BIOS < 1.2 doesn't set cseg_16_len */
- if (apm_bios_info.version < 0x102)
- apm_bios_info.cseg_16_len = 0; /* 64k */
+ if (apm_info.bios.version < 0x102)
+ apm_info.bios.cseg_16_len = 0; /* 64k */
if (debug) {
printk(KERN_INFO "apm: entry %x:%lx cseg16 %x dseg %x",
- apm_bios_info.cseg, apm_bios_info.offset,
- apm_bios_info.cseg_16, apm_bios_info.dseg);
- if (apm_bios_info.version > 0x100)
+ apm_info.bios.cseg, apm_info.bios.offset,
+ apm_info.bios.cseg_16, apm_info.bios.dseg);
+ if (apm_info.bios.version > 0x100)
printk(" cseg len %x, dseg len %x",
- apm_bios_info.cseg_len,
- apm_bios_info.dseg_len);
- if (apm_bios_info.version > 0x101)
- printk(" cseg16 len %x", apm_bios_info.cseg_16_len);
+ apm_info.bios.cseg_len,
+ apm_info.bios.dseg_len);
+ if (apm_info.bios.version > 0x101)
+ printk(" cseg16 len %x", apm_info.bios.cseg_16_len);
printk("\n");
}
__va((unsigned long)0x40 << 4));
_set_limit((char *)&gdt[APM_40 >> 3], 4095 - (0x40 << 4));
- apm_bios_entry.offset = apm_bios_info.offset;
+ apm_bios_entry.offset = apm_info.bios.offset;
apm_bios_entry.segment = APM_CS;
set_base(gdt[APM_CS >> 3],
- __va((unsigned long)apm_bios_info.cseg << 4));
+ __va((unsigned long)apm_info.bios.cseg << 4));
set_base(gdt[APM_CS_16 >> 3],
- __va((unsigned long)apm_bios_info.cseg_16 << 4));
+ __va((unsigned long)apm_info.bios.cseg_16 << 4));
set_base(gdt[APM_DS >> 3],
- __va((unsigned long)apm_bios_info.dseg << 4));
+ __va((unsigned long)apm_info.bios.dseg << 4));
#ifndef APM_RELAX_SEGMENTS
- if (apm_bios_info.version == 0x100) {
+ if (apm_info.bios.version == 0x100) {
#endif
/* For ASUS motherboard, Award BIOS rev 110 (and others?) */
_set_limit((char *)&gdt[APM_CS >> 3], 64 * 1024 - 1);
#ifndef APM_RELAX_SEGMENTS
} else {
_set_limit((char *)&gdt[APM_CS >> 3],
- (apm_bios_info.cseg_len - 1) & 0xffff);
+ (apm_info.bios.cseg_len - 1) & 0xffff);
_set_limit((char *)&gdt[APM_CS_16 >> 3],
- (apm_bios_info.cseg_16_len - 1) & 0xffff);
+ (apm_info.bios.cseg_16_len - 1) & 0xffff);
_set_limit((char *)&gdt[APM_DS >> 3],
- (apm_bios_info.dseg_len - 1) & 0xffff);
+ (apm_info.bios.dseg_len - 1) & 0xffff);
}
#endif
- create_proc_info_entry("apm", 0, NULL, apm_get_info);
+ apm_proc = create_proc_info_entry("apm", 0, NULL, apm_get_info);
+ if (apm_proc)
+ SET_MODULE_OWNER(apm_proc);
kernel_thread(apm, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
static void __exit apm_exit(void)
{
+ int error;
+
+ if (((apm_info.bios.flags & APM_BIOS_DISENGAGED) == 0)
+ && (apm_info.connection_version > 0x0100)) {
+ error = apm_engage_power_management(APM_DEVICE_ALL, 0);
+ if (error)
+ apm_error("disengage power management", error);
+ }
misc_deregister(&apm_device);
remove_proc_entry("apm", NULL);
#ifdef CONFIG_MAGIC_SYSRQ
EXPORT_SYMBOL(pm_idle);
EXPORT_SYMBOL(pm_power_off);
EXPORT_SYMBOL(get_cmos_time);
-EXPORT_SYMBOL(apm_bios_info);
+EXPORT_SYMBOL(apm_info);
EXPORT_SYMBOL(gdt);
EXPORT_SYMBOL_NOVERS(__down_failed);
*/
struct drive_info_struct { char dummy[32]; } drive_info;
struct screen_info screen_info;
-struct apm_bios_info apm_bios_info;
+struct apm_info apm_info;
struct sys_desc_table_struct {
unsigned short length;
unsigned char table[0];
ROOT_DEV = to_kdev_t(ORIG_ROOT_DEV);
drive_info = DRIVE_INFO;
screen_info = SCREEN_INFO;
- apm_bios_info = APM_BIOS_INFO;
+ apm_info.bios = APM_BIOS_INFO;
if( SYS_DESC_TABLE.length != 0 ) {
MCA_bus = SYS_DESC_TABLE.table[3] &0x2;
machine_id = SYS_DESC_TABLE.table[0];
# machines may also. Since BFD is incredibly buggy with respect to
# crossformat linking we rely on the elf2ecoff tool for format conversion.
#
+CFLAGS += -I $(TOPDIR)/include/asm $(CFLAGS)
CFLAGS += -mabi=64 -G 0 -mno-abicalls -fno-pic -Wa,--trap -pipe
LINKFLAGS += -G 0 -static # -N
MODFLAGS += -mlong-calls
@$(MAKEBOOT) clean
$(MAKE) -C arch/$(ARCH)/kernel clean
$(MAKE) -C arch/$(ARCH)/tools clean
- rm -f vmlinux.64 arch/($ARCH)/ld.script.elf32
+ rm -f vmlinux.64 arch/$(ARCH)/ld.script.elf32
archmrproper:
@$(MAKEBOOT) mrproper
interruptible_sleep_on(&acpi_thread_wait);
if (signal_pending(current))
break;
- do {
- run_task_queue(&acpi_thread_run);
- } while (acpi_thread_run);
+ run_task_queue(&acpi_thread_run);
}
/*
*/
-#define DAC960_DriverVersion "2.4.8"
-#define DAC960_DriverDate "19 August 2000"
+#define DAC960_DriverVersion "2.4.9"
+#define DAC960_DriverDate "7 September 2000"
#include <linux/version.h>
static void DAC960_WaitForCommand(DAC960_Controller_T *Controller)
{
- DECLARE_WAITQUEUE(WaitQueueEntry, current);
- add_wait_queue(&Controller->CommandWaitQueue, &WaitQueueEntry);
- current->state = TASK_UNINTERRUPTIBLE;
- spin_unlock(&io_request_lock);
- schedule();
- current->state = TASK_RUNNING;
- remove_wait_queue(&Controller->CommandWaitQueue, &WaitQueueEntry);
+ spin_unlock_irq(&io_request_lock);
+ __wait_event(Controller->CommandWaitQueue, Controller->FreeCommands);
spin_lock_irq(&io_request_lock);
}
}
Geometry.start =
Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)].start_sect;
- return copy_to_user(UserGeometry, &Geometry, sizeof(DiskGeometry_T));
+ return (copy_to_user(UserGeometry, &Geometry,
+ sizeof(DiskGeometry_T)) ? -EFAULT : 0);
case BLKGETSIZE:
/* Get Device Size. */
if ((long *) Argument == NULL) return -EINVAL;
ControllerInfo.PCI_Address = Controller->PCI_Address;
strcpy(ControllerInfo.ModelName, Controller->ModelName);
strcpy(ControllerInfo.FirmwareVersion, Controller->FirmwareVersion);
- return copy_to_user(UserSpaceControllerInfo, &ControllerInfo,
- sizeof(DAC960_ControllerInfo_T));
+ return (copy_to_user(UserSpaceControllerInfo, &ControllerInfo,
+ sizeof(DAC960_ControllerInfo_T)) ? -EFAULT : 0);
}
case DAC960_IOCTL_V1_EXECUTE_COMMAND:
{
unsigned char CommandBuffer[80];
int Length;
if (Count > sizeof(CommandBuffer)-1) return -EINVAL;
- copy_from_user(CommandBuffer, Buffer, Count);
+ if (copy_from_user(CommandBuffer, Buffer, Count)) return -EFAULT;
CommandBuffer[Count] = '\0';
Length = strlen(CommandBuffer);
if (CommandBuffer[Length-1] == '\n')
while (q->make_request_fn(q, rw, bh));
}
+
+/*
+ * Submit a buffer head for IO.
+ */
+void submit_bh(int rw, struct buffer_head * bh)
+{
+ if (!test_bit(BH_Lock, &bh->b_state))
+ BUG();
+
+ set_bit(BH_Req, &bh->b_state);
+
+ /*
+ * First step, 'identity mapping' - RAID or LVM might
+ * further remap this.
+ */
+ bh->b_rdev = bh->b_dev;
+ bh->b_rsector = bh->b_blocknr * (bh->b_size>>9);
+
+ generic_make_request(rw, bh);
+}
+
+/*
+ * Default IO end handler, used by "ll_rw_block()".
+ */
+static void end_buffer_io_sync(struct buffer_head *bh, int uptodate)
+{
+ mark_buffer_uptodate(bh, uptodate);
+ unlock_buffer(bh);
+}
+
/* This function can be used to request a number of buffers from a block
device. Currently the only restriction is that all buffers must belong to
the same device */
if (test_and_set_bit(BH_Lock, &bh->b_state))
continue;
- set_bit(BH_Req, &bh->b_state);
+ /* We have the buffer lock */
+ bh->b_end_io = end_buffer_io_sync;
switch(rw) {
case WRITE:
end_io:
bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state));
continue;
-
}
- /*
- * First step, 'identity mapping' - RAID or LVM might
- * further remap this.
- */
- bh->b_rdev = bh->b_dev;
- bh->b_rsector = bh->b_blocknr * (bh->b_size>>9);
-
- generic_make_request(rw, bh);
+ submit_bh(rw, bh);
}
return;
buffer_IO_error(bhs[i]);
}
-
#ifdef CONFIG_STRAM_SWAP
extern int stram_device_init (void);
#endif
* Make sure that the tty's task queue isn't activated.
*/
run_task_queue(&tq_timer);
- run_schedule_tasks();
+ flush_scheduled_tasks();
/*
* The release_mem function takes care of the details of clearing
pci_announce_device(struct pci_driver *drv, struct pci_dev *dev)
{
const struct pci_device_id *id;
+ int ret = 0;
if (drv->id_table) {
id = pci_match_device(drv->id_table, dev);
- if (!id)
- return 0;
+ if (!id) {
+ ret = 0;
+ goto out;
+ }
} else
id = NULL;
+
+ dev_probe_lock();
if (drv->probe(dev, id) >= 0) {
dev->driver = drv;
- return 1;
+ ret = 1;
}
- return 0;
+ dev_probe_unlock();
+out:
+ return ret;
}
int
if (!hotplug_path[0])
return;
- sprintf(class_id, "PCI_CLASS=%X", pdev->class);
- sprintf(id, "PCI_ID=%X/%X", pdev->vendor, pdev->device);
- sprintf(sub_id, "PCI_SUBSYS_ID=%X/%X", pdev->subsystem_vendor, pdev->subsystem_device);
+ sprintf(class_id, "PCI_CLASS=%04X", pdev->class);
+ sprintf(id, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device);
+ sprintf(sub_id, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, pdev->subsystem_device);
sprintf(bus_id, "PCI_SLOT_NAME=%s", pdev->slot_name);
i = 0;
static struct pci_bus * __init pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
{
struct pci_bus *child;
+ int i;
/*
* Allocate a new bus, and inherit stuff from the parent..
child->primary = parent->secondary;
child->subordinate = 0xff;
+ /* Set up default resource pointers.. */
+ for (i = 0; i < 4; i++)
+ child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
+
return child;
}
unsigned int cmax = pci_do_scan_bus(child);
if (cmax > max) max = cmax;
} else {
- int i;
unsigned int cmax = child->subordinate;
- for (i = 0; i < 4; i++)
- child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
if (cmax > max) max = cmax;
}
} else {
pci_read_config_word(dev, PCI_COMMAND, &cr);
pci_write_config_word(dev, PCI_COMMAND, 0x0000);
pci_write_config_word(dev, PCI_STATUS, 0xffff);
+
child = pci_add_new_bus(bus, dev, ++max);
buses = (buses & 0xff000000)
| ((unsigned int)(child->primary) << 0)
/* Now we can scan all subordinate buses... */
max = pci_do_scan_bus(child);
} else {
- int i;
/*
* For CardBus bridges, we leave 4 bus numbers
* as cards with a PCI-to-PCI bridge can be
* inserted later.
*/
max += 3;
- for (i = 0; i < 4; i++)
- child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
}
/*
* Set the subordinate bus number to its real value.
return 0;
}
+
+/* take care to suspend/resume bridges only once */
+
static int pci_pm_suspend_bus(struct pci_bus *bus)
{
struct list_head *list;
/* Walk the device children list */
list_for_each(list, &bus->devices)
pci_pm_suspend_device(pci_dev_b(list));
-
- /* Suspend the bus controller.. */
- pci_pm_suspend_device(bus->self);
return 0;
}
{
struct list_head *list;
- pci_pm_resume_device(bus->self);
-
/* Walk the device children list */
list_for_each(list, &bus->devices)
pci_pm_resume_device(pci_dev_b(list));
static int pci_pm_suspend(void)
{
struct list_head *list;
+ struct pci_bus *bus;
- list_for_each(list, &pci_root_buses)
- pci_pm_suspend_bus(pci_bus_b(list));
+ list_for_each(list, &pci_root_buses) {
+ bus = pci_bus_b(list);
+ pci_pm_suspend_bus(bus);
+ pci_pm_suspend_device(bus->self);
+ }
return 0;
}
static int pci_pm_resume(void)
{
struct list_head *list;
+ struct pci_bus *bus;
- list_for_each(list, &pci_root_buses)
- pci_pm_resume_bus(pci_bus_b(list));
+ list_for_each(list, &pci_root_buses) {
+ bus = pci_bus_b(list);
+ pci_pm_resume_device(bus->self);
+ pci_pm_resume_bus(bus);
+ }
return 0;
}
{SOUND_MIXER_PCM, 0x4343},
{SOUND_MIXER_SPEAKER, 0x4343},
{SOUND_MIXER_LINE, 0x4343},
- {SOUND_MIXER_MIC, 0x4343},
+ {SOUND_MIXER_MIC, 0x0000},
{SOUND_MIXER_CD, 0x4343},
{SOUND_MIXER_ALTPCM, 0x4343},
{SOUND_MIXER_IGAIN, 0x4343},
#define SNDCTL_DSP_CS_GETDBGMASK _SIOWR('P', 52, int)
#define SNDCTL_DSP_CS_SETDBGMASK _SIOWR('P', 53, int)
-void printioctl(unsigned int x)
+static void printioctl(unsigned int x)
{
unsigned int i;
unsigned char vidx;
#define SNDCTL_DSP_CS_GETDBGMASK _SIOWR('P', 52, int)
#define SNDCTL_DSP_CS_SETDBGMASK _SIOWR('P', 53, int)
-void printioctl(unsigned int x)
+static void printioctl(unsigned int x)
{
unsigned int i;
unsigned char vidx;
struct urb *urb; /* Interrupt polling pipe */
- char buffer[USB_MAXCHILDREN / 8];
-
+ char buffer[(USB_MAXCHILDREN + 1 + 7) / 8]; /* add 1 bit for hub status change */
+ /* and add 7 bits to round up to byte boundary */
int error;
int nerrors;
{ idVendor: 0x04a5, idProduct: 0x2022 },/* Vuego Scan Brisa 340U */
/* Agfa */
{ idVendor: 0x06bd, idProduct: 0x0001 }, /* SnapScan 1212U */
+ { idVendor: 0x06bd, idProduct: 0x0002 }, /* SnapScan 1236U */
{ idVendor: 0x06bd, idProduct: 0x2061 }, /* Another SnapScan 1212U (?)*/
{ idVendor: 0x06bd, idProduct: 0x0100 }, /* SnapScan Touch */
/* Colorado -- See Primax/Colorado below */
{ idVendor: 0x04b8, idProduct: 0x0101 },/* Perfection 636U and 636Photo */
{ idVendor: 0x04b8, idProduct: 0x0103 },/* Perfection 610 */
{ idVendor: 0x04b8, idProduct: 0x0104 },/* Perfection 1200U and 1200Photo*/
+ { idVendor: 0x04b8, idProduct: 0x0106 },/* Stylus Scan 2500 */
{ idVendor: 0x04b8, idProduct: 0x0107 },/* Expression 1600 */
/* Umax */
{ idVendor: 0x1606, idProduct: 0x0010 }, /* Astra 1220U */
- { idVendor: 0x1606, idProduct: 0x0002 }, /* Astra 1236U */
{ idVendor: 0x1606, idProduct: 0x0030 }, /* Astra 2000U */
{ idVendor: 0x1606, idProduct: 0x0230 }, /* Astra 2200U */
/* Visioneer */
bool ' USB Keyspan USA-18X Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA18X
bool ' USB Keyspan USA-19W Firmware' CONFIG_USB_SERIAL_KEYSPAN_USA19W
fi
+ dep_tristate ' USB MCT Single Port Serial Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_MCT_U232 $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
dep_tristate ' USB ZyXEL omni.net LCD Plus Driver (EXPERIMENTAL)' CONFIG_USB_SERIAL_OMNINET $CONFIG_USB_SERIAL $CONFIG_EXPERIMENTAL
fi
obj-$(CONFIG_USB_SERIAL_DIGI_ACCELEPORT) += digi_acceleport.o
obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o
obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o
+obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o
# Objects that export symbols.
export-objs := usbserial.o
and Keyspan, Inc the manufacturers of the Keyspan USB-serial products.
Thanks Guys :)
+ Thanks to Paulus for miscellaneous tidy ups, some largish chunks
+ of much nicer and/or completely new code and (perhaps most uniquely)
+ having the patience to sit down and explain why and where he'd changed
+ stuff.
+
Tip 'o the hat to Linuxcare for supporting staff in their work on
open source projects.
- (11/01/2000) Adam J. Richter
+ Change History
+ (11/01/2000) Adam J. Richter
usb_device_id table support.
+
+ Tue Oct 10 23:15:33 EST 2000 Hugh
+ Merged Paul's changes with my USA-49W mods. Work in progress
+ still...
+
+ Wed Jul 19 14:00:42 EST 2000 gkh
+ Added module_init and module_exit functions to handle the fact that
+ this driver is a loadable module now.
- (10/05/2000) gkh
- Fixed bug with urb->dev not being set properly, now that the usb
- core needs it.
-
- Wed Jul 19 14:00:42 EST 2000 gkh
- Added module_init and module_exit functions to handle the fact that this
- driver is a loadable module now.
-
- Tue Jul 18 16:14:52 EST 2000 Hugh
- Basic character input/output for USA-19 now mostly works,
- fixed at 9600 baud for the moment.
+ Tue Jul 18 16:14:52 EST 2000 Hugh
+ Basic character input/output for USA-19 now mostly works,
+ fixed at 9600 baud for the moment.
+ Sat Jul 8 11:11:48 EST 2000 Hugh
+ First public release - nothing works except the firmware upload.
+ Tested on PPC and x86 architectures, seems to behave...
*/
#include <linux/module.h>
#include <linux/spinlock.h>
-#ifdef CONFIG_USB_SERIAL_DEBUG
+#define DEBUG
+/* #ifdef CONFIG_USB_SERIAL_DEBUG */
#define DEBUG
-#else
- #undef DEBUG
-#endif
+/* #endif */
#include <linux/usb.h>
#include "usb-serial.h"
#include "keyspan.h"
+#define INSTAT_BUFLEN 32
+#define GLOCONT_BUFLEN 64
+
/* Per device and per port private data */
struct keyspan_serial_private {
- struct urb *in_urbs[8];
- struct urb *out_urbs[8];
- char out_buffer[64];
- char in_buffer[64];
+ /* number of active ports */
+ atomic_t active_count;
+
+ const keyspan_device_details *device_details;
+
+ urb_t *instat_urb;
+ char instat_buf[INSTAT_BUFLEN];
+
+ /* XXX this one probably will need a lock */
+ urb_t *glocont_urb;
+ char glocont_buf[GLOCONT_BUFLEN];
};
struct keyspan_port_private {
- /* Keep track of which output endpoint to use */
+ /* Keep track of which input & output endpoints to use */
+ int in_flip;
int out_flip;
- /* Settings for the port */
+ /* Keep duplicate of device details in each port
+ structure as well - simplifies some of the
+ callback functions etc. */
+ const keyspan_device_details *device_details;
+
+ /* Input endpoints and buffer for this port */
+ urb_t *in_urbs[2];
+ char in_buffer[2][64];
+ /* Output endpoints and buffer for this port */
+ urb_t *out_urbs[2];
+ char out_buffer[2][64];
+
+ /* Input ack endpoint */
+ urb_t *inack_urb;
+ char inack_buffer[1];
+
+ /* Output control endpoint */
+ urb_t *outcont_urb;
+ char outcont_buffer[64];
+
+ /* Settings for the port */
int baud;
int old_baud;
- enum {parity_none, parity_odd, parity_even} parity;
+ unsigned int cflag;
enum {flow_none, flow_cts, flow_xon} flow_control;
- int rts_state;
+ int rts_state; /* Handshaking pins (outputs) */
int dtr_state;
+ int cts_state; /* Handshaking pins (inputs) */
+ int dsr_state;
+ int dcd_state;
+ int ri_state;
+ unsigned long tx_start_time[2];
+ int resend_cont; /* need to resend control packet */
};
-
- /* FIXME this will break if multiple physical interfaces used */
-static wait_queue_head_t out_wait;
- /* Include Keyspan message headers (not both yet, need some tweaks
- to get clean build) */
-/*#include "keyspan_usa26msg.h"*/
+/* Include Keyspan message headers. All current Keyspan Adapters
+ make use of one of three message formats which are referred
+ to as USA-26, USA-28 and USA-49 by Keyspan and within this driver. */
+#include "keyspan_usa26msg.h"
#include "keyspan_usa28msg.h"
+#include "keyspan_usa49msg.h"
- /* If you don't get debugging output, uncomment the following
- two lines to enable cheat. */
-#undef dbg
-#define dbg printk
+/* If you don't get debugging output, uncomment the following
+ two lines to enable cheat. */
+#if 0
+ #undef dbg
+ #define dbg printk
+#endif
+
+static void keyspan_send_setup(struct usb_serial_port *port);
+
+/* Functions used by new usb-serial code. */
+int keyspan_init (void)
+{
+ usb_serial_register (&keyspan_usa18x_pre_device);
+ usb_serial_register (&keyspan_usa19_pre_device);
+ usb_serial_register (&keyspan_usa19w_pre_device);
+ usb_serial_register (&keyspan_usa28_pre_device);
+ usb_serial_register (&keyspan_usa28x_pre_device);
+ usb_serial_register (&keyspan_usa49w_pre_device);
+
+ usb_serial_register (&keyspan_usa18x_device);
+ usb_serial_register (&keyspan_usa19_device);
+ usb_serial_register (&keyspan_usa19w_device);
+ usb_serial_register (&keyspan_usa28_device);
+ usb_serial_register (&keyspan_usa28x_device);
+ usb_serial_register (&keyspan_usa49w_device);
+ return 0;
+}
+
+void keyspan_exit (void)
+{
+ usb_serial_deregister (&keyspan_usa18x_pre_device);
+ usb_serial_deregister (&keyspan_usa19_pre_device);
+ usb_serial_deregister (&keyspan_usa19w_pre_device);
+ usb_serial_deregister (&keyspan_usa28_pre_device);
+ usb_serial_deregister (&keyspan_usa28x_pre_device);
+ usb_serial_deregister (&keyspan_usa49w_pre_device);
+
+ usb_serial_deregister (&keyspan_usa18x_device);
+ usb_serial_deregister (&keyspan_usa19_device);
+ usb_serial_deregister (&keyspan_usa19w_device);
+ usb_serial_deregister (&keyspan_usa28_device);
+ usb_serial_deregister (&keyspan_usa28x_device);
+ usb_serial_deregister (&keyspan_usa49w_device);
+}
+
+module_init(keyspan_init);
+module_exit(keyspan_exit);
- /* Functions - mostly stubs for now */
static void keyspan_rx_throttle (struct usb_serial_port *port)
{
dbg("keyspan_rx_throttle port %d", port->number);
static void keyspan_set_termios (struct usb_serial_port *port,
struct termios *old_termios)
{
- dbg("keyspan_set_termios");
+ int baud_rate;
+ struct keyspan_port_private *p_priv;
+ const keyspan_device_details *d_details;
+ unsigned int cflag;
+
+ /* dbg(__FUNCTION__ "."); */
+
+ p_priv = (struct keyspan_port_private *)(port->private);
+ d_details = p_priv->device_details;
+ cflag = port->tty->termios->c_cflag;
+
+ /* Baud rate calculation takes baud rate as an integer
+ so other rates can be generated if desired. */
+ baud_rate = tty_get_baud_rate(port->tty);
+ /* If no match or invalid, don't change */
+ if (baud_rate >= 0
+ && d_details->calculate_baud_rate(baud_rate, d_details->baudclk,
+ NULL, NULL, NULL) == KEYSPAN_BAUD_RATE_OK) {
+ /* FIXME - more to do here to ensure rate changes cleanly */
+ p_priv->baud = baud_rate;
+ }
+
+ /* set CTS/RTS handshake etc. */
+ p_priv->cflag = cflag;
+ p_priv->flow_control = (cflag & CRTSCTS)? flow_cts: flow_none;
+
+ keyspan_send_setup(port);
}
static int keyspan_ioctl(struct usb_serial_port *port, struct file *file,
unsigned int cmd, unsigned long arg)
{
- unsigned int value;
+ unsigned int value, set;
+ struct keyspan_port_private *p_priv;
- dbg("keyspan_ioctl_info");
+ p_priv = (struct keyspan_port_private *)(port->private);
switch (cmd) {
case TIOCMGET:
- value = TIOCM_DTR | TIOCM_RNG;
- if (copy_to_user((unsigned int *)arg, &value, sizeof(int))) {
+ value = ((p_priv->rts_state) ? TIOCM_RTS : 0) |
+ ((p_priv->dtr_state) ? TIOCM_DTR : 0) |
+ ((p_priv->cts_state) ? TIOCM_CTS : 0) |
+ ((p_priv->dsr_state) ? TIOCM_DSR : 0) |
+ ((p_priv->dcd_state) ? TIOCM_CAR : 0) |
+ ((p_priv->ri_state) ? TIOCM_RNG : 0);
+
+ if (put_user(value, (unsigned int *) arg))
return -EFAULT;
- }
- else {
- return 0;
- }
-
- default:
- return -ENOIOCTLCMD;
+ return 0;
+
+ case TIOCMSET:
+ if (get_user(value, (unsigned int *) arg))
+ return -EFAULT;
+ p_priv->rts_state = ((value & TIOCM_RTS) ? 1 : 0);
+ p_priv->dtr_state = ((value & TIOCM_DTR) ? 1 : 0);
+ keyspan_send_setup(port);
+ return 0;
+
+ case TIOCMBIS:
+ case TIOCMBIC:
+ if (get_user(value, (unsigned int *) arg))
+ return -EFAULT;
+ set = (cmd == TIOCMBIS);
+ if (value & TIOCM_RTS)
+ p_priv->rts_state = set;
+ if (value & TIOCM_DTR)
+ p_priv->dtr_state = set;
+ keyspan_send_setup(port);
+ return 0;
}
return -ENOIOCTLCMD;
}
+ /* Write function is generic for the three protocols used
+ with only a minor change for usa49 required */
static int keyspan_write(struct usb_serial_port *port, int from_user,
- const unsigned char *buf, int count)
+ const unsigned char *buf, int count)
{
- struct usb_serial *serial = port->serial;
- struct keyspan_serial_private *s_priv;
struct keyspan_port_private *p_priv;
- int current_urb;
- int i;
+ const keyspan_device_details *d_details;
+ int flip;
+ int left, todo;
+ urb_t *this_urb;
+ int err;
- s_priv = (struct keyspan_serial_private *)(serial->private);
p_priv = (struct keyspan_port_private *)(port->private);
-
- if (p_priv->out_flip == 0) {
- current_urb = 0;
- p_priv->out_flip = 1;
- }
- else {
- current_urb = 1;
- p_priv->out_flip = 0;
- }
+ d_details = p_priv->device_details;
- dbg("keyspan_write called for port %d (%d) chars {", port->number, count);
- for (i = 0; i < count ; i++) {
- dbg("%02x ", buf[i]);
- }
- dbg("}\n");
+#if 0
+ dbg(__FUNCTION__ " for port %d (%d chars [%x]), flip=%d",
+ port->number, count, buf[0], p_priv->out_flip);
+#endif
- if (count == 0) {
- dbg("write request of 0 bytes");
- return (0);
- }
+ for (left = count; left > 0; left -= todo) {
+ todo = left;
+ if (todo > 63)
+ todo = 63;
- /* only send data if we have a bulk out endpoint */
- if (s_priv->out_urbs[current_urb]) {
- while (s_priv->out_urbs[current_urb]->status == -EINPROGRESS) {
- dbg (__FUNCTION__ " INPROGRES\n");
- interruptible_sleep_on(&out_wait);
- if (signal_pending(current)) {
- dbg (__FUNCTION__ " signal\n");
- return (-ERESTARTSYS);
- }
+ flip = p_priv->out_flip;
+
+ /* Check we have a valid urb/endpoint before we use it... */
+ if ((this_urb = p_priv->out_urbs[flip]) == 0) {
+ /* no bulk out, so return 0 bytes written */
+ dbg(__FUNCTION__ " no output urb :(");
+ return count;
+ }
+
+ if (this_urb->status == -EINPROGRESS) {
+ if (this_urb->transfer_flags & USB_ASYNC_UNLINK)
+ break;
+ if (jiffies - p_priv->tx_start_time[flip] < 10 * HZ)
+ break;
+ this_urb->transfer_flags |= USB_ASYNC_UNLINK;
+ usb_unlink_urb(this_urb);
+ break;
}
- /*if (s_priv->out_urbs[current_urb]->status == -EINPROGRESS) {
- dbg ("already writing");
- return (-EAGAIN);
- }*/
- /* First byte in buffer is "last flag" - unused so
- for now so set to zero */
- memset(s_priv->out_urbs[current_urb]->transfer_buffer, 0, 1);
+
+ /* First byte in buffer is "last flag" - unused so
+ for now so set to zero */
+ ((char *)this_urb->transfer_buffer)[0] = 0;
if (from_user) {
- copy_from_user(s_priv->out_urbs[current_urb]->transfer_buffer + 1, buf, count);
+ copy_from_user(this_urb->transfer_buffer + 1, buf, todo);
+ } else {
+ memcpy (this_urb->transfer_buffer + 1, buf, todo);
}
- else {
- memcpy (s_priv->out_urbs[current_urb]->transfer_buffer + 1, buf, count);
- }
+ buf += todo;
/* send the data out the bulk port */
- s_priv->out_urbs[current_urb]->transfer_buffer_length = count + 1;
- s_priv->out_urbs[current_urb]->dev = serial->dev;
+ this_urb->transfer_buffer_length = todo + 1;
- if (usb_submit_urb(s_priv->out_urbs[current_urb])) {
- dbg("usb_submit_urb(write bulk) failed");
+ this_urb->transfer_flags &= ~USB_ASYNC_UNLINK;
+ this_urb->dev = port->serial->dev;
+ if ((err = usb_submit_urb(this_urb)) != 0) {
+ dbg("usb_submit_urb(write bulk) failed (%d)", err);
}
+ p_priv->tx_start_time[flip] = jiffies;
- return (count);
+ /* Flip for next time if usa26 or usa28 interface
+ (not used on usa49) */
+ p_priv->out_flip = (flip + 1) & d_details->outdat_endp_flip;
}
-
- /* no bulk out, so return 0 bytes written */
- return (0);
-}
+ return count - left;
+}
-static void keyspan_write_bulk_callback (struct urb *urb)
+static void usa26_indat_callback(struct urb *urb)
{
- int endpoint;
-
+ int i, err;
+ int endpoint;
+ struct usb_serial_port *port;
+ struct tty_struct *tty;
+ unsigned char *data = urb->transfer_buffer;
+
+ /* dbg (__FUNCTION__); */
+
endpoint = usb_pipeendpoint(urb->pipe);
- dbg("keyspan_write_bulk_callback for endpoint %d\n", endpoint);
+ if (urb->status) {
+ dbg(__FUNCTION__ "nonzero status: %x on endpoint %d.",
+ urb->status, endpoint);
+ return;
+ }
+
+ port = (struct usb_serial_port *) urb->context;
+ tty = port->tty;
+ if (urb->actual_length) {
+ if (data[0] == 0) {
+ /* no error on any byte */
+ for (i = 1; i < urb->actual_length ; ++i) {
+ tty_insert_flip_char(tty, data[i], 0);
+ }
+ } else {
+ /* some bytes had errors, every byte has status */
+ for (i = 0; i + 1 < urb->actual_length; i += 2) {
+ int stat = data[i], flag = 0;
+ if (stat & RXERROR_OVERRUN)
+ flag |= TTY_OVERRUN;
+ if (stat & RXERROR_FRAMING)
+ flag |= TTY_FRAME;
+ if (stat & RXERROR_PARITY)
+ flag |= TTY_PARITY;
+ /* XXX should handle break (0x10) */
+ tty_insert_flip_char(tty, data[i+1], flag);
+ }
+ }
+ tty_flip_buffer_push(tty);
+ }
+
+ /* Resubmit urb so we continue receiving */
+ urb->dev = port->serial->dev;
+ if ((err = usb_submit_urb(urb)) != 0) {
+ dbg(__FUNCTION__ "resubmit read urb failed. (%d)", err);
+ }
+ return;
+}
- /* Only do wakeup if this callback is from one of the data
- endpoints. */
- if (endpoint == 2 || endpoint == 3) {
- wake_up_interruptible(&out_wait);
+ /* Outdat handling is common for usa26, usa28 and usa49 messages */
+static void usa2x_outdat_callback(struct urb *urb)
+{
+ struct usb_serial_port *port;
+ struct keyspan_port_private *p_priv;
+
+ port = (struct usb_serial_port *) urb->context;
+ p_priv = (struct keyspan_port_private *)(port->private);
+ /* dbg (__FUNCTION__ " urb %d", urb == p_priv->out_urbs[1]); */
+
+ if (port->active) {
+ queue_task(&port->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
}
+}
+static void usa26_inack_callback(struct urb *urb)
+{
+ dbg (__FUNCTION__);
+
}
+static void usa26_outcont_callback(struct urb *urb)
+{
+ struct usb_serial_port *port;
+ struct keyspan_port_private *p_priv;
-static void keyspan_read_bulk_callback (struct urb *urb)
+ port = (struct usb_serial_port *) urb->context;
+ p_priv = (struct keyspan_port_private *)(port->private);
+
+ if (p_priv->resend_cont) {
+ /* dbg (__FUNCTION__ " sending setup"); */
+ keyspan_usa26_send_setup(port->serial, port);
+ }
+}
+
+static void usa26_instat_callback(struct urb *urb)
{
- struct usb_serial *serial = (struct usb_serial *)urb->context;
- struct usb_serial_port *port;
- int i;
- int endpoint;
- struct tty_struct *tty;
- unsigned char *data = urb->transfer_buffer;
+ unsigned char *data = urb->transfer_buffer;
+ keyspan_usa26_portStatusMessage *msg;
+ struct usb_serial *serial;
+ struct usb_serial_port *port;
+ struct keyspan_port_private *p_priv;
+ int old_dcd_state, err;
- if (serial_paranoia_check (serial, __FUNCTION__))
+ serial = (struct usb_serial *) urb->context;
+
+ if (urb->status) {
+ dbg(__FUNCTION__ " nonzero status: %x", urb->status);
return;
- port = &serial->port[0];
- if (port_paranoia_check (port, __FUNCTION__))
+ }
+ if (urb->actual_length != 9) {
+ dbg(__FUNCTION__ " %d byte report??", urb->actual_length);
+ goto exit;
+ }
+
+ msg = (keyspan_usa26_portStatusMessage *)data;
+
+#if 0
+ dbg(__FUNCTION__ " port status: port %d cts %d dcd %d dsr %d ri %d toff %d txoff %d rxen %d cr %d",
+ msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr, msg->ri, msg->_txOff,
+ msg->_txXoff, msg->rxEnabled, msg->controlResponse);
+#endif
+
+ /* Now do something useful with the data */
+
+
+ /* Check port number from message and retrieve private data */
+ if (msg->port >= serial->num_ports) {
+ dbg ("Unexpected port number %d", msg->port);
+ goto exit;
+ }
+ port = &serial->port[msg->port];
+ p_priv = (struct keyspan_port_private *)(port->private);
+
+ /* Update handshaking pin state information */
+ old_dcd_state = p_priv->dcd_state;
+ p_priv->cts_state = ((msg->hskia_cts) ? 1 : 0);
+ p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
+ p_priv->dcd_state = ((msg->gpia_dcd) ? 1 : 0);
+ p_priv->ri_state = ((msg->ri) ? 1 : 0);
+
+ if (port->tty && !C_CLOCAL(port->tty)
+ && old_dcd_state != p_priv->dcd_state) {
+ if (old_dcd_state)
+ tty_hangup(port->tty);
+ /* else */
+ /* wake_up_interruptible(&p_priv->open_wait); */
+ }
+
+exit:
+ /* Resubmit urb so we continue receiving */
+ urb->dev = serial->dev;
+ if ((err = usb_submit_urb(urb)) != 0) {
+ dbg(__FUNCTION__ "resubmit read urb failed. (%d)", err);
+ }
+}
+
+static void usa26_glocont_callback(struct urb *urb)
+{
+ dbg (__FUNCTION__);
+
+}
+
+
+static void usa28_indat_callback(struct urb *urb)
+{
+ int i, err;
+ struct usb_serial_port *port;
+ struct tty_struct *tty;
+ unsigned char *data;
+ struct keyspan_port_private *p_priv;
+
+ /* dbg (__FUNCTION__); */
+
+ port = (struct usb_serial_port *) urb->context;
+ p_priv = (struct keyspan_port_private *)(port->private);
+ data = urb->transfer_buffer;
+
+ if (urb != p_priv->in_urbs[p_priv->in_flip])
return;
+ do {
+ if (urb->status) {
+ dbg(__FUNCTION__ "nonzero status: %x on endpoint
+%d.",
+ urb->status, usb_pipeendpoint(urb->pipe));
+ return;
+ }
+
+ port = (struct usb_serial_port *) urb->context;
+ p_priv = (struct keyspan_port_private *)(port->private);
+ data = urb->transfer_buffer;
+
+ tty = port->tty;
+ if (urb->actual_length) {
+ for (i = 0; i < urb->actual_length ; ++i) {
+ tty_insert_flip_char(tty, data[i], 0);
+ }
+ tty_flip_buffer_push(tty);
+ }
+
+ /* Resubmit urb so we continue receiving */
+ urb->dev = port->serial->dev;
+ if ((err = usb_submit_urb(urb)) != 0) {
+ dbg(__FUNCTION__ "resubmit read urb failed. (%d)",
+err);
+ }
+ p_priv->in_flip ^= 1;
+
+ urb = p_priv->in_urbs[p_priv->in_flip];
+ } while (urb->status != -EINPROGRESS);
+}
+
+static void usa28_inack_callback(struct urb *urb)
+{
+ dbg (__FUNCTION__);
+}
+
+static void usa28_outcont_callback(struct urb *urb)
+{
+ struct usb_serial_port *port;
+ struct keyspan_port_private *p_priv;
+
+ port = (struct usb_serial_port *) urb->context;
+ p_priv = (struct keyspan_port_private *)(port->private);
+
+ if (p_priv->resend_cont) {
+ dbg (__FUNCTION__ " sending setup");
+ keyspan_usa28_send_setup(port->serial, port);
+ }
+}
+
+static void usa28_instat_callback(struct urb *urb)
+{
+ int err;
+ unsigned char *data = urb->transfer_buffer;
+ keyspan_usa28_portStatusMessage *msg;
+ struct usb_serial *serial;
+ struct usb_serial_port *port;
+ struct keyspan_port_private *p_priv;
+ int old_dcd_state;
+
+ serial = (struct usb_serial *) urb->context;
+
if (urb->status) {
- dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
+ dbg(__FUNCTION__ " nonzero status: %x", urb->status);
return;
}
- usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+ if (urb->actual_length != sizeof(struct keyspan_usa28_portStatusMessage)) {
+ dbg(__FUNCTION__ " bad length %d", urb->actual_length);
+ goto exit;
+ }
- endpoint = usb_pipeendpoint(urb->pipe);
+ /*dbg(__FUNCTION__ " %x %x %x %x %x %x %x %x %x %x %x %x",
+ data[0], data[1], data[2], data[3], data[4], data[5],
+ data[6], data[7], data[8], data[9], data[10], data[11]);*/
+
+ /* Now do something useful with the data */
+ msg = (keyspan_usa28_portStatusMessage *)data;
+
+
+ /* Check port number from message and retrieve private data */
+ if (msg->port >= serial->num_ports) {
+ dbg ("Unexpected port number %d", msg->port);
+ goto exit;
+ }
+ port = &serial->port[msg->port];
+ p_priv = (struct keyspan_port_private *)(port->private);
+
+ /* Update handshaking pin state information */
+ old_dcd_state = p_priv->dcd_state;
+ p_priv->cts_state = ((msg->cts) ? 1 : 0);
+ p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
+ p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
+ p_priv->ri_state = ((msg->ri) ? 1 : 0);
+
+ if (port->tty && !C_CLOCAL(port->tty)
+ && old_dcd_state != p_priv->dcd_state) {
+ if (old_dcd_state)
+ tty_hangup(port->tty);
+ /* else */
+ /* wake_up_interruptible(&p_priv->open_wait); */
+ }
+
+exit:
+ /* Resubmit urb so we continue receiving */
+ urb->dev = serial->dev;
+ if ((err = usb_submit_urb(urb)) != 0) {
+ dbg(__FUNCTION__ "resubmit read urb failed. (%d)", err);
+ }
+}
+
+static void usa28_glocont_callback(struct urb *urb)
+{
+ dbg (__FUNCTION__);
+}
+
+
+static void usa49_glocont_callback(struct urb *urb)
+{
+ struct usb_serial *serial;
+ struct usb_serial_port *port;
+ struct keyspan_port_private *p_priv;
+ int i;
+
+ /* dbg (__FUNCTION__); */
+ serial = (struct usb_serial *) urb->context;
+ for (i = 0; i < serial->num_ports; ++i) {
+ port = &serial->port[i];
+ p_priv = (struct keyspan_port_private *)(port->private);
+
+ if (p_priv->resend_cont) {
+ /* dbg (__FUNCTION__ " sending setup"); */
+ keyspan_usa49_send_setup(serial, port);
+ break;
+ }
+ }
+}
+
+ /* This is actually called glostat in the Keyspan
+ doco */
+static void usa49_instat_callback(struct urb *urb)
+{
+ int err;
+ unsigned char *data = urb->transfer_buffer;
+ keyspan_usa49_portStatusMessage *msg;
+ struct usb_serial *serial;
+ struct usb_serial_port *port;
+ struct keyspan_port_private *p_priv;
+ int old_dcd_state;
+
+ /* dbg (__FUNCTION__); */
+
+ serial = (struct usb_serial *) urb->context;
if (urb->status) {
- dbg(__FUNCTION__ "nonzero status: %x on endpoint %d.\n",
- urb->status, endpoint);
+ dbg(__FUNCTION__ " nonzero status: %x", urb->status);
return;
}
- switch (endpoint) {
+ if (urb->actual_length != sizeof(struct keyspan_usa49_portStatusMessage)) {
+ dbg(__FUNCTION__ " bad length %d", urb->actual_length);
+ goto exit;
+ }
- /* If this is one of the data endpoints, stuff it's
- contents into the tty flip_buffer. */
- case 1:
- case 2:
- tty = port->tty;
- if (urb->actual_length) {
- for (i = 0; i < urb->actual_length ; ++i) {
- tty_insert_flip_char(tty, data[i], 0);
- }
- tty_flip_buffer_push(tty);
- }
- break;
+ /*dbg(__FUNCTION__ " %x %x %x %x %x %x %x %x %x %x %x",
+ data[0], data[1], data[2], data[3], data[4], data[5],
+ data[6], data[7], data[8], data[9], data[10]);*/
+
+ /* Now do something useful with the data */
+ msg = (keyspan_usa49_portStatusMessage *)data;
- /* INACK endpoint */
- case 3: dbg(__FUNCTION__ " callback for INACK endpoint\n");
- break;
+ /* Check port number from message and retrieve private data */
+ if (msg->portNumber >= serial->num_ports) {
+ dbg ("Unexpected port number %d", msg->portNumber);
+ goto exit;
+ }
+ port = &serial->port[msg->portNumber];
+ p_priv = (struct keyspan_port_private *)(port->private);
+
+ /* Update handshaking pin state information */
+ old_dcd_state = p_priv->dcd_state;
+ p_priv->cts_state = ((msg->cts) ? 1 : 0);
+ p_priv->dsr_state = ((msg->dsr) ? 1 : 0);
+ p_priv->dcd_state = ((msg->dcd) ? 1 : 0);
+ p_priv->ri_state = ((msg->ri) ? 1 : 0);
+
+ if (port->tty && !C_CLOCAL(port->tty)
+ && old_dcd_state != p_priv->dcd_state) {
+ if (old_dcd_state)
+ tty_hangup(port->tty);
+ /* else */
+ /* wake_up_interruptible(&p_priv->open_wait); */
+ }
- /* INSTAT endpoint */
- case 4: dbg(__FUNCTION__ " callback for INSTAT endpoint\n");
- break;
-
- default:
- dbg(__FUNCTION__ " callback for unknown endpoint!\n");
- break;
+exit:
+ /* Resubmit urb so we continue receiving */
+ urb->dev = serial->dev;
+
+ if ((err = usb_submit_urb(urb)) != 0) {
+ dbg(__FUNCTION__ "resubmit read urb failed. (%d)", err);
+ }
+}
+
+static void usa49_inack_callback(struct urb *urb)
+{
+ dbg (__FUNCTION__);
+}
+
+static void usa49_indat_callback(struct urb *urb)
+{
+ int i, err;
+ int endpoint;
+ struct usb_serial_port *port;
+ struct tty_struct *tty;
+ unsigned char *data = urb->transfer_buffer;
+
+ /* dbg (__FUNCTION__); */
+
+ endpoint = usb_pipeendpoint(urb->pipe);
+
+ if (urb->status) {
+ dbg(__FUNCTION__ "nonzero status: %x on endpoint %d.",
+ urb->status, endpoint);
+ return;
+ }
+
+ port = (struct usb_serial_port *) urb->context;
+ tty = port->tty;
+ if (urb->actual_length) {
+ if (data[0] == 0) {
+ /* no error on any byte */
+ for (i = 1; i < urb->actual_length ; ++i) {
+ tty_insert_flip_char(tty, data[i], 0);
+ }
+ } else {
+ /* some bytes had errors, every byte has status */
+ for (i = 0; i + 1 < urb->actual_length; i += 2) {
+ int stat = data[i], flag = 0;
+ if (stat & RXERROR_OVERRUN)
+ flag |= TTY_OVERRUN;
+ if (stat & RXERROR_FRAMING)
+ flag |= TTY_FRAME;
+ if (stat & RXERROR_PARITY)
+ flag |= TTY_PARITY;
+ /* XXX should handle break (0x10) */
+ tty_insert_flip_char(tty, data[i+1], flag);
+ }
+ }
+ tty_flip_buffer_push(tty);
}
- /* Resubmit urb so we continue receiving */
- urb->dev = serial->dev;
- if (usb_submit_urb(urb)) {
- dbg(__FUNCTION__ "resubmit read urb failed.\n");
+ /* Resubmit urb so we continue receiving */
+ urb->dev = port->serial->dev;
+ if ((err = usb_submit_urb(urb)) != 0) {
+ dbg(__FUNCTION__ "resubmit read urb failed. (%d)", err);
}
- return;
-
}
+/* not used, usa-49 doesn't have per-port control endpoints */
+static void usa49_outcont_callback(struct urb *urb)
+{
+ dbg (__FUNCTION__);
+}
+
+
+
static int keyspan_write_room (struct usb_serial_port *port)
{
-// dbg("keyspan_write_room called\n");
+// dbg("keyspan_write_room called");
return (32);
}
struct keyspan_port_private *p_priv;
struct keyspan_serial_private *s_priv;
struct usb_serial *serial = port->serial;
- int i;
-
- s_priv = (struct keyspan_serial_private *)(serial->private);
- p_priv = (struct keyspan_port_private *)(port->private);
-
- dbg("keyspan_open called.\n");
-
- if (port->active) {
- dbg(__FUNCTION__ "port->active already true!\n");
- return (-EINVAL);
- }
+ const keyspan_device_details *d_details;
+ int i, already_active, err;
+ unsigned long flags;
+ urb_t *urb;
+ s_priv = (struct keyspan_serial_private *)(serial->private);
p_priv = (struct keyspan_port_private *)(port->private);
+ d_details = s_priv->device_details;
- p_priv->out_flip = 0;
+ /* dbg("keyspan_open called."); */
+ MOD_INC_USE_COUNT;
+
+ spin_lock_irqsave (&port->port_lock, flags);
+ ++port->open_count;
+ already_active = port->active;
port->active = 1;
+ spin_unlock_irqrestore (&port->port_lock, flags);
- /* Start reading from port */
- for (i = 0; i < 4; i++) {
- if (s_priv->in_urbs[i]) {
- s_priv->in_urbs[i]->dev = serial->dev;
- if (usb_submit_urb(s_priv->in_urbs[i])) {
- dbg(__FUNCTION__ " submit in urb %d failed", i);
- }
- }
+ if (already_active)
+ return 0;
+ p_priv = (struct keyspan_port_private *)(port->private);
+
+ /* Set some sane defaults */
+ p_priv->baud = 9600;
+ p_priv->cflag = CREAD | CLOCAL;
+ p_priv->flow_control = flow_none;
+ p_priv->rts_state = 1;
+ p_priv->dtr_state = 1;
+
+ /* Start reading from endpoints */
+ for (i = 0; i < 2; i++) {
+ if ((urb = p_priv->in_urbs[i]) == NULL)
+ continue;
+ urb->dev = serial->dev;
+ if ((err = usb_submit_urb(urb)) != 0) {
+ dbg(__FUNCTION__ " submit urb %d failed (%d)", i, err);
+ }
}
-
- keyspan_usa19_send_setup(serial, port);
+/* Now done in startup routine
+ if (atomic_inc_return(&s_priv->active_count) == 1) {
+ s_priv->instat_urb->dev = serial->dev;
+ if ((err = usb_submit_urb(s_priv->instat_urb)) != 0) {
+ dbg(__FUNCTION__ " submit instat urb failed %d", err);
+ }
+ }
+*/
+
+ keyspan_send_setup(port);
return (0);
}
+static inline void stop_urb(urb_t *urb)
+{
+ if (urb && urb->status == -EINPROGRESS) {
+ urb->transfer_flags &= ~USB_ASYNC_UNLINK;
+ usb_unlink_urb(urb);
+ }
+}
static void keyspan_close(struct usb_serial_port *port, struct file *filp)
{
int i;
struct usb_serial *serial = port->serial; /* FIXME should so sanity check */
struct keyspan_serial_private *s_priv;
+ struct keyspan_port_private *p_priv;
+ unsigned long flags;
+ /* dbg("keyspan_close called"); */
s_priv = (struct keyspan_serial_private *)(serial->private);
-
- /* Stop reading/writing urbs */
- for (i = 0; i < 4; i++) {
- if (s_priv->in_urbs[i]) {
- usb_unlink_urb(s_priv->in_urbs[i]);
- }
+ p_priv = (struct keyspan_port_private *)(port->private);
- }
- for (i = 0; i < 3; i++) {
- if (s_priv->out_urbs[i]) {
- usb_unlink_urb(s_priv->out_urbs[i]);
- }
+ spin_lock_irqsave (&port->port_lock, flags);
+ if (--port->open_count <= 0) {
+ if (port->active) {
+ /* Stop reading/writing urbs */
+ stop_urb(p_priv->inack_urb);
+ stop_urb(p_priv->outcont_urb);
+ for (i = 0; i < 2; i++) {
+ stop_urb(p_priv->in_urbs[i]);
+ stop_urb(p_priv->out_urbs[i]);
+ }
+ /* Now done in shutdown
+ if (atomic_dec_return(&s_priv->active_count) <= 0) {
+ stop_urb(s_priv->instat_urb);
+ stop_urb(s_priv->glocont_urb);
+ } */
+ }
+ port->active = 0;
+ port->open_count = 0;
+ port->tty = 0;
}
- port->active = 0;
- dbg("keyspan_close called\n");
+ spin_unlock_irqrestore (&port->port_lock, flags);
+
+ MOD_DEC_USE_COUNT;
}
const struct ezusb_hex_record *record;
char *fw_name;
- dbg("Keyspan startup version %04x product %04x\n", serial->dev->descriptor.bcdDevice,
- serial->dev->descriptor.idProduct);
+ dbg("Keyspan startup version %04x product %04x",
+ serial->dev->descriptor.bcdDevice,
+ serial->dev->descriptor.idProduct);
if ((serial->dev->descriptor.bcdDevice & 0x8000) != 0x8000) {
- dbg("Firmware already loaded. Quitting.\n");
+ dbg("Firmware already loaded. Quitting.");
return(1);
}
/* Select firmware image on the basis of idProduct */
switch (serial->dev->descriptor.idProduct) {
- case 0x0101: record = &keyspan_usa28_firmware[0];
- fw_name = "USA28";
- break;
+ case 0x0101:
+ record = &keyspan_usa28_firmware[0];
+ fw_name = "USA28";
+ break;
+
+ case 0x0102:
+ record = &keyspan_usa28x_firmware[0];
+ fw_name = "USA28X";
+ break;
+
+ case 0x0103:
+ record = &keyspan_usa19_firmware[0];
+ fw_name = "USA19";
+ break;
- case 0x0102: record = &keyspan_usa28x_firmware[0];
- fw_name = "USA28X";
- break;
-
- case 0x0103: record = &keyspan_usa19_firmware[0];
- fw_name = "USA19";
- break;
-
- case 0x0105: record = &keyspan_usa18x_firmware[0];
- fw_name = "USA18X";
- break;
+ case 0x0105:
+ record = &keyspan_usa18x_firmware[0];
+ fw_name = "USA18X";
+ break;
- case 0x0106: record = &keyspan_usa19w_firmware[0];
- fw_name = "USA19W";
- break;
+ case 0x0106:
+ record = &keyspan_usa19w_firmware[0];
+ fw_name = "USA19W";
+ break;
- default: record = NULL;
- fw_name = "Unknown";
- break;
+ case 0x0109:
+ record = &keyspan_usa49w_firmware[0];
+ fw_name = "USA49W";
+ break;
+
+ default:
+ record = NULL;
+ fw_name = "Unknown";
+ break;
}
if (record == NULL) {
- err("Required keyspan firmware image (%s) unavailable.\n", fw_name);
+ err("Required keyspan firmware image (%s) unavailable.", fw_name);
return(1);
}
- dbg("Uploading Keyspan %s firmware.\n", fw_name);
+ dbg("Uploading Keyspan %s firmware.", fw_name);
/* download the firmware image */
response = ezusb_set_reset(serial, 1);
moment and the new device will bind to the real driver */
response = ezusb_set_reset(serial, 0);
- /* we don't want this device to have a driver assigned to it. */
+ /* we don't want this device to have a driver assigned to it. */
return (1);
}
- /* USA-19 uses three output endpoints and four input
- endpoints. First two output endpoints are for
- data (used in an alternating fashion), the third is
- output control. First two input endpoints are for
- data (again alternating), the third is the ACK
- endpoint, the fourth is input status. */
-static void keyspan_usa19_setup_urbs(struct usb_serial *serial)
+/* Helper functions used by keyspan_setup_urbs */
+static urb_t *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
+ int dir, void *ctx, char *buf, int len,
+ void (*callback)(urb_t *))
{
- struct keyspan_serial_private *s_priv;
- int i;
+ urb_t *urb;
- s_priv = (struct keyspan_serial_private *)(serial->private);
+ if (endpoint == -1)
+ return NULL; /* endpoint not needed */
+
+ /* dbg (__FUNCTION__ " alloc for endpoint %d.", endpoint); */
+ urb = usb_alloc_urb(0); /* No ISO */
+ if (urb == NULL) {
+ dbg (__FUNCTION__ " alloc for endpoint %d failed.", endpoint);
+ return NULL;
+ }
- /* Output urbs first */
- dbg(__FUNCTION__ "Allocating output urbs.\n");
- for (i = 0; i < 3; i++) {
+ /* Fill URB using supplied data. */
+ FILL_BULK_URB(urb, serial->dev,
+ usb_sndbulkpipe(serial->dev, endpoint) | dir,
+ buf, len, callback, ctx);
- s_priv->out_urbs[i] = usb_alloc_urb (0); /* No ISO */
- if (!s_priv->out_urbs[i]) {
- dbg (__FUNCTION__ "Alloc for %d out urb failed.\n", i);
- return;
- }
+ return urb;
+}
- FILL_BULK_URB(s_priv->out_urbs[i], serial->dev,
- usb_sndbulkpipe(serial->dev, i + 1),
- &s_priv->out_buffer[i], sizeof(s_priv->out_buffer[i]),
- keyspan_write_bulk_callback,
- serial);
+struct callbacks {
+ void (*instat_callback)(urb_t *);
+ void (*glocont_callback)(urb_t *);
+ void (*indat_callback)(urb_t *);
+ void (*outdat_callback)(urb_t *);
+ void (*inack_callback)(urb_t *);
+ void (*outcont_callback)(urb_t *);
+} keyspan_callbacks[] = {
+ {
+ /* msg_usa26 callbacks */
+ instat_callback: usa26_instat_callback,
+ glocont_callback: usa26_glocont_callback,
+ indat_callback: usa26_indat_callback,
+ outdat_callback: usa2x_outdat_callback,
+ inack_callback: usa26_inack_callback,
+ outcont_callback: usa26_outcont_callback,
+ }, {
+ /* msg_usa28 callbacks */
+ instat_callback: usa28_instat_callback,
+ glocont_callback: usa28_glocont_callback,
+ indat_callback: usa28_indat_callback,
+ outdat_callback: usa2x_outdat_callback,
+ inack_callback: usa28_inack_callback,
+ outcont_callback: usa28_outcont_callback,
+ }, {
+ /* msg_usa49 callbacks */
+ instat_callback: usa49_instat_callback,
+ glocont_callback: usa49_glocont_callback,
+ indat_callback: usa49_indat_callback,
+ outdat_callback: usa2x_outdat_callback,
+ inack_callback: usa49_inack_callback,
+ outcont_callback: usa49_outcont_callback,
}
+};
+
+ /* Generic setup urbs function that uses
+ data in device_details */
+static void keyspan_setup_urbs(struct usb_serial *serial)
+{
+ int i, j;
+ struct keyspan_serial_private *s_priv;
+ const keyspan_device_details *d_details;
+ struct usb_serial_port *port;
+ struct keyspan_port_private *p_priv;
+ struct callbacks *cback;
+ int endp;
- /* Now input urbs */
- dbg(__FUNCTION__ "Allocating input urbs.\n");
- for (i = 0; i < 4; i++) {
+ /* dbg (__FUNCTION__); */
- s_priv->in_urbs[i] = usb_alloc_urb (0); /* No ISO */
- if (!s_priv->in_urbs[i]) {
- dbg (__FUNCTION__ "Alloc for %d in urb failed.\n", i);
- return;
+ s_priv = (struct keyspan_serial_private *)(serial->private);
+ d_details = s_priv->device_details;
+
+ /* Setup values for the various callback routines */
+ cback = &keyspan_callbacks[d_details->msg_format];
+
+ /* Allocate and set up urbs for each one that is in use,
+ starting with instat endpoints */
+ s_priv->instat_urb = keyspan_setup_urb
+ (serial, d_details->instat_endpoint, USB_DIR_IN,
+ serial, s_priv->instat_buf, INSTAT_BUFLEN,
+ cback->instat_callback);
+
+ s_priv->glocont_urb = keyspan_setup_urb
+ (serial, d_details->glocont_endpoint, USB_DIR_OUT,
+ serial, s_priv->glocont_buf, GLOCONT_BUFLEN,
+ cback->glocont_callback);
+
+ /* Setup endpoints for each port specific thing */
+ for (i = 0; i < d_details->num_ports; i ++) {
+ port = &serial->port[i];
+ p_priv = (struct keyspan_port_private *)(port->private);
+
+ /* Do indat endpoints first, once for each flip */
+ endp = d_details->indat_endpoints[i];
+ for (j = 0; j <= d_details->indat_endp_flip; ++j, ++endp) {
+ p_priv->in_urbs[j] = keyspan_setup_urb
+ (serial, endp, USB_DIR_IN, port,
+ p_priv->in_buffer[j], 64,
+ cback->indat_callback);
}
+ for (; j < 2; ++j)
+ p_priv->in_urbs[j] = NULL;
+
+ /* outdat endpoints also have flip */
+ endp = d_details->outdat_endpoints[i];
+ for (j = 0; j <= d_details->outdat_endp_flip; ++j, ++endp) {
+ p_priv->out_urbs[j] = keyspan_setup_urb
+ (serial, endp, USB_DIR_OUT, port,
+ p_priv->out_buffer[j], 64,
+ cback->outdat_callback);
+ }
+ for (; j < 2; ++j)
+ p_priv->out_urbs[j] = NULL;
+
+ /* inack endpoint */
+ p_priv->inack_urb = keyspan_setup_urb
+ (serial, d_details->inack_endpoints[i], USB_DIR_IN,
+ port, p_priv->inack_buffer, 1, cback->inack_callback);
+
+ /* outcont endpoint */
+ p_priv->outcont_urb = keyspan_setup_urb
+ (serial, d_details->outcont_endpoints[i], USB_DIR_OUT,
+ port, p_priv->outcont_buffer, 64,
+ cback->outcont_callback);
+ }
- FILL_BULK_URB(s_priv->in_urbs[i], serial->dev,
- usb_rcvbulkpipe(serial->dev, i + 0x81),
- &s_priv->in_buffer[i], sizeof(s_priv->in_buffer[i]),
- keyspan_read_bulk_callback,
- serial);
- }
-
}
-static int keyspan_usa19_calc_baud(u32 baud_rate, u8 *rate_hi, u8 *rate_low)
+/* usa19 function doesn't require prescaler */
+static int keyspan_usa19_calc_baud(u32 baud_rate, u32 baudclk,
+ u8 *rate_hi, u8 *rate_low, u8 *prescaler)
{
- u32 b16, /* baud rate times 16 (actual rate used internally) */
+ u32 b16, /* baud rate times 16 (actual rate used internally) */
div, /* divisor */
cnt; /* inverse of divisor (programmed into 8051) */
+
/* prevent divide by zero... */
if( (b16 = (baud_rate * 16L)) == 0) {
return (KEYSPAN_INVALID_BAUD_RATE);
}
+ /* Any "standard" rate over 57k6 is marginal on the USA-19
+ as we run out of divisor resolution. */
+ if (baud_rate > 57600) {
+ return (KEYSPAN_INVALID_BAUD_RATE);
+ }
+
/* calculate the divisor and the counter (its inverse) */
- if( (div = (USA19_BAUDCLK / b16)) == 0) {
+ if( (div = (baudclk / b16)) == 0) {
return (KEYSPAN_INVALID_BAUD_RATE);
}
else {
return (KEYSPAN_INVALID_BAUD_RATE);
}
- /* return the counter values */
- *rate_low = (u8) (cnt & 0xff);
- *rate_hi = (u8) ((cnt >> 8) & 0xff);
+ /* return the counter values if non-null */
+ if (rate_low) {
+ *rate_low = (u8) (cnt & 0xff);
+ }
+ if (rate_hi) {
+ *rate_hi = (u8) ((cnt >> 8) & 0xff);
+ }
+ if (rate_low && rate_hi) {
+ dbg (__FUNCTION__ " %d %02x %02x.", baud_rate, *rate_hi, *rate_low);
+ }
- dbg(__FUNCTION__ " Baud rate of %d is %02x %02x.\n", baud_rate, *rate_hi, *rate_low);
+ return (KEYSPAN_BAUD_RATE_OK);
+}
+
+static int keyspan_usa19w_calc_baud(u32 baud_rate, u32 baudclk,
+ u8 *rate_hi, u8 *rate_low, u8 *prescaler)
+{
+ u32 b16, /* baud rate times 16 (actual rate used internally) */
+ clk, /* clock with 13/8 prescaler */
+ div, /* divisor using 13/8 prescaler */
+ res, /* resulting baud rate using 13/8 prescaler */
+ diff, /* error using 13/8 prescaler */
+ smallest_diff;
+ u8 best_prescaler;
+ int i;
+
+ /* dbg (__FUNCTION__ " %d.", baud_rate); */
+
+ /* prevent divide by zero */
+ if( (b16 = baud_rate * 16L) == 0) {
+ return (KEYSPAN_INVALID_BAUD_RATE);
+ }
+
+ /* Calculate prescaler by trying them all and looking
+ for best fit */
+
+ /* start with largest possible difference */
+ smallest_diff = 0xffffffff;
+
+ /* 0 is an invalid prescaler, used as a flag */
+ best_prescaler = 0;
+
+ for(i = 8; i <= 0xff; ++i)
+ {
+ clk = (baudclk * 8) / (u32) i;
+
+ if( (div = clk / b16) == 0) {
+ continue;
+ }
+
+ res = clk / div;
+ diff= (res > b16) ? (res-b16) : (b16-res);
+
+ if(diff < smallest_diff)
+ {
+ best_prescaler = i;
+ smallest_diff = diff;
+ }
+ }
+
+ if(best_prescaler == 0) {
+ return (KEYSPAN_INVALID_BAUD_RATE);
+ }
+
+ clk = (baudclk * 8) / (u32) best_prescaler;
+ div = clk / b16;
+ /* return the divisor and prescaler if non-null */
+ if (rate_low) {
+ *rate_low = (u8) (div & 0xff);
+ }
+ if (rate_hi) {
+ *rate_hi = (u8) ((div >> 8) & 0xff);
+ }
+ if (prescaler) {
+ *prescaler = best_prescaler;
+ /* dbg(__FUNCTION__ " %d %d", *prescaler, div); */
+ }
return (KEYSPAN_BAUD_RATE_OK);
}
-static int keyspan_usa19_send_setup(struct usb_serial *serial, struct usb_serial_port *port)
+static int keyspan_usa26_send_setup(struct usb_serial *serial,
+ struct usb_serial_port *port)
{
- struct portControlMessage msg;
- struct keyspan_serial_private *s_priv;
- struct keyspan_port_private *p_priv;
+ struct keyspan_usa26_portControlMessage msg;
+ struct keyspan_serial_private *s_priv;
+ struct keyspan_port_private *p_priv;
+ const keyspan_device_details *d_details;
+ int outcont_urb;
+ urb_t *this_urb;
+ int err;
+
+ /* dbg (__FUNCTION__); */
s_priv = (struct keyspan_serial_private *)(serial->private);
p_priv = (struct keyspan_port_private *)(port->private);
+ d_details = s_priv->device_details;
+
+ outcont_urb = d_details->outcont_endpoints[port->number];
+ this_urb = p_priv->outcont_urb;
+
+ /* Make sure we have an urb then send the message */
+ if (this_urb == NULL) {
+ dbg(__FUNCTION__ " oops no urb.");
+ return -1;
+ }
+
+ p_priv->resend_cont = 1;
+ if (this_urb->status == -EINPROGRESS) {
+ /* dbg (__FUNCTION__ " already writing"); */
+ return(-1);
+ }
+
+ memset(&msg, 0, sizeof (struct keyspan_usa26_portControlMessage));
+
+ /* Only set baud rate if it's changed */
+ if (p_priv->old_baud != p_priv->baud) {
+ p_priv->old_baud = p_priv->baud;
+ msg.setClocking = 0xff;
+ if (d_details->calculate_baud_rate
+ (p_priv->baud, d_details->baudclk, &msg.baudHi,
+ &msg.baudLo, &msg.prescaler) == KEYSPAN_INVALID_BAUD_RATE ) {
+ dbg(__FUNCTION__ "Invalid baud rate %d requested, using 9600.",
+ p_priv->baud);
+ msg.baudLo = 0;
+ msg.baudHi = 125; /* Values for 9600 baud */
+ msg.prescaler = 10;
+ }
+ msg.setPrescaler = 0xff;
+ }
+
+ msg.lcr = USA_DATABITS_8 | STOPBITS_5678_1;
+ if (p_priv->cflag & PARENB) {
+ /* note USA_PARITY_NONE == 0 */
+ msg.lcr |= (p_priv->cflag & PARODD)?
+ USA_PARITY_ODD: USA_PARITY_EVEN;
+ }
+ msg.setLcr = 0xff;
+
+ msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
+ msg.xonFlowControl = 0;
+ msg.setFlowControl = 0xff;
+
+ msg.forwardingLength = 1;
+ msg.xonChar = 17;
+ msg.xoffChar = 19;
+
+ msg._txOn = 1;
+ msg._txOff = 0;
+ msg.txFlush = 0;
+ msg.txBreak = 0;
+ msg.rxOn = 1;
+ msg.rxOff = 0;
+ msg.rxFlush = 0;
+ msg.rxForward = 0;
+ /*msg.returnStatus = 1;
+ msg.resetDataToggle = 0xff;*/
- //memset(msg, 0, sizeof (struct portControlMessage));
+ /* Do handshaking outputs */
+ msg.setTxTriState_setRts = 0xff;
+ msg.txTriState_rts = p_priv->rts_state;
+
+ msg.setHskoa_setDtr = 0xff;
+ msg.hskoa_dtr = p_priv->dtr_state;
+ p_priv->resend_cont = 0;
+ memcpy (this_urb->transfer_buffer, &msg, sizeof(msg));
+
+ /* send the data out the device on control endpoint */
+ this_urb->transfer_buffer_length = sizeof(msg);
+
+ this_urb->dev = serial->dev;
+ if ((err = usb_submit_urb(this_urb)) != 0) {
+ dbg(__FUNCTION__ " usb_submit_urb(setup) failed (%d)", err);
+ }
+#if 0
+ else {
+ dbg(__FUNCTION__ " usb_submit_urb(%d) OK %d bytes (end %d)",
+ outcont_urb, this_urb->transfer_buffer_length,
+ usb_pipeendpoint(this_urb->pipe));
+ }
+#endif
+
+ return (0);
+}
+
+static int keyspan_usa28_send_setup(struct usb_serial *serial,
+ struct usb_serial_port *port)
+{
+ struct keyspan_usa28_portControlMessage msg;
+ struct keyspan_serial_private *s_priv;
+ struct keyspan_port_private *p_priv;
+ const keyspan_device_details *d_details;
+ urb_t *this_urb;
+ int err;
+
+ s_priv = (struct keyspan_serial_private *)(serial->private);
+ p_priv = (struct keyspan_port_private *)(port->private);
+ d_details = s_priv->device_details;
+
+ /* only do something if we have a bulk out endpoint */
+ if ((this_urb = p_priv->outcont_urb) == NULL) {
+ dbg(__FUNCTION__ " oops no urb.");
+ return -1;
+ }
+
+ p_priv->resend_cont = 1;
+ if (this_urb->status == -EINPROGRESS) {
+ dbg (__FUNCTION__ " already writing");
+ return(-1);
+ }
+
+ memset(&msg, 0, sizeof (struct keyspan_usa28_portControlMessage));
+
msg.setBaudRate = 1;
- if (keyspan_usa19_calc_baud(9600, &msg.baudHi, &msg.baudLo) ==
- KEYSPAN_INVALID_BAUD_RATE ) {
- dbg(__FUNCTION__ "Invalid baud rate requested %d.\n", 9600);
+ if (keyspan_usa19_calc_baud(p_priv->baud, d_details->baudclk,
+ &msg.baudHi, &msg.baudLo, NULL) == KEYSPAN_INVALID_BAUD_RATE ) {
+ dbg(__FUNCTION__ "Invalid baud rate requested %d.", 9600);
msg.baudLo = 0xff;
msg.baudHi = 0xb2; /* Values for 9600 baud */
}
- /* If parity is enabled, we must calculate it ourselves. */
- if (p_priv->parity) {
- msg.parity = 1;
+ /* If parity is enabled, we must calculate it ourselves. */
+ msg.parity = 0; /* XXX for now */
+
+ msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
+ msg.xonFlowControl = 0;
+
+ /* Do handshaking outputs, DTR is inverted relative to RTS */
+ msg.rts = p_priv->rts_state;
+ msg.dtr = p_priv->dtr_state;
+
+ msg.forwardingLength = 1;
+ msg.forwardMs = 10;
+ msg.breakThreshold = 45;
+ msg.xonChar = 17;
+ msg.xoffChar = 19;
+
+ msg._txOn = 1;
+ msg._txOff = 0;
+ msg.txFlush = 0;
+ msg.txForceXoff = 0;
+ msg.txBreak = 0;
+ msg.rxOn = 1;
+ msg.rxOff = 0;
+ msg.rxFlush = 0;
+ msg.rxForward = 0;
+ /*msg.returnStatus = 1;
+ msg.resetDataToggle = 0xff;*/
+
+ p_priv->resend_cont = 0;
+ memcpy (this_urb->transfer_buffer, &msg, sizeof(msg));
+
+ /* send the data out the device on control endpoint */
+ this_urb->transfer_buffer_length = sizeof(msg);
+
+ this_urb->dev = serial->dev;
+ if ((err = usb_submit_urb(this_urb)) != 0) {
+ dbg(__FUNCTION__ " usb_submit_urb(setup) failed");
}
+#if 0
else {
- msg.parity = 0;
+ dbg(__FUNCTION__ " usb_submit_urb(setup) OK %d bytes",
+ this_urb->transfer_buffer_length);
+ }
+#endif
+
+ return (0);
+}
+
+static int keyspan_usa49_send_setup(struct usb_serial *serial,
+ struct usb_serial_port *port)
+{
+ struct keyspan_usa49_portControlMessage msg;
+ struct keyspan_serial_private *s_priv;
+ struct keyspan_port_private *p_priv;
+ const keyspan_device_details *d_details;
+ int glocont_urb;
+ urb_t *this_urb;
+ int err;
+
+ /* dbg (__FUNCTION__); */
+
+ s_priv = (struct keyspan_serial_private *)(serial->private);
+ p_priv = (struct keyspan_port_private *)(port->private);
+ d_details = s_priv->device_details;
+
+ glocont_urb = d_details->glocont_endpoint;
+ this_urb = s_priv->glocont_urb;
+
+ /* dbg(__FUNCTION__ " port %d\n", port->number); */
+
+ /* Make sure we have an urb then send the message */
+ if (this_urb == NULL) {
+ dbg(__FUNCTION__ " oops no urb for port %d.", port->number);
+ return -1;
+ }
+
+ p_priv->resend_cont = 1;
+ if (this_urb->status == -EINPROGRESS) {
+ /* dbg (__FUNCTION__ " already writing"); */
+ return(-1);
+ }
+
+ memset(&msg, 0, sizeof (struct keyspan_usa49_portControlMessage));
+
+ msg.portNumber = port->number;
+
+ /* Only set baud rate if it's changed */
+ if (p_priv->old_baud != p_priv->baud) {
+ p_priv->old_baud = p_priv->baud;
+ msg.setClocking = 0xff;
+ if (d_details->calculate_baud_rate
+ (p_priv->baud, d_details->baudclk, &msg.baudHi,
+ &msg.baudLo, &msg.prescaler) == KEYSPAN_INVALID_BAUD_RATE ) {
+ dbg(__FUNCTION__ "Invalid baud rate %d requested, using 9600.",
+ p_priv->baud);
+ msg.baudLo = 0;
+ msg.baudHi = 125; /* Values for 9600 baud */
+ msg.prescaler = 10;
+ }
+ //msg.setPrescaler = 0xff;
+ }
+
+ msg.lcr = USA_DATABITS_8 | STOPBITS_5678_1;
+ if (p_priv->cflag & PARENB) {
+ /* note USA_PARITY_NONE == 0 */
+ msg.lcr |= (p_priv->cflag & PARODD)?
+ USA_PARITY_ODD: USA_PARITY_EVEN;
}
+ msg.setLcr = 0xff;
- msg.ctsFlowControl = 0;
+ msg.ctsFlowControl = (p_priv->flow_control == flow_cts);
msg.xonFlowControl = 0;
- msg.rts = 1;
- msg.dtr = 0;
+ msg.setFlowControl = 0xff;
msg.forwardingLength = 1;
- msg.forwardMs = 10;
- msg.breakThreshold = 45;
msg.xonChar = 17;
msg.xoffChar = 19;
msg._txOn = 1;
msg._txOff = 0;
msg.txFlush = 0;
- msg.txForceXoff = 0;
msg.txBreak = 0;
msg.rxOn = 1;
msg.rxOff = 0;
msg.rxFlush = 0;
msg.rxForward = 0;
- msg.returnStatus = 1;
- msg.resetDataToggle = 1;
+ msg.enablePort = 0xff;
+ msg.disablePort = 0;
+ /* Do handshaking outputs */
+ msg.setRts = 0xff;
+ msg.rts = p_priv->rts_state;
+
+ msg.setDtr = 0xff;
+ msg.dtr = p_priv->dtr_state;
- /* only do something if we have a bulk out endpoint */
- if (s_priv->out_urbs[2]) {
- if (s_priv->out_urbs[2]->status == -EINPROGRESS) {
- dbg (__FUNCTION__ " already writing");
- return(-1);
- }
- memcpy (s_priv->out_urbs[2]->transfer_buffer, &msg, sizeof(msg));
+ p_priv->resend_cont = 0;
+ memcpy (this_urb->transfer_buffer, &msg, sizeof(msg));
- /* send the data out the device on control endpoint */
- s_priv->out_urbs[2]->transfer_buffer_length = sizeof(msg);
- s_priv->out_urbs[2]->dev = serial->dev;
+ /* send the data out the device on control endpoint */
+ this_urb->transfer_buffer_length = sizeof(msg);
- if (usb_submit_urb(s_priv->out_urbs[2])) {
- dbg(__FUNCTION__ " usb_submit_urb(setup) failed\n");
- }
- else {
- dbg(__FUNCTION__ " usb_submit_urb(setup) OK %d bytes\n", s_priv->out_urbs[2]->transfer_buffer_length);
- }
-
+ this_urb->dev = serial->dev;
+ if ((err = usb_submit_urb(this_urb)) != 0) {
+ dbg(__FUNCTION__ " usb_submit_urb(setup) failed (%d)", err);
}
+#if 0
+ else {
+ dbg(__FUNCTION__ " usb_submit_urb(%d) OK %d bytes (end %d)",
+ outcont_urb, this_urb->transfer_buffer_length,
+ usb_pipeendpoint(this_urb->pipe));
+ }
+#endif
+
return (0);
}
+static void keyspan_send_setup(struct usb_serial_port *port)
+{
+ struct usb_serial *serial = port->serial;
+ struct keyspan_serial_private *s_priv;
+ const keyspan_device_details *d_details;
+
+ s_priv = (struct keyspan_serial_private *)(serial->private);
+ d_details = s_priv->device_details;
+
+ switch (d_details->msg_format) {
+ case msg_usa26:
+ keyspan_usa26_send_setup(serial, port);
+ break;
+ case msg_usa28:
+ keyspan_usa28_send_setup(serial, port);
+ break;
+ case msg_usa49:
+ keyspan_usa49_send_setup(serial, port);
+ break;
+ }
+}
- /* Gets called by the "real" driver (ie once firmware is loaded
- and renumeration has taken place. */
+/* Gets called by the "real" driver (ie once firmware is loaded
+ and renumeration has taken place. */
static int keyspan_startup (struct usb_serial *serial)
{
- int i;
- struct usb_serial_port *port;
+ int i, err;
+ struct usb_serial_port *port;
+ struct keyspan_serial_private *s_priv;
+ struct keyspan_port_private *p_priv;
+ const keyspan_device_details *d_details;
- dbg("keyspan_startup called.\n");
+ /* dbg("keyspan_startup called."); */
+
+ for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i)
+ if (d_details->product_id == serial->dev->descriptor.idProduct)
+ break;
+ if (d_details == NULL) {
+ printk(KERN_ERR __FUNCTION__ ": unknown product id %x\n",
+ serial->dev->descriptor.idProduct);
+ return 1;
+ }
- /* Setup private data for serial driver */
- serial->private = kmalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL);
+ /* Setup private data for serial driver */
+ serial->private = kmalloc(sizeof(struct keyspan_serial_private),
+ GFP_KERNEL);
if (!serial->private) {
- dbg(__FUNCTION__ "kmalloc for keyspan_serial_private failed!.\n");
+ dbg(__FUNCTION__ "kmalloc for keyspan_serial_private failed.");
return (1);
}
memset(serial->private, 0, sizeof(struct keyspan_serial_private));
+
+ s_priv = (struct keyspan_serial_private *)(serial->private);
+ s_priv->device_details = d_details;
- init_waitqueue_head(&out_wait);
-
- /* Now setup per port private data */
+ /* Now setup per port private data */
for (i = 0; i < serial->num_ports; i++) {
port = &serial->port[i];
- port->private = kmalloc(sizeof(struct keyspan_port_private), GFP_KERNEL);
+ port->private = kmalloc(sizeof(struct keyspan_port_private),
+ GFP_KERNEL);
if (!port->private) {
- dbg(__FUNCTION__ "kmalloc for keyspan_port_private (%d) failed!.\n", i);
+ dbg(__FUNCTION__ "kmalloc for keyspan_port_private (%d) failed!.", i);
return (1);
}
memset(port->private, 0, sizeof(struct keyspan_port_private));
+ p_priv = (struct keyspan_port_private *)(port->private);
+ p_priv->device_details = d_details;
}
-
-
- switch (serial->dev->descriptor.idProduct) {
- case 0x0107: keyspan_usa19_setup_urbs(serial);
- //keyspan_send_usa19_setup(serial);
- break;
+ keyspan_setup_urbs(serial);
- default: break;
+ s_priv->instat_urb->dev = serial->dev;
+ if ((err = usb_submit_urb(s_priv->instat_urb)) != 0) {
+ dbg(__FUNCTION__ " submit instat urb failed %d", err);
}
-
return (0);
}
static void keyspan_shutdown (struct usb_serial *serial)
{
- int i;
+ int i, j;
struct usb_serial_port *port;
struct keyspan_serial_private *s_priv;
+ struct keyspan_port_private *p_priv;
- dbg("keyspan_shutdown called freeing ");
+ /* dbg("keyspan_shutdown called"); */
s_priv = (struct keyspan_serial_private *)(serial->private);
- /* Stop reading/writing urbs */
- for (i = 0; i < 4; i++) {
- if (s_priv->in_urbs[i]) {
- usb_unlink_urb(s_priv->in_urbs[i]);
+ /* Stop reading/writing urbs */
+ stop_urb(s_priv->instat_urb);
+ stop_urb(s_priv->glocont_urb);
+ for (i = 0; i < serial->num_ports; ++i) {
+ port = &serial->port[i];
+ p_priv = (struct keyspan_port_private *)(port->private);
+ stop_urb(p_priv->inack_urb);
+ stop_urb(p_priv->outcont_urb);
+ for (j = 0; j < 2; j++) {
+ stop_urb(p_priv->in_urbs[j]);
+ stop_urb(p_priv->out_urbs[j]);
}
-
}
- for (i = 0; i < 3; i++) {
- if (s_priv->out_urbs[i]) {
- usb_unlink_urb(s_priv->out_urbs[i]);
- }
- }
- /* Now free them */
- for (i = 0; i < 7; i ++) {
- if (s_priv->in_urbs[i] != NULL) {
- dbg("in%d ", i);
- usb_free_urb(s_priv->in_urbs[i]);
- }
-
- if (s_priv->out_urbs[i] != NULL) {
- dbg("out%d ", i);
- usb_free_urb(s_priv->out_urbs[i]);
+ /* Now free them */
+ if (s_priv->instat_urb)
+ usb_free_urb(s_priv->instat_urb);
+ if (s_priv->glocont_urb)
+ usb_free_urb(s_priv->glocont_urb);
+ for (i = 0; i < serial->num_ports; ++i) {
+ port = &serial->port[i];
+ p_priv = (struct keyspan_port_private *)(port->private);
+ if (p_priv->inack_urb)
+ usb_free_urb(p_priv->inack_urb);
+ if (p_priv->outcont_urb)
+ usb_free_urb(p_priv->outcont_urb);
+ for (j = 0; j < 2; j++) {
+ if (p_priv->in_urbs[j])
+ usb_free_urb(p_priv->in_urbs[j]);
+ if (p_priv->out_urbs[j])
+ usb_free_urb(p_priv->out_urbs[j]);
}
}
- dbg("urbs.\n");
- dbg("Freeing serial->private.\n");
+ /* dbg("Freeing serial->private."); */
kfree(serial->private);
- dbg("Freeing port->private.\n");
- /* Now free per port private data */
+ /* dbg("Freeing port->private."); */
+ /* Now free per port private data */
for (i = 0; i < serial->num_ports; i++) {
port = &serial->port[i];
+ while (port->open_count > 0) {
+ --port->open_count;
+ MOD_DEC_USE_COUNT;
+ }
kfree(port->private);
}
-
-}
-
-
-static int __init keyspan_init (void)
-{
- usb_serial_register (&keyspan_usa18x_pre_device);
- usb_serial_register (&keyspan_usa19_pre_device);
- usb_serial_register (&keyspan_usa19w_pre_device);
- usb_serial_register (&keyspan_usa28_pre_device);
- usb_serial_register (&keyspan_usa28x_pre_device);
- usb_serial_register (&keyspan_usa18x_device);
- usb_serial_register (&keyspan_usa19_device);
- usb_serial_register (&keyspan_usa19w_device);
- usb_serial_register (&keyspan_usa28_device);
- usb_serial_register (&keyspan_usa28x_device);
- return 0;
-}
-
-
-static void __exit keyspan_exit (void)
-{
- usb_serial_deregister (&keyspan_usa18x_pre_device);
- usb_serial_deregister (&keyspan_usa19_pre_device);
- usb_serial_deregister (&keyspan_usa19w_pre_device);
- usb_serial_deregister (&keyspan_usa28_pre_device);
- usb_serial_deregister (&keyspan_usa28x_pre_device);
- usb_serial_deregister (&keyspan_usa18x_device);
- usb_serial_deregister (&keyspan_usa19_device);
- usb_serial_deregister (&keyspan_usa19w_device);
- usb_serial_deregister (&keyspan_usa28_device);
- usb_serial_deregister (&keyspan_usa28x_device);
}
-
-
-module_init(keyspan_init);
-module_exit(keyspan_exit);
-
-MODULE_AUTHOR("Hugh Blemings <hugh@linuxcare.com>");
-MODULE_DESCRIPTION("Keyspan USB to Serial Converter driver");
and Keyspan, Inc the manufacturers of the Keyspan USB-serial products.
Thanks Guys :)
+ Thanks to Paulus for miscellaneous tidy ups, some largish chunks
+ of much nicer and/or completely new code and (perhaps most uniquely)
+ having the patience to sit down and explain why and where he'd changed
+ stuff.
+
Tip 'o the hat to Linuxcare for supporting staff in their work on
open source projects.
#ifndef __LINUX_USB_SERIAL_KEYSPAN_H
#define __LINUX_USB_SERIAL_KEYSPAN_H
-#include <linux/config.h>
/* Function prototypes for Keyspan serial converter */
static int keyspan_open (struct usb_serial_port *port,
static void keyspan_rx_throttle (struct usb_serial_port *port);
static void keyspan_rx_unthrottle (struct usb_serial_port *port);
static int keyspan_write_room (struct usb_serial_port *port);
+
static int keyspan_write (struct usb_serial_port *port,
int from_user,
const unsigned char *buf,
int count);
+
+#if 0
static void keyspan_write_bulk_callback (struct urb *urb);
-static void keyspan_read_bulk_callback (struct urb *urb);
+#endif
+
+//static void keyspan_usa26_read_int_callback (struct urb *urb);
+//static void keyspan_usa28_read_int_callback (struct urb *urb);
static int keyspan_chars_in_buffer (struct usb_serial_port *port);
static int keyspan_ioctl (struct usb_serial_port *port,
struct file *file,
int break_state);
static int keyspan_fake_startup (struct usb_serial *serial);
-static int keyspan_usa19_calc_baud (u32 baud_rate, u8 *rate_hi,
- u8 *rate_low);
-static void keyspan_usa19_setup_urbs (struct usb_serial *serial);
-static int keyspan_usa19_send_setup (struct usb_serial *serial,
- struct usb_serial_port *port);
+static int keyspan_usa19_calc_baud (u32 baud_rate, u32 baudclk,
+ u8 *rate_hi, u8 *rate_low, u8 *prescaler);
+static int keyspan_usa19w_calc_baud (u32 baud_rate, u32 baudclk,
+ u8 *rate_hi, u8 *rate_low, u8 *prescaler);
+
+//static void keyspan_usa19_setup_urbs (struct usb_serial *serial);
+
+static int keyspan_usa28_send_setup (struct usb_serial *serial,
+ struct usb_serial_port *port);
+static int keyspan_usa26_send_setup (struct usb_serial *serial,
+ struct usb_serial_port *port);
+static int keyspan_usa49_send_setup (struct usb_serial *serial,
+ struct usb_serial_port *port);
/* Functions from usbserial.c for ezusb firmware handling */
extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit);
static const struct ezusb_hex_record *keyspan_usa19w_firmware = NULL;
#endif
-
+#ifdef CONFIG_USB_SERIAL_KEYSPAN_USA49W
+ #include "keyspan_usa49w_fw.h"
+#else
+ static const struct ezusb_hex_record *keyspan_usa49w_firmware = NULL;
+#endif
+
/* Values used for baud rate calculation - device specific */
#define KEYSPAN_INVALID_BAUD_RATE (-1)
#define KEYSPAN_BAUD_RATE_OK (0)
-#define USA19_BAUDCLK (12000000L)
+#define KEYSPAN_USA18X_BAUDCLK (12000000L) /* a guess */
+#define KEYSPAN_USA19_BAUDCLK (12000000L)
+#define KEYSPAN_USA19W_BAUDCLK (24000000L)
+#define KEYSPAN_USA28X_BAUDCLK (12000000L)
+#define KEYSPAN_USA49W_BAUDCLK (48000000L)
+
+ /* Some constants used to characterise each device.
+ There is a four port device due later in the year,
+ we allow for it now in the following */
+#define KEYSPAN_MAX_NUM_PORTS (4)
+#define KEYSPAN_MAX_FLIPS (2)
+
+typedef struct {
+ /* product ID value */
+ int product_id;
+
+ enum {msg_usa26, msg_usa28, msg_usa49} msg_format;
+
+ /* Number of physical ports */
+ int num_ports;
+
+ /* 1 if endpoint flipping used on input, 0 if not */
+ int indat_endp_flip;
+
+ /* 1 if endpoint flipping used on output, 0 if not */
+ int outdat_endp_flip;
+
+ /* Table mapping input data endpoint IDs to physical
+ port number and flip if used */
+ int indat_endpoints[KEYSPAN_MAX_NUM_PORTS];
+
+ /* Same for output endpoints */
+ int outdat_endpoints[KEYSPAN_MAX_NUM_PORTS];
+
+ /* Input acknowledge endpoints */
+ int inack_endpoints[KEYSPAN_MAX_NUM_PORTS];
+
+ /* Output control endpoints */
+ int outcont_endpoints[KEYSPAN_MAX_NUM_PORTS];
+
+ /* Endpoint used for input status */
+ int instat_endpoint;
+
+ /* Endpoint used for global control functions */
+ int glocont_endpoint;
+
+ int (*calculate_baud_rate) (u32 baud_rate, u32 baudclk,
+ u8 *rate_hi, u8 *rate_low, u8 *prescaler);
+ u32 baudclk;
+
+} keyspan_device_details;
+
+ /* Now for each device type we setup the device detail
+ structure with the appropriate information (provided
+ in Keyspan's documentation) */
+
+static const keyspan_device_details usa18x_device_details = {
+ 0x112, /* product ID */
+ msg_usa26, /* msg type*/
+ 1, /* num ports */
+ 0, /* indat endpoint flip */
+ 1, /* outdat endpoint flip */
+ {0x81}, /* per port indat */
+ {0x01}, /* per port outdat */
+ {0x85}, /* per port inack */
+ {0x05}, /* per port outcont */
+ 0x87, /* instat endpoint */
+ 0x07, /* glocont endpoint */
+ keyspan_usa19w_calc_baud, /* calc baud rate */
+ KEYSPAN_USA18X_BAUDCLK /* base baud clock */
+};
+
+static const keyspan_device_details usa19_device_details = {
+ 0x107, /* product ID */
+ msg_usa28, /* msg type*/
+ 1, /* num ports */
+ 1, /* indat endpoint flip */
+ 1, /* outdat endpoint flip */
+ {0x81}, /* per port indat */
+ {0x01}, /* per port outdat */
+ {0x83}, /* per port inack */
+ {0x03}, /* per port outcont */
+ 0x84, /* instat endpoint */
+ -1, /* glocont endpoint */
+ keyspan_usa19_calc_baud, /* calc baud rate */
+ KEYSPAN_USA19_BAUDCLK /* base baud clock */
+};
+
+static const keyspan_device_details usa19w_device_details = {
+ 0x108, /* product ID */
+ msg_usa26, /* msg type*/
+ 1, /* num ports */
+ 0, /* indat endpoint flip */
+ 1, /* outdat endpoint flip */
+ {0x81}, /* per port indat */
+ {0x01}, /* per port outdat */
+ {0x85}, /* per port inack */
+ {0x05}, /* per port outcont */
+ 0x87, /* instat endpoint */
+ 0x07, /* glocont endpoint */
+ keyspan_usa19w_calc_baud, /* calc baud rate */
+ KEYSPAN_USA19W_BAUDCLK /* base baud clock */
+};
+
+static const keyspan_device_details usa28x_device_details = {
+ 0x110, /* product ID */
+ msg_usa26, /* msg type*/
+ 2, /* num ports */
+ 0, /* indat endpoint flip */
+ 1, /* outdat endpoint flip */
+ {0x81, 0x83}, /* per port indat */
+ {0x01, 0x03}, /* per port outdat */
+ {0x85, 0x86}, /* per port inack */
+ {0x05, 0x06}, /* per port outcont */
+ 0x87, /* instat endpoint */
+ 0x07, /* glocont endpoint */
+ keyspan_usa19w_calc_baud, /* calc baud rate */
+ KEYSPAN_USA28X_BAUDCLK
+};
+
+static const keyspan_device_details usa49w_device_details = {
+ 0x010a, /* product ID */
+ msg_usa49, /* msg type*/
+ 4, /* num ports */
+ 0, /* indat endpoint flip */
+ 0, /* outdat endpoint flip */
+ { 0x81, 0x82, 0x83, 0x84}, /* per port indat */
+ { 0x01, 0x02, 0x03, 0x04}, /* per port outdat */
+ {-1, -1, -1, -1}, /* per port inack */
+ {-1, -1, -1, -1}, /* per port outcont */
+ 0x87, /* instat endpoint */
+ 0x07, /* glocont endpoint */
+ keyspan_usa19w_calc_baud, /* calc baud rate */
+ KEYSPAN_USA49W_BAUDCLK
+};
- /* Device info for the Keyspan serial converter */
+static const keyspan_device_details *keyspan_devices[] = {
+ &usa18x_device_details,
+ &usa19_device_details,
+ &usa19w_device_details,
+ &usa28x_device_details,
+ &usa49w_device_details,
+ NULL
+};
+
+ /* Device info for the Keyspan serial converter, used
+ by the overall usb-serial probe function */
#define KEYSPAN_VENDOR_ID (0x06cd)
/* Product IDs for the five products supported, pre-renumeration */
#define keyspan_usa19w_pre_product_id 0x0106
#define keyspan_usa28_pre_product_id 0x0101
#define keyspan_usa28x_pre_product_id 0x0102
+#define keyspan_usa49w_pre_product_id 0x0109
/* Product IDs post-renumeration */
#define keyspan_usa18x_product_id 0x0112
#define keyspan_usa19w_product_id 0x0108
#define keyspan_usa28_product_id 0x010f
#define keyspan_usa28x_product_id 0x0110
+#define keyspan_usa49w_product_id 0x010a
static __devinitdata struct usb_device_id keyspan_ids_combined[] = {
{idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa18x_pre_product_id},
{idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa19w_pre_product_id},
{idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa28_pre_product_id},
{idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa28x_pre_product_id},
+ {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa49w_pre_product_id},
{idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa18x_product_id},
{idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa19_product_id},
{idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa19w_product_id},
{idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa28_product_id},
{idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa28x_product_id},
+ {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa49w_product_id},
{ } /* Terminating entry */
};
{ } /* Terminating entry */
};
+static __devinitdata struct usb_device_id keyspan_usa49w_pre_ids[] = {
+ {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa49w_pre_product_id},
+ { } /* Terminating entry */
+};
+
static __devinitdata struct usb_device_id keyspan_usa18x_ids[] = {
{idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa18x_product_id},
{ } /* Terminating entry */
{ } /* Terminating entry */
};
+static __devinitdata struct usb_device_id keyspan_usa49w_ids[] = {
+ {idVendor: KEYSPAN_VENDOR_ID, idProduct: keyspan_usa49w_product_id},
+ { } /* Terminating entry */
+};
+
/* Structs for the devices, pre and post renumeration.
These are incomplete at present - HAB 20000708 */
struct usb_serial_device_type keyspan_usa18x_pre_device = {
- name: "Keyspan USA18X - (prerenumeration)",
+ name: "Keyspan USA18X - (without firmware)",
id_table: keyspan_usa18x_pre_ids,
needs_interrupt_in: DONT_CARE,
needs_bulk_in: DONT_CARE,
};
struct usb_serial_device_type keyspan_usa19_pre_device = {
- name: "Keyspan USA19 - (prerenumeration)",
+ name: "Keyspan USA19 - (without firmware)",
id_table: keyspan_usa19_pre_ids,
needs_interrupt_in: DONT_CARE,
needs_bulk_in: DONT_CARE,
struct usb_serial_device_type keyspan_usa19w_pre_device = {
- name: "Keyspan USA19W - (prerenumeration)",
+ name: "Keyspan USA19W - (without firmware)",
id_table: keyspan_usa19w_pre_ids,
needs_interrupt_in: DONT_CARE,
needs_bulk_in: DONT_CARE,
struct usb_serial_device_type keyspan_usa28_pre_device = {
- name: "Keyspan USA28 - (prerenumeration)",
+ name: "Keyspan USA28 - (without firmware)",
id_table: keyspan_usa28_pre_ids,
needs_interrupt_in: DONT_CARE,
needs_bulk_in: DONT_CARE,
};
struct usb_serial_device_type keyspan_usa28x_pre_device = {
- name: "Keyspan USA28X - (prerenumeration)",
+ name: "Keyspan USA28X - (without firmware)",
id_table: keyspan_usa28x_pre_ids,
needs_interrupt_in: DONT_CARE,
needs_bulk_in: DONT_CARE,
startup: keyspan_fake_startup
};
+struct usb_serial_device_type keyspan_usa49w_pre_device = {
+ name: "Keyspan USA49W - (without firmware)",
+ id_table: keyspan_usa49w_pre_ids,
+ needs_interrupt_in: DONT_CARE,
+ needs_bulk_in: DONT_CARE,
+ needs_bulk_out: DONT_CARE,
+ num_interrupt_in: NUM_DONT_CARE,
+ num_bulk_in: NUM_DONT_CARE,
+ num_bulk_out: NUM_DONT_CARE,
+ num_ports: 4,
+ startup: keyspan_fake_startup
+};
struct usb_serial_device_type keyspan_usa18x_device = {
name: "Keyspan USA18X",
id_table: keyspan_usa18x_ids,
needs_interrupt_in: DONT_CARE,
- needs_bulk_in: DONT_CARE,
- needs_bulk_out: DONT_CARE,
+ needs_bulk_in: MUST_HAVE,
+ needs_bulk_out: MUST_HAVE,
num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: NUM_DONT_CARE,
- num_bulk_out: NUM_DONT_CARE,
+ num_bulk_in: 3,
+ num_bulk_out: 4,
num_ports: 1,
open: keyspan_open,
close: keyspan_close,
+ write: keyspan_write,
+ write_room: keyspan_write_room,
+ //write_bulk_callback: Not used - we define our own herbs
+ //read_int_callback: keyspan_usa26_read_int_callback,
+ chars_in_buffer: keyspan_chars_in_buffer,
throttle: keyspan_rx_throttle,
unthrottle: keyspan_rx_unthrottle,
+ ioctl: keyspan_ioctl,
set_termios: keyspan_set_termios,
+ break_ctl: keyspan_break_ctl,
+ startup: keyspan_startup,
+ shutdown: keyspan_shutdown,
};
struct usb_serial_device_type keyspan_usa19_device = {
close: keyspan_close,
write: keyspan_write,
write_room: keyspan_write_room,
- write_bulk_callback: keyspan_write_bulk_callback,
- read_int_callback: keyspan_read_bulk_callback,
+// write_bulk_callback: keyspan_write_bulk_callback,
+// read_int_callback: keyspan_usa28_read_int_callback,
chars_in_buffer: keyspan_chars_in_buffer,
throttle: keyspan_rx_throttle,
unthrottle: keyspan_rx_unthrottle,
name: "Keyspan USA19W",
id_table: keyspan_usa19w_ids,
needs_interrupt_in: DONT_CARE,
- needs_bulk_in: DONT_CARE,
- needs_bulk_out: DONT_CARE,
+ needs_bulk_in: MUST_HAVE,
+ needs_bulk_out: MUST_HAVE,
num_interrupt_in: NUM_DONT_CARE,
- num_bulk_in: NUM_DONT_CARE,
- num_bulk_out: NUM_DONT_CARE,
+ num_bulk_in: 3,
+ num_bulk_out: 4,
num_ports: 1,
open: keyspan_open,
close: keyspan_close,
+ write: keyspan_write,
+ write_room: keyspan_write_room,
+ //write_bulk_callback: Not used - we define our own herbs
+ //read_int_callback: keyspan_usa26_read_int_callback,
+ chars_in_buffer: keyspan_chars_in_buffer,
throttle: keyspan_rx_throttle,
unthrottle: keyspan_rx_unthrottle,
+ ioctl: keyspan_ioctl,
set_termios: keyspan_set_termios,
+ break_ctl: keyspan_break_ctl,
+ startup: keyspan_startup,
+ shutdown: keyspan_shutdown,
};
close: keyspan_close,
write: keyspan_write,
write_room: keyspan_write_room,
- write_bulk_callback: keyspan_write_bulk_callback,
- read_int_callback: keyspan_read_bulk_callback,
+// write_bulk_callback: keyspan_write_bulk_callback,
+// read_int_callback: keyspan_usa26_read_int_callback,
chars_in_buffer: keyspan_chars_in_buffer,
throttle: keyspan_rx_throttle,
unthrottle: keyspan_rx_unthrottle,
startup: keyspan_startup,
shutdown: keyspan_shutdown,
+};
+struct usb_serial_device_type keyspan_usa49w_device = {
+ name: "Keyspan USA49W",
+ id_table: keyspan_usa49w_ids,
+ needs_interrupt_in: DONT_CARE,
+ needs_bulk_in: MUST_HAVE,
+ needs_bulk_out: MUST_HAVE,
+ num_interrupt_in: NUM_DONT_CARE,
+ num_bulk_in: 5,
+ num_bulk_out: 5,
+ num_ports: 4,
+ open: keyspan_open,
+ close: keyspan_close,
+ write: keyspan_write,
+ write_room: keyspan_write_room,
+ //write_bulk_callback: Not used - we define our own herbs
+ //read_int_callback: keyspan_usa26_read_int_callback,
+ chars_in_buffer: keyspan_chars_in_buffer,
+ throttle: keyspan_rx_throttle,
+ unthrottle: keyspan_rx_unthrottle,
+ ioctl: keyspan_ioctl,
+ set_termios: keyspan_set_termios,
+ break_ctl: keyspan_break_ctl,
+ startup: keyspan_startup,
+ shutdown: keyspan_shutdown,
};
-
#endif
#ifndef __USA26MSG__
#define __USA26MSG__
-#ifndef __stubs__
-#include "datadefs.h"
-#endif
-
-typedef struct txAckMessage
-{
- u8 dummy;
-} txAckMessage;
-typedef struct portControlMessage
+typedef struct keyspan_usa26_portControlMessage
{
/*
there are three types of "commands" sent in the control message:
returnStatus, // BOTH: return current status (even if it hasn't changed)
resetDataToggle;// BOTH: reset data toggle state to DATA0
-} portControlMessage;
+} keyspan_usa26_portControlMessage;
// defines for bits in lcr
#define USA_DATABITS_5 0x00
// all things called "StatusMessage" are sent on the status endpoint
-typedef struct portStatusMessage // one for each port
+typedef struct keyspan_usa26_portStatusMessage // one for each port
{
u8 port, // BOTH: 0=first, 1=second, other=see below
hskia_cts, // USA26: reports HSKIA pin
_txXoff, // port is in XOFF state (either host or RX XOFF)
rxEnabled, // as configured by rxOn/rxOff 1=on, 0=off
controlResponse;// 1=a control message has been processed
-} portStatusMessage;
+} keyspan_usa26_portStatusMessage;
// bits in RX data message when STAT byte is included
#define RXERROR_OVERRUN 0x02
#define RXERROR_FRAMING 0x08
#define RXERROR_BREAK 0x10
-typedef struct globalControlMessage
+typedef struct keyspan_usa26_globalControlMessage
{
u8 sendGlobalStatus, // 2=request for two status responses
resetStatusToggle, // 1=reset global status toggle
resetStatusCount; // a cycling value
-} globalControlMessage;
+} keyspan_usa26_globalControlMessage;
-typedef struct globalStatusMessage
+typedef struct keyspan_usa26_globalStatusMessage
{
u8 port, // 3
sendGlobalStatus, // from request, decremented
resetStatusCount; // as in request
-} globalStatusMessage;
+} keyspan_usa26_globalStatusMessage;
-typedef struct globalDebugMessage
+typedef struct keyspan_usa26_globalDebugMessage
{
u8 port, // 2
a,
b,
c,
d;
-} globalDebugMessage;
+} keyspan_usa26_globalDebugMessage;
// ie: the maximum length of an EZUSB endpoint buffer
#define MAX_DATA_LEN 64
#ifndef __USA28MSG__
#define __USA28MSG__
-/*#ifndef STUBS
-#include "datadefs.h"
-#endif*/
-typedef struct txAckMessage
-{
- u8 dummy;
-} txAckMessage;
-
-typedef struct portControlMessage
+typedef struct keyspan_usa28_portControlMessage
{
/*
there are four types of "commands" sent in the control message:
returnStatus, // return current status n times (1 or 2)
resetDataToggle;// reset data toggle state to DATA0
-} portControlMessage;
+} keyspan_usa28_portControlMessage;
-typedef struct portStatusMessage
+typedef struct keyspan_usa28_portStatusMessage
{
u8 port, // 0=first, 1=second, 2=global (see below)
cts,
rxBreak, // 1=we're in break state
rs232invalid, // 1=no valid signals on rs-232 inputs
controlResponse;// 1=a control messages has been processed
-} portStatusMessage;
+} keyspan_usa28_portStatusMessage;
// bit defines in txState
#define TX_OFF 0x01 // requested by host txOff command
#define TX_XOFF 0x02 // either real, or simulated by host
-typedef struct globalControlMessage
+typedef struct keyspan_usa28_globalControlMessage
{
u8 sendGlobalStatus, // 2=request for two status responses
resetStatusToggle, // 1=reset global status toggle
resetStatusCount; // a cycling value
-} globalControlMessage;
+} keyspan_usa28_globalControlMessage;
-typedef struct globalStatusMessage
+typedef struct keyspan_usa28_globalStatusMessage
{
u8 port, // 3
sendGlobalStatus, // from request, decremented
resetStatusCount; // as in request
-} globalStatusMessage;
+} keyspan_usa28_globalStatusMessage;
-typedef struct globalDebugMessage
+typedef struct keyspan_usa28_globalDebugMessage
{
u8 port, // 2
n, // typically a count/status byte
b; // typically a data byte
-} globalDebugMessage;
+} keyspan_usa28_globalDebugMessage;
// ie: the maximum length of an EZUSB endpoint buffer
#define MAX_DATA_LEN 64
--- /dev/null
+/*
+ usa49msg.h
+
+ Copyright (c) 1998-2000 InnoSys Incorporated. All Rights Reserved
+ This file is available under a BSD-style copyright
+
+ Keyspan USB Async Firmware to run on Anchor EZ-USB
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ 1. Redistributions of source code must retain this licence text
+ without modification, this list of conditions, and the following
+ disclaimer. The following copyright notice must appear immediately at
+ the beginning of all source files:
+
+ Copyright (c) 1998-2000 InnoSys Incorporated. All Rights Reserved
+
+ This file is available under a BSD-style copyright
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. The name of InnoSys Incorprated may not be used to endorse or promote
+ products derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY INNOSYS CORP. ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+ 4th revision: USA49W version
+
+ See usa26msg.h for description of message formats
+
+ Third revision: USA28X version (aka USA26)
+
+ Buffer formats for RX/TX data messages are not defined by
+ a structure, but are described here:
+
+ USB OUT (host -> USA26, transmit) messages contain a
+ REQUEST_ACK indicator (set to 0xff to request an ACK at the
+ completion of transmit; 0x00 otherwise), followed by data:
+
+ RQSTACK DAT DAT DAT ...
+
+ with a total data length of 63.
+
+ USB IN (USA26 -> host, receive) messages contain either a zero
+ flag (indicating no error in any data bytes):
+
+ 00 DAT DAT DAT ...
+
+ for a total of 63 data bytes, or a non-zero status flag (indicating
+ that all data bytes will be preceded by status flag):
+
+ STAT DAT STAT DAT STAT DAT ...
+
+ for a total of 32 data bytes. The valid bits in the STAT bytes are:
+
+ OVERRUN 0x02
+ PARITY 0x04
+ FRAMING 0x08
+ BREAK 0x10
+
+ Notes:
+
+ 1. a "no status" RX data message (first byte zero) can serve as
+ a "break off" indicator.
+ 2. a control message specifying disablePort will be answered
+ with a status message, but no further status will be sent
+ until a control messages with enablePort is sent
+
+ revision history:
+
+ 1999feb10 add reportHskiaChanges to allow us to ignore them
+ 1999feb10 add txAckThreshold for fast+loose throughput enhancement
+ 1999mar30 beef up support for RX error reporting
+ 1999apr14 add resetDataToggle to control message
+ 2000jan04 merge with usa17msg.h
+ 2000mar08 clone from usa26msg.h -> usa49msg.h
+ 2000mar09 change to support 4 ports
+ 2000may03 change external clocking to match USA-49W hardware
+ 2000jun01 add extended BSD-style copyright text
+*/
+
+#ifndef __USA49MSG__
+#define __USA49MSG__
+
+
+/*
+ Host->device messages sent on the global control endpoint:
+
+ portNumber message
+ ---------- --------------------
+ 0,1,2,3 portControlMessage
+ 0x80 globalControlMessage
+*/
+
+typedef struct keyspan_usa49_portControlMessage
+{
+ /*
+ 0. 0/1/2/3 port control message follows
+ 0x80 set non-port control message follows
+ */
+ u8 portNumber,
+
+ /*
+ there are three types of "commands" sent in the control message:
+
+ 1. configuration changes which must be requested by setting
+ the corresponding "set" flag (and should only be requested
+ when necessary, to reduce overhead on the USA26):
+ */
+ setClocking, // host requests baud rate be set
+ baudLo, // host does baud divisor calculation
+ baudHi, // baudHi is only used for first port (gives lower rates)
+ prescaler, // specified as N/8; values 8-ff are valid
+ // must be set any time internal baud rate is set;
+ txClocking, // 0=internal, 1=external/DSR
+ rxClocking, // 0=internal, 1=external/DSR
+
+ setLcr, // host requests lcr be set
+ lcr, // use PARITY, STOPBITS, DATABITS below
+
+ setFlowControl, // host requests flow control be set
+ ctsFlowControl, // 1=use CTS flow control, 0=don't
+ xonFlowControl, // 1=use XON/XOFF flow control, 0=don't
+ xonChar, // specified in current character format
+ xoffChar, // specified in current character format
+
+ setRts, // host requests RTS output be set
+ rts, // 1=active, 0=inactive
+
+ setDtr, // host requests DTR output be set
+ dtr; // 1=on, 0=off
+
+
+ /*
+ 3. configuration data which is simply used as is (no overhead,
+ but must be specified correctly in every host message).
+ */
+ u8 forwardingLength, // forward when this number of chars available
+ dsrFlowControl, // 1=use DSR flow control, 0=don't
+ txAckThreshold, // 0=not allowed, 1=normal, 2-255 deliver ACK faster
+ loopbackMode; // 0=no loopback, 1=loopback enabled
+
+ /*
+ 4. commands which are flags only; these are processed in order
+ (so that, e.g., if both _txOn and _txOff flags are set, the
+ port ends in a TX_OFF state); any non-zero value is respected
+ */
+ u8 _txOn, // enable transmitting (and continue if there's data)
+ _txOff, // stop transmitting
+ txFlush, // toss outbound data
+ txBreak, // turn on break (cleared by _txOn)
+ rxOn, // turn on receiver
+ rxOff, // turn off receiver
+ rxFlush, // toss inbound data
+ rxForward, // forward all inbound data, NOW (as if fwdLen==1)
+ returnStatus, // return current status (even if it hasn't changed)
+ resetDataToggle,// reset data toggle state to DATA0
+ enablePort, // start servicing port (move data, check status)
+ disablePort; // stop servicing port (does implicit tx/rx flush/off)
+
+} keyspan_usa49_portControlMessage;
+
+// defines for bits in lcr
+#define USA_DATABITS_5 0x00
+#define USA_DATABITS_6 0x01
+#define USA_DATABITS_7 0x02
+#define USA_DATABITS_8 0x03
+#define STOPBITS_5678_1 0x00 // 1 stop bit for all byte sizes
+#define STOPBITS_5_1p5 0x04 // 1.5 stop bits for 5-bit byte
+#define STOPBITS_678_2 0x04 // 2 stop bits for 6/7/8-bit byte
+#define USA_PARITY_NONE 0x00
+#define USA_PARITY_ODD 0x08
+#define USA_PARITY_EVEN 0x18
+#define PARITY_1 0x28
+#define PARITY_0 0x38
+
+typedef struct keyspan_usa49_globalControlMessage
+{
+ u8 portNumber, // 0x80
+ sendGlobalStatus, // 1/2=number of status responses requested
+ resetStatusToggle, // 1=reset global status toggle
+ resetStatusCount, // a cycling value
+ remoteWakeupEnable; // 0x10=P1, 0x20=P2, 0x40=P3, 0x80=P3
+} keyspan_usa49_globalControlMessage;
+
+/*
+ Device->host messages send on the global status endpoint
+
+ portNumber message
+ ---------- --------------------
+ 0x00,0x01,0x02,0x03 portStatusMessage
+ 0x80 globalStatusMessage
+ 0x81 globalDebugMessage
+*/
+
+typedef struct keyspan_usa49_portStatusMessage // one for each port
+{
+ u8 portNumber, // 0,1,2,3
+ cts, // reports CTS pin
+ dcd, // reports DCD pin
+ dsr, // reports DSR pin
+ ri, // reports RI pin
+ _txOff, // transmit has been disabled (by host)
+ _txXoff, // transmit is in XOFF state (either host or RX XOFF)
+ rxEnabled, // as configured by rxOn/rxOff 1=on, 0=off
+ controlResponse,// 1=a control message has been processed
+ txAck, // ACK (data TX complete)
+ rs232valid; // RS-232 signal valid
+} keyspan_usa49_portStatusMessage;
+
+// bits in RX data message when STAT byte is included
+#define RXERROR_OVERRUN 0x02
+#define RXERROR_PARITY 0x04
+#define RXERROR_FRAMING 0x08
+#define RXERROR_BREAK 0x10
+
+typedef struct keyspan_usa49_globalStatusMessage
+{
+ u8 portNumber, // 0x80=globalStatusMessage
+ sendGlobalStatus, // from request, decremented
+ resetStatusCount; // as in request
+} keyspan_usa49_globalStatusMessage;
+
+typedef struct keyspan_usa49_globalDebugMessage
+{
+ u8 portNumber, // 0x81=globalDebugMessage
+ n, // typically a count/status byte
+ b; // typically a data byte
+} keyspan_usa49_globalDebugMessage;
+
+// ie: the maximum length of an EZUSB endpoint buffer
+#define MAX_DATA_LEN 64
+
+// update status approx. 60 times a second (16.6666 ms)
+#define STATUS_UPDATE_INTERVAL 16
+
+// status rationing tuning value (each port gets checked each n ms)
+#define STATUS_RATION 10
+
+#endif
--- /dev/null
+/* keyspan_usa49w_fw.h
+
+ Generated from Keyspan firmware image Thu Sep 28 09:13:26 2000 EST
+ This firmware is for the Keyspan USA-49W Serial Adaptor
+
+ "The firmware contained herein as keyspan_usa49w_fw.h is
+ Copyright (C) 1999-2000 Keyspan, A division of InnoSys Incorporated
+ ("Keyspan"), as an unpublished work. This notice does not imply
+ unrestricted or public access to this firmware which is a trade secret of
+ Keyspan, and which may not be reproduced, used, sold or transferred to any
+ third party without Keyspan's prior written consent. All Rights Reserved.
+
+ This firmware may not be modified and may only be used with the Keyspan
+ USA-49W Serial Adapter. Distribution and/or Modification of the
+ keyspan.c driver which includes this firmware, in whole or in part,
+ requires the inclusion of this statement."
+
+*/
+
+static const struct ezusb_hex_record keyspan_usa49w_firmware[] = {
+{ 0x0000, 3, {0x02, 0x10, 0x36} },
+{ 0x0003, 16, {0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x78, 0x41, 0x74} },
+{ 0x0013, 16, {0x01, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24} },
+{ 0x0023, 16, {0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x0033, 3, {0x02, 0x17, 0xf0} },
+{ 0x0036, 12, {0x90, 0x78, 0x41, 0x74, 0x01, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x0043, 3, {0x02, 0x18, 0x00} },
+{ 0x0046, 16, {0xe4, 0xff, 0x74, 0x40, 0x2f, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xe0, 0xfe, 0xe5, 0x27} },
+{ 0x0056, 16, {0x24, 0x04, 0xfd, 0xe4, 0x35, 0x26, 0xfa, 0xa9, 0x05, 0x7b, 0x01, 0xef, 0x7c, 0x00, 0x29, 0xf9} },
+{ 0x0066, 16, {0xec, 0x3a, 0xfa, 0xee, 0x12, 0x11, 0x90, 0x0f, 0xbf, 0x22, 0xd7, 0xe5, 0x27, 0x24, 0x05, 0xf5} },
+{ 0x0076, 16, {0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x70, 0x03, 0x02, 0x01, 0x4f, 0x7f, 0x01, 0xe5, 0x27} },
+{ 0x0086, 16, {0x24, 0x08, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xfd, 0x12, 0x15, 0x3d, 0xe5, 0x27} },
+{ 0x0096, 16, {0x24, 0x06, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xff, 0x12, 0x15, 0x6c, 0xe5, 0x27} },
+{ 0x00a6, 16, {0x24, 0x07, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xff, 0x12, 0x00, 0x03, 0xe5, 0x27} },
+{ 0x00b6, 16, {0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x30, 0xf0, 0x7d, 0x04, 0x44} },
+{ 0x00c6, 16, {0x20, 0xf0, 0xe5, 0x27, 0x24, 0x09, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x12} },
+{ 0x00d6, 16, {0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xdf, 0xf0, 0x43} },
+{ 0x00e6, 16, {0x05, 0xc0, 0xe5, 0x27, 0x24, 0x0a, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x14} },
+{ 0x00f6, 16, {0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xdf, 0xf0, 0x43} },
+{ 0x0106, 16, {0x05, 0x0b, 0x80, 0x03, 0x43, 0x05, 0x02, 0x7f, 0x03, 0x12, 0x15, 0x3d, 0xe5, 0x27, 0x24, 0x39} },
+{ 0x0116, 16, {0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x04} },
+{ 0x0126, 16, {0xf0, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x90, 0xc0, 0x00} },
+{ 0x0136, 16, {0xf0, 0x90, 0x78, 0x41, 0x74, 0x02, 0xf0, 0xe5, 0x27, 0x24, 0x36, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0146, 16, {0xf5, 0x83, 0xe0, 0x44, 0x06, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x0b, 0xf5, 0x82, 0xe4} },
+{ 0x0156, 16, {0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x32, 0xe5, 0x27, 0x24, 0x0c, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0166, 16, {0xf5, 0x83, 0xe0, 0x54, 0x3f, 0xff, 0xe5, 0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x0176, 16, {0x83, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4} },
+{ 0x0186, 16, {0x35, 0x26, 0xf5, 0x83, 0xe0, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x0d, 0xf5, 0x82, 0xe4} },
+{ 0x0196, 16, {0x35, 0x26, 0xf5, 0x83, 0xe0, 0x70, 0x03, 0x02, 0x02, 0x6a, 0xe5, 0x27, 0x24, 0x17, 0xf5, 0x82} },
+{ 0x01a6, 16, {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x11, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x01b6, 16, {0x26, 0xf5, 0x83, 0xe0, 0x44, 0x04, 0xf0, 0x80, 0x0f, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4} },
+{ 0x01c6, 16, {0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xfb, 0xf0, 0xe4, 0xff, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82} },
+{ 0x01d6, 16, {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xfd, 0x12, 0x15, 0x3d, 0xe5, 0x27, 0x24, 0x0e, 0xf5, 0x82} },
+{ 0x01e6, 16, {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x11, 0xe5, 0x27, 0x24, 0x33, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x01f6, 16, {0x26, 0xf5, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x0f, 0xe5, 0x27, 0x24, 0x33, 0xf5, 0x82, 0xe4} },
+{ 0x0206, 16, {0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0xf0, 0xe5, 0x27, 0x24, 0x33, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x0216, 16, {0x26, 0xf5, 0x83, 0xe0, 0x54, 0xfc, 0xf0, 0xe5, 0x27, 0x24, 0x0f, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0226, 16, {0xf5, 0x83, 0xe0, 0x60, 0x2f, 0xe5, 0x27, 0x24, 0x33, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} },
+{ 0x0236, 16, {0xe0, 0x44, 0x02, 0xf0, 0xe5, 0x27, 0x24, 0x10, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x0246, 16, {0xff, 0x12, 0x14, 0xdd, 0xe5, 0x27, 0x24, 0x11, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x0256, 16, {0xff, 0x12, 0x15, 0x0d, 0xe5, 0x27, 0x24, 0x33, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x0266, 16, {0xff, 0x12, 0x14, 0xad, 0xe5, 0x27, 0x24, 0x14, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x0276, 16, {0x60, 0x44, 0xe5, 0x27, 0x24, 0x15, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x11} },
+{ 0x0286, 16, {0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x01, 0xf0, 0x80} },
+{ 0x0296, 16, {0x0f, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xfe, 0xf0} },
+{ 0x02a6, 16, {0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x02b6, 16, {0x83, 0xe0, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x12, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x02c6, 16, {0x83, 0xe0, 0x60, 0x44, 0xe5, 0x27, 0x24, 0x13, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x02d6, 16, {0x60, 0x11, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x02} },
+{ 0x02e6, 16, {0xf0, 0x80, 0x0f, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54} },
+{ 0x02f6, 16, {0xfd, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x0306, 16, {0x26, 0xf5, 0x83, 0xe0, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x16, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x0316, 16, {0x26, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x27, 0x24, 0x35, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} },
+{ 0x0326, 16, {0xef, 0xf0, 0xe5, 0x27, 0x24, 0x17, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x30, 0xe0} },
+{ 0x0336, 16, {0x11, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x40, 0xf0} },
+{ 0x0346, 16, {0x80, 0x0f, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xbf} },
+{ 0x0356, 16, {0xf0, 0xe5, 0x27, 0x24, 0x18, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x27} },
+{ 0x0366, 16, {0x24, 0x3b, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xef, 0xf0, 0xe5, 0x27, 0x24, 0x19, 0xf5} },
+{ 0x0376, 16, {0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x11, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4} },
+{ 0x0386, 16, {0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x10, 0xf0, 0x80, 0x0f, 0xe5, 0x27, 0x24, 0x39, 0xf5, 0x82} },
+{ 0x0396, 16, {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0xe5} },
+{ 0x03a6, 16, {0x27, 0x24, 0x39, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x90, 0xc0, 0x00, 0xf0, 0xe5} },
+{ 0x03b6, 16, {0x27, 0x24, 0x1a, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x6b, 0xe5, 0x27, 0x24} },
+{ 0x03c6, 16, {0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xbf, 0xf0, 0x90, 0x78, 0x41, 0x74} },
+{ 0x03d6, 16, {0x03, 0xf0, 0xe5, 0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f} },
+{ 0x03e6, 16, {0x90, 0xc0, 0x00, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x01, 0xf0, 0x12, 0x00, 0x36, 0xef, 0x54, 0xfe} },
+{ 0x03f6, 16, {0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x0406, 16, {0x54, 0xfd, 0xff, 0xf0, 0xfd, 0xe4, 0xff, 0x12, 0x15, 0x3d, 0xe5, 0x27, 0x24, 0x2c, 0xf5, 0x82} },
+{ 0x0416, 16, {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x27, 0x24, 0x2b, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0426, 16, {0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x28, 0x42, 0x25, 0xe5, 0x27, 0x24, 0x1b, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x0436, 16, {0x26, 0xf5, 0x83, 0xe0, 0x70, 0x0e, 0xe5, 0x27, 0x24, 0x25, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x0446, 16, {0x83, 0xe0, 0x60, 0x28, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x0456, 16, {0x44, 0x02, 0xff, 0xf0, 0xfd, 0xe4, 0xff, 0x12, 0x15, 0x3d, 0xe5, 0x27, 0x24, 0x2b, 0xf5, 0x82} },
+{ 0x0466, 16, {0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0xe5, 0x28, 0x42, 0x25, 0xe5, 0x27, 0x24, 0x1c} },
+{ 0x0476, 16, {0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x70, 0x0e, 0xe5, 0x27, 0x24, 0x25, 0xf5, 0x82} },
+{ 0x0486, 16, {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x2c, 0x90, 0x78, 0x41, 0x74, 0x02, 0xf0, 0xe5, 0x27} },
+{ 0x0496, 16, {0x24, 0x36, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x04, 0x90, 0xc0, 0x00, 0xf0} },
+{ 0x04a6, 16, {0xe4, 0xff, 0x12, 0x14, 0x0c, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} },
+{ 0x04b6, 16, {0xe0, 0x54, 0x7f, 0xf0, 0xe5, 0x27, 0x24, 0x1d, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x04c6, 16, {0x60, 0x27, 0xe5, 0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x40} },
+{ 0x04d6, 16, {0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x04e6, 16, {0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x1e, 0xf5, 0x82, 0xe4} },
+{ 0x04f6, 16, {0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x28, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0506, 16, {0xf5, 0x83, 0xe0, 0x54, 0xfe, 0xff, 0xf0, 0xfd, 0xe4, 0xff, 0x12, 0x15, 0x3d, 0xe5, 0x27, 0x24} },
+{ 0x0516, 16, {0x2d, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0xe5, 0x28, 0x42, 0x25, 0xe5} },
+{ 0x0526, 16, {0x27, 0x24, 0x1f, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x70, 0x0e, 0xe5, 0x27, 0x24} },
+{ 0x0536, 16, {0x25, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x27, 0xe5, 0x27, 0x24, 0x32, 0xf5} },
+{ 0x0546, 16, {0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x01, 0xff, 0xf0, 0xfd, 0xe4, 0xff, 0x12, 0x15} },
+{ 0x0556, 16, {0x3d, 0xe5, 0x27, 0x24, 0x2d, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x28} },
+{ 0x0566, 16, {0x42, 0x25, 0xe5, 0x27, 0x24, 0x20, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x70, 0x0e} },
+{ 0x0576, 16, {0xe5, 0x27, 0x24, 0x25, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x18, 0x90, 0x78} },
+{ 0x0586, 16, {0x41, 0x74, 0x02, 0xf0, 0xe5, 0x27, 0x24, 0x36, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x0596, 16, {0x44, 0x02, 0x90, 0xc0, 0x00, 0xf0, 0xe5, 0x27, 0x24, 0x21, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x05a6, 16, {0x83, 0xe0, 0x60, 0x0f, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x05b6, 16, {0x44, 0x02, 0xf0, 0xe5, 0x27, 0x24, 0x22, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60} },
+{ 0x05c6, 16, {0x1f, 0xe5, 0x27, 0x24, 0x2e, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0xe5} },
+{ 0x05d6, 16, {0x27, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe4, 0xf0, 0xe5, 0x28, 0x42, 0x25} },
+{ 0x05e6, 16, {0xe5, 0x27, 0x24, 0x23, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x03, 0x12, 0x17} },
+{ 0x05f6, 16, {0x4e, 0xe5, 0x27, 0x24, 0x24, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x1b, 0xe5} },
+{ 0x0606, 16, {0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x08, 0xf0, 0x90, 0x7f} },
+{ 0x0616, 16, {0x98, 0xe0, 0xff, 0xe5, 0x28, 0xf4, 0xfe, 0xef, 0x5e, 0xf0, 0xe5, 0x27, 0x24, 0x25, 0xf5, 0x82} },
+{ 0x0626, 16, {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x60, 0x16, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x0636, 14, {0x26, 0xf5, 0x83, 0xe0, 0x54, 0xf7, 0xf0, 0x90, 0x7f, 0x98, 0xe0, 0x45, 0x28, 0xf0} },
+{ 0x0644, 1, {0x22} },
+{ 0x0645, 16, {0x90, 0x7f, 0xe9, 0xe0, 0x12, 0x11, 0xa2, 0x07, 0x42, 0x00, 0x07, 0xb6, 0x01, 0x08, 0x22, 0x03} },
+{ 0x0655, 16, {0x06, 0x68, 0x06, 0x07, 0x35, 0x08, 0x07, 0x2f, 0x09, 0x07, 0x17, 0x0a, 0x07, 0x26, 0x0b, 0x00} },
+{ 0x0665, 16, {0x00, 0x08, 0x71, 0x90, 0x7f, 0xeb, 0xe0, 0x24, 0xfe, 0x60, 0x19, 0x14, 0x60, 0x77, 0x24, 0x02} },
+{ 0x0675, 16, {0x60, 0x03, 0x02, 0x07, 0x0d, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x00, 0x90, 0x7f, 0xd5} },
+{ 0x0685, 16, {0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xea, 0xe0, 0x04, 0x75, 0x82, 0x17, 0x75, 0x83, 0x19, 0xf0} },
+{ 0x0695, 16, {0x90, 0x7f, 0xea, 0xe0, 0x30, 0xe0, 0x04, 0x7f, 0x03, 0x80, 0x02, 0x7f, 0x02, 0x75, 0x82, 0x82} },
+{ 0x06a5, 16, {0x75, 0x83, 0x19, 0xef, 0xf0, 0x75, 0x82, 0x6d, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82, 0x66, 0x75} },
+{ 0x06b5, 16, {0x83, 0x19, 0xf0, 0x75, 0x82, 0x5f, 0x75, 0x83, 0x19, 0xf0, 0x75, 0x82, 0x58, 0x75, 0x83, 0x19} },
+{ 0x06c5, 16, {0xf0, 0x90, 0x7f, 0xea, 0xe0, 0x30, 0xe1, 0x04, 0x7f, 0x64, 0x80, 0x02, 0x7f, 0x32, 0x75, 0x82} },
+{ 0x06d5, 16, {0x1a, 0x75, 0x83, 0x19, 0xef, 0xf0, 0x74, 0x19, 0x90, 0x7f, 0xd4, 0xf0, 0x74, 0x12, 0x90, 0x7f} },
+{ 0x06e5, 16, {0xd5, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xea, 0xe0, 0xff, 0x12, 0x13, 0x54, 0xea, 0x49, 0x60} },
+{ 0x06f5, 16, {0x0d, 0xea, 0x90, 0x7f, 0xd4, 0xf0, 0xe9, 0x90, 0x7f, 0xd5, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f} },
+{ 0x0705, 16, {0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02} },
+{ 0x0715, 16, {0x08, 0x78, 0x90, 0x7f, 0x00, 0xe5, 0x0a, 0xf0, 0x90, 0x7f, 0xb5, 0x74, 0x01, 0xf0, 0x02, 0x08} },
+{ 0x0725, 16, {0x78, 0x90, 0x7f, 0xea, 0xe0, 0xf5, 0x0a, 0x02, 0x08, 0x78, 0x12, 0x0a, 0x6a, 0x02, 0x08, 0x78} },
+{ 0x0735, 16, {0x90, 0x7f, 0x00, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xb5, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xe8} },
+{ 0x0745, 16, {0xe0, 0x24, 0x7f, 0x60, 0x24, 0x14, 0x60, 0x31, 0x24, 0x02, 0x70, 0x5b, 0xa2, 0x00, 0xe4, 0x33} },
+{ 0x0755, 16, {0xff, 0x25, 0xe0, 0xff, 0xa2, 0x06, 0xe4, 0x33, 0x4f, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0} },
+{ 0x0765, 16, {0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x08, 0x78, 0xe4, 0x90, 0x7f, 0x00, 0xf0, 0xa3, 0xf0} },
+{ 0x0775, 16, {0x90, 0x7f, 0xb5, 0x74, 0x02, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80} },
+{ 0x0785, 16, {0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4} },
+{ 0x0795, 16, {0x34, 0x7f, 0xf5, 0x83, 0xe0, 0x54, 0xfd, 0x90, 0x7f, 0x00, 0xf0, 0xe4, 0xa3, 0xf0, 0x90, 0x7f} },
+{ 0x07a5, 16, {0xb5, 0x74, 0x02, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x02, 0x08} },
+{ 0x07b5, 16, {0x78, 0x90, 0x7f, 0xe8, 0xe0, 0x24, 0xfe, 0x60, 0x1d, 0x24, 0x02, 0x60, 0x03, 0x02, 0x08, 0x78} },
+{ 0x07c5, 16, {0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x05, 0xc2, 0x00, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xb4, 0xe0} },
+{ 0x07d5, 16, {0x44, 0x01, 0xf0, 0x02, 0x08, 0x78, 0x90, 0x7f, 0xea, 0xe0, 0x70, 0x38, 0x90, 0x7f, 0xec, 0xe0} },
+{ 0x07e5, 16, {0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4} },
+{ 0x07f5, 16, {0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0xe4, 0xf0, 0x90, 0x7f, 0xec, 0xe0, 0x54, 0x80, 0xff} },
+{ 0x0805, 16, {0x13, 0x13, 0x13, 0x54, 0x1f, 0xff, 0xe0, 0x54, 0x07, 0x2f, 0x90, 0x7f, 0xd7, 0xf0, 0xe0, 0x44} },
+{ 0x0815, 16, {0x20, 0xf0, 0x80, 0x5f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x56, 0x90, 0x7f, 0xe8} },
+{ 0x0825, 16, {0xe0, 0x24, 0xfe, 0x60, 0x18, 0x24, 0x02, 0x70, 0x4a, 0x90, 0x7f, 0xea, 0xe0, 0xb4, 0x01, 0x04} },
+{ 0x0835, 16, {0xd2, 0x00, 0x80, 0x3f, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x36, 0x90, 0x7f, 0xea} },
+{ 0x0845, 16, {0xe0, 0x70, 0x20, 0x90, 0x7f, 0xec, 0xe0, 0xf4, 0x54, 0x80, 0xff, 0xc4, 0x54, 0x0f, 0xff, 0xe0} },
+{ 0x0855, 16, {0x54, 0x07, 0x2f, 0x25, 0xe0, 0x24, 0xb4, 0xf5, 0x82, 0xe4, 0x34, 0x7f, 0xf5, 0x83, 0x74, 0x01} },
+{ 0x0865, 16, {0xf0, 0x80, 0x10, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x01, 0xf0, 0x80, 0x07, 0x90, 0x7f, 0xb4, 0xe0} },
+{ 0x0875, 10, {0x44, 0x01, 0xf0, 0x90, 0x7f, 0xb4, 0xe0, 0x44, 0x02, 0xf0} },
+{ 0x087f, 1, {0x22} },
+{ 0x0880, 16, {0xe5, 0x23, 0x54, 0x0f, 0x70, 0x03, 0x02, 0x09, 0x5f, 0x12, 0x15, 0x9b, 0xef, 0x20, 0xe1, 0x63} },
+{ 0x0890, 16, {0x12, 0x15, 0xf9, 0xef, 0x14, 0xf5, 0x1a, 0x12, 0x17, 0xc1, 0xef, 0x25, 0x1a, 0xff, 0xe4, 0x33} },
+{ 0x08a0, 16, {0xfe, 0xc3, 0xef, 0x94, 0x80, 0xee, 0x64, 0x80, 0x94, 0x80, 0x50, 0x47, 0x85, 0x27, 0x82, 0x85} },
+{ 0x08b0, 16, {0x26, 0x83, 0xe0, 0xfe, 0xa3, 0xe0, 0xff, 0xf5, 0x82, 0x8e, 0x83, 0xe0, 0x30, 0xe0, 0x11, 0xe5} },
+{ 0x08c0, 16, {0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x80, 0xf0, 0x80, 0x0f} },
+{ 0x08d0, 16, {0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0xf0, 0x85} },
+{ 0x08e0, 16, {0x1a, 0x08, 0xef, 0x24, 0x01, 0xf5, 0x10, 0xe4, 0x3e, 0xf5, 0x0f, 0x12, 0x13, 0xd6, 0xe4, 0xff} },
+{ 0x08f0, 16, {0x12, 0x14, 0x0c, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x30} },
+{ 0x0900, 16, {0xe7, 0x5d, 0x12, 0x17, 0xc1, 0xe5, 0x27, 0x24, 0x3b, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} },
+{ 0x0910, 16, {0xe0, 0xfe, 0xef, 0xc3, 0x9e, 0x50, 0x48, 0xe5, 0x27, 0x24, 0x2f, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0920, 16, {0xf5, 0x83, 0x74, 0x01, 0xf0, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} },
+{ 0x0930, 16, {0xe0, 0x54, 0x7f, 0xf0, 0xe5, 0x27, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe4} },
+{ 0x0940, 16, {0xf0, 0xe5, 0x28, 0x42, 0x25, 0x90, 0x7f, 0xc2, 0xe0, 0x30, 0xe1, 0x10, 0xe5, 0x27, 0x24, 0x26} },
+{ 0x0950, 16, {0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xf5, 0x09, 0x80, 0x03, 0x12, 0x12, 0x3d, 0x12} },
+{ 0x0960, 16, {0x15, 0xca, 0xef, 0x30, 0xe1, 0x03, 0x02, 0x0a, 0x69, 0xe5, 0x27, 0x24, 0x38, 0xf5, 0x82, 0xe4} },
+{ 0x0970, 16, {0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x80, 0xf0, 0xe5, 0x27, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x0980, 16, {0x26, 0xf5, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfe, 0x12, 0x17, 0xcd, 0xee, 0x4f, 0xd0, 0x82} },
+{ 0x0990, 16, {0xd0, 0x83, 0xf0, 0x12, 0x16, 0xd1, 0x8f, 0x1a, 0xe5, 0x27, 0x24, 0x35, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x09a0, 16, {0x26, 0xf5, 0x83, 0xe0, 0xfe, 0xef, 0xc3, 0x9e, 0x50, 0x28, 0x12, 0x17, 0xa9, 0xef, 0x30, 0xe0} },
+{ 0x09b0, 16, {0x21, 0xe5, 0x27, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x20, 0xe7, 0x12} },
+{ 0x09c0, 16, {0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x20, 0xe1, 0x03, 0x02} },
+{ 0x09d0, 16, {0x0a, 0x69, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0xfd} },
+{ 0x09e0, 16, {0xf0, 0xe5, 0x1a, 0x70, 0x0e, 0xe5, 0x27, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} },
+{ 0x09f0, 16, {0xe4, 0xf0, 0x22, 0xe5, 0x27, 0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xff} },
+{ 0x0a00, 16, {0x30, 0xe7, 0x29, 0xe5, 0x1a, 0xd3, 0x94, 0x20, 0x40, 0x03, 0x75, 0x1a, 0x20, 0x85, 0x1a, 0x08} },
+{ 0x0a10, 16, {0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0xa3, 0xa3, 0xe0, 0xfc, 0xa3, 0xe0, 0x8c, 0x0f, 0xf5, 0x10} },
+{ 0x0a20, 16, {0x12, 0x13, 0x06, 0xe5, 0x1a, 0x25, 0xe0, 0xff, 0x12, 0x14, 0x42, 0x22, 0xe5, 0x1a, 0xd3, 0x94} },
+{ 0x0a30, 16, {0x3f, 0x40, 0x03, 0x75, 0x1a, 0x3f, 0x85, 0x1a, 0x08, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0xa3} },
+{ 0x0a40, 16, {0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0xf5, 0x82, 0x8e, 0x83, 0xe4, 0xf0, 0x85, 0x27, 0x82, 0x85, 0x26} },
+{ 0x0a50, 16, {0x83, 0xa3, 0xa3, 0xe0, 0xfe, 0xa3, 0xe0, 0x24, 0x01, 0xf5, 0x10, 0xe4, 0x3e, 0xf5, 0x0f, 0x12} },
+{ 0x0a60, 9, {0x13, 0x95, 0xe5, 0x1a, 0x04, 0xff, 0x12, 0x14, 0x42} },
+{ 0x0a69, 1, {0x22} },
+{ 0x0a6a, 16, {0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xf0, 0xf0, 0x90, 0x7f, 0x96, 0xf0, 0xe4} },
+{ 0x0a7a, 16, {0x90, 0x7f, 0x94, 0xf0, 0x90, 0x78, 0x4a, 0x04, 0xf0, 0xf5, 0x8e, 0x90, 0x7f, 0x95, 0x74, 0xc0} },
+{ 0x0a8a, 16, {0xf0, 0x90, 0x7f, 0x9e, 0x74, 0x3f, 0xf0, 0x90, 0x7f, 0x98, 0x74, 0x1f, 0xf0, 0x90, 0x78, 0x43} },
+{ 0x0a9a, 16, {0x74, 0xff, 0xf0, 0xe4, 0x90, 0x78, 0x41, 0xf0, 0x90, 0x7f, 0xdf, 0x74, 0x9f, 0xf0, 0x90, 0x7f} },
+{ 0x0aaa, 16, {0xde, 0xf0, 0x90, 0x7f, 0x92, 0xe0, 0x44, 0x02, 0xf0, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x26, 0x7b} },
+{ 0x0aba, 16, {0x75, 0x27, 0xc0, 0x90, 0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75, 0x28, 0x01, 0x12, 0x0e, 0xb3, 0x7e} },
+{ 0x0aca, 16, {0x7b, 0x7f, 0xc0, 0x75, 0x26, 0x7b, 0x75, 0x27, 0xc0, 0x90, 0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75} },
+{ 0x0ada, 16, {0x28, 0x01, 0xe5, 0x27, 0x24, 0x26, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe4, 0xf0, 0x7e} },
+{ 0x0aea, 16, {0x7e, 0x7f, 0x40, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0x74, 0x7e, 0xf0, 0xa3, 0x74, 0x40, 0xf0} },
+{ 0x0afa, 16, {0x7e, 0x7e, 0x7f, 0x80, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0xa3, 0xa3, 0x74, 0x7e, 0xf0, 0xa3} },
+{ 0x0b0a, 16, {0x74, 0x80, 0xf0, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x00, 0x90, 0x7f, 0x96} },
+{ 0x0b1a, 16, {0x74, 0xdf, 0xf0, 0x75, 0x28, 0x02, 0x12, 0x0e, 0xb3, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x26, 0x7c} },
+{ 0x0b2a, 16, {0x75, 0x27, 0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75, 0x28, 0x02, 0xe5, 0x27, 0x24, 0x26} },
+{ 0x0b3a, 16, {0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x7e, 0x7d, 0x7f, 0xc0, 0x85, 0x27} },
+{ 0x0b4a, 16, {0x82, 0x85, 0x26, 0x83, 0x74, 0x7d, 0xf0, 0xa3, 0x74, 0xc0, 0xf0, 0x7e, 0x7e, 0x7f, 0x00, 0x85} },
+{ 0x0b5a, 16, {0x27, 0x82, 0x85, 0x26, 0x83, 0xa3, 0xa3, 0x74, 0x7e, 0xf0, 0xa3, 0x74, 0x00, 0xf0, 0x7e, 0x7c} },
+{ 0x0b6a, 16, {0x7f, 0x40, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x40, 0x90, 0x7f, 0x96, 0x74, 0xbf, 0xf0, 0x75, 0x28} },
+{ 0x0b7a, 16, {0x04, 0x12, 0x0e, 0xb3, 0x7e, 0x7c, 0x7f, 0x40, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x40, 0x90, 0x7f} },
+{ 0x0b8a, 16, {0x96, 0x74, 0xbf, 0xf0, 0x75, 0x28, 0x04, 0xe5, 0x27, 0x24, 0x26, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0b9a, 16, {0xf5, 0x83, 0x74, 0x02, 0xf0, 0x7e, 0x7d, 0x7f, 0x40, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0x74} },
+{ 0x0baa, 16, {0x7d, 0xf0, 0xa3, 0x74, 0x40, 0xf0, 0x7e, 0x7d, 0x7f, 0x80, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83} },
+{ 0x0bba, 16, {0xa3, 0xa3, 0x74, 0x7d, 0xf0, 0xa3, 0x74, 0x80, 0xf0, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x26, 0x7c} },
+{ 0x0bca, 16, {0x75, 0x27, 0x80, 0x90, 0x7f, 0x96, 0x74, 0x7f, 0xf0, 0x75, 0x28, 0x08, 0x12, 0x0e, 0xb3, 0x7e} },
+{ 0x0bda, 16, {0x7c, 0x7f, 0x80, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x80, 0x90, 0x7f, 0x96, 0x74, 0x7f, 0xf0, 0x75} },
+{ 0x0bea, 16, {0x28, 0x08, 0xe5, 0x27, 0x24, 0x26, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x03, 0xf0} },
+{ 0x0bfa, 16, {0x7e, 0x7c, 0x7f, 0xc0, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0x74, 0x7c, 0xf0, 0xa3, 0x74, 0xc0} },
+{ 0x0c0a, 16, {0xf0, 0x7e, 0x7d, 0x7f, 0x00, 0x85, 0x27, 0x82, 0x85, 0x26, 0x83, 0xa3, 0xa3, 0x74, 0x7d, 0xf0} },
+{ 0x0c1a, 7, {0xa3, 0x74, 0x00, 0xf0, 0xd2, 0x02, 0x22} },
+{ 0x0c21, 16, {0xe5, 0x22, 0x04, 0x54, 0x03, 0xf5, 0x22, 0x14, 0x60, 0x1f, 0x14, 0x60, 0x31, 0x14, 0x60, 0x43} },
+{ 0x0c31, 16, {0x24, 0x03, 0x70, 0x52, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x26, 0x7b, 0x75, 0x27, 0xc0, 0x90, 0x7f} },
+{ 0x0c41, 16, {0x96, 0x74, 0xef, 0xf0, 0x75, 0x28, 0x01, 0x80, 0x3d, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x26, 0x7c} },
+{ 0x0c51, 16, {0x75, 0x27, 0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75, 0x28, 0x02, 0x80, 0x28, 0x7e, 0x7c} },
+{ 0x0c61, 16, {0x7f, 0x40, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x40, 0x90, 0x7f, 0x96, 0x74, 0xbf, 0xf0, 0x75, 0x28} },
+{ 0x0c71, 16, {0x04, 0x80, 0x13, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x80, 0x90, 0x7f, 0x96} },
+{ 0x0c81, 16, {0x74, 0x7f, 0xf0, 0x75, 0x28, 0x08, 0xe5, 0x15, 0x55, 0x28, 0x70, 0x03, 0x02, 0x0d, 0xbf, 0xe5} },
+{ 0x0c91, 16, {0x28, 0xf4, 0xff, 0x52, 0x15, 0xe5, 0x0b, 0x54, 0x7f, 0xfe, 0x70, 0x0f, 0xe5, 0x0d, 0x55, 0x28} },
+{ 0x0ca1, 16, {0x60, 0x24, 0x90, 0x7f, 0x98, 0xe0, 0x45, 0x28, 0xf0, 0x80, 0x1b, 0xbe, 0x20, 0x18, 0xe5, 0x27} },
+{ 0x0cb1, 16, {0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x30, 0xe3, 0x09, 0xe4, 0xf5, 0x0d} },
+{ 0x0cc1, 16, {0x90, 0x7f, 0x98, 0xe0, 0x5f, 0xf0, 0xe5, 0x27, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x0cd1, 16, {0x83, 0xe0, 0x60, 0x03, 0xe0, 0x14, 0xf0, 0xe5, 0x27, 0x24, 0x34, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0ce1, 16, {0xf5, 0x83, 0xe0, 0x60, 0x03, 0xe0, 0x14, 0xf0, 0xe0, 0x60, 0x03, 0x02, 0x0d, 0xbf, 0x74, 0x0a} },
+{ 0x0cf1, 16, {0xf0, 0x12, 0x00, 0x36, 0xef, 0x54, 0x01, 0xff, 0xf5, 0x1a, 0xe5, 0x27, 0x24, 0x2c, 0xf5, 0x82} },
+{ 0x0d01, 16, {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x6f, 0x60, 0x07, 0xe5, 0x1a, 0xf0, 0xe5, 0x28, 0x42, 0x25} },
+{ 0x0d11, 16, {0x12, 0x17, 0xd9, 0x8f, 0x1a, 0xe5, 0x27, 0x24, 0x27, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83} },
+{ 0x0d21, 16, {0xe0, 0xff, 0xe5, 0x1a, 0x54, 0x10, 0xfe, 0x6f, 0x60, 0x06, 0xee, 0xf0, 0xe5, 0x28, 0x42, 0x25} },
+{ 0x0d31, 16, {0xe5, 0x27, 0x24, 0x28, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x1a, 0x54} },
+{ 0x0d41, 16, {0x80, 0xfe, 0x6f, 0x60, 0x06, 0xee, 0xf0, 0xe5, 0x28, 0x42, 0x25, 0xe5, 0x27, 0x24, 0x29, 0xf5} },
+{ 0x0d51, 16, {0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0xff, 0xe5, 0x1a, 0x54, 0x20, 0xfe, 0x6f, 0x60, 0x15} },
+{ 0x0d61, 16, {0xee, 0xf0, 0xe5, 0x27, 0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x30, 0xe4} },
+{ 0x0d71, 16, {0x04, 0xe5, 0x28, 0x42, 0x25, 0xe5, 0x24, 0x55, 0x28, 0xff, 0xf5, 0x1a, 0xe5, 0x27, 0x24, 0x2a} },
+{ 0x0d81, 16, {0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x6f, 0x60, 0x16, 0xe5, 0x1a, 0xf0, 0xe5, 0x27} },
+{ 0x0d91, 16, {0x24, 0x31, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x30, 0xe5, 0x04, 0xe5, 0x28, 0x42} },
+{ 0x0da1, 16, {0x25, 0xe5, 0x29, 0x55, 0x28, 0xff, 0xf5, 0x1a, 0xe5, 0x27, 0x24, 0x30, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x0db1, 14, {0x26, 0xf5, 0x83, 0xe0, 0x6f, 0x60, 0x07, 0xe5, 0x1a, 0xf0, 0xe5, 0x28, 0x42, 0x25} },
+{ 0x0dbf, 1, {0x22} },
+{ 0x0dc0, 16, {0xe5, 0x09, 0x14, 0x60, 0x2a, 0x14, 0x60, 0x41, 0x14, 0x60, 0x58, 0x14, 0x60, 0x6f, 0x24, 0x04} },
+{ 0x0dd0, 16, {0x60, 0x03, 0x02, 0x0e, 0x77, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x26, 0x7b, 0x75, 0x27, 0xc0, 0x90} },
+{ 0x0de0, 16, {0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75, 0x28, 0x01, 0x12, 0x12, 0x3d, 0x75, 0x09, 0x01, 0x22, 0x7e} },
+{ 0x0df0, 16, {0x7c, 0x7f, 0x00, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75} },
+{ 0x0e00, 16, {0x28, 0x02, 0x12, 0x12, 0x3d, 0x75, 0x09, 0x02, 0x22, 0x7e, 0x7c, 0x7f, 0x40, 0x75, 0x26, 0x7c} },
+{ 0x0e10, 16, {0x75, 0x27, 0x40, 0x90, 0x7f, 0x96, 0x74, 0xbf, 0xf0, 0x75, 0x28, 0x04, 0x12, 0x12, 0x3d, 0x75} },
+{ 0x0e20, 16, {0x09, 0x03, 0x22, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x80, 0x90, 0x7f, 0x96} },
+{ 0x0e30, 16, {0x74, 0x7f, 0xf0, 0x75, 0x28, 0x08, 0x12, 0x12, 0x3d, 0x75, 0x09, 0x04, 0x22, 0x30, 0x04, 0x33} },
+{ 0x0e40, 16, {0xc2, 0x04, 0x53, 0x25, 0xdf, 0xe4, 0xf5, 0x1a, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x11, 0x25, 0x1a} },
+{ 0x0e50, 16, {0xf9, 0xee, 0x34, 0x00, 0xfa, 0x12, 0x11, 0x4a, 0xff, 0x74, 0x80, 0x25, 0x1a, 0xf5, 0x82, 0xe4} },
+{ 0x0e60, 16, {0x34, 0x7b, 0xf5, 0x83, 0xef, 0xf0, 0x05, 0x1a, 0xe5, 0x1a, 0xb4, 0x03, 0xdb, 0x90, 0x7f, 0xc3} },
+{ 0x0e70, 16, {0x74, 0x03, 0xf0, 0x75, 0x09, 0x05, 0x22, 0xe5, 0x17, 0x60, 0x34, 0xd5, 0x17, 0x03, 0x53, 0x25} },
+{ 0x0e80, 16, {0xef, 0xe4, 0xf5, 0x1a, 0x7e, 0x00, 0x7b, 0x00, 0x74, 0x16, 0x25, 0x1a, 0xf9, 0xee, 0x34, 0x00} },
+{ 0x0e90, 16, {0xfa, 0x12, 0x11, 0x4a, 0xff, 0x74, 0x80, 0x25, 0x1a, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83} },
+{ 0x0ea0, 16, {0xef, 0xf0, 0x05, 0x1a, 0xe5, 0x1a, 0xb4, 0x03, 0xdb, 0x90, 0x7f, 0xc3, 0x74, 0x03, 0xf0, 0xe4} },
+{ 0x0eb0, 2, {0xf5, 0x09} },
+{ 0x0eb2, 1, {0x22} },
+{ 0x0eb3, 16, {0xe4, 0xf5, 0x19, 0x7e, 0x00, 0x7b, 0x01, 0xe5, 0x27, 0x25, 0x19, 0xf9, 0xee, 0x35, 0x26, 0xfa} },
+{ 0x0ec3, 16, {0xe4, 0x12, 0x11, 0x90, 0x05, 0x19, 0xe5, 0x19, 0xb4, 0x3c, 0xe8, 0xe5, 0x27, 0x24, 0x35, 0xf5} },
+{ 0x0ed3, 16, {0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x01, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5} },
+{ 0x0ee3, 16, {0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00} },
+{ 0x0ef3, 16, {0xf0, 0x7f, 0x0c, 0xe4, 0xfd, 0x12, 0x15, 0x3d, 0x7f, 0x10, 0xe5, 0x27, 0x24, 0x33, 0xf5, 0x82} },
+{ 0x0f03, 16, {0xe4, 0x35, 0x26, 0xf5, 0x83, 0xef, 0xf0, 0x12, 0x14, 0xad, 0x90, 0x78, 0x41, 0x74, 0x02, 0xf0} },
+{ 0x0f13, 16, {0x7f, 0x01, 0xe5, 0x27, 0x24, 0x36, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xef, 0xf0, 0x44} },
+{ 0x0f23, 16, {0x06, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0xe5, 0x27, 0x24, 0x39, 0xf5} },
+{ 0x0f33, 16, {0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0x74, 0x80, 0xf0, 0x90, 0xc0, 0x00, 0xf0, 0x0f, 0xe4, 0xfd} },
+{ 0x0f43, 16, {0x12, 0x15, 0x3d, 0xe4, 0xff, 0x7e, 0xa3, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x26} },
+{ 0x0f53, 16, {0xf5, 0x83, 0xee, 0xf0, 0xfd, 0x12, 0x15, 0x3d, 0x90, 0x78, 0x41, 0x74, 0x01, 0xf0, 0x90, 0xc0} },
+{ 0x0f63, 16, {0x00, 0xe4, 0xf0, 0x7f, 0x05, 0x7d, 0x7f, 0x12, 0x15, 0x3d, 0x7f, 0x01, 0x12, 0x14, 0x78, 0x7f} },
+{ 0x0f73, 6, {0x03, 0x7d, 0x07, 0x12, 0x15, 0x3d} },
+{ 0x0f79, 1, {0x22} },
+{ 0x0f7a, 16, {0x53, 0x25, 0x3f, 0x90, 0x7b, 0xf1, 0xe0, 0x30, 0xe3, 0x16, 0x7e, 0x7b, 0x7f, 0xc0, 0x75, 0x26} },
+{ 0x0f8a, 16, {0x7b, 0x75, 0x27, 0xc0, 0x90, 0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75, 0x28, 0x01, 0x12, 0x08, 0x80} },
+{ 0x0f9a, 16, {0x90, 0x7c, 0x31, 0xe0, 0x30, 0xe3, 0x16, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x26, 0x7c, 0x75, 0x27} },
+{ 0x0faa, 16, {0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75, 0x28, 0x02, 0x12, 0x08, 0x80, 0x90, 0x7c, 0x71} },
+{ 0x0fba, 16, {0xe0, 0x30, 0xe3, 0x16, 0x7e, 0x7c, 0x7f, 0x40, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x40, 0x90, 0x7f} },
+{ 0x0fca, 16, {0x96, 0x74, 0xbf, 0xf0, 0x75, 0x28, 0x04, 0x12, 0x08, 0x80, 0x90, 0x7c, 0xb1, 0xe0, 0x30, 0xe3} },
+{ 0x0fda, 16, {0x16, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x80, 0x90, 0x7f, 0x96, 0x74, 0x7f} },
+{ 0x0fea, 16, {0xf0, 0x75, 0x28, 0x08, 0x12, 0x08, 0x80, 0x05, 0x23, 0xe5, 0x23, 0x54, 0x0f, 0xf5, 0x19, 0x70} },
+{ 0x0ffa, 16, {0x1f, 0x90, 0x78, 0x41, 0xe0, 0x54, 0xf7, 0xf0, 0x90, 0x7f, 0x99, 0xe0, 0xf5, 0x29, 0x90, 0x78} },
+{ 0x100a, 16, {0x41, 0xe0, 0x44, 0x08, 0xf0, 0x90, 0x7f, 0x99, 0xe0, 0xf4, 0xf5, 0x24, 0x12, 0x10, 0xc2, 0x22} },
+{ 0x101a, 16, {0xe5, 0x19, 0xb4, 0x01, 0x04, 0x12, 0x0c, 0x21, 0x22, 0x90, 0x7f, 0xc2, 0xe0, 0x20, 0xe1, 0x08} },
+{ 0x102a, 11, {0xe5, 0x25, 0x60, 0x04, 0x12, 0x0d, 0xc0, 0x22, 0x12, 0x0c, 0x21} },
+{ 0x1035, 1, {0x22} },
+{ 0x1036, 12, {0x78, 0x7f, 0xe4, 0xf6, 0xd8, 0xfd, 0x75, 0x81, 0x29, 0x02, 0x10, 0x7d} },
+{ 0x1042, 16, {0x02, 0x11, 0xc8, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0x40, 0x03, 0xf6, 0x80, 0x01, 0xf2} },
+{ 0x1052, 16, {0x08, 0xdf, 0xf4, 0x80, 0x29, 0xe4, 0x93, 0xa3, 0xf8, 0x54, 0x07, 0x24, 0x0c, 0xc8, 0xc3, 0x33} },
+{ 0x1062, 16, {0xc4, 0x54, 0x0f, 0x44, 0x20, 0xc8, 0x83, 0x40, 0x04, 0xf4, 0x56, 0x80, 0x01, 0x46, 0xf6, 0xdf} },
+{ 0x1072, 16, {0xe4, 0x80, 0x0b, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x90, 0x17, 0x67, 0xe4, 0x7e} },
+{ 0x1082, 16, {0x01, 0x93, 0x60, 0xbc, 0xa3, 0xff, 0x54, 0x3f, 0x30, 0xe5, 0x09, 0x54, 0x1f, 0xfe, 0xe4, 0x93} },
+{ 0x1092, 16, {0xa3, 0x60, 0x01, 0x0e, 0xcf, 0x54, 0xc0, 0x25, 0xe0, 0x60, 0xa8, 0x40, 0xb8, 0xe4, 0x93, 0xa3} },
+{ 0x10a2, 16, {0xfa, 0xe4, 0x93, 0xa3, 0xf8, 0xe4, 0x93, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca} },
+{ 0x10b2, 16, {0xf0, 0xa3, 0xc8, 0xc5, 0x82, 0xc8, 0xca, 0xc5, 0x83, 0xca, 0xdf, 0xe9, 0xde, 0xe7, 0x80, 0xbe} },
+{ 0x10c2, 16, {0x90, 0x7f, 0xd2, 0xe0, 0x30, 0xe1, 0x03, 0x02, 0x11, 0x49, 0x90, 0x7b, 0x40, 0xe0, 0x14, 0x60} },
+{ 0x10d2, 16, {0x26, 0x14, 0x60, 0x3b, 0x14, 0x60, 0x50, 0x24, 0x83, 0x60, 0x64, 0x24, 0x80, 0x70, 0x63, 0x7e} },
+{ 0x10e2, 16, {0x7b, 0x7f, 0xc0, 0x75, 0x26, 0x7b, 0x75, 0x27, 0xc0, 0x90, 0x7f, 0x96, 0x74, 0xef, 0xf0, 0x75} },
+{ 0x10f2, 16, {0x28, 0x01, 0x12, 0x00, 0x46, 0x80, 0x4b, 0x7e, 0x7c, 0x7f, 0x00, 0x75, 0x26, 0x7c, 0x75, 0x27} },
+{ 0x1102, 16, {0x00, 0x90, 0x7f, 0x96, 0x74, 0xdf, 0xf0, 0x75, 0x28, 0x02, 0x12, 0x00, 0x46, 0x80, 0x33, 0x7e} },
+{ 0x1112, 16, {0x7c, 0x7f, 0x40, 0x75, 0x26, 0x7c, 0x75, 0x27, 0x40, 0x90, 0x7f, 0x96, 0x74, 0xbf, 0xf0, 0x75} },
+{ 0x1122, 16, {0x28, 0x04, 0x12, 0x00, 0x46, 0x80, 0x1b, 0x7e, 0x7c, 0x7f, 0x80, 0x75, 0x26, 0x7c, 0x75, 0x27} },
+{ 0x1132, 16, {0x80, 0x90, 0x7f, 0x96, 0x74, 0x7f, 0xf0, 0x75, 0x28, 0x08, 0x12, 0x00, 0x46, 0x80, 0x03, 0x12} },
+{ 0x1142, 8, {0x16, 0x56, 0xe4, 0x90, 0x7f, 0xd3, 0xf0, 0x22} },
+{ 0x114a, 16, {0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xe0, 0x22, 0x50, 0x02, 0xe7, 0x22, 0xbb, 0xfe, 0x02} },
+{ 0x115a, 9, {0xe3, 0x22, 0x89, 0x82, 0x8a, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x1163, 16, {0xbb, 0x01, 0x0c, 0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe0, 0x22, 0x50} },
+{ 0x1173, 16, {0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe6, 0x22, 0xbb, 0xfe, 0x06, 0xe9, 0x25, 0x82, 0xf8, 0xe2, 0x22} },
+{ 0x1183, 13, {0xe5, 0x82, 0x29, 0xf5, 0x82, 0xe5, 0x83, 0x3a, 0xf5, 0x83, 0xe4, 0x93, 0x22} },
+{ 0x1190, 16, {0xbb, 0x01, 0x06, 0x89, 0x82, 0x8a, 0x83, 0xf0, 0x22, 0x50, 0x02, 0xf7, 0x22, 0xbb, 0xfe, 0x01} },
+{ 0x11a0, 2, {0xf3, 0x22} },
+{ 0x11a2, 16, {0xd0, 0x83, 0xd0, 0x82, 0xf8, 0xe4, 0x93, 0x70, 0x12, 0x74, 0x01, 0x93, 0x70, 0x0d, 0xa3, 0xa3} },
+{ 0x11b2, 16, {0x93, 0xf8, 0x74, 0x01, 0x93, 0xf5, 0x82, 0x88, 0x83, 0xe4, 0x73, 0x74, 0x02, 0x93, 0x68, 0x60} },
+{ 0x11c2, 6, {0xef, 0xa3, 0xa3, 0xa3, 0x80, 0xdf} },
+{ 0x11c8, 16, {0x90, 0x7f, 0xae, 0xe0, 0xff, 0xd3, 0x92, 0x00, 0xe4, 0x33, 0xfe, 0xef, 0x4e, 0xf0, 0xd2, 0xe8} },
+{ 0x11d8, 16, {0x43, 0xd8, 0x20, 0x90, 0x7f, 0xde, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xdf, 0xf0, 0x90, 0x7f, 0xab} },
+{ 0x11e8, 16, {0x74, 0xff, 0xf0, 0x90, 0x7f, 0xa9, 0xf0, 0x90, 0x7f, 0xaa, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f} },
+{ 0x11f8, 16, {0xaf, 0x74, 0x01, 0xf0, 0x90, 0x7f, 0xae, 0x74, 0x0d, 0xf0, 0xd2, 0xaf, 0xd2, 0x09, 0x12, 0x17} },
+{ 0x1208, 16, {0x13, 0xc2, 0x01, 0xe4, 0xf5, 0x0e, 0xf5, 0x14, 0xc2, 0x07, 0xc2, 0x02, 0x90, 0x7f, 0xd8, 0xe0} },
+{ 0x1218, 16, {0x65, 0x0b, 0x60, 0x06, 0x75, 0x15, 0x0f, 0xe0, 0xf5, 0x0b, 0x30, 0x02, 0x03, 0x12, 0x0f, 0x7a} },
+{ 0x1228, 16, {0x30, 0x01, 0x07, 0xc2, 0x01, 0x12, 0x06, 0x45, 0x80, 0xe2, 0x30, 0x08, 0xdf, 0xc2, 0x08, 0x12} },
+{ 0x1238, 5, {0x17, 0x95, 0x80, 0xd8, 0x22} },
+{ 0x123d, 16, {0xe5, 0x25, 0x55, 0x28, 0x60, 0x6a, 0xe5, 0x27, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x124d, 16, {0x83, 0xe0, 0x70, 0x5c, 0xe5, 0x28, 0xf4, 0x52, 0x25, 0xe5, 0x27, 0x24, 0x26, 0xff, 0xe4, 0x35} },
+{ 0x125d, 16, {0x26, 0xfe, 0xe4, 0xfd, 0x0f, 0xef, 0xaa, 0x06, 0x70, 0x01, 0x0e, 0x14, 0xf5, 0x82, 0x8a, 0x83} },
+{ 0x126d, 16, {0xe0, 0xfc, 0x74, 0x80, 0x2d, 0xf5, 0x82, 0xe4, 0x34, 0x7b, 0xf5, 0x83, 0xec, 0xf0, 0x0d, 0xbd} },
+{ 0x127d, 16, {0x0b, 0xe2, 0x90, 0x7f, 0xc3, 0x74, 0x0b, 0xf0, 0xe5, 0x27, 0x24, 0x3a, 0xf5, 0x82, 0xe4, 0x35} },
+{ 0x128d, 16, {0x26, 0xf5, 0x83, 0x74, 0x10, 0xf0, 0xe5, 0x27, 0x24, 0x2e, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x129d, 16, {0x83, 0xe4, 0xf0, 0xe5, 0x27, 0x24, 0x2f, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe4, 0xf0} },
+{ 0x12ad, 1, {0x22} },
+{ 0x12ae, 16, {0xe4, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xf0, 0xf0, 0x90, 0x7f, 0x96, 0xf0, 0xe4} },
+{ 0x12be, 16, {0x90, 0x78, 0x4a, 0xf0, 0x90, 0x7f, 0x94, 0xf0, 0x90, 0x7f, 0x9d, 0x74, 0xff, 0xf0, 0xe4, 0x90} },
+{ 0x12ce, 16, {0x7f, 0x97, 0xf0, 0xe5, 0x0c, 0x54, 0xf0, 0x44, 0x08, 0x90, 0x78, 0x41, 0xf0, 0xe4, 0x90, 0x7f} },
+{ 0x12de, 16, {0x98, 0xf0, 0x90, 0x7f, 0x95, 0xf0, 0x90, 0x7f, 0x9e, 0x74, 0xff, 0xf0, 0xe4, 0x90, 0x7f, 0x98} },
+{ 0x12ee, 16, {0xf0, 0x90, 0x7f, 0x93, 0xf0, 0x90, 0x7f, 0x9c, 0x74, 0xf0, 0xf0, 0xe4, 0x90, 0x7f, 0x96, 0xf0} },
+{ 0x12fe, 8, {0x90, 0x7f, 0x92, 0xe0, 0x54, 0xfd, 0xf0, 0x22} },
+{ 0x1306, 16, {0x8f, 0x1b, 0x05, 0x10, 0xe5, 0x10, 0xae, 0x0f, 0x70, 0x02, 0x05, 0x0f, 0x14, 0xf5, 0x82, 0x8e} },
+{ 0x1316, 16, {0x83, 0xe5, 0x1b, 0xf0, 0x12, 0x17, 0xe5, 0x05, 0x10, 0xe5, 0x10, 0xac, 0x0f, 0x70, 0x02, 0x05} },
+{ 0x1326, 16, {0x0f, 0x14, 0xf5, 0x82, 0x8c, 0x83, 0xef, 0xf0, 0x15, 0x08, 0xe5, 0x08, 0x60, 0x1f, 0xe5, 0x27} },
+{ 0x1336, 16, {0x24, 0x38, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xc0, 0x83, 0xc0, 0x82, 0xe0, 0xfe, 0x12} },
+{ 0x1346, 14, {0x17, 0xcd, 0x8f, 0x1b, 0xee, 0x4f, 0xd0, 0x82, 0xd0, 0x83, 0xf0, 0x80, 0xb5, 0x22} },
+{ 0x1354, 2, {0x8f, 0x19} },
+{ 0x1356, 16, {0xe4, 0xf5, 0x1a, 0x75, 0x1b, 0xff, 0x75, 0x1c, 0x19, 0x75, 0x1d, 0x86, 0xab, 0x1b, 0xaa, 0x1c} },
+{ 0x1366, 16, {0xa9, 0x1d, 0x90, 0x00, 0x01, 0x12, 0x11, 0x63, 0xb4, 0x03, 0x1d, 0xaf, 0x1a, 0x05, 0x1a, 0xef} },
+{ 0x1376, 16, {0xb5, 0x19, 0x01, 0x22, 0x12, 0x11, 0x4a, 0x7e, 0x00, 0x29, 0xff, 0xee, 0x3a, 0xa9, 0x07, 0x75} },
+{ 0x1386, 14, {0x1b, 0xff, 0xf5, 0x1c, 0x89, 0x1d, 0x80, 0xd4, 0x7b, 0x00, 0x7a, 0x00, 0x79, 0x00} },
+{ 0x1394, 1, {0x22} },
+{ 0x1395, 16, {0xe4, 0x90, 0x78, 0x41, 0xf0, 0x90, 0x78, 0x4f, 0x74, 0xc0, 0xf0, 0xe4, 0x90, 0x78, 0x50, 0xf0} },
+{ 0x13a5, 16, {0xe5, 0x0f, 0x90, 0x78, 0x51, 0xf0, 0xae, 0x0f, 0xe5, 0x10, 0x90, 0x78, 0x52, 0xf0, 0x90, 0x78} },
+{ 0x13b5, 16, {0x54, 0xe5, 0x08, 0xf0, 0x90, 0x78, 0x57, 0x74, 0x04, 0xf0, 0x90, 0x7f, 0xe2, 0xe0, 0x44, 0x10} },
+{ 0x13c5, 16, {0xf0, 0xe0, 0x54, 0xf7, 0xf0, 0xe4, 0x90, 0x78, 0x55, 0xf0, 0x90, 0x78, 0x55, 0xe0, 0x60, 0xfa} },
+{ 0x13d5, 1, {0x22} },
+{ 0x13d6, 16, {0xe4, 0x90, 0x78, 0x41, 0xf0, 0xe5, 0x0f, 0x90, 0x78, 0x4f, 0xf0, 0xae, 0x0f, 0xe5, 0x10, 0x90} },
+{ 0x13e6, 16, {0x78, 0x50, 0xf0, 0x90, 0x78, 0x51, 0x74, 0xc0, 0xf0, 0xe4, 0x90, 0x78, 0x52, 0xf0, 0x90, 0x78} },
+{ 0x13f6, 16, {0x54, 0xe5, 0x08, 0xf0, 0x90, 0x78, 0x57, 0x74, 0x04, 0xf0, 0xe4, 0x90, 0x78, 0x55, 0xf0, 0x90} },
+{ 0x1406, 6, {0x78, 0x55, 0xe0, 0x60, 0xfa, 0x22} },
+{ 0x140c, 16, {0xe5, 0x27, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0f, 0x14} },
+{ 0x141c, 16, {0x60, 0x13, 0x14, 0x60, 0x17, 0x80, 0x00, 0x90, 0x7f, 0xc7, 0xef, 0xf0, 0x80, 0x13, 0x90, 0x7f} },
+{ 0x142c, 16, {0xc9, 0xef, 0xf0, 0x80, 0x0c, 0x90, 0x7f, 0xcb, 0xef, 0xf0, 0x80, 0x05, 0x90, 0x7f, 0xcd, 0xef} },
+{ 0x143c, 6, {0xf0, 0xe5, 0x28, 0x42, 0x0d, 0x22} },
+{ 0x1442, 16, {0xe5, 0x27, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0f, 0x14} },
+{ 0x1452, 16, {0x60, 0x13, 0x14, 0x60, 0x17, 0x80, 0x00, 0x90, 0x7f, 0xb7, 0xef, 0xf0, 0x80, 0x13, 0x90, 0x7f} },
+{ 0x1462, 16, {0xb9, 0xef, 0xf0, 0x80, 0x0c, 0x90, 0x7f, 0xbb, 0xef, 0xf0, 0x80, 0x05, 0x90, 0x7f, 0xbd, 0xef} },
+{ 0x1472, 6, {0xf0, 0xe5, 0x28, 0x42, 0x0d, 0x22} },
+{ 0x1478, 16, {0xae, 0x07, 0xe4, 0xff, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0} },
+{ 0x1488, 16, {0x54, 0x7f, 0xfd, 0x12, 0x15, 0x3d, 0x90, 0x78, 0x41, 0x74, 0x01, 0xf0, 0x90, 0xc0, 0x00, 0xee} },
+{ 0x1498, 16, {0xf0, 0xe4, 0xe5, 0x27, 0x24, 0x32, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x44, 0x80} },
+{ 0x14a8, 5, {0xfd, 0x12, 0x15, 0x3d, 0x22} },
+{ 0x14ad, 16, {0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x78, 0x41, 0x74} },
+{ 0x14bd, 16, {0x02, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24} },
+{ 0x14cd, 16, {0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x14dd, 16, {0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x78, 0x41, 0x74} },
+{ 0x14ed, 16, {0x04, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24} },
+{ 0x14fd, 16, {0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x150d, 16, {0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0x90, 0x78, 0x41, 0x74} },
+{ 0x151d, 16, {0x06, 0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24} },
+{ 0x152d, 16, {0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x153d, 16, {0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24, 0x37, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5} },
+{ 0x154d, 16, {0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x07, 0xf0, 0x90, 0xc0} },
+{ 0x155d, 15, {0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x05, 0xf0, 0x90, 0xc0, 0x00, 0xed, 0xf0, 0x22} },
+{ 0x156c, 16, {0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0x74, 0xbf, 0xf0, 0xe4, 0x90, 0x78, 0x41} },
+{ 0x157c, 16, {0xf0, 0x90, 0xc0, 0x00, 0xef, 0xf0, 0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0xe5, 0x27, 0x24, 0x37} },
+{ 0x158c, 15, {0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x54, 0x7f, 0x90, 0xc0, 0x00, 0xf0, 0x22} },
+{ 0x159b, 16, {0xe5, 0x27, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0e, 0x14} },
+{ 0x15ab, 16, {0x60, 0x11, 0x14, 0x60, 0x14, 0x80, 0x00, 0x90, 0x7f, 0xc6, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xc8} },
+{ 0x15bb, 15, {0xe0, 0xff, 0x22, 0x90, 0x7f, 0xca, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xcc, 0xe0, 0xff, 0x22} },
+{ 0x15ca, 16, {0xe5, 0x27, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0e, 0x14} },
+{ 0x15da, 16, {0x60, 0x11, 0x14, 0x60, 0x14, 0x80, 0x00, 0x90, 0x7f, 0xb6, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xb8} },
+{ 0x15ea, 15, {0xe0, 0xff, 0x22, 0x90, 0x7f, 0xba, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xbc, 0xe0, 0xff, 0x22} },
+{ 0x15f9, 16, {0xe5, 0x27, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x14, 0x60, 0x0e, 0x14} },
+{ 0x1609, 16, {0x60, 0x11, 0x14, 0x60, 0x14, 0x80, 0x00, 0x90, 0x7f, 0xc7, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xc9} },
+{ 0x1619, 15, {0xe0, 0xff, 0x22, 0x90, 0x7f, 0xcb, 0xe0, 0xff, 0x22, 0x90, 0x7f, 0xcd, 0xe0, 0xff, 0x22} },
+{ 0x1628, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x30} },
+{ 0x1638, 16, {0x05, 0x04, 0xc2, 0x05, 0x80, 0x02, 0xd2, 0x08, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x08} },
+{ 0x1648, 14, {0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x1656, 16, {0x90, 0x7b, 0x41, 0xe0, 0xf5, 0x17, 0x43, 0x25, 0x10, 0xa3, 0xe0, 0x60, 0x09, 0x90, 0x7f, 0xd7} },
+{ 0x1666, 16, {0x74, 0x17, 0xf0, 0x74, 0x37, 0xf0, 0x90, 0x7b, 0x43, 0xe0, 0xf5, 0x18, 0x30, 0x00, 0x07, 0xa3} },
+{ 0x1676, 10, {0xe0, 0x54, 0xf0, 0xf5, 0x0c, 0x22, 0xe4, 0xf5, 0x0c, 0x22} },
+{ 0x1680, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0x90} },
+{ 0x1690, 16, {0x7f, 0xc4, 0xe4, 0xf0, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x04, 0xf0, 0xd0, 0x86, 0xd0} },
+{ 0x16a0, 10, {0x84, 0xd0, 0x85, 0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x16aa, 16, {0xc0, 0xe0, 0xc0, 0x83, 0xc0, 0x82, 0xc0, 0x85, 0xc0, 0x84, 0xc0, 0x86, 0x75, 0x86, 0x00, 0xd2} },
+{ 0x16ba, 16, {0x01, 0x53, 0x91, 0xef, 0x90, 0x7f, 0xab, 0x74, 0x01, 0xf0, 0xd0, 0x86, 0xd0, 0x84, 0xd0, 0x85} },
+{ 0x16ca, 7, {0xd0, 0x82, 0xd0, 0x83, 0xd0, 0xe0, 0x32} },
+{ 0x16d1, 16, {0x12, 0x17, 0xb5, 0xae, 0x07, 0x12, 0x17, 0xb5, 0xad, 0x07, 0xee, 0x6d, 0x60, 0x10, 0x12, 0x17} },
+{ 0x16e1, 16, {0xb5, 0xae, 0x07, 0xee, 0x6d, 0x60, 0x07, 0x12, 0x17, 0xb5, 0xad, 0x07, 0x80, 0xec, 0xaf, 0x06} },
+{ 0x16f1, 1, {0x22} },
+{ 0x16f2, 16, {0x74, 0x00, 0xf5, 0x86, 0x90, 0xfd, 0xa5, 0x7c, 0x05, 0xa3, 0xe5, 0x82, 0x45, 0x83, 0x70, 0xf9} },
+{ 0x1702, 1, {0x22} },
+{ 0x1703, 16, {0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x80, 0xf0, 0x43, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22} },
+{ 0x1713, 16, {0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x04, 0xf0, 0xe0, 0x44, 0x08, 0xf0, 0x30, 0x09, 0x04, 0xe0, 0x44} },
+{ 0x1723, 16, {0x02, 0xf0, 0x7f, 0xf4, 0x7e, 0x01, 0x12, 0x17, 0x34, 0x90, 0x7f, 0xd6, 0xe0, 0x54, 0xf7, 0xf0} },
+{ 0x1733, 1, {0x22} },
+{ 0x1734, 16, {0x8e, 0x19, 0x8f, 0x1a, 0xe5, 0x1a, 0x15, 0x1a, 0xae, 0x19, 0x70, 0x02, 0x15, 0x19, 0x4e, 0x60} },
+{ 0x1744, 10, {0x08, 0x12, 0x16, 0xf2, 0x12, 0x16, 0xf2, 0x80, 0xeb, 0x22} },
+{ 0x174e, 16, {0xe5, 0x27, 0x24, 0x04, 0xf5, 0x82, 0xe4, 0x35, 0x26, 0xf5, 0x83, 0xe0, 0x04, 0xff, 0x44, 0x10} },
+{ 0x175e, 9, {0x90, 0x7f, 0xd7, 0xf0, 0xef, 0x44, 0x30, 0xf0, 0x22} },
+{ 0x1767, 16, {0x03, 0x16, 0x80, 0x00, 0x00, 0x03, 0x11, 0x81, 0x00, 0x00, 0xc1, 0x85, 0xc1, 0x81, 0xc1, 0x08} },
+{ 0x1777, 7, {0xc1, 0x00, 0xc1, 0x86, 0x01, 0x09, 0x00} },
+{ 0x177e, 1, {0x00} },
+{ 0x177f, 16, {0x90, 0x7f, 0xd6, 0xe0, 0x44, 0x01, 0xf0, 0x7f, 0x0d, 0x7e, 0x00, 0x12, 0x17, 0x34, 0x90, 0x7f} },
+{ 0x178f, 6, {0xd6, 0xe0, 0x54, 0xfe, 0xf0, 0x22} },
+{ 0x1795, 16, {0x12, 0x12, 0xae, 0x12, 0x17, 0x03, 0x90, 0x7f, 0xd6, 0xe0, 0x30, 0xe7, 0x03, 0x12, 0x17, 0x7f} },
+{ 0x17a5, 4, {0x12, 0x0a, 0x6a, 0x22} },
+{ 0x17a9, 12, {0x90, 0x78, 0x41, 0x74, 0x02, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x17b5, 12, {0x90, 0x78, 0x41, 0x74, 0x03, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x17c1, 12, {0x90, 0x78, 0x41, 0x74, 0x04, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x17cd, 12, {0x90, 0x78, 0x41, 0x74, 0x05, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x17d9, 12, {0x90, 0x78, 0x41, 0x74, 0x06, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x17e5, 11, {0xe4, 0x90, 0x78, 0x41, 0xf0, 0x90, 0xc0, 0x00, 0xe0, 0xff, 0x22} },
+{ 0x17f0, 4, {0x53, 0xd8, 0xef, 0x32} },
+{ 0x1800, 15, {0x02, 0x16, 0xaa, 0x00, 0x02, 0x18, 0x04, 0x00, 0x02, 0x16, 0x80, 0x00, 0x02, 0x16, 0x28} },
+{ 0x1900, 16, {0x12, 0x01, 0x01, 0x00, 0xff, 0x00, 0x00, 0x40, 0xcd, 0x06, 0x0a, 0x01, 0x00, 0x00, 0x01, 0x02} },
+{ 0x1910, 16, {0x00, 0x04, 0x09, 0x02, 0x74, 0x00, 0x01, 0x01, 0x00, 0xa0, 0x32, 0x09, 0x04, 0x00, 0x00, 0x0e} },
+{ 0x1920, 16, {0xff, 0x00, 0x00, 0x00, 0x07, 0x05, 0x01, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x02, 0x02, 0x40} },
+{ 0x1930, 16, {0x00, 0x00, 0x07, 0x05, 0x03, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, 0x00} },
+{ 0x1940, 16, {0x07, 0x05, 0x05, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x06, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05} },
+{ 0x1950, 16, {0x07, 0x02, 0x40, 0x00, 0x00, 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x82, 0x02} },
+{ 0x1960, 16, {0x40, 0x00, 0x01, 0x07, 0x05, 0x83, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00} },
+{ 0x1970, 16, {0x01, 0x07, 0x05, 0x85, 0x02, 0x40, 0x00, 0x01, 0x07, 0x05, 0x86, 0x02, 0x40, 0x00, 0x01, 0x07} },
+{ 0x1980, 16, {0x05, 0x87, 0x02, 0x40, 0x00, 0x01, 0x04, 0x03, 0x09, 0x04, 0x48, 0x03, 0x4b, 0x00, 0x65, 0x00} },
+{ 0x1990, 16, {0x79, 0x00, 0x73, 0x00, 0x70, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x2c, 0x00, 0x20, 0x00, 0x61, 0x00} },
+{ 0x19a0, 16, {0x20, 0x00, 0x64, 0x00, 0x69, 0x00, 0x76, 0x00, 0x69, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00} },
+{ 0x19b0, 16, {0x6e, 0x00, 0x20, 0x00, 0x6f, 0x00, 0x66, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x6e, 0x00} },
+{ 0x19c0, 16, {0x6f, 0x00, 0x53, 0x00, 0x79, 0x00, 0x73, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x63, 0x00} },
+{ 0x19d0, 16, {0x2e, 0x00, 0x36, 0x03, 0x4b, 0x00, 0x65, 0x00, 0x79, 0x00, 0x73, 0x00, 0x70, 0x00, 0x61, 0x00} },
+{ 0x19e0, 16, {0x6e, 0x00, 0x20, 0x00, 0x55, 0x00, 0x53, 0x00, 0x42, 0x00, 0x20, 0x00, 0x53, 0x00, 0x65, 0x00} },
+{ 0x19f0, 16, {0x72, 0x00, 0x69, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x20, 0x00, 0x41, 0x00, 0x64, 0x00, 0x61, 0x00} },
+{ 0x1a00, 10, {0x70, 0x00, 0x74, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00} },
+{ 0xffff, 0, {0x00} }
+};
--- /dev/null
+/*
+ * MCT (Magic Control Technology Corp.) USB RS232 Converter Driver
+ *
+ * Copyright (C) 2000 Wolfgang Grandegger (wolfgang@ces.ch)
+ *
+ * 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 largely derived from the Belkin USB Serial Adapter Driver
+ * (see belkin_sa.[ch]). All of the information about the device was acquired
+ * by using SniffUSB on Windows98. For technical details see mct_u232.h.
+ *
+ * William G. Greathouse and Greg Kroah-Hartman provided great help on how to
+ * do the reverse engineering and how to write a USB serial device driver.
+ *
+ * TO BE DONE, TO BE CHECKED:
+ * DTR/RTS signal handling may be incomplete or incorrect. I have mainly
+ * implemented what I have seen with SniffUSB or found in belkin_sa.c.
+ * For further TODOs check also belkin_sa.c.
+ *
+ * TEST STATUS:
+ * Basic tests have been performed with minicom/zmodem transfers and
+ * modem dialing under Linux 2.4.0-test10 (for me it works fine).
+ *
+ * 29-Nov-2000 Greg Kroah-Hartman
+ * - Added device id table to fit with 2.4.0-test11 structure.
+ * - took out DEAL_WITH_TWO_INT_IN_ENDPOINTS #define as it's not needed
+ * (lots of things will change if/when the usb-serial core changes to
+ * handle these issues.
+ *
+ * 27-Nov-2000 Wolfgang Grandegger
+ * A version for kernel 2.4.0-test10 released to the Linux community
+ * (via linux-usb-devel).
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+#include <linux/fcntl.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#ifdef CONFIG_USB_SERIAL_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
+#include <linux/usb.h>
+
+#include "usb-serial.h"
+#include "mct_u232.h"
+
+
+/*
+ * Some not properly written applications do not handle the return code of
+ * write() correctly. This can result in character losses. A work-a-round
+ * can be compiled in with the following definition. This work-a-round
+ * should _NOT_ be part of an 'official' kernel release, of course!
+ */
+#undef FIX_WRITE_RETURN_CODE_PROBLEM
+#ifdef FIX_WRITE_RETURN_CODE_PROBLEM
+static int write_blocking = 0; /* disabled by default */
+#endif
+
+/*
+ * Function prototypes
+ */
+static int mct_u232_startup (struct usb_serial *serial);
+static void mct_u232_shutdown (struct usb_serial *serial);
+static int mct_u232_open (struct usb_serial_port *port,
+ struct file *filp);
+static void mct_u232_close (struct usb_serial_port *port,
+ struct file *filp);
+#ifdef FIX_WRITE_RETURN_CODE_PROBLEM
+static int mct_u232_write (struct usb_serial_port *port,
+ int from_user,
+ const unsigned char *buf,
+ int count);
+static void mct_u232_write_bulk_callback (struct urb *urb);
+#endif
+static void mct_u232_read_int_callback (struct urb *urb);
+static void mct_u232_set_termios (struct usb_serial_port *port,
+ struct termios * old);
+static int mct_u232_ioctl (struct usb_serial_port *port,
+ struct file * file,
+ unsigned int cmd,
+ unsigned long arg);
+static void mct_u232_break_ctl (struct usb_serial_port *port,
+ int break_state );
+
+/*
+ * All of the device info needed for the MCT USB-RS232 converter.
+ */
+static __devinitdata struct usb_device_id id_table [] = {
+ { idVendor: MCT_U232_VID, idProduct: MCT_U232_PID },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, id_table);
+
+
+struct usb_serial_device_type mct_u232_device = {
+ name: "Magic Control Technology USB-RS232",
+ id_table: id_table,
+ needs_interrupt_in: MUST_HAVE, /* 2 interrupt-in endpoints */
+ needs_bulk_in: MUST_HAVE_NOT, /* no bulk-in endpoint */
+ needs_bulk_out: MUST_HAVE, /* 1 bulk-out endpoint */
+ num_interrupt_in: 2,
+ num_bulk_in: 0,
+ num_bulk_out: 1,
+ num_ports: 1,
+ open: mct_u232_open,
+ close: mct_u232_close,
+#ifdef FIX_WRITE_RETURN_CODE_PROBLEM
+ write: mct_u232_write,
+ write_bulk_callback: mct_u232_write_bulk_callback,
+#endif
+ read_int_callback: mct_u232_read_int_callback,
+ ioctl: mct_u232_ioctl,
+ set_termios: mct_u232_set_termios,
+ break_ctl: mct_u232_break_ctl,
+ startup: mct_u232_startup,
+ shutdown: mct_u232_shutdown,
+};
+
+struct mct_u232_private {
+ unsigned long control_state; /* Modem Line Setting (TIOCM) */
+ unsigned char last_lcr; /* Line Control Register */
+ unsigned char last_lsr; /* Line Status Register */
+ unsigned char last_msr; /* Modem Status Register */
+};
+
+/*
+ * Handle vendor specific USB requests
+ */
+
+#define WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
+
+static int mct_u232_set_baud_rate(struct usb_serial *serial, int value)
+{
+ unsigned int divisor;
+ int rc;
+ divisor = MCT_U232_BAUD_RATE(value);
+ rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ MCT_U232_SET_BAUD_RATE_REQUEST,
+ MCT_U232_SET_REQUEST_TYPE,
+ 0, 0, &divisor, MCT_U232_SET_BAUD_RATE_SIZE,
+ WDR_TIMEOUT);
+ if (rc < 0)
+ err("Set BAUD RATE %d failed (error = %d)", value, rc);
+ dbg("set_baud_rate: 0x%x", divisor);
+ return rc;
+} /* mct_u232_set_baud_rate */
+
+static int mct_u232_set_line_ctrl(struct usb_serial *serial, unsigned char lcr)
+{
+ int rc;
+ rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ MCT_U232_SET_LINE_CTRL_REQUEST,
+ MCT_U232_SET_REQUEST_TYPE,
+ 0, 0, &lcr, MCT_U232_SET_LINE_CTRL_SIZE,
+ WDR_TIMEOUT);
+ if (rc < 0)
+ err("Set LINE CTRL 0x%x failed (error = %d)", lcr, rc);
+ dbg("set_line_ctrl: 0x%x", lcr);
+ return rc;
+} /* mct_u232_set_line_ctrl */
+
+static int mct_u232_set_modem_ctrl(struct usb_serial *serial,
+ unsigned long control_state)
+{
+ int rc;
+ unsigned char mcr = MCT_U232_MCR_NONE;
+
+ if (control_state & TIOCM_DTR)
+ mcr |= MCT_U232_MCR_DTR;
+ if (control_state & TIOCM_RTS)
+ mcr |= MCT_U232_MCR_RTS;
+
+ rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ MCT_U232_SET_MODEM_CTRL_REQUEST,
+ MCT_U232_SET_REQUEST_TYPE,
+ 0, 0, &mcr, MCT_U232_SET_MODEM_CTRL_SIZE,
+ WDR_TIMEOUT);
+ if (rc < 0)
+ err("Set MODEM CTRL 0x%x failed (error = %d)", mcr, rc);
+ dbg("set_modem_ctrl: state=0x%lx ==> mcr=0x%x", control_state, mcr);
+
+ return rc;
+} /* mct_u232_set_modem_ctrl */
+
+static int mct_u232_get_modem_stat(struct usb_serial *serial, unsigned char *msr)
+{
+ int rc;
+ rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ MCT_U232_GET_MODEM_STAT_REQUEST,
+ MCT_U232_GET_REQUEST_TYPE,
+ 0, 0, msr, MCT_U232_GET_MODEM_STAT_SIZE,
+ WDR_TIMEOUT);
+ if (rc < 0) {
+ err("Get MODEM STATus failed (error = %d)", rc);
+ *msr = 0;
+ }
+ dbg("get_modem_stat: 0x%x", *msr);
+ return rc;
+} /* mct_u232_get_modem_stat */
+
+static void mct_u232_msr_to_state(unsigned long *control_state, unsigned char msr)
+{
+ /* Translate Control Line states */
+ if (msr & MCT_U232_MSR_DSR)
+ *control_state |= TIOCM_DSR;
+ else
+ *control_state &= ~TIOCM_DSR;
+ if (msr & MCT_U232_MSR_CTS)
+ *control_state |= TIOCM_CTS;
+ else
+ *control_state &= ~TIOCM_CTS;
+ if (msr & MCT_U232_MSR_RI)
+ *control_state |= TIOCM_RI;
+ else
+ *control_state &= ~TIOCM_RI;
+ if (msr & MCT_U232_MSR_CD)
+ *control_state |= TIOCM_CD;
+ else
+ *control_state &= ~TIOCM_CD;
+ dbg("msr_to_state: msr=0x%x ==> state=0x%lx", msr, *control_state);
+} /* mct_u232_msr_to_state */
+
+/*
+ * Driver's tty interface functions
+ */
+
+static int mct_u232_startup (struct usb_serial *serial)
+{
+ struct mct_u232_private *priv;
+
+ /* allocate the private data structure */
+ serial->port->private = kmalloc(sizeof(struct mct_u232_private),
+ GFP_KERNEL);
+ if (!serial->port->private)
+ return (-1); /* error */
+ priv = (struct mct_u232_private *)serial->port->private;
+ /* set initial values for control structures */
+ priv->control_state = 0;
+ priv->last_lsr = 0;
+ priv->last_msr = 0;
+
+ init_waitqueue_head(&serial->port->write_wait);
+
+ return (0);
+} /* mct_u232_startup */
+
+
+static void mct_u232_shutdown (struct usb_serial *serial)
+{
+ int i;
+
+ dbg (__FUNCTION__);
+
+ /* stop reads and writes on all ports */
+ for (i=0; i < serial->num_ports; ++i) {
+ while (serial->port[i].open_count > 0) {
+ mct_u232_close (&serial->port[i], NULL);
+ }
+ /* My special items, the standard routines free my urbs */
+ if (serial->port->private)
+ kfree(serial->port->private);
+ }
+} /* mct_u232_shutdown */
+
+static int mct_u232_open (struct usb_serial_port *port, struct file *filp)
+{
+ unsigned long flags;
+ struct usb_serial *serial = port->serial;
+ struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
+
+ dbg(__FUNCTION__" port %d", port->number);
+
+ spin_lock_irqsave (&port->port_lock, flags);
+
+ ++port->open_count;
+ MOD_INC_USE_COUNT;
+
+ if (!port->active) {
+ port->active = 1;
+
+ /* Do a defined restart: the normal serial device seems to
+ * always turn on DTR and RTS here, so do the same. I'm not
+ * sure if this is really necessary. But it should not harm
+ * either.
+ */
+ if (port->tty->termios->c_cflag & CBAUD)
+ priv->control_state = TIOCM_DTR | TIOCM_RTS;
+ else
+ priv->control_state = 0;
+ mct_u232_set_modem_ctrl(serial, priv->control_state);
+
+ priv->last_lcr = (MCT_U232_DATA_BITS_8 |
+ MCT_U232_PARITY_NONE |
+ MCT_U232_STOP_BITS_1);
+ mct_u232_set_line_ctrl(serial, priv->last_lcr);
+
+ /* Read modem status and update control state */
+ mct_u232_get_modem_stat(serial, &priv->last_msr);
+ mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
+
+ {
+ /* Puh, that's dirty */
+ struct usb_serial_port *rport;
+ rport = &serial->port[1];
+ rport->tty = port->tty;
+ rport->private = port->private;
+ port->read_urb = rport->interrupt_in_urb;
+ }
+
+ port->read_urb->dev = port->serial->dev;
+ if (usb_submit_urb(port->read_urb))
+ err("usb_submit_urb(read bulk) failed");
+
+ port->interrupt_in_urb->dev = port->serial->dev;
+ if (usb_submit_urb(port->interrupt_in_urb))
+ err(" usb_submit_urb(read int) failed");
+
+ }
+
+ spin_unlock_irqrestore (&port->port_lock, flags);
+
+ return 0;
+} /* mct_u232_open */
+
+
+static void mct_u232_close (struct usb_serial_port *port, struct file *filp)
+{
+ unsigned long flags;
+
+ dbg(__FUNCTION__" port %d", port->number);
+
+ spin_lock_irqsave (&port->port_lock, flags);
+
+ --port->open_count;
+ MOD_DEC_USE_COUNT;
+
+ if (port->open_count <= 0) {
+ /* shutdown our bulk reads and writes */
+ usb_unlink_urb (port->write_urb);
+ usb_unlink_urb (port->read_urb);
+ /* wgg - do I need this? I think so. */
+ usb_unlink_urb (port->interrupt_in_urb);
+ port->active = 0;
+ }
+
+ spin_unlock_irqrestore (&port->port_lock, flags);
+
+} /* mct_u232_close */
+
+
+#ifdef FIX_WRITE_RETURN_CODE_PROBLEM
+/* The generic routines work fine otherwise */
+
+static int mct_u232_write (struct usb_serial_port *port, int from_user,
+ const unsigned char *buf, int count)
+{
+ struct usb_serial *serial = port->serial;
+ unsigned long flags;
+ int result, bytes_sent, size;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ if (count == 0) {
+ dbg(__FUNCTION__ " - write request of 0 bytes");
+ return (0);
+ }
+
+ /* only do something if we have a bulk out endpoint */
+ if (!serial->num_bulk_out)
+ return(0);;
+
+ /* another write is still pending? */
+ if (port->write_urb->status == -EINPROGRESS) {
+ dbg (__FUNCTION__ " - already writing");
+ return (0);
+ }
+
+ bytes_sent = 0;
+ while (count > 0) {
+
+ spin_lock_irqsave (&port->port_lock, flags);
+
+ size = (count > port->bulk_out_size) ? port->bulk_out_size : count;
+
+ usb_serial_debug_data (__FILE__, __FUNCTION__, size, buf);
+
+ if (from_user) {
+ copy_from_user(port->write_urb->transfer_buffer, buf, size);
+ }
+ else {
+ memcpy (port->write_urb->transfer_buffer, buf, size);
+ }
+
+ /* set up our urb */
+ FILL_BULK_URB(port->write_urb, serial->dev,
+ usb_sndbulkpipe(serial->dev,
+ port->bulk_out_endpointAddress),
+ port->write_urb->transfer_buffer, size,
+ ((serial->type->write_bulk_callback) ?
+ serial->type->write_bulk_callback :
+ mct_u232_write_bulk_callback),
+ port);
+
+ /* send the data out the bulk port */
+ result = usb_submit_urb(port->write_urb);
+ if (result) {
+ err(__FUNCTION__
+ " - failed submitting write urb, error %d", result);
+ spin_unlock_irqrestore (&port->port_lock, flags);
+ return bytes_sent;
+ }
+
+ spin_unlock_irqrestore (&port->port_lock, flags);
+
+ bytes_sent += size;
+ if (write_blocking)
+ interruptible_sleep_on(&port->write_wait);
+ else
+ break;
+
+ buf += size;
+ count -= size;
+ }
+
+ return bytes_sent;
+} /* mct_u232_write */
+
+static void mct_u232_write_bulk_callback (struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct usb_serial *serial = port->serial;
+ struct tty_struct *tty = port->tty;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ if (!serial) {
+ dbg(__FUNCTION__ " - bad serial pointer, exiting");
+ return;
+ }
+
+ if (urb->status) {
+ dbg(__FUNCTION__ " - nonzero write bulk status received: %d",
+ urb->status);
+ return;
+ }
+
+ if (write_blocking) {
+ wake_up_interruptible(&port->write_wait);
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+ wake_up_interruptible(&tty->write_wait);
+
+ } else {
+ /* from generic_write_bulk_callback */
+ queue_task(&port->tqueue, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
+
+ return;
+} /* mct_u232_write_bulk_callback */
+#endif
+
+static void mct_u232_read_int_callback (struct urb *urb)
+{
+ struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
+ struct usb_serial *serial = port->serial;
+ struct tty_struct *tty;
+ unsigned char *data = urb->transfer_buffer;
+
+ dbg(__FUNCTION__ " - port %d", port->number);
+
+ /* The urb might have been killed. */
+ if (urb->status) {
+ dbg(__FUNCTION__ " - nonzero read bulk status received: %d",
+ urb->status);
+ return;
+ }
+ if (!serial) {
+ dbg(__FUNCTION__ " - bad serial pointer, exiting");
+ return;
+ }
+
+ usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
+
+ /*
+ * Work-a-round: handle the 'usual' bulk-in pipe here
+ */
+ if (urb->transfer_buffer_length > 2) {
+ int i;
+ tty = port->tty;
+ if (urb->actual_length) {
+ for (i = 0; i < urb->actual_length ; ++i) {
+ tty_insert_flip_char(tty, data[i], 0);
+ }
+ tty_flip_buffer_push(tty);
+ }
+ /* INT urbs are automatically re-submitted */
+ return;
+ }
+
+ /*
+ * The interrupt-in pipe signals exceptional conditions (modem line
+ * signal changes and errors). data[0] holds MSR, data[1] holds LSR.
+ */
+ priv->last_msr = data[MCT_U232_MSR_INDEX];
+
+ /* Record Control Line states */
+ mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
+
+#if 0
+ /* Not yet handled. See belin_sa.c for further information */
+ /* Now to report any errors */
+ priv->last_lsr = data[MCT_U232_LSR_INDEX];
+ /*
+ * fill in the flip buffer here, but I do not know the relation
+ * to the current/next receive buffer or characters. I need
+ * to look in to this before committing any code.
+ */
+ if (priv->last_lsr & MCT_U232_LSR_ERR) {
+ tty = port->tty;
+ /* Overrun Error */
+ if (priv->last_lsr & MCT_U232_LSR_OE) {
+ }
+ /* Parity Error */
+ if (priv->last_lsr & MCT_U232_LSR_PE) {
+ }
+ /* Framing Error */
+ if (priv->last_lsr & MCT_U232_LSR_FE) {
+ }
+ /* Break Indicator */
+ if (priv->last_lsr & MCT_U232_LSR_BI) {
+ }
+ }
+#endif
+
+ /* INT urbs are automatically re-submitted */
+} /* mct_u232_read_int_callback */
+
+
+static void mct_u232_set_termios (struct usb_serial_port *port,
+ struct termios *old_termios)
+{
+ struct usb_serial *serial = port->serial;
+ struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
+ unsigned int iflag = port->tty->termios->c_iflag;
+ unsigned int old_iflag = old_termios->c_iflag;
+ unsigned int cflag = port->tty->termios->c_cflag;
+ unsigned int old_cflag = old_termios->c_cflag;
+
+ /*
+ * Update baud rate
+ */
+ if( (cflag & CBAUD) != (old_cflag & CBAUD) ) {
+ /* reassert DTR and (maybe) RTS on transition from B0 */
+ if( (old_cflag & CBAUD) == B0 ) {
+ dbg(__FUNCTION__ ": baud was B0");
+ priv->control_state |= TIOCM_DTR;
+ /* don't set RTS if using hardware flow control */
+ if (!(old_cflag & CRTSCTS)) {
+ priv->control_state |= TIOCM_RTS;
+ }
+ mct_u232_set_modem_ctrl(serial, priv->control_state);
+ }
+
+ switch(cflag & CBAUD) {
+ case B0: /* handled below */
+ break;
+ case B300: mct_u232_set_baud_rate(serial, 300);
+ break;
+ case B600: mct_u232_set_baud_rate(serial, 600);
+ break;
+ case B1200: mct_u232_set_baud_rate(serial, 1200);
+ break;
+ case B2400: mct_u232_set_baud_rate(serial, 2400);
+ break;
+ case B4800: mct_u232_set_baud_rate(serial, 4800);
+ break;
+ case B9600: mct_u232_set_baud_rate(serial, 9600);
+ break;
+ case B19200: mct_u232_set_baud_rate(serial, 19200);
+ break;
+ case B38400: mct_u232_set_baud_rate(serial, 38400);
+ break;
+ case B57600: mct_u232_set_baud_rate(serial, 57600);
+ break;
+ case B115200: mct_u232_set_baud_rate(serial, 115200);
+ break;
+ default: err("MCT USB-RS232 converter: unsupported baudrate request, using default of 9600");
+ mct_u232_set_baud_rate(serial, 9600); break;
+ }
+ if ((cflag & CBAUD) == B0 ) {
+ dbg(__FUNCTION__ ": baud is B0");
+ /* Drop RTS and DTR */
+ priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+ mct_u232_set_modem_ctrl(serial, priv->control_state);
+ }
+ }
+
+ /*
+ * Update line control register (LCR)
+ */
+ if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))
+ || (cflag & CSIZE) != (old_cflag & CSIZE)
+ || (cflag & CSTOPB) != (old_cflag & CSTOPB) ) {
+
+
+ priv->last_lcr = 0;
+
+ /* set the parity */
+ if (cflag & PARENB)
+ priv->last_lcr |= (cflag & PARODD) ?
+ MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN;
+ else
+ priv->last_lcr |= MCT_U232_PARITY_NONE;
+
+ /* set the number of data bits */
+ switch (cflag & CSIZE) {
+ case CS5:
+ priv->last_lcr |= MCT_U232_DATA_BITS_5; break;
+ case CS6:
+ priv->last_lcr |= MCT_U232_DATA_BITS_6; break;
+ case CS7:
+ priv->last_lcr |= MCT_U232_DATA_BITS_7; break;
+ case CS8:
+ priv->last_lcr |= MCT_U232_DATA_BITS_8; break;
+ default:
+ err("CSIZE was not CS5-CS8, using default of 8");
+ priv->last_lcr |= MCT_U232_DATA_BITS_8;
+ break;
+ }
+
+ /* set the number of stop bits */
+ priv->last_lcr |= (cflag & CSTOPB) ?
+ MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1;
+
+ mct_u232_set_line_ctrl(serial, priv->last_lcr);
+ }
+
+ /*
+ * Set flow control: well, I do not really now how to handle DTR/RTS.
+ * Just do what we have seen with SniffUSB on Win98.
+ */
+ if( (iflag & IXOFF) != (old_iflag & IXOFF)
+ || (iflag & IXON) != (old_iflag & IXON)
+ || (cflag & CRTSCTS) != (old_cflag & CRTSCTS) ) {
+
+ /* Drop DTR/RTS if no flow control otherwise assert */
+ if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS) )
+ priv->control_state |= TIOCM_DTR | TIOCM_RTS;
+ else
+ priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+ mct_u232_set_modem_ctrl(serial, priv->control_state);
+ }
+} /* mct_u232_set_termios */
+
+
+static void mct_u232_break_ctl( struct usb_serial_port *port, int break_state )
+{
+ struct usb_serial *serial = port->serial;
+ struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
+ unsigned char lcr = priv->last_lcr;
+
+ dbg (__FUNCTION__ "state=%d", break_state);
+
+ if (break_state)
+ lcr |= MCT_U232_SET_BREAK;
+
+ mct_u232_set_line_ctrl(serial, lcr);
+} /* mct_u232_break_ctl */
+
+
+static int mct_u232_ioctl (struct usb_serial_port *port, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct usb_serial *serial = port->serial;
+ struct mct_u232_private *priv = (struct mct_u232_private *)port->private;
+ int ret, mask;
+
+ dbg (__FUNCTION__ "cmd=0x%x", cmd);
+
+ /* Based on code from acm.c and others */
+ switch (cmd) {
+ case TIOCMGET:
+ return put_user(priv->control_state, (unsigned long *) arg);
+ break;
+
+ case TIOCMSET: /* Turns on and off the lines as specified by the mask */
+ case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
+ case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
+ if ((ret = get_user(mask, (unsigned long *) arg))) return ret;
+
+ if ((cmd == TIOCMSET) || (mask & TIOCM_RTS)) {
+ /* RTS needs set */
+ if( ((cmd == TIOCMSET) && (mask & TIOCM_RTS)) ||
+ (cmd == TIOCMBIS) )
+ priv->control_state |= TIOCM_RTS;
+ else
+ priv->control_state &= ~TIOCM_RTS;
+ }
+
+ if ((cmd == TIOCMSET) || (mask & TIOCM_DTR)) {
+ /* DTR needs set */
+ if( ((cmd == TIOCMSET) && (mask & TIOCM_DTR)) ||
+ (cmd == TIOCMBIS) )
+ priv->control_state |= TIOCM_DTR;
+ else
+ priv->control_state &= ~TIOCM_DTR;
+ }
+ mct_u232_set_modem_ctrl(serial, priv->control_state);
+ break;
+
+ case TIOCMIWAIT:
+ /* wait for any of the 4 modem inputs (DCD,RI,DSR,CTS)*/
+ /* TODO */
+ return( 0 );
+
+ case TIOCGICOUNT:
+ /* return count of modemline transitions */
+ /* TODO */
+ return 0;
+
+ default:
+ dbg(__FUNCTION__ ": arg not supported - 0x%04x",cmd);
+ return(-ENOIOCTLCMD);
+ break;
+ }
+ return 0;
+} /* mct_u232_ioctl */
+
+
+static int __init mct_u232_init (void)
+{
+ usb_serial_register (&mct_u232_device);
+
+ return 0;
+}
+
+
+static void __exit mct_u232_exit (void)
+{
+ usb_serial_deregister (&mct_u232_device);
+}
+
+
+module_init (mct_u232_init);
+module_exit(mct_u232_exit);
+
+MODULE_AUTHOR("Wolfgang Grandegger <wolfgang@ces.ch>");
+MODULE_DESCRIPTION("Magic Control Technology USB-RS232 converter driver");
+
+#ifdef FIX_WRITE_RETURN_CODE_PROBLEM
+MODULE_PARM(write_blocking, "i");
+MODULE_PARM_DESC(write_blocking,
+ "The write function will block to write out all data");
+#endif
--- /dev/null
+/*
+ * Definitions for MCT (Magic Control Technology) USB-RS232 Converter Driver
+ *
+ * Copyright (C) 2000 Wolfgang Grandegger (wolfgang@ces.ch)
+ *
+ * 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 driver is for the device MCT USB-RS232 Converter (25 pin, Model No.
+ * U232-P25) from Magic Control Technology Corp. (there is also a 9 pin
+ * Model No. U232-P9). See http://www.mct.com.tw/p_u232.html for further
+ * information. The properties of this device are listed at the end of this
+ * file. This device is available from various distributors. I know Hana,
+ * http://www.hana.de and D-Link, http://www.dlink.com/products/usb/dsbs25.
+ *
+ * All of the information about the device was acquired by using SniffUSB
+ * on Windows98. The technical details of the reverse engineering are
+ * summarized at the end of this file.
+ */
+
+#ifndef __LINUX_USB_SERIAL_MCT_U232_H
+#define __LINUX_USB_SERIAL_MCT_U232_H
+
+#define MCT_U232_VID 0x0711 /* Vendor Id */
+#define MCT_U232_PID 0x0210 /* Product Id */
+
+/*
+ * Vendor Request Interface
+ */
+#define MCT_U232_SET_REQUEST_TYPE 0x40
+#define MCT_U232_GET_REQUEST_TYPE 0xc0
+
+#define MCT_U232_GET_MODEM_STAT_REQUEST 2 /* Get Modem Status Register (MSR) */
+#define MCT_U232_GET_MODEM_STAT_SIZE 1
+
+#define MCT_U232_GET_LINE_CTRL_REQUEST 6 /* Get Line Control Register (LCR) */
+#define MCT_U232_GET_LINE_CTRL_SIZE 1 /* ... not used by this driver */
+
+#define MCT_U232_SET_BAUD_RATE_REQUEST 5 /* Set Baud Rate Divisor */
+#define MCT_U232_SET_BAUD_RATE_SIZE 4
+
+#define MCT_U232_SET_LINE_CTRL_REQUEST 7 /* Set Line Control Register (LCR) */
+#define MCT_U232_SET_LINE_CTRL_SIZE 1
+
+#define MCT_U232_SET_MODEM_CTRL_REQUEST 10 /* Set Modem Control Register (MCR) */
+#define MCT_U232_SET_MODEM_CTRL_SIZE 1
+
+/*
+ * Baud rate (divisor)
+ */
+#define MCT_U232_BAUD_RATE(b) (115200/b)
+
+/*
+ * Line Control Register (LCR)
+ */
+#define MCT_U232_SET_BREAK 0x40
+
+#define MCT_U232_PARITY_SPACE 0x38
+#define MCT_U232_PARITY_MARK 0x28
+#define MCT_U232_PARITY_EVEN 0x18
+#define MCT_U232_PARITY_ODD 0x08
+#define MCT_U232_PARITY_NONE 0x00
+
+#define MCT_U232_DATA_BITS_5 0x00
+#define MCT_U232_DATA_BITS_6 0x01
+#define MCT_U232_DATA_BITS_7 0x02
+#define MCT_U232_DATA_BITS_8 0x03
+
+#define MCT_U232_STOP_BITS_2 0x04
+#define MCT_U232_STOP_BITS_1 0x00
+
+/*
+ * Modem Control Register (MCR)
+ */
+#define MCT_U232_MCR_NONE 0x8 /* Deactivate DTR and RTS */
+#define MCT_U232_MCR_RTS 0xa /* Activate RTS */
+#define MCT_U232_MCR_DTR 0x9 /* Activate DTR */
+
+/*
+ * Modem Status Register (MSR)
+ */
+#define MCT_U232_MSR_INDEX 0x0 /* data[index] */
+#define MCT_U232_MSR_CD 0x80 /* Current CD */
+#define MCT_U232_MSR_RI 0x40 /* Current RI */
+#define MCT_U232_MSR_DSR 0x20 /* Current DSR */
+#define MCT_U232_MSR_CTS 0x10 /* Current CTS */
+#define MCT_U232_MSR_DCD 0x08 /* Delta CD */
+#define MCT_U232_MSR_DRI 0x04 /* Delta RI */
+#define MCT_U232_MSR_DDSR 0x02 /* Delta DSR */
+#define MCT_U232_MSR_DCTS 0x01 /* Delta CTS */
+
+/*
+ * Line Status Register (LSR)
+ */
+#define MCT_U232_LSR_INDEX 1 /* data[index] */
+#define MCT_U232_LSR_ERR 0x80 /* OE | PE | FE | BI */
+#define MCT_U232_LSR_TEMT 0x40 /* transmit register empty */
+#define MCT_U232_LSR_THRE 0x20 /* transmit holding register empty */
+#define MCT_U232_LSR_BI 0x10 /* break indicator */
+#define MCT_U232_LSR_FE 0x08 /* framing error */
+#define MCT_U232_LSR_OE 0x02 /* overrun error */
+#define MCT_U232_LSR_PE 0x04 /* parity error */
+#define MCT_U232_LSR_OE 0x02 /* overrun error */
+#define MCT_U232_LSR_DR 0x01 /* receive data ready */
+
+
+/* -----------------------------------------------------------------------------
+ * Technical Specification reverse engineered with SniffUSB on Windows98
+ * =====================================================================
+ *
+ * The technical details of the device have been acquired be using "SniffUSB"
+ * and the vendor-supplied device driver (version 2.3A) under Windows98. To
+ * identify the USB vendor-specific requests and to assign them to terminal
+ * settings (flow control, baud rate, etc.) the program "SerialSettings" from
+ * William G. Greathouse has been proven to be very useful. I also used the
+ * Win98 "HyperTerminal" and "usb-robot" on Linux for testing. The results and
+ * observations are summarized below:
+ *
+ * The USB requests seem to be directly mapped to the registers of a 8250,
+ * 16450 or 16550 UART. The FreeBSD handbook (appendix F.4 "Input/Output
+ * devices") contains a comprehensive description of UARTs and its registers.
+ * The bit descriptions are actually taken from there.
+ *
+ *
+ * Baud rate (divisor)
+ * -------------------
+ *
+ * BmRequestType: 0x4 (0100 0000B)
+ * bRequest: 0x5
+ * wValue: 0x0
+ * wIndex: 0x0
+ * wLength: 0x4
+ * Data: divisor = 115200 / baud_rate
+ *
+ *
+ * Line Control Register (LCR)
+ * ---------------------------
+ *
+ * BmRequestType: 0x4 (0100 0000B) 0xc (1100 0000B)
+ * bRequest: 0x7 0x6
+ * wValue: 0x0
+ * wIndex: 0x0
+ * wLength: 0x1
+ * Data: LCR (see below)
+ *
+ * Bit 7: Divisor Latch Access Bit (DLAB). When set, access to the data
+ * transmit/receive register (THR/RBR) and the Interrupt Enable Register
+ * (IER) is disabled. Any access to these ports is now redirected to the
+ * Divisor Latch Registers. Setting this bit, loading the Divisor
+ * Registers, and clearing DLAB should be done with interrupts disabled.
+ * Bit 6: Set Break. When set to "1", the transmitter begins to transmit
+ * continuous Spacing until this bit is set to "0". This overrides any
+ * bits of characters that are being transmitted.
+ * Bit 5: Stick Parity. When parity is enabled, setting this bit causes parity
+ * to always be "1" or "0", based on the value of Bit 4.
+ * Bit 4: Even Parity Select (EPS). When parity is enabled and Bit 5 is "0",
+ * setting this bit causes even parity to be transmitted and expected.
+ * Otherwise, odd parity is used.
+ * Bit 3: Parity Enable (PEN). When set to "1", a parity bit is inserted
+ * between the last bit of the data and the Stop Bit. The UART will also
+ * expect parity to be present in the received data.
+ * Bit 2: Number of Stop Bits (STB). If set to "1" and using 5-bit data words,
+ * 1.5 Stop Bits are transmitted and expected in each data word. For
+ * 6, 7 and 8-bit data words, 2 Stop Bits are transmitted and expected.
+ * When this bit is set to "0", one Stop Bit is used on each data word.
+ * Bit 1: Word Length Select Bit #1 (WLSB1)
+ * Bit 0: Word Length Select Bit #0 (WLSB0)
+ * Together these bits specify the number of bits in each data word.
+ * 1 0 Word Length
+ * 0 0 5 Data Bits
+ * 0 1 6 Data Bits
+ * 1 0 7 Data Bits
+ * 1 1 8 Data Bits
+ *
+ * SniffUSB observations: Bit 7 seems not to be used. There seem to be two bugs
+ * in the Win98 driver: the break does not work (bit 6 is not asserted) and the
+ * sticky parity bit is not cleared when set once. The LCR can also be read
+ * back with USB request 6 but this has never been observed with SniffUSB.
+ *
+ *
+ * Modem Control Register (MCR)
+ * ----------------------------
+ *
+ * BmRequestType: 0x4 (0100 0000B)
+ * bRequest: 0xa
+ * wValue: 0x0
+ * wIndex: 0x0
+ * wLength: 0x1
+ * Data: MCR (Bit 4..7, see below)
+ *
+ * Bit 7: Reserved, always 0.
+ * Bit 6: Reserved, always 0.
+ * Bit 5: Reserved, always 0.
+ * Bit 4: Loop-Back Enable. When set to "1", the UART transmitter and receiver
+ * are internally connected together to allow diagnostic operations. In
+ * addition, the UART modem control outputs are connected to the UART
+ * modem control inputs. CTS is connected to RTS, DTR is connected to
+ * DSR, OUT1 is connected to RI, and OUT 2 is connected to DCD.
+ * Bit 3: OUT 2. An auxiliary output that the host processor may set high or
+ * low. In the IBM PC serial adapter (and most clones), OUT 2 is used
+ * to tri-state (disable) the interrupt signal from the
+ * 8250/16450/16550 UART.
+ * Bit 2: OUT 1. An auxiliary output that the host processor may set high or
+ * low. This output is not used on the IBM PC serial adapter.
+ * Bit 1: Request to Send (RTS). When set to "1", the output of the UART -RTS
+ * line is Low (Active).
+ * Bit 0: Data Terminal Ready (DTR). When set to "1", the output of the UART
+ * -DTR line is Low (Active).
+ *
+ * SniffUSB observations: Bit 2 and 4 seem not to be used but bit 3 has been
+ * seen _always_ set.
+ *
+ *
+ * Modem Status Register (MSR)
+ * ---------------------------
+ *
+ * BmRequestType: 0xc (1100 0000B)
+ * bRequest: 0x2
+ * wValue: 0x0
+ * wIndex: 0x0
+ * wLength: 0x1
+ * Data: MSR (see below)
+ *
+ * Bit 7: Data Carrier Detect (CD). Reflects the state of the DCD line on the
+ * UART.
+ * Bit 6: Ring Indicator (RI). Reflects the state of the RI line on the UART.
+ * Bit 5: Data Set Ready (DSR). Reflects the state of the DSR line on the UART.
+ * Bit 4: Clear To Send (CTS). Reflects the state of the CTS line on the UART.
+ * Bit 3: Delta Data Carrier Detect (DDCD). Set to "1" if the -DCD line has
+ * changed state one more more times since the last time the MSR was
+ * read by the host.
+ * Bit 2: Trailing Edge Ring Indicator (TERI). Set to "1" if the -RI line has
+ * had a low to high transition since the last time the MSR was read by
+ * the host.
+ * Bit 1: Delta Data Set Ready (DDSR). Set to "1" if the -DSR line has changed
+ * state one more more times since the last time the MSR was read by the
+ * host.
+ * Bit 0: Delta Clear To Send (DCTS). Set to "1" if the -CTS line has changed
+ * state one more times since the last time the MSR was read by the
+ * host.
+ *
+ * SniffUSB observations: the MSR is also returned as first byte on the
+ * interrupt-in endpoint 0x83 to signal changes of modem status lines. The USB
+ * request to read MSR cannot be applied during normal device operation.
+ *
+ *
+ * Line Status Register (LSR)
+ * --------------------------
+ *
+ * Bit 7 Error in Receiver FIFO. On the 8250/16450 UART, this bit is zero.
+ * This bit is set to "1" when any of the bytes in the FIFO have one or
+ * more of the following error conditions: PE, FE, or BI.
+ * Bit 6 Transmitter Empty (TEMT). When set to "1", there are no words
+ * remaining in the transmit FIFO or the transmit shift register. The
+ * transmitter is completely idle.
+ * Bit 5 Transmitter Holding Register Empty (THRE). When set to "1", the FIFO
+ * (or holding register) now has room for at least one additional word
+ * to transmit. The transmitter may still be transmitting when this bit
+ * is set to "1".
+ * Bit 4 Break Interrupt (BI). The receiver has detected a Break signal.
+ * Bit 3 Framing Error (FE). A Start Bit was detected but the Stop Bit did not
+ * appear at the expected time. The received word is probably garbled.
+ * Bit 2 Parity Error (PE). The parity bit was incorrect for the word received.
+ * Bit 1 Overrun Error (OE). A new word was received and there was no room in
+ * the receive buffer. The newly-arrived word in the shift register is
+ * discarded. On 8250/16450 UARTs, the word in the holding register is
+ * discarded and the newly- arrived word is put in the holding register.
+ * Bit 0 Data Ready (DR). One or more words are in the receive FIFO that the
+ * host may read. A word must be completely received and moved from the
+ * shift register into the FIFO (or holding register for 8250/16450
+ * designs) before this bit is set.
+ *
+ * SniffUSB observations: the LSR is returned as second byte on the interrupt-in
+ * endpoint 0x83 to signal error conditions. Such errors have been seen with
+ * minicom/zmodem transfers (CRC errors).
+ *
+ *
+ * Flow control
+ * ------------
+ *
+ * SniffUSB observations: no flow control specific requests have been realized
+ * apart from DTR/RTS settings. Both signals are dropped for no flow control
+ * but asserted for hardware or software flow control.
+ *
+ *
+ * Endpoint usage
+ * --------------
+ *
+ * SniffUSB observations: the bulk-out endpoint 0x1 and interrupt-in endpoint
+ * 0x81 is used to transmit and receive characters. The second interrupt-in
+ * endpoint 0x83 signals exceptional conditions like modem line changes and
+ * errors. The first byte returned is the MSR and the second byte the LSR.
+ *
+ *
+ * Other observations
+ * ------------------
+ *
+ * Queued bulk transfers like used in visor.c did not work.
+ *
+ *
+ * Properties of the USB device used (as found in /var/log/messages)
+ * -----------------------------------------------------------------
+ *
+ * Manufacturer: MCT Corporation.
+ * Product: USB-232 Interfact Controller
+ * SerialNumber: U2S22050
+ *
+ * Length = 18
+ * DescriptorType = 01
+ * USB version = 1.00
+ * Vendor:Product = 0711:0210
+ * MaxPacketSize0 = 8
+ * NumConfigurations = 1
+ * Device version = 1.02
+ * Device Class:SubClass:Protocol = 00:00:00
+ * Per-interface classes
+ * Configuration:
+ * bLength = 9
+ * bDescriptorType = 02
+ * wTotalLength = 0027
+ * bNumInterfaces = 01
+ * bConfigurationValue = 01
+ * iConfiguration = 00
+ * bmAttributes = c0
+ * MaxPower = 100mA
+ *
+ * Interface: 0
+ * Alternate Setting: 0
+ * bLength = 9
+ * bDescriptorType = 04
+ * bInterfaceNumber = 00
+ * bAlternateSetting = 00
+ * bNumEndpoints = 03
+ * bInterface Class:SubClass:Protocol = 00:00:00
+ * iInterface = 00
+ * Endpoint:
+ * bLength = 7
+ * bDescriptorType = 05
+ * bEndpointAddress = 81 (in)
+ * bmAttributes = 03 (Interrupt)
+ * wMaxPacketSize = 0040
+ * bInterval = 02
+ * Endpoint:
+ * bLength = 7
+ * bDescriptorType = 05
+ * bEndpointAddress = 01 (out)
+ * bmAttributes = 02 (Bulk)
+ * wMaxPacketSize = 0040
+ * bInterval = 00
+ * Endpoint:
+ * bLength = 7
+ * bDescriptorType = 05
+ * bEndpointAddress = 83 (in)
+ * bmAttributes = 03 (Interrupt)
+ * wMaxPacketSize = 0002
+ * bInterval = 02
+ */
+
+#endif /* __LINUX_USB_SERIAL_MCT_U232_H */
+
urbp = (struct urb_priv *)u->hcpriv;
if (urbp) {
/* Check if the FSBR timed out */
- if (urbp->fsbr && time_after(urbp->inserttime + IDLE_TIMEOUT, jiffies))
+ if (urbp->fsbr && time_after_eq(jiffies, urbp->inserttime + IDLE_TIMEOUT))
uhci_fsbr_timeout(uhci, u);
/* Check if the URB timed out */
- if (u->timeout && time_after(u->timeout, jiffies)) {
+ if (u->timeout && time_after_eq(jiffies, u->timeout)) {
u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED;
uhci_unlink_urb(u);
}
// Completion
if (urb->complete) {
urb->dev = NULL;
+ spin_unlock(&s->urb_list_lock);
urb->complete ((struct urb *) urb);
// Re-submit the URB if ring-linked
if (is_ring && (urb->status != -ENOENT) && !contains_killed) {
urb->dev=usb_dev;
- spin_unlock(&s->urb_list_lock);
uhci_submit_urb (urb);
- spin_lock(&s->urb_list_lock);
}
+ spin_lock(&s->urb_list_lock);
}
usb_dec_dev_use (usb_dev);
if (err < 0) {
err("unable to get device %d configuration (error=%d)",
dev->devnum, err);
- usb_destroy_configuration(dev);
clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
dev->devnum = -1;
+ usb_free_dev(dev);
return 1;
}
bh->b_private = private;
}
-static void end_buffer_io_sync(struct buffer_head *bh, int uptodate)
-{
- mark_buffer_uptodate(bh, uptodate);
- unlock_buffer(bh);
-}
-
static void end_buffer_io_bad(struct buffer_head *bh, int uptodate)
{
mark_buffer_uptodate(bh, uptodate);
* and it is clean.
*/
if (bh) {
- init_buffer(bh, end_buffer_io_sync, NULL);
+ init_buffer(bh, end_buffer_io_bad, NULL);
bh->b_dev = dev;
bh->b_blocknr = block;
bh->b_state = 1 << BH_Mapped;
return NULL;
}
-/*
- * Ok, breada can be used as bread, but additionally to mark other
- * blocks for reading as well. End the argument list with a negative
- * number.
- */
-
-#define NBUF 16
-
-struct buffer_head * breada(kdev_t dev, int block, int bufsize,
- unsigned int pos, unsigned int filesize)
-{
- struct buffer_head * bhlist[NBUF];
- unsigned int blocks;
- struct buffer_head * bh;
- int index;
- int i, j;
-
- if (pos >= filesize)
- return NULL;
-
- if (block < 0)
- return NULL;
-
- bh = getblk(dev, block, bufsize);
- index = BUFSIZE_INDEX(bh->b_size);
-
- if (buffer_uptodate(bh))
- return(bh);
- else ll_rw_block(READ, 1, &bh);
-
- blocks = (filesize - pos) >> (9+index);
-
- if (blocks > NBUF)
- blocks = NBUF;
-
- bhlist[0] = bh;
- j = 1;
- for(i=1; i<blocks; i++) {
- bh = getblk(dev,block+i,bufsize);
- if (buffer_uptodate(bh)) {
- brelse(bh);
- break;
- }
- else bhlist[j++] = bh;
- }
-
- /* Request the read for these buffers, and then release them. */
- if (j>1)
- ll_rw_block(READA, (j-1), bhlist+1);
- for(i=1; i<j; i++)
- brelse(bhlist[i]);
-
- /* Wait for this buffer, and then continue on. */
- bh = bhlist[0];
- wait_on_buffer(bh);
- if (buffer_uptodate(bh))
- return bh;
- brelse(bh);
- return NULL;
-}
-
/*
* Note: the caller should wake up the buffer_wait list if needed.
*/
goto try_again;
}
-static int create_page_buffers(int rw, struct page *page, kdev_t dev, int b[], int size)
-{
- struct buffer_head *head, *bh, *tail;
- int block;
-
- if (!PageLocked(page))
- BUG();
- /*
- * Allocate async buffer heads pointing to this page, just for I/O.
- * They don't show up in the buffer hash table, but they *are*
- * registered in page->buffers.
- */
- head = create_buffers(page, size, 1);
- if (page->buffers)
- BUG();
- if (!head)
- BUG();
- tail = head;
- for (bh = head; bh; bh = bh->b_this_page) {
- block = *(b++);
-
- tail = bh;
- init_buffer(bh, end_buffer_io_async, NULL);
- bh->b_dev = dev;
- bh->b_blocknr = block;
-
- set_bit(BH_Mapped, &bh->b_state);
- }
- tail->b_this_page = head;
- page_cache_get(page);
- page->buffers = head;
- return 0;
-}
-
static void unmap_buffer(struct buffer_head * bh)
{
if (buffer_mapped(bh)) {
return 1;
}
-static void create_empty_buffers(struct page *page, struct inode *inode, unsigned long blocksize)
+static void create_empty_buffers(struct page *page, kdev_t dev, unsigned long blocksize)
{
struct buffer_head *bh, *head, *tail;
bh = head;
do {
- bh->b_dev = inode->i_dev;
+ bh->b_dev = dev;
bh->b_blocknr = 0;
bh->b_end_io = end_buffer_io_bad;
tail = bh;
int err, i;
unsigned long block;
struct buffer_head *bh, *head;
- struct buffer_head *arr[MAX_BUF_PER_PAGE];
- int nr = 0;
if (!PageLocked(page))
BUG();
if (!page->buffers)
- create_empty_buffers(page, inode, inode->i_sb->s_blocksize);
+ create_empty_buffers(page, inode->i_dev, inode->i_sb->s_blocksize);
head = page->buffers;
block = page->index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
bh = head;
i = 0;
+
+ /* Stage 1: make sure we have all the buffers mapped! */
do {
/*
* If the buffer isn't up-to-date, we can't be sure
if (buffer_new(bh))
unmap_underlying_metadata(bh);
}
- set_bit(BH_Uptodate, &bh->b_state);
- set_bit(BH_Dirty, &bh->b_state);
+ bh = bh->b_this_page;
+ block++;
+ } while (bh != head);
+
+ /* Stage 2: lock the buffers, mark them dirty */
+ do {
+ lock_buffer(bh);
bh->b_end_io = end_buffer_io_async;
atomic_inc(&bh->b_count);
- arr[nr++] = bh;
+ set_bit(BH_Uptodate, &bh->b_state);
+ set_bit(BH_Dirty, &bh->b_state);
bh = bh->b_this_page;
- block++;
} while (bh != head);
- if (nr) {
- ll_rw_block(WRITE, nr, arr);
- } else {
- UnlockPage(page);
- }
+ /* Stage 3: submit the IO */
+ do {
+ submit_bh(WRITE, bh);
+ bh = bh->b_this_page;
+ } while (bh != head);
+
+ /* Done - end_buffer_io_async will unlock */
SetPageUptodate(page);
return 0;
+
out:
- if (nr) {
- ll_rw_block(WRITE, nr, arr);
- } else {
- UnlockPage(page);
- }
ClearPageUptodate(page);
+ UnlockPage(page);
return err;
}
blocksize = inode->i_sb->s_blocksize;
if (!page->buffers)
- create_empty_buffers(page, inode, blocksize);
+ create_empty_buffers(page, inode->i_dev, blocksize);
head = page->buffers;
bbits = inode->i_sb->s_blocksize_bits;
continue;
if (block_start >= to)
break;
- bh->b_end_io = end_buffer_io_sync;
if (!buffer_mapped(bh)) {
err = get_block(inode, block, bh, 1);
if (err)
unsigned long iblock, lblock;
struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE];
unsigned int blocksize, blocks;
- char *kaddr = NULL;
int nr, i;
if (!PageLocked(page))
PAGE_BUG(page);
blocksize = inode->i_sb->s_blocksize;
if (!page->buffers)
- create_empty_buffers(page, inode, blocksize);
+ create_empty_buffers(page, inode->i_dev, blocksize);
head = page->buffers;
blocks = PAGE_CACHE_SIZE >> inode->i_sb->s_blocksize_bits;
continue;
}
if (!buffer_mapped(bh)) {
- if (!kaddr)
- kaddr = kmap(page);
- memset(kaddr + i*blocksize, 0, blocksize);
+ memset(kmap(page) + i*blocksize, 0, blocksize);
flush_dcache_page(page);
+ kunmap(page);
set_bit(BH_Uptodate, &bh->b_state);
continue;
}
}
- init_buffer(bh, end_buffer_io_async, NULL);
- atomic_inc(&bh->b_count);
arr[nr] = bh;
nr++;
} while (i++, iblock++, (bh = bh->b_this_page) != head);
- if (nr) {
- if (Page_Uptodate(page))
- BUG();
- ll_rw_block(READ, nr, arr);
- } else {
+ if (!nr) {
/*
* all buffers are uptodate - we can set the page
* uptodate as well.
*/
SetPageUptodate(page);
UnlockPage(page);
+ return 0;
}
- if (kaddr)
- kunmap(page);
+
+ /* Stage two: lock the buffers */
+ for (i = 0; i < nr; i++) {
+ struct buffer_head * bh = arr[i];
+ lock_buffer(bh);
+ bh->b_end_io = end_buffer_io_async;
+ atomic_inc(&bh->b_count);
+ }
+
+ /* Stage 3: start the IO */
+ for (i = 0; i < nr; i++)
+ submit_bh(READ, arr[i]);
+
return 0;
}
goto out;
if (!page->buffers)
- create_empty_buffers(page, inode, blocksize);
+ create_empty_buffers(page, inode->i_dev, blocksize);
/* Find the buffer that contains "offset" */
bh = page->buffers;
if (Page_Uptodate(page))
set_bit(BH_Uptodate, &bh->b_state);
- bh->b_end_io = end_buffer_io_sync;
if (!buffer_uptodate(bh)) {
err = -EIO;
ll_rw_block(READ, 1, &bh);
*/
int brw_page(int rw, struct page *page, kdev_t dev, int b[], int size)
{
- struct buffer_head *head, *bh, *arr[MAX_BUF_PER_PAGE];
- int nr, fresh /* temporary debugging flag */, block;
+ struct buffer_head *head, *bh;
if (!PageLocked(page))
panic("brw_page: page not locked for I/O");
-// ClearPageError(page);
- /*
- * We pretty much rely on the page lock for this, because
- * create_page_buffers() might sleep.
- */
- fresh = 0;
- if (!page->buffers) {
- create_page_buffers(rw, page, dev, b, size);
- fresh = 1;
- }
+
if (!page->buffers)
- BUG();
+ create_empty_buffers(page, dev, size);
+ head = bh = page->buffers;
- head = page->buffers;
- bh = head;
- nr = 0;
+ /* Stage 1: lock all the buffers */
do {
- block = *(b++);
+ lock_buffer(bh);
+ bh->b_blocknr = *(b++);
+ set_bit(BH_Mapped, &bh->b_state);
+ bh->b_end_io = end_buffer_io_async;
+ atomic_inc(&bh->b_count);
+ bh = bh->b_this_page;
+ } while (bh != head);
- if (fresh && (atomic_read(&bh->b_count) != 0))
- BUG();
- if (rw == READ) {
- if (!fresh)
- BUG();
- if (!buffer_uptodate(bh)) {
- arr[nr++] = bh;
- atomic_inc(&bh->b_count);
- }
- } else { /* WRITE */
- if (!bh->b_blocknr) {
- if (!block)
- BUG();
- bh->b_blocknr = block;
- } else {
- if (!block)
- BUG();
- }
- set_bit(BH_Uptodate, &bh->b_state);
- set_bit(BH_Dirty, &bh->b_state);
- arr[nr++] = bh;
- atomic_inc(&bh->b_count);
- }
+ /* Stage 2: start the IO */
+ do {
+ submit_bh(rw, bh);
bh = bh->b_this_page;
} while (bh != head);
- if ((rw == READ) && nr) {
- if (Page_Uptodate(page))
- BUG();
- ll_rw_block(rw, nr, arr);
- } else {
- if (!nr && rw == READ) {
- SetPageUptodate(page);
- UnlockPage(page);
- }
- if (nr && (rw == WRITE))
- ll_rw_block(rw, nr, arr);
- }
return 0;
}
if (!ahead || secno + ahead >= s->s_hpfs_fs_size)
*bhp = bh = bread(dev, secno, 512);
- else *bhp = bh = breada(dev, secno, 512, 0, (ahead + 1) << 9);
+ else *bhp = bh = bread(dev, secno, 512);
if (bh != NULL)
return bh->b_data;
else {
if (!ahead || secno + 4 + ahead > s->s_hpfs_fs_size)
qbh->bh[0] = bh = bread(dev, secno, 512);
- else qbh->bh[0] = bh = breada(dev, secno, 512, 0, (ahead + 4) << 9);
+ else qbh->bh[0] = bh = bread(dev, secno, 512);
if (!bh)
goto bail0;
memcpy(data, bh->b_data, 512);
NFS_FILEID(inode) != fattr.fileid)
goto out_bad;
- /* Filehandle matches? */
- if (memcmp(NFS_FH(inode), fhandle.data, sizeof(struct nfs_fh)))
- goto out_bad;
-
/* Ok, remember that we successfully checked it.. */
nfs_refresh_inode(inode, &fattr);
+ if (nfs_inode_is_stale(inode, &fhandle, &fattr))
+ goto out_bad;
+
out_valid_renew:
nfs_renew_times(dentry);
out_valid:
return 1;
}
-static int
+int
nfs_inode_is_stale(struct inode *inode, struct nfs_fh *fh, struct nfs_fattr *fattr)
{
/* Empty inodes are not stale */
/* Has the filehandle changed? If so is the old one stale? */
if (memcmp(&inode->u.nfs_i.fh, fh, sizeof(inode->u.nfs_i.fh)) != 0 &&
- __nfs_revalidate_inode(NFS_SERVER(inode),inode) < 0)
+ __nfs_revalidate_inode(NFS_SERVER(inode),inode) == -ESTALE)
return 1;
return 0;
inode->i_dev, (long long)NFS_FILEID(inode));
lock_kernel();
- if (!inode || is_bad_inode(inode)) {
+ if (!inode || is_bad_inode(inode) || NFS_STALE(inode)) {
unlock_kernel();
return -ESTALE;
}
return status;
}
if (time_before(jiffies,NFS_READTIME(inode)+NFS_ATTRTIMEO(inode))) {
- unlock_kernel();
- return 0;
+ status = NFS_STALE(inode) ? -ESTALE : 0;
+ goto out_nowait;
}
}
NFS_FLAGS(inode) |= NFS_INO_REVALIDATING;
if (status) {
dfprintk(PAGECACHE, "nfs_revalidate_inode: (%x/%Ld) getattr failed, error=%d\n",
inode->i_dev, (long long)NFS_FILEID(inode), status);
+ if (status == -ESTALE) {
+ NFS_FLAGS(inode) |= NFS_INO_STALE;
+ remove_inode_hash(inode);
+ }
goto out;
}
out:
NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING;
wake_up(&inode->i_wait);
+ out_nowait:
unlock_kernel();
return status;
}
qname.len = entry->len;
entry->ino = find_inode_number(dentry, &qname);
if (!entry->ino)
- entry->ino = smb_invent_inos(1);
+ entry->ino = iunique(dentry->d_sb, 2);
}
if (filldir(dirent, entry->name, entry->len,
goto add_entry;
if (!error) {
error = -EACCES;
- finfo.f_ino = smb_invent_inos(1);
+ finfo.f_ino = iunique(dentry->d_sb, 2);
inode = smb_iget(dir->i_sb, &finfo);
if (inode) {
add_entry:
goto out_close;
smb_renew_times(dentry);
- fattr.f_ino = smb_invent_inos(1);
+ fattr.f_ino = iunique(dentry->d_sb, 2);
inode = smb_iget(dentry->d_sb, &fattr);
if (!inode)
goto out_no_inode;
DENTRY_PATH(dentry), count, offset, rsize);
result = smb_open(dentry, SMB_O_RDONLY);
- if (result < 0)
- {
+ if (result < 0) {
PARANOIA("%s/%s open failed, error=%d\n",
DENTRY_PATH(dentry), result);
goto io_error;
if (count < rsize)
rsize = count;
- result = smb_proc_read(dentry, offset, rsize, buffer);
+ result = smb_proc_read(dentry->d_inode, offset, rsize, buffer);
if (result < 0)
goto io_error;
* Offset is the data offset within the page.
*/
static int
-smb_writepage_sync(struct dentry *dentry, struct page *page,
+smb_writepage_sync(struct inode *inode, struct page *page,
unsigned long offset, unsigned int count)
{
- struct inode *inode = dentry->d_inode;
u8 *buffer = page_address(page) + offset;
- int wsize = smb_get_wsize(server_from_dentry(dentry));
+ int wsize = smb_get_wsize(server_from_inode(inode));
int result, written = 0;
offset += page->index << PAGE_CACHE_SHIFT;
- VERBOSE("file %s/%s, count=%d@%ld, wsize=%d\n",
- DENTRY_PATH(dentry), count, offset, wsize);
+ VERBOSE("file ino=%ld, fileid=%d, count=%d@%ld, wsize=%d\n",
+ inode->i_ino, inode->u.smbfs_i.fileid, count, offset, wsize);
do {
if (count < wsize)
wsize = count;
- result = smb_proc_write(dentry, offset, wsize, buffer);
- if (result < 0)
+ result = smb_proc_write(inode, offset, wsize, buffer);
+ if (result < 0) {
+ PARANOIA("failed write, wsize=%d, result=%d\n",
+ wsize, result);
break;
+ }
/* N.B. what if result < wsize?? */
#ifdef SMBFS_PARANOIA
if (result < wsize)
smb_writepage(struct page *page)
{
struct address_space *mapping = page->mapping;
- struct dentry *dentry;
struct inode *inode;
- struct list_head *head;
unsigned long end_index;
unsigned offset = PAGE_CACHE_SIZE;
int err;
if (!inode)
BUG();
- /* Pick the first dentry for this inode. */
- head = &inode->i_dentry;
- if (list_empty(head))
- BUG(); /* We need one, are we guaranteed to have one? */
- dentry = list_entry(head->next, struct dentry, d_alias);
-
end_index = inode->i_size >> PAGE_CACHE_SHIFT;
/* easy case */
return -EIO;
do_it:
get_page(page);
- err = smb_writepage_sync(dentry, page, 0, offset);
+ err = smb_writepage_sync(inode, page, 0, offset);
SetPageUptodate(page);
UnlockPage(page);
put_page(page);
DEBUG1("(%s/%s %d@%ld)\n", DENTRY_PATH(dentry),
count, (page->index << PAGE_CACHE_SHIFT)+offset);
- return smb_writepage_sync(dentry, page, offset, count);
+ return smb_writepage_sync(dentry->d_inode, page, offset, count);
}
static ssize_t
struct address_space_operations smb_file_aops = {
readpage: smb_readpage,
- /* writepage: smb_writepage, */
+ writepage: smb_writepage,
prepare_write: smb_prepare_write,
commit_write: smb_commit_write
};
static int
smb_file_open(struct inode *inode, struct file * file)
{
+ int result;
+ struct dentry *dentry = file->f_dentry;
+ int smb_mode = (file->f_mode & O_ACCMODE) - 1;
+
lock_kernel();
+ result = smb_open(dentry, smb_mode);
+ if (result)
+ goto out;
inode->u.smbfs_i.openers++;
+out:
unlock_kernel();
return 0;
}
statfs: smb_statfs,
};
-/* FIXME: Look at all inodes whether so that we do not get duplicate
- * inode numbers. */
-
-unsigned long
-smb_invent_inos(unsigned long n)
-{
- static unsigned long ino = 2;
-
- if (ino + 2*n < ino)
- {
- /* wrap around */
- ino = 2;
- }
- ino += n;
- return ino;
-}
/* We are always generating a new inode here */
struct inode *
static void
smb_delete_inode(struct inode *ino)
{
- DEBUG1("\n");
+ DEBUG1("ino=%ld\n", ino->i_ino);
lock_kernel();
if (smb_close(ino))
PARANOIA("could not close inode %ld\n", ino->i_ino);
file-id would not be valid after a reconnection. */
int
-smb_proc_read(struct dentry *dentry, off_t offset, int count, char *data)
+smb_proc_read(struct inode *inode, off_t offset, int count, char *data)
{
- struct smb_sb_info *server = server_from_dentry(dentry);
+ struct smb_sb_info *server = server_from_inode(inode);
__u16 returned_count, data_len;
unsigned char *buf;
int result;
smb_lock_server(server);
smb_setup_header(server, SMBread, 5, 0);
buf = server->packet;
- WSET(buf, smb_vwv0, dentry->d_inode->u.smbfs_i.fileid);
+ WSET(buf, smb_vwv0, inode->u.smbfs_i.fileid);
WSET(buf, smb_vwv1, count);
DSET(buf, smb_vwv2, offset);
WSET(buf, smb_vwv4, 0);
result = data_len;
out:
- VERBOSE("file %s/%s, count=%d, result=%d\n",
- DENTRY_PATH(dentry), count, result);
+ VERBOSE("ino=%ld, fileid=%d, count=%d, result=%d\n",
+ inode->ino, inode->u.smbfs_i.fileid, count, result);
smb_unlock_server(server);
return result;
}
int
-smb_proc_write(struct dentry *dentry, off_t offset, int count, const char *data)
+smb_proc_write(struct inode *inode, off_t offset, int count, const char *data)
{
- struct smb_sb_info *server = server_from_dentry(dentry);
+ struct smb_sb_info *server = server_from_inode(inode);
int result;
__u8 *p;
- VERBOSE("file %s/%s, count=%d@%ld, packet_size=%d\n",
- DENTRY_PATH(dentry), count, offset, server->packet_size);
+ VERBOSE("ino=%ld, fileid=%d, count=%d@%ld, packet_size=%d\n",
+ inode->ino, inode->u.smbfs_i.fileid, count, offset,
+ server->packet_size);
smb_lock_server(server);
p = smb_setup_header(server, SMBwrite, 5, count + 3);
- WSET(server->packet, smb_vwv0, dentry->d_inode->u.smbfs_i.fileid);
+ WSET(server->packet, smb_vwv0, inode->u.smbfs_i.fileid);
WSET(server->packet, smb_vwv1, count);
DSET(server->packet, smb_vwv2, offset);
WSET(server->packet, smb_vwv4, 0);
unsigned short dseg_len;
};
- /* Results of APM Installation Check */
+/* Results of APM Installation Check */
#define APM_16_BIT_SUPPORT 0x0001
#define APM_32_BIT_SUPPORT 0x0002
#define APM_IDLE_SLOWS_CLOCK 0x0004
#define APM_BIOS_DISABLED 0x0008
#define APM_BIOS_DISENGAGED 0x0010
+/*
+ * Data for APM that is persistant across module unload/load
+ */
+struct apm_info {
+ struct apm_bios_info bios;
+ unsigned short connection_version;
+ int get_power_status_broken;
+};
+
/*
* The APM function codes
*/
#define APM_FUNC_TIMER_GET 2
/*
- * in init/main.c
+ * in arch/i386/kernel/setup.c
*/
-extern struct apm_bios_info apm_bios_info;
-
-extern int apm_register_callback(int (*callback)(apm_event_t));
-extern void apm_unregister_callback(int (*callback)(apm_event_t));
+extern struct apm_info apm_info;
#endif /* __KERNEL__ */
/*
* This is the "All Devices" ID communicated to the BIOS
*/
-#define APM_DEVICE_BALL ((apm_bios_info.version > 0x0100) ? \
+#define APM_DEVICE_BALL ((apm_info.connection_version > 0x0100) ? \
APM_DEVICE_ALL : APM_DEVICE_OLD_ALL)
#endif
extern struct buffer_head * get_hash_table(kdev_t, int, int);
extern struct buffer_head * getblk(kdev_t, int, int);
extern void ll_rw_block(int, int, struct buffer_head * bh[]);
+extern void submit_bh(int, struct buffer_head *);
extern int is_read_only(kdev_t);
extern void __brelse(struct buffer_head *);
static inline void brelse(struct buffer_head *buf)
extern void set_blocksize(kdev_t, int);
extern unsigned int get_hardblocksize(kdev_t);
extern struct buffer_head * bread(kdev_t, int, int);
-extern struct buffer_head * breada(kdev_t, int, int, unsigned int, unsigned int);
extern void wakeup_bdflush(int wait);
extern int brw_page(int, struct page *, kdev_t, int [], int);
extern int get_option(char **str, int *pint);
extern char *get_options(char *str, int nints, int *ints);
extern unsigned long memparse(char *ptr, char **retptr);
+extern void dev_probe_lock(void);
+extern void dev_probe_unlock(void);
extern int session_of_pgrp(int pgrp);
#define NFS_FLAGS(inode) ((inode)->u.nfs_i.flags)
#define NFS_REVALIDATING(inode) (NFS_FLAGS(inode) & NFS_INO_REVALIDATING)
+#define NFS_STALE(inode) (NFS_FLAGS(inode) & NFS_INO_STALE)
#define NFS_FILEID(inode) ((inode)->u.nfs_i.fileid)
#define NFS_FSID(inode) ((inode)->u.nfs_i.fsid)
extern struct super_block *nfs_read_super(struct super_block *, void *, int);
extern int init_nfs_fs(void);
extern void nfs_zap_caches(struct inode *);
+extern int nfs_inode_is_stale(struct inode *, struct nfs_fh *,
+ struct nfs_fattr *);
extern struct inode *nfs_fhget(struct dentry *, struct nfs_fh *,
struct nfs_fattr *);
extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
asmlinkage void schedule(void);
extern int schedule_task(struct tq_struct *task);
-extern void run_schedule_tasks(void);
+extern void flush_scheduled_tasks(void);
extern int start_context_thread(void);
+extern int current_is_keventd(void);
/*
* The default fd array needs to be at least BITS_PER_LONG,
int smb_close(struct inode *);
int smb_close_fileid(struct dentry *, __u16);
int smb_open(struct dentry *, int);
-int smb_proc_read(struct dentry *, off_t, int, char *);
-int smb_proc_write(struct dentry *, off_t, int, const char *);
+int smb_proc_read(struct inode *, off_t, int, char *);
+int smb_proc_write(struct inode *, off_t, int, const char *);
int smb_proc_create(struct dentry *, __u16, time_t, __u16 *);
int smb_proc_mv(struct dentry *, struct dentry *);
int smb_proc_mkdir(struct dentry *);
#include <linux/types.h>
#include <linux/smb.h>
-/* Get the server for the specified dentry */
-#define server_from_dentry(dentry) &dentry->d_sb->u.smbfs_sb
+/* structure access macros */
+#define server_from_inode(inode) (&(inode)->i_sb->u.smbfs_sb)
+#define server_from_dentry(dentry) (&(dentry)->d_sb->u.smbfs_sb)
#define SB_of(server) ((struct super_block *) ((char *)(server) - \
(unsigned long)(&((struct super_block *)0)->u.smbfs_sb)))
#define _LINUX_TQUEUE_H
#include <linux/spinlock.h>
+#include <linux/list.h>
#include <asm/bitops.h>
#include <asm/system.h>
*/
struct tq_struct {
- struct tq_struct *next; /* linked list of active bh's */
+ struct list_head list; /* linked list of active bh's */
unsigned long sync; /* must be initialized to zero */
void (*routine)(void *); /* function to call */
void *data; /* argument to function */
};
-typedef struct tq_struct * task_queue;
+typedef struct list_head task_queue;
-#define DECLARE_TASK_QUEUE(q) task_queue q = NULL
+#define DECLARE_TASK_QUEUE(q) LIST_HEAD(q)
+#define TQ_ACTIVE(q) (!list_empty(&q))
extern task_queue tq_timer, tq_immediate, tq_disk;
* To implement your own list of active bottom halfs, use the following
* two definitions:
*
- * struct tq_struct *my_bh = NULL;
+ * DECLARE_TASK_QUEUE(my_bh);
* struct tq_struct run_my_bh = {
- * 0, 0, (void (*)(void *)) run_task_queue, &my_bh
+ * routine: (void (*)(void *)) run_task_queue,
+ * data: &my_bh
* };
*
* To activate a bottom half on your list, use:
if (!test_and_set_bit(0,&bh_pointer->sync)) {
unsigned long flags;
spin_lock_irqsave(&tqueue_lock, flags);
- bh_pointer->next = *bh_list;
- *bh_list = bh_pointer;
+ list_add_tail(&bh_pointer->list, bh_list);
spin_unlock_irqrestore(&tqueue_lock, flags);
ret = 1;
}
*/
static inline void run_task_queue(task_queue *list)
{
- if (*list) {
+ while (!list_empty(list)) {
unsigned long flags;
- struct tq_struct *p;
+ struct list_head *next;
spin_lock_irqsave(&tqueue_lock, flags);
- p = *list;
- *list = NULL;
- spin_unlock_irqrestore(&tqueue_lock, flags);
-
- while (p) {
+ next = list->next;
+ if (next != list) {
void *arg;
void (*f) (void *);
- struct tq_struct *save_p;
- arg = p -> data;
- f = p -> routine;
- save_p = p;
- p = p -> next;
- smp_mb();
- save_p -> sync = 0;
+ struct tq_struct *p;
+
+ list_del(next);
+ p = list_entry(next, struct tq_struct, list);
+ arg = p->data;
+ f = p->routine;
+ p->sync = 0;
+ spin_unlock_irqrestore(&tqueue_lock, flags);
+
if (f)
- (*f)(arg);
+ f(arg);
+ continue;
}
+ spin_unlock_irqrestore(&tqueue_lock, flags);
}
}
struct list_head inodes;
};
-#define USB_MAXCHILDREN (8) /* This is arbitrary */
+#define USB_MAXCHILDREN (16) /* This is arbitrary */
struct usb_device {
int devnum; /* Device number on USB bus */
/* Mount the root filesystem.. */
mount_root();
-#if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
- /* do this after other 'do this last' stuff, because we want
- * to minimize spurious executions of /sbin/hotplug
- * during boot-up
- */
- net_notifier_init();
-#endif
-
mount_devfs_fs ();
#ifdef CONFIG_BLK_DEV_INITRD
*
* Mechanism for running arbitrary tasks in process context
*
- * dwmw2@redhat.com
+ * dwmw2@redhat.com: Genesis
+ *
+ * andrewm@uow.edu.au: 2.4.0-test12
+ * - Child reaping
+ * - Support for tasks which re-add themselves
+ * - flush_scheduled_tasks.
*/
#define __KERNEL_SYSCALLS__
static DECLARE_TASK_QUEUE(tq_context);
static DECLARE_WAIT_QUEUE_HEAD(context_task_wq);
+static DECLARE_WAIT_QUEUE_HEAD(context_task_done);
static int keventd_running;
+static struct task_struct *keventd_task;
+
+static int need_keventd(const char *who)
+{
+ if (keventd_running == 0)
+ printk(KERN_ERR "%s(): keventd has not started\n", who);
+ return keventd_running;
+}
+
+int current_is_keventd(void)
+{
+ int ret = 0;
+ if (need_keventd(__FUNCTION__))
+ ret = (current == keventd_task);
+ return ret;
+}
+/**
+ * schedule_task - schedule a function for subsequent execution in process context.
+ * @task: pointer to a &tq_struct which defines the function to be scheduled.
+ *
+ * May be called from interrupt context. The scheduled function is run at some
+ * time in the near future by the keventd kernel thread. If it can sleep, it
+ * should be designed to do so for the minimum possible time, as it will be
+ * stalling all other scheduled tasks.
+ *
+ * schedule_task() returns non-zero if the task was successfully scheduled.
+ * If @task is already residing on a task queue then schedule_task() fails
+ * to schedule your task and returns zero.
+ */
int schedule_task(struct tq_struct *task)
{
int ret;
- if (keventd_running == 0)
- printk(KERN_ERR "schedule_task(): keventd has not started\n");
+ need_keventd(__FUNCTION__);
ret = queue_task(task, &tq_context);
wake_up(&context_task_wq);
return ret;
daemonize();
strcpy(curtask->comm, "keventd");
keventd_running = 1;
+ keventd_task = curtask;
spin_lock_irq(&curtask->sigmask_lock);
siginitsetinv(&curtask->blocked, sigmask(SIGCHLD));
siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));
do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0);
- /*
- * If one of the functions on a task queue re-adds itself
- * to the task queue we call schedule() in state TASK_RUNNING
- */
- for (;;) {
+ /*
+ * If one of the functions on a task queue re-adds itself
+ * to the task queue we call schedule() in state TASK_RUNNING
+ */
+ for (;;) {
set_task_state(curtask, TASK_INTERRUPTIBLE);
- add_wait_queue(&context_task_wq, &wait);
- if (tq_context)
+ add_wait_queue(&context_task_wq, &wait);
+ if (TQ_ACTIVE(tq_context))
set_task_state(curtask, TASK_RUNNING);
schedule();
- remove_wait_queue(&context_task_wq, &wait);
- run_task_queue(&tq_context);
+ remove_wait_queue(&context_task_wq, &wait);
+ run_task_queue(&tq_context);
+ wake_up(&context_task_done);
if (signal_pending(curtask)) {
while (waitpid(-1, (unsigned int *)0, __WALL|WNOHANG) > 0)
;
}
}
-/*
- * Run the tq_context queue right now. Must be called from process context
+/**
+ * flush_scheduled_tasks - ensure that any scheduled tasks have run to completion.
+ *
+ * Forces execution of the schedule_task() queue and blocks until its completion.
+ *
+ * If a kernel subsystem uses schedule_task() and wishes to flush any pending
+ * tasks, it should use this function. This is typically used in driver shutdown
+ * handlers.
+ *
+ * The caller should hold no spinlocks and should hold no semaphores which could
+ * cause the scheduled tasks to block.
*/
-void run_schedule_tasks(void)
+static struct tq_struct dummy_task;
+
+void flush_scheduled_tasks(void)
{
- run_task_queue(&tq_context);
+ int count;
+ DECLARE_WAITQUEUE(wait, current);
+
+ /*
+ * Do it twice. It's possible, albeit highly unlikely, that
+ * the caller queued a task immediately before calling us,
+ * and that the eventd thread was already past the run_task_queue()
+ * but not yet into wake_up(), so it woke us up before completing
+ * the caller's queued task or our new dummy task.
+ */
+ add_wait_queue(&context_task_done, &wait);
+ for (count = 0; count < 2; count++) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+
+ /* Queue a dummy task to make sure we get kicked */
+ schedule_task(&dummy_task);
+
+ /* Wait for it to complete */
+ schedule();
+ }
+ remove_wait_queue(&context_task_done, &wait);
}
int start_context_thread(void)
}
EXPORT_SYMBOL(schedule_task);
-EXPORT_SYMBOL(run_schedule_tasks);
+EXPORT_SYMBOL(flush_scheduled_tasks);
{
struct mm_struct * mm = tsk->mm;
+ mm_release();
if (mm) {
atomic_inc(&mm->mm_count);
- mm_release();
if (mm != tsk->active_mm) BUG();
/* more a memory barrier than a real lock */
task_lock(tsk);
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/unistd.h>
+#include <linux/kmod.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#endif /* CONFIG_HOTPLUG */
-
-static int exec_helper (void *arg)
-{
- long ret;
- void **params = (void **) arg;
- char *path = (char *) params [0];
- char **argv = (char **) params [1];
- char **envp = (char **) params [2];
-
- ret = exec_usermodehelper (path, argv, envp);
- if (ret < 0)
- ret = -ret;
- do_exit(ret);
-}
-
struct subprocess_info {
struct semaphore *sem;
char *path;
char **argv;
char **envp;
- int retval;
+ pid_t retval;
};
/*
- * This is a standalone child of keventd. It forks off another thread which
- * is the desired usermode helper and then waits for the child to exit.
- * We return the usermode process's exit code, or some -ve error code.
+ * This is the task which runs the usermode application
*/
static int ____call_usermodehelper(void *data)
{
struct subprocess_info *sub_info = data;
- struct task_struct *curtask = current;
- void *params [3] = { sub_info->path, sub_info->argv, sub_info->envp };
- pid_t pid, pid2;
- mm_segment_t fs;
- int retval = 0;
-
- if (!curtask->fs->root) {
- printk(KERN_ERR "call_usermodehelper[%s]: no root fs\n", sub_info->path);
- retval = -EPERM;
- goto up_and_out;
- }
- if ((pid = kernel_thread(exec_helper, (void *) params, 0)) < 0) {
- printk(KERN_ERR "failed fork2 %s, errno = %d", sub_info->argv[0], -pid);
- retval = pid;
- goto up_and_out;
- }
+ int retval;
- if (retval >= 0) {
- /* Block everything but SIGKILL/SIGSTOP */
- spin_lock_irq(&curtask->sigmask_lock);
- siginitsetinv(&curtask->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP));
- recalc_sigpending(curtask);
- spin_unlock_irq(&curtask->sigmask_lock);
-
- /* Allow the system call to access kernel memory */
- fs = get_fs();
- set_fs(KERNEL_DS);
- pid2 = waitpid(pid, &retval, __WCLONE);
- if (pid2 == -1 && errno < 0)
- pid2 = errno;
- set_fs(fs);
-
- if (pid2 != pid) {
- printk(KERN_ERR "waitpid(%d) failed, %d\n", pid, pid2);
- retval = (pid2 < 0) ? pid2 : -1;
- }
- }
+ retval = -EPERM;
+ if (current->fs->root)
+ retval = exec_usermodehelper(sub_info->path, sub_info->argv, sub_info->envp);
-up_and_out:
- sub_info->retval = retval;
- curtask->exit_signal = SIGCHLD; /* Wake up parent */
- up_and_exit(sub_info->sem, retval);
+ /* Exec failed? */
+ sub_info->retval = (pid_t)retval;
+ do_exit(0);
}
/*
- * This is a schedule_task function, so we must not sleep for very long at all.
- * But the exec'ed process could do anything at all. So we launch another
- * kernel thread.
+ * This is run by keventd.
*/
static void __call_usermodehelper(void *data)
{
struct subprocess_info *sub_info = data;
pid_t pid;
- if ((pid = kernel_thread (____call_usermodehelper, (void *)sub_info, 0)) < 0) {
- printk(KERN_ERR "failed fork1 %s, errno = %d", sub_info->argv[0], -pid);
+ /*
+ * CLONE_VFORK: wait until the usermode helper has execve'd successfully
+ * We need the data structures to stay around until that is done.
+ */
+ pid = kernel_thread(____call_usermodehelper, sub_info, CLONE_VFORK | SIGCHLD);
+ if (pid < 0)
sub_info->retval = pid;
- up(sub_info->sem);
- }
+ up(sub_info->sem);
}
-/*
- * This function can be called via do_exit->__exit_files, which means that
- * we're partway through exitting and things break if we fork children.
- * So we use keventd to parent the usermode helper.
- * We return the usermode application's exit code or some -ve error.
+/**
+ * call_usermodehelper - start a usermode application
+ * @path: pathname for the application
+ * @argv: null-terminated argument list
+ * @envp: null-terminated environment list
+ *
+ * Runs a user-space application. The application is started asynchronously. It
+ * runs as a child of keventd. It runs with full root capabilities. keventd silently
+ * reaps the child when it exits.
+ *
+ * Must be called from process context. Returns zero on success, else a negative
+ * error code.
*/
-int call_usermodehelper (char *path, char **argv, char **envp)
+int call_usermodehelper(char *path, char **argv, char **envp)
{
DECLARE_MUTEX_LOCKED(sem);
struct subprocess_info sub_info = {
- sem: &sem,
- path: path,
- argv: argv,
- envp: envp,
- retval: 0,
+ sem: &sem,
+ path: path,
+ argv: argv,
+ envp: envp,
+ retval: 0,
};
struct tq_struct tqs = {
- next: 0,
- sync: 0,
routine: __call_usermodehelper,
data: &sub_info,
};
- schedule_task(&tqs);
- down(&sem); /* Wait for an error or completion */
+ if (path[0] == '\0')
+ goto out;
+
+ if (current_is_keventd()) {
+ /* We can't wait on keventd! */
+ __call_usermodehelper(&sub_info);
+ } else {
+ schedule_task(&tqs);
+ down(&sem); /* Wait until keventd has started the subprocess */
+ }
+out:
return sub_info.retval;
}
+/*
+ * This is for the serialisation of device probe() functions
+ * against device open() functions
+ */
+static DECLARE_MUTEX(dev_probe_sem);
+
+void dev_probe_lock(void)
+{
+ down(&dev_probe_sem);
+}
+
+void dev_probe_unlock(void)
+{
+ up(&dev_probe_sem);
+}
+
EXPORT_SYMBOL(exec_usermodehelper);
EXPORT_SYMBOL(call_usermodehelper);
EXPORT_SYMBOL(bdget);
EXPORT_SYMBOL(bdput);
EXPORT_SYMBOL(bread);
-EXPORT_SYMBOL(breada);
EXPORT_SYMBOL(__brelse);
EXPORT_SYMBOL(__bforget);
EXPORT_SYMBOL(ll_rw_block);
update_process_times(user_mode(regs));
#endif
mark_bh(TIMER_BH);
- if (tq_timer)
+ if (TQ_ACTIVE(tq_timer))
mark_bh(TQUEUE_BH);
}
static struct timer_list samp_timer = { function: sample_queue };
#endif
+#ifdef CONFIG_HOTPLUG
+static int net_run_sbin_hotplug(struct net_device *dev, char *action);
+#else
+#define net_run_sbin_hotplug(dev, action) ({ 0; })
+#endif
+
/*
* Our notifier list
*/
if (!capable(CAP_NET_ADMIN))
return -EPERM;
dev_load(ifr.ifr_name);
+ dev_probe_lock();
rtnl_lock();
ret = dev_ifsioc(&ifr, cmd);
rtnl_unlock();
+ dev_probe_unlock();
return ret;
case SIOCGIFMEM:
if (cmd >= SIOCDEVPRIVATE &&
cmd <= SIOCDEVPRIVATE + 15) {
dev_load(ifr.ifr_name);
+ dev_probe_lock();
rtnl_lock();
ret = dev_ifsioc(&ifr, cmd);
rtnl_unlock();
+ dev_probe_unlock();
if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq)))
return -EFAULT;
return ret;
if (ret)
return ret;
#endif /* CONFIG_NET_DIVERT */
-
+
/* Notify protocols, that a new device appeared. */
notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);
+ net_run_sbin_hotplug(dev, "register");
+
return 0;
}
/* Shutdown queueing discipline. */
dev_shutdown(dev);
+ net_run_sbin_hotplug(dev, "unregister");
+
/* Notify protocols, that we are about to destroy
this device. They should clean all the things.
*/
/* Notify userspace when a netdevice event occurs,
* by running '/sbin/hotplug net' with certain
* environment variables set.
- *
- * Currently reported events are listed in netdev_event_names[].
*/
-/* /sbin/hotplug ONLY executes for events named here */
-static char *netdev_event_names[] = {
- [NETDEV_REGISTER] = "register",
- [NETDEV_UNREGISTER] = "unregister",
-};
-
-static int run_sbin_hotplug(struct notifier_block *this,
- unsigned long event, void *ptr)
+static int net_run_sbin_hotplug(struct net_device *dev, char *action)
{
- struct net_device *dev = (struct net_device *) ptr;
- char *argv[3], *envp[5], ifname[12 + IFNAMSIZ], action[32];
+ char *argv[3], *envp[5], ifname[12 + IFNAMSIZ], action_str[32];
int i;
- if ((event >= ARRAY_SIZE(netdev_event_names)) ||
- !netdev_event_names[event])
- return NOTIFY_DONE;
-
sprintf(ifname, "INTERFACE=%s", dev->name);
- sprintf(action, "ACTION=%s", netdev_event_names[event]);
+ sprintf(action_str, "ACTION=%s", action);
i = 0;
argv[i++] = hotplug_path;
envp [i++] = "HOME=/";
envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
envp [i++] = ifname;
- envp [i++] = action;
+ envp [i++] = action_str;
envp [i] = 0;
- call_usermodehelper (argv [0], argv, envp);
-
- return NOTIFY_DONE;
-}
-
-static struct notifier_block sbin_hotplug = {
- notifier_call: run_sbin_hotplug,
-};
-
-/*
- * called from init/main.c, -after- all the initcalls are complete.
- * Registers a hook that calls /sbin/hotplug on every netdev
- * addition and removal.
- */
-void __init net_notifier_init (void)
-{
- if (register_netdevice_notifier(&sbin_hotplug))
- printk (KERN_WARNING "unable to register netdev notifier\n"
- KERN_WARNING "/sbin/hotplug will not be run.\n");
+ return call_usermodehelper(argv [0], argv, envp);
}
#endif
return -EINVAL;
}
+ dev_probe_lock();
rtnl_lock();
if ((dev = __dev_get_by_name(ifr.ifr_name)) == NULL) {
}
done:
rtnl_unlock();
+ dev_probe_unlock();
return ret;
rarok:
rtnl_unlock();
+ dev_probe_unlock();
if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
return -EFAULT;
return 0;